@humain/ui 2.1.63 → 2.1.65

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 (160) hide show
  1. package/dist/components/organisms/ai/AIToolCall/AIToolCall.d.ts +9 -3
  2. package/dist/components/organisms/ai/AIToolRun/index.d.ts +1 -1
  3. package/dist/components/organisms/ai/AIToolRun/validation.d.ts +24 -3
  4. package/dist/components/organisms/ai/_shared/format-ai-duration.d.ts +1 -0
  5. package/dist/components/organisms/ai/_shared/workflow-step-renderer.d.ts +1 -0
  6. package/dist/index.js +52 -52
  7. package/dist/index151.js +1 -1
  8. package/dist/index174.js +7 -339
  9. package/dist/index174.js.map +1 -1
  10. package/dist/index175.js +310 -137
  11. package/dist/index175.js.map +1 -1
  12. package/dist/index176.js +148 -174
  13. package/dist/index176.js.map +1 -1
  14. package/dist/index177.js +186 -78
  15. package/dist/index177.js.map +1 -1
  16. package/dist/index178.js +74 -124
  17. package/dist/index178.js.map +1 -1
  18. package/dist/index179.js +133 -1
  19. package/dist/index179.js.map +1 -0
  20. package/dist/index180.js +2 -201
  21. package/dist/index181.js +201 -0
  22. package/dist/{index180.js.map → index181.js.map} +1 -1
  23. package/dist/index183.js +130 -166
  24. package/dist/index183.js.map +1 -1
  25. package/dist/index184.js +195 -983
  26. package/dist/index184.js.map +1 -1
  27. package/dist/index185.js +1069 -369
  28. package/dist/index185.js.map +1 -1
  29. package/dist/index186.js +395 -197
  30. package/dist/index186.js.map +1 -1
  31. package/dist/index187.js +198 -243
  32. package/dist/index187.js.map +1 -1
  33. package/dist/index188.js +263 -3
  34. package/dist/index188.js.map +1 -1
  35. package/dist/index189.js +3 -209
  36. package/dist/index189.js.map +1 -1
  37. package/dist/index190.js +190 -777
  38. package/dist/index190.js.map +1 -1
  39. package/dist/index191.js +771 -252
  40. package/dist/index191.js.map +1 -1
  41. package/dist/index192.js +250 -65
  42. package/dist/index192.js.map +1 -1
  43. package/dist/index193.js +72 -523
  44. package/dist/index193.js.map +1 -1
  45. package/dist/index194.js +537 -144
  46. package/dist/index194.js.map +1 -1
  47. package/dist/index195.js +139 -720
  48. package/dist/index195.js.map +1 -1
  49. package/dist/index196.js +707 -167
  50. package/dist/index196.js.map +1 -1
  51. package/dist/index197.js +175 -151
  52. package/dist/index197.js.map +1 -1
  53. package/dist/index198.js +152 -487
  54. package/dist/index198.js.map +1 -1
  55. package/dist/index199.js +472 -225
  56. package/dist/index199.js.map +1 -1
  57. package/dist/index200.js +236 -260
  58. package/dist/index200.js.map +1 -1
  59. package/dist/index201.js +265 -215
  60. package/dist/index201.js.map +1 -1
  61. package/dist/index202.js +207 -307
  62. package/dist/index202.js.map +1 -1
  63. package/dist/index203.js +302 -135
  64. package/dist/index203.js.map +1 -1
  65. package/dist/index204.js +140 -271
  66. package/dist/index204.js.map +1 -1
  67. package/dist/index205.js +263 -253
  68. package/dist/index205.js.map +1 -1
  69. package/dist/index206.js +244 -137
  70. package/dist/index206.js.map +1 -1
  71. package/dist/index207.js +100 -238
  72. package/dist/index207.js.map +1 -1
  73. package/dist/index208.js +278 -74
  74. package/dist/index208.js.map +1 -1
  75. package/dist/index209.js +56 -97
  76. package/dist/index209.js.map +1 -1
  77. package/dist/index210.js +142 -47
  78. package/dist/index210.js.map +1 -1
  79. package/dist/index211.js +38 -84
  80. package/dist/index211.js.map +1 -1
  81. package/dist/index212.js +72 -252
  82. package/dist/index212.js.map +1 -1
  83. package/dist/index213.js +274 -26
  84. package/dist/index213.js.map +1 -1
  85. package/dist/index214.js +29 -94
  86. package/dist/index214.js.map +1 -1
  87. package/dist/index215.js +98 -25
  88. package/dist/index215.js.map +1 -1
  89. package/dist/index216.js +20 -565
  90. package/dist/index216.js.map +1 -1
  91. package/dist/index217.js +564 -17
  92. package/dist/index217.js.map +1 -1
  93. package/dist/index218.js +20 -23
  94. package/dist/index218.js.map +1 -1
  95. package/dist/index219.js +20 -95
  96. package/dist/index219.js.map +1 -1
  97. package/dist/index220.js +92 -88
  98. package/dist/index220.js.map +1 -1
  99. package/dist/index221.js +97 -29
  100. package/dist/index221.js.map +1 -1
  101. package/dist/index222.js +24 -470
  102. package/dist/index222.js.map +1 -1
  103. package/dist/index223.js +446 -196
  104. package/dist/index223.js.map +1 -1
  105. package/dist/index224.js +199 -729
  106. package/dist/index224.js.map +1 -1
  107. package/dist/index225.js +750 -61
  108. package/dist/index225.js.map +1 -1
  109. package/dist/index226.js +58 -181
  110. package/dist/index226.js.map +1 -1
  111. package/dist/index227.js +175 -259
  112. package/dist/index227.js.map +1 -1
  113. package/dist/index228.js +246 -172
  114. package/dist/index228.js.map +1 -1
  115. package/dist/index229.js +195 -32
  116. package/dist/index229.js.map +1 -1
  117. package/dist/index230.js +12 -40
  118. package/dist/index230.js.map +1 -1
  119. package/dist/index231.js +23 -26
  120. package/dist/index231.js.map +1 -1
  121. package/dist/index232.js +45 -22
  122. package/dist/index232.js.map +1 -1
  123. package/dist/index233.js +27 -48
  124. package/dist/index233.js.map +1 -1
  125. package/dist/index234.js +52 -26
  126. package/dist/index234.js.map +1 -1
  127. package/dist/index235.js +40 -225
  128. package/dist/index235.js.map +1 -1
  129. package/dist/index236.js +217 -39
  130. package/dist/index236.js.map +1 -1
  131. package/dist/index237.js +50 -0
  132. package/dist/index237.js.map +1 -0
  133. package/dist/styles.css +1 -1
  134. package/dist/wc/AIToolCall.js +218 -0
  135. package/dist/wc/AIToolCall.js.map +1 -0
  136. package/dist/wc/hf-ai-tool-call.js +34 -219
  137. package/dist/wc/hf-ai-tool-call.js.map +1 -1
  138. package/dist/wc/hf-ai-tool-run.js +673 -576
  139. package/dist/wc/hf-ai-tool-run.js.map +1 -1
  140. package/dist/wc/workflow-step-renderer.js +79 -78
  141. package/dist/wc/workflow-step-renderer.js.map +1 -1
  142. package/dist/wc-react/AIToolCall.js +218 -0
  143. package/dist/wc-react/AIToolCall.js.map +1 -0
  144. package/dist/wc-react/hf-ai-tool-call.js +32 -217
  145. package/dist/wc-react/hf-ai-tool-call.js.map +1 -1
  146. package/dist/wc-react/hf-ai-tool-run.js +698 -601
  147. package/dist/wc-react/hf-ai-tool-run.js.map +1 -1
  148. package/dist/wc-react/workflow-step-renderer.js +58 -57
  149. package/dist/wc-react/workflow-step-renderer.js.map +1 -1
  150. package/package.json +1 -1
  151. package/skills/humain-ui/SKILL.md +1 -1
  152. package/skills/humain-ui-wc/SKILL.md +1 -1
  153. package/skills/humain-ui-wc.skill +0 -0
  154. package/skills/humain-ui.skill +0 -0
  155. package/dist/index182.js +0 -143
  156. package/dist/index182.js.map +0 -1
  157. package/dist/wc/wrench.js +0 -10
  158. package/dist/wc/wrench.js.map +0 -1
  159. package/dist/wc-react/wrench.js +0 -10
  160. package/dist/wc-react/wrench.js.map +0 -1
