@harborclient/sdk 1.0.16 → 1.0.18

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.
@@ -0,0 +1,24 @@
1
+ import type { JSX } from 'react';
2
+ import type { TabItem } from './types.js';
3
+ interface Props<T extends string> {
4
+ /**
5
+ * Tabs that can be shown or hidden via the menu.
6
+ */
7
+ tabs: TabItem<T>[];
8
+ /**
9
+ * Tab values currently shown in the tab strip.
10
+ */
11
+ visibleTabValues: T[];
12
+ /**
13
+ * Called when the user toggles a tab's visibility in the menu.
14
+ *
15
+ * @param tabValue - Tab value to toggle.
16
+ */
17
+ onToggle: (tabValue: T) => void;
18
+ }
19
+ /**
20
+ * Caret-triggered menu for toggling which segmented tabs are visible.
21
+ */
22
+ export declare function SegmentedTabsVisibilityMenu<T extends string>({ tabs, visibleTabValues, onToggle }: Props<T>): JSX.Element;
23
+ export {};
24
+ //# sourceMappingURL=SegmentedTabsVisibilityMenu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SegmentedTabsVisibilityMenu.d.ts","sourceRoot":"","sources":["../../../src/components/SegmentedTabs/SegmentedTabsVisibilityMenu.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAA4B,MAAM,OAAO,CAAC;AAK3D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;IAC9B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnB;;OAEG;IACH,gBAAgB,EAAE,CAAC,EAAE,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;CACjC;AAQD;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,MAAM,EAAE,EAC5D,IAAI,EACJ,gBAAgB,EAChB,QAAQ,EACT,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAwLxB"}
@@ -0,0 +1,155 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
+ import { useCallback, useEffect, useId, useRef, useState } from '@harborclient/sdk/react';
3
+ import { faCaretDown, faCheck } from '@fortawesome/free-solid-svg-icons';
4
+ import { Button } from '../Button/index.js';
5
+ import { FaIcon } from '../FaIcon/index.js';
6
+ import { resolveTabListKeyAction } from '../utils.js';
7
+ const menuItemClass = 'flex w-full cursor-pointer items-center gap-2 border-none bg-transparent px-3.5 py-1.5 text-left text-[14px] text-text hover:bg-selection app-no-drag';
8
+ const triggerClassName = '!rounded-full hover:!bg-[rgba(0,122,255,0.18)] dark:hover:!bg-[rgba(10,132,255,0.22)]';
9
+ /**
10
+ * Caret-triggered menu for toggling which segmented tabs are visible.
11
+ */
12
+ export function SegmentedTabsVisibilityMenu({ tabs, visibleTabValues, onToggle }) {
13
+ const menuId = useId();
14
+ const menuElementId = `${menuId}-menu`;
15
+ const rootRef = useRef(null);
16
+ const triggerRef = useRef(null);
17
+ const itemRefs = useRef([]);
18
+ const wasOpenRef = useRef(false);
19
+ const [isOpen, setIsOpen] = useState(false);
20
+ const [focusedIndex, setFocusedIndex] = useState(0);
21
+ const visibleSet = new Set(visibleTabValues);
22
+ /**
23
+ * Closes the menu and returns focus to the trigger button.
24
+ */
25
+ const closeMenu = useCallback(() => {
26
+ setIsOpen(false);
27
+ requestAnimationFrame(() => {
28
+ triggerRef.current?.focus();
29
+ });
30
+ }, []);
31
+ /**
32
+ * Opens the menu and focuses the first or last item.
33
+ *
34
+ * @param focusLast - When true, focus the last item instead of the first.
35
+ */
36
+ const openMenu = useCallback((focusLast = false) => {
37
+ if (tabs.length === 0)
38
+ return;
39
+ setFocusedIndex(focusLast ? tabs.length - 1 : 0);
40
+ setIsOpen(true);
41
+ }, [tabs.length]);
42
+ /**
43
+ * Focuses a menu item by index and updates roving tabindex state.
44
+ *
45
+ * @param index - Index of the menu item to focus.
46
+ */
47
+ const focusItem = useCallback((index) => {
48
+ setFocusedIndex(index);
49
+ requestAnimationFrame(() => {
50
+ itemRefs.current[index]?.focus();
51
+ });
52
+ }, []);
53
+ /**
54
+ * Moves focus into the menu after it opens and item refs are mounted.
55
+ */
56
+ useEffect(() => {
57
+ if (isOpen && !wasOpenRef.current) {
58
+ requestAnimationFrame(() => {
59
+ itemRefs.current[focusedIndex]?.focus();
60
+ });
61
+ }
62
+ wasOpenRef.current = isOpen;
63
+ }, [focusedIndex, isOpen]);
64
+ /**
65
+ * Resets item refs when the menu closes.
66
+ */
67
+ useEffect(() => {
68
+ if (!isOpen) {
69
+ itemRefs.current = [];
70
+ setFocusedIndex(0);
71
+ }
72
+ }, [isOpen]);
73
+ /**
74
+ * Closes the menu on outside click or Escape while it is open.
75
+ */
76
+ useEffect(() => {
77
+ if (!isOpen)
78
+ return;
79
+ const handleMouseDown = (e) => {
80
+ if (rootRef.current && !rootRef.current.contains(e.target)) {
81
+ closeMenu();
82
+ }
83
+ };
84
+ const handleKeyDown = (e) => {
85
+ if (e.key === 'Escape') {
86
+ e.preventDefault();
87
+ closeMenu();
88
+ }
89
+ };
90
+ document.addEventListener('mousedown', handleMouseDown);
91
+ document.addEventListener('keydown', handleKeyDown);
92
+ return () => {
93
+ document.removeEventListener('mousedown', handleMouseDown);
94
+ document.removeEventListener('keydown', handleKeyDown);
95
+ };
96
+ }, [closeMenu, isOpen]);
97
+ /**
98
+ * Handles keyboard interaction on the menu trigger when closed.
99
+ *
100
+ * @param event - Keyboard event from the trigger button.
101
+ */
102
+ const handleTriggerKeyDown = (event) => {
103
+ if (isOpen)
104
+ return;
105
+ if (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ') {
106
+ event.preventDefault();
107
+ openMenu(false);
108
+ return;
109
+ }
110
+ if (event.key === 'ArrowUp') {
111
+ event.preventDefault();
112
+ openMenu(true);
113
+ }
114
+ };
115
+ /**
116
+ * Handles keyboard navigation within the open menu.
117
+ *
118
+ * @param event - Keyboard event from the menu container.
119
+ */
120
+ const handleMenuKeyDown = (event) => {
121
+ if (tabs.length === 0)
122
+ return;
123
+ if (event.key === 'Tab') {
124
+ closeMenu();
125
+ return;
126
+ }
127
+ const arrowIndex = resolveTabListKeyAction(event.key, focusedIndex, tabs.length);
128
+ if (arrowIndex !== null) {
129
+ event.preventDefault();
130
+ focusItem(arrowIndex);
131
+ }
132
+ };
133
+ return (_jsxs("div", { ref: rootRef, className: "hc-segmented-tabs-visibility-menu relative shrink-0", children: [_jsx(Button, { innerRef: triggerRef, type: "button", variant: "icon", className: triggerClassName, "aria-label": "Customize visible tabs", "aria-haspopup": "menu", "aria-expanded": isOpen, "aria-controls": isOpen ? menuElementId : undefined, onClick: () => {
134
+ if (isOpen) {
135
+ closeMenu();
136
+ }
137
+ else {
138
+ openMenu(false);
139
+ }
140
+ }, onKeyDown: handleTriggerKeyDown, children: _jsx(FaIcon, { icon: faCaretDown, className: "h-3.5 w-3.5" }) }), isOpen && (_jsx("div", { id: menuElementId, role: "menu", className: "absolute right-0 top-full z-10 mt-0.5 min-w-[140px] rounded-md border border-separator bg-surface py-1 shadow-md app-no-drag", onKeyDown: handleMenuKeyDown, children: tabs.map((tab, index) => {
141
+ const checked = visibleSet.has(tab.value);
142
+ return (_jsx(MenuCheckboxItem, { ref: (element) => {
143
+ itemRefs.current[index] = element;
144
+ }, checked: checked, tabIndex: index === focusedIndex ? 0 : -1, label: tab.label, onSelect: () => onToggle(tab.value) }, tab.value));
145
+ }) }))] }));
146
+ }
147
+ /**
148
+ * Single checkbox-style row in the tab visibility menu.
149
+ */
150
+ function MenuCheckboxItem({ checked, label, tabIndex, onSelect, ref }) {
151
+ return (_jsxs("button", { ref: ref, type: "button", role: "menuitemcheckbox", "aria-checked": checked, tabIndex: tabIndex, className: menuItemClass, onClick: (e) => {
152
+ e.stopPropagation();
153
+ onSelect();
154
+ }, children: [_jsx("span", { className: "inline-flex w-4 shrink-0 justify-center", "aria-hidden": true, children: checked ? _jsx(FaIcon, { icon: faCheck, className: "h-3 w-3" }) : null }), _jsx("span", { className: "min-w-0", children: label })] }));
155
+ }
@@ -19,6 +19,26 @@ interface Props<T extends string> {
19
19
  * @param value - Newly selected tab value.
20
20
  */
21
21
  onChange?: (value: T) => void;
22
+ /**
23
+ * When true, shows a menu for toggling tab visibility.
24
+ */
25
+ editable?: boolean;
26
+ /**
27
+ * Controlled set of tab values shown in the tab strip. Used with
28
+ * `onVisibleTabValuesChange` when tab visibility is persisted.
29
+ */
30
+ visibleTabValues?: T[];
31
+ /**
32
+ * Initial visible tab values for uncontrolled visibility. Defaults to all
33
+ * non-`hidden` tabs. Keep a copy in the parent to reset saved preferences.
34
+ */
35
+ defaultVisibleTabValues?: T[];
36
+ /**
37
+ * Called when the user toggles tab visibility in the edit menu.
38
+ *
39
+ * @param visibleTabValues - Updated visible tab values.
40
+ */
41
+ onVisibleTabValuesChange?: (visibleTabValues: T[]) => void;
22
42
  /**
23
43
  * When true, the group and each tab stretch to full width.
24
44
  */
@@ -41,5 +61,5 @@ interface Props<T extends string> {
41
61
  /**
42
62
  * macOS-style segmented tab control with WAI-ARIA tabs or radiogroup semantics.
43
63
  */
44
- export declare function SegmentedTabs<T extends string>({ tabs, value: valueProp, onChange: onChangeProp, fullWidth, className, pattern, ariaLabel: ariaLabelProp }: Props<T>): JSX.Element;
64
+ export declare function SegmentedTabs<T extends string>({ tabs, value: valueProp, onChange: onChangeProp, editable, visibleTabValues: visibleTabValuesProp, defaultVisibleTabValues, onVisibleTabValuesChange, fullWidth, className, pattern, ariaLabel: ariaLabelProp }: Props<T>): JSX.Element;
45
65
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SegmentedTabs/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAC;AAIhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;IAC9B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IAEV;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAE9B;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAEhC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,EAC9C,IAAI,EACJ,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,SAAiB,EACjB,SAAS,EACT,OAAgB,EAChB,SAAS,EAAE,aAAa,EACzB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CA+GxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/SegmentedTabs/index.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,GAAG,EAAiB,MAAM,OAAO,CAAC;AAKhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,UAAU,KAAK,CAAC,CAAC,SAAS,MAAM;IAC9B;;OAEG;IACH,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnB;;OAEG;IACH,KAAK,CAAC,EAAE,CAAC,CAAC;IAEV;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAE9B;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,EAAE,CAAC;IAEvB;;;OAGG;IACH,uBAAuB,CAAC,EAAE,CAAC,EAAE,CAAC;IAE9B;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAE3D;;OAEG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;IAEhC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,EAC9C,IAAI,EACJ,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,YAAY,EACtB,QAAe,EACf,gBAAgB,EAAE,oBAAoB,EACtC,uBAAuB,EACvB,wBAAwB,EACxB,SAAiB,EACjB,SAAS,EACT,OAAgB,EAChB,SAAS,EAAE,aAAa,EACzB,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAuNxB"}
@@ -1,14 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "@harborclient/sdk/jsx-runtime";
2
- import { useCallback, useContext, useId, useMemo, useRef } from '@harborclient/sdk/react';
2
+ import { useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from '@harborclient/sdk/react';
3
3
  import { resolveTabListKeyAction } from '../utils.js';
4
4
  import { segment, segmentGroup } from '../classes.js';
5
5
  import { SegmentedTabsContext } from './SegmentedTabsContext.js';
6
+ import { SegmentedTabsVisibilityMenu } from './SegmentedTabsVisibilityMenu.js';
6
7
  export { SegmentedTabsGroup } from './SegmentedTabsGroup.js';
7
8
  export { SegmentedTabPanel } from './SegmentedTabPanel.js';
8
9
  /**
9
10
  * macOS-style segmented tab control with WAI-ARIA tabs or radiogroup semantics.
10
11
  */
11
- export function SegmentedTabs({ tabs, value: valueProp, onChange: onChangeProp, fullWidth = false, className, pattern = 'tabs', ariaLabel: ariaLabelProp }) {
12
+ export function SegmentedTabs({ tabs, value: valueProp, onChange: onChangeProp, editable = true, visibleTabValues: visibleTabValuesProp, defaultVisibleTabValues, onVisibleTabValuesChange, fullWidth = false, className, pattern = 'tabs', ariaLabel: ariaLabelProp }) {
12
13
  const context = useContext(SegmentedTabsContext);
13
14
  const standaloneId = useId();
14
15
  const tabRefs = useRef(new Map());
@@ -32,8 +33,84 @@ export function SegmentedTabs({ tabs, value: valueProp, onChange: onChangeProp,
32
33
  const getPanelId = context
33
34
  ? (tabValue) => context.getPanelId(tabValue)
34
35
  : (tabValue) => `${standaloneId}-panel-${tabValue}`;
35
- const visibleTabs = tabs.filter((tab) => !tab.hidden);
36
- const groupClassName = ['hc-segmented-tabs', segmentGroup, fullWidth ? 'w-full' : '', className]
36
+ const editableTabs = useMemo(() => tabs.filter((tab) => !tab.hidden), [tabs]);
37
+ const defaultVisible = useMemo(() => defaultVisibleTabValues ?? editableTabs.map((tab) => tab.value), [defaultVisibleTabValues, editableTabs]);
38
+ const [internalVisibleTabValues, setInternalVisibleTabValues] = useState(defaultVisible);
39
+ const visibleTabValues = visibleTabValuesProp ?? internalVisibleTabValues;
40
+ const visibleSet = useMemo(() => new Set(visibleTabValues), [visibleTabValues]);
41
+ const visibleTabs = editable
42
+ ? editableTabs.filter((tab) => visibleSet.has(tab.value))
43
+ : editableTabs;
44
+ /**
45
+ * Updates visible tab values and notifies the parent when controlled props
46
+ * are used for persistence.
47
+ *
48
+ * @param nextVisibleTabValues - New visible tab values.
49
+ */
50
+ const updateVisibleTabValues = useCallback((nextVisibleTabValues) => {
51
+ if (visibleTabValuesProp === undefined) {
52
+ setInternalVisibleTabValues(nextVisibleTabValues);
53
+ }
54
+ onVisibleTabValuesChange?.(nextVisibleTabValues);
55
+ }, [onVisibleTabValuesChange, visibleTabValuesProp]);
56
+ /**
57
+ * Toggles a tab's visibility in the edit menu, keeping at least one tab
58
+ * visible and moving selection when the active tab is hidden.
59
+ *
60
+ * @param tabValue - Tab value to show or hide.
61
+ */
62
+ const handleVisibilityToggle = useCallback((tabValue) => {
63
+ const isVisible = visibleSet.has(tabValue);
64
+ if (isVisible && visibleTabs.length <= 1)
65
+ return;
66
+ const nextVisibleSet = new Set(visibleTabValues);
67
+ if (isVisible) {
68
+ nextVisibleSet.delete(tabValue);
69
+ }
70
+ else {
71
+ nextVisibleSet.add(tabValue);
72
+ }
73
+ const nextVisibleTabValues = editableTabs
74
+ .filter((tab) => nextVisibleSet.has(tab.value))
75
+ .map((tab) => tab.value);
76
+ updateVisibleTabValues(nextVisibleTabValues);
77
+ if (isVisible && tabValue === value) {
78
+ const nextSelectedTab = editableTabs.find((tab) => nextVisibleSet.has(tab.value));
79
+ if (nextSelectedTab) {
80
+ onChange(nextSelectedTab.value);
81
+ }
82
+ }
83
+ }, [
84
+ editableTabs,
85
+ onChange,
86
+ updateVisibleTabValues,
87
+ value,
88
+ visibleSet,
89
+ visibleTabValues,
90
+ visibleTabs.length
91
+ ]);
92
+ /**
93
+ * When visibility changes externally, select the first visible tab if the
94
+ * current selection is hidden.
95
+ */
96
+ useEffect(() => {
97
+ if (!editable || visibleSet.has(value))
98
+ return;
99
+ const nextSelectedTab = visibleTabs[0];
100
+ if (nextSelectedTab) {
101
+ onChange(nextSelectedTab.value);
102
+ }
103
+ }, [editable, onChange, value, visibleSet, visibleTabs]);
104
+ const outerClassName = [
105
+ 'hc-segmented-tabs',
106
+ segmentGroup,
107
+ 'items-center gap-1',
108
+ fullWidth ? 'flex-1 min-w-0' : '',
109
+ className
110
+ ]
111
+ .filter(Boolean)
112
+ .join(' ');
113
+ const tabListClassName = ['inline-flex min-w-0 flex-1 items-center', fullWidth ? 'w-full' : '']
37
114
  .filter(Boolean)
38
115
  .join(' ');
39
116
  /**
@@ -62,21 +139,21 @@ export function SegmentedTabs({ tabs, value: valueProp, onChange: onChangeProp,
62
139
  });
63
140
  }, [visibleTabs, value, onChange]);
64
141
  const isRadiogroup = pattern === 'radiogroup';
65
- return (_jsx("div", { className: groupClassName, role: isRadiogroup ? 'radiogroup' : 'tablist', "aria-label": ariaLabel, ...(!isRadiogroup ? { 'aria-orientation': 'horizontal' } : {}), onKeyDown: handleKeyDown, children: visibleTabs.map((tab) => {
66
- const selected = value === tab.value;
67
- const tabClassName = `${segment(selected)}${fullWidth ? ' flex-1' : ''}`;
68
- return (_jsx("button", { ref: (element) => {
69
- if (element)
70
- tabRefs.current.set(tab.value, element);
71
- else
72
- tabRefs.current.delete(tab.value);
73
- }, type: "button", className: tabClassName, disabled: tab.disabled, tabIndex: selected ? 0 : -1, onClick: () => onChange(tab.value), ...(isRadiogroup
74
- ? { role: 'radio', 'aria-checked': selected }
75
- : {
76
- role: 'tab',
77
- id: getTabId(tab.value),
78
- 'aria-selected': selected,
79
- ...(context ? { 'aria-controls': getPanelId(tab.value) } : {})
80
- }), children: _jsxs("span", { className: "inline-flex items-center gap-1.5", children: [tab.label, tab.indicator && _jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-accent", "aria-hidden": true })] }) }, tab.value));
81
- }) }));
142
+ return (_jsxs("div", { className: outerClassName, children: [_jsx("div", { className: tabListClassName, role: isRadiogroup ? 'radiogroup' : 'tablist', "aria-label": ariaLabel, ...(!isRadiogroup ? { 'aria-orientation': 'horizontal' } : {}), onKeyDown: handleKeyDown, children: visibleTabs.map((tab) => {
143
+ const selected = value === tab.value;
144
+ const tabClassName = `${segment(selected)}${fullWidth ? ' flex-1' : ''}`;
145
+ return (_jsx("button", { ref: (element) => {
146
+ if (element)
147
+ tabRefs.current.set(tab.value, element);
148
+ else
149
+ tabRefs.current.delete(tab.value);
150
+ }, type: "button", className: tabClassName, disabled: tab.disabled, tabIndex: selected ? 0 : -1, onClick: () => onChange(tab.value), ...(isRadiogroup
151
+ ? { role: 'radio', 'aria-checked': selected }
152
+ : {
153
+ role: 'tab',
154
+ id: getTabId(tab.value),
155
+ 'aria-selected': selected,
156
+ ...(context ? { 'aria-controls': getPanelId(tab.value) } : {})
157
+ }), children: _jsxs("span", { className: "inline-flex items-center gap-1.5", children: [tab.label, tab.indicator && (_jsx("span", { className: "h-1.5 w-1.5 rounded-full bg-accent", "aria-hidden": true }))] }) }, tab.value));
158
+ }) }), editable && (_jsx(SegmentedTabsVisibilityMenu, { tabs: editableTabs, visibleTabValues: visibleTabValues, onToggle: handleVisibilityToggle }))] }));
82
159
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@harborclient/sdk",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "TypeScript SDK for HarborClient plugin development.",
5
5
  "keywords": [
6
6
  "harborclient",