@harborclient/sdk 1.3.2 → 1.3.4

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 (102) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/components/AnchorMenuPanel/index.d.ts +35 -0
  3. package/dist/components/AnchorMenuPanel/index.d.ts.map +1 -0
  4. package/dist/components/AnchorMenuPanel/index.js +364 -0
  5. package/dist/components/ColorPicker/index.d.ts +5 -1
  6. package/dist/components/ColorPicker/index.d.ts.map +1 -1
  7. package/dist/components/ColorPicker/index.js +2 -2
  8. package/dist/components/FilterButton/FilterButtonIcon.d.ts +29 -0
  9. package/dist/components/FilterButton/FilterButtonIcon.d.ts.map +1 -0
  10. package/dist/components/FilterButton/FilterButtonIcon.js +18 -0
  11. package/dist/components/FilterButton/index.d.ts +26 -0
  12. package/dist/components/FilterButton/index.d.ts.map +1 -0
  13. package/dist/components/FilterButton/index.js +14 -0
  14. package/dist/components/FormGroup/index.d.ts +7 -1
  15. package/dist/components/FormGroup/index.d.ts.map +1 -1
  16. package/dist/components/FormGroup/index.js +8 -11
  17. package/dist/components/PageSidebar/index.d.ts +1 -0
  18. package/dist/components/PageSidebar/index.d.ts.map +1 -1
  19. package/dist/components/PageSidebar/index.js +4 -13
  20. package/dist/components/Resizable/applyResizableSizes.d.ts +11 -0
  21. package/dist/components/Resizable/applyResizableSizes.d.ts.map +1 -0
  22. package/dist/components/Resizable/applyResizableSizes.js +34 -0
  23. package/dist/components/Resizable/footerPanelUtils.d.ts +1 -1
  24. package/dist/components/Resizable/footerPanelUtils.js +4 -4
  25. package/dist/components/Resizable/index.d.ts +1 -0
  26. package/dist/components/Resizable/index.d.ts.map +1 -1
  27. package/dist/components/Resizable/index.js +1 -0
  28. package/dist/components/Resizable/useResizable.d.ts +7 -1
  29. package/dist/components/Resizable/useResizable.d.ts.map +1 -1
  30. package/dist/components/Resizable/useResizable.js +141 -11
  31. package/dist/components/RowActionsMenu/index.d.ts +7 -1
  32. package/dist/components/RowActionsMenu/index.d.ts.map +1 -1
  33. package/dist/components/RowActionsMenu/index.js +40 -18
  34. package/dist/components/SettingFieldActions/index.d.ts +42 -0
  35. package/dist/components/SettingFieldActions/index.d.ts.map +1 -0
  36. package/dist/components/SettingFieldActions/index.js +66 -0
  37. package/dist/components/SidebarItem/SidebarDocumentItem.d.ts +6 -6
  38. package/dist/components/SidebarItem/SidebarDocumentItem.d.ts.map +1 -1
  39. package/dist/components/SidebarItem/SidebarDocumentItem.js +4 -4
  40. package/dist/components/SidebarItem/SidebarEnvironmentItem.d.ts +4 -4
  41. package/dist/components/SidebarItem/SidebarEnvironmentItem.d.ts.map +1 -1
  42. package/dist/components/SidebarItem/SidebarEnvironmentItem.js +3 -3
  43. package/dist/components/SidebarItem/SidebarFolderItem.d.ts +5 -5
  44. package/dist/components/SidebarItem/SidebarFolderItem.d.ts.map +1 -1
  45. package/dist/components/SidebarItem/SidebarFolderItem.js +4 -4
  46. package/dist/components/SidebarItem/SidebarHistoryItem.d.ts +13 -1
  47. package/dist/components/SidebarItem/SidebarHistoryItem.d.ts.map +1 -1
  48. package/dist/components/SidebarItem/SidebarHistoryItem.js +3 -3
  49. package/dist/components/SidebarItem/SidebarMarkerDot.d.ts +22 -0
  50. package/dist/components/SidebarItem/SidebarMarkerDot.d.ts.map +1 -0
  51. package/dist/components/SidebarItem/SidebarMarkerDot.js +11 -0
  52. package/dist/components/SidebarItem/SidebarMethodBadge.d.ts +9 -1
  53. package/dist/components/SidebarItem/SidebarMethodBadge.d.ts.map +1 -1
  54. package/dist/components/SidebarItem/SidebarMethodBadge.js +7 -5
  55. package/dist/components/SidebarItem/SidebarRequestItem.d.ts +9 -5
  56. package/dist/components/SidebarItem/SidebarRequestItem.d.ts.map +1 -1
  57. package/dist/components/SidebarItem/SidebarRequestItem.js +4 -4
  58. package/dist/components/SidebarItem/SidebarRunItem.d.ts +9 -1
  59. package/dist/components/SidebarItem/SidebarRunItem.d.ts.map +1 -1
  60. package/dist/components/SidebarItem/SidebarRunItem.js +2 -2
  61. package/dist/components/SidebarItem/SidebarStatusDot.d.ts +11 -1
  62. package/dist/components/SidebarItem/SidebarStatusDot.d.ts.map +1 -1
  63. package/dist/components/SidebarItem/SidebarStatusDot.js +10 -1
  64. package/dist/components/SidebarItem/{SidebarTabGroupItem.d.ts → SidebarWorkspaceItem.d.ts} +9 -9
  65. package/dist/components/SidebarItem/SidebarWorkspaceItem.d.ts.map +1 -0
  66. package/dist/components/SidebarItem/{SidebarTabGroupItem.js → SidebarWorkspaceItem.js} +4 -4
  67. package/dist/components/SidebarItem/index.d.ts +3 -3
  68. package/dist/components/SidebarItem/index.d.ts.map +1 -1
  69. package/dist/components/SidebarItem/index.js +3 -3
  70. package/dist/components/SidebarItem/sidebarItemClasses.d.ts +17 -0
  71. package/dist/components/SidebarItem/sidebarItemClasses.d.ts.map +1 -1
  72. package/dist/components/SidebarItem/sidebarItemClasses.js +26 -2
  73. package/dist/components/SidebarSection/SectionItem.d.ts.map +1 -1
  74. package/dist/components/SidebarSection/SectionItem.js +3 -1
  75. package/dist/components/SortButton/SortButtonIcon.d.ts +29 -0
  76. package/dist/components/SortButton/SortButtonIcon.d.ts.map +1 -0
  77. package/dist/components/SortButton/SortButtonIcon.js +18 -0
  78. package/dist/components/SortButton/SortMenu.d.ts +42 -0
  79. package/dist/components/SortButton/SortMenu.d.ts.map +1 -0
  80. package/dist/components/SortButton/SortMenu.js +137 -0
  81. package/dist/components/SortButton/SortMenuOption.d.ts +35 -0
  82. package/dist/components/SortButton/SortMenuOption.d.ts.map +1 -0
  83. package/dist/components/SortButton/SortMenuOption.js +18 -0
  84. package/dist/components/SortButton/index.d.ts +32 -0
  85. package/dist/components/SortButton/index.d.ts.map +1 -0
  86. package/dist/components/SortButton/index.js +15 -0
  87. package/dist/components/SortButton/sortOptions.d.ts +14 -0
  88. package/dist/components/SortButton/sortOptions.d.ts.map +1 -0
  89. package/dist/components/SortButton/sortOptions.js +1 -0
  90. package/dist/components/TabBar/types.d.ts +1 -1
  91. package/dist/components/index.d.ts +9 -2
  92. package/dist/components/index.d.ts.map +1 -1
  93. package/dist/components/index.js +8 -2
  94. package/dist/runtime/createBridgedPluginContext.js +170 -2
  95. package/dist/snippets.d.ts +22 -0
  96. package/dist/types.d.ts +913 -1
  97. package/dist/types.d.ts.map +1 -1
  98. package/package.json +3 -3
  99. package/dist/components/SidebarItem/SidebarColorDot.d.ts +0 -22
  100. package/dist/components/SidebarItem/SidebarColorDot.d.ts.map +0 -1
  101. package/dist/components/SidebarItem/SidebarColorDot.js +0 -11
  102. package/dist/components/SidebarItem/SidebarTabGroupItem.d.ts.map +0 -1
