@stll/ui 0.0.1-placeholder.0 → 0.2.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.
Files changed (133) hide show
  1. package/README.md +84 -0
  2. package/dist/components/accordion.d.ts +8 -0
  3. package/dist/components/accordion.js +38 -0
  4. package/dist/components/alert-dialog.d.ts +32 -0
  5. package/dist/components/alert-dialog.js +75 -0
  6. package/dist/components/avatar.d.ts +7 -0
  7. package/dist/components/avatar.js +22 -0
  8. package/dist/components/bidi-text.d.ts +24 -0
  9. package/dist/components/bidi-text.js +38 -0
  10. package/dist/components/brand-icons.d.ts +7 -0
  11. package/dist/components/brand-icons.js +18 -0
  12. package/dist/components/breadcrumb.d.ts +12 -0
  13. package/dist/components/breadcrumb.js +61 -0
  14. package/dist/components/button-variants.d.ts +17 -0
  15. package/dist/components/button-variants.js +43 -0
  16. package/dist/components/button.d.ts +20 -0
  17. package/dist/components/button.js +53 -0
  18. package/dist/components/checkbox.d.ts +5 -0
  19. package/dist/components/checkbox.js +44 -0
  20. package/dist/components/color-picker.d.ts +47 -0
  21. package/dist/components/color-picker.js +249 -0
  22. package/dist/components/combobox.d.ts +40 -0
  23. package/dist/components/combobox.js +208 -0
  24. package/dist/components/command.d.ts +34 -0
  25. package/dist/components/command.js +100 -0
  26. package/dist/components/date-picker-popover.d.ts +29 -0
  27. package/dist/components/date-picker-popover.js +548 -0
  28. package/dist/components/date-picker-popover.logic.d.ts +14 -0
  29. package/dist/components/date-picker-popover.logic.js +26 -0
  30. package/dist/components/destructive-action-confirmation.d.ts +21 -0
  31. package/dist/components/destructive-action-confirmation.js +60 -0
  32. package/dist/components/destructive-confirm-dialog.d.ts +17 -0
  33. package/dist/components/destructive-confirm-dialog.js +49 -0
  34. package/dist/components/dialog.d.ts +37 -0
  35. package/dist/components/dialog.js +92 -0
  36. package/dist/components/directional-icon.d.ts +30 -0
  37. package/dist/components/directional-icon.js +12 -0
  38. package/dist/components/field.d.ts +11 -0
  39. package/dist/components/field.js +34 -0
  40. package/dist/components/form.d.ts +5 -0
  41. package/dist/components/form.js +12 -0
  42. package/dist/components/frame.d.ts +10 -0
  43. package/dist/components/frame.js +35 -0
  44. package/dist/components/hex-color-picker.d.ts +11 -0
  45. package/dist/components/hex-color-picker.js +366 -0
  46. package/dist/components/input-group.d.ts +15 -0
  47. package/dist/components/input-group.js +53 -0
  48. package/dist/components/input-otp.d.ts +13 -0
  49. package/dist/components/input-otp.js +39 -0
  50. package/dist/components/input.d.ts +12 -0
  51. package/dist/components/input.js +46 -0
  52. package/dist/components/label.d.ts +5 -0
  53. package/dist/components/label.js +18 -0
  54. package/dist/components/menu.d.ts +44 -0
  55. package/dist/components/menu.js +152 -0
  56. package/dist/components/outline-rail.d.ts +39 -0
  57. package/dist/components/outline-rail.js +405 -0
  58. package/dist/components/pagination.d.ts +17 -0
  59. package/dist/components/pagination.js +78 -0
  60. package/dist/components/popover.d.ts +34 -0
  61. package/dist/components/popover.js +67 -0
  62. package/dist/components/preview-card.d.ts +12 -0
  63. package/dist/components/preview-card.js +25 -0
  64. package/dist/components/preview-pane.d.ts +23 -0
  65. package/dist/components/preview-pane.js +33 -0
  66. package/dist/components/scroll-area.d.ts +19 -0
  67. package/dist/components/scroll-area.js +38 -0
  68. package/dist/components/scroll-to-top.d.ts +12 -0
  69. package/dist/components/scroll-to-top.js +43 -0
  70. package/dist/components/secret-input.d.ts +9 -0
  71. package/dist/components/secret-input.js +38 -0
  72. package/dist/components/segmented-icon-toggle.d.ts +22 -0
  73. package/dist/components/segmented-icon-toggle.js +30 -0
  74. package/dist/components/select.d.ts +25 -0
  75. package/dist/components/select.js +196 -0
  76. package/dist/components/separator.d.ts +16 -0
  77. package/dist/components/separator.js +26 -0
  78. package/dist/components/sheet.d.ts +29 -0
  79. package/dist/components/sheet.js +87 -0
  80. package/dist/components/skeleton.d.ts +4 -0
  81. package/dist/components/skeleton.js +10 -0
  82. package/dist/components/stella-mark.d.ts +5 -0
  83. package/dist/components/stella-mark.js +12 -0
  84. package/dist/components/stella-wordmark.d.ts +5 -0
  85. package/dist/components/stella-wordmark.js +21 -0
  86. package/dist/components/table.d.ts +20 -0
  87. package/dist/components/table.js +80 -0
  88. package/dist/components/tabs.d.ts +11 -0
  89. package/dist/components/tabs.js +46 -0
  90. package/dist/components/textarea.d.ts +9 -0
  91. package/dist/components/textarea.js +31 -0
  92. package/dist/components/toast.d.ts +60 -0
  93. package/dist/components/toast.js +261 -0
  94. package/dist/components/tooltip-trigger-helper.d.ts +11 -0
  95. package/dist/components/tooltip-trigger-helper.js +14 -0
  96. package/dist/components/tooltip.d.ts +15 -0
  97. package/dist/components/tooltip.js +32 -0
  98. package/dist/hooks/use-contained-handler.d.ts +55 -0
  99. package/dist/hooks/use-contained-handler.js +54 -0
  100. package/dist/hooks/use-content-dir.d.ts +48 -0
  101. package/dist/hooks/use-content-dir.js +45 -0
  102. package/dist/hooks/use-mobile.d.ts +4 -0
  103. package/dist/hooks/use-mobile.js +16 -0
  104. package/dist/hooks/use-viewport-width.d.ts +5 -0
  105. package/dist/hooks/use-viewport-width.js +14 -0
  106. package/dist/index.d.ts +60 -0
  107. package/dist/index.js +59 -0
  108. package/dist/inspector/chrome.d.ts +72 -0
  109. package/dist/inspector/chrome.js +153 -0
  110. package/dist/inspector/dock.d.ts +48 -0
  111. package/dist/inspector/dock.js +36 -0
  112. package/dist/inspector/index.d.ts +6 -0
  113. package/dist/inspector/index.js +6 -0
  114. package/dist/inspector/layout-tokens.d.ts +28 -0
  115. package/dist/inspector/layout-tokens.js +28 -0
  116. package/dist/inspector/pane-width.d.ts +64 -0
  117. package/dist/inspector/pane-width.js +53 -0
  118. package/dist/inspector/use-pane-width.d.ts +99 -0
  119. package/dist/inspector/use-pane-width.js +149 -0
  120. package/dist/lib/button-disposition.d.ts +63 -0
  121. package/dist/lib/button-disposition.js +52 -0
  122. package/dist/lib/overlay-layer.d.ts +22 -0
  123. package/dist/lib/overlay-layer.js +21 -0
  124. package/dist/lib/tab-order.d.ts +15 -0
  125. package/dist/lib/tab-order.js +15 -0
  126. package/dist/lib/tooltip-content.d.ts +13 -0
  127. package/dist/lib/tooltip-content.js +12 -0
  128. package/dist/lib/utils.d.ts +20 -0
  129. package/dist/lib/utils.js +41 -0
  130. package/dist/lib/week.d.ts +25 -0
  131. package/dist/lib/week.js +40 -0
  132. package/dist/styles/theme.css +1209 -0
  133. package/package.json +506 -2
