@smwb/ui-solid 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -0
- package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
- package/dist/assets/styles/less/components/avatar/avatar.entry.css +1 -1
- package/dist/assets/styles/less/components/badge/badge.entry.css +1 -1
- package/dist/assets/styles/less/components/breadcrumbs/breadcrumbs.entry.css +1 -1
- package/dist/assets/styles/less/components/button/button.entry.css +1 -1
- package/dist/assets/styles/less/components/buttonGroup/buttonGroup.entry.css +1 -1
- package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -1
- package/dist/assets/styles/less/components/meter/meter.entry.css +1 -1
- package/dist/assets/styles/less/components/screenDivider/screenDivider.entry.css +1 -1
- package/dist/assets/styles/less/components/sheet/sheet.entry.css +1 -1
- package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -1
- package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -1
- package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
- package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
- package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
- package/dist/assets/styles/less/tokens.entry.css +1 -1
- package/dist/components/dataDisplay/avatar/avatar.d.ts +5 -2
- package/dist/components/dataDisplay/avatar/avatar.js +9 -9
- package/dist/components/dataDisplay/avatar/avatar.js.map +1 -1
- package/dist/components/dataDisplay/badge/badge.d.ts +2 -1
- package/dist/components/dataDisplay/badge/badge.js.map +1 -1
- package/dist/components/dataDisplay/chart/chart.d.ts +16 -8
- package/dist/components/dataDisplay/chart/chartFull.d.ts +14 -0
- package/dist/components/dataDisplay/chart/core.d.ts +19 -0
- package/dist/components/dataDisplay/chart/index.d.ts +1 -1
- package/dist/components/dataDisplay/dagView/dagView.d.ts +4 -0
- package/dist/components/dataDisplay/dagView/dagView.js +124 -123
- package/dist/components/dataDisplay/dagView/dagView.js.map +1 -1
- package/dist/components/dataDisplay/dagView/index.d.ts +1 -1
- package/dist/components/dataDisplay/meter/index.d.ts +1 -1
- package/dist/components/dataDisplay/meter/meter.d.ts +14 -0
- package/dist/components/dataDisplay/meter/meter.js +32 -30
- package/dist/components/dataDisplay/meter/meter.js.map +1 -1
- package/dist/components/dataDisplay/statusDot/index.d.ts +1 -1
- package/dist/components/dataDisplay/statusDot/statusDot.d.ts +10 -1
- package/dist/components/dataDisplay/statusDot/statusDot.js +20 -11
- package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -1
- package/dist/components/dataDisplay/treeView/treeView.d.ts +18 -2
- package/dist/components/dataDisplay/treeView/treeView.js +140 -121
- package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/components/inputs/button/button.d.ts +7 -0
- package/dist/components/inputs/button/button.js +57 -51
- package/dist/components/inputs/button/button.js.map +1 -1
- package/dist/components/inputs/toggle/toggle.d.ts +6 -0
- package/dist/components/inputs/toggle/toggle.js +23 -23
- package/dist/components/inputs/toggle/toggle.js.map +1 -1
- package/dist/components/layout/appLayout/appLayout.d.ts +6 -1
- package/dist/components/layout/appLayout/appLayout.js +49 -42
- package/dist/components/layout/appLayout/appLayout.js.map +1 -1
- package/dist/components/layout/screenDivider/screenDivider.d.ts +12 -0
- package/dist/components/layout/screenDivider/screenDivider.js +87 -46
- package/dist/components/layout/screenDivider/screenDivider.js.map +1 -1
- package/dist/components/layout/sheet/sheet.d.ts +11 -0
- package/dist/components/layout/sheet/sheet.js +122 -102
- package/dist/components/layout/sheet/sheet.js.map +1 -1
- package/dist/components/layout/tabGroups/index.d.ts +1 -1
- package/dist/components/layout/tabGroups/tabGroups.d.ts +44 -1
- package/dist/components/layout/tabGroups/tabGroups.js +500 -460
- package/dist/components/layout/tabGroups/tabGroups.js.map +1 -1
- package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +16 -0
- package/dist/components/layout/tabGroups/tabGroupsFocus.js +102 -70
- package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
- package/dist/components/navigation/appBar/appBar.d.ts +12 -0
- package/dist/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/components/navigation/breadcrumbs/breadcrumbs.d.ts +9 -0
- package/dist/components/navigation/breadcrumbs/breadcrumbs.js +47 -31
- package/dist/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/components/navigation/tabs/tab/tab.js +71 -68
- package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/components/navigation/tabs/tabs.d.ts +15 -1
- package/dist/components/navigation/tabs/tabs.js +19 -16
- package/dist/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/components/navigation/tabs/tabsContext.d.ts +2 -0
- package/dist/components/navigation/tabs/tabsContext.js.map +1 -1
- package/dist/headless/components/dataDisplay/avatar/avatar.js +9 -9
- package/dist/headless/components/dataDisplay/avatar/avatar.js.map +1 -1
- package/dist/headless/components/dataDisplay/badge/badge.js.map +1 -1
- package/dist/headless/components/dataDisplay/dagView/dagView.js +133 -132
- package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -1
- package/dist/headless/components/dataDisplay/meter/meter.js +32 -30
- package/dist/headless/components/dataDisplay/meter/meter.js.map +1 -1
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js +19 -10
- package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -1
- package/dist/headless/components/dataDisplay/treeView/treeView.js +139 -120
- package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
- package/dist/headless/components/inputs/button/button.js +57 -51
- package/dist/headless/components/inputs/button/button.js.map +1 -1
- package/dist/headless/components/inputs/toggle/toggle.js +23 -23
- package/dist/headless/components/inputs/toggle/toggle.js.map +1 -1
- package/dist/headless/components/layout/appLayout/appLayout.js +52 -45
- package/dist/headless/components/layout/appLayout/appLayout.js.map +1 -1
- package/dist/headless/components/layout/screenDivider/screenDivider.js +88 -47
- package/dist/headless/components/layout/screenDivider/screenDivider.js.map +1 -1
- package/dist/headless/components/layout/sheet/sheet.js +124 -104
- package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroups.js +500 -460
- package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -1
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +102 -70
- package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -1
- package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
- package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js +46 -30
- package/dist/headless/components/navigation/breadcrumbs/breadcrumbs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tab/tab.js +70 -67
- package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabs.js +19 -16
- package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
- package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -1
- package/dist/headless/primitives/publishHeaderOffset.js +19 -0
- package/dist/headless/primitives/publishHeaderOffset.js.map +1 -0
- package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx +1 -0
- package/dist/headless/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/badge/badge.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/chart/chart.jsx +14 -12
- package/dist/headless/source/components/dataDisplay/chart/chart.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/chart/chartFull.js +12 -0
- package/dist/headless/source/components/dataDisplay/chart/chartFull.js.map +7 -0
- package/dist/headless/source/components/dataDisplay/chart/core.js +11 -0
- package/dist/headless/source/components/dataDisplay/chart/core.js.map +7 -0
- package/dist/headless/source/components/dataDisplay/chart/index.js +1 -1
- package/dist/headless/source/components/dataDisplay/chart/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx +2 -1
- package/dist/headless/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/dagView/index.js.map +2 -2
- package/dist/headless/source/components/dataDisplay/meter/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/meter/meter.jsx +14 -2
- package/dist/headless/source/components/dataDisplay/meter/meter.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/statusDot/index.js.map +1 -1
- package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
- package/dist/headless/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
- package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx +16 -3
- package/dist/headless/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
- package/dist/headless/source/components/inputs/button/button.jsx +26 -1
- package/dist/headless/source/components/inputs/button/button.jsx.map +1 -1
- package/dist/headless/source/components/inputs/toggle/toggle.jsx +9 -2
- package/dist/headless/source/components/inputs/toggle/toggle.jsx.map +1 -1
- package/dist/headless/source/components/layout/appLayout/appLayout.jsx +14 -2
- package/dist/headless/source/components/layout/appLayout/appLayout.jsx.map +1 -1
- package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx +102 -18
- package/dist/headless/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
- package/dist/headless/source/components/layout/sheet/sheet.jsx +14 -1
- package/dist/headless/source/components/layout/sheet/sheet.jsx.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/index.js.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx +55 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
- package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
- package/dist/headless/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
- package/dist/headless/source/components/navigation/appBar/appBar.jsx.map +1 -1
- package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
- package/dist/headless/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tab/tab.jsx +7 -1
- package/dist/headless/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tabs.jsx +5 -1
- package/dist/headless/source/components/navigation/tabs/tabs.jsx.map +1 -1
- package/dist/headless/source/components/navigation/tabs/tabsContext.js.map +2 -2
- package/dist/headless/source/index.js +8 -1
- package/dist/headless/source/index.js.map +2 -2
- package/dist/headless/source/primitives/publishHeaderOffset.js +34 -0
- package/dist/headless/source/primitives/publishHeaderOffset.js.map +7 -0
- package/dist/index.d.ts +5 -5
- package/dist/primitives/publishHeaderOffset.d.ts +7 -0
- package/dist/primitives/publishHeaderOffset.js +19 -0
- package/dist/primitives/publishHeaderOffset.js.map +1 -0
- package/dist/source/components/dataDisplay/avatar/avatar.jsx +1 -0
- package/dist/source/components/dataDisplay/avatar/avatar.jsx.map +1 -1
- package/dist/source/components/dataDisplay/badge/badge.jsx.map +1 -1
- package/dist/source/components/dataDisplay/chart/chart.jsx +14 -12
- package/dist/source/components/dataDisplay/chart/chart.jsx.map +1 -1
- package/dist/source/components/dataDisplay/chart/chartFull.js +12 -0
- package/dist/source/components/dataDisplay/chart/chartFull.js.map +7 -0
- package/dist/source/components/dataDisplay/chart/core.js +11 -0
- package/dist/source/components/dataDisplay/chart/core.js.map +7 -0
- package/dist/source/components/dataDisplay/chart/index.js +1 -1
- package/dist/source/components/dataDisplay/chart/index.js.map +1 -1
- package/dist/source/components/dataDisplay/dagView/dagView.jsx +2 -1
- package/dist/source/components/dataDisplay/dagView/dagView.jsx.map +1 -1
- package/dist/source/components/dataDisplay/dagView/index.js.map +2 -2
- package/dist/source/components/dataDisplay/meter/index.js.map +1 -1
- package/dist/source/components/dataDisplay/meter/meter.jsx +14 -2
- package/dist/source/components/dataDisplay/meter/meter.jsx.map +1 -1
- package/dist/source/components/dataDisplay/statusDot/index.js.map +1 -1
- package/dist/source/components/dataDisplay/statusDot/statusDot.jsx +13 -1
- package/dist/source/components/dataDisplay/statusDot/statusDot.jsx.map +1 -1
- package/dist/source/components/dataDisplay/treeView/treeView.jsx +16 -3
- package/dist/source/components/dataDisplay/treeView/treeView.jsx.map +1 -1
- package/dist/source/components/inputs/button/button.jsx +26 -1
- package/dist/source/components/inputs/button/button.jsx.map +1 -1
- package/dist/source/components/inputs/toggle/toggle.jsx +9 -2
- package/dist/source/components/inputs/toggle/toggle.jsx.map +1 -1
- package/dist/source/components/layout/appLayout/appLayout.jsx +14 -2
- package/dist/source/components/layout/appLayout/appLayout.jsx.map +1 -1
- package/dist/source/components/layout/screenDivider/screenDivider.jsx +102 -18
- package/dist/source/components/layout/screenDivider/screenDivider.jsx.map +1 -1
- package/dist/source/components/layout/sheet/sheet.jsx +14 -1
- package/dist/source/components/layout/sheet/sheet.jsx.map +1 -1
- package/dist/source/components/layout/tabGroups/index.js.map +1 -1
- package/dist/source/components/layout/tabGroups/tabGroups.jsx +55 -1
- package/dist/source/components/layout/tabGroups/tabGroups.jsx.map +1 -1
- package/dist/source/components/layout/tabGroups/tabGroupsFocus.js +42 -0
- package/dist/source/components/layout/tabGroups/tabGroupsFocus.js.map +2 -2
- package/dist/source/components/navigation/appBar/appBar.jsx.map +1 -1
- package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx +39 -4
- package/dist/source/components/navigation/breadcrumbs/breadcrumbs.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tab/tab.jsx +7 -1
- package/dist/source/components/navigation/tabs/tab/tab.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tabs.jsx +5 -1
- package/dist/source/components/navigation/tabs/tabs.jsx.map +1 -1
- package/dist/source/components/navigation/tabs/tabsContext.js.map +2 -2
- package/dist/source/index.js +8 -1
- package/dist/source/index.js.map +2 -2
- package/dist/source/primitives/publishHeaderOffset.js +34 -0
- package/dist/source/primitives/publishHeaderOffset.js.map +7 -0
- package/package.json +9 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/components/layout/screenDivider/screenDivider.tsx"],"sourcesContent":["import {\n type JSX,\n type ParentProps,\n children as resolveChildren,\n createEffect,\n createSignal,\n mergeProps,\n onCleanup,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { throttle } from \"../../../utils/throttle\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport interface ScreenDividerProps {\n sizeFirst?: number;\n sizeSecond?: number;\n class?: string;\n orientation?: \"horizontal\" | \"vertical\";\n /** Called with the first pane size (percent) whenever it changes. */\n onSizeChange?: (sizeFirst: number) => void;\n /** Step (in percent) applied on arrow-key resize. */\n keyboardStep?: number;\n /** Accessible label for the resizer handle. */\n resizerAriaLabel?: string;\n ref?: Ref<HTMLDivElement>;\n}\n\nconst getInitialDivider = (sizeFirst?: number | null, sizeSecond?: number | null): number => {\n if (!sizeFirst && sizeSecond) {\n return 100 - sizeSecond;\n }\n if (sizeFirst) {\n return sizeFirst;\n }\n return 50;\n};\n\nexport function ScreenDivider(props: ParentProps<ScreenDividerProps>): JSX.Element {\n const merged = mergeProps(\n { orientation: \"horizontal\" as const, keyboardStep: 5, resizerAriaLabel: \"Resize panels\" },\n props\n );\n const [local] = splitProps(merged, [\n \"class\",\n \"orientation\",\n \"sizeFirst\",\n \"sizeSecond\",\n \"children\",\n \"onSizeChange\",\n \"keyboardStep\",\n \"resizerAriaLabel\",\n \"ref\",\n ]);\n\n let wrapperEl: HTMLDivElement | undefined;\n const [divider, setDivider] = createSignal(getInitialDivider(local.sizeFirst, local.sizeSecond));\n const [isDragging, setIsDragging] = createSignal(false);\n\n // Sync with controlled size props.\n createEffect(() => {\n setDivider(getInitialDivider(local.sizeFirst, local.sizeSecond));\n });\n\n // Report size changes.\n createEffect(() => {\n local.onSizeChange?.(divider());\n });\n\n const resolved = resolveChildren(() => local.children);\n const child = (): unknown[] => resolved.toArray();\n\n const dragOver = throttle((event: PointerEvent) => {\n if (!isDragging()) return;\n const wrapper = wrapperEl;\n if (!wrapper) return;\n // Viewport-relative rect — using offsetLeft/offsetTop here is wrong\n // because they are relative to the nearest positioned ancestor, not\n // the viewport that clientX/clientY live in (this is what made the\n // divider drift away from the cursor when the wrapper was nested).\n const rect = wrapper.getBoundingClientRect();\n const total = local.orientation === \"vertical\" ? rect.height : rect.width;\n const cursor = local.orientation === \"vertical\" ? event.clientY - rect.top : event.clientX - rect.left;\n // 5px margin on each side so neither pane fully collapses.\n const clamped = Math.max(5, Math.min(total - 5, cursor));\n setDivider((clamped / total) * 100);\n }, 1000 / 60);\n\n const handleDragStart = (): void => {\n setIsDragging(true);\n };\n const handleDragEnd = (): void => {\n setIsDragging(false);\n };\n\n createEffect(() => {\n if (isServer) return;\n if (isDragging()) {\n document.body.addEventListener(\"pointerup\", handleDragEnd);\n document.body.addEventListener(\"pointermove\", dragOver);\n document.body.style.cursor = local.orientation === \"horizontal\" ? \"e-resize\" : \"n-resize\";\n } else {\n document.body.style.cursor = \"default\";\n }\n onCleanup(() => {\n document.body.removeEventListener(\"pointerup\", handleDragEnd);\n document.body.removeEventListener(\"pointermove\", dragOver);\n });\n });\n\n const onResizerKeyDown: JSX.EventHandler<HTMLSpanElement, KeyboardEvent> = (event) => {\n const decreaseKey = local.orientation === \"vertical\" ? \"ArrowUp\" : \"ArrowLeft\";\n const increaseKey = local.orientation === \"vertical\" ? \"ArrowDown\" : \"ArrowRight\";\n if (event.key === decreaseKey) {\n event.preventDefault();\n setDivider((prev) => Math.max(0, prev - local.keyboardStep));\n } else if (event.key === increaseKey) {\n event.preventDefault();\n setDivider((prev) => Math.min(100, prev + local.keyboardStep));\n } else if (event.key === \"Home\") {\n event.preventDefault();\n setDivider(0);\n } else if (event.key === \"End\") {\n event.preventDefault();\n setDivider(100);\n }\n };\n\n const firstChildStyle = (): JSX.CSSProperties =>\n local.orientation === \"vertical\" ? { height: `${divider()}%` } : { width: `${divider()}%` };\n const secondChildStyle = (): JSX.CSSProperties =>\n local.orientation === \"vertical\" ? { height: `${100 - divider()}%` } : { width: `${100 - divider()}%` };\n\n return (\n <div\n class={cn(\"smwb-screen-divider__wrapper\", `smwb-${local.orientation}`, local.class)}\n ref={mergeRefs(local.ref, (el) => (wrapperEl = el))}\n data-testid=\"screen-divider\"\n >\n <div class={cn(\"smwb-screen-divider__first\", `smwb-${local.orientation}`)} style={firstChildStyle()}>\n {(child()[0] ?? \"\") as JSX.Element}\n </div>\n <span\n class=\"smwb-screen-divider__resizer\"\n onPointerDown={handleDragStart}\n draggable={false}\n role=\"separator\"\n aria-orientation={local.orientation === \"vertical\" ? \"horizontal\" : \"vertical\"}\n aria-valuenow={Math.round(divider())}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={local.resizerAriaLabel}\n tabindex={0}\n onKeyDown={onResizerKeyDown}\n />\n <div class={cn(\"smwb-screen-divider__second\", `smwb-${local.orientation}`)} style={secondChildStyle()}>\n {(child()[1] ?? \"\") as JSX.Element}\n </div>\n </div>\n );\n}\n\nexport default ScreenDivider;\n"],"mappings":"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","names":[],"file":"screenDivider.jsx"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/components/layout/screenDivider/screenDivider.tsx"],"sourcesContent":["import {\n type JSX,\n type ParentProps,\n children as resolveChildren,\n createEffect,\n createSignal,\n mergeProps,\n onCleanup,\n splitProps,\n} from \"solid-js\";\nimport { isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { throttle } from \"../../../utils/throttle\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\n\nexport interface ScreenDividerProps {\n sizeFirst?: number;\n sizeSecond?: number;\n class?: string;\n orientation?: \"horizontal\" | \"vertical\";\n /** Called with the first pane size (percent) whenever it changes. */\n onSizeChange?: (sizeFirst: number) => void;\n /** Step (in percent) applied on arrow-key resize. */\n keyboardStep?: number;\n /** Accessible label for the resizer handle. */\n resizerAriaLabel?: string;\n /**\n * Smallest size of the first pane that dragging and the keyboard (arrows, Home, End) leave it:\n * a number is pixels, a string is `\"120px\"` or `\"20%\"`; any other unit is ignored. Unset means no minimum.\n */\n minSizeFirst?: number | string | undefined;\n /** Smallest size of the second pane, same units as `minSizeFirst`. If both minimums do not fit, the first one wins. */\n minSizeSecond?: number | string | undefined;\n /**\n * Folds one pane to zero and hides the resizer; the other pane takes the whole divider. Both panes stay mounted,\n * and clearing it brings back the split the divider had. `onSizeChange` is not called for the fold.\n */\n collapsed?: \"first\" | \"second\" | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\ntype ParsedMin = { value: number; unit: \"px\" | \"%\" } | null;\n\n// A bare number, or a number with `px` / `%`; any other unit (`rem`, `vh`, `calc(...)`) is no minimum.\nconst MIN_SIZE = /^(\\d*\\.?\\d+)(px|%)?$/i;\n\nconst parseMinSize = (min: number | string | undefined): ParsedMin => {\n if (min === undefined) return null;\n if (typeof min === \"number\") return Number.isFinite(min) && min > 0 ? { value: min, unit: \"px\" } : null;\n const match = MIN_SIZE.exec(min.trim());\n if (!match) return null;\n const [, digits = \"\", unit] = match;\n const value = parseFloat(digits);\n return value > 0 ? { value, unit: unit === \"%\" ? \"%\" : \"px\" } : null;\n};\n\n/** A minimum as a share (percent) of `available` pixels, the space the two panes split. */\nconst minToPercent = (min: number | string | undefined, available: number): number => {\n const parsed = parseMinSize(min);\n if (!parsed) return 0;\n if (parsed.unit === \"%\") return parsed.value;\n return available > 0 ? (parsed.value / available) * 100 : 0;\n};\n\n/** The range of the first pane's share: the second pane's minimum caps it, the first pane's minimum wins a clash. */\nconst getBounds = (\n minFirst: number | string | undefined,\n minSecond: number | string | undefined,\n available: number\n): [number, number] => {\n const low = Math.min(100, minToPercent(minFirst, available));\n const high = Math.max(low, 100 - minToPercent(minSecond, available));\n return [low, high];\n};\n\n/** Whether the first pane's minimum leaves the second less than its own: then the first one wins. */\nconst minimumsClash = (\n minFirst: number | string | undefined,\n minSecond: number | string | undefined,\n available: number\n): boolean => Math.min(100, minToPercent(minFirst, available)) + minToPercent(minSecond, available) > 100;\n\nconst clampDivider = (value: number, [low, high]: [number, number]) => Math.max(low, Math.min(high, value));\n\nconst getInitialDivider = (sizeFirst?: number | null, sizeSecond?: number | null): number => {\n if (!sizeFirst && sizeSecond) {\n return 100 - sizeSecond;\n }\n if (sizeFirst) {\n return sizeFirst;\n }\n return 50;\n};\n\nexport function ScreenDivider(props: ParentProps<ScreenDividerProps>): JSX.Element {\n const merged = mergeProps(\n { orientation: \"horizontal\" as const, keyboardStep: 5, resizerAriaLabel: \"Resize panels\" },\n props\n );\n const [local] = splitProps(merged, [\n \"class\",\n \"orientation\",\n \"sizeFirst\",\n \"sizeSecond\",\n \"children\",\n \"onSizeChange\",\n \"keyboardStep\",\n \"resizerAriaLabel\",\n \"minSizeFirst\",\n \"minSizeSecond\",\n \"collapsed\",\n \"ref\",\n ]);\n\n let wrapperEl: HTMLDivElement | undefined;\n let resizerEl: HTMLSpanElement | undefined;\n // The thickness the resizer had the last time it was shown.\n let lastBar = 0;\n const [divider, setDivider] = createSignal(getInitialDivider(local.sizeFirst, local.sizeSecond));\n const [isDragging, setIsDragging] = createSignal(false);\n const [available, setAvailable] = createSignal(0);\n const vertical = (): boolean => local.orientation === \"vertical\";\n\n // The pixels the two panes split: the wrapper along its main axis less the resizer. A hidden resizer measures 0, so\n // the thickness it had while shown is subtracted instead, and folding a pane leaves the minimums where they were.\n const measureAvailable = (): number => {\n const main = (el: HTMLElement | undefined): number => {\n const rect = el?.getBoundingClientRect();\n return rect ? (vertical() ? rect.height : rect.width) : 0;\n };\n const bar = main(resizerEl);\n if (bar > 0) lastBar = bar;\n return Math.max(0, main(wrapperEl) - (bar > 0 ? bar : lastBar));\n };\n\n createEffect(() => {\n if (isServer) return;\n if (!parseMinSize(local.minSizeFirst) && !parseMinSize(local.minSizeSecond)) return;\n // Measured again when the orientation or the folded pane changes, and when the wrapper resizes.\n void local.orientation;\n void local.collapsed;\n const update = (): void => {\n setAvailable(measureAvailable());\n };\n update();\n if (!wrapperEl || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(update);\n observer.observe(wrapperEl);\n onCleanup(() => observer.disconnect());\n });\n\n // Sync with controlled size props.\n createEffect(() => {\n setDivider(getInitialDivider(local.sizeFirst, local.sizeSecond));\n });\n\n const bounds = (): [number, number] => getBounds(local.minSizeFirst, local.minSizeSecond, available());\n // What the panes show: the split held within the minimums, whatever the props or the last resize said.\n const shown = (): number => clampDivider(divider(), bounds());\n\n // Report size changes.\n createEffect(() => {\n local.onSizeChange?.(shown());\n });\n\n const resolved = resolveChildren(() => local.children);\n const child = (): unknown[] => resolved.toArray();\n\n const dragOver = throttle((event: PointerEvent) => {\n if (!isDragging() || local.collapsed) return;\n const wrapper = wrapperEl;\n if (!wrapper) return;\n // Viewport-relative rect — using offsetLeft/offsetTop here is wrong\n // because they are relative to the nearest positioned ancestor, not\n // the viewport that clientX/clientY live in (this is what made the\n // divider drift away from the cursor when the wrapper was nested).\n const rect = wrapper.getBoundingClientRect();\n const total = vertical() ? rect.height : rect.width;\n const cursor = vertical() ? event.clientY - rect.top : event.clientX - rect.left;\n // 5px margin on each side so neither pane fully collapses.\n const clamped = Math.max(5, Math.min(total - 5, cursor));\n setDivider(\n clampDivider((clamped / total) * 100, getBounds(local.minSizeFirst, local.minSizeSecond, measureAvailable()))\n );\n }, 1000 / 60);\n\n const handleDragStart = (): void => {\n setIsDragging(true);\n };\n const handleDragEnd = (): void => {\n setIsDragging(false);\n };\n\n createEffect(() => {\n if (isServer) return;\n if (isDragging()) {\n document.body.addEventListener(\"pointerup\", handleDragEnd);\n document.body.addEventListener(\"pointermove\", dragOver);\n document.body.style.cursor = local.orientation === \"horizontal\" ? \"e-resize\" : \"n-resize\";\n } else {\n document.body.style.cursor = \"default\";\n }\n onCleanup(() => {\n document.body.removeEventListener(\"pointerup\", handleDragEnd);\n document.body.removeEventListener(\"pointermove\", dragOver);\n });\n });\n\n const onResizerKeyDown: JSX.EventHandler<HTMLSpanElement, KeyboardEvent> = (event) => {\n const decreaseKey = vertical() ? \"ArrowUp\" : \"ArrowLeft\";\n const increaseKey = vertical() ? \"ArrowDown\" : \"ArrowRight\";\n // Measured now rather than read from the signal, so the minimums hold at the size the divider has this instant.\n const keyBounds = getBounds(local.minSizeFirst, local.minSizeSecond, measureAvailable());\n if (event.key === decreaseKey) {\n event.preventDefault();\n setDivider(clampDivider(Math.max(0, shown() - local.keyboardStep), keyBounds));\n } else if (event.key === increaseKey) {\n event.preventDefault();\n setDivider(clampDivider(Math.min(100, shown() + local.keyboardStep), keyBounds));\n } else if (event.key === \"Home\") {\n event.preventDefault();\n setDivider(clampDivider(0, keyBounds));\n } else if (event.key === \"End\") {\n event.preventDefault();\n setDivider(clampDivider(100, keyBounds));\n }\n };\n\n // A folded pane is 0 and the other 100; both stay in the tree, so nothing inside either remounts.\n const sizeOf = (pane: \"first\" | \"second\"): number => {\n const share = pane === \"first\" ? shown() : 100 - shown();\n return local.collapsed ? (local.collapsed === pane ? 0 : 100) : share;\n };\n const paneStyle = (pane: \"first\" | \"second\"): JSX.CSSProperties => {\n const style: JSX.CSSProperties = vertical() ? { height: `${sizeOf(pane)}%` } : { width: `${sizeOf(pane)}%` };\n // Pixel minimums also floor the pane in CSS, so it holds between a resize and the next measurement.\n const min = parseMinSize(pane === \"first\" ? local.minSizeFirst : local.minSizeSecond);\n // The second pane's floor would beat a first pane's minimum that wins the clash, so it gives way to it.\n const gives = pane === \"second\" && minimumsClash(local.minSizeFirst, local.minSizeSecond, available());\n if (!local.collapsed && !gives && min?.unit === \"px\")\n style[vertical() ? \"min-height\" : \"min-width\"] = `${min.value}px`;\n return style;\n };\n\n return (\n <div\n class={cn(\"smwb-screen-divider__wrapper\", `smwb-${local.orientation}`, local.class)}\n ref={mergeRefs(local.ref, (el) => (wrapperEl = el))}\n data-testid=\"screen-divider\"\n >\n <div\n class={cn(\n \"smwb-screen-divider__first\",\n `smwb-${local.orientation}`,\n local.collapsed === \"first\" && \"smwb-collapsed\"\n )}\n style={paneStyle(\"first\")}\n >\n {(child()[0] ?? \"\") as JSX.Element}\n </div>\n <span\n ref={(el) => (resizerEl = el)}\n class=\"smwb-screen-divider__resizer\"\n hidden={local.collapsed !== undefined}\n onPointerDown={handleDragStart}\n draggable={false}\n role=\"separator\"\n aria-orientation={local.orientation === \"vertical\" ? \"horizontal\" : \"vertical\"}\n aria-valuenow={Math.round(shown())}\n aria-valuemin={Math.round(bounds()[0])}\n aria-valuemax={Math.round(bounds()[1])}\n aria-label={local.resizerAriaLabel}\n tabindex={0}\n onKeyDown={onResizerKeyDown}\n />\n <div\n class={cn(\n \"smwb-screen-divider__second\",\n `smwb-${local.orientation}`,\n local.collapsed === \"second\" && \"smwb-collapsed\"\n )}\n style={paneStyle(\"second\")}\n >\n {(child()[1] ?? \"\") as JSX.Element}\n </div>\n </div>\n );\n}\n\nexport default ScreenDivider;\n"],"mappings":"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","names":[],"file":"screenDivider.jsx"}
|
|
@@ -9,6 +9,10 @@ import { isTopOverlayLayer } from "../../../primitives/overlayLayer";
|
|
|
9
9
|
import { restoreFocus } from "../../../primitives/restoreFocus";
|
|
10
10
|
import { mergeRefs } from "../../../primitives/mergeRefs";
|
|
11
11
|
import { mergeStyle } from "../../../primitives/mergeStyle";
|
|
12
|
+
const landedAboveScrim = (event, scrim) => {
|
|
13
|
+
const y = "changedTouches" in event ? event.changedTouches[0]?.clientY : event.clientY;
|
|
14
|
+
return scrim != null && y !== void 0 && y < scrim.getBoundingClientRect().top;
|
|
15
|
+
};
|
|
12
16
|
const isVerticalAxis = (placement) => placement === "bottom" || placement === "top";
|
|
13
17
|
function SheetBlock(props) {
|
|
14
18
|
const merged = mergeProps(
|
|
@@ -220,6 +224,7 @@ function Sheet(props) {
|
|
|
220
224
|
"placement",
|
|
221
225
|
"disableOutsideClick",
|
|
222
226
|
"closeOnEsc",
|
|
227
|
+
"offsetTop",
|
|
223
228
|
"ref"
|
|
224
229
|
]);
|
|
225
230
|
const [mode, setMode] = createSignal(null);
|
|
@@ -245,6 +250,10 @@ function Sheet(props) {
|
|
|
245
250
|
local.onClose?.();
|
|
246
251
|
setMode(null);
|
|
247
252
|
};
|
|
253
|
+
const wrapperStyle = () => {
|
|
254
|
+
const offset = local.offsetTop;
|
|
255
|
+
return offset === void 0 ? void 0 : { "--smui-sheet-offset-top": typeof offset === "number" ? `${offset}px` : offset };
|
|
256
|
+
};
|
|
248
257
|
const block = () => <SheetBlock
|
|
249
258
|
{...rest}
|
|
250
259
|
ref={local.ref}
|
|
@@ -265,9 +274,12 @@ function Sheet(props) {
|
|
|
265
274
|
fallback={<div
|
|
266
275
|
ref={(el) => wrapperEl = el}
|
|
267
276
|
data-smwb-overlay-layer
|
|
277
|
+
style={wrapperStyle()}
|
|
268
278
|
class={cn("smwb-sheet__overlay", "smwb-dark", `smwb-${local.placement}`, `smwb-sheet_${local.variant}`, outer.classes())}
|
|
269
279
|
>
|
|
270
|
-
<ClickAwayListener
|
|
280
|
+
<ClickAwayListener
|
|
281
|
+
onClickAway={(event) => !local.disableOutsideClick && !landedAboveScrim(event, wrapperEl) && handleClose()}
|
|
282
|
+
>
|
|
271
283
|
{block()}
|
|
272
284
|
</ClickAwayListener>
|
|
273
285
|
</div>}
|
|
@@ -275,6 +287,7 @@ function Sheet(props) {
|
|
|
275
287
|
<div
|
|
276
288
|
ref={(el) => wrapperEl = el}
|
|
277
289
|
data-smwb-overlay-layer
|
|
290
|
+
style={wrapperStyle()}
|
|
278
291
|
class={cn(local.disableOutsideClick ? "smwb-sheet__overlay" : "smwb-sheet__default", outer.classes())}
|
|
279
292
|
>
|
|
280
293
|
{block()}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/components/layout/sheet/sheet.tsx"],"sourcesContent":["import { type JSX, type ParentProps, Show, createEffect, createSignal, mergeProps, on, onCleanup, splitProps } from \"solid-js\";\nimport { Portal, isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Button } from \"../../inputs/button\";\nimport { Icon } from \"../../base/icon\";\nimport { ClickAwayListener } from \"../../clickAwayListener\";\nimport { createCssTransition } from \"../../../primitives/createCssTransition\";\nimport { isTopOverlayLayer } from \"../../../primitives/overlayLayer\";\nimport { restoreFocus } from \"../../../primitives/restoreFocus\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\n\nexport interface SheetProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onResize\"> {\n placement?: \"top\" | \"bottom\" | \"right\" | \"left\";\n isOpen: boolean;\n onClose?: (() => void) | undefined;\n variant?: \"default\" | \"modal\";\n withSizeToggle?: boolean;\n /** Hide built-in header actions; onClose still handles Esc and backdrop. */\n hideHeaderActions?: boolean;\n reverseHeaderActions?: boolean;\n /** Accessible name of the header close button (default \"Close sheet\"). */\n closeAriaLabel?: string;\n /**\n * Accessible name of the size toggle while the sheet is at its normal size (default \"Expand sheet\"). The toggle\n * cycles normal, expanded, collapsed and back, and its name always says what the next press does; the\n * name changing is how it exposes its state. It shows the `open_in_full` icon, and `close_fullscreen` while expanded.\n */\n expandAriaLabel?: string;\n /** Accessible name of the size toggle while the sheet is expanded (default \"Collapse sheet\"). */\n collapseAriaLabel?: string;\n /** Accessible name of the size toggle while the sheet is collapsed to its header (default \"Restore sheet size\"). */\n restoreAriaLabel?: string;\n size?: string;\n disableOutsideClick?: boolean;\n /** Close the sheet when Escape is pressed. */\n closeOnEsc?: boolean;\n /** Allow drag-to-resize (mobile bottom-sheet style). Off by default. */\n resizable?: boolean;\n /** Minimum size in px while resizing (default 80). */\n minSize?: number;\n /** Maximum size in px while resizing (default: viewport dimension). */\n maxSize?: number;\n /** Step in px for keyboard resizing (default 24). */\n resizeStep?: number;\n /** Accessible label for the resize handle. */\n resizeHandleAriaLabel?: string;\n /** Called with the new size in px while/after resizing. */\n onResize?: (size: number) => void;\n \"aria-label\"?: string;\n /** Test id of the sheet panel (the dialog); `sheet` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\ntype Mode = \"small\" | \"expanded\" | null;\n\nconst isVerticalAxis = (placement: SheetProps[\"placement\"]): boolean => placement === \"bottom\" || placement === \"top\";\n\ninterface SheetBlockProps extends ParentProps<SheetProps> {\n mode: Mode;\n handleSizeButton: () => void;\n handleClose: () => void;\n}\n\nfunction SheetBlock(props: SheetBlockProps): JSX.Element {\n const merged = mergeProps(\n {\n size: \"60%\",\n withSizeToggle: true,\n hideHeaderActions: false,\n reverseHeaderActions: false,\n closeAriaLabel: \"Close sheet\",\n expandAriaLabel: \"Expand sheet\",\n collapseAriaLabel: \"Collapse sheet\",\n restoreAriaLabel: \"Restore sheet size\",\n resizable: false,\n minSize: 80,\n resizeStep: 24,\n resizeHandleAriaLabel: \"Resize sheet\",\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"isOpen\",\n \"placement\",\n \"class\",\n \"mode\",\n \"size\",\n \"variant\",\n \"onClose\",\n \"withSizeToggle\",\n \"hideHeaderActions\",\n \"reverseHeaderActions\",\n \"closeAriaLabel\",\n \"expandAriaLabel\",\n \"collapseAriaLabel\",\n \"restoreAriaLabel\",\n \"resizable\",\n \"minSize\",\n \"maxSize\",\n \"resizeStep\",\n \"resizeHandleAriaLabel\",\n \"onResize\",\n \"style\",\n \"handleClose\",\n \"handleSizeButton\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n let rootEl: HTMLDivElement | undefined;\n const [dragSize, setDragSize] = createSignal<number | null>(null);\n const vertical = (): boolean => isVerticalAxis(local.placement);\n\n const inner = createCssTransition({\n in: () => local.isOpen,\n timeout: { enter: 120, exit: 120 },\n classNames: { enterDone: \"smwb-sheet_entered\" },\n appear: true,\n });\n\n const clamp = (px: number): number => {\n const viewport = vertical() ? window.innerHeight : window.innerWidth;\n const max = local.maxSize ?? viewport;\n return Math.max(local.minSize, Math.min(max, px));\n };\n\n const currentSizePx = (): number => {\n const rect = rootEl?.getBoundingClientRect();\n if (!rect) return local.minSize;\n return vertical() ? rect.height : rect.width;\n };\n\n const applySize = (px: number): void => {\n const next = clamp(px);\n setDragSize(next);\n local.onResize?.(next);\n };\n\n let drag: { start: number; size: number } | null = null;\n\n const onPointerDown = (event: PointerEvent & { currentTarget: HTMLDivElement }): void => {\n event.preventDefault();\n drag = { start: vertical() ? event.clientY : event.clientX, size: currentSizePx() };\n try {\n event.currentTarget.setPointerCapture?.(event.pointerId);\n } catch {\n /* best-effort */\n }\n };\n\n const onPointerMove = (event: PointerEvent): void => {\n if (!drag) return;\n const pos = vertical() ? event.clientY : event.clientX;\n const delta = pos - drag.start;\n const grow = local.placement === \"bottom\" || local.placement === \"right\" ? -delta : delta;\n applySize(drag.size + grow);\n };\n\n const endDrag = (event: PointerEvent & { currentTarget: HTMLDivElement }): void => {\n drag = null;\n if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n }\n };\n\n const onHandleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n const base = dragSize() ?? currentSizePx();\n const max = local.maxSize ?? (vertical() ? window.innerHeight : window.innerWidth);\n const incKey =\n local.placement === \"bottom\" ? \"ArrowUp\" : local.placement === \"top\" ? \"ArrowDown\" : local.placement === \"left\" ? \"ArrowRight\" : \"ArrowLeft\";\n const decKey =\n local.placement === \"bottom\" ? \"ArrowDown\" : local.placement === \"top\" ? \"ArrowUp\" : local.placement === \"left\" ? \"ArrowLeft\" : \"ArrowRight\";\n if (event.key === incKey) {\n event.preventDefault();\n applySize(base + local.resizeStep);\n } else if (event.key === decKey) {\n event.preventDefault();\n applySize(base - local.resizeStep);\n } else if (event.key === \"Home\") {\n event.preventDefault();\n applySize(local.minSize);\n } else if (event.key === \"End\") {\n event.preventDefault();\n applySize(max);\n }\n };\n\n // Keyed on `isOpen` alone: root.focus() fires focus handlers synchronously, and Solid runs those\n // without untrack, so any signal they read would otherwise re-run this effect and steal focus.\n createEffect(\n on(\n () => local.isOpen,\n (open) => {\n if (!open) {\n setDragSize(null);\n return;\n }\n const root = rootEl;\n // The element that had focus when the sheet opened gets it back when it closes (or unmounts\n // while open), unless the app has put focus somewhere else by then.\n const opener = root?.contains(document.activeElement) ? null : document.activeElement;\n root?.focus();\n onCleanup(() => restoreFocus(opener, root));\n },\n ),\n );\n\n const showActions = (): boolean => !local.hideHeaderActions && (!!local.onClose || local.withSizeToggle);\n const actionNodes = (): JSX.Element[] => {\n const nodes: JSX.Element[] = [];\n if (local.withSizeToggle) {\n nodes.push(\n <Button\n variant=\"outlined\"\n size=\"small\"\n onClick={local.handleSizeButton}\n aria-label={\n local.mode === \"expanded\" ? local.collapseAriaLabel : local.mode === \"small\" ? local.restoreAriaLabel : local.expandAriaLabel\n }\n >\n <Icon name={local.mode === \"expanded\" ? \"close_fullscreen\" : \"open_in_full\"} />\n </Button>\n );\n }\n if (local.onClose) {\n nodes.push(\n <Button variant=\"outlined\" size=\"small\" onClick={local.handleClose} aria-label={local.closeAriaLabel}>\n <Icon name=\"close\" />\n </Button>\n );\n }\n if (local.reverseHeaderActions) nodes.reverse();\n return nodes;\n };\n\n const sizeStyle = (): JSX.CSSProperties => {\n if (local.resizable && dragSize() !== null) {\n const px = `${dragSize()}px`;\n return { ...(vertical() ? { height: px } : { width: px }), transition: \"none\" };\n }\n return {};\n };\n\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref, (el) => (rootEl = el as HTMLDivElement))}\n data-testid={local[\"data-testid\"] ?? \"sheet\"}\n tabindex={-1}\n role=\"dialog\"\n aria-modal={local.variant === \"modal\" || undefined}\n class={cn(\"smwb-sheet\", local.class, `smwb-sheet_${local.variant}`, `smwb-${local.placement}`, inner.classes(), {\n \"smwb-expanded\": local.mode === \"expanded\",\n \"smwb-small\": local.mode === \"small\",\n \"smwb-sheet_resizable\": local.resizable,\n })}\n style={mergeStyle({ \"--sizeProp\": local.size, ...sizeStyle() }, local.style)}\n >\n <Show when={local.resizable}>\n <div\n class=\"smwb-sheet__drag-handle\"\n data-testid=\"sheet-drag-handle\"\n role=\"separator\"\n tabindex={0}\n aria-orientation={vertical() ? \"horizontal\" : \"vertical\"}\n aria-label={local.resizeHandleAriaLabel}\n aria-valuemin={local.minSize}\n aria-valuemax={Math.round(local.maxSize ?? (vertical() ? window.innerHeight : window.innerWidth))}\n aria-valuenow={Math.round(dragSize() ?? currentSizePx())}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={onHandleKeyDown}\n >\n <span class=\"smwb-sheet__drag-handle-bar\" />\n </div>\n </Show>\n <Show when={showActions()}>\n <div class=\"smwb-sheet__header\">{actionNodes()}</div>\n </Show>\n <Show when={local.isOpen && local.mode !== \"small\"}>\n <div class=\"smwb-sheet__inner\">{local.children}</div>\n </Show>\n </div>\n );\n}\n\nexport function Sheet(props: ParentProps<SheetProps>): JSX.Element {\n const merged = mergeProps({ variant: \"default\" as const, placement: \"bottom\" as const, closeOnEsc: true }, props);\n const [local, rest] = splitProps(merged, [\n \"isOpen\",\n \"onClose\",\n \"variant\",\n \"children\",\n \"placement\",\n \"disableOutsideClick\",\n \"closeOnEsc\",\n \"ref\",\n ]);\n\n const [mode, setMode] = createSignal<Mode>(null);\n let wrapperEl: HTMLDivElement | undefined;\n\n const outer = createCssTransition({\n in: () => local.isOpen,\n timeout: { enter: 70, exit: 70 },\n classNames: { enterDone: \"smwb-entered\" },\n appear: true,\n });\n\n createEffect(() => {\n if (!local.isOpen || !local.closeOnEsc || !local.onClose) return;\n const onKeyDown = (event: KeyboardEvent): void => {\n // Only the topmost overlay layer reacts to Escape, and not to one handled inside\n // it, e.g. by a menu closing on it.\n if (event.key === \"Escape\" && !event.defaultPrevented && isTopOverlayLayer(wrapperEl)) local.onClose?.();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onKeyDown));\n });\n\n const handleSizeButton = (): void => {\n setMode((prev) => (prev === \"expanded\" ? \"small\" : prev === null ? \"expanded\" : null));\n };\n const handleClose = (): void => {\n local.onClose?.();\n setMode(null);\n };\n\n const block = (): JSX.Element => (\n <SheetBlock\n {...rest}\n ref={local.ref}\n isOpen={local.isOpen}\n onClose={local.onClose}\n handleSizeButton={handleSizeButton}\n handleClose={handleClose}\n mode={mode()}\n placement={local.placement}\n variant={local.variant}\n >\n {local.children}\n </SheetBlock>\n );\n\n return (\n <Show when={outer.mounted()}>\n <Portal mount={(isServer ? undefined : document.body) as Node}>\n <Show\n when={local.variant === \"default\"}\n fallback={\n <div\n ref={(el) => (wrapperEl = el)}\n data-smwb-overlay-layer\n class={cn(\"smwb-sheet__overlay\", \"smwb-dark\", `smwb-${local.placement}`, `smwb-sheet_${local.variant}`, outer.classes())}\n >\n <ClickAwayListener onClickAway={() => !local.disableOutsideClick && handleClose()}>\n {block()}\n </ClickAwayListener>\n </div>\n }\n >\n <div\n ref={(el) => (wrapperEl = el)}\n data-smwb-overlay-layer\n class={cn(local.disableOutsideClick ? \"smwb-sheet__overlay\" : \"smwb-sheet__default\", outer.classes())}\n >\n {block()}\n </div>\n </Show>\n </Portal>\n </Show>\n );\n}\n\nexport default Sheet;\n"],"mappings":"AAAA,SAAqC,MAAM,cAAc,cAAc,YAAY,IAAI,WAAW,kBAAkB;AACpH,SAAS,QAAQ,gBAAgB;AACjC,OAAO,QAAQ;AACf,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,SAAS,yBAAyB;AAClC,SAAS,2BAA2B;AACpC,SAAS,yBAAyB;AAClC,SAAS,oBAAoB;AAC7B,SAAS,iBAA2B;AACpC,SAAS,kBAAkB;AA+C3B,MAAM,iBAAiB,CAAC,cAAgD,cAAc,YAAY,cAAc;AAQhH,SAAS,WAAW,OAAqC;AACvD,QAAM,SAAS;AAAA,IACb;AAAA,MACE,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,mBAAmB;AAAA,MACnB,sBAAsB;AAAA,MACtB,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,mBAAmB;AAAA,MACnB,kBAAkB;AAAA,MAClB,WAAW;AAAA,MACX,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,uBAAuB;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,OAAO,IAAI,IAAI,WAAW,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,MAAI;AACJ,QAAM,CAAC,UAAU,WAAW,IAAI,aAA4B,IAAI;AAChE,QAAM,WAAW,MAAe,eAAe,MAAM,SAAS;AAE9D,QAAM,QAAQ,oBAAoB;AAAA,IAChC,IAAI,MAAM,MAAM;AAAA,IAChB,SAAS,EAAE,OAAO,KAAK,MAAM,IAAI;AAAA,IACjC,YAAY,EAAE,WAAW,qBAAqB;AAAA,IAC9C,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,QAAQ,CAAC,OAAuB;AACpC,UAAM,WAAW,SAAS,IAAI,OAAO,cAAc,OAAO;AAC1D,UAAM,MAAM,MAAM,WAAW;AAC7B,WAAO,KAAK,IAAI,MAAM,SAAS,KAAK,IAAI,KAAK,EAAE,CAAC;AAAA,EAClD;AAEA,QAAM,gBAAgB,MAAc;AAClC,UAAM,OAAO,QAAQ,sBAAsB;AAC3C,QAAI,CAAC,KAAM,QAAO,MAAM;AACxB,WAAO,SAAS,IAAI,KAAK,SAAS,KAAK;AAAA,EACzC;AAEA,QAAM,YAAY,CAAC,OAAqB;AACtC,UAAM,OAAO,MAAM,EAAE;AACrB,gBAAY,IAAI;AAChB,UAAM,WAAW,IAAI;AAAA,EACvB;AAEA,MAAI,OAA+C;AAEnD,QAAM,gBAAgB,CAAC,UAAkE;AACvF,UAAM,eAAe;AACrB,WAAO,EAAE,OAAO,SAAS,IAAI,MAAM,UAAU,MAAM,SAAS,MAAM,cAAc,EAAE;AAClF,QAAI;AACF,YAAM,cAAc,oBAAoB,MAAM,SAAS;AAAA,IACzD,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,gBAAgB,CAAC,UAA8B;AACnD,QAAI,CAAC,KAAM;AACX,UAAM,MAAM,SAAS,IAAI,MAAM,UAAU,MAAM;AAC/C,UAAM,QAAQ,MAAM,KAAK;AACzB,UAAM,OAAO,MAAM,cAAc,YAAY,MAAM,cAAc,UAAU,CAAC,QAAQ;AACpF,cAAU,KAAK,OAAO,IAAI;AAAA,EAC5B;AAEA,QAAM,UAAU,CAAC,UAAkE;AACjF,WAAO;AACP,QAAI,MAAM,cAAc,oBAAoB,MAAM,SAAS,GAAG;AAC5D,YAAM,cAAc,wBAAwB,MAAM,SAAS;AAAA,IAC7D;AAAA,EACF;AAEA,QAAM,kBAAmE,CAAC,UAAU;AAClF,UAAM,OAAO,SAAS,KAAK,cAAc;AACzC,UAAM,MAAM,MAAM,YAAY,SAAS,IAAI,OAAO,cAAc,OAAO;AACvE,UAAM,SACJ,MAAM,cAAc,WAAW,YAAY,MAAM,cAAc,QAAQ,cAAc,MAAM,cAAc,SAAS,eAAe;AACnI,UAAM,SACJ,MAAM,cAAc,WAAW,cAAc,MAAM,cAAc,QAAQ,YAAY,MAAM,cAAc,SAAS,cAAc;AAClI,QAAI,MAAM,QAAQ,QAAQ;AACxB,YAAM,eAAe;AACrB,gBAAU,OAAO,MAAM,UAAU;AAAA,IACnC,WAAW,MAAM,QAAQ,QAAQ;AAC/B,YAAM,eAAe;AACrB,gBAAU,OAAO,MAAM,UAAU;AAAA,IACnC,WAAW,MAAM,QAAQ,QAAQ;AAC/B,YAAM,eAAe;AACrB,gBAAU,MAAM,OAAO;AAAA,IACzB,WAAW,MAAM,QAAQ,OAAO;AAC9B,YAAM,eAAe;AACrB,gBAAU,GAAG;AAAA,IACf;AAAA,EACF;AAIA;AAAA,IACE;AAAA,MACE,MAAM,MAAM;AAAA,MACZ,CAAC,SAAS;AACR,YAAI,CAAC,MAAM;AACT,sBAAY,IAAI;AAChB;AAAA,QACF;AACA,cAAM,OAAO;AAGb,cAAM,SAAS,MAAM,SAAS,SAAS,aAAa,IAAI,OAAO,SAAS;AACxE,cAAM,MAAM;AACZ,kBAAU,MAAM,aAAa,QAAQ,IAAI,CAAC;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAEA,QAAM,cAAc,MAAe,CAAC,MAAM,sBAAsB,CAAC,CAAC,MAAM,WAAW,MAAM;AACzF,QAAM,cAAc,MAAqB;AACvC,UAAM,QAAuB,CAAC;AAC9B,QAAI,MAAM,gBAAgB;AACxB,YAAM;AAAA,QACJ,CAAC;AAAA,UACC,QAAQ;AAAA,UACR,KAAK;AAAA,UACL,SAAS,MAAM;AAAA,UACf,YACE,MAAM,SAAS,aAAa,MAAM,oBAAoB,MAAM,SAAS,UAAU,MAAM,mBAAmB,MAAM;AAAA,SAEjH;AAAA,UACC,CAAC,KAAK,MAAM,MAAM,SAAS,aAAa,qBAAqB,gBAAgB,EAAE;AAAA,QACjF,EATC;AAAA,MAUH;AAAA,IACF;AACA,QAAI,MAAM,SAAS;AACjB,YAAM;AAAA,QACJ,CAAC,OAAO,QAAQ,WAAW,KAAK,QAAQ,SAAS,MAAM,aAAa,YAAY,MAAM,gBAAgB;AAAA,UACpG,CAAC,KAAK,KAAK,QAAQ,EAAE;AAAA,QACvB,EAFC;AAAA,MAGH;AAAA,IACF;AACA,QAAI,MAAM,qBAAsB,OAAM,QAAQ;AAC9C,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAyB;AACzC,QAAI,MAAM,aAAa,SAAS,MAAM,MAAM;AAC1C,YAAM,KAAK,GAAG,SAAS,CAAC;AACxB,aAAO,EAAE,GAAI,SAAS,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,OAAO,GAAG,GAAI,YAAY,OAAO;AAAA,IAChF;AACA,WAAO,CAAC;AAAA,EACV;AAEA,SACE,CAAC;AAAA,QACK;AAAA,IACJ,KAAK,UAAU,MAAM,KAAK,CAAC,OAAQ,SAAS,EAAqB;AAAA,IACjE,aAAa,MAAM,aAAa,KAAK;AAAA,IACrC,UAAU;AAAA,IACV,KAAK;AAAA,IACL,YAAY,MAAM,YAAY,WAAW;AAAA,IACzC,OAAO,GAAG,cAAc,MAAM,OAAO,cAAc,MAAM,OAAO,IAAI,QAAQ,MAAM,SAAS,IAAI,MAAM,QAAQ,GAAG;AAAA,MAC9G,iBAAiB,MAAM,SAAS;AAAA,MAChC,cAAc,MAAM,SAAS;AAAA,MAC7B,wBAAwB,MAAM;AAAA,IAChC,CAAC;AAAA,IACD,OAAO,WAAW,EAAE,cAAc,MAAM,MAAM,GAAG,UAAU,EAAE,GAAG,MAAM,KAAK;AAAA,GAC5E;AAAA,MACC,CAAC,KAAK,MAAM,MAAM,WAAW;AAAA,QAC3B,CAAC;AAAA,IACC,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,UAAU;AAAA,IACV,kBAAkB,SAAS,IAAI,eAAe;AAAA,IAC9C,YAAY,MAAM;AAAA,IAClB,eAAe,MAAM;AAAA,IACrB,eAAe,KAAK,MAAM,MAAM,YAAY,SAAS,IAAI,OAAO,cAAc,OAAO,WAAW;AAAA,IAChG,eAAe,KAAK,MAAM,SAAS,KAAK,cAAc,CAAC;AAAA,IACvD,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,WAAW;AAAA,GACZ;AAAA,UACC,CAAC,KAAK,MAAM,8BAA8B,EAAE;AAAA,QAC9C,EAjBC,IAiBK;AAAA,MACR,EAnBC,KAmBM;AAAA,MACP,CAAC,KAAK,MAAM,YAAY,GAAG;AAAA,QACzB,CAAC,IAAI,MAAM,sBAAsB,YAAY,EAAE,EAA9C,IAAoD;AAAA,MACvD,EAFC,KAEM;AAAA,MACP,CAAC,KAAK,MAAM,MAAM,UAAU,MAAM,SAAS,SAAS;AAAA,QAClD,CAAC,IAAI,MAAM,qBAAqB,MAAM,SAAS,EAA9C,IAAoD;AAAA,MACvD,EAFC,KAEM;AAAA,IACT,EAxCC;AA0CL;AAEO,SAAS,MAAM,OAA6C;AACjE,QAAM,SAAS,WAAW,EAAE,SAAS,WAAoB,WAAW,UAAmB,YAAY,KAAK,GAAG,KAAK;AAChH,QAAM,CAAC,OAAO,IAAI,IAAI,WAAW,QAAQ;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,CAAC,MAAM,OAAO,IAAI,aAAmB,IAAI;AAC/C,MAAI;AAEJ,QAAM,QAAQ,oBAAoB;AAAA,IAChC,IAAI,MAAM,MAAM;AAAA,IAChB,SAAS,EAAE,OAAO,IAAI,MAAM,GAAG;AAAA,IAC/B,YAAY,EAAE,WAAW,eAAe;AAAA,IACxC,QAAQ;AAAA,EACV,CAAC;AAED,eAAa,MAAM;AACjB,QAAI,CAAC,MAAM,UAAU,CAAC,MAAM,cAAc,CAAC,MAAM,QAAS;AAC1D,UAAM,YAAY,CAAC,UAA+B;AAGhD,UAAI,MAAM,QAAQ,YAAY,CAAC,MAAM,oBAAoB,kBAAkB,SAAS,EAAG,OAAM,UAAU;AAAA,IACzG;AACA,aAAS,iBAAiB,WAAW,SAAS;AAC9C,cAAU,MAAM,SAAS,oBAAoB,WAAW,SAAS,CAAC;AAAA,EACpE,CAAC;AAED,QAAM,mBAAmB,MAAY;AACnC,YAAQ,CAAC,SAAU,SAAS,aAAa,UAAU,SAAS,OAAO,aAAa,IAAK;AAAA,EACvF;AACA,QAAM,cAAc,MAAY;AAC9B,UAAM,UAAU;AAChB,YAAQ,IAAI;AAAA,EACd;AAEA,QAAM,QAAQ,MACZ,CAAC;AAAA,QACK;AAAA,IACJ,KAAK,MAAM;AAAA,IACX,QAAQ,MAAM;AAAA,IACd,SAAS,MAAM;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,MAAM,KAAK;AAAA,IACX,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,GAChB;AAAA,OACE,MAAM,SAAS;AAAA,IAClB,EAZC;AAeH,SACE,CAAC,KAAK,MAAM,MAAM,QAAQ,GAAG;AAAA,MAC3B,CAAC,OAAO,OAAQ,WAAW,SAAY,SAAS,MAAe;AAAA,QAC7D,CAAC;AAAA,IACC,MAAM,MAAM,YAAY;AAAA,IACxB,UACE,CAAC;AAAA,MACC,KAAK,CAAC,OAAQ,YAAY;AAAA,MAC1B;AAAA,MACA,OAAO,GAAG,uBAAuB,aAAa,QAAQ,MAAM,SAAS,IAAI,cAAc,MAAM,OAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,KACxH;AAAA,cACC,CAAC,kBAAkB,aAAa,MAAM,CAAC,MAAM,uBAAuB,YAAY,GAAG;AAAA,iBAChF,MAAM,EAAE;AAAA,cACX,EAFC,kBAEmB;AAAA,YACtB,EARC;AAAA,GAUJ;AAAA,UACC,CAAC;AAAA,IACC,KAAK,CAAC,OAAQ,YAAY;AAAA,IAC1B;AAAA,IACA,OAAO,GAAG,MAAM,sBAAsB,wBAAwB,uBAAuB,MAAM,QAAQ,CAAC;AAAA,GACrG;AAAA,aACE,MAAM,EAAE;AAAA,UACX,EANC,IAMK;AAAA,QACR,EArBC,KAqBM;AAAA,MACT,EAvBC,OAuBQ;AAAA,IACX,EAzBC;AA2BL;AAEA,IAAO,gBAAQ;","names":[],"file":"sheet.jsx"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/components/layout/sheet/sheet.tsx"],"sourcesContent":["import { type JSX, type ParentProps, Show, createEffect, createSignal, mergeProps, on, onCleanup, splitProps } from \"solid-js\";\nimport { Portal, isServer } from \"solid-js/web\";\nimport cn from \"clsx\";\nimport { Button } from \"../../inputs/button\";\nimport { Icon } from \"../../base/icon\";\nimport { ClickAwayListener } from \"../../clickAwayListener\";\nimport { createCssTransition } from \"../../../primitives/createCssTransition\";\nimport { isTopOverlayLayer } from \"../../../primitives/overlayLayer\";\nimport { restoreFocus } from \"../../../primitives/restoreFocus\";\nimport { mergeRefs, type Ref } from \"../../../primitives/mergeRefs\";\nimport { mergeStyle } from \"../../../primitives/mergeStyle\";\n\nexport interface SheetProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onResize\"> {\n placement?: \"top\" | \"bottom\" | \"right\" | \"left\";\n isOpen: boolean;\n onClose?: (() => void) | undefined;\n variant?: \"default\" | \"modal\";\n withSizeToggle?: boolean;\n /** Hide built-in header actions; onClose still handles Esc and backdrop. */\n hideHeaderActions?: boolean;\n reverseHeaderActions?: boolean;\n /** Accessible name of the header close button (default \"Close sheet\"). */\n closeAriaLabel?: string;\n /**\n * Accessible name of the size toggle while the sheet is at its normal size (default \"Expand sheet\"). The toggle\n * cycles normal, expanded, collapsed and back, and its name always says what the next press does; the\n * name changing is how it exposes its state. It shows the `open_in_full` icon, and `close_fullscreen` while expanded.\n */\n expandAriaLabel?: string;\n /** Accessible name of the size toggle while the sheet is expanded (default \"Collapse sheet\"). */\n collapseAriaLabel?: string;\n /** Accessible name of the size toggle while the sheet is collapsed to its header (default \"Restore sheet size\"). */\n restoreAriaLabel?: string;\n size?: string;\n /**\n * Gap between the top edge of the window and the top of the sheet and of its modal scrim (px, or any CSS length),\n * so a panel can start below a fixed app bar and leave it visible and clickable. It applies to the `top`, `left`\n * and `right` placements and to the scrim of every placement. Without it the sheet takes the page's\n * `--smui-sheet-offset-top`, which `AppLayout` sets to the height of its sticky header and which is 0 elsewhere;\n * `offsetTop={0}` covers the header anyway. A press in the strip above a modal scrim belongs to the page and does\n * not close the sheet, so a header button can toggle it. The modal sheet keeps `aria-modal`, though that strip can\n * still be reached by pointer and Tab; for a header that must stay available to assistive technology, use\n * `variant=\"default\"`.\n */\n offsetTop?: number | string;\n disableOutsideClick?: boolean;\n /** Close the sheet when Escape is pressed. */\n closeOnEsc?: boolean;\n /** Allow drag-to-resize (mobile bottom-sheet style). Off by default. */\n resizable?: boolean;\n /** Minimum size in px while resizing (default 80). */\n minSize?: number;\n /** Maximum size in px while resizing (default: viewport dimension). */\n maxSize?: number;\n /** Step in px for keyboard resizing (default 24). */\n resizeStep?: number;\n /** Accessible label for the resize handle. */\n resizeHandleAriaLabel?: string;\n /** Called with the new size in px while/after resizing. */\n onResize?: (size: number) => void;\n \"aria-label\"?: string;\n /** Test id of the sheet panel (the dialog); `sheet` unless given. */\n \"data-testid\"?: string | undefined;\n ref?: Ref<HTMLDivElement>;\n}\n\ntype Mode = \"small\" | \"expanded\" | null;\n\n/**\n * Whether a press ended above the top edge of the scrim, i.e. in the strip an `offsetTop` leaves uncovered. The page\n * owns that strip (a header button there, say), so it is not \"away\" from a modal sheet: a button that toggles the\n * sheet would otherwise see it close on the release and open again on the click.\n */\nconst landedAboveScrim = (event: MouseEvent | TouchEvent, scrim: HTMLElement | null | undefined): boolean => {\n const y = \"changedTouches\" in event ? event.changedTouches[0]?.clientY : event.clientY;\n return scrim != null && y !== undefined && y < scrim.getBoundingClientRect().top;\n};\n\nconst isVerticalAxis = (placement: SheetProps[\"placement\"]): boolean => placement === \"bottom\" || placement === \"top\";\n\ninterface SheetBlockProps extends ParentProps<SheetProps> {\n mode: Mode;\n handleSizeButton: () => void;\n handleClose: () => void;\n}\n\nfunction SheetBlock(props: SheetBlockProps): JSX.Element {\n const merged = mergeProps(\n {\n size: \"60%\",\n withSizeToggle: true,\n hideHeaderActions: false,\n reverseHeaderActions: false,\n closeAriaLabel: \"Close sheet\",\n expandAriaLabel: \"Expand sheet\",\n collapseAriaLabel: \"Collapse sheet\",\n restoreAriaLabel: \"Restore sheet size\",\n resizable: false,\n minSize: 80,\n resizeStep: 24,\n resizeHandleAriaLabel: \"Resize sheet\",\n },\n props\n );\n const [local, rest] = splitProps(merged, [\n \"isOpen\",\n \"placement\",\n \"class\",\n \"mode\",\n \"size\",\n \"variant\",\n \"onClose\",\n \"withSizeToggle\",\n \"hideHeaderActions\",\n \"reverseHeaderActions\",\n \"closeAriaLabel\",\n \"expandAriaLabel\",\n \"collapseAriaLabel\",\n \"restoreAriaLabel\",\n \"resizable\",\n \"minSize\",\n \"maxSize\",\n \"resizeStep\",\n \"resizeHandleAriaLabel\",\n \"onResize\",\n \"style\",\n \"handleClose\",\n \"handleSizeButton\",\n \"children\",\n \"ref\",\n \"data-testid\",\n ]);\n\n let rootEl: HTMLDivElement | undefined;\n const [dragSize, setDragSize] = createSignal<number | null>(null);\n const vertical = (): boolean => isVerticalAxis(local.placement);\n\n const inner = createCssTransition({\n in: () => local.isOpen,\n timeout: { enter: 120, exit: 120 },\n classNames: { enterDone: \"smwb-sheet_entered\" },\n appear: true,\n });\n\n const clamp = (px: number): number => {\n const viewport = vertical() ? window.innerHeight : window.innerWidth;\n const max = local.maxSize ?? viewport;\n return Math.max(local.minSize, Math.min(max, px));\n };\n\n const currentSizePx = (): number => {\n const rect = rootEl?.getBoundingClientRect();\n if (!rect) return local.minSize;\n return vertical() ? rect.height : rect.width;\n };\n\n const applySize = (px: number): void => {\n const next = clamp(px);\n setDragSize(next);\n local.onResize?.(next);\n };\n\n let drag: { start: number; size: number } | null = null;\n\n const onPointerDown = (event: PointerEvent & { currentTarget: HTMLDivElement }): void => {\n event.preventDefault();\n drag = { start: vertical() ? event.clientY : event.clientX, size: currentSizePx() };\n try {\n event.currentTarget.setPointerCapture?.(event.pointerId);\n } catch {\n /* best-effort */\n }\n };\n\n const onPointerMove = (event: PointerEvent): void => {\n if (!drag) return;\n const pos = vertical() ? event.clientY : event.clientX;\n const delta = pos - drag.start;\n const grow = local.placement === \"bottom\" || local.placement === \"right\" ? -delta : delta;\n applySize(drag.size + grow);\n };\n\n const endDrag = (event: PointerEvent & { currentTarget: HTMLDivElement }): void => {\n drag = null;\n if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {\n event.currentTarget.releasePointerCapture?.(event.pointerId);\n }\n };\n\n const onHandleKeyDown: JSX.EventHandler<HTMLDivElement, KeyboardEvent> = (event) => {\n const base = dragSize() ?? currentSizePx();\n const max = local.maxSize ?? (vertical() ? window.innerHeight : window.innerWidth);\n const incKey =\n local.placement === \"bottom\" ? \"ArrowUp\" : local.placement === \"top\" ? \"ArrowDown\" : local.placement === \"left\" ? \"ArrowRight\" : \"ArrowLeft\";\n const decKey =\n local.placement === \"bottom\" ? \"ArrowDown\" : local.placement === \"top\" ? \"ArrowUp\" : local.placement === \"left\" ? \"ArrowLeft\" : \"ArrowRight\";\n if (event.key === incKey) {\n event.preventDefault();\n applySize(base + local.resizeStep);\n } else if (event.key === decKey) {\n event.preventDefault();\n applySize(base - local.resizeStep);\n } else if (event.key === \"Home\") {\n event.preventDefault();\n applySize(local.minSize);\n } else if (event.key === \"End\") {\n event.preventDefault();\n applySize(max);\n }\n };\n\n // Keyed on `isOpen` alone: root.focus() fires focus handlers synchronously, and Solid runs those\n // without untrack, so any signal they read would otherwise re-run this effect and steal focus.\n createEffect(\n on(\n () => local.isOpen,\n (open) => {\n if (!open) {\n setDragSize(null);\n return;\n }\n const root = rootEl;\n // The element that had focus when the sheet opened gets it back when it closes (or unmounts\n // while open), unless the app has put focus somewhere else by then.\n const opener = root?.contains(document.activeElement) ? null : document.activeElement;\n root?.focus();\n onCleanup(() => restoreFocus(opener, root));\n },\n ),\n );\n\n const showActions = (): boolean => !local.hideHeaderActions && (!!local.onClose || local.withSizeToggle);\n const actionNodes = (): JSX.Element[] => {\n const nodes: JSX.Element[] = [];\n if (local.withSizeToggle) {\n nodes.push(\n <Button\n variant=\"outlined\"\n size=\"small\"\n onClick={local.handleSizeButton}\n aria-label={\n local.mode === \"expanded\" ? local.collapseAriaLabel : local.mode === \"small\" ? local.restoreAriaLabel : local.expandAriaLabel\n }\n >\n <Icon name={local.mode === \"expanded\" ? \"close_fullscreen\" : \"open_in_full\"} />\n </Button>\n );\n }\n if (local.onClose) {\n nodes.push(\n <Button variant=\"outlined\" size=\"small\" onClick={local.handleClose} aria-label={local.closeAriaLabel}>\n <Icon name=\"close\" />\n </Button>\n );\n }\n if (local.reverseHeaderActions) nodes.reverse();\n return nodes;\n };\n\n const sizeStyle = (): JSX.CSSProperties => {\n if (local.resizable && dragSize() !== null) {\n const px = `${dragSize()}px`;\n return { ...(vertical() ? { height: px } : { width: px }), transition: \"none\" };\n }\n return {};\n };\n\n return (\n <div\n {...rest}\n ref={mergeRefs(local.ref, (el) => (rootEl = el as HTMLDivElement))}\n data-testid={local[\"data-testid\"] ?? \"sheet\"}\n tabindex={-1}\n role=\"dialog\"\n aria-modal={local.variant === \"modal\" || undefined}\n class={cn(\"smwb-sheet\", local.class, `smwb-sheet_${local.variant}`, `smwb-${local.placement}`, inner.classes(), {\n \"smwb-expanded\": local.mode === \"expanded\",\n \"smwb-small\": local.mode === \"small\",\n \"smwb-sheet_resizable\": local.resizable,\n })}\n style={mergeStyle({ \"--sizeProp\": local.size, ...sizeStyle() }, local.style)}\n >\n <Show when={local.resizable}>\n <div\n class=\"smwb-sheet__drag-handle\"\n data-testid=\"sheet-drag-handle\"\n role=\"separator\"\n tabindex={0}\n aria-orientation={vertical() ? \"horizontal\" : \"vertical\"}\n aria-label={local.resizeHandleAriaLabel}\n aria-valuemin={local.minSize}\n aria-valuemax={Math.round(local.maxSize ?? (vertical() ? window.innerHeight : window.innerWidth))}\n aria-valuenow={Math.round(dragSize() ?? currentSizePx())}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onKeyDown={onHandleKeyDown}\n >\n <span class=\"smwb-sheet__drag-handle-bar\" />\n </div>\n </Show>\n <Show when={showActions()}>\n <div class=\"smwb-sheet__header\">{actionNodes()}</div>\n </Show>\n <Show when={local.isOpen && local.mode !== \"small\"}>\n <div class=\"smwb-sheet__inner\">{local.children}</div>\n </Show>\n </div>\n );\n}\n\nexport function Sheet(props: ParentProps<SheetProps>): JSX.Element {\n const merged = mergeProps({ variant: \"default\" as const, placement: \"bottom\" as const, closeOnEsc: true }, props);\n const [local, rest] = splitProps(merged, [\n \"isOpen\",\n \"onClose\",\n \"variant\",\n \"children\",\n \"placement\",\n \"disableOutsideClick\",\n \"closeOnEsc\",\n \"offsetTop\",\n \"ref\",\n ]);\n\n const [mode, setMode] = createSignal<Mode>(null);\n let wrapperEl: HTMLDivElement | undefined;\n\n const outer = createCssTransition({\n in: () => local.isOpen,\n timeout: { enter: 70, exit: 70 },\n classNames: { enterDone: \"smwb-entered\" },\n appear: true,\n });\n\n createEffect(() => {\n if (!local.isOpen || !local.closeOnEsc || !local.onClose) return;\n const onKeyDown = (event: KeyboardEvent): void => {\n // Only the topmost overlay layer reacts to Escape, and not to one handled inside\n // it, e.g. by a menu closing on it.\n if (event.key === \"Escape\" && !event.defaultPrevented && isTopOverlayLayer(wrapperEl)) local.onClose?.();\n };\n document.addEventListener(\"keydown\", onKeyDown);\n onCleanup(() => document.removeEventListener(\"keydown\", onKeyDown));\n });\n\n const handleSizeButton = (): void => {\n setMode((prev) => (prev === \"expanded\" ? \"small\" : prev === null ? \"expanded\" : null));\n };\n const handleClose = (): void => {\n local.onClose?.();\n setMode(null);\n };\n\n // The variable goes on the wrapper, so the panel and the scrim both inherit it. Left off when not given: an\n // undefined style key would print `style=\"\"` on the server.\n const wrapperStyle = (): JSX.CSSProperties | undefined => {\n const offset = local.offsetTop;\n return offset === undefined ? undefined : { \"--smui-sheet-offset-top\": typeof offset === \"number\" ? `${offset}px` : offset };\n };\n\n const block = (): JSX.Element => (\n <SheetBlock\n {...rest}\n ref={local.ref}\n isOpen={local.isOpen}\n onClose={local.onClose}\n handleSizeButton={handleSizeButton}\n handleClose={handleClose}\n mode={mode()}\n placement={local.placement}\n variant={local.variant}\n >\n {local.children}\n </SheetBlock>\n );\n\n return (\n <Show when={outer.mounted()}>\n <Portal mount={(isServer ? undefined : document.body) as Node}>\n <Show\n when={local.variant === \"default\"}\n fallback={\n <div\n ref={(el) => (wrapperEl = el)}\n data-smwb-overlay-layer\n style={wrapperStyle()}\n class={cn(\"smwb-sheet__overlay\", \"smwb-dark\", `smwb-${local.placement}`, `smwb-sheet_${local.variant}`, outer.classes())}\n >\n <ClickAwayListener\n onClickAway={(event) => !local.disableOutsideClick && !landedAboveScrim(event, wrapperEl) && handleClose()}\n >\n {block()}\n </ClickAwayListener>\n </div>\n }\n >\n <div\n ref={(el) => (wrapperEl = el)}\n data-smwb-overlay-layer\n style={wrapperStyle()}\n class={cn(local.disableOutsideClick ? \"smwb-sheet__overlay\" : \"smwb-sheet__default\", outer.classes())}\n >\n {block()}\n </div>\n </Show>\n </Portal>\n </Show>\n );\n}\n\nexport default Sheet;\n"],"mappings":"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","names":[],"file":"sheet.jsx"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/components/layout/tabGroups/index.ts"],
|
|
4
|
-
"sourcesContent": ["export { TabGroups, default } from \"./tabGroups\";\nexport type { TabGroupsProps, TabGroupsTab } from \"./tabGroups\";\n// The pure model behind the component: `tabGroupsLayout.addTab`, `parseTabGroupsLayout`, \u2026\n// Generic names stay inside the namespace, so the barrel gains no ambiguous top-level functions.\nexport * as tabGroupsLayout from \"./tabGroupsLayout\";\nexport type {\n TabGroupsChange,\n TabGroupsDropZone,\n TabGroupsEdge,\n TabGroupsGroup,\n TabGroupsLabels,\n TabGroupsLayout,\n TabGroupsMoveTarget,\n TabGroupsNode,\n TabGroupsSplit,\n} from \"./tabGroupsLayout\";\n"],
|
|
4
|
+
"sourcesContent": ["export { TabGroups, default } from \"./tabGroups\";\nexport type { TabGroupsProps, TabGroupsStripGroup, TabGroupsTab } from \"./tabGroups\";\n// The pure model behind the component: `tabGroupsLayout.addTab`, `parseTabGroupsLayout`, \u2026\n// Generic names stay inside the namespace, so the barrel gains no ambiguous top-level functions.\nexport * as tabGroupsLayout from \"./tabGroupsLayout\";\nexport type {\n TabGroupsChange,\n TabGroupsDropZone,\n TabGroupsEdge,\n TabGroupsGroup,\n TabGroupsLabels,\n TabGroupsLayout,\n TabGroupsMoveTarget,\n TabGroupsNode,\n TabGroupsSplit,\n} from \"./tabGroupsLayout\";\n"],
|
|
5
5
|
"mappings": "AAAA,SAAS,WAAW,WAAAA,gBAAe;AAInC,YAAY,qBAAqB;",
|
|
6
6
|
"names": ["default"]
|
|
7
7
|
}
|
|
@@ -56,6 +56,8 @@ import {
|
|
|
56
56
|
lastStopOf,
|
|
57
57
|
ownGroupIdOf,
|
|
58
58
|
ownerRootOf,
|
|
59
|
+
slotFocusHeir,
|
|
60
|
+
slotFocusOf,
|
|
59
61
|
tabMove
|
|
60
62
|
} from "./tabGroupsFocus";
|
|
61
63
|
const CHORD_SHORTCUTS = [
|
|
@@ -74,6 +76,7 @@ const DIRECTION_CHORDS = [
|
|
|
74
76
|
["top", ["Alt", "Shift", "ArrowUp"]],
|
|
75
77
|
["bottom", ["Alt", "Shift", "ArrowDown"]]
|
|
76
78
|
];
|
|
79
|
+
const present = (node) => node != null && typeof node !== "boolean" && node !== "";
|
|
77
80
|
const FIRST_MENU_ITEM = '[role^="menuitem"]:not([aria-disabled="true"])';
|
|
78
81
|
function groupIdOf(node) {
|
|
79
82
|
let current = node ?? null;
|
|
@@ -181,7 +184,9 @@ function TabGroups(props) {
|
|
|
181
184
|
"minGroupSize",
|
|
182
185
|
"keyboardStep",
|
|
183
186
|
"groupActions",
|
|
187
|
+
"stripActions",
|
|
184
188
|
"dense",
|
|
189
|
+
"fit",
|
|
185
190
|
"labels",
|
|
186
191
|
// Wrapped so that the caller's handler still runs, first.
|
|
187
192
|
"onDragStart",
|
|
@@ -300,6 +305,7 @@ function TabGroups(props) {
|
|
|
300
305
|
let leaving = false;
|
|
301
306
|
let lastFocus = null;
|
|
302
307
|
let pointerFocus = false;
|
|
308
|
+
let slotFocus = null;
|
|
303
309
|
const announce = (next, change) => {
|
|
304
310
|
const text = describeTabGroupsChange(change, next, tabTitle, labels());
|
|
305
311
|
if (text === "") return;
|
|
@@ -340,6 +346,18 @@ function TabGroups(props) {
|
|
|
340
346
|
if (active !== null && active !== doc.body && active !== pending.from && !containsDeep(rootEl, active)) return;
|
|
341
347
|
element.focus();
|
|
342
348
|
};
|
|
349
|
+
const restoreSlotFocus = () => {
|
|
350
|
+
const lost = slotFocus;
|
|
351
|
+
if (!lost || !rootEl || lost.element.isConnected) return;
|
|
352
|
+
slotFocus = null;
|
|
353
|
+
const doc = rootEl.ownerDocument;
|
|
354
|
+
const active = deepActiveElement(doc);
|
|
355
|
+
if (active !== null && active !== doc.body) return;
|
|
356
|
+
slotFocusHeir(rootEl, lost, layout().activeGroup)?.focus();
|
|
357
|
+
};
|
|
358
|
+
const forgetGoneSlotFocus = () => {
|
|
359
|
+
if (slotFocus && !slotFocus.element.isConnected) slotFocus = null;
|
|
360
|
+
};
|
|
343
361
|
const commit = (next, change) => {
|
|
344
362
|
if (next === latest) return;
|
|
345
363
|
latest = next;
|
|
@@ -360,11 +378,16 @@ function TabGroups(props) {
|
|
|
360
378
|
latest = layout();
|
|
361
379
|
};
|
|
362
380
|
if (!isServer) {
|
|
381
|
+
createComputed(() => {
|
|
382
|
+
layout();
|
|
383
|
+
forgetGoneSlotFocus();
|
|
384
|
+
});
|
|
363
385
|
createEffect(
|
|
364
386
|
on(
|
|
365
387
|
layout,
|
|
366
388
|
() => {
|
|
367
389
|
focusPending();
|
|
390
|
+
restoreSlotFocus();
|
|
368
391
|
},
|
|
369
392
|
{ defer: true }
|
|
370
393
|
)
|
|
@@ -790,6 +813,7 @@ function TabGroups(props) {
|
|
|
790
813
|
if (!root || !(target instanceof HTMLElement)) return;
|
|
791
814
|
const previous = lastFocus;
|
|
792
815
|
lastFocus = ownerRootOf(target) === root ? target : null;
|
|
816
|
+
slotFocus = lastFocus === null ? null : slotFocusOf(root, target);
|
|
793
817
|
if (previous instanceof HTMLElement && previous.localName === "iframe" && previous !== target && !pointerFocus) {
|
|
794
818
|
const instead = frameExitTarget(root, previous, target);
|
|
795
819
|
if (instead !== null && instead === guardEl) {
|
|
@@ -841,7 +865,17 @@ function TabGroups(props) {
|
|
|
841
865
|
}, 0);
|
|
842
866
|
};
|
|
843
867
|
const onFocusOut = (event) => {
|
|
844
|
-
if (event.relatedTarget instanceof Node && !root.contains(event.relatedTarget))
|
|
868
|
+
if (event.relatedTarget instanceof Node && !root.contains(event.relatedTarget)) {
|
|
869
|
+
lastFocus = null;
|
|
870
|
+
slotFocus = null;
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
const lost = slotFocus;
|
|
874
|
+
if (event.relatedTarget === null && lost?.element === event.target) {
|
|
875
|
+
queueMicrotask(() => {
|
|
876
|
+
if (slotFocus === lost && lost.element.isConnected) slotFocus = null;
|
|
877
|
+
});
|
|
878
|
+
}
|
|
845
879
|
};
|
|
846
880
|
const onWindowBlur = () => {
|
|
847
881
|
const active = root.ownerDocument.activeElement;
|
|
@@ -897,6 +931,7 @@ function TabGroups(props) {
|
|
|
897
931
|
if (given?.disabled) extra.disabled = true;
|
|
898
932
|
if (given?.closeLabel !== void 0) extra.closeLabel = given.closeLabel;
|
|
899
933
|
if (given?.actions !== void 0) extra.actions = given.actions;
|
|
934
|
+
if (local.fit === true && given?.title !== void 0) extra.title = given.title;
|
|
900
935
|
return extra;
|
|
901
936
|
});
|
|
902
937
|
const shortcuts = createMemo(() => meta()?.disabled ? void 0 : CHORD_SHORTCUTS);
|
|
@@ -922,6 +957,21 @@ function TabGroups(props) {
|
|
|
922
957
|
const index = tabs().indexOf(active);
|
|
923
958
|
return index < 0 ? 0 : index;
|
|
924
959
|
};
|
|
960
|
+
const stripIndex = createMemo(() => indexOfGroup(groupId));
|
|
961
|
+
const stripActive = createMemo(() => layout().activeGroup === groupId);
|
|
962
|
+
const stripGroup = {
|
|
963
|
+
get index() {
|
|
964
|
+
return stripIndex();
|
|
965
|
+
},
|
|
966
|
+
get count() {
|
|
967
|
+
return groupCount();
|
|
968
|
+
},
|
|
969
|
+
get active() {
|
|
970
|
+
return stripActive();
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
const strip = resolveChildren(() => local.stripActions?.(stripGroup));
|
|
974
|
+
const hasStrip = () => strip.toArray().some(present);
|
|
925
975
|
return <div
|
|
926
976
|
class={cn("smwb-tab-groups__header", {
|
|
927
977
|
"smwb-tab-groups__header--active": layout().activeGroup === groupId
|
|
@@ -940,9 +990,13 @@ function TabGroups(props) {
|
|
|
940
990
|
scrollable
|
|
941
991
|
overflowMenu
|
|
942
992
|
dense={local.dense === true}
|
|
993
|
+
fit={local.fit === true}
|
|
943
994
|
>
|
|
944
995
|
<For each={tabs()}>{(tabId) => renderTab(groupId, tabId)}</For>
|
|
945
996
|
</Tabs>
|
|
997
|
+
<Show when={hasStrip()}>
|
|
998
|
+
<div class="smwb-tab-groups__strip-actions">{strip()}</div>
|
|
999
|
+
</Show>
|
|
946
1000
|
<Show when={withGroupActions()}>
|
|
947
1001
|
<button
|
|
948
1002
|
type="button"
|