@techsio/ui-kit 0.41.1 → 0.42.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 (151) hide show
  1. package/README.md +2 -1
  2. package/dist/atoms/numeric-input.js +3 -3
  3. package/dist/atoms/rating.js +3 -3
  4. package/dist/atoms/tooltip.js +3 -3
  5. package/dist/internal/molecules/drawer.context.js +133 -0
  6. package/dist/internal/molecules/drawer.styles.js +107 -0
  7. package/dist/internal/organisms/sidebar.context.js +223 -0
  8. package/dist/internal/organisms/sidebar.focus.js +169 -0
  9. package/dist/internal/organisms/sidebar.styles.js +146 -0
  10. package/dist/molecules/accordion.js +3 -3
  11. package/dist/molecules/carousel.js +3 -3
  12. package/dist/molecules/chart.js +1 -1
  13. package/dist/molecules/dialog.js +3 -3
  14. package/dist/molecules/drawer.js +262 -0
  15. package/dist/molecules/menu.js +5 -5
  16. package/dist/molecules/radio-group.js +3 -3
  17. package/dist/molecules/select.js +4 -4
  18. package/dist/molecules/slider.js +3 -3
  19. package/dist/molecules/switch.js +3 -3
  20. package/dist/molecules/tabs.js +3 -3
  21. package/dist/molecules/toast.js +6 -6
  22. package/dist/molecules/tree-view.js +4 -4
  23. package/dist/organisms/data-table.fields.js +1 -1
  24. package/dist/organisms/data-table.js +7 -7
  25. package/dist/organisms/sidebar.js +448 -0
  26. package/dist/src/atoms/action-icon.d.ts +1 -1
  27. package/dist/src/atoms/button.d.ts +1 -1
  28. package/dist/src/atoms/link-button.d.ts +1 -1
  29. package/dist/src/atoms/numeric-input.d.ts +1 -1
  30. package/dist/src/atoms/status-text.d.ts +1 -1
  31. package/dist/src/internal/molecules/drawer.context.d.ts +53 -0
  32. package/dist/src/internal/molecules/drawer.context.d.ts.map +1 -0
  33. package/dist/src/internal/molecules/drawer.styles.d.ts +115 -0
  34. package/dist/src/internal/molecules/drawer.styles.d.ts.map +1 -0
  35. package/dist/src/internal/organisms/sidebar.context.d.ts +83 -0
  36. package/dist/src/internal/organisms/sidebar.context.d.ts.map +1 -0
  37. package/dist/src/internal/organisms/sidebar.focus.d.ts +16 -0
  38. package/dist/src/internal/organisms/sidebar.focus.d.ts.map +1 -0
  39. package/dist/src/internal/organisms/sidebar.styles.d.ts +149 -0
  40. package/dist/src/internal/organisms/sidebar.styles.d.ts.map +1 -0
  41. package/dist/src/molecules/accordion.d.ts +1 -1
  42. package/dist/src/molecules/breadcrumb.d.ts +2 -2
  43. package/dist/src/molecules/carousel.d.ts +2 -2
  44. package/dist/src/molecules/combobox.d.ts +1 -1
  45. package/dist/src/molecules/drawer.d.ts +112 -0
  46. package/dist/src/molecules/drawer.d.ts.map +1 -0
  47. package/dist/src/molecules/form-input.d.ts +1 -1
  48. package/dist/src/molecules/form-numeric-input.d.ts +1 -1
  49. package/dist/src/molecules/form-textarea.d.ts +1 -1
  50. package/dist/src/molecules/menu.d.ts +1 -1
  51. package/dist/src/molecules/pagination.d.ts +1 -1
  52. package/dist/src/molecules/phone-input.d.ts +3 -3
  53. package/dist/src/molecules/popover.d.ts +1 -1
  54. package/dist/src/molecules/product-card.d.ts +4 -4
  55. package/dist/src/molecules/radio-card.d.ts +2 -2
  56. package/dist/src/molecules/radio-group.d.ts +2 -2
  57. package/dist/src/molecules/search-form.d.ts +5 -5
  58. package/dist/src/molecules/select.d.ts +1 -1
  59. package/dist/src/molecules/steps.d.ts +1 -1
  60. package/dist/src/molecules/switch.d.ts +3 -3
  61. package/dist/src/molecules/tabs.d.ts +1 -1
  62. package/dist/src/molecules/toast.d.ts +6 -6
  63. package/dist/src/molecules/tree-view.d.ts +1 -1
  64. package/dist/src/organisms/data-table.d.ts +8 -8
  65. package/dist/src/organisms/data-table.fields.d.ts +2 -2
  66. package/dist/src/organisms/data-table.helpers.d.ts +1 -1
  67. package/dist/src/organisms/gallery.d.ts +2 -2
  68. package/dist/src/organisms/sidebar.d.ts +93 -0
  69. package/dist/src/organisms/sidebar.d.ts.map +1 -0
  70. package/dist/src/templates/accordion.d.ts +2 -2
  71. package/dist/src/templates/breadcrumb.d.ts +2 -2
  72. package/dist/src/templates/carousel.d.ts +2 -2
  73. package/dist/src/templates/gallery.d.ts +3 -3
  74. package/dist/src/templates/numeric-input.d.ts +2 -2
  75. package/dist/src/templates/popover.d.ts +1 -1
  76. package/dist/src/templates/product-card.d.ts +2 -2
  77. package/dist/src/templates/select.d.ts +1 -1
  78. package/dist/src/templates/tabs.d.ts +1 -1
  79. package/dist/src/theme/theme-provider.d.ts +1 -1
  80. package/dist/src/types/zag.d.ts +1 -0
  81. package/dist/src/types/zag.d.ts.map +1 -1
  82. package/dist/stories/atoms/badge.stories.d.ts +1 -1
  83. package/dist/stories/atoms/button.stories.d.ts +1 -1
  84. package/dist/stories/atoms/checkbox.stories.d.ts +1 -1
  85. package/dist/stories/atoms/icon.stories.d.ts +1 -1
  86. package/dist/stories/atoms/image.stories.d.ts +1 -1
  87. package/dist/stories/atoms/input.stories.d.ts +1 -1
  88. package/dist/stories/atoms/numeric-input.stories.d.ts +1 -1
  89. package/dist/stories/atoms/rating.stories.d.ts +1 -1
  90. package/dist/stories/atoms/skeleton.stories.d.ts +1 -1
  91. package/dist/stories/atoms/status-text.stories.d.ts +1 -1
  92. package/dist/stories/atoms/textarea.stories.d.ts +1 -1
  93. package/dist/stories/atoms/tooltip.stories.d.ts +2 -2
  94. package/dist/stories/changelog/changelog.stories.d.ts.map +1 -1
  95. package/dist/stories/helpers/icon-options.d.ts +1 -1
  96. package/dist/stories/molecules/accordion.stories.d.ts +1 -1
  97. package/dist/stories/molecules/breadcrumb.stories.d.ts +1 -1
  98. package/dist/stories/molecules/carousel.stories.d.ts +1 -1
  99. package/dist/stories/molecules/chart.stories.d.ts +1 -1
  100. package/dist/stories/molecules/color-select.stories.d.ts +1 -1
  101. package/dist/stories/molecules/combobox.stories.d.ts +1 -1
  102. package/dist/stories/molecules/dialog.stories.d.ts +1 -1
  103. package/dist/stories/molecules/drawer.stories.d.ts +158 -0
  104. package/dist/stories/molecules/drawer.stories.d.ts.map +1 -0
  105. package/dist/stories/molecules/form-checkbox.stories.d.ts +1 -1
  106. package/dist/stories/molecules/form-input.stories.d.ts +1 -1
  107. package/dist/stories/molecules/form-numeric-input.stories.d.ts +1 -1
  108. package/dist/stories/molecules/form-textarea.stories.d.ts +1 -1
  109. package/dist/stories/molecules/menu.stories.d.ts +1 -1
  110. package/dist/stories/molecules/pagination.stories.d.ts +1 -1
  111. package/dist/stories/molecules/phone-input.stories.d.ts +1 -1
  112. package/dist/stories/molecules/popover.stories.d.ts +1 -1
  113. package/dist/stories/molecules/product-card.stories.d.ts +1 -1
  114. package/dist/stories/molecules/radio-card.stories.d.ts +1 -1
  115. package/dist/stories/molecules/radio-group.stories.d.ts +1 -1
  116. package/dist/stories/molecules/search-form.stories.d.ts +1 -1
  117. package/dist/stories/molecules/select.stories.d.ts +1 -1
  118. package/dist/stories/molecules/slider.stories.d.ts +1 -1
  119. package/dist/stories/molecules/steps.stories.d.ts +1 -1
  120. package/dist/stories/molecules/switch.stories.d.ts +1 -1
  121. package/dist/stories/molecules/tabs.stories.d.ts +1 -1
  122. package/dist/stories/molecules/tree-view.stories.d.ts +1 -1
  123. package/dist/stories/organisms/data-table.stories.d.ts +1 -1
  124. package/dist/stories/organisms/footer.stories.d.ts +1 -1
  125. package/dist/stories/organisms/gallery.stories.d.ts +2 -2
  126. package/dist/stories/organisms/header.stories.d.ts +1 -1
  127. package/dist/stories/organisms/sidebar.stories.d.ts +66 -0
  128. package/dist/stories/organisms/sidebar.stories.d.ts.map +1 -0
  129. package/dist/stories/organisms/table.stories.d.ts +1 -1
  130. package/dist/stories/templates/accordion.stories.d.ts +1 -1
  131. package/dist/stories/templates/breadcrumb.stories.d.ts +1 -1
  132. package/dist/stories/templates/carousel.stories.d.ts +1 -1
  133. package/dist/stories/templates/gallery.stories.d.ts +1 -1
  134. package/dist/stories/templates/numeric-input.stories.d.ts +1 -1
  135. package/dist/stories/templates/popover.stories.d.ts +1 -1
  136. package/dist/stories/templates/product-card.stories.d.ts +1 -1
  137. package/dist/stories/templates/select.stories.d.ts +1 -1
  138. package/dist/stories/templates/tabs.stories.d.ts +1 -1
  139. package/dist/test/drawer.behavior.spec.d.ts +2 -0
  140. package/dist/test/drawer.behavior.spec.d.ts.map +1 -0
  141. package/dist/test/sidebar.behavior.spec.d.ts +2 -0
  142. package/dist/test/sidebar.behavior.spec.d.ts.map +1 -0
  143. package/dist/test/sidebar.ssr.bun.d.ts +2 -0
  144. package/dist/test/sidebar.ssr.bun.d.ts.map +1 -0
  145. package/dist/theme/theme-provider.js +4 -4
  146. package/dist/theme/theme-toggle.js +1 -1
  147. package/package.json +43 -33
  148. package/src/tokens/components/components.css +2 -0
  149. package/src/tokens/components/molecules/_drawer.css +369 -0
  150. package/src/tokens/components/organisms/_sidebar.css +93 -0
  151. package/src/tokens/styles.d.ts +3 -0