@@ -2,21 +2,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
2
  import { useId } from '@harborclient/sdk/react';
3
3
  import { FieldError } from '../FieldError/index.js';
4
4
  import { enhanceControl } from '../enhanceControl.js';
5
- /**
6
- * Returns Tailwind classes for the label text based on tone and visibility.
7
- *
8
- * @returns Class string for the label element.
9
- */
10
5
  /**
11
6
  * Returns wrapper classes for bordered stacked, checkbox, and inline layouts.
12
7
  *
13
8
  * @param bordered - Whether the default border and padding should be applied.
14
9
  * @param layoutClasses - Layout-specific flex and sizing classes.
15
10
  * @param extra - Caller-supplied className override.
11
+ * @param modified - When true with `bordered`, adds a left unsaved-tab color border.
16
12
  */
17
- function borderedWrapperClasses(bordered, layoutClasses, extra) {
13
+ function borderedWrapperClasses(bordered, layoutClasses, extra, modified = false) {
18
14
  const frame = bordered ? 'p-4 border border-separator rounded-md' : '';
19
- const base = `hc-form-group ${layoutClasses} ${frame}`.trim();
15
+ const accent = bordered && modified ? 'border-l-2 border-l-[var(--color-tab-unsaved)]' : '';
16
+ const base = `hc-form-group ${layoutClasses} ${frame} ${accent}`.trim();
20
17
  return extra ? `${base} ${extra}` : base;
21
18
  }
22
19
  /**
@@ -39,7 +36,7 @@ function labelClasses(tone, srOnly, inline) {
39
36
  * Supports stacked fields, checkboxes, inline rows, radio options, and
40
37
  * adjacent checkbox rows used in list pickers.
41
38
  */
42
- export function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout = 'stacked', labelTone = 'default', srOnly = false, className, labelClassName, bordered = true, ...props }) {
39
+ export function FormGroup({ label, children, htmlFor, description, error, errorId, descriptionId, layout = 'stacked', labelTone = 'default', srOnly = false, className, labelClassName, bordered = true, modified = false, ...props }) {
43
40
  const generatedId = useId();
44
41
  const controlId = htmlFor ?? generatedId;
45
42
  const extra = className ?? '';
@@ -78,11 +75,11 @@ export function FormGroup({ label, children, htmlFor, description, error, errorI
78
75
  id: controlId,
79
76
  invalid: resolvedErrorId != null
80
77
  });
81
- const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra);
78
+ const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra, modified);
82
79
  return (_jsxs("div", { ...props, className: wrapperClasses, children: [_jsxs("label", { htmlFor: controlId, className: "hc-form-group-label flex flex-col gap-1", children: [_jsxs("span", { className: "hc-form-group-label-row flex items-center gap-2", children: [linkedChildren, _jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label })] }), resolvedDescriptionId ? (_jsx("p", { id: resolvedDescriptionId, className: "hc-form-group-description m-0 pl-[26px] text-[14px] text-muted", children: description })) : null] }), resolvedErrorId ? (_jsx(FieldError, { id: resolvedErrorId, spacing: "field", children: error })) : null] }));
