mirror of
https://github.com/logseq/logseq.git
synced 2026-02-01 14:43:56 +00:00
chore: remove silkhq components
This commit is contained in:
156
deps/shui/src/logseq/shui/silkhq.cljs
vendored
156
deps/shui/src/logseq/shui/silkhq.cljs
vendored
@@ -1,156 +0,0 @@
|
||||
(ns logseq.shui.silkhq
|
||||
(:require [goog.object :refer [getValueByKeys] :as gobj]
|
||||
[logseq.shui.util :refer [component-wrap] :as util]))
|
||||
|
||||
(goog-define NODETEST false)
|
||||
|
||||
(def silkhq-wrap
|
||||
(partial component-wrap js/window.LSSilkhq))
|
||||
|
||||
(defn silkhq-get
|
||||
[name]
|
||||
(if NODETEST
|
||||
#js {}
|
||||
(let [path (util/get-path name)]
|
||||
(some-> js/window.LSSilkhq (gobj/getValueByKeys (clj->js path))))))
|
||||
|
||||
(def fixed (silkhq-wrap "Fixed.Root"))
|
||||
(def fixed-content (silkhq-wrap "Fixed.Content"))
|
||||
|
||||
(def scroll (silkhq-wrap "Scroll.Root"))
|
||||
(def scroll-trigger (silkhq-wrap "Scroll.Trigger"))
|
||||
(def scroll-content (silkhq-wrap "Scroll.Content"))
|
||||
(def scroll-view (silkhq-wrap "Scroll.View"))
|
||||
|
||||
(def sheet (silkhq-wrap "Sheet.Root"))
|
||||
(def sheet-bleeding-background (silkhq-wrap "Sheet.BleedingBackground"))
|
||||
(def sheet-portal (silkhq-wrap "Sheet.Portal"))
|
||||
(def sheet-handle (silkhq-wrap "Sheet.Handle"))
|
||||
(def sheet-content (silkhq-wrap "Sheet.Content"))
|
||||
(def sheet-title (silkhq-wrap "Sheet.Title"))
|
||||
(def sheet-description (silkhq-wrap "Sheet.Description"))
|
||||
(def sheet-trigger (silkhq-wrap "Sheet.Trigger"))
|
||||
(def sheet-outlet (silkhq-wrap "Sheet.Outlet"))
|
||||
(def sheet-backdrop (silkhq-wrap "Sheet.Backdrop"))
|
||||
(def sheet-view (silkhq-wrap "Sheet.View"))
|
||||
|
||||
(def bottom-sheet (silkhq-wrap "BottomSheet.Root"))
|
||||
(def bottom-sheet-portal (silkhq-wrap "BottomSheet.Portal"))
|
||||
(def bottom-sheet-handle (silkhq-wrap "BottomSheet.Handle"))
|
||||
(def bottom-sheet-content (silkhq-wrap "BottomSheet.Content"))
|
||||
(def bottom-sheet-title (silkhq-wrap "BottomSheet.Title"))
|
||||
(def bottom-sheet-description (silkhq-wrap "BottomSheet.Description"))
|
||||
(def bottom-sheet-trigger (silkhq-wrap "BottomSheet.Trigger"))
|
||||
(def bottom-sheet-outlet (silkhq-wrap "BottomSheet.Outlet"))
|
||||
(def bottom-sheet-backdrop (silkhq-wrap "BottomSheet.Backdrop"))
|
||||
(def bottom-sheet-view (silkhq-wrap "BottomSheet.View"))
|
||||
|
||||
(def depth-sheet (silkhq-wrap "SheetWithDepth.Root"))
|
||||
(def depth-sheet-portal (silkhq-wrap "SheetWithDepth.Portal"))
|
||||
(def depth-sheet-handle (silkhq-wrap "SheetWithDepth.Handle"))
|
||||
(def depth-sheet-content (silkhq-wrap "SheetWithDepth.Content"))
|
||||
(def depth-sheet-title (silkhq-wrap "SheetWithDepth.Title"))
|
||||
(def depth-sheet-description (silkhq-wrap "SheetWithDepth.Description"))
|
||||
(def depth-sheet-trigger (silkhq-wrap "SheetWithDepth.Trigger"))
|
||||
(def depth-sheet-outlet (silkhq-wrap "SheetWithDepth.Outlet"))
|
||||
(def depth-sheet-backdrop (silkhq-wrap "SheetWithDepth.Backdrop"))
|
||||
(def depth-sheet-view (silkhq-wrap "SheetWithDepth.View"))
|
||||
(def depth-sheet-stack (silkhq-wrap "SheetWithDepthStack.Root"))
|
||||
(def depth-sheet-scenery-outlets
|
||||
(silkhq-wrap "SheetWithDepthStack.SceneryOutlets" {:static? true}))
|
||||
|
||||
(def detent-sheet (silkhq-wrap "SheetWithDetent.Root"))
|
||||
(def detent-sheet-portal (silkhq-wrap "SheetWithDetent.Portal"))
|
||||
(def detent-sheet-handle (silkhq-wrap "SheetWithDetent.Handle"))
|
||||
(def detent-sheet-content (silkhq-wrap "SheetWithDetent.Content"))
|
||||
(def detent-sheet-title (silkhq-wrap "SheetWithDetent.Title"))
|
||||
(def detent-sheet-description (silkhq-wrap "SheetWithDetent.Description"))
|
||||
(def detent-sheet-trigger (silkhq-wrap "SheetWithDetent.Trigger"))
|
||||
(def detent-sheet-outlet (silkhq-wrap "SheetWithDetent.Outlet"))
|
||||
(def detent-sheet-backdrop (silkhq-wrap "SheetWithDetent.Backdrop"))
|
||||
(def detent-sheet-view (silkhq-wrap "SheetWithDetent.View"))
|
||||
(def detent-sheet-scroll (silkhq-wrap "SheetWithDetent.ScrollRoot"))
|
||||
(def detent-sheet-scroll-content (silkhq-wrap "SheetWithDetent.ScrollContent"))
|
||||
(def detent-sheet-scroll-view (silkhq-wrap "SheetWithDetent.ScrollView"))
|
||||
|
||||
(def stacking-sheet (silkhq-wrap "SheetWithStacking.Root"))
|
||||
(def stacking-sheet-portal (silkhq-wrap "SheetWithStacking.Portal"))
|
||||
(def stacking-sheet-handle (silkhq-wrap "SheetWithStacking.Handle"))
|
||||
(def stacking-sheet-content (silkhq-wrap "SheetWithStacking.Content"))
|
||||
(def stacking-sheet-title (silkhq-wrap "SheetWithStacking.Title"))
|
||||
(def stacking-sheet-description (silkhq-wrap "SheetWithStacking.Description"))
|
||||
(def stacking-sheet-trigger (silkhq-wrap "SheetWithStacking.Trigger"))
|
||||
(def stacking-sheet-outlet (silkhq-wrap "SheetWithStacking.Outlet"))
|
||||
(def stacking-sheet-backdrop (silkhq-wrap "SheetWithStacking.Backdrop"))
|
||||
(def stacking-sheet-view (silkhq-wrap "SheetWithStacking.View"))
|
||||
(def stacking-sheet-stack (silkhq-wrap "SheetWithStackingStack.Root"))
|
||||
|
||||
(def parallax-page (silkhq-wrap "ParallaxPage.Root"))
|
||||
(def parallax-page-portal (silkhq-wrap "ParallaxPage.Portal"))
|
||||
(def parallax-page-handle (silkhq-wrap "ParallaxPage.Handle"))
|
||||
(def parallax-page-content (silkhq-wrap "ParallaxPage.Content"))
|
||||
(def parallax-page-description (silkhq-wrap "ParallaxPage.Description"))
|
||||
(def parallax-page-title (silkhq-wrap "ParallaxPage.Title"))
|
||||
(def parallax-page-trigger (silkhq-wrap "ParallaxPage.Trigger"))
|
||||
(def parallax-page-outlet (silkhq-wrap "ParallaxPage.Outlet"))
|
||||
(def parallax-page-backdrop (silkhq-wrap "ParallaxPage.Backdrop"))
|
||||
(def parallax-page-view (silkhq-wrap "ParallaxPage.View"))
|
||||
(def parallax-page-view-portal (silkhq-wrap "ParallaxPage.ViewPortal"))
|
||||
(def parallax-page-topbar-title (silkhq-wrap "ParallaxPage.TopBarTitle"))
|
||||
(def parallax-page-topbar-portal (silkhq-wrap "ParallaxPage.TopBarTitlePortal"))
|
||||
(def parallax-page-topbar-dismiss-trigger (silkhq-wrap "ParallaxPage.TopBarDismissTrigger"))
|
||||
(def parallax-page-topbar-dismiss-trigger-portal (silkhq-wrap "ParallaxPage.TopBarDismissTriggerPortal"))
|
||||
|
||||
(def parallax-page-stack (silkhq-wrap "ParallaxPageStack.Root"))
|
||||
(def parallax-page-stack-scenery-outlet (silkhq-wrap "ParallaxPageStack.SceneryOutlet"))
|
||||
;; stack topbar components
|
||||
(def parallax-page-stack-island (silkhq-wrap "ParallaxPageStack.IslandRoot"))
|
||||
(def parallax-page-stack-island-content (silkhq-wrap "ParallaxPageStack.IslandContent"))
|
||||
(def parallax-page-stack-topbar-dismiss-trigger-container (silkhq-wrap "ParallaxPageStack.TopBarDismissTriggerContainer"))
|
||||
(def parallax-page-stack-topbar-title-outlet (silkhq-wrap "ParallaxPageStack.TopBarTitleOutlet"))
|
||||
(def parallax-page-stack-topbar-title-container (silkhq-wrap "ParallaxPageStack.TopBarTitleContainer"))
|
||||
|
||||
(def page (silkhq-wrap "Page.Root"))
|
||||
(def page-portal (silkhq-wrap "Page.Portal"))
|
||||
(def page-handle (silkhq-wrap "Page.Handle"))
|
||||
(def page-content (silkhq-wrap "Page.Content"))
|
||||
(def page-title (silkhq-wrap "Page.Title"))
|
||||
(def page-description (silkhq-wrap "Page.Description"))
|
||||
(def page-trigger (silkhq-wrap "Page.Trigger"))
|
||||
(def page-outlet (silkhq-wrap "Page.Outlet"))
|
||||
(def page-backdrop (silkhq-wrap "Page.Backdrop"))
|
||||
(def page-view (silkhq-wrap "Page.View"))
|
||||
|
||||
(def card-sheet (silkhq-wrap "CardSheet.Root"))
|
||||
(def card-sheet-portal (silkhq-wrap "CardSheet.Portal"))
|
||||
(def card-sheet-handle (silkhq-wrap "CardSheet.Handle"))
|
||||
(def card-sheet-content (silkhq-wrap "CardSheet.Content"))
|
||||
(def card-sheet-title (silkhq-wrap "CardSheet.Title"))
|
||||
(def card-sheet-description (silkhq-wrap "CardSheet.Description"))
|
||||
(def card-sheet-trigger (silkhq-wrap "CardSheet.Trigger"))
|
||||
(def card-sheet-outlet (silkhq-wrap "CardSheet.Outlet"))
|
||||
(def card-sheet-backdrop (silkhq-wrap "CardSheet.Backdrop"))
|
||||
(def card-sheet-view (silkhq-wrap "CardSheet.View"))
|
||||
|
||||
(def sidebar-sheet (silkhq-wrap "Sidebar.Root"))
|
||||
(def sidebar-sheet-portal (silkhq-wrap "Sidebar.Portal"))
|
||||
(def sidebar-sheet-view (silkhq-wrap "Sidebar.View"))
|
||||
(def sidebar-sheet-backdrop (silkhq-wrap "Sidebar.Backdrop"))
|
||||
(def sidebar-sheet-content (silkhq-wrap "Sidebar.Content"))
|
||||
(def sidebar-sheet-trigger (silkhq-wrap "Sidebar.Trigger"))
|
||||
(def sidebar-sheet-handle (silkhq-wrap "Sidebar.Handle"))
|
||||
(def sidebar-sheet-outlet (silkhq-wrap "Sidebar.Outlet"))
|
||||
(def sidebar-sheet-title (silkhq-wrap "Sidebar.Title"))
|
||||
(def sidebar-sheet-description (silkhq-wrap "Sidebar.Description"))
|
||||
|
||||
(def persistent-sheet (silkhq-wrap "PersistentSheetWithDetent.Root"))
|
||||
(def persistent-sheet-portal (silkhq-wrap "PersistentSheetWithDetent.Portal"))
|
||||
(def persistent-sheet-view (silkhq-wrap "PersistentSheetWithDetent.View"))
|
||||
(def persistent-sheet-content (silkhq-wrap "PersistentSheetWithDetent.Content"))
|
||||
(def persistent-sheet-trigger (silkhq-wrap "PersistentSheetWithDetent.Trigger"))
|
||||
(def persistent-sheet-handle (silkhq-wrap "PersistentSheetWithDetent.Handle"))
|
||||
(def persistent-sheet-retracted-content (silkhq-wrap "PersistentSheetWithDetent.RetractedContent"))
|
||||
(def persistent-sheet-expanded-content (silkhq-wrap "PersistentSheetWithDetent.ExpandedContent"))
|
||||
(def persistent-sheet-outlet (silkhq-wrap "PersistentSheetWithDetent.Outlet"))
|
||||
(def persistent-sheet-title (silkhq-wrap "PersistentSheetWithDetent.Title"))
|
||||
(def persistent-sheet-description (silkhq-wrap "PersistentSheetWithDetent.Description"))
|
||||
@@ -6,8 +6,7 @@
|
||||
"scripts": {
|
||||
"watch:ui:examples": "parcel serve ./examples/index.html",
|
||||
"build:ui:only": "parcel build --target ui",
|
||||
"build:silkhq:only": "parcel build --target silkhq",
|
||||
"build:ui": "rm -rf .parcel-cache && yarn build:ui:only && yarn build:silkhq:only",
|
||||
"build:ui": "rm -rf .parcel-cache && yarn build:ui:only",
|
||||
"watch:storybook": "storybook dev -p 6006",
|
||||
"postinstall": "yarn build:ui"
|
||||
},
|
||||
@@ -33,7 +32,6 @@
|
||||
"@radix-ui/react-toggle": "^1.1.6",
|
||||
"@radix-ui/react-toggle-group": "^1.1.7",
|
||||
"@radix-ui/react-tooltip": "^1.2.4",
|
||||
"@silk-hq/components": "^0.9.10",
|
||||
"aws-amplify": "^6.15.6",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.0.0",
|
||||
@@ -101,14 +99,6 @@
|
||||
"react": false,
|
||||
"react-dom": false
|
||||
}
|
||||
},
|
||||
"silkhq": {
|
||||
"source": "src/silkhq/silkhq.ts",
|
||||
"outputFormat": "global",
|
||||
"includeNodeModules": {
|
||||
"react": false,
|
||||
"react-dom": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"resolutions": {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
.BottomSheet-view {
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
|
||||
.BottomSheet-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
height: auto;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
.BottomSheet-bleedingBackground {
|
||||
/* APPEARANCE */
|
||||
border-radius: 24px;
|
||||
background-color: white;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
.BottomSheet-handle {
|
||||
/* SELF-LAYOUT */
|
||||
width: 50px;
|
||||
height: 6px;
|
||||
|
||||
/* APPEARANCE */
|
||||
border: 0;
|
||||
border-radius: 9999px;
|
||||
background-color: rgb(209, 213, 219);
|
||||
|
||||
/* INTERACTIVITY */
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import React from "react";
|
||||
import { Sheet } from "@silk-hq/components";
|
||||
import "./BottomSheet.css";
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type BottomSheetRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
};
|
||||
|
||||
const BottomSheetRoot = React.forwardRef<React.ElementRef<typeof Sheet.Root>, BottomSheetRootProps>(
|
||||
({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
BottomSheetRoot.displayName = "BottomSheet.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const BottomSheetView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`BottomSheet-view ${className ?? ""}`.trim()}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
);
|
||||
});
|
||||
BottomSheetView.displayName = "BottomSheet.View";
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const BottomSheetBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
className={`BottomSheet-backdrop ${className ?? ""}`.trim()}
|
||||
themeColorDimming="auto"
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
BottomSheetBackdrop.displayName = "BottomSheet.Backdrop";
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const BottomSheetContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`BottomSheet-content ${className ?? ""}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.BleedingBackground className="BottomSheet-bleedingBackground" />
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
BottomSheetContent.displayName = "BottomSheet.Content";
|
||||
|
||||
// ================================================================================================
|
||||
// Handle
|
||||
// ================================================================================================
|
||||
|
||||
const BottomSheetHandle = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Handle>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Handle>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Handle
|
||||
className={`BottomSheet-handle ${className ?? ""}`.trim()}
|
||||
action="dismiss"
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
BottomSheetHandle.displayName = "BottomSheet.Handle";
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const BottomSheetPortal = Sheet.Portal;
|
||||
const BottomSheetTrigger = Sheet.Trigger;
|
||||
const BottomSheetOutlet = Sheet.Outlet;
|
||||
const BottomSheetTitle = Sheet.Title;
|
||||
const BottomSheetDescription = Sheet.Description;
|
||||
|
||||
export const BottomSheet = {
|
||||
Root: BottomSheetRoot,
|
||||
Portal: BottomSheetPortal,
|
||||
View: BottomSheetView,
|
||||
Backdrop: BottomSheetBackdrop,
|
||||
Content: BottomSheetContent,
|
||||
Trigger: BottomSheetTrigger,
|
||||
Handle: BottomSheetHandle,
|
||||
Outlet: BottomSheetOutlet,
|
||||
Title: BottomSheetTitle,
|
||||
Description: BottomSheetDescription,
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
.Card-view {
|
||||
--card-radius: 36px;
|
||||
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.Card-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: min(600px, calc(100% - 2 * 1rem));
|
||||
height: auto;
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
border-radius: var(--card-radius);
|
||||
background-color: white;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
import React from 'react'
|
||||
import { Sheet } from '@silk-hq/components'
|
||||
import './Card.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type CardRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const CardRoot = React.forwardRef<React.ElementRef<typeof Sheet.Root>, CardRootProps>(
|
||||
({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
)
|
||||
}
|
||||
)
|
||||
CardRoot.displayName = 'Card.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const CardView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`Card-view ${className ?? ''}`.trim()}
|
||||
contentPlacement="center"
|
||||
tracks="top"
|
||||
enteringAnimationSettings={{
|
||||
easing: 'spring',
|
||||
stiffness: 260,
|
||||
damping: 20,
|
||||
mass: 1,
|
||||
}}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
)
|
||||
})
|
||||
CardView.displayName = 'Card.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const CardBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
className={`Card-backdrop ${className ?? ''}`.trim()}
|
||||
travelAnimation={{
|
||||
opacity: ({ progress }) => Math.min(0.4 * progress, 0.4),
|
||||
}}
|
||||
themeColorDimming="auto"
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
CardBackdrop.displayName = 'Card.Backdrop'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const CardContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`Card-content ${className ?? ''}`.trim()}
|
||||
travelAnimation={{ scale: [0.8, 1] }}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
)
|
||||
})
|
||||
CardContent.displayName = 'Card.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const CardPortal = Sheet.Portal
|
||||
const CardTrigger = Sheet.Trigger
|
||||
const CardHandle = Sheet.Handle
|
||||
const CardOutlet = Sheet.Outlet
|
||||
const CardTitle = Sheet.Title
|
||||
const CardDescription = Sheet.Description
|
||||
|
||||
export const Card = {
|
||||
Root: CardRoot,
|
||||
Portal: CardPortal,
|
||||
View: CardView,
|
||||
Backdrop: CardBackdrop,
|
||||
Content: CardContent,
|
||||
Trigger: CardTrigger,
|
||||
Handle: CardHandle,
|
||||
Outlet: CardOutlet,
|
||||
Title: CardTitle,
|
||||
Description: CardDescription,
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
.Page-view {
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
|
||||
.Page-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: white;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
import React from 'react'
|
||||
import { Sheet } from '@silk-hq/components'
|
||||
import './Page.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type PageRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const PageRoot = React.forwardRef<React.ElementRef<typeof Sheet.Root>, PageRootProps>(
|
||||
({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
)
|
||||
}
|
||||
)
|
||||
PageRoot.displayName = 'Page.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const PageView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`Page-view ${className ?? ''}`.trim()}
|
||||
contentPlacement="right"
|
||||
swipeOvershoot={false}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
)
|
||||
})
|
||||
PageView.displayName = 'Page.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const PageBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
className={`Page-backdrop ${className ?? ''}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
PageBackdrop.displayName = 'Page.Backdrop'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const PageContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content className={`Page-content ${className ?? ''}`.trim()} {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
)
|
||||
})
|
||||
PageContent.displayName = 'Page.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const PagePortal = Sheet.Portal
|
||||
const PageTrigger = Sheet.Trigger
|
||||
const PageHandle = Sheet.Handle
|
||||
const PageOutlet = Sheet.Outlet
|
||||
const PageTitle = Sheet.Title
|
||||
const PageDescription = Sheet.Description
|
||||
|
||||
export const Page = {
|
||||
Root: PageRoot,
|
||||
Portal: PagePortal,
|
||||
View: PageView,
|
||||
Backdrop: PageBackdrop,
|
||||
Content: PageContent,
|
||||
Trigger: PageTrigger,
|
||||
Handle: PageHandle,
|
||||
Outlet: PageOutlet,
|
||||
Title: PageTitle,
|
||||
Description: PageDescription,
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/* Stack top bar elements */
|
||||
|
||||
.ParallaxPage-stackTopBarDismissTriggerContainer {
|
||||
/* INNER-LAYOUT */
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.ParallaxPage-stackTopBarTitleContainer {
|
||||
/* INNER-LAYOUT */
|
||||
display: grid;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
/* Page */
|
||||
|
||||
.ParallaxPage-view {
|
||||
--header-height: 49px;
|
||||
|
||||
/* SELF-LAYOUT */
|
||||
/* Adding 60px to make it fully visible below iOS Safari's bottom UI */
|
||||
/* Subtracting 1px to avoid sub-pixel gap in Safari */
|
||||
height: calc(
|
||||
var(--silk-100-lvh-dvh-pct) + 60px -
|
||||
(env(safe-area-inset-top, 0px) + var(--header-height) + 1px)
|
||||
);
|
||||
top: calc(env(safe-area-inset-top, 0px) + var(--header-height) - 1px);
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.ParallaxPage-view {
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) - var(--header-height));
|
||||
}
|
||||
}
|
||||
|
||||
.ParallaxPage-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: white;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
|
||||
/* Page top bar elements */
|
||||
|
||||
.ParallaxPage-topBarDismissTrigger {
|
||||
/* SELF-LAYOUT */
|
||||
grid-area: 1 / 1;
|
||||
align-self: center;
|
||||
margin-left: -14px;
|
||||
width: 36px;
|
||||
height: 44px;
|
||||
|
||||
/* APPEARANCE */
|
||||
border-radius: 12px;
|
||||
outline-offset: -5px;
|
||||
appearance: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
|
||||
/* INTERACTIVITY */
|
||||
cursor: pointer;
|
||||
|
||||
/* TRANSFORMATION */
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
padding: 0;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.ParallaxPage-topBarDismissIcon {
|
||||
/* SELF-LAYOUT */
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
|
||||
/* APPEARANCE */
|
||||
color: rgb(75, 85, 99);
|
||||
}
|
||||
|
||||
.ParallaxPage-topBarTitle {
|
||||
/* SELF-LAYOUT */
|
||||
grid-area: 1 / 1;
|
||||
max-width: 100%;
|
||||
|
||||
/* APPEARANCE */
|
||||
opacity: 0;
|
||||
|
||||
/* TEXT */
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
font-size: 17.25px;
|
||||
font-weight: 620;
|
||||
color: rgb(31, 41, 55);
|
||||
}
|
||||
@@ -1,464 +0,0 @@
|
||||
import React, { createContext, useContext, useRef, useState } from 'react'
|
||||
import { createComponentId, Island, Sheet, SheetStack } from '@silk-hq/components'
|
||||
import './ParallaxPage.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Utils
|
||||
// ================================================================================================
|
||||
|
||||
const setRefs = <T, >(...refs: (React.Ref<T> | undefined)[]): ((node: T) => void) => {
|
||||
return (node: T) => {
|
||||
refs.forEach((ref) => {
|
||||
if (typeof ref === 'function') {
|
||||
ref(node)
|
||||
} else if (ref) {
|
||||
// @ts-ignore - intentionally breaking the readonly nature for compatibility
|
||||
ref.current = node
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Id
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPageExampleStackId = createComponentId()
|
||||
|
||||
// ================================================================================================
|
||||
// StackRoot Context
|
||||
// ================================================================================================
|
||||
|
||||
type ParallaxPageStackRootContextValue = {
|
||||
pageContainer: HTMLElement | null;
|
||||
setPageContainer: React.Dispatch<React.SetStateAction<HTMLElement | null>>;
|
||||
dismissTriggerContainerRef: React.RefObject<HTMLDivElement>;
|
||||
topBarTitleContainerRef: React.RefObject<HTMLDivElement>;
|
||||
};
|
||||
|
||||
const ParallaxPageStackRootContext = createContext<ParallaxPageStackRootContextValue | null>(null)
|
||||
const useParallaxPageStackRootContext = () => {
|
||||
const context = useContext(ParallaxPageStackRootContext)
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useParallaxPageStackRootContext must be used within a ParallaxPageStackRootContext'
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Root
|
||||
// ================================================================================================
|
||||
|
||||
// In this component, the stack root is designed to receive the
|
||||
// parallax page Views.
|
||||
|
||||
const ParallaxPageStackRoot = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetStack.Root>
|
||||
>(({ componentId, ...restProps }, ref) => {
|
||||
const [pageContainer, setPageContainer] = useState<HTMLElement | null>(null)
|
||||
const dismissTriggerContainerRef = useRef<HTMLDivElement>(null)
|
||||
const topBarTitleContainerRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
return (
|
||||
<ParallaxPageStackRootContext.Provider
|
||||
value={{
|
||||
pageContainer,
|
||||
setPageContainer,
|
||||
dismissTriggerContainerRef,
|
||||
topBarTitleContainerRef,
|
||||
}}
|
||||
>
|
||||
<SheetStack.Root
|
||||
// Using a componentId to associate the SheetStack
|
||||
// with the ParallaxPageStackIslandRoot
|
||||
componentId={componentId ?? ParallaxPageExampleStackId}
|
||||
{...restProps}
|
||||
ref={setRefs(ref, setPageContainer)}
|
||||
/>
|
||||
</ParallaxPageStackRootContext.Provider>
|
||||
)
|
||||
})
|
||||
ParallaxPageStackRoot.displayName = 'ParallaxPageStack.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Scenery Outlet
|
||||
// ================================================================================================
|
||||
|
||||
// An outlet meant to wrap the content below the stack for the
|
||||
// initial parallax effect.
|
||||
|
||||
const ParallaxPageStackSceneryOutlet = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Outlet>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetStack.Outlet>
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<SheetStack.Outlet
|
||||
stackingAnimation={{
|
||||
transformOrigin: '50% 0px',
|
||||
translateX: ({ progress }) => (progress <= 1 ? progress * -80 + 'px' : '-80px'),
|
||||
}}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageStackSceneryOutlet.displayName = 'ParallaxPageStack.SceneryOutlet'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Island Root
|
||||
// ================================================================================================
|
||||
|
||||
// An Island meant to wrap the top bar, but which can be used
|
||||
// elsewhere as well.
|
||||
|
||||
const ParallaxPageStackIslandRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Island.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof Island.Root>
|
||||
>(({ forComponent, ...restProps }, ref) => {
|
||||
return (
|
||||
<Island.Root
|
||||
forComponent={forComponent ?? ParallaxPageExampleStackId}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageStackIslandRoot.displayName = 'ParallaxPageStack.IslandRoot'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Island Content
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPageStackIslandContent = Island.Content
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Top Bar Dismiss Trigger Container
|
||||
// ================================================================================================
|
||||
|
||||
// A container meant to receive the parallax pages dismiss
|
||||
// triggers in the top bar.
|
||||
|
||||
const ParallaxPageStackTopBarDismissTriggerContainer = ({
|
||||
className,
|
||||
...restProps
|
||||
}: React.ComponentPropsWithoutRef<'div'>) => {
|
||||
const { dismissTriggerContainerRef } = useParallaxPageStackRootContext()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`ParallaxPage-stackTopBarDismissTriggerContainer ${className ?? ''}`.trim()}
|
||||
{...restProps}
|
||||
ref={dismissTriggerContainerRef}
|
||||
/>
|
||||
)
|
||||
}
|
||||
ParallaxPageStackTopBarDismissTriggerContainer.displayName =
|
||||
'ParallaxPageStack.TopBarDismissTriggerContainer'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Top Bar Title Outlet
|
||||
// ================================================================================================
|
||||
|
||||
// An outlet meant to wrap the initial title of the top bar.
|
||||
|
||||
const ParallaxPageStackTopBarTitleOutlet = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Outlet>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetStack.Outlet>
|
||||
>(({ stackingAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<SheetStack.Outlet
|
||||
stackingAnimation={{
|
||||
opacity: ({ progress }) => 0.75 - (1 / 0.75) * (progress - 0.25),
|
||||
...stackingAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageStackTopBarTitleOutlet.displayName = 'ParallaxPageStack.TopBarTitleOutlet'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Top Bar Title Container
|
||||
// ================================================================================================
|
||||
|
||||
// A container meant to receive the parallax pages titles in the
|
||||
// top bar.
|
||||
|
||||
const ParallaxPageStackTopBarTitleContainer = ({
|
||||
className,
|
||||
...restProps
|
||||
}: React.ComponentPropsWithoutRef<'div'>) => {
|
||||
const { topBarTitleContainerRef } = useParallaxPageStackRootContext()
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`ParallaxPage-stackTopBarTitleContainer ${className ?? ''}`.trim()}
|
||||
{...restProps}
|
||||
ref={topBarTitleContainerRef}
|
||||
/>
|
||||
)
|
||||
}
|
||||
ParallaxPageStackTopBarTitleContainer.displayName = 'ParallaxPageStack.TopBarTitleContainer'
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type ParallaxPageRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const ParallaxPageRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Root>,
|
||||
ParallaxPageRootProps
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<Sheet.Root
|
||||
license="commercial"
|
||||
// By default, the Sheet will be associated with the
|
||||
// closest SheetStack
|
||||
forComponent="closest"
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageRoot.displayName = 'ParallaxPage.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View Portal
|
||||
// ================================================================================================
|
||||
|
||||
// A portal that will render the View in the stack root by
|
||||
// default.
|
||||
|
||||
const ParallaxPageViewPortal = (props: React.ComponentPropsWithoutRef<typeof Sheet.Portal>) => {
|
||||
const { pageContainer } = useParallaxPageStackRootContext()
|
||||
|
||||
return <Sheet.Portal container={pageContainer as HTMLElement} {...props} />
|
||||
}
|
||||
ParallaxPageViewPortal.displayName = 'ParallaxPage.ViewPortal'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPageView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(
|
||||
(
|
||||
{ className, contentPlacement, swipeOvershoot, nativeEdgeSwipePrevention, ...restProps },
|
||||
ref
|
||||
) => {
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`ParallaxPage-view ${className ?? ''}`.trim()}
|
||||
contentPlacement={contentPlacement ?? 'right'}
|
||||
swipeOvershoot={swipeOvershoot ?? false}
|
||||
nativeEdgeSwipePrevention={nativeEdgeSwipePrevention ?? true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
ParallaxPageView.displayName = 'ParallaxPage.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPageBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ travelAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
travelAnimation={{ opacity: [0, 0.25], ...travelAnimation }}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
ParallaxPageBackdrop.displayName = 'ParallaxPage.Backdrop'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPageContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ stackingAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className="ParallaxPage-content"
|
||||
stackingAnimation={{
|
||||
translateX: ({ progress }) => (progress <= 1 ? progress * -80 + 'px' : '-80px'),
|
||||
...stackingAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageContent.displayName = 'ParallaxPage.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Top Bar Dismiss Trigger Portal
|
||||
// ================================================================================================
|
||||
|
||||
// A portal that will render the dismiss trigger in the top bar
|
||||
// dismiss trigger container by default.
|
||||
|
||||
const ParallaxPageTopBarDismissTriggerPortal = ({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof Sheet.Portal>) => {
|
||||
const { dismissTriggerContainerRef } = useParallaxPageStackRootContext()
|
||||
|
||||
return (
|
||||
<Sheet.Portal container={dismissTriggerContainerRef.current as HTMLElement} {...props}>
|
||||
{children}
|
||||
</Sheet.Portal>
|
||||
)
|
||||
}
|
||||
ParallaxPageTopBarDismissTriggerPortal.displayName = 'ParallaxPage.TopBarDismissTriggerPortal'
|
||||
|
||||
// ================================================================================================
|
||||
// Top Bar Dismiss Trigger
|
||||
// ================================================================================================
|
||||
|
||||
// The top bar dismiss trigger associated with the parallax page.
|
||||
|
||||
const ParallaxPageTopBarDismissTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Trigger>
|
||||
>(({ className, action, travelAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Trigger
|
||||
className={`ParallaxPage-topBarDismissTrigger ${className ?? ''}`.trim()}
|
||||
action={action ?? 'dismiss'}
|
||||
travelAnimation={{
|
||||
visibility: 'visible',
|
||||
opacity: ({ progress }) => (1 / 0.75) * (progress - 0.25),
|
||||
...travelAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
className="ParallaxPage-topBarDismissIcon"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M11.78 5.22a.75.75 0 0 1 0 1.06L8.06 10l3.72 3.72a.75.75 0 1 1-1.06 1.06l-4.25-4.25a.75.75 0 0 1 0-1.06l4.25-4.25a.75.75 0 0 1 1.06 0Z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</Sheet.Trigger>
|
||||
)
|
||||
})
|
||||
ParallaxPageTopBarDismissTrigger.displayName = 'ParallaxPage.TopBarDismissTrigger'
|
||||
|
||||
// ================================================================================================
|
||||
// Top Bar Title Portal
|
||||
// ================================================================================================
|
||||
|
||||
// A portal that will render the top bar title in the top bar
|
||||
// title container by default.
|
||||
|
||||
const ParallaxPageTopBarTitlePortal = ({
|
||||
children,
|
||||
...props
|
||||
}: React.ComponentPropsWithoutRef<typeof Sheet.Outlet>) => {
|
||||
const { topBarTitleContainerRef } = useParallaxPageStackRootContext()
|
||||
|
||||
return (
|
||||
<Sheet.Portal container={topBarTitleContainerRef.current as HTMLElement} {...props}>
|
||||
{children}
|
||||
</Sheet.Portal>
|
||||
)
|
||||
}
|
||||
ParallaxPageTopBarTitlePortal.displayName = 'ParallaxPage.TopBarTitlePortal'
|
||||
|
||||
// ================================================================================================
|
||||
// Top Bar Title
|
||||
// ================================================================================================
|
||||
|
||||
// The top bar title associated with the parallax page.
|
||||
|
||||
const ParallaxPageTopBarTitle = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Outlet>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Outlet>
|
||||
>(({ className, travelAnimation, stackingAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Outlet
|
||||
className={`ParallaxPage-topBarTitle ${className ?? ''}`.trim()}
|
||||
travelAnimation={{
|
||||
opacity: ({ progress }) => (1 / 0.75) * (progress - 0.25),
|
||||
...travelAnimation,
|
||||
}}
|
||||
stackingAnimation={{
|
||||
opacity: ({ progress }) => 0.75 - (1 / 0.75) * (progress - 0.25),
|
||||
...stackingAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
})
|
||||
ParallaxPageTopBarTitle.displayName = 'ParallaxPage.TopBarTitle'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged components
|
||||
// ================================================================================================
|
||||
|
||||
const ParallaxPagePortal = Sheet.Portal
|
||||
const ParallaxPageTrigger = Sheet.Trigger
|
||||
const ParallaxPageHandle = Sheet.Handle
|
||||
const ParallaxPageOutlet = Sheet.Outlet
|
||||
const ParallaxPageTitle = Sheet.Title
|
||||
const ParallaxPageDescription = Sheet.Description
|
||||
|
||||
export const ParallaxPageStack = {
|
||||
// Stack
|
||||
Root: ParallaxPageStackRoot,
|
||||
SceneryOutlet: ParallaxPageStackSceneryOutlet,
|
||||
// Stack top bar components
|
||||
IslandRoot: ParallaxPageStackIslandRoot,
|
||||
IslandContent: ParallaxPageStackIslandContent,
|
||||
TopBarDismissTriggerContainer: ParallaxPageStackTopBarDismissTriggerContainer,
|
||||
TopBarTitleOutlet: ParallaxPageStackTopBarTitleOutlet,
|
||||
TopBarTitleContainer: ParallaxPageStackTopBarTitleContainer,
|
||||
}
|
||||
|
||||
export const ParallaxPage = {
|
||||
// Page
|
||||
Root: ParallaxPageRoot,
|
||||
ViewPortal: ParallaxPageViewPortal,
|
||||
View: ParallaxPageView,
|
||||
Backdrop: ParallaxPageBackdrop,
|
||||
Content: ParallaxPageContent,
|
||||
Trigger: ParallaxPageTrigger,
|
||||
Handle: ParallaxPageHandle,
|
||||
Outlet: ParallaxPageOutlet,
|
||||
Portal: ParallaxPagePortal,
|
||||
Title: ParallaxPageTitle,
|
||||
Description: ParallaxPageDescription,
|
||||
// Top Bar page components
|
||||
TopBarDismissTriggerPortal: ParallaxPageTopBarDismissTriggerPortal,
|
||||
TopBarDismissTrigger: ParallaxPageTopBarDismissTrigger,
|
||||
TopBarTitlePortal: ParallaxPageTopBarTitlePortal,
|
||||
TopBarTitle: ParallaxPageTopBarTitle,
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
.PersistentSheetWithDetent-customBackdrop {
|
||||
/* SELF-LAYOUT */
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: black;
|
||||
|
||||
/* INTERACTIVITY */
|
||||
pointer-events: none;
|
||||
|
||||
/* TRANSFORMATION */
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-themeColorDimmingController {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
top: -10px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
background-color: rgba(63, 165, 225, 1);
|
||||
box-shadow: 0 2px 6px -2px rgb(0, 0, 0, 0.25);
|
||||
|
||||
/* TRANSFORMATION */
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-view {
|
||||
--retracted-height: 76px;
|
||||
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 2;
|
||||
bottom: -1px; /* Avoid subpixel misalignment in Safari */
|
||||
width: 100%;
|
||||
}
|
||||
.PersistentSheetWithDetent-view.onDetent2-true {
|
||||
/* SELF-LAYOUT */
|
||||
/* When resting on the detent 2, we switch the side the view is
|
||||
anchored to to the top. It looks better when mobile browsers'
|
||||
UI expand/collapse. */
|
||||
bottom: initial;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 -2px 6px -2px rgb(0, 0, 0, 0.25);
|
||||
background-color: rgba(63, 165, 225, 1);
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-innerContent {
|
||||
/* INNER-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
position: relative;
|
||||
padding-top: env(safe-area-inset-top, 0px);
|
||||
display: grid;
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-retractedContent {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: var(--retracted-height);
|
||||
}
|
||||
|
||||
.PersistentSheetWithDetent-expandedContent {
|
||||
/* SELF-LAYOUT */
|
||||
place-self: stretch;
|
||||
}
|
||||
@@ -1,327 +0,0 @@
|
||||
"use client";
|
||||
import React, { useState, useRef, useCallback, useEffect, useMemo } from "react";
|
||||
import { Sheet, useThemeColorDimmingOverlay } from "@silk-hq/components";
|
||||
import "./PersistentSheetWithDetent.css";
|
||||
|
||||
// ================================================================================================
|
||||
// Utils
|
||||
// ================================================================================================
|
||||
|
||||
const setRefs = <T,>(...refs: (React.Ref<T> | undefined)[]): ((node: T) => void) => {
|
||||
return (node: T) => {
|
||||
refs.forEach((ref) => {
|
||||
if (typeof ref === "function") {
|
||||
ref(node);
|
||||
} else if (ref) {
|
||||
// @ts-ignore - intentionally breaking the readonly nature for compatibility
|
||||
ref.current = node;
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// Context
|
||||
// ================================================================================================
|
||||
|
||||
type PersistentSheetWithDetentContextValue = {
|
||||
range: { start: number; end: number };
|
||||
setRange: React.Dispatch<React.SetStateAction<{ start: number; end: number }>>;
|
||||
backdropRef: React.RefObject<HTMLDivElement>;
|
||||
themeColorDimmingControllerRef: React.RefObject<HTMLDivElement>;
|
||||
rectractedContentRef: React.RefObject<HTMLDivElement>;
|
||||
expandedContentRef: React.RefObject<HTMLDivElement>;
|
||||
};
|
||||
|
||||
const PersistentSheetWithDetentContext =
|
||||
React.createContext<PersistentSheetWithDetentContextValue | null>(null);
|
||||
|
||||
const usePersistentSheetWithDetentContext = () => {
|
||||
const context = React.useContext(PersistentSheetWithDetentContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"usePersistentSheetWithDetentContext must be used within a PersistentSheetWithDetentContextProvider"
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type PersistentSheetWithDetentRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
};
|
||||
|
||||
const PersistentSheetWithDetentRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Root>,
|
||||
PersistentSheetWithDetentRootProps
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
const [range, setRange] = useState({ start: 0, end: 0 });
|
||||
const backdropRef = useRef<HTMLDivElement>(null);
|
||||
const themeColorDimmingControllerRef = useRef<HTMLDivElement>(null);
|
||||
const rectractedContentRef = useRef<HTMLDivElement>(null);
|
||||
const expandedContentRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
return (
|
||||
<PersistentSheetWithDetentContext.Provider
|
||||
value={{
|
||||
range,
|
||||
setRange,
|
||||
backdropRef,
|
||||
themeColorDimmingControllerRef,
|
||||
rectractedContentRef,
|
||||
expandedContentRef,
|
||||
}}
|
||||
>
|
||||
<Sheet.Root license="commercial" {...restProps} ref={ref}>
|
||||
<Sheet.Portal>
|
||||
{/* Using a custom backdrop because the real one's features are
|
||||
not needed, and to be able to put it outside of the view */}
|
||||
{range.end > 1 && (
|
||||
<>
|
||||
<Sheet.Outlet
|
||||
className="PersistentSheetWithDetent-customBackdrop"
|
||||
ref={backdropRef}
|
||||
/>
|
||||
<div
|
||||
className="PersistentSheetWithDetent-themeColorDimmingController"
|
||||
ref={themeColorDimmingControllerRef}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Sheet.Portal>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
</PersistentSheetWithDetentContext.Provider>
|
||||
);
|
||||
});
|
||||
PersistentSheetWithDetentRoot.displayName = "PersistentSheetWithDetent.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const PersistentSheetWithDetentView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View> & {
|
||||
dimmingColor?: string;
|
||||
}
|
||||
>(({ children, className, dimmingColor, onTravel, ...restProps }, ref) => {
|
||||
const viewRef = useRef<HTMLDivElement>(null);
|
||||
const [inertOutside, setInertOutside] = useState(restProps.inertOutside);
|
||||
|
||||
const {
|
||||
range,
|
||||
setRange,
|
||||
backdropRef,
|
||||
themeColorDimmingControllerRef,
|
||||
rectractedContentRef,
|
||||
expandedContentRef,
|
||||
} = usePersistentSheetWithDetentContext();
|
||||
|
||||
const rangeChangeHandler: NonNullable<
|
||||
React.ComponentProps<typeof Sheet.View>["onTravelRangeChange"]
|
||||
> = useCallback(
|
||||
(newRange) => {
|
||||
setRange(newRange);
|
||||
setInertOutside(newRange.start === 2 && newRange.end === 2);
|
||||
},
|
||||
[setRange]
|
||||
);
|
||||
|
||||
//
|
||||
// Height setter
|
||||
|
||||
// We set the height only when the sheet is resting on a
|
||||
// detent.
|
||||
|
||||
useEffect(() => {
|
||||
const updateHeight = () => {
|
||||
if (viewRef.current && range.start === range.end) {
|
||||
const height = window.innerHeight;
|
||||
viewRef.current.style.height = `${height + 1}px`;
|
||||
}
|
||||
};
|
||||
|
||||
if (range.start === range.end) {
|
||||
updateHeight();
|
||||
}
|
||||
|
||||
visualViewport?.addEventListener("resize", updateHeight);
|
||||
|
||||
return () => {
|
||||
visualViewport?.removeEventListener("resize", updateHeight);
|
||||
};
|
||||
}, [range.start, range.end]);
|
||||
|
||||
useEffect(() => {setInertOutside(restProps.inertOutside)}, [restProps.inertOutside]);
|
||||
|
||||
//
|
||||
// Travel handler
|
||||
|
||||
// We use a travel handler instead of travel animations because
|
||||
// it is not (yet) to define animation based on the progress
|
||||
// during a specific range.
|
||||
|
||||
const { setDimmingOverlayOpacity } = useThemeColorDimmingOverlay({
|
||||
elementRef: themeColorDimmingControllerRef,
|
||||
dimmingColor: dimmingColor ?? "rgba(63, 165, 225, 1)",
|
||||
});
|
||||
|
||||
const travelHandler: NonNullable<React.ComponentProps<typeof Sheet.View>["onTravel"]> =
|
||||
useCallback(
|
||||
(data) => {
|
||||
if (typeof onTravel === 'function') {
|
||||
onTravel(data)
|
||||
}
|
||||
|
||||
const { progress, range, progressAtDetents } = data
|
||||
if (!progressAtDetents) return;
|
||||
|
||||
if (range.end > 1) {
|
||||
const normalisedProgress = (progress - progressAtDetents[1]) / (1 - progressAtDetents[1]);
|
||||
|
||||
setDimmingOverlayOpacity(normalisedProgress);
|
||||
|
||||
rectractedContentRef.current?.style.setProperty(
|
||||
"opacity",
|
||||
(1 - normalisedProgress) as unknown as string
|
||||
);
|
||||
backdropRef.current?.style.setProperty(
|
||||
"opacity",
|
||||
(normalisedProgress * 0.25) as unknown as string
|
||||
);
|
||||
expandedContentRef.current?.style.setProperty(
|
||||
"opacity",
|
||||
normalisedProgress as unknown as string
|
||||
);
|
||||
}
|
||||
},
|
||||
[setDimmingOverlayOpacity]
|
||||
);
|
||||
|
||||
//
|
||||
// Return
|
||||
|
||||
const onDetent2 = useMemo(() => range.start === 2 && range.end === 2, [range.start, range.end]);
|
||||
|
||||
return (
|
||||
<Sheet.View
|
||||
ref={setRefs(viewRef, ref)}
|
||||
className={`PersistentSheetWithDetent-view onDetent2-${onDetent2} ${className ?? ""}`.trim()}
|
||||
detents="max(env(safe-area-inset-bottom, 0px) - 10px + var(--retracted-height), var(--retracted-height))"
|
||||
swipeOvershoot={false}
|
||||
swipeDismissal={false}
|
||||
onTravelRangeChange={rangeChangeHandler}
|
||||
inertOutside={inertOutside}
|
||||
onClickOutside={{ dismiss: range.end === 2 }}
|
||||
onTravel={travelHandler}
|
||||
nativeEdgeSwipePrevention={range.end !== 1}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
);
|
||||
});
|
||||
PersistentSheetWithDetentView.displayName = "PersistentSheetWithDetent.View";
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const PersistentSheetWithDetentContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`PersistentSheetWithDetent-content ${className ?? ""}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.SpecialWrapper.Root>
|
||||
<Sheet.SpecialWrapper.Content>
|
||||
<div className="PersistentSheetWithDetent-innerContent">{children}</div>
|
||||
</Sheet.SpecialWrapper.Content>
|
||||
</Sheet.SpecialWrapper.Root>
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
PersistentSheetWithDetentContent.displayName = "PersistentSheetWithDetent.Content";
|
||||
|
||||
// ================================================================================================
|
||||
// Retracted Content
|
||||
// ================================================================================================
|
||||
|
||||
const PersistentSheetWithDetentRetractedContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const { range, rectractedContentRef } = usePersistentSheetWithDetentContext();
|
||||
|
||||
if (range.start >= 2) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`PersistentSheetWithDetent-retractedContent ${className ?? ""}`.trim()}
|
||||
ref={setRefs(rectractedContentRef, ref)}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
PersistentSheetWithDetentRetractedContent.displayName =
|
||||
"PersistentSheetWithDetent.RetractedContent";
|
||||
|
||||
// ================================================================================================
|
||||
// Expanded Content
|
||||
// ================================================================================================
|
||||
|
||||
const PersistentSheetWithDetentExpandedContent = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const { range, expandedContentRef } = usePersistentSheetWithDetentContext();
|
||||
|
||||
if (range.end <= 1) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`PersistentSheetWithDetent-expandedContent ${className ?? ""}`.trim()}
|
||||
ref={setRefs(expandedContentRef, ref)}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
PersistentSheetWithDetentExpandedContent.displayName = "PersistentSheetWithDetent.ExpandedContent";
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged components
|
||||
// ================================================================================================
|
||||
|
||||
const PersistentSheetWithDetentPortal = Sheet.Portal;
|
||||
const PersistentSheetWithDetentTrigger = Sheet.Trigger;
|
||||
const PersistentSheetWithDetentHandle = Sheet.Handle;
|
||||
const PersistentSheetWithOutlet = Sheet.Outlet;
|
||||
const PersistentSheetWithTitle = Sheet.Title;
|
||||
const PersistentSheetWithDescription = Sheet.Description;
|
||||
|
||||
export const PersistentSheetWithDetent = {
|
||||
Root: PersistentSheetWithDetentRoot,
|
||||
Portal: PersistentSheetWithDetentPortal,
|
||||
View: PersistentSheetWithDetentView,
|
||||
Content: PersistentSheetWithDetentContent,
|
||||
Trigger: PersistentSheetWithDetentTrigger,
|
||||
Handle: PersistentSheetWithDetentHandle,
|
||||
RetractedContent: PersistentSheetWithDetentRetractedContent,
|
||||
ExpandedContent: PersistentSheetWithDetentExpandedContent,
|
||||
Outlet: PersistentSheetWithOutlet,
|
||||
Title: PersistentSheetWithTitle,
|
||||
Description: PersistentSheetWithDescription,
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
/* Stack Scenery */
|
||||
|
||||
.SheetWithDepth-stackSceneryBackground {
|
||||
/* SELF-LAYOUT */
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: black;
|
||||
opacity: 0;
|
||||
|
||||
will-change: opacity;
|
||||
}
|
||||
.SheetWithDepth-stackSceneryBackground.nativePageScrollReplaced-true {
|
||||
/* APPEARANCE */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.SheetWithDepth-stackSceneryContainer {
|
||||
/* INNER-LAYOUT */
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.SheetWithDepth-stackSceneryFirstSheetBackdrop {
|
||||
/* SELF-LAYOUT */
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
inset: 0;
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: rgb(0, 0, 0);
|
||||
opacity: 0;
|
||||
|
||||
/* INTERACTIVITY */
|
||||
pointer-events: none;
|
||||
|
||||
/* MISCELLANEOUS */
|
||||
will-change: opacity;
|
||||
}
|
||||
|
||||
/* Sheet */
|
||||
|
||||
.SheetWithDepth-view {
|
||||
/* SELF-LAYOUT */
|
||||
top: 0;
|
||||
bottom: initial;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's
|
||||
bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
|
||||
.SheetWithDepth-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
height: calc(100% - max(calc(env(safe-area-inset-top) + 1.3vh), 2.6vh));
|
||||
}
|
||||
|
||||
.SheetWithDepth-bleedingBackground {
|
||||
/* APPEARANCE */
|
||||
border-radius: 24px 24px 0 0;
|
||||
background-color: white;
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
}
|
||||
@@ -1,434 +0,0 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
Sheet,
|
||||
SheetStack,
|
||||
animate,
|
||||
useThemeColorDimmingOverlay,
|
||||
usePageScrollData,
|
||||
SheetViewProps,
|
||||
createComponentId,
|
||||
} from '@silk-hq/components'
|
||||
import './SheetWithDepth.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Id
|
||||
// ================================================================================================
|
||||
|
||||
const sheetWithDepthStackId = createComponentId()
|
||||
|
||||
// ================================================================================================
|
||||
// StackRoot Context
|
||||
// ================================================================================================
|
||||
|
||||
type SheetWithDepthStackRootContextValue = {
|
||||
stackBackgroundRef: React.RefObject<HTMLDivElement>;
|
||||
stackFirstSheetBackdropRef: React.RefObject<HTMLDivElement>;
|
||||
stackingCount: number;
|
||||
setStackingCount: React.Dispatch<React.SetStateAction<number>>;
|
||||
};
|
||||
|
||||
const SheetWithDepthStackRootContext = createContext<SheetWithDepthStackRootContextValue | null>(
|
||||
null
|
||||
)
|
||||
const useSheetWithDepthStackRootContext = () => {
|
||||
const context = useContext(SheetWithDepthStackRootContext)
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useSheetWithDepthStackRootContext must be used within a SheetWithDepthStackRootContext'
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// View Context
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthViewContext = createContext<{
|
||||
indexInStack: number;
|
||||
} | null>(null)
|
||||
const useSheetWithDepthViewContext = () => {
|
||||
const context = useContext(SheetWithDepthViewContext)
|
||||
if (!context) {
|
||||
throw new Error('useSheetWithDepthViewContext must be used within a SheetWithDepthViewContext')
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
// ================================================================================================
|
||||
// StackRoot
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthStackRoot = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Root>,
|
||||
React.ComponentProps<typeof SheetStack.Root>
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
const stackBackgroundRef = useRef<HTMLDivElement | null>(null)
|
||||
const stackFirstSheetBackdropRef = useRef<HTMLDivElement | null>(null)
|
||||
|
||||
const [stackingCount, setStackingCount] = useState(0)
|
||||
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
stackBackgroundRef,
|
||||
stackFirstSheetBackdropRef,
|
||||
stackingCount,
|
||||
setStackingCount,
|
||||
}),
|
||||
[stackingCount]
|
||||
)
|
||||
|
||||
return (
|
||||
<SheetWithDepthStackRootContext.Provider value={contextValue}>
|
||||
<SheetStack.Root componentId={sheetWithDepthStackId} {...restProps} ref={ref}>
|
||||
{children}
|
||||
</SheetStack.Root>
|
||||
</SheetWithDepthStackRootContext.Provider>
|
||||
)
|
||||
})
|
||||
SheetWithDepthStackRoot.displayName = 'SheetWithDepthStack.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// StackSceneryOutlets
|
||||
// ================================================================================================
|
||||
|
||||
// The SheetStack outlets that define the scenery of the stack
|
||||
// (i.e. the content underneath) for the depth effect.
|
||||
|
||||
const isIOS = window.navigator.userAgent?.match(/iPhone|iPad/i)
|
||||
const initialTopOffset = isIOS ?
|
||||
'max(env(safe-area-inset-top), 1.3vh)' : 'max(var(--safe-area-inset-top), 1.3vh)'
|
||||
|
||||
const SheetWithDepthStackSceneryOutlets = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Outlet>,
|
||||
Omit<React.ComponentProps<typeof SheetStack.Outlet>, 'asChild'>
|
||||
>(({ children, className, stackingAnimation: stackingAnimationFromProps, ...restProps }, ref) => {
|
||||
const { stackBackgroundRef, stackFirstSheetBackdropRef } = useSheetWithDepthStackRootContext()
|
||||
|
||||
const { nativePageScrollReplaced } = usePageScrollData()
|
||||
|
||||
const [iOSStandalone, setiOSStandalone] = useState(false)
|
||||
useEffect(() => {
|
||||
setiOSStandalone(
|
||||
// @ts-ignore
|
||||
window.navigator.standalone && window.navigator.userAgent?.match(/iPhone|iPad/i)
|
||||
)
|
||||
}, [])
|
||||
|
||||
const stackingAnimation: React.ComponentPropsWithoutRef<
|
||||
typeof Sheet.Outlet
|
||||
>['stackingAnimation'] = {
|
||||
// Clipping & border-radius. We have a different animation
|
||||
// when the native page scroll is replaced, and in iOS
|
||||
// standalone mode.
|
||||
...(nativePageScrollReplaced
|
||||
? iOSStandalone
|
||||
? // In iOS standalone mode we don't need to animate the
|
||||
// border-radius because the corners are hidden by the
|
||||
// screen corners. So we just set the border-radius to
|
||||
// the needed value.
|
||||
{
|
||||
overflow: 'clip',
|
||||
borderRadius: '24px',
|
||||
transformOrigin: '50% 0',
|
||||
}
|
||||
: // Outside of iOS standalone mode we do animate
|
||||
// the border-radius because the scenery is a visible
|
||||
// rectangle.
|
||||
{
|
||||
overflow: 'clip',
|
||||
borderRadius: ({ progress }: any) => Math.min(progress * 24, 24) + 'px',
|
||||
transformOrigin: '50% 0',
|
||||
}
|
||||
: // When the native page scroll is not replaced we
|
||||
// need to use the Silk's special clip properties to cut
|
||||
// off the rest of the page.
|
||||
{
|
||||
clipBoundary: 'layout-viewport',
|
||||
clipBorderRadius: '24px',
|
||||
clipTransformOrigin: '50% 0',
|
||||
}),
|
||||
|
||||
// Translate & scale
|
||||
translateY: ({ progress }) =>
|
||||
progress <= 1
|
||||
? 'calc(' + progress + ' * ' + initialTopOffset + ')'
|
||||
: // prettier-ignore
|
||||
'calc(' + initialTopOffset + ' + 0.65vh * ' + (progress - 1) + ')',
|
||||
scale: [1, 0.91],
|
||||
|
||||
// We merge animations coming from the props
|
||||
...stackingAnimationFromProps,
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Element used as a black background representing the void under the stack. */}
|
||||
<div
|
||||
className={`SheetWithDepth-stackSceneryBackground nativePageScrollReplaced-${nativePageScrollReplaced}`}
|
||||
ref={stackBackgroundRef}
|
||||
/>
|
||||
{/* Element used as a container for the content under the stack. */}
|
||||
<SheetStack.Outlet
|
||||
className={`SheetWithDepth-stackSceneryContainer ${className ?? ''}`.trim()}
|
||||
forComponent={sheetWithDepthStackId}
|
||||
stackingAnimation={stackingAnimation}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
{/* Element used as the first sheet's backdrop, which only covers the stackSceneryContainer, not the entire viewport. */}
|
||||
<div
|
||||
className="SheetWithDepth-stackSceneryFirstSheetBackdrop"
|
||||
ref={stackFirstSheetBackdropRef}
|
||||
/>
|
||||
</SheetStack.Outlet>
|
||||
</>
|
||||
)
|
||||
})
|
||||
SheetWithDepthStackSceneryOutlets.displayName = 'SheetWithDepthStack.SceneryOutlets'
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type SheetWithDepthRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const SheetWithDepthRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Root>,
|
||||
SheetWithDepthRootProps
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" forComponent={sheetWithDepthStackId} {...props} ref={ref}/>
|
||||
)
|
||||
})
|
||||
SheetWithDepthRoot.displayName = 'SheetWithDepth.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
// We use animate(), animateDimmingOverlayOpacity() and the
|
||||
// travelHandler instead of relying on stackingAnimation for the
|
||||
// stackSceneryBackground and stackSceneryFirstSheetBackdrop
|
||||
// elements in order to have a different (the default CSS
|
||||
// "ease"), less abrupt animation easing for them.
|
||||
|
||||
const SheetWithDepthView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(
|
||||
(
|
||||
{ children, className, onTravelStatusChange, onTravel: travelHandlerFromProps, ...restProps },
|
||||
ref
|
||||
) => {
|
||||
const {
|
||||
stackingCount,
|
||||
setStackingCount,
|
||||
|
||||
stackBackgroundRef,
|
||||
stackFirstSheetBackdropRef,
|
||||
} = useSheetWithDepthStackRootContext()
|
||||
|
||||
const [indexInStack, setIndexInStack] = useState(0)
|
||||
const [travelStatus, setTravelStatus] = useState('idleOutside')
|
||||
|
||||
//
|
||||
// Define a dimming overlay
|
||||
|
||||
const { setDimmingOverlayOpacity, animateDimmingOverlayOpacity } = useThemeColorDimmingOverlay({
|
||||
elementRef: stackBackgroundRef,
|
||||
dimmingColor: 'rgb(0, 0, 0)',
|
||||
})
|
||||
|
||||
//
|
||||
// travelStatusChangeHandler
|
||||
|
||||
const travelStatusChangeHandler = useCallback<
|
||||
NonNullable<SheetViewProps['onTravelStatusChange']>
|
||||
>(
|
||||
(newTravelStatus) => {
|
||||
// Set indexInStack & stackingCount
|
||||
if (travelStatus !== 'stepping' && newTravelStatus === 'idleInside') {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount + 1)
|
||||
if (indexInStack === 0) {
|
||||
setIndexInStack(stackingCount + 1)
|
||||
}
|
||||
}
|
||||
//
|
||||
else if (newTravelStatus === 'idleOutside') {
|
||||
setStackingCount((prevStackingCount: number) => prevStackingCount - 1)
|
||||
setIndexInStack(0)
|
||||
}
|
||||
|
||||
// Animate on entering
|
||||
if (newTravelStatus === 'entering' && stackingCount === 0) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [0, 1] })
|
||||
animate(stackFirstSheetBackdropRef.current as HTMLElement, {
|
||||
opacity: [0, 0.33],
|
||||
})
|
||||
}
|
||||
|
||||
// Animate on exiting
|
||||
if (newTravelStatus === 'exiting' && stackingCount === 1) {
|
||||
animateDimmingOverlayOpacity({ keyframes: [1, 0] })
|
||||
animate(stackFirstSheetBackdropRef.current as HTMLElement, {
|
||||
opacity: [0.33, 0],
|
||||
})
|
||||
}
|
||||
|
||||
// Set the state
|
||||
onTravelStatusChange?.(newTravelStatus)
|
||||
setTravelStatus(newTravelStatus)
|
||||
},
|
||||
[
|
||||
travelStatus,
|
||||
indexInStack,
|
||||
stackingCount,
|
||||
setStackingCount,
|
||||
stackFirstSheetBackdropRef,
|
||||
animateDimmingOverlayOpacity,
|
||||
onTravelStatusChange,
|
||||
]
|
||||
)
|
||||
|
||||
//
|
||||
// travelHandler
|
||||
|
||||
const travelHandler = useMemo(() => {
|
||||
if (indexInStack === 1 && travelStatus !== 'entering' && travelStatus !== 'exiting') {
|
||||
const handler: NonNullable<SheetViewProps['onTravel']> = ({ progress, ...rest }) => {
|
||||
setDimmingOverlayOpacity(progress)
|
||||
stackFirstSheetBackdropRef.current?.style.setProperty(
|
||||
'opacity',
|
||||
(progress * 0.33) as unknown as string
|
||||
)
|
||||
travelHandlerFromProps?.({ progress, ...rest })
|
||||
}
|
||||
return handler
|
||||
} else {
|
||||
return travelHandlerFromProps
|
||||
}
|
||||
}, [indexInStack, travelStatus, stackFirstSheetBackdropRef, setDimmingOverlayOpacity])
|
||||
|
||||
//
|
||||
// Return
|
||||
|
||||
return (
|
||||
<SheetWithDepthViewContext.Provider value={{ indexInStack }}>
|
||||
<Sheet.View
|
||||
className={`SheetWithDepth-view ${className ?? ''}`.trim()}
|
||||
contentPlacement="bottom"
|
||||
onTravelStatusChange={travelStatusChangeHandler}
|
||||
onTravel={travelHandler}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
</SheetWithDepthViewContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
SheetWithDepthView.displayName = 'SheetWithDepth.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
// @ts-ignore
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
const { stackingCount } = useSheetWithDepthStackRootContext()
|
||||
const { indexInStack } = useSheetWithDepthViewContext()
|
||||
|
||||
return (
|
||||
// We don't render the Backdrop for the first sheet in the
|
||||
// stack, instead we use the stackSceneryFirstSheetBackdrop
|
||||
// element.
|
||||
stackingCount > 0 &&
|
||||
indexInStack !== 1 && (
|
||||
<Sheet.Backdrop
|
||||
className={`SheetWithDepth-backdrop ${className ?? ''}`.trim()}
|
||||
travelAnimation={{ opacity: [0, 0.33] }}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
)
|
||||
)
|
||||
})
|
||||
SheetWithDepthBackdrop.displayName = 'SheetWithDepth.Backdrop'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentProps<typeof Sheet.Content>
|
||||
>(({ children, className, stackingAnimation, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`SheetWithDepth-content ${className ?? ''}`.trim()}
|
||||
stackingAnimation={{
|
||||
translateY: ({ progress }) =>
|
||||
progress <= 1
|
||||
? progress * -1.3 + 'vh'
|
||||
: // prettier-ignore
|
||||
'calc(-1.3vh + 0.65vh * ' + (progress - 1) + ')',
|
||||
scale: [1, 0.91],
|
||||
transformOrigin: '50% 0',
|
||||
...stackingAnimation,
|
||||
}}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.BleedingBackground className="SheetWithDepth-bleedingBackground"/>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
)
|
||||
})
|
||||
SheetWithDepthContent.displayName = 'SheetWithDepth.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged components
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDepthPortal = Sheet.Portal
|
||||
const SheetWithDepthTrigger = Sheet.Trigger
|
||||
const SheetWithDepthHandle = Sheet.Handle
|
||||
const SheetWithDepthOutlet = Sheet.Outlet
|
||||
const SheetWithDepthTitle = Sheet.Title
|
||||
const SheetWithDepthDescription = Sheet.Description
|
||||
|
||||
export const SheetWithDepthStack = {
|
||||
Root: SheetWithDepthStackRoot,
|
||||
SceneryOutlets: SheetWithDepthStackSceneryOutlets,
|
||||
}
|
||||
|
||||
export const SheetWithDepth = {
|
||||
Root: SheetWithDepthRoot,
|
||||
Portal: SheetWithDepthPortal,
|
||||
View: SheetWithDepthView,
|
||||
Content: SheetWithDepthContent,
|
||||
Backdrop: SheetWithDepthBackdrop,
|
||||
Trigger: SheetWithDepthTrigger,
|
||||
Handle: SheetWithDepthHandle,
|
||||
Outlet: SheetWithDepthOutlet,
|
||||
Title: SheetWithDepthTitle,
|
||||
Description: SheetWithDepthDescription,
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
.SheetWithDetent-view {
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
top: 0;
|
||||
bottom: initial;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's
|
||||
bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
|
||||
.SheetWithDetent-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
height: calc(100% - max(env(safe-area-inset-top), 6px));
|
||||
max-width: 800px;
|
||||
|
||||
/* APPEARANCE */
|
||||
border-radius: 24px 24px 0 0;
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
}
|
||||
@media (min-width: 800px) {
|
||||
.SheetWithDetent-content {
|
||||
/* SELF-LAYOUT */
|
||||
height: calc(100% - max(env(safe-area-inset-top), 5vh));
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
border-radius: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.SheetWithDetent-handle {
|
||||
/* SELF-LAYOUT */
|
||||
width: 50px;
|
||||
height: 6px;
|
||||
|
||||
/* APPEARANCE */
|
||||
border: 0;
|
||||
border-radius: 9999px;
|
||||
background-color: rgb(209, 213, 219);
|
||||
|
||||
/* INTERACTIVITY */
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
import React, { createContext, useContext, useMemo, useRef, useState } from "react";
|
||||
import { Sheet, Scroll, type SheetViewProps } from "@silk-hq/components";
|
||||
import "./SheetWithDetent.css";
|
||||
|
||||
// ================================================================================================
|
||||
// Context
|
||||
// ================================================================================================
|
||||
|
||||
type SheetWithDetentContextValue = {
|
||||
reachedLastDetent: boolean;
|
||||
setReachedLastDetent: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
viewRef: React.RefObject<HTMLElement>;
|
||||
};
|
||||
|
||||
const SheetWithDetentContext = createContext<SheetWithDetentContextValue | null>(null);
|
||||
|
||||
const useSheetWithDetentContext = () => {
|
||||
const context = useContext(SheetWithDetentContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
"useSheetWithDetentContext must be used within a SheetWithDetentContextProvider"
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type SheetWithDetentRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
};
|
||||
|
||||
const SheetWithDetentRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Root>,
|
||||
SheetWithDetentRootProps
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
const [reachedLastDetent, setReachedLastDetent] = useState(false);
|
||||
const viewRef = useRef<HTMLElement>(null);
|
||||
|
||||
return (
|
||||
<SheetWithDetentContext.Provider
|
||||
value={{
|
||||
reachedLastDetent,
|
||||
setReachedLastDetent,
|
||||
viewRef,
|
||||
}}
|
||||
>
|
||||
<Sheet.Root license="commercial" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
</SheetWithDetentContext.Provider>
|
||||
);
|
||||
});
|
||||
SheetWithDetentRoot.displayName = "SheetWithDetent.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(
|
||||
(
|
||||
{ children, className, onTravelStatusChange, onTravelRangeChange, onTravel, ...restProps },
|
||||
ref
|
||||
) => {
|
||||
const { reachedLastDetent, setReachedLastDetent, viewRef } = useSheetWithDetentContext();
|
||||
|
||||
//
|
||||
|
||||
const travelHandler = useMemo(() => {
|
||||
if (!reachedLastDetent) return onTravel;
|
||||
|
||||
const handler: SheetViewProps["onTravel"] = ({ progress, ...rest }) => {
|
||||
if (!viewRef.current) return onTravel?.({ progress, ...rest });
|
||||
|
||||
// Dismiss the on-screen keyboard.
|
||||
if (progress < 0.999) {
|
||||
viewRef.current.focus();
|
||||
}
|
||||
onTravel?.({ progress, ...rest });
|
||||
};
|
||||
return handler;
|
||||
}, [reachedLastDetent, onTravel, viewRef]);
|
||||
|
||||
//
|
||||
|
||||
const setRefs = React.useCallback((node: HTMLElement | null) => {
|
||||
// @ts-ignore - intentionally breaking the readonly nature for compatibility
|
||||
viewRef.current = node;
|
||||
|
||||
if (typeof ref === "function") {
|
||||
ref(node);
|
||||
} else if (ref) {
|
||||
ref.current = node;
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`SheetWithDetent-view ${className ?? ""}`.trim()}
|
||||
detents={!reachedLastDetent ? "66vh" : undefined}
|
||||
swipeOvershoot={false}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
onTravelStatusChange={(travelStatus) => {
|
||||
if (travelStatus === "idleOutside") setReachedLastDetent(false);
|
||||
onTravelStatusChange?.(travelStatus);
|
||||
}}
|
||||
onTravelRangeChange={(range) => {
|
||||
if (range.start === 2) setReachedLastDetent(true);
|
||||
onTravelRangeChange?.(range);
|
||||
}}
|
||||
onTravel={travelHandler}
|
||||
ref={setRefs}
|
||||
{...restProps}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
);
|
||||
}
|
||||
);
|
||||
SheetWithDetentView.displayName = "SheetWithDetent.View";
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
className={`SheetWithDetent-backdrop ${className ?? ""}`.trim()}
|
||||
themeColorDimming="auto"
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
SheetWithDetentBackdrop.displayName = "SheetWithDetent.Backdrop";
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`SheetWithDetent-content ${className ?? ""}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
SheetWithDetentContent.displayName = "SheetWithDetent.Content";
|
||||
|
||||
// ================================================================================================
|
||||
// Handle
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentHandle = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Handle>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Handle>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
const { reachedLastDetent } = useSheetWithDetentContext();
|
||||
|
||||
return (
|
||||
<Sheet.Handle
|
||||
className={`SheetWithDetent-handle ${className ?? ""}`.trim()}
|
||||
action={reachedLastDetent ? "dismiss" : "step"}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
SheetWithDetentHandle.displayName = "SheetWithDetent.Handle";
|
||||
|
||||
// ================================================================================================
|
||||
// Scroll Root
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentScrollRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Scroll.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof Scroll.Root>
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<Scroll.Root {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Scroll.Root>
|
||||
);
|
||||
});
|
||||
SheetWithDetentScrollRoot.displayName = "SheetWithDetent.ScrollRoot";
|
||||
|
||||
// ================================================================================================
|
||||
// Scroll View
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentScrollView = React.forwardRef<
|
||||
React.ElementRef<typeof Scroll.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Scroll.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const { reachedLastDetent } = useSheetWithDetentContext();
|
||||
|
||||
return (
|
||||
<Scroll.View
|
||||
className={`SheetWithDetent-scrollView ${className ?? ""}`.trim()}
|
||||
scrollGestureTrap={{ yEnd: true }}
|
||||
scrollGesture={!reachedLastDetent ? false : "auto"}
|
||||
safeArea="layout-viewport"
|
||||
onScrollStart={{ dismissKeyboard: true }}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Scroll.View>
|
||||
);
|
||||
});
|
||||
SheetWithDetentScrollView.displayName = "SheetWithDetent.ScrollView";
|
||||
|
||||
// ================================================================================================
|
||||
// Scroll Content
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentScrollContent = React.forwardRef<
|
||||
React.ElementRef<typeof Scroll.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Scroll.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Scroll.Content
|
||||
className={`SheetWithDetent-scrollContent ${className ?? ""}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Scroll.Content>
|
||||
);
|
||||
});
|
||||
SheetWithDetentScrollContent.displayName = "SheetWithDetent.ScrollContent";
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithDetentPortal = Sheet.Portal;
|
||||
const SheetWithDetentTrigger = Sheet.Trigger;
|
||||
const SheetWithDetentOutlet = Sheet.Outlet;
|
||||
const SheetWithDetentTitle = Sheet.Title;
|
||||
const SheetWithDetentDescription = Sheet.Description;
|
||||
|
||||
export const SheetWithDetent = {
|
||||
Root: SheetWithDetentRoot,
|
||||
Portal: SheetWithDetentPortal,
|
||||
View: SheetWithDetentView,
|
||||
Backdrop: SheetWithDetentBackdrop,
|
||||
Content: SheetWithDetentContent,
|
||||
Trigger: SheetWithDetentTrigger,
|
||||
Handle: SheetWithDetentHandle,
|
||||
Outlet: SheetWithDetentOutlet,
|
||||
Title: SheetWithDetentTitle,
|
||||
Description: SheetWithDetentDescription,
|
||||
//
|
||||
ScrollRoot: SheetWithDetentScrollRoot,
|
||||
ScrollView: SheetWithDetentScrollView,
|
||||
ScrollContent: SheetWithDetentScrollContent,
|
||||
};
|
||||
@@ -1,46 +0,0 @@
|
||||
.SheetWithStacking-view {
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's
|
||||
bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
.SheetWithStacking-view.contentPlacement-right {
|
||||
/* SELF-LAYOUT */
|
||||
height: var(--silk-100-lvh-dvh-pct);
|
||||
}
|
||||
|
||||
.SheetWithStacking-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
height: calc(min(500px, 90svh) + env(safe-area-inset-bottom, 0px));
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: transparent;
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
padding-inline: 0.5rem;
|
||||
padding-block: 0.5rem max(env(safe-area-inset-bottom, 0px), 0.5rem);
|
||||
display: grid;
|
||||
}
|
||||
.SheetWithStacking-content.contentPlacement-right {
|
||||
/* SELF-LAYOUT */
|
||||
height: 100%;
|
||||
width: min(80%, 700px);
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.SheetWithStacking-innerContent {
|
||||
/* SELF-LAYOUT */
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
overflow: hidden;
|
||||
overflow: clip;
|
||||
border-radius: 24px;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -1,199 +0,0 @@
|
||||
import React, { createContext, useContext } from "react";
|
||||
import {
|
||||
Sheet,
|
||||
SheetStack,
|
||||
useClientMediaQuery,
|
||||
type SheetContentProps,
|
||||
} from "@silk-hq/components";
|
||||
import "./SheetWithStacking.css";
|
||||
|
||||
// ================================================================================================
|
||||
// Context
|
||||
// ================================================================================================
|
||||
|
||||
type SheetWithStackingContextValue = {
|
||||
travelStatus: string;
|
||||
setTravelStatus: (status: string) => void;
|
||||
contentPlacement: "right" | "bottom";
|
||||
};
|
||||
|
||||
const SheetWithStackingContext = createContext<SheetWithStackingContextValue | null>(null);
|
||||
|
||||
// ================================================================================================
|
||||
// Stack Root
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithStackingStackRoot = React.forwardRef<
|
||||
React.ElementRef<typeof SheetStack.Root>,
|
||||
React.ComponentPropsWithoutRef<typeof SheetStack.Root>
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<SheetStack.Root {...restProps} ref={ref}>
|
||||
{children}
|
||||
</SheetStack.Root>
|
||||
);
|
||||
});
|
||||
SheetWithStackingStackRoot.displayName = "SheetWithStackingStack.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type SheetWithStackingRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
};
|
||||
|
||||
const SheetWithStackingRoot = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Root>,
|
||||
SheetWithStackingRootProps
|
||||
>(({ children, ...restProps }, ref) => {
|
||||
const [travelStatus, setTravelStatus] = React.useState("idleOutside");
|
||||
const largeViewport = useClientMediaQuery("(min-width: 700px)");
|
||||
const contentPlacement = largeViewport ? "right" : "bottom";
|
||||
|
||||
return (
|
||||
<SheetWithStackingContext.Provider
|
||||
value={{
|
||||
travelStatus,
|
||||
setTravelStatus,
|
||||
contentPlacement,
|
||||
}}
|
||||
>
|
||||
<Sheet.Root license="commercial" forComponent="closest" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
</SheetWithStackingContext.Provider>
|
||||
);
|
||||
});
|
||||
SheetWithStackingRoot.displayName = "SheetWithStacking.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithStackingView = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const context = useContext(SheetWithStackingContext);
|
||||
if (!context)
|
||||
throw new Error(
|
||||
"SheetWithStackingView must be used within a SheetWithStackingContext.Provider"
|
||||
);
|
||||
const { setTravelStatus, contentPlacement } = context;
|
||||
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`SheetWithStacking-view contentPlacement-${contentPlacement} ${className ?? ""}`}
|
||||
contentPlacement={contentPlacement}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
onTravelStatusChange={setTravelStatus}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
);
|
||||
});
|
||||
SheetWithStackingView.displayName = "SheetWithStacking.View";
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithStackingBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>((props, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
travelAnimation={{ opacity: [0, 0.2] }}
|
||||
themeColorDimming="auto"
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
SheetWithStackingBackdrop.displayName = "SheetWithStacking.Backdrop";
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithStackingContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, stackingAnimation: stackingAnimationFromProps, ...restProps }, ref) => {
|
||||
const context = useContext(SheetWithStackingContext);
|
||||
if (!context)
|
||||
throw new Error(
|
||||
"SheetWithStackingContent must be used within a SheetWithStackingContext.Provider"
|
||||
);
|
||||
const { contentPlacement } = context;
|
||||
|
||||
const stackingAnimation: SheetContentProps["stackingAnimation"] =
|
||||
contentPlacement === "right"
|
||||
? {
|
||||
translateX: ({ progress }: { progress: number }) =>
|
||||
progress <= 1
|
||||
? progress * -10 + "px"
|
||||
: // prettier-ignore
|
||||
"calc(-12.5px + 2.5px *" + progress + ")",
|
||||
scale: [1, 0.933],
|
||||
transformOrigin: "0 50%",
|
||||
...stackingAnimationFromProps,
|
||||
}
|
||||
: {
|
||||
translateY: ({ progress }: { progress: number }) =>
|
||||
progress <= 1
|
||||
? progress * -10 + "px"
|
||||
: // prettier-ignore
|
||||
"calc(-12.5px + 2.5px *" + progress + ")",
|
||||
scale: [1, 0.933],
|
||||
transformOrigin: "50% 0",
|
||||
...stackingAnimationFromProps,
|
||||
};
|
||||
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`SheetWithStacking-content contentPlacement-${contentPlacement} ${
|
||||
className ?? ""
|
||||
}`}
|
||||
stackingAnimation={stackingAnimation}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<div className="SheetWithStacking-innerContent">{children}</div>
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
SheetWithStackingContent.displayName = "SheetWithStacking.Content";
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const SheetWithStackingPortal = Sheet.Portal;
|
||||
const SheetWithStackingTrigger = Sheet.Trigger;
|
||||
const SheetWithStackingHandle = Sheet.Handle;
|
||||
const SheetWithStackingOutlet = Sheet.Outlet;
|
||||
const SheetWithStackingTitle = Sheet.Title;
|
||||
const SheetWithStackingDescription = Sheet.Description;
|
||||
|
||||
export const SheetWithStackingStack = {
|
||||
Root: SheetWithStackingStackRoot,
|
||||
};
|
||||
|
||||
export const SheetWithStacking = {
|
||||
Root: SheetWithStackingRoot,
|
||||
View: SheetWithStackingView,
|
||||
Portal: SheetWithStackingPortal,
|
||||
Backdrop: SheetWithStackingBackdrop,
|
||||
Content: SheetWithStackingContent,
|
||||
Trigger: SheetWithStackingTrigger,
|
||||
Handle: SheetWithStackingHandle,
|
||||
Outlet: SheetWithStackingOutlet,
|
||||
Title: SheetWithStackingTitle,
|
||||
Description: SheetWithStackingDescription,
|
||||
};
|
||||
@@ -1,16 +0,0 @@
|
||||
.Sidebar-view {
|
||||
/* SELF-LAYOUT */
|
||||
z-index: 1;
|
||||
/* Adding 60px to make it fully visible below iOS Safari's bottom UI */
|
||||
height: calc(var(--silk-100-lvh-dvh-pct) + 60px);
|
||||
}
|
||||
|
||||
.Sidebar-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: min(90vw, 325px);
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
background-color: white;
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
"use client";
|
||||
import React from "react";
|
||||
import { Sheet, VisuallyHidden } from "@silk-hq/components";
|
||||
import "./Sidebar.css";
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type SidebarRootProps = Omit<SheetRootProps, "license"> & {
|
||||
license?: SheetRootProps["license"];
|
||||
};
|
||||
|
||||
const SidebarRoot = React.forwardRef<React.ElementRef<typeof Sheet.Root>, SidebarRootProps>(
|
||||
({ children, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Root license="commercial" sheetRole="dialog" {...restProps} ref={ref}>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
);
|
||||
}
|
||||
);
|
||||
SidebarRoot.displayName = "Sidebar.Root";
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const SidebarView = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.View>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.View
|
||||
className={`Sidebar-view ${className ?? ""}`.trim()}
|
||||
contentPlacement="left"
|
||||
swipeOvershoot={false}
|
||||
nativeEdgeSwipePrevention={true}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
);
|
||||
});
|
||||
SidebarView.displayName = "Sidebar.View";
|
||||
|
||||
// ================================================================================================
|
||||
// Backdrop
|
||||
// ================================================================================================
|
||||
|
||||
const SidebarBackdrop = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Backdrop>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Backdrop>
|
||||
>(({ className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Backdrop
|
||||
className={`Sidebar-backdrop ${className ?? ""}`.trim()}
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
SidebarBackdrop.displayName = "Sidebar.Backdrop";
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const SidebarContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
return (
|
||||
<Sheet.Content className={`Sidebar-content ${className ?? ""}`.trim()} {...restProps} ref={ref}>
|
||||
<VisuallyHidden.Root>
|
||||
<Sheet.Title>Sidebar Example</Sheet.Title>
|
||||
<Sheet.Trigger action="dismiss">Close Sidebar example</Sheet.Trigger>
|
||||
</VisuallyHidden.Root>
|
||||
{children}
|
||||
</Sheet.Content>
|
||||
);
|
||||
});
|
||||
SidebarContent.displayName = "Sidebar.Content";
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const SidebarPortal = Sheet.Portal;
|
||||
const SidebarTrigger = Sheet.Trigger;
|
||||
const SidebarHandle = Sheet.Handle;
|
||||
const SidebarOutlet = Sheet.Outlet;
|
||||
const SidebarTitle = Sheet.Title;
|
||||
const SidebarDescription = Sheet.Description;
|
||||
|
||||
export const Sidebar = {
|
||||
Root: SidebarRoot,
|
||||
Portal: SidebarPortal,
|
||||
View: SidebarView,
|
||||
Backdrop: SidebarBackdrop,
|
||||
Content: SidebarContent,
|
||||
Trigger: SidebarTrigger,
|
||||
Handle: SidebarHandle,
|
||||
Outlet: SidebarOutlet,
|
||||
Title: SidebarTitle,
|
||||
Description: SidebarDescription,
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
.Toast-container {
|
||||
/* SELF-LAYOUT */
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.Toast-view {
|
||||
--padding-x: 0.75rem;
|
||||
--padding-top: 0.75rem;
|
||||
--padding-bottom: 2.75rem;
|
||||
--max-height: 90px;
|
||||
--contentHeight: calc(
|
||||
max(env(safe-area-inset-top, 0px), var(--padding-top)) + var(--max-height) +
|
||||
var(--padding-bottom)
|
||||
);
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.Toast-view {
|
||||
--padding-x: 0.875rem;
|
||||
--padding-top: 0.875rem;
|
||||
|
||||
/* SELF-LAYOUT */
|
||||
height: var(--contentHeight);
|
||||
}
|
||||
}
|
||||
|
||||
.Toast-content {
|
||||
/* SELF-LAYOUT */
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
height: var(--contentHeight);
|
||||
|
||||
/* APPEARANCE */
|
||||
background-color: transparent;
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
padding: var(--padding-x);
|
||||
padding-top: max(env(safe-area-inset-top), var(--padding-top));
|
||||
padding-bottom: var(--padding-bottom);
|
||||
display: grid;
|
||||
}
|
||||
@media (min-width: 1000px) {
|
||||
.Toast-content {
|
||||
/* SELF-LAYOUT */
|
||||
max-width: 400px;
|
||||
|
||||
/* INNER-LAYOUT */
|
||||
padding-top: var(--padding-top);
|
||||
}
|
||||
}
|
||||
|
||||
.Toast-innerContent {
|
||||
/* SELF-LAYOUT */
|
||||
max-height: var(--max-height);
|
||||
|
||||
/* APPEARANCE */
|
||||
box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
border-radius: 24px;
|
||||
border: 1px solid rgb(240, 240, 240);
|
||||
background-color: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: saturate(5) blur(20px);
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
import React, { useEffect, useState, useRef, createContext, useContext } from 'react'
|
||||
import { Sheet, useClientMediaQuery } from '@silk-hq/components'
|
||||
import './Toast.css'
|
||||
|
||||
// ================================================================================================
|
||||
// Context
|
||||
// ================================================================================================
|
||||
|
||||
type ToastContextValue = {
|
||||
presented: boolean;
|
||||
setPresented: (presented: boolean) => void;
|
||||
pointerOver: boolean;
|
||||
setPointerOver: (pointerOver: boolean) => void;
|
||||
travelStatus: string;
|
||||
setTravelStatus: (status: string) => void;
|
||||
};
|
||||
|
||||
const ToastContext = createContext<ToastContextValue | null>(null)
|
||||
|
||||
// ================================================================================================
|
||||
// Root
|
||||
// ================================================================================================
|
||||
|
||||
type SheetRootProps = React.ComponentPropsWithoutRef<typeof Sheet.Root>;
|
||||
type ToastRootProps = Omit<SheetRootProps, 'license'> & {
|
||||
license?: SheetRootProps['license'];
|
||||
};
|
||||
|
||||
const ToastRoot = React.forwardRef<React.ElementRef<typeof Sheet.Root>, ToastRootProps>(
|
||||
({ children, ...restProps }, ref) => {
|
||||
const [presented, setPresented] = useState(false)
|
||||
const [pointerOver, setPointerOver] = useState(false)
|
||||
const [travelStatus, setTravelStatus] = useState('idleOutside')
|
||||
const autoCloseTimeout = useRef<ReturnType<typeof setTimeout> | undefined>()
|
||||
|
||||
useEffect(() => {
|
||||
const startAutoCloseTimeout = () => {
|
||||
autoCloseTimeout.current = setTimeout(() => setPresented(false), 5000)
|
||||
}
|
||||
|
||||
const clearAutoCloseTimeout = () => {
|
||||
clearTimeout(autoCloseTimeout.current)
|
||||
}
|
||||
|
||||
if (presented) {
|
||||
if (travelStatus === 'idleInside' && !pointerOver) {
|
||||
startAutoCloseTimeout()
|
||||
} else {
|
||||
clearAutoCloseTimeout()
|
||||
}
|
||||
}
|
||||
return clearAutoCloseTimeout
|
||||
}, [presented, travelStatus, pointerOver])
|
||||
|
||||
return (
|
||||
<ToastContext.Provider
|
||||
value={{
|
||||
presented,
|
||||
setPresented,
|
||||
pointerOver,
|
||||
setPointerOver,
|
||||
travelStatus,
|
||||
setTravelStatus,
|
||||
}}
|
||||
>
|
||||
<Sheet.Root
|
||||
license="commercial"
|
||||
presented={presented}
|
||||
onPresentedChange={setPresented}
|
||||
sheetRole=""
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</Sheet.Root>
|
||||
</ToastContext.Provider>
|
||||
)
|
||||
}
|
||||
)
|
||||
ToastRoot.displayName = 'Toast.Root'
|
||||
|
||||
// ================================================================================================
|
||||
// View
|
||||
// ================================================================================================
|
||||
|
||||
const ToastView = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.View>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const largeViewport = useClientMediaQuery('(min-width: 1000px)')
|
||||
const contentPlacement = largeViewport ? 'right' : 'top'
|
||||
|
||||
const context = useContext(ToastContext)
|
||||
if (!context) throw new Error('ToastView must be used within a ToastContext.Provider')
|
||||
const { setTravelStatus } = context
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`Toast-container ${className ?? ''}`.trim()}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.View
|
||||
className={`Toast-view ${className ?? ''}`.trim()}
|
||||
contentPlacement={contentPlacement}
|
||||
inertOutside={false}
|
||||
onPresentAutoFocus={{ focus: false }}
|
||||
onDismissAutoFocus={{ focus: false }}
|
||||
onClickOutside={{
|
||||
dismiss: false,
|
||||
stopOverlayPropagation: false,
|
||||
}}
|
||||
onEscapeKeyDown={{
|
||||
dismiss: false,
|
||||
stopOverlayPropagation: false,
|
||||
}}
|
||||
onTravelStatusChange={setTravelStatus}
|
||||
>
|
||||
{children}
|
||||
</Sheet.View>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
ToastView.displayName = 'Toast.View'
|
||||
|
||||
// ================================================================================================
|
||||
// Content
|
||||
// ================================================================================================
|
||||
|
||||
const ToastContent = React.forwardRef<
|
||||
React.ElementRef<typeof Sheet.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof Sheet.Content>
|
||||
>(({ children, className, ...restProps }, ref) => {
|
||||
const context = useContext(ToastContext)
|
||||
if (!context) throw new Error('ToastContent must be used within ToastRoot')
|
||||
|
||||
return (
|
||||
<Sheet.Content
|
||||
className={`Toast-content ${className ?? ''}`.trim()}
|
||||
asChild
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
>
|
||||
<Sheet.SpecialWrapper.Root>
|
||||
<Sheet.SpecialWrapper.Content
|
||||
className="Toast-innerContent"
|
||||
onPointerEnter={() => context.setPointerOver(true)}
|
||||
onPointerLeave={() => context.setPointerOver(false)}
|
||||
>
|
||||
{children}
|
||||
</Sheet.SpecialWrapper.Content>
|
||||
</Sheet.SpecialWrapper.Root>
|
||||
</Sheet.Content>
|
||||
)
|
||||
})
|
||||
ToastContent.displayName = 'Toast.Content'
|
||||
|
||||
// ================================================================================================
|
||||
// Unchanged Components
|
||||
// ================================================================================================
|
||||
|
||||
const ToastPortal = Sheet.Portal
|
||||
const ToastTrigger = Sheet.Trigger
|
||||
const ToastHandle = Sheet.Handle
|
||||
const ToastOutlet = Sheet.Outlet
|
||||
const ToastTitle = Sheet.Title
|
||||
const ToastDescription = Sheet.Description
|
||||
|
||||
export const Toast = {
|
||||
Root: ToastRoot,
|
||||
Portal: ToastPortal,
|
||||
View: ToastView,
|
||||
Content: ToastContent,
|
||||
Trigger: ToastTrigger,
|
||||
Title: ToastTitle,
|
||||
Description: ToastDescription,
|
||||
Handle: ToastHandle,
|
||||
Outlet: ToastOutlet,
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import '@silk-hq/components/dist/main-unlayered.css'
|
||||
import { Fixed, Scroll, Sheet } from '@silk-hq/components'
|
||||
import { BottomSheet } from './BottomSheet'
|
||||
import { SheetWithDepth, SheetWithDepthStack } from './SheetWithDepth'
|
||||
import { SheetWithDetent } from './SheetWithDetent'
|
||||
import { SheetWithStacking, SheetWithStackingStack } from './SheetWithStacking'
|
||||
import { ParallaxPage, ParallaxPageStack } from './ParallaxPage'
|
||||
import { Toast } from './Toast'
|
||||
import { Card } from './Card'
|
||||
import { Page } from './Page'
|
||||
import { Sidebar } from './Sidebar'
|
||||
import { PersistentSheetWithDetent } from './PersistentSheetWithDetent'
|
||||
|
||||
declare global {
|
||||
var LSSilkhq: any
|
||||
}
|
||||
|
||||
const silkhq = {
|
||||
Sheet, Fixed, Scroll, BottomSheet,
|
||||
SheetWithDepth, SheetWithDepthStack,
|
||||
SheetWithStacking, SheetWithDetent,
|
||||
SheetWithStackingStack,
|
||||
ParallaxPage, ParallaxPageStack,
|
||||
Toast, CardSheet: Card, Page, Sidebar, PersistentSheetWithDetent
|
||||
}
|
||||
|
||||
window.LSSilkhq = silkhq
|
||||
|
||||
export default silkhq
|
||||
@@ -3786,11 +3786,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.1.tgz#78244efe12930c56fd255d7923865857c41ac8cb"
|
||||
integrity sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==
|
||||
|
||||
"@silk-hq/components@^0.9.10":
|
||||
version "0.9.10"
|
||||
resolved "https://registry.yarnpkg.com/@silk-hq/components/-/components-0.9.10.tgz#ed6baa898b4f36ce0e5ecadabfecef748546db74"
|
||||
integrity sha512-dr6NRdGR2vovh4Uv27IhnkvpcUwHR9D7YZLCxTE6fyl4Zb6K6cGUlWVo3b3tgfCHVyirvrRvqWOF2nxMVlmVXg==
|
||||
|
||||
"@sinclair/typebox@^0.27.8":
|
||||
version "0.27.8"
|
||||
resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
|
||||
|
||||
Reference in New Issue
Block a user