@harborclient/sdk 1.3.6 → 1.3.7

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 (39) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/components/Breadcrumb/SegmentShell.d.ts +2 -2
  3. package/dist/components/Breadcrumb/SegmentShell.d.ts.map +1 -1
  4. package/dist/components/Breadcrumb/SegmentShell.js +5 -5
  5. package/dist/components/Breadcrumb/index.d.ts +2 -2
  6. package/dist/components/Breadcrumb/index.d.ts.map +1 -1
  7. package/dist/components/Breadcrumb/index.js +3 -5
  8. package/dist/components/FloatingDialog/index.d.ts +0 -4
  9. package/dist/components/FloatingDialog/index.d.ts.map +1 -1
  10. package/dist/components/FloatingDialog/index.js +1 -5
  11. package/dist/components/FooterPanel/index.d.ts +6 -1
  12. package/dist/components/FooterPanel/index.d.ts.map +1 -1
  13. package/dist/components/FooterPanel/index.js +2 -2
  14. package/dist/components/Resizable/Resizable.d.ts +6 -1
  15. package/dist/components/Resizable/Resizable.d.ts.map +1 -1
  16. package/dist/components/Resizable/Resizable.js +2 -2
  17. package/dist/components/Sidebar/index.d.ts +9 -1
  18. package/dist/components/Sidebar/index.d.ts.map +1 -1
  19. package/dist/components/Sidebar/index.js +2 -2
  20. package/dist/components/SidebarRail/SidebarRailItem.d.ts +66 -0
  21. package/dist/components/SidebarRail/SidebarRailItem.d.ts.map +1 -0
  22. package/dist/components/SidebarRail/SidebarRailItem.js +59 -0
  23. package/dist/components/SidebarRail/SidebarRailSeparator.d.ts +11 -0
  24. package/dist/components/SidebarRail/SidebarRailSeparator.d.ts.map +1 -0
  25. package/dist/components/SidebarRail/SidebarRailSeparator.js +12 -0
  26. package/dist/components/SidebarRail/index.d.ts +49 -0
  27. package/dist/components/SidebarRail/index.d.ts.map +1 -0
  28. package/dist/components/SidebarRail/index.js +66 -0
  29. package/dist/components/TabBar/TabContextMenu.d.ts +5 -1
  30. package/dist/components/TabBar/TabContextMenu.d.ts.map +1 -1
  31. package/dist/components/TabBar/TabContextMenu.js +2 -2
  32. package/dist/components/classes.js +2 -2
  33. package/dist/components/index.d.ts +2 -0
  34. package/dist/components/index.d.ts.map +1 -1
  35. package/dist/components/index.js +1 -0
  36. package/dist/runtime/createBridgedPluginContext.js +58 -1
  37. package/dist/types.d.ts +143 -5
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 1.3.7 - 2026-07-29
8
+
9
+ - Implement workflow run history management and UI enhancements. (`c87feda3`)
10
+ - Enhance development and testing workflow in AGENTS.md and CONTRIBUTING.md. (`181dc04a`)
11
+ - Refactor styling in WorkflowRecordingDialog and TimelineBlock components. (`3f0b9348`)
12
+
7
13
  ## 1.3.6 - 2026-07-29
8
14
 
9
15
  - Enhance Response Editor and Summary with Close Functionality. (`e14d7c7d`)
@@ -50,8 +50,8 @@ interface Props {
50
50
  * Renders the arrow-shaped background shell shared by crumb and editable segments.
51
51
  *
52
52
  * First and only shapes use an overflow-hidden rounded wrapper so the left (or
53
- * full) edge can be pill-capped like the URL bar; middle and last keep a single
54
- * clip-path layer for chevron interlocking.
53
+ * full) edge matches the URL bar's `rounded-md` corners; middle and last keep a
54
+ * single clip-path layer for chevron interlocking.
55
55
  */
56
56
  export declare function SegmentShell({ shape, tone, grow, density, className, children }: Props): JSX.Element;
57
57
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentShell.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/SegmentShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM5C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhE;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAsBnD;;GAEG;AACH,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,YAAY,CAAC;IAEpB;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IAEnB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAa,EACb,IAAY,EACZ,OAAmB,EACnB,SAAS,EACT,QAAQ,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkErB"}
1
+ {"version":3,"file":"SegmentShell.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/SegmentShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAM5C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhE;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,CAAC;AAsBnD;;GAEG;AACH,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,YAAY,CAAC;IAEpB;;;OAGG;IACH,IAAI,CAAC,EAAE,WAAW,CAAC;IAEnB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IAEzB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAa,EACb,IAAY,EACZ,OAAmB,EACnB,SAAS,EACT,QAAQ,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA8DrB"}
@@ -25,8 +25,8 @@ function clipPathForShape(shape) {
25
25
  * Renders the arrow-shaped background shell shared by crumb and editable segments.
26
26
  *
27
27
  * First and only shapes use an overflow-hidden rounded wrapper so the left (or
28
- * full) edge can be pill-capped like the URL bar; middle and last keep a single
29
- * clip-path layer for chevron interlocking.
28
+ * full) edge matches the URL bar's `rounded-md` corners; middle and last keep a
29
+ * single clip-path layer for chevron interlocking.
30
30
  */