83
80
  }
84
81
  if (layout === 'inline') {
85
- const wrapperClasses = borderedWrapperClasses(bordered, 'flex min-w-0 flex-1 items-center gap-2', extra);
82
+ const wrapperClasses = borderedWrapperClasses(bordered, 'flex min-w-0 flex-1 items-center gap-2', extra, modified);
86
83
  const linkedChildren = enhanceControl(children, { id: controlId });
87
84
  return (_jsxs("label", { htmlFor: controlId, className: wrapperClasses, children: [_jsx("span", { className: labelClasses(labelTone, srOnly, true), children: label }), linkedChildren] }));
88
85
  }
@@ -97,6 +94,6 @@ export function FormGroup({ label, children, htmlFor, description, error, errorI
97
94
  invalid: resolvedErrorId != null,
98
95
  id: htmlFor
99
96
  });
100
- const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra);
97
+ const wrapperClasses = borderedWrapperClasses(bordered, 'flex flex-col gap-1', extra, modified);
101
98
  return (_jsxs("div", { ...props, className: wrapperClasses, children: [_jsxs("label", { htmlFor: htmlFor, className: "hc-form-group-label flex flex-col gap-1", children: [_jsx("span", { className: labelClasses(labelTone, srOnly, false), children: label }), resolvedDescriptionId ? (_jsx("p", { id: resolvedDescriptionId, className: "hc-form-group-description m-0 text-[14px] text-muted", children: description })) : null, control] }), resolvedErrorId ? (_jsx(FieldError, { id: resolvedErrorId, spacing: "field", children: error })) : null] }));
102
99
  }
@@ -37,6 +37,7 @@ interface Props<T extends string> extends Omit<ComponentPropsWithoutRef<'nav'>,
37
37
  }
38
38
  /**
39
39
  * Narrow sidebar navigation for multi-section pages such as settings overlays.
40
+ * Row chrome matches collections sidebar items via {@link sourceRow}.
40
41
  */
41
42
  export declare function PageSidebar<T extends string>({ items, selected, onSelect, ariaLabel, className, ...props }: Props<T>): JSX.Element;
42
43
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PageSidebar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAI3D;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC;IAET;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,IAAI,CAC5C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,YAAY,GAAG,UAAU,CAC1B;IACC;;OAEG;IACH,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,CAAC,CAAC;IAEZ;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAE7B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,EAC5C,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CA4CxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/PageSidebar/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAK3D;;GAEG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACxD;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC;IAET;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,IAAI,CAAC,EAAE,cAAc,CAAC;CACvB;AAED,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM,CAAE,SAAQ,IAAI,CAC5C,wBAAwB,CAAC,KAAK,CAAC,EAC/B,YAAY,GAAG,UAAU,CAC1B;IACC;;OAEG;IACH,KAAK,EAAE,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAE5B;;OAEG;IACH,QAAQ,EAAE,CAAC,CAAC;IAEZ;;OAEG;IACH,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAE7B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,EAC5C,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAuCxB"}
@@ -1,23 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
2
  import { FaIcon } from '../FaIcon/index.js';
3
+ import { sourceRow } from '../SidebarItem/sidebarItemClasses.js';
3
4
  import { cn } from '../utils.js';
4
- /**
5
- * Tailwind classes for a sidebar navigation row.
6
- */
7
- function sidebarRow(active) {
8
- return active
9
- ? 'group flex cursor-pointer items-center gap-1 rounded-md bg-selection px-1.5 py-2 app-no-drag'
10
- : 'group flex cursor-pointer items-center gap-1 rounded-md px-1.5 py-2 hover:bg-selection/60 app-no-drag';
11
- }
12
5
  /**
13
6
  * Narrow sidebar navigation for multi-section pages such as settings overlays.
7
+ * Row chrome matches collections sidebar items via {@link sourceRow}.
14
8
  */