@@ -0,0 +1,64 @@
1
+ //#region src/inspector/pane-width.d.ts
2
+ /**
3
+ * Width arithmetic for a docked inspector pane.
4
+ *
5
+ * The pane is a fixed overlay backed by an in-flow spacer, so nothing in
6
+ * the layout pushes back when it grows: whatever the pane takes comes
7
+ * straight out of the content column. Without a clamp against the space
8
+ * actually available, shrinking the window (or expanding the sidebar)
9
+ * leaves the content column a few dozen pixels wide instead of folding.
10
+ *
11
+ * The host application's sidebar width is a parameter rather than an
12
+ * import, so the policy carries no coupling to any particular shell.
13
+ */
14
+ declare const INSPECTOR_PANE_DEFAULT_WIDTH = 512;
15
+ declare const INSPECTOR_PANE_MIN_WIDTH = 320;
16
+ declare const INSPECTOR_PANE_MAX_WIDTH = 800;
17
+ /**
18
+ * Floor for the content column beside the pane. Below this the content
19
+ * surface stops being usable, so the pane yields space first.
20
+ */
21
+ declare const INSPECTOR_CONTENT_MIN_WIDTH = 400;
22
+ /** Inline size of the collapsed icon rail, in CSS pixels. */
23
+ declare const INSPECTOR_RAIL_WIDTH = 48;
24
+ type ForceSidebarCollapsedInput = {
25
+ /** Inline size the expanded sidebar takes out of the layout row. */
26
+ expandedSidebarWidth: number;
27
+ inspectorPaneOpen: boolean;
28
+ /** Viewport width in CSS pixels; 0 before the viewport is known. */
29
+ viewportWidth: number;
30
+ };
31
+ /**
32
+ * The expanded sidebar yields its optional width before either docked pane
33
+ * can violate its minimum. The collapsed rail plus both minimums fit at the
34
+ * desktop breakpoint, so this policy keeps every desktop width usable.
35
+ */
36
+ declare const shouldForceSidebarCollapsed: ({ expandedSidebarWidth, inspectorPaneOpen, viewportWidth }: ForceSidebarCollapsedInput) => boolean;
37
+ type InspectorPaneWidthInput = {
38
+ /** Width the user dragged the pane to. */
39
+ desiredWidth: number;
40
+ /** Inline size the sidebar takes out of the same layout row. */
41
+ sidebarWidth: number;
42
+ /** Viewport width in CSS pixels; 0 before the viewport is known. */
43
+ viewportWidth: number;
44
+ };
45
+ /**
46
+ * Largest width the pane may take without starving the content column.
47
+ * Never returns less than {@link INSPECTOR_PANE_MIN_WIDTH}: a pane too
48
+ * narrow to read is no better than a content column too narrow to read,
49
+ * and collapsing the sidebar is the escape hatch for a genuinely small
50
+ * viewport.
51
+ */
52
+ declare const resolveInspectorPaneMaxWidth: ({ sidebarWidth, viewportWidth }: Omit<InspectorPaneWidthInput, "desiredWidth">) => number;
53
+ /** Width the pane renders at, given the width the user asked for. */
54
+ declare const resolveInspectorPaneWidth: ({ desiredWidth, sidebarWidth, viewportWidth }: InspectorPaneWidthInput) => number;
55
+ /**
56
+ * Width the dock reserves in the layout: the full pane while content is
57
+ * shown, the bare rail while it is collapsed or minimized.
58
+ */
59
+ declare const resolveInspectorDockWidth: ({ paneWidth, showPaneContent }: {
60
+ paneWidth: number;
61
+ showPaneContent: boolean;
62
+ }) => number;
63
+ //#endregion
64
+ export { INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, shouldForceSidebarCollapsed };
@@ -0,0 +1,53 @@
1
+ //#region src/inspector/pane-width.ts
2
+ /**
3
+ * Width arithmetic for a docked inspector pane.
4
+ *
5
+ * The pane is a fixed overlay backed by an in-flow spacer, so nothing in
6
+ * the layout pushes back when it grows: whatever the pane takes comes
7
+ * straight out of the content column. Without a clamp against the space
8
+ * actually available, shrinking the window (or expanding the sidebar)
9
+ * leaves the content column a few dozen pixels wide instead of folding.
10
+ *
11
+ * The host application's sidebar width is a parameter rather than an
12
+ * import, so the policy carries no coupling to any particular shell.
13
+ */
14
+ const INSPECTOR_PANE_DEFAULT_WIDTH = 512;
15
+ const INSPECTOR_PANE_MIN_WIDTH = 320;
16
+ const INSPECTOR_PANE_MAX_WIDTH = 800;
17
+ /**
18
+ * Floor for the content column beside the pane. Below this the content
19
+ * surface stops being usable, so the pane yields space first.
20
+ */
21
+ const INSPECTOR_CONTENT_MIN_WIDTH = 400;
22
+ /** Inline size of the collapsed icon rail, in CSS pixels. */
23
+ const INSPECTOR_RAIL_WIDTH = 48;
24
+ /**
25
+ * The expanded sidebar yields its optional width before either docked pane
26
+ * can violate its minimum. The collapsed rail plus both minimums fit at the
27
+ * desktop breakpoint, so this policy keeps every desktop width usable.
28
+ */
29
+ const shouldForceSidebarCollapsed = ({ expandedSidebarWidth, inspectorPaneOpen, viewportWidth }) => inspectorPaneOpen && viewportWidth > 0 && viewportWidth < expandedSidebarWidth + 400 + 320;
30
+ /**
31
+ * Largest width the pane may take without starving the content column.
32
+ * Never returns less than {@link INSPECTOR_PANE_MIN_WIDTH}: a pane too
33
+ * narrow to read is no better than a content column too narrow to read,
34
+ * and collapsing the sidebar is the escape hatch for a genuinely small
35
+ * viewport.
36
+ */
37
+ const resolveInspectorPaneMaxWidth = ({ sidebarWidth, viewportWidth }) => {
38
+ if (viewportWidth <= 0) return 320;
39
+ const available = viewportWidth - sidebarWidth - 400;
40
+ return Math.max(320, Math.min(800, available));
41
+ };
42
+ /** Width the pane renders at, given the width the user asked for. */
43
+ const resolveInspectorPaneWidth = ({ desiredWidth, sidebarWidth, viewportWidth }) => Math.min(Math.max(desiredWidth, 320), resolveInspectorPaneMaxWidth({
44
+ sidebarWidth,
45
+ viewportWidth
46
+ }));
47
+ /**
48
+ * Width the dock reserves in the layout: the full pane while content is
49
+ * shown, the bare rail while it is collapsed or minimized.
50
+ */
51
+ const resolveInspectorDockWidth = ({ paneWidth, showPaneContent }) => showPaneContent ? paneWidth : 48;
52
+ //#endregion
53
+ export { INSPECTOR_CONTENT_MIN_WIDTH, INSPECTOR_PANE_DEFAULT_WIDTH, INSPECTOR_PANE_MAX_WIDTH, INSPECTOR_PANE_MIN_WIDTH, INSPECTOR_RAIL_WIDTH, resolveInspectorDockWidth, resolveInspectorPaneMaxWidth, resolveInspectorPaneWidth, shouldForceSidebarCollapsed };
@@ -0,0 +1,99 @@
1
+ import { KeyboardEvent, PointerEvent } from "react";
2
+ //#region src/inspector/use-pane-width.d.ts
3
+ /**
4
+ * Reads a persisted pane width, rejecting anything that is not a finite
5
+ * number inside the pane's own bounds. A corrupt or stale entry must not
6
+ * be able to render the pane at a width the drag handle cannot recover
7
+ * from, so an unusable value falls back to the default rather than being
8
+ * clamped into something the user never chose.
9
+ */
10
+ declare const parsePersistedPaneWidth: (raw: string | null) => number;
11
+ /**
12
+ * Width the drag produces for a pane docked to the inline-end edge.
13
+ *
14
+ * That edge is the right in LTR (width = distance from the right) and the
15
+ * left in RTL (width = distance from the left). Without the RTL branch the
16
+ * delta is inverted and the drag oscillates.
17
+ */
18
+ declare const resolveDragWidth: ({ clientX, isRtl, viewportWidth }: {
19
+ clientX: number;
20
+ isRtl: boolean;
21
+ viewportWidth: number;
22
+ }) => number;
23
+ /** Pixels one arrow press moves the edge; Page/Home/End move further. */
24
+ declare const INSPECTOR_PANE_KEYBOARD_STEP = 16;
25
+ declare const INSPECTOR_PANE_KEYBOARD_PAGE_STEP = 64;
26
+ /**
27
+ * Width a keyboard resize produces. Returns `null` for keys the handle does
28
+ * not own, so the caller can leave the event alone rather than swallowing
29
+ * every keystroke that reaches a focusable separator.
30
+ *
31
+ * Arrow semantics follow the *edge*, not the width: on an inline-end pane
32
+ * the inline-start arrow grows it. Under RTL the physical arrows swap, so
33
+ * the same key keeps meaning "make it bigger" on both sides.
34
+ */
35
+ declare const resolveKeyboardWidth: ({ currentWidth, isRtl, key }: {
36
+ currentWidth: number;
37
+ isRtl: boolean;
38
+ key: string;
39
+ }) => number | null;
40
+ /**
41
+ * Reads and writes are wrapped because `window.localStorage` is a getter that
42
+ * *throws* where storage is blocked — a sandboxed iframe, a hardened privacy
43
+ * mode, a full quota. The `typeof window` check does not cover that, and a
44
+ * throw in the state initializer takes the whole pane down on mount. A pane
45
+ * that forgets its width is a smaller failure than a pane that does not
46
+ * render, so both directions degrade to in-memory.
47
+ */
48
+ declare const readStoredWidth: (storageKey: string) => number;
49
+ declare const writeStoredWidth: (storageKey: string, width: number) => void;
50
+ type UseInspectorPaneWidthOptions = {
51
+ /** Inline size the sidebar takes out of the same layout row. */
52
+ sidebarWidth: number;
53
+ /**
54
+ * `localStorage` key the dragged width is remembered under. Omit to keep
55
+ * the width in memory only, which resets the pane on every reload.
56
+ */
57
+ storageKey?: string | undefined;
58
+ /** Viewport width in CSS pixels; 0 before the viewport is known. */
59
+ viewportWidth: number;
60
+ };
61
+ type UseInspectorPaneWidthResult = {
62
+ /**
63
+ * Pointer + keyboard handlers and ARIA state to spread onto the drag
64
+ * handle. The handle is a focusable `separator`, so it is operable
65
+ * without a pointer.
66
+ */
67
+ resizeHandleProps: {
68
+ "aria-orientation": "vertical";
69
+ "aria-valuemax": number;
70
+ "aria-valuemin": number;
71
+ "aria-valuenow": number;
72
+ onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
73
+ onLostPointerCapture: (event: PointerEvent<HTMLElement>) => void;
74
+ onPointerCancel: (event: PointerEvent<HTMLElement>) => void;
75
+ onPointerDown: (event: PointerEvent<HTMLElement>) => void;
76
+ onPointerMove: (event: PointerEvent<HTMLElement>) => void;
77
+ onPointerUp: (event: PointerEvent<HTMLElement>) => void;
78
+ tabIndex: number;
79
+ };
80
+ /** Reset the pane to its default width (double-click affordance). */
81
+ resetWidth: () => void;
82
+ /**
83
+ * Width the pane renders at: the dragged width clamped against the room
84
+ * left beside the sidebar.
85
+ */
86
+ width: number;
87
+ };
88
+ /**
89
+ * Owns the docked pane's width: the width the user dragged to, its
90
+ * persistence, and the clamp against the room actually available.
91
+ *
92
+ * What renders is always the clamped value, so shrinking the window or
93
+ * expanding the sidebar takes space back from the pane instead of crushing
94
+ * the content column. The *desired* width keeps the user's choice, so the
95
+ * pane returns to it once the room comes back.
96
+ */
97
+ declare const useInspectorPaneWidth: ({ sidebarWidth, storageKey, viewportWidth }: UseInspectorPaneWidthOptions) => UseInspectorPaneWidthResult;
98
+ //#endregion
99
+ export { INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, parsePersistedPaneWidth, readStoredWidth, resolveDragWidth, resolveKeyboardWidth, useInspectorPaneWidth, writeStoredWidth };
@@ -0,0 +1,149 @@
1
+ import { resolveInspectorPaneWidth } from "./pane-width.js";
2
+ import { useEffect, useRef, useState } from "react";
3
+ //#region src/inspector/use-pane-width.ts
4
+ /**
5
+ * Reads a persisted pane width, rejecting anything that is not a finite
6
+ * number inside the pane's own bounds. A corrupt or stale entry must not
7
+ * be able to render the pane at a width the drag handle cannot recover
8
+ * from, so an unusable value falls back to the default rather than being
9
+ * clamped into something the user never chose.
10
+ */
11
+ const parsePersistedPaneWidth = (raw) => {
12
+ if (raw === null) return 512;
13
+ const parsed = Number.parseInt(raw, 10);
14
+ if (!Number.isFinite(parsed) || parsed < 320 || parsed > 800) return 512;
15
+ return parsed;
16
+ };
17
+ /**
18
+ * Width the drag produces for a pane docked to the inline-end edge.
19
+ *
20
+ * That edge is the right in LTR (width = distance from the right) and the
21
+ * left in RTL (width = distance from the left). Without the RTL branch the
22
+ * delta is inverted and the drag oscillates.
23
+ */
24
+ const resolveDragWidth = ({ clientX, isRtl, viewportWidth }) => isRtl ? clientX : viewportWidth - clientX;
25
+ /** Pixels one arrow press moves the edge; Page/Home/End move further. */
26
+ const INSPECTOR_PANE_KEYBOARD_STEP = 16;
27
+ const INSPECTOR_PANE_KEYBOARD_PAGE_STEP = 64;
28
+ /**
29
+ * Width a keyboard resize produces. Returns `null` for keys the handle does
30
+ * not own, so the caller can leave the event alone rather than swallowing
31
+ * every keystroke that reaches a focusable separator.
32
+ *
33
+ * Arrow semantics follow the *edge*, not the width: on an inline-end pane
34
+ * the inline-start arrow grows it. Under RTL the physical arrows swap, so
35
+ * the same key keeps meaning "make it bigger" on both sides.
36
+ */
37
+ const resolveKeyboardWidth = ({ currentWidth, isRtl, key }) => {
38
+ const grow = isRtl ? "ArrowRight" : "ArrowLeft";
39
+ const shrink = isRtl ? "ArrowLeft" : "ArrowRight";
40
+ switch (key) {
41
+ case grow: return currentWidth + 16;
42
+ case shrink: return currentWidth - 16;
43
+ case "PageUp": return currentWidth + 64;
44
+ case "PageDown": return currentWidth - 64;
45
+ case "Home": return 320;
46
+ case "End": return 800;
47
+ case "Enter": return 512;
48
+ default: return null;
49
+ }
50
+ };
51
+ /**
52
+ * Reads and writes are wrapped because `window.localStorage` is a getter that
53
+ * *throws* where storage is blocked — a sandboxed iframe, a hardened privacy
54
+ * mode, a full quota. The `typeof window` check does not cover that, and a
55
+ * throw in the state initializer takes the whole pane down on mount. A pane
56
+ * that forgets its width is a smaller failure than a pane that does not
57
+ * render, so both directions degrade to in-memory.
58
+ */
59
+ const readStoredWidth = (storageKey) => {
60
+ if (typeof window === "undefined") return 512;
61
+ try {
62
+ return parsePersistedPaneWidth(window.localStorage.getItem(storageKey));
63
+ } catch {
64
+ return 512;
65
+ }
66
+ };
67
+ const writeStoredWidth = (storageKey, width) => {
68
+ if (typeof window === "undefined") return;
69
+ try {
70
+ window.localStorage.setItem(storageKey, String(width));
71
+ } catch {}
72
+ };
73
+ /**
74
+ * Owns the docked pane's width: the width the user dragged to, its
75
+ * persistence, and the clamp against the room actually available.
76
+ *
77
+ * What renders is always the clamped value, so shrinking the window or
78
+ * expanding the sidebar takes space back from the pane instead of crushing
79
+ * the content column. The *desired* width keeps the user's choice, so the
80
+ * pane returns to it once the room comes back.
81
+ */
82
+ const useInspectorPaneWidth = ({ sidebarWidth, storageKey, viewportWidth }) => {
83
+ const [desiredWidth, setDesiredWidth] = useState(() => storageKey === void 0 ? 512 : readStoredWidth(storageKey));
84
+ const isDragging = useRef(false);
85
+ useEffect(() => {
86
+ if (storageKey === void 0) return;
87
+ writeStoredWidth(storageKey, desiredWidth);
88
+ }, [desiredWidth, storageKey]);
89
+ const handlePointerDown = (event) => {
90
+ event.preventDefault();
91
+ isDragging.current = true;
92
+ event.currentTarget.setPointerCapture(event.pointerId);
93
+ };
94
+ const handlePointerMove = (event) => {
95
+ if (!isDragging.current) return;
96
+ setDesiredWidth(resolveDragWidth({
97
+ clientX: event.clientX,
98
+ isRtl: document.documentElement.dir === "rtl",
99
+ viewportWidth: window.innerWidth
100
+ }));
101
+ };
102
+ /**
103
+ * Ends the drag however the pointer stream ended. `pointerup` is only one of
104
+ * the ways: a touch taken over by scrolling, a context menu, or the handle
105
+ * losing capture mid-drag all end it without one, and a drag flag left set
106
+ * would resize the pane on the next pointer movement with no button held.
107
+ */
108
+ const endDrag = (event) => {
109
+ isDragging.current = false;
110
+ if (event.currentTarget.hasPointerCapture(event.pointerId)) event.currentTarget.releasePointerCapture(event.pointerId);
111
+ };
112
+ const handleKeyDown = (event) => {
113
+ const next = resolveKeyboardWidth({
114
+ currentWidth: desiredWidth,
115
+ isRtl: document.documentElement.dir === "rtl",
116
+ key: event.key
117
+ });
118
+ if (next === null) return;
119
+ event.preventDefault();
120
+ setDesiredWidth(Math.min(Math.max(next, 320), 800));
121
+ };
122
+ const resetWidth = () => {
123
+ setDesiredWidth(512);
124
+ };
125
+ const width = resolveInspectorPaneWidth({
126
+ desiredWidth,
127
+ sidebarWidth,
128
+ viewportWidth
129
+ });
130
+ return {
131
+ resetWidth,
132
+ resizeHandleProps: {
133
+ "aria-orientation": "vertical",
134
+ "aria-valuemax": 800,
135
+ "aria-valuemin": 320,
136
+ "aria-valuenow": width,
137
+ onKeyDown: handleKeyDown,
138
+ onLostPointerCapture: endDrag,
139
+ onPointerCancel: endDrag,
140
+ onPointerDown: handlePointerDown,
141
+ onPointerMove: handlePointerMove,
142
+ onPointerUp: endDrag,
143
+ tabIndex: 0
144
+ },
145
+ width
146
+ };
147
+ };
148
+ //#endregion
149
+ export { INSPECTOR_PANE_KEYBOARD_PAGE_STEP, INSPECTOR_PANE_KEYBOARD_STEP, parsePersistedPaneWidth, readStoredWidth, resolveDragWidth, resolveKeyboardWidth, useInspectorPaneWidth, writeStoredWidth };
@@ -0,0 +1,63 @@
1
+ import * as React$1 from "react";
2
+ //#region src/lib/button-disposition.d.ts
3
+ /**
4
+ * How a button expresses "unavailable".
5
+ *
6
+ * `buttonVariants` carries `disabled:pointer-events-none`, and the browser
7
+ * suppresses pointer and focus events on a natively disabled control anyway, so
8
+ * a disabled button never receives hover or focus. A tooltip attached to it can
9
+ * therefore never open, which is exactly when the user most needs to be told
10
+ * why the action is unavailable. When there is a tooltip to show, the button
11
+ * switches to the ARIA accessible-disabled pattern instead: it stays in the tab
12
+ * order and keeps receiving pointer events, while every activation path is
13
+ * blocked (see `blockDisabledActivation`).
14
+ *
15
+ * This mirrors Base UI's own `focusableWhenDisabled` disposition
16
+ * (`useFocusableWhenDisabled`): `aria-disabled` instead of `disabled`, focusable,
17
+ * and non-`Tab` key defaults suppressed.
18
+ */
19
+ declare const BUTTON_DISPOSITION: {
20
+ readonly enabled: "enabled";
21
+ /** Native `disabled`: out of the tab order, inert to pointer and keyboard. */
22
+ readonly nativeDisabled: "native-disabled";
23
+ /** `aria-disabled`: focusable and hoverable so its tooltip can still open. */
24
+ readonly accessibleDisabled: "accessible-disabled";
25
+ };
26
+ type ButtonDisposition = (typeof BUTTON_DISPOSITION)[keyof typeof BUTTON_DISPOSITION];
27
+ type ButtonDispositionInput = {
28
+ disabled: boolean | undefined;
29
+ loading: boolean | undefined;
30
+ /** Resolved tooltip content, i.e. what `renderTooltipTrigger` would mount. */
31
+ tooltip: React$1.ReactNode;
32
+ };
33
+ declare const resolveButtonDisposition: ({ disabled, loading, tooltip }: ButtonDispositionInput) => ButtonDisposition;
34
+ /**
35
+ * The parts of a React synthetic event these blockers touch.
36
+ *
37
+ * `preventBaseUIHandler` is added by Base UI's `mergeProps` to the rightmost
38
+ * handler in a merged chain; calling it stops the handlers merged to its left,
39
+ * which is how a caller's own `onClick` is suppressed.
40
+ */
41
+ type BlockableEvent = {
42
+ preventDefault: () => void;
43
+ preventBaseUIHandler?: (() => void) | undefined;
44
+ };
45
+ /**
46
+ * Swallow an activation on an `aria-disabled` control.
47
+ *
48
+ * `preventDefault()` is what keeps a `type="submit"` button from submitting its
49
+ * form: the browser's form-submission default runs off the click event, and
50
+ * implicit submission (Enter in a text field) dispatches a click at the form's
51
+ * default button, so both paths funnel through here.
52
+ */
53
+ declare const blockDisabledActivation: (event: BlockableEvent) => void;
54
+ /**
55
+ * The keyboard counterpart. `Tab` keeps its default so focus can leave the
56
+ * control; suppressing the default on `Enter`/`Space` stops the browser from
57
+ * synthesizing the click that would activate or submit.
58
+ */
59
+ declare const blockDisabledKeyActivation: (event: BlockableEvent & {
60
+ key: string;
61
+ }) => void;
62
+ //#endregion
63
+ export { BUTTON_DISPOSITION, ButtonDisposition, blockDisabledActivation, blockDisabledKeyActivation, resolveButtonDisposition };
@@ -0,0 +1,52 @@
1
+ import { hasTooltipContent } from "./tooltip-content.js";
2
+ //#region src/lib/button-disposition.ts
3
+ /**
4
+ * How a button expresses "unavailable".
5
+ *
6
+ * `buttonVariants` carries `disabled:pointer-events-none`, and the browser
7
+ * suppresses pointer and focus events on a natively disabled control anyway, so
8
+ * a disabled button never receives hover or focus. A tooltip attached to it can
9
+ * therefore never open, which is exactly when the user most needs to be told
10
+ * why the action is unavailable. When there is a tooltip to show, the button
11
+ * switches to the ARIA accessible-disabled pattern instead: it stays in the tab
12
+ * order and keeps receiving pointer events, while every activation path is
13
+ * blocked (see `blockDisabledActivation`).
14
+ *
15
+ * This mirrors Base UI's own `focusableWhenDisabled` disposition
16
+ * (`useFocusableWhenDisabled`): `aria-disabled` instead of `disabled`, focusable,
17
+ * and non-`Tab` key defaults suppressed.
18
+ */
19
+ const BUTTON_DISPOSITION = {
20
+ enabled: "enabled",
21
+ /** Native `disabled`: out of the tab order, inert to pointer and keyboard. */
22
+ nativeDisabled: "native-disabled",
23
+ /** `aria-disabled`: focusable and hoverable so its tooltip can still open. */
24
+ accessibleDisabled: "accessible-disabled"
25
+ };
26
+ const resolveButtonDisposition = ({ disabled, loading, tooltip }) => {
27
+ if (disabled !== true && loading !== true) return BUTTON_DISPOSITION.enabled;
28
+ return hasTooltipContent(tooltip) ? BUTTON_DISPOSITION.accessibleDisabled : BUTTON_DISPOSITION.nativeDisabled;
29
+ };
30
+ /**
31
+ * Swallow an activation on an `aria-disabled` control.
32
+ *
33
+ * `preventDefault()` is what keeps a `type="submit"` button from submitting its
34
+ * form: the browser's form-submission default runs off the click event, and
35
+ * implicit submission (Enter in a text field) dispatches a click at the form's
36
+ * default button, so both paths funnel through here.
37
+ */
38
+ const blockDisabledActivation = (event) => {
39
+ event.preventBaseUIHandler?.();
40
+ event.preventDefault();
41
+ };
42
+ /**
43
+ * The keyboard counterpart. `Tab` keeps its default so focus can leave the
44
+ * control; suppressing the default on `Enter`/`Space` stops the browser from
45
+ * synthesizing the click that would activate or submit.
46
+ */
47
+ const blockDisabledKeyActivation = (event) => {
48
+ event.preventBaseUIHandler?.();
49
+ if (event.key !== "Tab") event.preventDefault();
50
+ };
51
+ //#endregion
52
+ export { BUTTON_DISPOSITION, blockDisabledActivation, blockDisabledKeyActivation, resolveButtonDisposition };
@@ -0,0 +1,22 @@
1
+ //#region src/lib/overlay-layer.d.ts
2
+ declare const OVERLAY_LAYER_CLASS_NAMES: {
3
+ /** Docked composer, suggestion chips, and other in-pane floating chrome. */
4
+ readonly chrome: "z-[80]";
5
+ /** Dialogs, sheets, popovers, tooltips: above chrome, below toasts. */
6
+ readonly default: "z-[85]";
7
+ /** Search sits a hair above a plain dialog so its own popup wins. */
8
+ readonly search: "z-[86]";
9
+ /**
10
+ * Transient popups — menu, select, combobox, context menus. Above everything
11
+ * including the toast viewport (z-[90]), because any of them can be opened
12
+ * *from* a dialog, a popover or a toast action and must cover its opener.
13
+ * They sat at z-50 alongside dialogs, so which one won was decided by portal
14
+ * mount order: a select inside a filter popover rendered behind it.
15
+ */
16
+ readonly popup: "z-[100]";
17
+ /** Historical alias for `popup`; Search's own menus use the same band. */
18
+ readonly "search-child": "z-[100]";
19
+ };
20
+ type OverlayLayer = keyof typeof OVERLAY_LAYER_CLASS_NAMES;
21
+ //#endregion
22
+ export { OVERLAY_LAYER_CLASS_NAMES, OverlayLayer };
@@ -0,0 +1,21 @@
1
+ //#region src/lib/overlay-layer.ts
2
+ const OVERLAY_LAYER_CLASS_NAMES = {
3
+ /** Docked composer, suggestion chips, and other in-pane floating chrome. */
4
+ chrome: "z-[80]",
5
+ /** Dialogs, sheets, popovers, tooltips: above chrome, below toasts. */
6
+ default: "z-[85]",
7
+ /** Search sits a hair above a plain dialog so its own popup wins. */
8
+ search: "z-[86]",
9
+ /**
10
+ * Transient popups — menu, select, combobox, context menus. Above everything
11
+ * including the toast viewport (z-[90]), because any of them can be opened
12
+ * *from* a dialog, a popover or a toast action and must cover its opener.
13
+ * They sat at z-50 alongside dialogs, so which one won was decided by portal
14
+ * mount order: a select inside a filter popover rendered behind it.
15
+ */
16
+ popup: "z-[100]",
17
+ /** Historical alias for `popup`; Search's own menus use the same band. */
18
+ "search-child": "z-[100]"
19
+ };
20
+ //#endregion
21
+ export { OVERLAY_LAYER_CLASS_NAMES };
@@ -0,0 +1,15 @@
1
+ //#region src/lib/tab-order.d.ts
2
+ /**
3
+ * Whether a committed tab list holds different elements, or the same elements
4
+ * in a different order, than the previous commit.
5
+ *
6
+ * Base UI measures the tabs indicator during render, so it reads the DOM as it
7
+ * stood before the commit. Its correction is a `ResizeObserver`, which catches
8
+ * an insertion or a removal (the list's own width changes) but not a reorder:
9
+ * there the tabs swap places without anything changing size. Detecting that is
10
+ * the whole of the workaround, so compare identity rather than count, because
11
+ * React moves the same nodes when it reorders keyed children.
12
+ */
13
+ declare const hasTabOrderChanged: <T>(previous: readonly T[], next: readonly T[]) => boolean;
14
+ //#endregion
15
+ export { hasTabOrderChanged };
@@ -0,0 +1,15 @@
1
+ //#region src/lib/tab-order.ts
2
+ /**
3
+ * Whether a committed tab list holds different elements, or the same elements
4
+ * in a different order, than the previous commit.
5
+ *
6
+ * Base UI measures the tabs indicator during render, so it reads the DOM as it
7
+ * stood before the commit. Its correction is a `ResizeObserver`, which catches
8
+ * an insertion or a removal (the list's own width changes) but not a reorder:
9
+ * there the tabs swap places without anything changing size. Detecting that is
10
+ * the whole of the workaround, so compare identity rather than count, because
11
+ * React moves the same nodes when it reorders keyed children.
12
+ */
13
+ const hasTabOrderChanged = (previous, next) => previous.length !== next.length || next.some((tab, index) => tab !== previous[index]);
14
+ //#endregion
15
+ export { hasTabOrderChanged };
@@ -0,0 +1,13 @@
1
+ import * as React$1 from "react";
2
+ //#region src/lib/tooltip-content.d.ts
3
+ /**
4
+ * Whether a tooltip value would actually render a popup.
5
+ *
6
+ * Single source of truth for "there is a tooltip": `renderTooltipTrigger`
7
+ * decides whether to mount one, and `resolveButtonDisposition` decides whether
8
+ * a disabled button has to stay hoverable so that popup can open. Two copies of
9
+ * this predicate would drift into a button that suppresses its own tooltip.
10
+ */
11
+ declare const hasTooltipContent: (content: React$1.ReactNode) => boolean;
12
+ //#endregion
13
+ export { hasTooltipContent };
@@ -0,0 +1,12 @@
1
+ //#region src/lib/tooltip-content.ts
2
+ /**
3
+ * Whether a tooltip value would actually render a popup.
4
+ *
5
+ * Single source of truth for "there is a tooltip": `renderTooltipTrigger`
6
+ * decides whether to mount one, and `resolveButtonDisposition` decides whether
7
+ * a disabled button has to stay hoverable so that popup can open. Two copies of
8
+ * this predicate would drift into a button that suppresses its own tooltip.
9
+ */
10
+ const hasTooltipContent = (content) => content !== void 0 && content !== null && content !== "" && content !== false;
11
+ //#endregion
12
+ export { hasTooltipContent };
@@ -0,0 +1,20 @@
1
+ import { ClassValue } from "clsx";
2
+ import * as React$1 from "react";
3
+ //#region src/lib/utils.d.ts
4
+ declare function cn(...inputs: ClassValue[]): string;
5
+ /**
6
+ * Compose multiple refs into a single ref callback.
7
+ * Adapted from `@radix-ui/react-compose-refs` (MIT).
8
+ *
9
+ * Collects cleanup functions returned by React 19 ref
10
+ * callbacks and returns a combined cleanup so React can
11
+ * invoke it on unmount instead of re-calling with `null`.
12
+ *
13
+ * Use this rather than merging refs inline: forwarding a
14
+ * caller's return value verbatim makes React read whatever
15
+ * their callback happened to return as a cleanup, and warn
16
+ * when it is neither a function nor `undefined`.
17
+ */
18
+ declare const composeRefs: <T>(...refs: (React$1.Ref<T> | undefined)[]) => ((node: T | null) => (() => void) | undefined);
19
+ //#endregion
20
+ export { cn, composeRefs };
@@ -0,0 +1,41 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ //#region src/lib/utils.ts
4
+ function cn(...inputs) {
5
+ return twMerge(clsx(inputs));
6
+ }
7
+ /**
8
+ * Compose multiple refs into a single ref callback.
9
+ * Adapted from `@radix-ui/react-compose-refs` (MIT).
10
+ *
11
+ * Collects cleanup functions returned by React 19 ref
12
+ * callbacks and returns a combined cleanup so React can
13
+ * invoke it on unmount instead of re-calling with `null`.
14
+ *
15
+ * Use this rather than merging refs inline: forwarding a
16
+ * caller's return value verbatim makes React read whatever
17
+ * their callback happened to return as a cleanup, and warn
18
+ * when it is neither a function nor `undefined`.
19
+ */
20
+ const composeRefs = (...refs) => (node) => {
21
+ const cleanups = [];
22
+ for (const ref of refs) if (typeof ref === "function") {
23
+ const cleanup = ref(node);
24
+ if (typeof cleanup === "function") cleanups.push(() => {
25
+ cleanup();
26
+ });
27
+ else if (node !== null) cleanups.push(() => {
28
+ ref(null);
29
+ });
30
+ } else if (ref !== void 0 && ref !== null) {
31
+ ref.current = node;
32
+ if (node !== null) cleanups.push(() => {
33
+ ref.current = null;
34
+ });
35
+ }
36
+ if (cleanups.length > 0) return () => {
37
+ for (const cleanup of cleanups) cleanup();
38
+ };
39
+ };
40
+ //#endregion
41
+ export { cn, composeRefs };