chore: remove silkhq components

This commit is contained in:
Tienson Qin
2025-12-09 20:53:38 +08:00
parent f594e2034f
commit 8f4a6d962b
24 changed files with 1 additions and 3024 deletions

View File

@@ -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"))

View File

@@ -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": {

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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,
}

View File

@@ -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);
}

View File

@@ -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,
}

View File

@@ -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);
}

View File

@@ -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,
}

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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);
}

View File

@@ -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,
}

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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);
}

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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"