package/dist/index223.js CHANGED
@@ -1,229 +1,479 @@
1
1
  "use client";
2
2
  import { cn } from "./index2.js";
3
- import { Button } from "./index5.js";
4
- import { DropdownMenu } from "./index191.js";
5
- import { usePanelExpansion } from "./index217.js";
6
- import { AppShellContent } from "./index218.js";
7
- import { EllipsisVertical, Maximize2, Minimize2 } from "lucide-react";
3
+ import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "./index49.js";
4
+ import { AppShell as AppShell$1 } from "./index214.js";
5
+ import { Sheet as SheetNamespace, SheetContent } from "./index215.js";
6
+ import { useIsMobile } from "./index216.js";
7
+ import { SidebarContext } from "./index217.js";
8
+ import { AppShellProvider, PanelIndexContext, PanelLayoutContext } from "./index218.js";
9
+ import { AppShellContent } from "./index219.js";
10
+ import { AppShellMobileTabBar } from "./index220.js";
11
+ import { AppShellPanel } from "./index221.js";
12
+ import { getExpandedPanelFromLayout, layoutMapToTuple, normalizePanelSizes, toResizableMinSize, toResizablePercentageSize } from "./index222.js";
8
13
  import * as React from "react";
9
14
  import { jsx, jsxs } from "react/jsx-runtime";