31
31
  export function SegmentShell({ shape, tone = 'path', grow = false, density = 'default', className, children }) {
32
32
  const hasChevron = shape !== 'only';
@@ -38,12 +38,12 @@ export function SegmentShell({ shape, tone = 'path', grow = false, density = 'de
38
38
  : tone === 'selection'
39
39
  ? 'bg-selection'
40
40
  : 'bg-breadcrumb-segment';
41
- const usesPillCap = shape === 'first' || shape === 'only';
41
+ const usesRoundedCap = shape === 'first' || shape === 'only';
42
42
  const leadingInsetPx = CHEVRON_PX + (isCompact ? 10 : 16);
43
43
  const layoutClass = cn('hc-breadcrumb-segment relative flex min-w-0 items-center', isCompact ? 'min-h-0 py-1' : 'min-h-[26px] py-2', grow ? 'min-w-[6rem] flex-1' : isCompact ? 'shrink-0' : 'max-w-[45%] shrink-0', hasChevron && shape !== 'last' && '-mr-[6px]', !needsLeadingInset && (isCompact ? 'pl-2.5' : 'pl-5'), isCompact ? 'pr-3' : 'pr-5', className);
44
44
  const content = (_jsx("div", { className: cn('relative min-w-0', isCompact ? 'flex items-center gap-1.5' : 'w-full truncate'), children: children }));
45
- if (usesPillCap) {
46
- return (_jsxs("div", { className: cn(layoutClass, 'overflow-hidden', shape === 'only' ? 'rounded-full!' : 'rounded-lg!'), style: needsLeadingInset ? { paddingLeft: `${leadingInsetPx}px` } : undefined, children: [_jsx("div", { "aria-hidden": true, className: cn('pointer-events-none absolute inset-0', toneClass), style: clipPath !== 'none' ? { clipPath } : undefined }), content] }));
45
+ if (usesRoundedCap) {
46
+ return (_jsxs("div", { className: cn(layoutClass, 'overflow-hidden', 'rounded-md!'), style: needsLeadingInset ? { paddingLeft: `${leadingInsetPx}px` } : undefined, children: [_jsx("div", { "aria-hidden": true, className: cn('pointer-events-none absolute inset-0', toneClass), style: clipPath !== 'none' ? { clipPath } : undefined }), content] }));
47
47
  }
48
48
  return (_jsx("div", { className: cn(layoutClass, toneClass), style: {
49
49
  ...(clipPath !== 'none' ? { clipPath } : {}),
@@ -35,8 +35,8 @@ interface Props {
35
35
  /**
36
36
  * Full-width breadcrumb bar with interlocking arrow-shaped segments. Leading
37
37
  * segments are optionally clickable; the trailing segment is inline-editable.
38
- * The track background is clipped to the segments' pill silhouette so the
39
- * rounded caps read against the surrounding surface instead of a square band.
38
+ * The track background is clipped to the segments' silhouette so the
39
+ * `rounded-md` ends read against the surrounding surface instead of a square band.
40
40
  */
41
41
  export declare function Breadcrumb({ segments, value, placeholder, editableLabel, onValueChange, className, flush }: Props): JSX.Element;
42
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAsC,MAAM,OAAO,CAAC;AAKrE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAE9B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,WAAgB,EAChB,aAAsB,EACtB,aAAa,EACb,SAAS,EACT,KAAa,EACd,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgErB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Breadcrumb/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAsC,MAAM,OAAO,CAAC;AAKrE,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD,UAAU,KAAK;IACb;;OAEG;IACH,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAE9B;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,KAAK,EACL,WAAgB,EAChB,aAAsB,EACtB,aAAa,EACb,SAAS,EACT,KAAa,EACd,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA2DrB"}
@@ -6,8 +6,8 @@ import { EditableSegment } from './EditableSegment.js';
6
6
  /**
7
7
  * Full-width breadcrumb bar with interlocking arrow-shaped segments. Leading
8
8
  * segments are optionally clickable; the trailing segment is inline-editable.
9
- * The track background is clipped to the segments' pill silhouette so the
10
- * rounded caps read against the surrounding surface instead of a square band.
9
+ * The track background is clipped to the segments' silhouette so the
10
+ * `rounded-md` ends read against the surrounding surface instead of a square band.
11
11
  */
12
12
  export function Breadcrumb({ segments, value, placeholder = '', editableLabel = 'Name', onValueChange, className, flush = false }) {
13
13
  const [editing, setEditing] = useState(false);
@@ -36,7 +36,5 @@ export function Breadcrumb({ segments, value, placeholder = '', editableLabel =
36
36
  return 'middle';
37
37
  };
38
38
  const editableShape = segments.length === 0 ? 'only' : 'last';
39
- return (_jsxs("nav", { id: navId, "aria-label": "Breadcrumb", className: cn('hc-breadcrumb flex min-w-0 items-stretch bg-breadcrumb-background', flush
40
- ? '-mx-3 -mt-3 w-[calc(100%+1.5rem)]'
41
- : cn('w-full overflow-hidden', editableShape === 'only' ? 'rounded-full' : 'rounded-l-full'), className), children: [segments.map((segment, index) => (_jsx(CrumbSegment, { segment: segment, shape: leadingShape(index) }, segment.id ?? `${segment.label}-${index}`))), _jsx(EditableSegment, { value: value, placeholder: placeholder, editableLabel: editableLabel, editing: editing, shape: editableShape, inputRef: inputRef, onStartEditing: () => setEditing(true), onStopEditing: () => setEditing(false), onValueChange: onValueChange })] }));
39
+ return (_jsxs("nav", { id: navId, "aria-label": "Breadcrumb", className: cn('hc-breadcrumb flex min-w-0 items-stretch bg-breadcrumb-background', flush ? '-mx-3 -mt-3 w-[calc(100%+1.5rem)]' : 'w-full overflow-hidden rounded-md', className), children: [segments.map((segment, index) => (_jsx(CrumbSegment, { segment: segment, shape: leadingShape(index) }, segment.id ?? `${segment.label}-${index}`))), _jsx(EditableSegment, { value: value, placeholder: placeholder, editableLabel: editableLabel, editing: editing, shape: editableShape, inputRef: inputRef, onStartEditing: () => setEditing(true), onStopEditing: () => setEditing(false), onValueChange: onValueChange })] }));
42
40
  }
@@ -87,10 +87,6 @@ interface Props {
87
87
  * `onPositionChange` / `onSizeChange`. If the panel would open or remain
88
88
  * off-screen after a window resize, it relocates to the default corner.
89
89
  *
90
- * Uses the elevated `bg-control` fill (not `bg-surface`) with a stronger border
91
- * and theme-aware shadow so the panel stays readable against the app chrome in
92
- * both light and dark themes.
93
- *
94
90
  * @param props - Dialog labelling, geometry, and content props.
95
91
  * @returns Floating dialog element.
96
92
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FloatingDialog/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAqD,SAAS,EAAE,MAAM,OAAO,CAAC;AAE/F,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EAExB,MAAM,6BAA6B,CAAC;AAErC,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAE9D;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAElD;;OAEG;IACH,UAAU,EAAE,SAAS,CAAC;IAEtB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAuCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,UAAU,EACV,OAAO,EACP,aAAqB,EACrB,SAAS,EACT,aAAa,EACb,WAA0C,EAC1C,UAAwC,EACxC,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAc,EACd,SAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,QAAQ,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA+VrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FloatingDialog/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAqD,SAAS,EAAE,MAAM,OAAO,CAAC;AAE/F,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EAExB,MAAM,6BAA6B,CAAC;AAErC,UAAU,KAAK;IACb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAE9D;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAElD;;OAEG;IACH,UAAU,EAAE,SAAS,CAAC;IAEtB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAuCD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,UAAU,EACV,OAAO,EACP,aAAqB,EACrB,SAAS,EACT,aAAa,EACb,WAA0C,EAC1C,UAAwC,EACxC,gBAAgB,EAChB,YAAY,EACZ,aAAa,EACb,QAAc,EACd,SAAe,EACf,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,UAAU,EACV,QAAQ,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA+VrB"}
@@ -37,10 +37,6 @@ function clampFloatingDialogSize(width, height, left, top, minWidth, minHeight,
37
37
  * `onPositionChange` / `onSizeChange`. If the panel would open or remain
38
38
  * off-screen after a window resize, it relocates to the default corner.
39
39
  *
40
- * Uses the elevated `bg-control` fill (not `bg-surface`) with a stronger border
41
- * and theme-aware shadow so the panel stays readable against the app chrome in
42
- * both light and dark themes.
43
- *
44
40
  * @param props - Dialog labelling, geometry, and content props.
45
41
  * @returns Floating dialog element.
46
42
  */
@@ -271,7 +267,7 @@ export function FloatingDialog({ label, labelledBy, onClose, disableEscape = fal
271
267
  setSize(next);
272
268
  onSizeChangeRef.current?.(next);
273
269
  }, [maxHeight, maxWidth, minHeight, minWidth, size]);
274
- return (_jsxs("div", { ref: panelRef, role: "dialog", "aria-modal": "false", "aria-label": labelledBy ? undefined : label, "aria-labelledby": labelledBy, className: cn('hc-floating-dialog fixed z-[60] flex min-w-[240px] flex-col overflow-hidden rounded-lg border border-text/15 bg-control shadow-[0_8px_28px_rgba(0,0,0,0.18)] dark:shadow-[0_12px_36px_rgba(0,0,0,0.55)]', className), style: {
270
+ return (_jsxs("div", { ref: panelRef, role: "dialog", "aria-modal": "false", "aria-label": labelledBy ? undefined : label, "aria-labelledby": labelledBy, className: cn('hc-floating-dialog fixed z-[60] flex min-w-[240px] flex-col overflow-hidden rounded-lg border border-separator bg-surface shadow-xl', className), style: {
275
271
  left: position.left,
276
272
  top: position.top,
277
273
  ...(size != null ? { width: size.width, height: size.height } : {})
@@ -41,10 +41,15 @@ interface Props {
41
41
  * When true, does not render children while the panel is closed.
42
42
  */
43
43
  unmountWhenClosed?: boolean;
44
+ /**
45
+ * Id of a visible heading that names this panel region. When set, forwarded
46
+ * to {@link Resizable} as `aria-labelledby`.
47
+ */
48
+ labelledBy?: string;
44
49
  }
45
50
  /**
46
51
  * Resizable panel that slides up from the footer.
47
52
  */
48
- export declare function FooterPanel({ id, title, badge, description, closeLabel, storageKey, buttons, open, onClose, children, unmountWhenClosed }: Props): JSX.Element;
53
+ export declare function FooterPanel({ id, title, badge, description, closeLabel, storageKey, buttons, open, onClose, children, unmountWhenClosed, labelledBy }: Props): JSX.Element;
49
54
  export {};
50
55
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FooterPanel/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAIxC,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IAE5B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EACL,KAAK,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,iBAAyB,EAC1B,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAuCrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FooterPanel/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,KAAK,GAAG,EAAE,MAAM,OAAO,CAAC;AAIxC,UAAU,KAAK;IACb,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAExB;;OAEG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAExB;;OAEG;IACH,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAE9B;;OAEG;IACH,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IAE5B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAE1B;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAC1B,EAAE,EACF,KAAK,EACL,KAAK,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,OAAO,EACP,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,iBAAyB,EACzB,UAAU,EACX,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAwCrB"}
@@ -5,7 +5,7 @@ import { RoundButton } from '../RoundButton/index.js';
5
5
  /**
6
6
  * Resizable panel that slides up from the footer.
7
7
  */
8
- export function FooterPanel({ id, title, badge, description, closeLabel, storageKey, buttons, open, onClose, children, unmountWhenClosed = false }) {
8
+ export function FooterPanel({ id, title, badge, description, closeLabel, storageKey, buttons, open, onClose, children, unmountWhenClosed = false, labelledBy }) {
9
9
  const closeButton = (_jsx(RoundButton, { icon: faXmark, title: "Close", ariaLabel: `Close ${closeLabel}`, onClick: onClose, className: "hc-footer-panel-close" }));
10
- return (_jsxs(Resizable, { id: id, open: open, onClose: onClose, closeLabel: closeLabel, storageKey: storageKey, unmountWhenClosed: unmountWhenClosed, showCloseButton: false, headerless: true, children: [_jsxs("div", { className: "hc-footer-panel flex shrink-0 items-center justify-between border-b border-separator px-3 py-2", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2 font-medium text-text", children: [title, badge && _jsx("span", { className: "hc-footer-panel-badge font-normal text-muted", children: badge })] }), description && _jsx("span", { className: "truncate text-muted", children: description })] }), _jsxs("div", { className: "flex gap-2", children: [buttons, closeButton] })] }), _jsx("div", { className: "hc-footer-panel-body min-h-0 flex-1 overflow-auto", children: children })] }));
10
+ return (_jsxs(Resizable, { id: id, open: open, onClose: onClose, closeLabel: closeLabel, storageKey: storageKey, unmountWhenClosed: unmountWhenClosed, labelledBy: labelledBy, showCloseButton: false, headerless: true, children: [_jsxs("div", { className: "hc-footer-panel flex shrink-0 items-center justify-between border-b border-separator px-3 py-2", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2 font-medium text-text", children: [title, badge && _jsx("span", { className: "hc-footer-panel-badge font-normal text-muted", children: badge })] }), description && _jsx("span", { className: "truncate text-muted", children: description })] }), _jsxs("div", { className: "flex gap-2", children: [buttons, closeButton] })] }), _jsx("div", { className: "hc-footer-panel-body min-h-0 flex-1 overflow-auto", children: children })] }));
11
11
  }
@@ -36,6 +36,11 @@ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'id'
36
36
  * Whether or not to show the close button.
37
37
  */
38
38
  showCloseButton?: boolean;
39
+ /**
40
+ * Id of a visible heading that names this panel region. When set, used as
41
+ * `aria-labelledby` instead of the default `aria-label`.
42
+ */
43
+ labelledBy?: string;
39
44
  /**
40
45
  * Panel body content.
41
46
  */
@@ -47,6 +52,6 @@ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'id'
47
52
  * Encapsulates resize handle wiring, height persistence, open/close animation,
48
53
  * and close affordance shared by Console, Variables, and plugin footer panels.
49
54
  */
50
- export declare function Resizable({ id, open, onClose, closeLabel, storageKey, title, headerless, unmountWhenClosed, showCloseButton, children, className, ...props }: Props): JSX.Element;
55
+ export declare function Resizable({ id, open, onClose, closeLabel, storageKey, title, headerless, unmountWhenClosed, showCloseButton, labelledBy, children, className, ...props }: Props): JSX.Element;
51
56
  export {};
52
57
  //# sourceMappingURL=Resizable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Resizable.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/Resizable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYtE,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC;IACxF;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,IAAI,EACJ,OAAO,EACP,UAAU,EACV,UAAU,EACV,KAAK,EACL,UAAkB,EAClB,iBAAyB,EACzB,eAAsB,EACtB,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAgFrB"}
1
+ {"version":3,"file":"Resizable.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/Resizable.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYtE,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI,GAAG,OAAO,CAAC;IACxF;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC;IAEd;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EACxB,EAAE,EACF,IAAI,EACJ,OAAO,EACP,UAAU,EACV,UAAU,EACV,KAAK,EACL,UAAkB,EAClB,iBAAyB,EACzB,eAAsB,EACtB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAiFrB"}
@@ -12,7 +12,7 @@ import { useResizable } from './useResizable.js';
12
12
  * Encapsulates resize handle wiring, height persistence, open/close animation,
13
13
  * and close affordance shared by Console, Variables, and plugin footer panels.
14
14
  */
15
- export function Resizable({ id, open, onClose, closeLabel, storageKey, title, headerless = false, unmountWhenClosed = false, showCloseButton = true, children, className, ...props }) {
15
+ export function Resizable({ id, open, onClose, closeLabel, storageKey, title, headerless = false, unmountWhenClosed = false, showCloseButton = true, labelledBy, children, className, ...props }) {
16
16
  const containerRef = useRef(null);
17
17
  /**
18
18
  * Keeps max-size measurement stable across re-renders so useResizable
@@ -29,5 +29,5 @@ export function Resizable({ id, open, onClose, closeLabel, storageKey, title, he
29
29
  });
30
30
  const closeButton = (_jsx(RoundButton, { icon: faXmark, ariaLabel: `Close ${closeLabel}`, onClick: onClose, className: "hc-resizable-close" }));
31
31
  const body = unmountWhenClosed && !open ? null : children;
32
- return (_jsxs("div", { ref: containerRef, ...props, id: id, className: cn('hc-resizable', footerPanelClassName(open), className), style: { height }, role: "region", "aria-label": `${closeLabel} panel`, "aria-hidden": !open, inert: !open || undefined, children: [_jsx(ResizeHandle, { orientation: "horizontal", value: height, min: panelMinSize, max: panelMaxSize, onResizeStart: onResizeStart, onKeyboardResize: onKeyboardResize, ariaLabel: `Resize ${closeLabel} panel` }), headerless ? (_jsxs("div", { className: "hc-resizable-headerless relative flex min-h-0 flex-1 flex-col overflow-hidden", children: [showCloseButton && (_jsx(RoundButton, { icon: faXmark, ariaLabel: `Close ${closeLabel}`, onClick: onClose, className: "hc-resizable-headerless-close absolute top-2 right-2 z-10" })), _jsx("div", { className: "hc-resizable-body flex min-h-0 flex-1 flex-col", children: body })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "hc-resizable-header flex shrink-0 items-center justify-between border-b border-separator px-3 py-2", children: [_jsx("div", { className: "hc-resizable-header-title min-w-0 flex-1", children: title }), showCloseButton && closeButton] }), body] }))] }));
32
+ return (_jsxs("div", { ref: containerRef, ...props, id: id, className: cn('hc-resizable', footerPanelClassName(open), className), style: { height }, role: "region", "aria-labelledby": labelledBy, "aria-label": labelledBy == null ? `${closeLabel} panel` : undefined, "aria-hidden": !open, inert: !open || undefined, children: [_jsx(ResizeHandle, { orientation: "horizontal", value: height, min: panelMinSize, max: panelMaxSize, onResizeStart: onResizeStart, onKeyboardResize: onKeyboardResize, ariaLabel: `Resize ${closeLabel} panel` }), headerless ? (_jsxs("div", { className: "hc-resizable-headerless relative flex min-h-0 flex-1 flex-col overflow-hidden", children: [showCloseButton && (_jsx(RoundButton, { icon: faXmark, ariaLabel: `Close ${closeLabel}`, onClick: onClose, className: "hc-resizable-headerless-close absolute top-2 right-2 z-10" })), _jsx("div", { className: "hc-resizable-body flex min-h-0 flex-1 flex-col", children: body })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "hc-resizable-header flex shrink-0 items-center justify-between border-b border-separator px-3 py-2", children: [_jsx("div", { className: "hc-resizable-header-title min-w-0 flex-1", children: title }), showCloseButton && closeButton] }), body] }))] }));
33
33
  }
@@ -36,6 +36,14 @@ interface Props {
36
36
  * Additional classes for the scrollable body wrapper.
37
37
  */
38
38
  bodyClassName?: string;
39
+ /**
40
+ * Optional id for the body wrapper (e.g. rail `aria-controls` target).
41
+ */
42
+ bodyId?: string;
43
+ /**
44
+ * Optional ARIA role for the body wrapper (e.g. `tabpanel` with a rail tablist).
45
+ */
46
+ bodyRole?: string;
39
47
  /**
40
48
  * Additional classes for the resizable aside element.
41
49
  */
@@ -70,6 +78,6 @@ interface Props {
70
78
  *
71
79
  * Left sidebars render `[aside][handle]`; right sidebars render `[handle][aside]`.
72
80
  */
73
- export declare function Sidebar({ side, ariaLabel, header, children, scroll, scrollAxis, scrollbarAutoHide, bodyClassName, asideClassName, resizeHandleClassName, resizeAriaLabel, defaultSize, minSize, getMaxSize, storageKey }: Props): JSX.Element;
81
+ export declare function Sidebar({ side, ariaLabel, header, children, scroll, scrollAxis, scrollbarAutoHide, bodyClassName, bodyId, bodyRole, asideClassName, resizeHandleClassName, resizeAriaLabel, defaultSize, minSize, getMaxSize, storageKey }: Props): JSX.Element;
74
82
  export {};
75
83
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Sidebar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKjD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,UAAU,KAAK;IACb;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAEhD;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAE1B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,QAAQ,EACR,MAAa,EACb,UAAuB,EACvB,iBAAwB,EACxB,aAAa,EACb,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACX,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAkFrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Sidebar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKjD;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3C,UAAU,KAAK;IACb;;OAEG;IACH,IAAI,EAAE,WAAW,CAAC;IAElB;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAC;IAEpB;;OAEG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,MAAM,CAAC;IAEhD;;OAEG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAE/B;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IAE1B;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,EACtB,IAAI,EACJ,SAAS,EACT,MAAM,EACN,QAAQ,EACR,MAAa,EACb,UAAuB,EACvB,iBAAwB,EACxB,aAAa,EACb,MAAM,EACN,QAAQ,EACR,cAAc,EACd,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACX,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAsFrB"}
@@ -7,7 +7,7 @@ import { cn } from '../utils.js';
7
7
  *
8
8
  * Left sidebars render `[aside][handle]`; right sidebars render `[handle][aside]`.
9
9
  */
10
- export function Sidebar({ side, ariaLabel, header, children, scroll = true, scrollAxis = 'vertical', scrollbarAutoHide = true, bodyClassName, asideClassName, resizeHandleClassName, resizeAriaLabel, defaultSize, minSize, getMaxSize, storageKey }) {
10
+ export function Sidebar({ side, ariaLabel, header, children, scroll = true, scrollAxis = 'vertical', scrollbarAutoHide = true, bodyClassName, bodyId, bodyRole, asideClassName, resizeHandleClassName, resizeAriaLabel, defaultSize, minSize, getMaxSize, storageKey }) {
11
11
  const resizableOptions = {
12
12
  axis: 'x',
13
13
  direction: side === 'left' ? 1 : -1,
@@ -23,7 +23,7 @@ export function Sidebar({ side, ariaLabel, header, children, scroll = true, scro
23
23
  * scroll viewport height while still allowing overflow scroll when content grows.
24
24
  */
25
25
  const scrollBody = _jsx("div", { className: "flex min-h-full min-w-0 flex-col", children: children });
26
- const body = scroll ? (_jsx(Scrollbars, { axis: scrollAxis, autoHide: scrollbarAutoHide, className: cn('min-h-0 flex-1', bodyClassName), children: scrollBody })) : (_jsx("div", { className: cn('flex min-h-0 flex-1 flex-col', bodyClassName), children: children }));
26
+ const body = scroll ? (_jsx(Scrollbars, { id: bodyId, role: bodyRole, axis: scrollAxis, autoHide: scrollbarAutoHide, className: cn('min-h-0 flex-1', bodyClassName), children: scrollBody })) : (_jsx("div", { id: bodyId, role: bodyRole, className: cn('flex min-h-0 flex-1 flex-col', bodyClassName), children: children }));
27
27
  const aside = (_jsxs("aside", { className: cn('hc-sidebar flex shrink-0 flex-col overflow-x-hidden bg-sidebar', side === 'right' && 'h-full min-h-0', asideClassName), style: { width }, "aria-label": ariaLabel, children: [header, body] }));
28
28
  if (side === 'left') {
29
29
  return (_jsxs(_Fragment, { children: [aside, handle] }));
@@ -0,0 +1,66 @@
1
+ import type { IconDefinition } from '@fortawesome/fontawesome-svg-core';
2
+ import type { JSX, KeyboardEvent, Ref } from 'react';
3
+ /**
4
+ * One entry in a {@link SidebarRail} navigation list.
5
+ */
6
+ export interface SidebarRailItemData {
7
+ /**
8
+ * Stable identifier passed to `onSelect` when the item is activated.
9
+ */
10
+ id: string;
11
+ /**
12
+ * Font Awesome icon shown for this rail item.
13
+ */
14
+ icon: IconDefinition;
15
+ /**
16
+ * Accessible name; also shown as visible text when the rail is expanded.
17
+ */
18
+ label: string;
19
+ /**
20
+ * When true, shows a small notification badge on the icon.
21
+ */
22
+ badge?: boolean;
23
+ }
24
+ interface Props {
25
+ /**
26
+ * Declarative rail item to render.
27
+ */
28
+ item: SidebarRailItemData;
29
+ /**
30
+ * Whether this item is the active selection.
31
+ */
32
+ active: boolean;
33
+ /**
34
+ * Whether the rail shows labels beside icons.
35
+ */
36
+ expanded: boolean;
37
+ /**
38
+ * Roving tabindex value: `0` for the selected tab, `-1` for others.
39
+ */
40
+ tabIndex: number;
41
+ /**
42
+ * Optional id of the sidebar panel this tab controls.
43
+ */
44
+ panelId?: string;
45
+ /**
46
+ * Called when the user activates this item.
47
+ */
48
+ onSelect: () => void;
49
+ /**
50
+ * Keyboard handler for tablist arrow-key navigation.
51
+ */
52
+ onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => void;
53
+ /**
54
+ * Ref attached to the item button for focus management.
55
+ */
56
+ buttonRef?: Ref<HTMLButtonElement>;
57
+ }
58
+ /**
59
+ * Single rail navigation tab: full-width active chrome with an icon button.
60
+ *
61
+ * @param props - Item identity, active/expanded chrome, and activation handlers.
62
+ * @returns Rail section with decorative icon and optional badge.
63
+ */
64
+ export declare function SidebarRailItem({ item, active, expanded, tabIndex, panelId, onSelect, onKeyDown, buttonRef }: Props): JSX.Element;
65
+ export {};
66
+ //# sourceMappingURL=SidebarRailItem.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarRailItem.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarRail/SidebarRailItem.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAUrD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,cAAc,CAAC;IAErB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,UAAU,KAAK;IACb;;OAEG;IACH,IAAI,EAAE,mBAAmB,CAAC;IAE1B;;OAEG;IACH,MAAM,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,QAAQ,EAAE,MAAM,IAAI,CAAC;IAErB;;OAEG;IACH,SAAS,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,iBAAiB,CAAC,KAAK,IAAI,CAAC;IAE7D;;OAEG;IACH,SAAS,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,CAAC;CACpC;AAiDD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,SAAS,EACT,SAAS,EACV,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CA8CrB"}
@@ -0,0 +1,59 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { FaIcon } from '../FaIcon/index.js';
3
+ import { cn } from '../utils.js';
4
+ /**
5
+ * Shared focus-visible outline for rail tabs (matches TabBar / segment chrome).
6
+ */
7
+ const railItemFocusVisible = 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-accent';
8
+ /**
9
+ * Builds the accessible name for a rail tab, including badge status when present.
10
+ *
11
+ * @param label - Visible item label.
12
+ * @param badge - Whether the item shows a notification badge.
13
+ * @returns Accessible name string for `aria-label` or visually hidden text.
14
+ */
15
+ function railItemAccessibleName(label, badge) {
16
+ return badge === true ? `${label}, notification` : label;
17
+ }
18
+ /**
19
+ * Tailwind classes for the full-width rail section chrome.
20
+ *
21
+ * Active/hover fill the entire section between separators — not an inset
22
+ * pill around the control.
23
+ *
24
+ * @param active - Whether this item is the current selection.
25
+ * @returns Class string for the section wrapper.
26
+ */
27
+ function railItemSectionClasses(active) {
28
+ return cn('hc-sidebar-rail-item-section w-full shrink-0 text-sidebar-rail-text', active ? 'bg-sidebar-rail-active' : 'bg-transparent');
29
+ }
30
+ /**
31
+ * Tailwind classes for the interactive control inside a rail section.
32
+ *
33
+ * Kept visually flat so selection chrome lives on the section, not the button.
34
+ * Focus outline always applies (including when active) so keyboard users can
35
+ * see focus on the current mode.
36
+ *
37
+ * @param active - Whether this item is the current selection.
38
+ * @param expanded - Whether the rail shows labels.
39
+ * @returns Class string for the item button.
40
+ */
41
+ function railItemButtonClasses(active, expanded) {
42
+ return cn('hc-sidebar-rail-item app-no-drag relative inline-flex min-h-12 w-full shrink-0 cursor-pointer items-center rounded-none border-none bg-transparent py-5', expanded ? 'gap-2 px-3' : 'justify-center', !active && 'hover:bg-sidebar-rail-active', railItemFocusVisible);
43
+ }
44
+ /**
45
+ * Single rail navigation tab: full-width active chrome with an icon button.
46
+ *
47
+ * @param props - Item identity, active/expanded chrome, and activation handlers.
48
+ * @returns Rail section with decorative icon and optional badge.
49
+ */
50
+ export function SidebarRailItem({ item, active, expanded, tabIndex, panelId, onSelect, onKeyDown, buttonRef }) {
51
+ const accessibleName = railItemAccessibleName(item.label, item.badge);
52
+ /**
53
+ * Icon-only (collapsed) uses aria-label. Expanded uses visible text (plus
54
+ * optional visually hidden badge status) as the accessible name so AT is not
55
+ * left with a color-only cue and is not announced twice via aria-label.
56
+ */
57
+ const ariaLabel = expanded ? undefined : accessibleName;
58
+ return (_jsx("div", { className: railItemSectionClasses(active), children: _jsxs("button", { type: "button", role: "tab", ref: buttonRef, className: railItemButtonClasses(active, expanded), title: item.label, tabIndex: tabIndex, "aria-label": ariaLabel, "aria-selected": active, "aria-controls": panelId, onClick: onSelect, onKeyDown: onKeyDown, children: [_jsxs("span", { className: "relative inline-flex shrink-0 items-center justify-center", children: [_jsx(FaIcon, { icon: item.icon, className: "hc-sidebar-rail-item-icon h-[22.5px]! w-[22.5px]!", "aria-hidden": true }), item.badge ? (_jsx("span", { className: "hc-sidebar-rail-item-badge absolute -top-0.5 -right-0.5 h-2 w-2 rounded-full bg-accent", "aria-hidden": true })) : null] }), expanded ? (_jsx("span", { className: "hc-sidebar-rail-item-label min-w-0 truncate text-left", children: item.label })) : null, expanded && item.badge === true ? _jsx("span", { className: "sr-only", children: ", notification" }) : null] }) }));
59
+ }
@@ -0,0 +1,11 @@
1
+ import type { JSX } from 'react';
2
+ /**
3
+ * Horizontal hairline divider between {@link SidebarRail} navigation items.
4
+ *
5
+ * Spans the full rail width (no horizontal inset) so separators read as
6
+ * section boundaries. Uses `sidebar-rail-separator`, a soft mix of rail fill
7
+ * and rail text so dividers stay close to the background in every theme.
8
+ * Decorative only — hidden from the accessibility tree so focus stays on tabs.
9
+ */
10
+ export declare function SidebarRailSeparator(): JSX.Element;
11
+ //# sourceMappingURL=SidebarRailSeparator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SidebarRailSeparator.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarRail/SidebarRailSeparator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAEjC;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,IAAI,GAAG,CAAC,OAAO,CAOlD"}
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx } from "@harborclient/sdk/jsx-runtime";
2
+ /**
3
+ * Horizontal hairline divider between {@link SidebarRail} navigation items.
4
+ *
5
+ * Spans the full rail width (no horizontal inset) so separators read as
6
+ * section boundaries. Uses `sidebar-rail-separator`, a soft mix of rail fill
7
+ * and rail text so dividers stay close to the background in every theme.
8
+ * Decorative only — hidden from the accessibility tree so focus stays on tabs.
9
+ */
10
+ export function SidebarRailSeparator() {
11
+ return (_jsx("div", { className: "hc-sidebar-rail-separator h-px w-full shrink-0 bg-sidebar-rail-separator", "aria-hidden": true }));
12
+ }
@@ -0,0 +1,49 @@
1
+ import { type ComponentPropsWithoutRef, type JSX } from 'react';
2
+ import { type SidebarRailItemData } from './SidebarRailItem.js';
3
+ export type { SidebarRailItemData };
4
+ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'aria-label' | 'onSelect'> {
5
+ /**
6
+ * Navigation entries rendered top-to-bottom in the rail.
7
+ */
8
+ items: SidebarRailItemData[];
9
+ /**
10
+ * Id of the currently selected rail item.
11
+ */
12
+ activeId: string;
13
+ /**
14
+ * Called when the user selects a different rail item.
15
+ *
16
+ * @param id - Selected item id from {@link SidebarRailItemData.id}.
17
+ */
18
+ onSelect: (id: string) => void;
19
+ /**
20
+ * When true, shows labels beside icons and uses the expanded width.
21
+ */
22
+ expanded: boolean;
23
+ /**
24
+ * Called when the user toggles the rail between collapsed and expanded.
25
+ *
26
+ * @param expanded - Next expanded state.
27
+ */
28
+ onExpandedChange: (expanded: boolean) => void;
29
+ /**
30
+ * Accessible name for the vertical tablist of sidebar modes.
31
+ */
32
+ ariaLabel?: string;
33
+ /**
34
+ * Id of the sidebar panel controlled by each rail tab (`aria-controls`).
35
+ */
36
+ panelId?: string;
37
+ }
38
+ /**
39
+ * Vertical activity rail for switching sidebar modes.
40
+ *
41
+ * Collapsed shows icons only; expanded shows icons with labels. Each item is a
42
+ * full-width tab section with an edge-to-edge separator after it (including the
43
+ * last item, so the list has a bottom border before the footer); active chrome
44
+ * uses the sidebar-rail-active token. Items form a vertical tablist with
45
+ * roving tabindex; Arrow keys move focus and selection; Home/End jump to the
46
+ * first/last item. Expand/collapse sits outside the tablist as its own Tab stop.
47
+ */
48
+ export declare function SidebarRail({ items, activeId, onSelect, expanded, onExpandedChange, ariaLabel, panelId, className, ...props }: Props): JSX.Element;
49
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SidebarRail/index.tsx"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,GAAG,EAIT,MAAM,OAAO,CAAC;AAGf,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAGjF,YAAY,EAAE,mBAAmB,EAAE,CAAC;AAQpC,UAAU,KAAM,SAAQ,IAAI,CAC1B,wBAAwB,CAAC,KAAK,CAAC,EAC/B,UAAU,GAAG,YAAY,GAAG,UAAU,CACvC;IACC;;OAEG;IACH,KAAK,EAAE,mBAAmB,EAAE,CAAC;IAE7B;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAE/B;;OAEG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IAE9C;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,EACR,gBAAgB,EAChB,SAA2B,EAC3B,OAAO,EACP,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAyGrB"}
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { faAnglesLeft, faAnglesRight } from '@fortawesome/free-solid-svg-icons';
3
+ import { useCallback, useRef } from 'react';
4
+ import { FaIcon } from '../FaIcon/index.js';
5
+ import { cn, resolveTabListKeyAction } from '../utils.js';
6
+ import { SidebarRailItem } from './SidebarRailItem.js';
7
+ import { SidebarRailSeparator } from './SidebarRailSeparator.js';
8
+ /**
9
+ * Shared focus-visible outline for the expand/collapse control.
10
+ */
11
+ const railExpandFocusVisible = 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-[-2px] focus-visible:outline-accent';
12
+ /**
13
+ * Vertical activity rail for switching sidebar modes.
14
+ *
15
+ * Collapsed shows icons only; expanded shows icons with labels. Each item is a
16
+ * full-width tab section with an edge-to-edge separator after it (including the
17
+ * last item, so the list has a bottom border before the footer); active chrome
18
+ * uses the sidebar-rail-active token. Items form a vertical tablist with
19
+ * roving tabindex; Arrow keys move focus and selection; Home/End jump to the
20
+ * first/last item. Expand/collapse sits outside the tablist as its own Tab stop.
21
+ */
22
+ export function SidebarRail({ items, activeId, onSelect, expanded, onExpandedChange, ariaLabel = 'Sidebar modes', panelId, className, ...props }) {
23
+ const itemRefs = useRef([]);
24
+ /**
25
+ * Focuses the item button at the given index when it exists.
26
+ *
27
+ * @param index - Zero-based item index to focus.
28
+ */
29
+ const focusItemAt = useCallback((index) => {
30
+ const clamped = Math.max(0, Math.min(index, itemRefs.current.length - 1));
31
+ itemRefs.current[clamped]?.focus();
32
+ }, []);
33
+ /**
34
+ * Handles tablist keyboard navigation: arrows/Home/End move focus and select.
35
+ *
36
+ * @param event - Keyboard event from the focused item.
37
+ * @param index - Index of the item that received the event.
38
+ */
39
+ const handleItemKeyDown = useCallback((event, index) => {
40
+ const nextIndex = resolveTabListKeyAction(event.key, index, items.length);
41
+ if (nextIndex === null) {
42
+ return;
43
+ }
44
+ event.preventDefault();
45
+ const nextItem = items[nextIndex];
46
+ if (nextItem == null) {
47
+ return;
48
+ }
49
+ onSelect(nextItem.id);
50
+ focusItemAt(nextIndex);
51
+ }, [focusItemAt, items, onSelect]);
52
+ /**
53
+ * Toggles the rail between collapsed and expanded density.
54
+ */
55
+ const handleToggleExpanded = useCallback(() => {
56
+ onExpandedChange(!expanded);
57
+ }, [expanded, onExpandedChange]);
58
+ const expandLabel = expanded ? 'Collapse' : 'Expand';
59
+ const expandAriaLabel = expanded ? 'Collapse sidebar rail' : 'Expand sidebar rail';
60
+ return (_jsxs("div", { ...props, className: cn('hc-sidebar-rail app-no-drag flex h-full shrink-0 flex-col bg-sidebar-rail text-sidebar-rail-text', expanded ? 'w-[168px]' : 'w-18', 'transition-[width] duration-200 ease-out motion-reduce:transition-none', className), children: [_jsx("div", { role: "tablist", "aria-orientation": "vertical", "aria-label": ariaLabel, className: "hc-sidebar-rail-items flex min-h-0 flex-1 flex-col items-stretch overflow-x-hidden overflow-y-auto", children: items.flatMap((item, index) => [
61
+ _jsx(SidebarRailItem, { item: item, active: item.id === activeId, expanded: expanded, tabIndex: item.id === activeId ? 0 : -1, panelId: panelId, onSelect: () => onSelect(item.id), onKeyDown: (event) => handleItemKeyDown(event, index), buttonRef: (node) => {
62
+ itemRefs.current[index] = node;
63
+ } }, item.id),
64
+ _jsx(SidebarRailSeparator, {}, `${item.id}-separator`)
65
+ ]) }), _jsx("div", { className: "hc-sidebar-rail-footer shrink-0", children: _jsxs("button", { type: "button", className: cn('hc-sidebar-rail-expand app-no-drag inline-flex min-h-12 w-full cursor-pointer items-center rounded-none border-none bg-transparent py-3 text-sidebar-rail-text', expanded ? 'gap-2 px-3' : 'justify-center', 'hover:bg-sidebar-rail-active', railExpandFocusVisible), "aria-label": expanded ? undefined : expandAriaLabel, "aria-expanded": expanded, title: expandLabel, onClick: handleToggleExpanded, children: [_jsx(FaIcon, { icon: expanded ? faAnglesLeft : faAnglesRight, className: "h-[18px]! w-[18px]!", "aria-hidden": true }), expanded ? _jsx("span", { className: "min-w-0 truncate text-left", children: expandLabel }) : null] }) })] }));
66
+ }
@@ -14,6 +14,10 @@ interface Props {
14
14
  * Called when the menu should close without selecting an item.
15
15
  */
16
16
  onClose: () => void;
17
+ /**
18
+ * Accessible name for the menu. Defaults to "Tab actions".
19
+ */
20
+ ariaLabel?: string;
17
21
  }
18
22
  /**
19
23
  * Cursor-positioned context menu for tab bars, rendered in a portal at the click point.
@@ -21,6 +25,6 @@ interface Props {
21
25
  * @param props - Menu groups, cursor anchor, and close handler.
22
26
  * @returns Portal menu panel, or null when there are no items.
23
27
  */
24
- export declare function TabContextMenu({ groups, position, onClose }: Props): JSX.Element | null;
28
+ export declare function TabContextMenu({ groups, position, onClose, ariaLabel }: Props): JSX.Element | null;
25
29
  export {};
26
30
  //# sourceMappingURL=TabContextMenu.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TabContextMenu.d.ts","sourceRoot":"","sources":["../../../src/components/TabBar/TabContextMenu.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAU1E,UAAU,KAAK;IACb;;OAEG;IACH,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;IAErB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoKvF"}
1
+ {"version":3,"file":"TabContextMenu.d.ts","sourceRoot":"","sources":["../../../src/components/TabBar/TabContextMenu.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,KAAK,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAU1E,UAAU,KAAK;IACb;;OAEG;IACH,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;IAErB;;OAEG;IACH,QAAQ,EAAE,YAAY,CAAC;IAEvB;;OAEG;IACH,OAAO,EAAE,MAAM,IAAI,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,QAAQ,EACR,OAAO,EACP,SAAyB,EAC1B,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,GAAG,IAAI,CAoK5B"}