15
9
  export function PageSidebar({ items, selected, onSelect, ariaLabel, className, ...props }) {
16
- return (_jsx("nav", { ...props, className: cn('hc-page-sidebar flex w-[220px] shrink-0 flex-col gap-1 border-r border-separator bg-sidebar px-2 py-3', className), "aria-label": ariaLabel, children: items.map((item) => {
10
+ return (_jsx("nav", { ...props, className: cn('hc-page-sidebar flex w-[220px] shrink-0 flex-col gap-0 border-r border-separator bg-sidebar px-2 py-3', className), "aria-label": ariaLabel, children: items.map((item) => {
17
11
  const active = selected === item.value;
18
- const rowClass = item.icon
19
- ? `hc-page-sidebar-item ${sidebarRow(active)} w-full gap-2 border-none text-left text-[15px] app-no-drag`
20
- : `hc-page-sidebar-item ${sidebarRow(active)} w-full border-none text-left text-[15px] app-no-drag`;
21
- return (_jsxs("button", { type: "button", className: rowClass, "aria-current": active ? 'page' : undefined, onClick: () => onSelect(item.value), children: [item.icon ? (_jsx(FaIcon, { icon: item.icon, className: cn('hc-page-sidebar-item-icon h-[18px] w-[18px] shrink-0', active ? 'text-text' : 'text-muted'), "aria-hidden": true })) : null, _jsx("span", { className: "hc-page-sidebar-item-label min-w-0 truncate", children: item.label })] }, item.value));
12
+ return (_jsxs("button", { type: "button", className: cn('hc-sidebar-item hc-page-sidebar-item', sourceRow(active, true), 'min-h-[30px] w-full cursor-pointer border-none text-left text-inherit', item.icon && 'gap-2'), "aria-current": active ? 'page' : undefined, onClick: () => onSelect(item.value), children: [item.icon ? (_jsx(FaIcon, { icon: item.icon, className: "hc-page-sidebar-item-icon h-3.5 w-3.5 shrink-0 text-muted", "aria-hidden": true })) : null, _jsx("span", { className: "hc-page-sidebar-item-label min-w-0 truncate", children: item.label })] }, item.value));
22
13
  }) }));
23
14
  }
@@ -0,0 +1,11 @@
1
+ /** Window event name used to re-read localStorage sizes after an external write. */
2
+ export declare const RESIZABLE_SYNC_EVENT = "hc:resizable-sync";
3
+ /**
4
+ * Writes resizable panel sizes to localStorage and notifies mounted hooks to re-read.
5
+ *
6
+ * Used when restoring a workspace layout snapshot that includes panel widths/heights.
7
+ *
8
+ * @param entries - Map of storageKey → size in pixels.
9
+ */
10
+ export declare function applyResizableSizes(entries: Record<string, number>): void;
11
+ //# sourceMappingURL=applyResizableSizes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"applyResizableSizes.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/applyResizableSizes.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AAgBxD;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAWzE"}
@@ -0,0 +1,34 @@
1
+ /** Window event name used to re-read localStorage sizes after an external write. */
2
+ export const RESIZABLE_SYNC_EVENT = 'hc:resizable-sync';
3
+ /**
4
+ * Persists a size to localStorage.
5
+ *
6
+ * @param storageKey - localStorage key for the panel size.
7
+ * @param size - Size in pixels to store.
8
+ */
9
+ function persistSize(storageKey, size) {
10
+ try {
11
+ localStorage.setItem(storageKey, String(size));
12
+ }
13
+ catch {
14
+ // Ignore quota or privacy-mode failures.
15
+ }
16
+ }
17
+ /**
18
+ * Writes resizable panel sizes to localStorage and notifies mounted hooks to re-read.
19
+ *
20
+ * Used when restoring a workspace layout snapshot that includes panel widths/heights.
21
+ *
22
+ * @param entries - Map of storageKey → size in pixels.
23
+ */
24
+ export function applyResizableSizes(entries) {
25
+ for (const [storageKey, size] of Object.entries(entries)) {
26
+ if (!Number.isFinite(size)) {
27
+ continue;
28
+ }
29
+ persistSize(storageKey, Math.round(size));
30
+ }
31
+ if (typeof window !== 'undefined') {
32
+ window.dispatchEvent(new CustomEvent(RESIZABLE_SYNC_EVENT));
33
+ }
34
+ }
@@ -7,7 +7,7 @@ export declare const MIN_HEIGHT = 120;
7
7
  * Computes the maximum height for a footer slide-up panel from the main content area.
8
8
  *
9
9
  * Walks from the panel container up to the app shell and measures the flex row
10
- * above the footer so panels cannot grow past the usable workspace.
10
+ * above the footer so panels cannot grow past the usable main content area.
11
11
  *
12
12
  * @param containerRef - Ref attached to the panel root element.
13
13
  * @returns Maximum panel height in pixels.
@@ -3,13 +3,13 @@ export const DEFAULT_HEIGHT = 280;
3
3
  /** Minimum slide-up footer panel height in pixels. */
4
4
  export const MIN_HEIGHT = 120;
5
5
  /**
6
- * Resolves the main workspace row above the footer for max-height measurement.
6
+ * Resolves the main content row above the footer for max-height measurement.
7
7
  *
8
8
  * Prefers the flex row wrapping `#main-content` so measurement stays correct
9
- * when the app shell includes skip links or other elements before the workspace.
9
+ * when the app shell includes skip links or other elements before the main content area.
10
10
  *
11
11
  * @param containerRef - Ref attached to the panel root element.
12
- * @returns Workspace row element, if found.
12
+ * @returns Main content row element, if found.
13
13
  */
14
14
  function resolveFooterPanelContentArea(containerRef) {
15
15
  const mainContentParent = document.getElementById('main-content')?.parentElement;
@@ -31,7 +31,7 @@ function resolveFooterPanelContentArea(containerRef) {
31
31
  * Computes the maximum height for a footer slide-up panel from the main content area.
32
32
  *
33
33
  * Walks from the panel container up to the app shell and measures the flex row
34
- * above the footer so panels cannot grow past the usable workspace.
34
+ * above the footer so panels cannot grow past the usable main content area.
35
35
  *
36
36
  * @param containerRef - Ref attached to the panel root element.
37
37
  * @returns Maximum panel height in pixels.
@@ -1,4 +1,5 @@
1
1
  export { Resizable } from './Resizable.js';
2
2
  export { ResizeHandle } from './ResizeHandle.js';
3
+ export { applyResizableSizes, RESIZABLE_SYNC_EVENT } from './applyResizableSizes.js';
3
4
  export { useResizable, type UseResizableOptions, type UseResizableResult } from './useResizable.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { Resizable } from './Resizable.js';
2
2
  export { ResizeHandle } from './ResizeHandle.js';
3
+ export { applyResizableSizes, RESIZABLE_SYNC_EVENT } from './applyResizableSizes.js';
3
4
  export { useResizable } from './useResizable.js';
@@ -1,4 +1,5 @@
1
1
  import type { KeyboardEvent as ReactKeyboardEvent, MouseEvent as ReactMouseEvent } from 'react';
2
+ export { applyResizableSizes, RESIZABLE_SYNC_EVENT } from './applyResizableSizes.js';
2
3
  type Axis = 'x' | 'y';
3
4
  export interface UseResizableOptions {
4
5
  /**
@@ -38,6 +39,11 @@ export interface UseResizableResult {
38
39
  onResizeStart: (event: ReactMouseEvent) => void;
39
40
  onKeyboardResize: (event: ReactKeyboardEvent) => void;
40
41
  }
42
+ /**
43
+ * Tracks resizable panel size with pointer drag and optional persistence.
44
+ *
45
+ * During drag, pointer movement sets a target size; the displayed size eases
46
+ * toward that target each frame unless the user prefers reduced motion.
47
+ */
41
48
  export declare function useResizable({ axis, direction, defaultSize, minSize, getMaxSize, storageKey, onPersist }: UseResizableOptions): UseResizableResult;
42
- export {};
43
49
  //# sourceMappingURL=useResizable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useResizable.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/useResizable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,OAAO,CAAC;AAEhG,KAAK,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC;AAkDtB,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IAEX;;OAEG;IACH,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAElB;;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,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,aAAa,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAChD,gBAAgB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACvD;AAyDD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,SAAS,EACT,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACV,EAAE,mBAAmB,GAAG,kBAAkB,CAgJ1C"}
1
+ {"version":3,"file":"useResizable.d.ts","sourceRoot":"","sources":["../../../src/components/Resizable/useResizable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,IAAI,kBAAkB,EAAE,UAAU,IAAI,eAAe,EAAE,MAAM,OAAO,CAAC;AAGhG,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErF,KAAK,IAAI,GAAG,GAAG,GAAG,GAAG,CAAC;AAyEtB,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IAEX;;OAEG;IACH,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAElB;;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,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,aAAa,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAChD,gBAAgB,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACvD;AAiED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,SAAS,EACT,WAAW,EACX,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACV,EAAE,mBAAmB,GAAG,kBAAkB,CA8P1C"}
@@ -1,6 +1,17 @@
1
1
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from '@harborclient/sdk/react';
2
+ import { RESIZABLE_SYNC_EVENT } from './applyResizableSizes.js';
3
+ export { applyResizableSizes, RESIZABLE_SYNC_EVENT } from './applyResizableSizes.js';
2
4
  /** Id of the shared stylesheet injected during resize drags. */
3
5
  const RESIZING_STYLE_ID = 'hc-resizable-drag-styles';
6
+ /**
7
+ * Fraction of the remaining target gap closed per animation frame during drag.
8
+ * Lower values feel heavier; higher values track the pointer more closely.
9
+ */
10
+ const RESIZE_DRAG_LERP = 0.22;
11
+ /**
12
+ * Stop the drag lerp loop when within this many pixels of the pointer target.
13
+ */
14
+ const RESIZE_DRAG_SNAP_EPSILON = 0.5;
4
15
  /**
5
16
  * Injects shared CSS that neutralizes webviews/iframes and shows the resize cursor during drags.
6
17
  * Electron webviews paint above normal DOM, so pointer-events must be disabled on the webview itself.
@@ -43,8 +54,22 @@ function setResizingState(axis) {
43
54
  function clearResizingState() {
44
55
  delete document.body.dataset.hcResizing;
45
56
  }
57
+ /**
58
+ * Returns whether the user prefers reduced motion.
59
+ *
60
+ * @returns True when the OS requests minimized animation.
61
+ */
62
+ function prefersReducedMotion() {
63
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
64
+ return false;
65
+ }
66
+ return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
67
+ }
46
68
  /**
47
69
  * Loads a persisted size from localStorage.
70
+ *
71
+ * @param storageKey - localStorage key for the panel size.
72
+ * @param defaultSize - Fallback when the key is unset or invalid.
48
73
  */
49
74
  function loadStoredSize(storageKey, defaultSize) {
50
75
  try {
@@ -60,6 +85,9 @@ function loadStoredSize(storageKey, defaultSize) {
60
85
  }
61
86
  /**
62
87
  * Persists a size to localStorage.
88
+ *
89
+ * @param storageKey - localStorage key for the panel size.
90
+ * @param size - Size in pixels to store.
63
91
  */
64
92
  function persistSize(storageKey, size) {
65
93
  try {
@@ -71,15 +99,17 @@ function persistSize(storageKey, size) {
71
99
  }
72
100
  /**
73
101
  * Clamps a size between min and optional max bounds.
102
+ *
103
+ * @param size - Candidate size in pixels.
104
+ * @param minSize - Minimum allowed size.
105
+ * @param getMaxSize - Optional dynamic max getter.
106
+ * @returns Size clamped to [minSize, max].
74
107
  */
75
108
  function clampSize(size, minSize, getMaxSize) {
76
109
  const rawMax = getMaxSize?.() ?? Number.POSITIVE_INFINITY;
77
110
  const maxSize = Math.max(minSize, rawMax);
78
111
  return Math.min(maxSize, Math.max(minSize, size));
79
112
  }
80
- /**
81
- * Tracks resizable panel size with pointer drag and optional persistence.
82
- */
83
113
  /**
84
114
  * Persists a committed resize size via localStorage and/or a caller callback.
85
115
  *
@@ -93,6 +123,12 @@ function commitSize(storageKey, onPersist, size) {
93
123
  }
94
124
  onPersist?.(size);
95
125
  }
126
+ /**
127
+ * Tracks resizable panel size with pointer drag and optional persistence.
128
+ *
129
+ * During drag, pointer movement sets a target size; the displayed size eases
130
+ * toward that target each frame unless the user prefers reduced motion.
131
+ */
96
132
  export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize, storageKey, onPersist }) {
97
133
  const [size, setSizeState] = useState(() => {
98
134
  const initial = storageKey ? loadStoredSize(storageKey, defaultSize) : defaultSize;
@@ -103,12 +139,80 @@ export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize
103
139
  const startPosRef = useRef(0);
104
140
  const startSizeRef = useRef(defaultSize);
105
141
  const sizeRef = useRef(size);
142
+ const targetSizeRef = useRef(size);
143
+ const rafIdRef = useRef(null);
144
+ const minSizeRef = useRef(minSize);
145
+ const getMaxSizeRef = useRef(getMaxSize);
106
146
  /**
107
147
  * Keeps a ref in sync with state so drag handlers read the latest size.
108
148
  */
109
149
  useEffect(() => {
110
150
  sizeRef.current = size;
111
151
  }, [size]);
152
+ /**
153
+ * Keeps bound refs current so the lerp loop does not close over stale values.
154
+ */
155
+ useEffect(() => {
156
+ minSizeRef.current = minSize;
157
+ getMaxSizeRef.current = getMaxSize;
158
+ }, [getMaxSize, minSize]);
159
+ /**
160
+ * Cancels any in-flight drag lerp animation frame.
161
+ */
162
+ const stopResizeLerp = useCallback(() => {
163
+ if (rafIdRef.current != null) {
164
+ cancelAnimationFrame(rafIdRef.current);
165
+ rafIdRef.current = null;
166
+ }
167
+ }, []);
168
+ /**
169
+ * Eases displayed size toward the pointer target while a drag is active.
170
+ */
171
+ const runResizeLerpStep = useCallback(() => {
172
+ rafIdRef.current = null;
173
+ if (!resizingRef.current) {
174
+ return;
175
+ }
176
+ const current = sizeRef.current;
177
+ const target = targetSizeRef.current;
178
+ const gap = target - current;
179
+ if (Math.abs(gap) <= RESIZE_DRAG_SNAP_EPSILON) {
180
+ setSizeState(target);
181
+ return;
182
+ }
183
+ const nextSize = clampSize(current + gap * RESIZE_DRAG_LERP, minSizeRef.current, getMaxSizeRef.current);
184
+ setSizeState(nextSize);
185
+ rafIdRef.current = requestAnimationFrame(runResizeLerpStep);
186
+ }, []);
187
+ /**
188
+ * Starts the drag lerp loop when it is not already scheduled.
189
+ */
190
+ const startResizeLerp = useCallback(() => {
191
+ if (rafIdRef.current != null) {
192
+ return;
193
+ }
194
+ rafIdRef.current = requestAnimationFrame(runResizeLerpStep);
195
+ }, [runResizeLerpStep]);
196
+ /**
197
+ * Re-reads this panel's localStorage size when a workspace (or other caller)
198
+ * applies sizes externally via {@link applyResizableSizes}.
199
+ */
200
+ useEffect(() => {
201
+ if (!storageKey) {
202
+ return;
203
+ }
204
+ /**
205
+ * Loads the stored size for this panel and clamps it to current bounds.
206
+ */
207
+ const handleSync = () => {
208
+ const nextSize = clampSize(loadStoredSize(storageKey, defaultSize), minSize, getMaxSize);
209
+ setSizeState(nextSize);
210
+ };
211
+ window.addEventListener(RESIZABLE_SYNC_EVENT, handleSync);
212
+ return () => {
213
+ window.removeEventListener(RESIZABLE_SYNC_EVENT, handleSync);
214
+ };
215
+ }, [defaultSize, getMaxSize, minSize, storageKey]);
112
216
  /**
113
217
  * Refreshes the computed max size when layout changes or the panel is resized.
114
218
  */
@@ -125,22 +229,30 @@ export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize
125
229
  }, [getMaxSize, size]);
126
230
  /**
127
231
  * Updates panel size with min/max clamping applied.
232
+ *
233
+ * @param nextSize - Desired size in pixels before clamping.
128
234
  */
129
235
  const setSize = useCallback((nextSize) => {
130
236
  setSizeState(clampSize(nextSize, minSize, getMaxSize));
131
237
  }, [getMaxSize, minSize]);
132
238
  /**
133
239
  * Captures pointer position and current size when a resize drag begins.
240
+ *
241
+ * @param event - React mouse event from the resize handle.
134
242
  */
135
243
  const onResizeStart = useCallback((event) => {
136
244
  event.preventDefault();
245
+ stopResizeLerp();
137
246
  resizingRef.current = true;
138
247
  startPosRef.current = axis === 'x' ? event.clientX : event.clientY;
139
248
  startSizeRef.current = sizeRef.current;
249
+ targetSizeRef.current = sizeRef.current;
140
250
  setResizingState(axis);
141
- }, [axis]);
251
+ }, [axis, stopResizeLerp]);
142
252
  /**
143
253
  * Nudges panel size from arrow keys using the same axis/direction math as drag.
254
+ *
255
+ * @param event - React keyboard event from the focused resize handle.
144
256
  */
145
257
  const onKeyboardResize = useCallback((event) => {
146
258
  if (event.key === 'Enter' || event.key === ' ') {
@@ -173,7 +285,7 @@ export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize
173
285
  */
174
286
  useEffect(() => {
175
287
  /**
176
- * Updates size from pointer movement while a resize drag is active.
288
+ * Updates the pointer target (and eases toward it) while a resize drag is active.
177
289
  *
178
290
  * @param event - Window mousemove event.
179
291
  */
@@ -183,17 +295,25 @@ export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize
183
295
  const currentPos = axis === 'x' ? event.clientX : event.clientY;
184
296
  const delta = (currentPos - startPosRef.current) * direction;
185
297
  const nextSize = clampSize(startSizeRef.current + delta, minSize, getMaxSize);
186
- setSizeState(nextSize);
298
+ targetSizeRef.current = nextSize;
299
+ if (prefersReducedMotion()) {
300
+ setSizeState(nextSize);
301
+ return;
302
+ }
303
+ startResizeLerp();
187
304
  };
188
305
  /**
189
- * Ends the resize drag and commits the final size when configured.
306
+ * Ends the resize drag, snaps to the pointer target, and commits the size.
190
307
  */
191
308
  const handleMouseUp = () => {
192
309
  if (!resizingRef.current)
193
310
  return;
194
311
  resizingRef.current = false;
312
+ stopResizeLerp();
195
313
  clearResizingState();
196
- commitSize(storageKey, onPersist, sizeRef.current);
314
+ const snapped = clampSize(targetSizeRef.current, minSize, getMaxSize);
315
+ setSizeState(snapped);
316
+ commitSize(storageKey, onPersist, snapped);
197
317
  };
198
318
  window.addEventListener('mousemove', handleMouseMove);
199
319
  window.addEventListener('mouseup', handleMouseUp);
@@ -207,17 +327,27 @@ export function useResizable({ axis, direction, defaultSize, minSize, getMaxSize
207
327
  window.removeEventListener('mousemove', handleMouseMove);
208
328
  window.removeEventListener('mouseup', handleMouseUp);
209
329
  };
210
- }, [axis, direction, getMaxSize, minSize, onPersist, storageKey]);
330
+ }, [
331
+ axis,
332
+ direction,
333
+ getMaxSize,
334
+ minSize,
335
+ onPersist,
336
+ startResizeLerp,
337
+ stopResizeLerp,
338
+ storageKey
339
+ ]);
211
340
  /**
212
- * Clears the document resize marker when the hook unmounts mid-drag.
341
+ * Clears the document resize marker and any lerp loop when the hook unmounts mid-drag.
213
342
  */
214
343
  useEffect(() => {
215
344
  return () => {
345
+ stopResizeLerp();
216
346
  if (resizingRef.current) {
217
347
  resizingRef.current = false;
218
348
  clearResizingState();
219
349
  }
220
350
  };
221
- }, []);
351
+ }, [stopResizeLerp]);
222
352
  return { size, minSize, maxSize, setSize, onResizeStart, onKeyboardResize };
223
353
  }
@@ -75,6 +75,12 @@ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
75
75
  * Additional classes merged onto the trigger button.
76
76
  */
77
77
  triggerClassName?: string;
78
+ /**
79
+ * When set, styles the trigger like {@link FilterButton}: muted when inactive,
80
+ * full-contrast when active, and an accent corner indicator on icon-only
81
+ * triggers while filters are applied.
82
+ */
83
+ triggerActive?: boolean;
78
84
  /**
79
85
  * Whether the menu opens below or above the trigger. Defaults to opening downward.
80
86
  */
@@ -88,6 +94,6 @@ interface Props extends Omit<ComponentPropsWithoutRef<'div'>, 'children'> {
88
94
  * `submenu` open a nested flyout panel beside them on hover, click, or
89
95
  * `ArrowRight`/`Enter`.
90
96
  */
91
- export declare function RowActionsMenu({ groups, menuId, openMenuId, onOpenChange, triggerVariant, triggerLabel, triggerIcon, triggerAriaLabel, triggerTitle, triggerClassName, placement, className, ...props }: Props): JSX.Element;
97
+ export declare function RowActionsMenu({ groups, menuId, openMenuId, onOpenChange, triggerVariant, triggerLabel, triggerIcon, triggerAriaLabel, triggerTitle, triggerClassName, triggerActive, placement, className, ...props }: Props): JSX.Element;
92
98
  export {};
93
99
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RowActionsMenu/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAUxE,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAC;AACrF,OAAO,EAAU,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAkBhE,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAE/B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAChB,CAAC,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,GAC9D,CAAC,YAAY,GAAG;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC;CACvB,CAAC,CAAC;AAEP,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACvE;;;OAGG;IACH,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;IAErB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAE1C;;OAEG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IAEzB;;OAEG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;IAE7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAUD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,SAAkB,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAojBrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/RowActionsMenu/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAUxE,OAAO,KAAK,EACV,wBAAwB,EACxB,GAAG,EAGH,SAAS,EACV,MAAM,OAAO,CAAC;AACf,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAmBlF,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAE/B;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,QAAQ,GAChB,CAAC,YAAY,GAAG;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;IAAC,OAAO,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC,GAC9D,CAAC,YAAY,GAAG;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;;OAGG;IACH,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC;CACvB,CAAC,CAAC;AAEP,UAAU,KAAM,SAAQ,IAAI,CAAC,wBAAwB,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IACvE;;;OAGG;IACH,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC;IAErB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1B;;OAEG;IACH,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAE1C;;OAEG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;IAE/B;;;OAGG;IACH,YAAY,CAAC,EAAE,SAAS,CAAC;IAEzB;;OAEG;IACH,WAAW,CAAC,EAAE,cAAc,CAAC;IAE7B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAUD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAC7B,MAAM,EACN,MAAM,EACN,UAAU,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,WAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,SAAkB,EAClB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAskBrB"}
@@ -3,6 +3,7 @@ import { faBars, faCaretRight, faCheck } from '@fortawesome/free-solid-svg-icons
3
3
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from '@harborclient/sdk/react';
4
4
  import { Button } from '../Button/index.js';
5
5
  import { FaIcon } from '../FaIcon/index.js';
6
+ import { FilterButtonIcon } from '../FilterButton/FilterButtonIcon.js';
6
7
  import { MENU_MIN_WIDTH_PX, clampMenuPosition, getTriggerAnchoredMenuPosition } from '../menuPosition.js';
7
8
  import { portalToBody } from '../portalToBody.js';
8
9
  import { findAdjacentEnabledIndex, findEdgeEnabledIndex, isMenuItemEnabled, menuItemClass } from '../rowActionsMenuHelpers.js';
@@ -21,7 +22,7 @@ const SUBMENU_CLOSE_DELAY_MS = 200;
21
22
  * `submenu` open a nested flyout panel beside them on hover, click, or
22
23
  * `ArrowRight`/`Enter`.
23
24
  */
24
- export function RowActionsMenu({ groups, menuId, openMenuId, onOpenChange, triggerVariant, triggerLabel, triggerIcon = faBars, triggerAriaLabel, triggerTitle, triggerClassName, placement = 'down', className, ...props }) {
25
+ export function RowActionsMenu({ groups, menuId, openMenuId, onOpenChange, triggerVariant, triggerLabel, triggerIcon = faBars, triggerAriaLabel, triggerTitle, triggerClassName, triggerActive, placement = 'down', className, ...props }) {
25
26
  const isOpen = openMenuId === menuId;
26
27
  const menuElementId = `${menuId}-menu`;
27
28
  const submenuElementId = `${menuId}-submenu`;
@@ -403,22 +404,43 @@ export function RowActionsMenu({ groups, menuId, openMenuId, onOpenChange, trigg
403
404
  const labeledTriggerVariant = resolvedTriggerVariant === 'icon' || resolvedTriggerVariant === 'iconDanger'
404
405
  ? 'secondary'
405
406
  : resolvedTriggerVariant;
406
- const triggerButton = isLabeledTrigger ? (_jsxs(Button, { innerRef: triggerRef, type: "button", variant: labeledTriggerVariant, className: cn('hc-row-actions-menu-trigger', triggerClassName), title: resolvedTriggerTitle, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? menuElementId : undefined, onClick: (e) => {
407
- e.stopPropagation();
408
- if (isOpen) {
409
- closeMenu();
410
- }
411
- else {
412
- openMenu(false);
413
- }
414
- }, onKeyDown: handleTriggerKeyDown, children: [_jsx(FaIcon, { icon: triggerIcon, className: "h-[1em] w-[1em] shrink-0", "aria-hidden": true }), _jsx("span", { className: "hc-row-actions-menu-trigger-label inline-flex min-w-0 flex-1 items-center truncate overflow-hidden leading-none", children: triggerLabel })] })) : (_jsx(Button, { innerRef: triggerRef, type: "button", variant: "icon", className: cn('hc-row-actions-menu-trigger', triggerClassName), title: resolvedTriggerTitle, "aria-label": resolvedTriggerAriaLabel, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? menuElementId : undefined, onClick: (e) => {
415
- e.stopPropagation();
416
- if (isOpen) {
417
- closeMenu();
418
- }
419
- else {
420
- openMenu(false);
421
- }
422
- }, onKeyDown: handleTriggerKeyDown, children: _jsx(FaIcon, { icon: triggerIcon, className: "h-3.5 w-3.5" }) }));
407
+ const triggerActiveClassName = triggerActive === undefined
408
+ ? undefined
409
+ : triggerActive
410
+ ? 'text-text hover:text-text'
411
+ : 'text-muted hover:text-text';
412
+ /**
413
+ * Toggles the menu from the trigger click without bubbling to the row.
414
+ *
415
+ * @param event - Native button click event.
416
+ */
417
+ const handleTriggerClick = (event) => {
418
+ event.stopPropagation();
419
+ if (isOpen) {
420
+ closeMenu();
421
+ }
422
+ else {
423
+ openMenu(false);
424
+ }
425
+ };
426
+ /**
427
+ * Icon-only trigger props. Cast through `ButtonProps` so `triggerVariant`
428
+ * (including `toolbar`) is accepted alongside the default `icon` variant;
429
+ * `aria-label` is always provided for accessibility.
430
+ */
431
+ const iconOnlyTriggerProps = {
432
+ innerRef: triggerRef,
433
+ type: 'button',
434
+ variant: resolvedTriggerVariant,
435
+ className: cn('hc-row-actions-menu-trigger', triggerActiveClassName, triggerClassName),
436
+ title: resolvedTriggerTitle,
437
+ 'aria-label': resolvedTriggerAriaLabel,
438
+ 'aria-haspopup': 'menu',
439
+ 'aria-expanded': isOpen,
440
+ 'aria-controls': isOpen ? menuElementId : undefined,
441
+ onClick: handleTriggerClick,
442
+ onKeyDown: handleTriggerKeyDown
443
+ };
444
+ const triggerButton = isLabeledTrigger ? (_jsxs(Button, { innerRef: triggerRef, type: "button", variant: labeledTriggerVariant, className: cn('hc-row-actions-menu-trigger', triggerActiveClassName, triggerClassName), title: resolvedTriggerTitle, "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? menuElementId : undefined, onClick: handleTriggerClick, onKeyDown: handleTriggerKeyDown, children: [_jsx(FaIcon, { icon: triggerIcon, className: "h-[1em] w-[1em] shrink-0", "aria-hidden": true }), _jsx("span", { className: "hc-row-actions-menu-trigger-label inline-flex min-w-0 flex-1 items-center truncate overflow-hidden leading-none", children: triggerLabel })] })) : (_jsx(Button, { ...iconOnlyTriggerProps, children: triggerActive !== undefined ? (_jsx(FilterButtonIcon, { active: triggerActive, icon: triggerIcon })) : (_jsx(FaIcon, { icon: triggerIcon, className: "h-3.5 w-3.5" })) }));
423
445
  return (_jsxs("div", { ref: rootRef, ...props, className: cn('hc-row-actions-menu shrink-0', className), children: [triggerButton, menuPanel ? portalToBody(menuPanel) : null, submenuPanel] }));
424
446
  }