10
- //#region src/components/templates/AppShellCard/AppShellCard.tsx
11
- var HEADER_TYPE = "AppShellCard.Header";
12
- var TOOLBAR_TYPE = "AppShellCard.Toolbar";
13
- var ACTIONS_TYPE = "AppShellCard.Actions";
14
- var MENU_TYPE = "AppShellCard.Menu";
15
- var TITLE_TYPE = "AppShellCard.Title";
16
- function getAppShellCardType(child) {
17
- if (!child.type || typeof child.type === "string") return;
18
- return child.type.__appShellCardType;
15
+ //#region src/components/templates/AppShell/AppShell.tsx
16
+ var DEFAULT_APP_SHELL_BACKGROUND = "var(--app-background)";
17
+ function isAppShellPanelComponent(type) {
18
+ return typeof type === "function" && type.__appShellType === "AppShell.Panel";
19
19
  }
20
- function assignAppShellCardType(component, type) {
21
- component.__appShellCardType = type;
22
- return component;
20
+ function isAppShellPanelElement(child) {
21
+ return React.isValidElement(child) && isAppShellPanelComponent(child.type);
23
22
  }
24
- function getNodeText(node) {
25
- if (typeof node === "string" || typeof node === "number") return String(node);
26
- if (Array.isArray(node)) return node.map(getNodeText).join("");
27
- if (React.isValidElement(node)) return getNodeText(node.props.children);
28
- return "";
23
+ function getAppShellPanelIdentity(panel, ariaBaseId, index) {
24
+ return panel.key ?? panel.props.label ?? `${ariaBaseId}-panel-${index}`;
29
25
  }
30
- function getTitleText(node) {
31
- let titleText = "";
32
- React.Children.forEach(node, (child) => {
33
- if (titleText || !React.isValidElement(child)) return;
34
- if (getAppShellCardType(child) === TITLE_TYPE) {
35
- titleText = getNodeText(child.props.children).trim();
36
- return;
37
- }
38
- titleText = getTitleText(child.props.children);
26
+ function AppShellPanelWithLayout({ panel, visible, index, overrides = {}, isMobile, activePanel, hasExpanded, hasTabBar, ariaBaseId, rootExpansionActive, firstExpandedIndex, onExpandedPanelChange }) {
27
+ if (isMobile && index !== activePanel) return null;
28
+ const layoutInfo = {
29
+ visible: isMobile ? true : visible,
30
+ collapseMode: hasExpanded ? "animated" : "removed",
31
+ isMobile,
32
+ tabId: hasTabBar ? `${ariaBaseId}-tab-${index}` : void 0,
33
+ panelId: hasTabBar ? `${ariaBaseId}-tabpanel-${index}` : void 0,
34
+ expanded: rootExpansionActive ? hasExpanded && index === firstExpandedIndex : void 0,
35
+ onExpandedChange: rootExpansionActive ? (nextExpanded) => onExpandedPanelChange(nextExpanded ? index : null) : void 0,
36
+ ...overrides
37
+ };
38
+ return /* @__PURE__ */ jsx(PanelIndexContext.Provider, {
39
+ value: index,
40
+ children: /* @__PURE__ */ jsx(PanelLayoutContext.Provider, {
41
+ value: layoutInfo,
42
+ children: panel
43
+ })
39
44
  });
40
- return titleText;
41
45
  }
42
- var appShellCardBodyPaddingClasses = {
43
- none: "",
44
- md: "p-4 sm:p-6"
45
- };
46
- var appShellCardElevationClasses = {
47
- none: "shadow-none",
48
- "2xs": "shadow-2xs",
49
- xs: "shadow-xs",
50
- sm: "shadow-sm",
51
- md: "shadow-md",
52
- lg: "shadow-lg",
53
- xl: "shadow-xl",
54
- "2xl": "shadow-2xl"
55
- };
56
- var appShellCardToolbarClassName = "flex shrink-0 items-center gap-4 overflow-hidden border-b border-border px-4 py-3 sm:gap-6 sm:p-6";
57
- var AppShellCardRoot = React.forwardRef(function AppShellCardRoot({ className, bodyPadding = "md", elevation = "md", bodyClassName, bodyAriaLabel, inset = false, children, ...props }, ref) {
58
- const expansion = usePanelExpansion();
59
- const menuId = React.useId();
60
- const bodyRef = React.useRef(null);
46
+ function AppShellRoot({ background = DEFAULT_APP_SHELL_BACKGROUND, height = "100dvh", padding = 16, mobilePadding, gap = 12, connected = false, skipToId, activePanel: activePanelProp, onActivePanelChange, defaultActivePanel = 0, expandedPanel: expandedPanelProp, defaultExpandedPanel, onExpandedPanelChange, resizablePanels, defaultPanelSizes, panelSizes, onPanelSizesChange, expandThreshold = 85, className, children, ...props }) {
47
+ const isMobile = useIsMobile();
48
+ const ariaBaseId = React.useId();
49
+ const [internalActivePanel, setInternalActivePanel] = React.useState(defaultActivePanel);
50
+ const [internalExpandedPanel, setInternalExpandedPanel] = React.useState(defaultExpandedPanel ?? null);
51
+ const [internalPanelSizes, setInternalPanelSizes] = React.useState(() => normalizePanelSizes(defaultPanelSizes));
52
+ const [isResizingPanels, setIsResizingPanels] = React.useState(false);
53
+ const [isRestoringResizablePanels, setIsRestoringResizablePanels] = React.useState(false);
54
+ const [internalMobileSidebarOpen, setInternalMobileSidebarOpen] = React.useState(false);
55
+ const resizableGroupRef = React.useRef(null);
56
+ const rootRef = React.useRef(null);
57
+ const allowResizeReleaseExpansionRef = React.useRef(false);
58
+ const suppressControlledLayoutChangeRef = React.useRef(false);
59
+ const previousResizableExpandedRef = React.useRef(false);
60
+ const activePanel = activePanelProp ?? internalActivePanel;
61
+ const handleActivePanelChange = React.useCallback((index) => {
62
+ if (activePanelProp === void 0) setInternalActivePanel((prev) => prev === index ? prev : index);
63
+ onActivePanelChange?.(index);
64
+ }, [activePanelProp, onActivePanelChange]);
65
+ const rootExpansionRequested = expandedPanelProp !== void 0 || defaultExpandedPanel !== void 0 || onExpandedPanelChange !== void 0;
66
+ const resolvedExpandedPanel = expandedPanelProp !== void 0 ? expandedPanelProp : internalExpandedPanel;
67
+ const handleExpandedPanelChange = React.useCallback((panelIndex) => {
68
+ if (expandedPanelProp === void 0) setInternalExpandedPanel(panelIndex);
69
+ onExpandedPanelChange?.(panelIndex);
70
+ }, [expandedPanelProp, onExpandedPanelChange]);
71
+ const { panels, panelInfos, sidebarChild, otherChildren } = React.useMemo(() => {
72
+ const p = [];
73
+ const infos = [];
74
+ let sidebar = null;
75
+ const other = [];
76
+ React.Children.forEach(children, (child) => {
77
+ if (isAppShellPanelElement(child)) {
78
+ infos.push({
79
+ key: child.key ?? child.props.label,
80
+ label: child.props.label
81
+ });
82
+ p.push(child);
83
+ return;
84
+ }
85
+ if (!React.isValidElement(child)) return;
86
+ if (child.type === AppShellSidebar) sidebar = child;
87
+ else other.push(child);
88
+ });
89
+ return {
90
+ panels: p,
91
+ panelInfos: infos,
92
+ sidebarChild: sidebar,
93
+ otherChildren: other
94
+ };
95
+ }, [children]);
96
+ const shouldUseResizablePanels = resizablePanels ?? true;
97
+ const firstPanelExpandedIndex = panels.findIndex((p) => p.props.expanded);
98
+ const hasPanelExpansionProps = panels.some((panel) => panel.props.expanded !== void 0 || panel.props.onExpandedChange !== void 0);
99
+ const canUseResizablePanelPair = shouldUseResizablePanels && !connected && !isMobile && panels.length === 2 && (resizablePanels !== void 0 || !hasPanelExpansionProps);
100
+ const rootExpansionActive = rootExpansionRequested || canUseResizablePanelPair;
101
+ const validRootExpandedPanel = typeof resolvedExpandedPanel === "number" && Number.isInteger(resolvedExpandedPanel) && resolvedExpandedPanel >= 0 && resolvedExpandedPanel < panels.length ? resolvedExpandedPanel : null;
102
+ let firstExpandedIndex = firstPanelExpandedIndex;
103
+ if (rootExpansionActive) firstExpandedIndex = validRootExpandedPanel;
104
+ const hasExpanded = firstExpandedIndex !== -1 && firstExpandedIndex !== null;
105
+ const visibleCount = hasExpanded ? 1 : Math.min(panels.length, 2);
106
+ const canRenderResizablePanels = canUseResizablePanelPair;
107
+ const resolvedPanelSizes = React.useMemo(() => normalizePanelSizes(panelSizes ?? internalPanelSizes), [panelSizes, internalPanelSizes]);
108
+ const resizablePanelSizes = React.useMemo(() => {
109
+ if (hasExpanded && firstExpandedIndex === 0) return [100, 0];
110
+ if (hasExpanded && firstExpandedIndex === 1) return [0, 100];
111
+ return resolvedPanelSizes;
112
+ }, [
113
+ firstExpandedIndex,
114
+ hasExpanded,
115
+ resolvedPanelSizes
116
+ ]);
117
+ const shouldBypassResizableMinSize = hasExpanded || isRestoringResizablePanels || !hasExpanded && previousResizableExpandedRef.current;
118
+ if (process.env.NODE_ENV !== "production") {
119
+ const expandedPanelPropCount = panels.filter((p) => p.props.expanded).length;
120
+ if (rootExpansionActive && expandedPanelPropCount > 0) console.warn("AppShell.Root: root-owned expansion props should not be mixed with AppShell.Panel expanded. Root expansion will be used.");
121
+ if (!rootExpansionActive && expandedPanelPropCount > 1) console.warn("AppShell.Root: multiple panels have expanded={true}. Only the first expanded panel will be shown.");
122
+ if (rootExpansionActive && resolvedExpandedPanel !== null && resolvedExpandedPanel !== void 0 && validRootExpandedPanel === null) console.warn(`AppShell.Root: expandedPanel index ${resolvedExpandedPanel} is out of range. No panel will be expanded.`);
123
+ if (resizablePanels === true && connected) console.warn("AppShell.Root: resizablePanels is not supported with connected. Rendering non-resizable panels.");
124
+ if (resizablePanels === true && !connected && panels.length !== 2) console.warn(`AppShell.Root: resizablePanels requires exactly 2 Panel children, got ${panels.length}. Rendering non-resizable panels.`);
125
+ if (panels.length > 2 && !hasExpanded) console.warn(`AppShell.Root: max 2 Panel children allowed, got ${panels.length}. Only the first 2 will be visible.`);
126
+ }
127
+ const handleLayoutChange = React.useCallback((layout) => {
128
+ if (hasExpanded || suppressControlledLayoutChangeRef.current) return;
129
+ if (panelSizes === void 0) setInternalPanelSizes(layoutMapToTuple(layout));
130
+ }, [hasExpanded, panelSizes]);
131
+ const handleLayoutChanged = React.useCallback((layout) => {
132
+ if (hasExpanded || !allowResizeReleaseExpansionRef.current || suppressControlledLayoutChangeRef.current) return;
133
+ const nextSizes = layoutMapToTuple(layout);
134
+ if (panelSizes === void 0) setInternalPanelSizes(nextSizes);
135
+ onPanelSizesChange?.(nextSizes);
136
+ const expandedIndex = getExpandedPanelFromLayout(layout, expandThreshold);
137
+ if (expandedIndex !== null) handleExpandedPanelChange(expandedIndex);
138
+ }, [
139
+ expandThreshold,
140
+ handleExpandedPanelChange,
141
+ hasExpanded,
142
+ onPanelSizesChange,
143
+ panelSizes
144
+ ]);
61
145
  React.useEffect(() => {
62
- const el = bodyRef.current;
63
- if (!el) return;
64
- const update = () => {
65
- const hasOverflow = el.scrollHeight > el.clientHeight;
66
- const top = hasOverflow && el.scrollTop > 0 ? "1" : "0";
67
- const bottom = hasOverflow && el.scrollTop + el.clientHeight < el.scrollHeight - 1 ? "1" : "0";
68
- if (el.style.getPropertyValue("--scroll-t") !== top) el.style.setProperty("--scroll-t", top);
69
- if (el.style.getPropertyValue("--scroll-b") !== bottom) el.style.setProperty("--scroll-b", bottom);
146
+ if (!canRenderResizablePanels) {
147
+ suppressControlledLayoutChangeRef.current = false;
148
+ previousResizableExpandedRef.current = false;
149
+ return;
150
+ }
151
+ const ownerWindow = rootRef.current?.ownerDocument.defaultView;
152
+ if (!ownerWindow) return;
153
+ const wasExpanded = previousResizableExpandedRef.current;
154
+ previousResizableExpandedRef.current = hasExpanded;
155
+ if (!(hasExpanded || wasExpanded || panelSizes !== void 0)) {
156
+ suppressControlledLayoutChangeRef.current = false;
157
+ return;
158
+ }
159
+ let restoreFrame;
160
+ const [first, second] = resizablePanelSizes;
161
+ if (wasExpanded && !hasExpanded) restoreFrame = ownerWindow.requestAnimationFrame(() => {
162
+ setIsRestoringResizablePanels(true);
163
+ });
164
+ suppressControlledLayoutChangeRef.current = true;
165
+ const nextLayout = {
166
+ panel0: first,
167
+ panel1: second
70
168
  };
71
- el.addEventListener("scroll", update, { passive: true });
72
- const OwnerResizeObserver = el.ownerDocument.defaultView?.ResizeObserver;
73
- const observer = OwnerResizeObserver ? new OwnerResizeObserver(update) : null;
74
- observer?.observe(el);
75
- update();
169
+ resizableGroupRef.current?.setLayout(nextLayout);
170
+ const frame = ownerWindow.requestAnimationFrame(() => {
171
+ resizableGroupRef.current?.setLayout(nextLayout);
172
+ });
173
+ const timeout = ownerWindow.setTimeout(() => {
174
+ suppressControlledLayoutChangeRef.current = false;
175
+ }, 350);
76
176
  return () => {
77
- el.removeEventListener("scroll", update);
78
- observer?.disconnect();
177
+ if (restoreFrame !== void 0) ownerWindow.cancelAnimationFrame(restoreFrame);
178
+ ownerWindow.cancelAnimationFrame(frame);
179
+ ownerWindow.clearTimeout(timeout);
180
+ suppressControlledLayoutChangeRef.current = false;
79
181
  };
80
- }, []);
81
- let toolbarSlot = null;
82
- let headerSlot = null;
83
- let actionsSlot = null;
84
- let menuSlot = null;
85
- const toolbarChildren = [];
86
- const bodyChildren = [];
87
- for (const child of React.Children.toArray(children)) {
88
- if (!React.isValidElement(child)) {
89
- bodyChildren.push(child);
90
- continue;
91
- }
92
- const type = getAppShellCardType(child);
93
- if (type === HEADER_TYPE) headerSlot = child;
94
- else if (type === TOOLBAR_TYPE) toolbarSlot = child;
95
- else if (type === ACTIONS_TYPE) actionsSlot = child;
96
- else if (type === MENU_TYPE) menuSlot = child;
97
- else bodyChildren.push(child);
98
- }
99
- if (toolbarSlot) for (const child of React.Children.toArray(toolbarSlot.props.children)) {
100
- if (!React.isValidElement(child)) {
101
- toolbarChildren.push(child);
102
- continue;
182
+ }, [
183
+ canRenderResizablePanels,
184
+ hasExpanded,
185
+ panelSizes,
186
+ resizablePanelSizes
187
+ ]);
188
+ React.useEffect(() => {
189
+ if (!isRestoringResizablePanels) return;
190
+ const ownerWindow = rootRef.current?.ownerDocument.defaultView;
191
+ if (!ownerWindow) return;
192
+ const timeout = ownerWindow.setTimeout(() => {
193
+ setIsRestoringResizablePanels(false);
194
+ }, 350);
195
+ return () => ownerWindow.clearTimeout(timeout);
196
+ }, [isRestoringResizablePanels]);
197
+ React.useEffect(() => {
198
+ if (!canRenderResizablePanels) {
199
+ allowResizeReleaseExpansionRef.current = false;
200
+ suppressControlledLayoutChangeRef.current = false;
201
+ return;
103
202
  }
104
- const type = getAppShellCardType(child);
105
- if (type === HEADER_TYPE) headerSlot = child;
106
- else if (type === ACTIONS_TYPE) actionsSlot = child;
107
- else if (type === MENU_TYPE) menuSlot = child;
108
- else toolbarChildren.push(child);
109
- }
110
- const hasToolbar = toolbarSlot || headerSlot || actionsSlot || menuSlot || toolbarChildren.length > 0 || expansion?.onExpandedChange;
111
- const titleText = headerSlot ? getTitleText(headerSlot) : "";
112
- const resolvedBodyAriaLabel = bodyAriaLabel ?? (titleText ? `${titleText} content` : "Card content");
113
- const { children: _toolbarSlotChildren, className: toolbarClassName, ...toolbarProps } = toolbarSlot?.props ?? {};
114
- return /* @__PURE__ */ jsxs(AppShellContent, {
115
- ref,
116
- "data-slot": "app-shell-card",
117
- className: cn(appShellCardElevationClasses[elevation], "transition-[margin] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]", inset && !expansion?.expanded ? "mx-5 my-10" : "m-0", className),
118
- ...props,
119
- children: [hasToolbar && /* @__PURE__ */ jsxs("div", {
120
- role: "toolbar",
121
- "aria-label": "Card actions",
122
- ...toolbarProps,
123
- "data-slot": "app-shell-card-toolbar",
124
- className: cn(appShellCardToolbarClassName, toolbarClassName),
125
- children: [
126
- headerSlot,
127
- toolbarChildren,
128
- actionsSlot,
129
- menuSlot && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenu.Trigger, { render: /* @__PURE__ */ jsx(Button, {
130
- appearance: "ghost",
131
- size: "icon",
132
- "aria-label": "More options",
133
- children: /* @__PURE__ */ jsx(EllipsisVertical, { className: "size-5" })
134
- }) }), /* @__PURE__ */ jsx(DropdownMenu.Popup, {
135
- id: `${menuId}-popup`,
136
- align: "end",
137
- sideOffset: 4,
138
- children: menuSlot.props.children
139
- })] }),
140
- expansion?.onExpandedChange && /* @__PURE__ */ jsx(Button, {
141
- appearance: "ghost",
142
- size: "icon",
143
- onClick: () => expansion.onExpandedChange?.(!expansion.expanded),
144
- "aria-label": expansion.expanded ? "Minimize panel" : "Maximize panel",
145
- children: /* @__PURE__ */ jsx("span", {
146
- className: "delight-fade-in inline-flex",
147
- children: expansion.expanded ? /* @__PURE__ */ jsx(Minimize2, { className: "size-5" }) : /* @__PURE__ */ jsx(Maximize2, { className: "size-5" })
148
- }, String(expansion.expanded))
203
+ const ownerWindow = rootRef.current?.ownerDocument.defaultView;
204
+ if (!ownerWindow) return;
205
+ const frame = ownerWindow.requestAnimationFrame(() => {
206
+ allowResizeReleaseExpansionRef.current = true;
207
+ });
208
+ return () => {
209
+ ownerWindow.cancelAnimationFrame(frame);
210
+ allowResizeReleaseExpansionRef.current = false;
211
+ };
212
+ }, [canRenderResizablePanels]);
213
+ React.useEffect(() => {
214
+ if (!isResizingPanels) return;
215
+ const ownerWindow = rootRef.current?.ownerDocument.defaultView;
216
+ if (!ownerWindow) return;
217
+ const stopResizing = () => setIsResizingPanels(false);
218
+ ownerWindow.addEventListener("pointerup", stopResizing);
219
+ ownerWindow.addEventListener("pointercancel", stopResizing);
220
+ return () => {
221
+ ownerWindow.removeEventListener("pointerup", stopResizing);
222
+ ownerWindow.removeEventListener("pointercancel", stopResizing);
223
+ };
224
+ }, [isResizingPanels]);
225
+ const handleResizablePointerDownCapture = React.useCallback((event) => {
226
+ const target = event.target;
227
+ if (!(target instanceof Element)) return;
228
+ if (target.closest("[data-slot=\"resizable-handle\"]")) setIsResizingPanels(true);
229
+ }, []);
230
+ const visiblePanels = React.useMemo(() => hasExpanded ? panels.map((panel, i) => ({
231
+ panel,
232
+ visible: i === firstExpandedIndex,
233
+ index: i
234
+ })) : panels.map((panel, i) => ({
235
+ panel,
236
+ visible: i < 2,
237
+ index: i
238
+ })), [
239
+ panels,
240
+ hasExpanded,
241
+ firstExpandedIndex
242
+ ]);
243
+ const hasTabBar = isMobile && panels.length > 1;
244
+ const getPanelPosition = React.useCallback((index) => {
245
+ if (visibleCount === 1) return "only";
246
+ if (hasExpanded) return index === firstExpandedIndex ? "only" : "last";
247
+ return index === 0 ? "first" : "last";
248
+ }, [
249
+ visibleCount,
250
+ hasExpanded,
251
+ firstExpandedIndex
252
+ ]);
253
+ const contextValue = React.useMemo(() => ({
254
+ connected,
255
+ panelCount: visibleCount,
256
+ getPanelPosition
257
+ }), [
258
+ connected,
259
+ visibleCount,
260
+ getPanelPosition
261
+ ]);
262
+ const sidebarContext = React.useContext(SidebarContext);
263
+ const mobileSidebarOpen = sidebarContext?.openMobile ?? internalMobileSidebarOpen;
264
+ const setMobileSidebarOpen = sidebarContext?.setOpenMobile ?? setInternalMobileSidebarOpen;
265
+ const handleSidebarOpen = React.useCallback(() => {
266
+ setMobileSidebarOpen(true);
267
+ }, [setMobileSidebarOpen]);
268
+ const handleSheetOpenChange = React.useCallback((open) => {
269
+ setMobileSidebarOpen(open);
270
+ }, [setMobileSidebarOpen]);
271
+ const skipLink = skipToId ? /* @__PURE__ */ jsx("a", {
272
+ href: `#${skipToId}`,
273
+ className: "sr-only focus:not-sr-only focus:fixed focus:left-4 focus:top-4 focus:z-50 focus:rounded-md focus:bg-background focus:px-4 focus:py-2 focus:text-sm focus:font-medium focus:text-foreground focus:shadow-sm focus:ring-2 focus:ring-ring",
274
+ children: "Skip to content"
275
+ }) : null;
276
+ const renderedPanels = React.useMemo(() => visiblePanels.map(({ panel, visible, index }) => /* @__PURE__ */ jsx(AppShellPanelWithLayout, {
277
+ panel,
278
+ visible,
279
+ index,
280
+ isMobile,
281
+ activePanel,
282
+ hasExpanded,
283
+ hasTabBar,
284
+ ariaBaseId,
285
+ rootExpansionActive,
286
+ firstExpandedIndex,
287
+ onExpandedPanelChange: handleExpandedPanelChange
288
+ }, getAppShellPanelIdentity(panel, ariaBaseId, index))), [
289
+ visiblePanels,
290
+ ariaBaseId,
291
+ isMobile,
292
+ activePanel,
293
+ hasExpanded,
294
+ hasTabBar,
295
+ rootExpansionActive,
296
+ firstExpandedIndex,
297
+ handleExpandedPanelChange
298
+ ]);
299
+ const renderedResizablePanels = canRenderResizablePanels ? /* @__PURE__ */ jsxs(ResizablePanelGroup, {
300
+ orientation: "horizontal",
301
+ disabled: hasExpanded,
302
+ groupRef: resizableGroupRef,
303
+ onLayoutChange: handleLayoutChange,
304
+ onLayoutChanged: handleLayoutChanged,
305
+ onPointerDownCapture: handleResizablePointerDownCapture,
306
+ className: cn("min-h-0 min-w-0 flex-1", !isResizingPanels && "[&>[data-slot=resizable-panel]]:transition-[flex-grow] [&>[data-slot=resizable-panel]]:duration-300 [&>[data-slot=resizable-panel]]:ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:[&>[data-slot=resizable-panel]]:transition-none"),
307
+ children: [
308
+ /* @__PURE__ */ jsx(ResizablePanel, {
309
+ id: "panel0",
310
+ defaultSize: toResizablePercentageSize(resizablePanelSizes[0]),
311
+ minSize: shouldBypassResizableMinSize ? 0 : toResizableMinSize(panels[0].props.minWidth),
312
+ children: /* @__PURE__ */ jsx(AppShellPanelWithLayout, {
313
+ panel: panels[0],
314
+ visible: !hasExpanded || firstExpandedIndex === 0,
315
+ index: 0,
316
+ overrides: { sizeManagedByRoot: true },
317
+ isMobile,
318
+ activePanel,
319
+ hasExpanded,
320
+ hasTabBar,
321
+ ariaBaseId,
322
+ rootExpansionActive,
323
+ firstExpandedIndex,
324
+ onExpandedPanelChange: handleExpandedPanelChange
149
325
  })
326
+ }),
327
+ /* @__PURE__ */ jsx(ResizableHandle, {
328
+ disabled: hasExpanded,
329
+ className: cn("z-10 min-w-2 shrink-0 cursor-col-resize w-[var(--app-shell-gap,0px)] bg-transparent after:w-2 hover:bg-transparent", "transition-[width,min-width,opacity,background-color] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none", hasExpanded && "min-w-0 w-0 opacity-0 after:w-0 pointer-events-none")
330
+ }),
331
+ /* @__PURE__ */ jsx(ResizablePanel, {
332
+ id: "panel1",
333
+ defaultSize: toResizablePercentageSize(resizablePanelSizes[1]),
334
+ minSize: shouldBypassResizableMinSize ? 0 : toResizableMinSize(panels[1].props.minWidth),
335
+ children: /* @__PURE__ */ jsx(AppShellPanelWithLayout, {
336
+ panel: panels[1],
337
+ visible: !hasExpanded || firstExpandedIndex === 1,
338
+ index: 1,
339
+ overrides: { sizeManagedByRoot: true },
340
+ isMobile,
341
+ activePanel,
342
+ hasExpanded,
343
+ hasTabBar,
344
+ ariaBaseId,
345
+ rootExpansionActive,
346
+ firstExpandedIndex,
347
+ onExpandedPanelChange: handleExpandedPanelChange
348
+ })
349
+ })
350
+ ]
351
+ }) : null;
352
+ const activeLabel = hasTabBar && panelInfos[activePanel] ? panelInfos[activePanel].label || `Panel ${activePanel + 1}` : null;
353
+ if (isMobile) return /* @__PURE__ */ jsx(AppShellProvider, {
354
+ value: contextValue,
355
+ children: /* @__PURE__ */ jsxs(AppShell$1, {
356
+ ref: rootRef,
357
+ background,
358
+ height,
359
+ padding,
360
+ mobilePadding,
361
+ gap: 0,
362
+ connected,
363
+ className,
364
+ ...props,
365
+ children: [
366
+ skipLink,
367
+ sidebarChild && /* @__PURE__ */ jsx(SheetNamespace, {
368
+ open: mobileSidebarOpen,
369
+ onOpenChange: handleSheetOpenChange,
370
+ children: /* @__PURE__ */ jsx(SheetContent, {
371
+ side: "left",
372
+ showCloseButton: false,
373
+ className: "w-[280px] p-0",
374
+ "aria-label": "Sidebar navigation",
375
+ children: sidebarChild
376
+ })
377
+ }),
378
+ /* @__PURE__ */ jsxs("div", {
379
+ className: "flex h-full min-w-0 flex-1 flex-col overflow-clip",
380
+ children: [/* @__PURE__ */ jsx(AppShellMobileTabBar, {
381
+ panels: panelInfos,
382
+ activeIndex: activePanel,
383
+ onActiveChange: handleActivePanelChange,
384
+ onSidebarOpen: sidebarChild ? handleSidebarOpen : void 0,
385
+ baseId: ariaBaseId
386
+ }), /* @__PURE__ */ jsx("div", {
387
+ className: "flex min-h-0 flex-1",
388
+ children: renderedPanels
389
+ })]
390
+ }),
391
+ activeLabel && /* @__PURE__ */ jsxs("div", {
392
+ className: "sr-only",
393
+ role: "status",
394
+ "aria-live": "polite",
395
+ children: [activeLabel, " panel active"]
396
+ }),
397
+ otherChildren
150
398
  ]
151
- }), /* @__PURE__ */ jsx("section", {
152
- ref: bodyRef,
153
- "data-slot": "app-shell-card-body",
154
- "aria-label": resolvedBodyAriaLabel || "Card content",
155
- tabIndex: 0,
156
- className: cn("delight-scroll-shadow flex-1 min-h-0 overflow-auto focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring rounded-b-[inherit]", appShellCardBodyPaddingClasses[bodyPadding], bodyClassName),
157
- children: bodyChildren
158
- })]
399
+ })
159
400
  });
160
- });
161
- AppShellCardRoot.displayName = "AppShellCard";
162
- function AppShellCardToolbar({ className, children, ...props }) {
163
- return /* @__PURE__ */ jsx("div", {
164
- "data-slot": "app-shell-card-toolbar",
165
- role: "toolbar",
166
- "aria-label": "Card actions",
167
- className: cn(appShellCardToolbarClassName, className),
168
- ...props,
169
- children
401
+ return /* @__PURE__ */ jsx(AppShellProvider, {
402
+ value: contextValue,
403
+ children: /* @__PURE__ */ jsxs(AppShell$1, {
404
+ ref: rootRef,
405
+ background,
406
+ height,
407
+ padding,
408
+ mobilePadding,
409
+ gap: connected || hasExpanded ? 0 : gap,
410
+ connected,
411
+ className,
412
+ ...props,
413
+ children: [
414
+ skipLink,
415
+ sidebarChild,
416
+ renderedResizablePanels ?? renderedPanels,
417
+ otherChildren
418
+ ]
419
+ })
170
420
  });
171
421
  }
172
- AppShellCardToolbar.displayName = "AppShellCard.Toolbar";
173
- assignAppShellCardType(AppShellCardToolbar, TOOLBAR_TYPE);
174
- function AppShellCardHeader({ className, children, ...props }) {
422
+ AppShellRoot.displayName = "AppShell";
423
+ /**
424
+ * Layout slot for the sidebar region. Renders a div — the actual aside
425
+ * landmark is provided by AppSidebar/Sidebar primitive inside it.
426
+ *
427
+ * **Auto-detection (default):** When no `width` prop is provided, the sidebar
428
+ * observes the child SidebarProvider's `data-state` attribute via CSS `:has()`
429
+ * and transitions between `collapsedWidth` and `expandedWidth` automatically.
430
+ *
431
+ * **Manual mode:** Pass an explicit `width` to control sizing yourself.
432
+ */
433
+ function AppShellSidebar({ width, expandedWidth = "280px", collapsedWidth = "64px", className, style, children, ...props }) {
434
+ const autoMode = !width;
175
435
  return /* @__PURE__ */ jsx("div", {
176
- "data-slot": "app-shell-card-header",
177
- className: cn("flex min-w-0 flex-1 flex-col justify-center", className),
436
+ "data-slot": "app-shell-sidebar",
437
+ style: {
438
+ ...autoMode ? {
439
+ "--app-shell-sidebar-collapsed": collapsedWidth,
440
+ "--app-shell-sidebar-expanded": expandedWidth
441
+ } : { "--app-shell-sidebar-width": width },
442
+ ...style
443
+ },
444
+ className: cn("flex h-full shrink-0 flex-col overflow-clip", "transition-[width] duration-300 ease-[cubic-bezier(0.16,1,0.3,1)]", "motion-reduce:transition-none", autoMode ? ["w-[var(--app-shell-sidebar-collapsed,64px)]", "[&:has([data-state=expanded])]:w-[var(--app-shell-sidebar-expanded,280px)]"] : "w-[var(--app-shell-sidebar-width,64px)]", className),
178
445
  ...props,
179
446
  children
180
447
  });
181
448
  }
182
- AppShellCardHeader.displayName = "AppShellCard.Header";
183
- assignAppShellCardType(AppShellCardHeader, HEADER_TYPE);
184
- function AppShellCardTitle({ className, children, ...props }) {
185
- return /* @__PURE__ */ jsx("h3", {
186
- "data-slot": "app-shell-card-title",
187
- className: cn("text-lg font-semibold leading-7 text-foreground", className),
188
- ...props,
189
- children
190
- });
191
- }
192
- AppShellCardTitle.displayName = "AppShellCard.Title";
193
- assignAppShellCardType(AppShellCardTitle, TITLE_TYPE);
194
- function AppShellCardSubtitle({ className, children, ...props }) {
195
- return /* @__PURE__ */ jsx("p", {
196
- "data-slot": "app-shell-card-subtitle",
197
- className: cn("text-sm leading-5 text-secondary-foreground", className),
198
- ...props,
199
- children
200
- });
201
- }
202
- AppShellCardSubtitle.displayName = "AppShellCard.Subtitle";
203
- function AppShellCardActions({ className, children, ...props }) {
449
+ AppShellSidebar.displayName = "AppShell.Sidebar";
450
+ function AppShellHeader({ className, children, ...props }) {
204
451
  return /* @__PURE__ */ jsx("div", {
205
- "data-slot": "app-shell-card-actions",
206
- className: cn("flex shrink-0 items-center gap-2", className),
452
+ "data-slot": "app-shell-header",
453
+ className: cn("shrink-0", className),
207
454
  ...props,
208
455
  children
209
456
  });
210
457
  }
211
- AppShellCardActions.displayName = "AppShellCard.Actions";
212
- assignAppShellCardType(AppShellCardActions, ACTIONS_TYPE);
213
- function AppShellCardMenu({ children }) {
214
- return children;
215
- }
216
- AppShellCardMenu.displayName = "AppShellCard.Menu";
217
- assignAppShellCardType(AppShellCardMenu, MENU_TYPE);
218
- var AppShellCard = Object.assign(AppShellCardRoot, {
219
- Toolbar: AppShellCardToolbar,
220
- Header: AppShellCardHeader,
221
- Title: AppShellCardTitle,
222
- Subtitle: AppShellCardSubtitle,
223
- Actions: AppShellCardActions,
224
- Menu: AppShellCardMenu
458
+ AppShellHeader.displayName = "AppShell.Header";
459
+ var appShellBackgrounds = {
460
+ transparent: "transparent",
461
+ appBg: DEFAULT_APP_SHELL_BACKGROUND,
462
+ neutral: "var(--muted)",
463
+ brandSubtle: "linear-gradient(135deg, var(--air-50) 0%, var(--air-100) 100%)",
464
+ brand: "linear-gradient(135deg, var(--air-400) 0%, var(--primary) 100%)",
465
+ brandDeep: "linear-gradient(135deg, var(--primary) 0%, var(--air-900) 100%)",
466
+ desertMidnight: "linear-gradient(135deg, var(--slate-500) 0%, var(--slate-700) 100%)",
467
+ aqua: "linear-gradient(135deg, var(--air-400) 0%, var(--air-600) 100%)"
468
+ };
469
+ var AppShell = Object.assign(AppShellRoot, {
470
+ Root: AppShellRoot,
471
+ Sidebar: AppShellSidebar,
472
+ Header: AppShellHeader,
473
+ Panel: AppShellPanel,
474
+ Content: AppShellContent
225
475
  });
226
476
  //#endregion
227
- export { AppShellCard, AppShellCardActions, AppShellCardHeader, AppShellCardMenu, AppShellCardRoot, AppShellCardSubtitle, AppShellCardTitle, AppShellCardToolbar };
477
+ export { AppShell, AppShellContent, AppShellHeader, AppShellPanel, AppShellRoot, AppShellSidebar, appShellBackgrounds };
228
478
 
229
479
  //# sourceMappingURL=index223.js.map