package/README.md CHANGED
@@ -204,7 +204,8 @@ TEST_BASE_URL=http://127.0.0.1:6006 PLAYWRIGHT_WORKERS=6 pnpm -C libs/ui test:co
204
204
 
205
205
  ## 8. Publishing and releases
206
206
 
207
- - Build + publint: `pnpm -C libs/ui build` runs `rsbuild-plugin-publint` after the build; if exports/entrypoints are wrong, this command fails.
207
+ - Build: `pnpm -C libs/ui build` creates the package without release-only validation.
208
+ - Package output checks: `pnpm -C libs/ui check:package` builds, runs publint against package structure and exports, and runs AreTheTypesWrong across TypeScript module-resolution modes. CI and the release workflow run this command automatically.
208
209
  - Exports only, no barrel: import from explicit subpaths (e.g. `@techsio/ui-kit/atoms/button`, `@techsio/ui-kit/templates/accordion`, `@techsio/ui-kit/utils`). The package root is intentionally not exported.
209
210
  - Automated releases: `libs/ui/release.config.mjs` uses semantic-release (tag format `ui-kit-v<version>`) to publish to npm and create GitHub releases without pushing generated version/changelog commits back to the protected branch. While we are <1.0.0, `BREAKING CHANGE` commits are forced to “minor” bumps to stay in 0.x; remove that release rule when stabilizing for 1.0.0+ to restore SemVer majors.
210
211
  - Security posture: releases are restricted to GitHub Actions (`GITHUB_ACTIONS` required), npm publishes use trusted publishing through GitHub OIDC (`id-token: write`) and do not require an npm token.
@@ -1,10 +1,10 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { connect, machine } from "@zag-js/number-input";
3
2
  import { normalizeProps, useMachine } from "@zag-js/react";
4
3
  import { createContext, useContext, useId } from "react";
5
4
  import { tv } from "../utils.js";
6
5
  import { Button } from "./button.js";
7
6
  import { Input } from "./input.js";
7
+ import * as __rspack_external__zag_js_number_input_f1a1f439 from "@zag-js/number-input";
8
8
  const numericInputVariants = tv({
9
9
  slots: {
10
10
  root: [
@@ -100,7 +100,7 @@ function NumericInput({ id, name, size, disabled = false, required = false, patt
100
100
  };
101
101
  const stringValue = void 0 !== value ? formatValue(value) : void 0;
102
102
  const stringDefaultValue = void 0 !== defaultValue ? formatValue(defaultValue) : void 0;
103
- const service = useMachine(machine, {
103
+ const service = useMachine(__rspack_external__zag_js_number_input_f1a1f439.machine, {
104
104
  id: uniqueId,
105
105
  min,
106
106
  max,
@@ -126,7 +126,7 @@ function NumericInput({ id, name, size, disabled = false, required = false, patt
126
126
  },
127
127
  focusInputOnChange: true
128
128
  });
129
- const api = connect(service, normalizeProps);
129
+ const api = __rspack_external__zag_js_number_input_f1a1f439.connect(service, normalizeProps);
130
130
  const styles = numericInputVariants({
131
131
  size
132
132
  });
@@ -1,9 +1,9 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { connect, machine } from "@zag-js/rating-group";
3
2
  import { normalizeProps, useMachine } from "@zag-js/react";
4
3
  import { useId } from "react";
5
4
  import { tv } from "../utils.js";
6
5
  import { Label } from "./label.js";
6
+ import * as __rspack_external__zag_js_rating_group_32de5b57 from "@zag-js/rating-group";
7
7
  const rating = tv({
8
8
  slots: {
9
9
  root: [
@@ -61,7 +61,7 @@ const rating = tv({
61
61
  function Rating({ value, defaultValue, count = 5, labelText, readOnly = false, disabled = false, allowHalf = true, name, dir = "ltr", translations, onChange, onHoverChange, size = "md", className, ...props }) {
62
62
  const generatedId = useId();
63
63
  const uniqueId = props.id || generatedId;
64
- const service = useMachine(machine, {
64
+ const service = useMachine(__rspack_external__zag_js_rating_group_32de5b57.machine, {
65
65
  id: uniqueId,
66
66
  count,
67
67
  value,
@@ -79,7 +79,7 @@ function Rating({ value, defaultValue, count = 5, labelText, readOnly = false, d
79
79
  onHoverChange?.(hoveredValue);
80
80
  }
81
81
  });
82
- const api = connect(service, normalizeProps);
82
+ const api = __rspack_external__zag_js_rating_group_32de5b57.connect(service, normalizeProps);
83
83
  const { root, control, itemWrapper, item } = rating({
84
84
  size,
85
85
  isInteractive: !(readOnly || disabled)
@@ -1,8 +1,8 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Portal, normalizeProps, useMachine } from "@zag-js/react";
3
- import { connect, machine } from "@zag-js/tooltip";
4
3
  import { useId } from "react";
5
4
  import { tv } from "tailwind-variants";
5
+ import * as __rspack_external__zag_js_tooltip_cb65b1a2 from "@zag-js/tooltip";
6
6
  const tooltipVariants = tv({
7
7
  slots: {
8
8
  trigger: [
@@ -50,7 +50,7 @@ function Tooltip({ content, children, className, ref, size, variant, id: MRAId,
50
50
  }, gutter, flip, sameWidth, boundary, listeners, strategy }) {
51
51
  const generatedId = useId();
52
52
  const id = MRAId || generatedId;
53
- const service = useMachine(machine, {
53
+ const service = useMachine(__rspack_external__zag_js_tooltip_cb65b1a2.machine, {
54
54
  id,
55
55
  dir,
56
56
  open,
@@ -75,7 +75,7 @@ function Tooltip({ content, children, className, ref, size, variant, id: MRAId,
75
75
  strategy
76
76
  }
77
77
  });
78
- const api = connect(service, normalizeProps);
78
+ const api = __rspack_external__zag_js_tooltip_cb65b1a2.connect(service, normalizeProps);
79
79
  const { trigger, positioner, content: contentSlot, arrow } = tooltipVariants({
80
80
  variant,
81
81
  size
@@ -0,0 +1,133 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { normalizeProps, useMachine } from "@zag-js/react";
4
+ import { createContext, useContext, useId, useMemo, useRef, useState, useSyncExternalStore } from "react";
5
+ import { drawerVariants } from "./drawer.styles.js";
6
+ import * as __rspack_external__zag_js_drawer_a300f837 from "@zag-js/drawer";
7
+ import * as __rspack_external__zag_js_presence_229d2f05 from "@zag-js/presence";
8
+ const DrawerContext = /*#__PURE__*/ createContext(null);
9
+ const DrawerStackStoreContext = /*#__PURE__*/ createContext(void 0);
10
+ const DrawerStackContext = /*#__PURE__*/ createContext(null);
11
+ function useDrawer(props = {}) {
12
+ const generatedId = useId();
13
+ const inheritedStack = useContext(DrawerStackStoreContext);
14
+ const { defaultSnapPoint, id = generatedId, stack = inheritedStack, ...machineProps } = props;
15
+ const machineOptions = {
16
+ id,
17
+ stack,
18
+ ...machineProps
19
+ };
20
+ if ("defaultSnapPoint" in props) Object.assign(machineOptions, {
21
+ defaultSnapPoint
22
+ });
23
+ const service = useMachine(__rspack_external__zag_js_drawer_a300f837.machine, machineOptions);
24
+ return __rspack_external__zag_js_drawer_a300f837.connect(service, normalizeProps);
25
+ }
26
+ function useDrawerContext() {
27
+ const context = useContext(DrawerContext);
28
+ if (!context) throw new Error("Drawer components must be used within Drawer.Root");
29
+ return context;
30
+ }
31
+ function useDrawerStackContext() {
32
+ const context = useContext(DrawerStackContext);
33
+ if (!context) throw new Error("Drawer stack components must be used within Drawer.Stack");
34
+ return context;
35
+ }
36
+ function useDrawerPresence({ immediate, lazyMount = true, onEnterComplete, onExitComplete, present, skipAnimationOnMount = false, unmountOnExit = true }) {
37
+ const wasEverPresent = useRef(false);
38
+ const service = useMachine(__rspack_external__zag_js_presence_229d2f05.machine, {
39
+ immediate,
40
+ onEnterComplete,
41
+ onExitComplete,
42
+ present
43
+ });
44
+ const api = __rspack_external__zag_js_presence_229d2f05.connect(service, normalizeProps);
45
+ const latestSetNode = useRef(api.setNode);
46
+ latestSetNode.current = api.setNode;
47
+ const presenceRef = useRef((node)=>{
48
+ latestSetNode.current(node);
49
+ return ()=>{
50
+ latestSetNode.current(null);
51
+ };
52
+ }).current;
53
+ if (api.present) wasEverPresent.current = true;
54
+ const unmounted = !(api.present || wasEverPresent.current) && lazyMount || !api.present && wasEverPresent.current && unmountOnExit;
55
+ return {
56
+ api,
57
+ ref: presenceRef,
58
+ skipAnimationOnMount,
59
+ unmounted
60
+ };
61
+ }
62
+ function DrawerProvider({ api, children, immediate, lazyMount = true, onEnterComplete, onExitComplete, size, skipAnimationOnMount = false, unmountOnExit = true }) {
63
+ const presenceOptions = {
64
+ immediate,
65
+ lazyMount,
66
+ skipAnimationOnMount,
67
+ unmountOnExit
68
+ };
69
+ const contentPresence = useDrawerPresence({
70
+ ...presenceOptions,
71
+ onEnterComplete,
72
+ onExitComplete,
73
+ present: api.open
74
+ });
75
+ const styles = drawerVariants({
76
+ size
77
+ });
78
+ return /*#__PURE__*/ jsx(DrawerContext.Provider, {
79
+ value: {
80
+ api,
81
+ presence: contentPresence,
82
+ presenceOptions,
83
+ styles
84
+ },
85
+ children: children
86
+ });
87
+ }
88
+ function getDrawerPresenceProps(open, presenceState) {
89
+ let dataState = null;
90
+ if (!(presenceState.api.skip && presenceState.skipAnimationOnMount)) dataState = open ? "open" : "closed";
91
+ return {
92
+ "data-state": dataState,
93
+ hidden: !presenceState.api.present
94
+ };
95
+ }
96
+ function composeRefs(...refs) {
97
+ return (node)=>{
98
+ const cleanups = [];
99
+ for (const ref of refs)if ("function" == typeof ref) {
100
+ const cleanup = ref(node);
101
+ cleanups.push("function" == typeof cleanup ? cleanup : ()=>ref(null));
102
+ } else if (ref) {
103
+ ref.current = node;
104
+ cleanups.push(()=>{
105
+ ref.current = null;
106
+ });
107
+ }
108
+ return ()=>{
109
+ for (const cleanup of cleanups)cleanup();
110
+ };
111
+ };
112
+ }
113
+ function useComposedRefs(firstRef, secondRef) {
114
+ return useMemo(()=>composeRefs(firstRef, secondRef), [
115
+ firstRef,
116
+ secondRef
117
+ ]);
118
+ }
119
+ function DrawerStackProvider({ children }) {
120
+ const [stack] = useState(()=>__rspack_external__zag_js_drawer_a300f837.createStack());
121
+ const snapshot = useSyncExternalStore(stack.subscribe, stack.getSnapshot, stack.getSnapshot);
122
+ const api = useMemo(()=>__rspack_external__zag_js_drawer_a300f837.connectStack(snapshot, normalizeProps), [
123
+ snapshot
124
+ ]);
125
+ return /*#__PURE__*/ jsx(DrawerStackStoreContext.Provider, {
126
+ value: stack,
127
+ children: /*#__PURE__*/ jsx(DrawerStackContext.Provider, {
128
+ value: api,
129
+ children: children
130
+ })
131
+ });
132
+ }
133
+ export { DrawerProvider, DrawerStackProvider, getDrawerPresenceProps, useComposedRefs, useDrawer, useDrawerContext, useDrawerPresence, useDrawerStackContext };
@@ -0,0 +1,107 @@
1
+ import { tv } from "../../utils.js";
2
+ const drawerVariants = tv({
3
+ slots: {
4
+ backdrop: [
5
+ "drawer-backdrop-layer fixed inset-0 bg-drawer-backdrop-bg",
6
+ "drawer-backdrop-motion"
7
+ ],
8
+ positioner: [
9
+ "drawer-physical-axis drawer-positioner-layer pointer-events-none fixed inset-0 flex",
10
+ "data-[swipe-direction=up]:items-start",
11
+ "data-[swipe-direction=down]:items-end",
12
+ "data-[swipe-direction=left]:justify-start",
13
+ "data-[swipe-direction=right]:justify-end"
14
+ ],
15
+ content: [
16
+ "drawer-content-layer drawer-content-bleed pointer-events-auto relative flex max-h-full max-w-full flex-col",
17
+ "bg-drawer-content-bg text-drawer-content-fg shadow-drawer-content",
18
+ "border-(length:--border-width-drawer) border-drawer-content-border",
19
+ "focus-visible:drawer-focus-ring",
20
+ "drawer-content-motion",
21
+ "data-[swipe-direction=up]:drawer-content-top data-[swipe-direction=up]:w-full data-[swipe-direction=up]:border-t-0",
22
+ "data-[swipe-direction=down]:drawer-content-bottom data-[swipe-direction=down]:w-full data-[swipe-direction=down]:border-b-0",
23
+ "data-[swipe-direction=left]:drawer-content-left data-[swipe-direction=left]:h-full data-[swipe-direction=left]:border-l-0",
24
+ "data-[swipe-direction=right]:drawer-content-right data-[swipe-direction=right]:h-full data-[swipe-direction=right]:border-r-0"
25
+ ],
26
+ header: [
27
+ "flex shrink-0 flex-col gap-drawer-header p-drawer-header",
28
+ "border-b-(length:--border-width-drawer) border-drawer-content-border"
29
+ ],
30
+ body: "flex min-h-0 flex-1 flex-col overflow-y-auto p-drawer-body",
31
+ footer: [
32
+ "flex shrink-0 items-center justify-end gap-drawer-footer p-drawer-footer",
33
+ "border-t-(length:--border-width-drawer) border-drawer-content-border"
34
+ ],
35
+ title: "drawer-title-typography font-drawer-title text-drawer-title-fg",
36
+ description: "drawer-description-typography text-drawer-description-fg",
37
+ trigger: "",
38
+ closeTrigger: "",
39
+ grabber: [
40
+ "group absolute flex items-center justify-center p-drawer-grabber",
41
+ "data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:bottom-0",
42
+ "data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:top-0",
43
+ "data-[swipe-direction=start]:inset-y-0 data-[swipe-direction=start]:end-0",
44
+ "data-[swipe-direction=end]:inset-y-0 data-[swipe-direction=end]:start-0"
45
+ ],
46
+ grabberIndicator: [
47
+ "rounded-drawer-grabber bg-drawer-grabber-bg",
48
+ "group-data-[swipe-direction=up]:h-drawer-grabber-thickness group-data-[swipe-direction=up]:w-drawer-grabber-length",
49
+ "group-data-[swipe-direction=down]:h-drawer-grabber-thickness group-data-[swipe-direction=down]:w-drawer-grabber-length",
50
+ "group-data-[swipe-direction=start]:h-drawer-grabber-length group-data-[swipe-direction=start]:w-drawer-grabber-thickness",
51
+ "group-data-[swipe-direction=end]:h-drawer-grabber-length group-data-[swipe-direction=end]:w-drawer-grabber-thickness"
52
+ ],
53
+ swipeArea: [
54
+ "drawer-swipe-area-layer fixed",
55
+ "data-[swipe-direction=up]:inset-x-0 data-[swipe-direction=up]:bottom-0 data-[swipe-direction=up]:h-drawer-swipe-area",
56
+ "data-[swipe-direction=down]:inset-x-0 data-[swipe-direction=down]:top-0 data-[swipe-direction=down]:h-drawer-swipe-area",
57
+ "data-[swipe-direction=left]:inset-y-0 data-[swipe-direction=left]:right-0 data-[swipe-direction=left]:w-drawer-swipe-area",
58
+ "data-[swipe-direction=right]:inset-y-0 data-[swipe-direction=right]:left-0 data-[swipe-direction=right]:w-drawer-swipe-area"
59
+ ],
60
+ indent: "drawer-indent",
61
+ indentBackground: "drawer-indent-background"
62
+ },
63
+ variants: {
64
+ size: {
65
+ xs: {
66
+ content: [
67
+ "data-[swipe-direction=down]:h-drawer-xs data-[swipe-direction=up]:h-drawer-xs",
68
+ "data-[swipe-direction=left]:w-drawer-xs data-[swipe-direction=right]:w-drawer-xs"
69
+ ]
70
+ },
71
+ sm: {
72
+ content: [
73
+ "data-[swipe-direction=down]:h-drawer-sm data-[swipe-direction=up]:h-drawer-sm",
74
+ "data-[swipe-direction=left]:w-drawer-sm data-[swipe-direction=right]:w-drawer-sm"
75
+ ]
76
+ },
77
+ md: {
78
+ content: [
79
+ "data-[swipe-direction=down]:h-drawer-md data-[swipe-direction=up]:h-drawer-md",
80
+ "data-[swipe-direction=left]:w-drawer-md data-[swipe-direction=right]:w-drawer-md"
81
+ ]
82
+ },
83
+ lg: {
84
+ content: [
85
+ "data-[swipe-direction=down]:h-drawer-lg data-[swipe-direction=up]:h-drawer-lg",
86
+ "data-[swipe-direction=left]:w-drawer-lg data-[swipe-direction=right]:w-drawer-lg"
87
+ ]
88
+ },
89
+ xl: {
90
+ content: [
91
+ "data-[swipe-direction=down]:h-drawer-xl data-[swipe-direction=up]:h-drawer-xl",
92
+ "data-[swipe-direction=left]:w-drawer-xl data-[swipe-direction=right]:w-drawer-xl"
93
+ ]
94
+ },
95
+ full: {
96
+ content: [
97
+ "data-[swipe-direction=down]:h-full data-[swipe-direction=up]:h-full",
98
+ "data-[swipe-direction=left]:w-full data-[swipe-direction=right]:w-full"
99
+ ]
100
+ }
101
+ }
102
+ },
103
+ defaultVariants: {
104
+ size: "md"
105
+ }
106
+ });
107
+ export { drawerVariants };
@@ -0,0 +1,223 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { createContext, useContext, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
4
+ import { useDrawer } from "../../molecules/drawer.js";
5
+ const SidebarContext = /*#__PURE__*/ createContext(null);
6
+ const SidebarPanelContext = /*#__PURE__*/ createContext(null);
7
+ const SIDES = [
8
+ "start",
9
+ "end"
10
+ ];
11
+ function createSidebarFocusRegistry() {
12
+ const origins = {
13
+ end: null,
14
+ start: null
15
+ };
16
+ const revisions = {
17
+ end: 0,
18
+ start: 0
19
+ };
20
+ const clear = (side, revision)=>{
21
+ const origin = origins[side];
22
+ if (origin && (void 0 === revision || origin.revision === revision)) origins[side] = null;
23
+ };
24
+ return {
25
+ blur: ({ mode, node, relatedTarget, side })=>{
26
+ if (relatedTarget && node.contains(relatedTarget)) return;
27
+ const document = node.ownerDocument;
28
+ const clearBlurredOrigin = ()=>{
29
+ const origin = origins[side];
30
+ if (!origin || origin.mode !== mode || origin.node !== node) return;
31
+ if (node.contains(document.activeElement)) return;
32
+ if (node.isConnected && node.getClientRects().length > 0) return void clear(side, origin.revision);
33
+ const expireLease = ()=>{
34
+ const leasedOrigin = origins[side];
35
+ if (leasedOrigin?.revision === origin.revision && leasedOrigin.mode === mode && (!node.isConnected || 0 === node.getClientRects().length)) origins[side] = null;
36
+ };
37
+ const view = document.defaultView;
38
+ if (view) view.requestAnimationFrame(expireLease);
39
+ else globalThis.queueMicrotask(expireLease);
40
+ };
41
+ if (relatedTarget) return void clearBlurredOrigin();
42
+ const view = document.defaultView;
43
+ if (view) view.queueMicrotask(clearBlurredOrigin);
44
+ else globalThis.queueMicrotask(clearBlurredOrigin);
45
+ },
46
+ capture: ({ mode, node, side, triggerValue })=>{
47
+ revisions[side] += 1;
48
+ origins[side] = {
49
+ document: node.ownerDocument,
50
+ mode,
51
+ node,
52
+ revision: revisions[side],
53
+ side,
54
+ triggerValue
55
+ };
56
+ },
57
+ claim: (side, fromMode)=>{
58
+ const origin = origins[side];
59
+ if (origin?.mode !== fromMode) return null;
60
+ origins[side] = null;
61
+ return origin;
62
+ },
63
+ clear,
64
+ getRevision: (side)=>revisions[side],
65
+ peek: (side)=>origins[side]
66
+ };
67
+ }
68
+ function getDesktopServerSnapshot() {
69
+ return true;
70
+ }
71
+ function createSidebarBreakpointStore() {
72
+ let node = null;
73
+ return {
74
+ getSnapshot: ()=>node ? "none" !== getComputedStyle(node).display : true,
75
+ ref: (nextNode)=>{
76
+ node = nextNode;
77
+ },
78
+ subscribe: (listener)=>{
79
+ const target = node?.ownerDocument.defaultView;
80
+ let subscribed = true;
81
+ target?.addEventListener("resize", listener);
82
+ target?.queueMicrotask(()=>{
83
+ if (subscribed) listener();
84
+ });
85
+ return ()=>{
86
+ subscribed = false;
87
+ target?.removeEventListener("resize", listener);
88
+ };
89
+ }
90
+ };
91
+ }
92
+ function useSidebarDesktopBreakpoint() {
93
+ const [store] = useState(createSidebarBreakpointStore);
94
+ const isDesktop = useSyncExternalStore(store.subscribe, store.getSnapshot, getDesktopServerSnapshot);
95
+ return {
96
+ breakpointRef: store.ref,
97
+ isDesktop
98
+ };
99
+ }
100
+ function normalizeExpanded(sides) {
101
+ return SIDES.filter((side)=>sides.includes(side));
102
+ }
103
+ function normalizeCollapsible(policy) {
104
+ return {
105
+ start: policy?.start ?? "icon",
106
+ end: policy?.end ?? "icon"
107
+ };
108
+ }
109
+ function useSidebarState({ collapsible: collapsiblePolicy, defaultExpanded = SIDES, defaultMobileOpen = null, dir, expanded: controlledExpanded, id, mobileOpen: controlledMobileOpen, onExpandedChange, onMobileOpenChange } = {}) {
110
+ const generatedId = useId();
111
+ const rootId = id ?? generatedId;
112
+ const resolvedDir = dir ?? "ltr";
113
+ const collapsible = normalizeCollapsible(collapsiblePolicy);
114
+ const [focus] = useState(createSidebarFocusRegistry);
115
+ const { breakpointRef, isDesktop } = useSidebarDesktopBreakpoint();
116
+ const wasDesktop = useRef(isDesktop);
117
+ const [uncontrolledExpanded, setUncontrolledExpanded] = useState(()=>normalizeExpanded(defaultExpanded));
118
+ const [uncontrolledMobileOpen, setUncontrolledMobileOpen] = useState(defaultMobileOpen);
119
+ const expanded = normalizeExpanded(controlledExpanded ?? uncontrolledExpanded);
120
+ const effectiveExpanded = normalizeExpanded([
121
+ ...expanded,
122
+ ...SIDES.filter((side)=>"none" === collapsible[side])
123
+ ]);
124
+ const mobileOpen = void 0 === controlledMobileOpen ? uncontrolledMobileOpen : controlledMobileOpen;
125
+ const changeMobileOpen = (open)=>{
126
+ if (void 0 === controlledMobileOpen) setUncontrolledMobileOpen(open);
127
+ if (open !== mobileOpen) onMobileOpenChange?.({
128
+ open
129
+ });
130
+ };
131
+ const setExpanded = (side, nextExpanded)=>{
132
+ if ("none" === collapsible[side]) return;
133
+ const next = normalizeExpanded(nextExpanded ? [
134
+ ...expanded,
135
+ side
136
+ ] : expanded.filter((candidate)=>candidate !== side));
137
+ if (void 0 === controlledExpanded) setUncontrolledExpanded(next);
138
+ if (next.length !== expanded.length) onExpandedChange?.({
139
+ expanded: [
140
+ ...next
141
+ ]
142
+ });
143
+ };
144
+ useLayoutEffect(()=>{
145
+ if (isDesktop && !wasDesktop.current && null !== mobileOpen) {
146
+ if (void 0 === controlledMobileOpen) setUncontrolledMobileOpen(null);
147
+ onMobileOpenChange?.({
148
+ open: null
149
+ });
150
+ }
151
+ wasDesktop.current = isDesktop;
152
+ }, [
153
+ controlledMobileOpen,
154
+ isDesktop,
155
+ mobileOpen,
156
+ onMobileOpenChange
157
+ ]);
158
+ const createOpenChangeHandler = (side)=>({ open })=>{
159
+ if (open) changeMobileOpen(side);
160
+ else if (mobileOpen === side) changeMobileOpen(null);
161
+ };
162
+ const startDrawer = useDrawer({
163
+ dir: resolvedDir,
164
+ id: `${rootId}-start-drawer`,
165
+ onOpenChange: createOpenChangeHandler("start"),
166
+ open: !isDesktop && "start" === mobileOpen,
167
+ swipeDirection: "start"
168
+ });
169
+ const endDrawer = useDrawer({
170
+ dir: resolvedDir,
171
+ id: `${rootId}-end-drawer`,
172
+ onOpenChange: createOpenChangeHandler("end"),
173
+ open: !isDesktop && "end" === mobileOpen,
174
+ swipeDirection: "end"
175
+ });
176
+ return {
177
+ breakpointRef,
178
+ closeMobile: ()=>changeMobileOpen(null),
179
+ dir: resolvedDir,
180
+ drawer: {
181
+ start: startDrawer,
182
+ end: endDrawer
183
+ },
184
+ expanded: effectiveExpanded,
185
+ focus,
186
+ getCollapsible: (side)=>collapsible[side],
187
+ getPanelId: (side)=>`${rootId}-${side}-panel`,
188
+ isDesktop,
189
+ isExpanded: (side)=>effectiveExpanded.includes(side),
190
+ isFixed: (side)=>"none" === collapsible[side],
191
+ mobileOpen,
192
+ openMobile: (side)=>changeMobileOpen(side),
193
+ rootId,
194
+ setExpanded,
195
+ toggle: (side)=>{
196
+ if (isDesktop) setExpanded(side, !expanded.includes(side));
197
+ else changeMobileOpen(mobileOpen === side ? null : side);
198
+ }
199
+ };
200
+ }
201
+ function SidebarProvider({ children, value }) {
202
+ return /*#__PURE__*/ jsx(SidebarContext.Provider, {
203
+ value: value,
204
+ children: children
205
+ });
206
+ }
207
+ function SidebarPanelProvider({ children, value }) {
208
+ return /*#__PURE__*/ jsx(SidebarPanelContext.Provider, {
209
+ value: value,
210
+ children: children
211
+ });
212
+ }
213
+ function useSidebarContext() {
214
+ const context = useContext(SidebarContext);
215
+ if (!context) throw new Error("Sidebar components must be used within Sidebar.Root");
216
+ return context;
217
+ }
218
+ function useSidebarPanelContext() {
219
+ const context = useContext(SidebarPanelContext);
220
+ if (!context) throw new Error("Sidebar panel parts must be used within Sidebar.Panel");
221
+ return context;
222
+ }
223
+ export { SidebarPanelProvider, SidebarProvider, useSidebarContext, useSidebarPanelContext, useSidebarState };