@salt-ds/lab 1.0.0-alpha.88 → 1.0.0-alpha.89
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.
- package/CHANGELOG.md +14 -0
- package/css/salt-lab.css +53 -25
- package/dist-cjs/list-deprecated/ListStateContext.js +1 -1
- package/dist-cjs/list-deprecated/ListStateContext.js.map +1 -1
- package/dist-cjs/tabs-next/TabBar.css.js +1 -1
- package/dist-cjs/tabs-next/TabBar.js +1 -1
- package/dist-cjs/tabs-next/TabBar.js.map +1 -1
- package/dist-cjs/tabs-next/TabListLayoutContext.js +13 -0
- package/dist-cjs/tabs-next/TabListLayoutContext.js.map +1 -0
- package/dist-cjs/tabs-next/TabListNext.css.js +1 -1
- package/dist-cjs/tabs-next/TabListNext.js +179 -33
- package/dist-cjs/tabs-next/TabListNext.js.map +1 -1
- package/dist-cjs/tabs-next/TabNext.js +111 -7
- package/dist-cjs/tabs-next/TabNext.js.map +1 -1
- package/dist-cjs/tabs-next/TabNextAction.js +25 -2
- package/dist-cjs/tabs-next/TabNextAction.js.map +1 -1
- package/dist-cjs/tabs-next/TabNextPanel.js +31 -16
- package/dist-cjs/tabs-next/TabNextPanel.js.map +1 -1
- package/dist-cjs/tabs-next/TabNextTrigger.js +110 -9
- package/dist-cjs/tabs-next/TabNextTrigger.js.map +1 -1
- package/dist-cjs/tabs-next/TabOverflowList.css.js +1 -1
- package/dist-cjs/tabs-next/TabOverflowList.js +168 -64
- package/dist-cjs/tabs-next/TabOverflowList.js.map +1 -1
- package/dist-cjs/tabs-next/TabSlot.js +30 -0
- package/dist-cjs/tabs-next/TabSlot.js.map +1 -0
- package/dist-cjs/tabs-next/TabSlotRegistryContext.js +16 -0
- package/dist-cjs/tabs-next/TabSlotRegistryContext.js.map +1 -0
- package/dist-cjs/tabs-next/TabsNext.css.js +6 -0
- package/dist-cjs/tabs-next/TabsNext.css.js.map +1 -0
- package/dist-cjs/tabs-next/TabsNext.js +113 -47
- package/dist-cjs/tabs-next/TabsNext.js.map +1 -1
- package/dist-cjs/tabs-next/TabsNextContext.js +17 -3
- package/dist-cjs/tabs-next/TabsNextContext.js.map +1 -1
- package/dist-cjs/tabs-next/domUtils.js +13 -0
- package/dist-cjs/tabs-next/domUtils.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/overflowMath.js +86 -0
- package/dist-cjs/tabs-next/hooks/overflowMath.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useCollection.js +147 -41
- package/dist-cjs/tabs-next/hooks/useCollection.js.map +1 -1
- package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js +64 -0
- package/dist-cjs/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useOverflow.js +240 -156
- package/dist-cjs/tabs-next/hooks/useOverflow.js.map +1 -1
- package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js +99 -0
- package/dist-cjs/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js +60 -0
- package/dist-cjs/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js +92 -0
- package/dist-cjs/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js +200 -0
- package/dist-cjs/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useTabListRecovery.js +76 -0
- package/dist-cjs/tabs-next/hooks/useTabListRecovery.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js +165 -0
- package/dist-cjs/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
- package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js +80 -0
- package/dist-cjs/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
- package/dist-cjs/tabs-next/widthMeasurement.js +42 -0
- package/dist-cjs/tabs-next/widthMeasurement.js.map +1 -0
- package/dist-cjs/tree/Tree.css.js +1 -1
- package/dist-cjs/tree/TreeNode.css.js +1 -1
- package/dist-cjs/tree/TreeNode.js +1 -1
- package/dist-cjs/tree/TreeNode.js.map +1 -1
- package/dist-cjs/tree/TreeNodeExpansionIcon.css.js +1 -1
- package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
- package/dist-cjs/tree/TreeNodeTrigger.js +2 -2
- package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
- package/dist-cjs/utils/useEventCallback.js +5 -5
- package/dist-cjs/utils/useEventCallback.js.map +1 -1
- package/dist-es/list-deprecated/ListStateContext.js +1 -1
- package/dist-es/list-deprecated/ListStateContext.js.map +1 -1
- package/dist-es/tabs-next/TabBar.css.js +1 -1
- package/dist-es/tabs-next/TabBar.js +1 -1
- package/dist-es/tabs-next/TabBar.js.map +1 -1
- package/dist-es/tabs-next/TabListLayoutContext.js +10 -0
- package/dist-es/tabs-next/TabListLayoutContext.js.map +1 -0
- package/dist-es/tabs-next/TabListNext.css.js +1 -1
- package/dist-es/tabs-next/TabListNext.js +182 -36
- package/dist-es/tabs-next/TabListNext.js.map +1 -1
- package/dist-es/tabs-next/TabNext.js +113 -9
- package/dist-es/tabs-next/TabNext.js.map +1 -1
- package/dist-es/tabs-next/TabNextAction.js +25 -2
- package/dist-es/tabs-next/TabNextAction.js.map +1 -1
- package/dist-es/tabs-next/TabNextPanel.js +31 -16
- package/dist-es/tabs-next/TabNextPanel.js.map +1 -1
- package/dist-es/tabs-next/TabNextTrigger.js +110 -9
- package/dist-es/tabs-next/TabNextTrigger.js.map +1 -1
- package/dist-es/tabs-next/TabOverflowList.css.js +1 -1
- package/dist-es/tabs-next/TabOverflowList.js +172 -68
- package/dist-es/tabs-next/TabOverflowList.js.map +1 -1
- package/dist-es/tabs-next/TabSlot.js +28 -0
- package/dist-es/tabs-next/TabSlot.js.map +1 -0
- package/dist-es/tabs-next/TabSlotRegistryContext.js +13 -0
- package/dist-es/tabs-next/TabSlotRegistryContext.js.map +1 -0
- package/dist-es/tabs-next/TabsNext.css.js +4 -0
- package/dist-es/tabs-next/TabsNext.css.js.map +1 -0
- package/dist-es/tabs-next/TabsNext.js +114 -48
- package/dist-es/tabs-next/TabsNext.js.map +1 -1
- package/dist-es/tabs-next/TabsNextContext.js +17 -3
- package/dist-es/tabs-next/TabsNextContext.js.map +1 -1
- package/dist-es/tabs-next/domUtils.js +11 -0
- package/dist-es/tabs-next/domUtils.js.map +1 -0
- package/dist-es/tabs-next/hooks/overflowMath.js +82 -0
- package/dist-es/tabs-next/hooks/overflowMath.js.map +1 -0
- package/dist-es/tabs-next/hooks/useCollection.js +148 -42
- package/dist-es/tabs-next/hooks/useCollection.js.map +1 -1
- package/dist-es/tabs-next/hooks/useFocusWithRetry.js +62 -0
- package/dist-es/tabs-next/hooks/useFocusWithRetry.js.map +1 -0
- package/dist-es/tabs-next/hooks/useOverflow.js +242 -158
- package/dist-es/tabs-next/hooks/useOverflow.js.map +1 -1
- package/dist-es/tabs-next/hooks/useOverflowLayoutState.js +97 -0
- package/dist-es/tabs-next/hooks/useOverflowLayoutState.js.map +1 -0
- package/dist-es/tabs-next/hooks/useOverflowSelectionState.js +58 -0
- package/dist-es/tabs-next/hooks/useOverflowSelectionState.js.map +1 -0
- package/dist-es/tabs-next/hooks/useRenderedTabWidth.js +90 -0
- package/dist-es/tabs-next/hooks/useRenderedTabWidth.js.map +1 -0
- package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js +198 -0
- package/dist-es/tabs-next/hooks/useRenderedTabsRegistry.js.map +1 -0
- package/dist-es/tabs-next/hooks/useTabListRecovery.js +74 -0
- package/dist-es/tabs-next/hooks/useTabListRecovery.js.map +1 -0
- package/dist-es/tabs-next/hooks/useTabRemovalHandler.js +163 -0
- package/dist-es/tabs-next/hooks/useTabRemovalHandler.js.map +1 -0
- package/dist-es/tabs-next/hooks/useTabSelectionFocus.js +78 -0
- package/dist-es/tabs-next/hooks/useTabSelectionFocus.js.map +1 -0
- package/dist-es/tabs-next/widthMeasurement.js +36 -0
- package/dist-es/tabs-next/widthMeasurement.js.map +1 -0
- package/dist-es/tree/Tree.css.js +1 -1
- package/dist-es/tree/TreeNode.css.js +1 -1
- package/dist-es/tree/TreeNode.js +1 -1
- package/dist-es/tree/TreeNode.js.map +1 -1
- package/dist-es/tree/TreeNodeExpansionIcon.css.js +1 -1
- package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
- package/dist-es/tree/TreeNodeTrigger.js +2 -2
- package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
- package/dist-es/utils/useEventCallback.js +5 -5
- package/dist-es/utils/useEventCallback.js.map +1 -1
- package/dist-types/cascading-menu/internal/useMenuTriggerHandlers.d.ts +1 -1
- package/dist-types/list-deprecated/ListStateContext.d.ts +7 -2
- package/dist-types/tabs-next/TabListLayoutContext.d.ts +9 -0
- package/dist-types/tabs-next/TabNext.d.ts +1 -1
- package/dist-types/tabs-next/TabNextPanel.d.ts +2 -1
- package/dist-types/tabs-next/TabOverflowList.d.ts +3 -4
- package/dist-types/tabs-next/TabSlot.d.ts +6 -0
- package/dist-types/tabs-next/TabSlotRegistryContext.d.ts +5 -0
- package/dist-types/tabs-next/TabsNext.d.ts +2 -1
- package/dist-types/tabs-next/TabsNextContext.d.ts +26 -4
- package/dist-types/tabs-next/domUtils.d.ts +1 -0
- package/dist-types/tabs-next/hooks/overflowMath.d.ts +18 -0
- package/dist-types/tabs-next/hooks/useCollection.d.ts +15 -3
- package/dist-types/tabs-next/hooks/useFocusWithRetry.d.ts +9 -0
- package/dist-types/tabs-next/hooks/useOverflow.d.ts +5 -5
- package/dist-types/tabs-next/hooks/useOverflowLayoutState.d.ts +13 -0
- package/dist-types/tabs-next/hooks/useOverflowSelectionState.d.ts +13 -0
- package/dist-types/tabs-next/hooks/useRenderedTabWidth.d.ts +12 -0
- package/dist-types/tabs-next/hooks/useRenderedTabsRegistry.d.ts +12 -0
- package/dist-types/tabs-next/hooks/useTabListRecovery.d.ts +12 -0
- package/dist-types/tabs-next/hooks/useTabRemovalHandler.d.ts +32 -0
- package/dist-types/tabs-next/hooks/useTabSelectionFocus.d.ts +15 -0
- package/dist-types/tabs-next/widthMeasurement.d.ts +5 -0
- package/dist-types/utils/useEventCallback.d.ts +1 -1
- package/package.json +2 -2
- package/dist-cjs/tabs-next/hooks/useFocusOutside.js +0 -25
- package/dist-cjs/tabs-next/hooks/useFocusOutside.js.map +0 -1
- package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js +0 -93
- package/dist-cjs/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
- package/dist-es/tabs-next/hooks/useFocusOutside.js +0 -23
- package/dist-es/tabs-next/hooks/useFocusOutside.js.map +0 -1
- package/dist-es/tabs-next/hooks/useRestoreActiveTab.js +0 -91
- package/dist-es/tabs-next/hooks/useRestoreActiveTab.js.map +0 -1
- package/dist-types/tabs-next/hooks/useFocusOutside.d.ts +0 -2
- package/dist-types/tabs-next/hooks/useRestoreActiveTab.d.ts +0 -10
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { usePrevious, useIsomorphicLayoutEffect } from '@salt-ds/core';
|
|
2
|
+
import { computeAccessibleName } from 'dom-accessibility-api';
|
|
3
|
+
import { useCallback } from 'react';
|
|
4
|
+
|
|
5
|
+
function hasLostDocumentFocus(doc) {
|
|
6
|
+
const activeElement = doc.activeElement;
|
|
7
|
+
return !activeElement || activeElement === doc.body || activeElement === doc.documentElement || !activeElement.isConnected;
|
|
8
|
+
}
|
|
9
|
+
function getTabAccessibleName(element) {
|
|
10
|
+
return computeAccessibleName(element).trim();
|
|
11
|
+
}
|
|
12
|
+
function useTabSelectionFocus({
|
|
13
|
+
announce,
|
|
14
|
+
focusElementWithRetry,
|
|
15
|
+
getRenderedTab,
|
|
16
|
+
getSelectedTabElement,
|
|
17
|
+
menuOpen,
|
|
18
|
+
resolvedOverflowActiveValue,
|
|
19
|
+
selected,
|
|
20
|
+
selectionFromOverflowValueRef,
|
|
21
|
+
targetWindow
|
|
22
|
+
}) {
|
|
23
|
+
const previousSelected = usePrevious(selected, [selected]);
|
|
24
|
+
const focusSelectedTab = useCallback(() => {
|
|
25
|
+
focusElementWithRetry(getSelectedTabElement);
|
|
26
|
+
}, [focusElementWithRetry, getSelectedTabElement]);
|
|
27
|
+
useIsomorphicLayoutEffect(() => {
|
|
28
|
+
if (!menuOpen || !resolvedOverflowActiveValue) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
focusElementWithRetry(
|
|
32
|
+
() => {
|
|
33
|
+
var _a;
|
|
34
|
+
return (_a = getRenderedTab(resolvedOverflowActiveValue)) == null ? void 0 : _a.trigger;
|
|
35
|
+
}
|
|
36
|
+
);
|
|
37
|
+
}, [
|
|
38
|
+
focusElementWithRetry,
|
|
39
|
+
getRenderedTab,
|
|
40
|
+
menuOpen,
|
|
41
|
+
resolvedOverflowActiveValue
|
|
42
|
+
]);
|
|
43
|
+
useIsomorphicLayoutEffect(() => {
|
|
44
|
+
const doc = targetWindow == null ? void 0 : targetWindow.document;
|
|
45
|
+
if (!doc || selected === void 0 || previousSelected === void 0 || selected === previousSelected) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (!hasLostDocumentFocus(doc)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
focusSelectedTab();
|
|
52
|
+
}, [focusSelectedTab, previousSelected, selected, targetWindow]);
|
|
53
|
+
useIsomorphicLayoutEffect(() => {
|
|
54
|
+
const selectedFromOverflow = selectionFromOverflowValueRef.current;
|
|
55
|
+
if (selectedFromOverflow == null || selected === void 0 || selected === previousSelected) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (selected !== selectedFromOverflow) {
|
|
59
|
+
selectionFromOverflowValueRef.current = null;
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
focusSelectedTab();
|
|
63
|
+
const selectedTab = getSelectedTabElement();
|
|
64
|
+
const selectedTabName = selectedTab ? getTabAccessibleName(selectedTab) || selected : selected;
|
|
65
|
+
announce(`${selectedTabName} moved to main tab list`, 100);
|
|
66
|
+
selectionFromOverflowValueRef.current = null;
|
|
67
|
+
}, [
|
|
68
|
+
announce,
|
|
69
|
+
getSelectedTabElement,
|
|
70
|
+
previousSelected,
|
|
71
|
+
focusSelectedTab,
|
|
72
|
+
selected,
|
|
73
|
+
selectionFromOverflowValueRef
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { useTabSelectionFocus };
|
|
78
|
+
//# sourceMappingURL=useTabSelectionFocus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTabSelectionFocus.js","sources":["../src/tabs-next/hooks/useTabSelectionFocus.ts"],"sourcesContent":["import { useIsomorphicLayoutEffect, usePrevious } from \"@salt-ds/core\";\nimport { computeAccessibleName } from \"dom-accessibility-api\";\nimport type { MutableRefObject } from \"react\";\nimport { useCallback } from \"react\";\nimport type { TabsNextContextValue } from \"../TabsNextContext\";\n\nfunction hasLostDocumentFocus(doc: Document) {\n const activeElement = doc.activeElement;\n return (\n !activeElement ||\n activeElement === doc.body ||\n activeElement === doc.documentElement ||\n !activeElement.isConnected\n );\n}\n\nfunction getTabAccessibleName(element: HTMLElement) {\n return computeAccessibleName(element).trim();\n}\n\ninterface UseTabSelectionFocusArgs {\n announce: (message: string, timeout?: number) => void;\n focusElementWithRetry: (\n getElement: () => HTMLElement | null | undefined,\n ) => void;\n getRenderedTab: TabsNextContextValue[\"getRenderedTab\"];\n getSelectedTabElement: () => HTMLElement | null | undefined;\n menuOpen: boolean;\n resolvedOverflowActiveValue: string | null;\n selected?: string;\n selectionFromOverflowValueRef: MutableRefObject<string | null>;\n targetWindow: Window | null | undefined;\n}\n\nexport function useTabSelectionFocus({\n announce,\n focusElementWithRetry,\n getRenderedTab,\n getSelectedTabElement,\n menuOpen,\n resolvedOverflowActiveValue,\n selected,\n selectionFromOverflowValueRef,\n targetWindow,\n}: UseTabSelectionFocusArgs) {\n const previousSelected = usePrevious(selected, [selected]);\n\n const focusSelectedTab = useCallback(() => {\n focusElementWithRetry(getSelectedTabElement);\n }, [focusElementWithRetry, getSelectedTabElement]);\n\n useIsomorphicLayoutEffect(() => {\n if (!menuOpen || !resolvedOverflowActiveValue) {\n return;\n }\n\n focusElementWithRetry(\n () => getRenderedTab(resolvedOverflowActiveValue)?.trigger,\n );\n }, [\n focusElementWithRetry,\n getRenderedTab,\n menuOpen,\n resolvedOverflowActiveValue,\n ]);\n\n useIsomorphicLayoutEffect(() => {\n const doc = targetWindow?.document;\n if (\n !doc ||\n selected === undefined ||\n previousSelected === undefined ||\n selected === previousSelected\n ) {\n return;\n }\n\n if (!hasLostDocumentFocus(doc)) {\n return;\n }\n\n focusSelectedTab();\n }, [focusSelectedTab, previousSelected, selected, targetWindow]);\n\n useIsomorphicLayoutEffect(() => {\n const selectedFromOverflow = selectionFromOverflowValueRef.current;\n if (\n selectedFromOverflow == null ||\n selected === undefined ||\n selected === previousSelected\n ) {\n return;\n }\n\n if (selected !== selectedFromOverflow) {\n selectionFromOverflowValueRef.current = null;\n return;\n }\n\n focusSelectedTab();\n\n const selectedTab = getSelectedTabElement();\n const selectedTabName = selectedTab\n ? getTabAccessibleName(selectedTab) || selected\n : selected;\n\n announce(`${selectedTabName} moved to main tab list`, 100);\n selectionFromOverflowValueRef.current = null;\n }, [\n announce,\n getSelectedTabElement,\n previousSelected,\n focusSelectedTab,\n selected,\n selectionFromOverflowValueRef,\n ]);\n}\n"],"names":[],"mappings":";;;;AAMA,SAAS,qBAAqB,GAAA,EAAe;AAC3C,EAAA,MAAM,gBAAgB,GAAA,CAAI,aAAA;AAC1B,EAAA,OACE,CAAC,iBACD,aAAA,KAAkB,GAAA,CAAI,QACtB,aAAA,KAAkB,GAAA,CAAI,eAAA,IACtB,CAAC,aAAA,CAAc,WAAA;AAEnB;AAEA,SAAS,qBAAqB,OAAA,EAAsB;AAClD,EAAA,OAAO,qBAAA,CAAsB,OAAO,CAAA,CAAE,IAAA,EAAK;AAC7C;AAgBO,SAAS,oBAAA,CAAqB;AAAA,EACnC,QAAA;AAAA,EACA,qBAAA;AAAA,EACA,cAAA;AAAA,EACA,qBAAA;AAAA,EACA,QAAA;AAAA,EACA,2BAAA;AAAA,EACA,QAAA;AAAA,EACA,6BAAA;AAAA,EACA;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,gBAAA,GAAmB,WAAA,CAAY,QAAA,EAAU,CAAC,QAAQ,CAAC,CAAA;AAEzD,EAAA,MAAM,gBAAA,GAAmB,YAAY,MAAM;AACzC,IAAA,qBAAA,CAAsB,qBAAqB,CAAA;AAAA,EAC7C,CAAA,EAAG,CAAC,qBAAA,EAAuB,qBAAqB,CAAC,CAAA;AAEjD,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,2BAAA,EAA6B;AAC7C,MAAA;AAAA,IACF;AAEA,IAAA,qBAAA;AAAA,MACE,MAAG;AAzDT,QAAA,IAAA,EAAA;AAyDY,QAAA,OAAA,CAAA,EAAA,GAAA,cAAA,CAAe,2BAA2B,MAA1C,IAAA,GAAA,MAAA,GAAA,EAAA,CAA6C,OAAA;AAAA,MAAA;AAAA,KACrD;AAAA,EACF,CAAA,EAAG;AAAA,IACD,qBAAA;AAAA,IACA,cAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,MAAM,MAAM,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,QAAA;AAC1B,IAAA,IACE,CAAC,GAAA,IACD,QAAA,KAAa,UACb,gBAAA,KAAqB,MAAA,IACrB,aAAa,gBAAA,EACb;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,oBAAA,CAAqB,GAAG,CAAA,EAAG;AAC9B,MAAA;AAAA,IACF;AAEA,IAAA,gBAAA,EAAiB;AAAA,EACnB,GAAG,CAAC,gBAAA,EAAkB,gBAAA,EAAkB,QAAA,EAAU,YAAY,CAAC,CAAA;AAE/D,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,MAAM,uBAAuB,6BAAA,CAA8B,OAAA;AAC3D,IAAA,IACE,oBAAA,IAAwB,IAAA,IACxB,QAAA,KAAa,MAAA,IACb,aAAa,gBAAA,EACb;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,aAAa,oBAAA,EAAsB;AACrC,MAAA,6BAAA,CAA8B,OAAA,GAAU,IAAA;AACxC,MAAA;AAAA,IACF;AAEA,IAAA,gBAAA,EAAiB;AAEjB,IAAA,MAAM,cAAc,qBAAA,EAAsB;AAC1C,IAAA,MAAM,eAAA,GAAkB,WAAA,GACpB,oBAAA,CAAqB,WAAW,KAAK,QAAA,GACrC,QAAA;AAEJ,IAAA,QAAA,CAAS,CAAA,EAAG,eAAe,CAAA,uBAAA,CAAA,EAA2B,GAAG,CAAA;AACzD,IAAA,6BAAA,CAA8B,OAAA,GAAU,IAAA;AAAA,EAC1C,CAAA,EAAG;AAAA,IACD,QAAA;AAAA,IACA,qBAAA;AAAA,IACA,gBAAA;AAAA,IACA,gBAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const WIDTH_EPSILON = 0.5;
|
|
2
|
+
function getMeasuredWidth(element) {
|
|
3
|
+
if (!element) {
|
|
4
|
+
return 0;
|
|
5
|
+
}
|
|
6
|
+
const width = element.getBoundingClientRect().width;
|
|
7
|
+
return width || element.clientWidth || 0;
|
|
8
|
+
}
|
|
9
|
+
function getIntrinsicMeasuredWidth(element) {
|
|
10
|
+
if (!element) {
|
|
11
|
+
return 0;
|
|
12
|
+
}
|
|
13
|
+
const borderWidth = element.offsetWidth - element.clientWidth;
|
|
14
|
+
return Math.max(getMeasuredWidth(element), element.scrollWidth + borderWidth);
|
|
15
|
+
}
|
|
16
|
+
function getGapValue(styles) {
|
|
17
|
+
return Number.parseFloat(styles.columnGap || styles.gap || "0") || 0;
|
|
18
|
+
}
|
|
19
|
+
function seedWidthMap(elements) {
|
|
20
|
+
const widths = /* @__PURE__ */ new Map();
|
|
21
|
+
for (const element of elements) {
|
|
22
|
+
widths.set(element, getMeasuredWidth(element));
|
|
23
|
+
}
|
|
24
|
+
return widths;
|
|
25
|
+
}
|
|
26
|
+
function updateWidthMap(widths, element, nextWidth, epsilon = WIDTH_EPSILON) {
|
|
27
|
+
const previousWidth = widths.get(element);
|
|
28
|
+
widths.set(element, nextWidth);
|
|
29
|
+
if (previousWidth === void 0) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
return Math.abs(previousWidth - nextWidth) > epsilon;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { getGapValue, getIntrinsicMeasuredWidth, getMeasuredWidth, seedWidthMap, updateWidthMap };
|
|
36
|
+
//# sourceMappingURL=widthMeasurement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widthMeasurement.js","sources":["../src/tabs-next/widthMeasurement.ts"],"sourcesContent":["const WIDTH_EPSILON = 0.5;\n\nexport function getMeasuredWidth(element: HTMLElement | null | undefined) {\n if (!element) {\n return 0;\n }\n\n const width = element.getBoundingClientRect().width;\n return width || element.clientWidth || 0;\n}\n\nexport function getIntrinsicMeasuredWidth(\n element: HTMLElement | null | undefined,\n) {\n if (!element) {\n return 0;\n }\n\n const borderWidth = element.offsetWidth - element.clientWidth;\n return Math.max(getMeasuredWidth(element), element.scrollWidth + borderWidth);\n}\n\nexport function getGapValue(styles: CSSStyleDeclaration) {\n return Number.parseFloat(styles.columnGap || styles.gap || \"0\") || 0;\n}\n\nexport function seedWidthMap(elements: HTMLElement[]) {\n const widths = new Map<HTMLElement, number>();\n for (const element of elements) {\n widths.set(element, getMeasuredWidth(element));\n }\n return widths;\n}\n\nexport function updateWidthMap(\n widths: Map<HTMLElement, number>,\n element: HTMLElement,\n nextWidth: number,\n epsilon = WIDTH_EPSILON,\n) {\n const previousWidth = widths.get(element);\n widths.set(element, nextWidth);\n\n if (previousWidth === undefined) {\n return false;\n }\n\n return Math.abs(previousWidth - nextWidth) > epsilon;\n}\n"],"names":[],"mappings":"AAAA,MAAM,aAAA,GAAgB,GAAA;AAEf,SAAS,iBAAiB,OAAA,EAAyC;AACxE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,qBAAA,EAAsB,CAAE,KAAA;AAC9C,EAAA,OAAO,KAAA,IAAS,QAAQ,WAAA,IAAe,CAAA;AACzC;AAEO,SAAS,0BACd,OAAA,EACA;AACA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,CAAA;AAAA,EACT;AAEA,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,WAAA,GAAc,OAAA,CAAQ,WAAA;AAClD,EAAA,OAAO,KAAK,GAAA,CAAI,gBAAA,CAAiB,OAAO,CAAA,EAAG,OAAA,CAAQ,cAAc,WAAW,CAAA;AAC9E;AAEO,SAAS,YAAY,MAAA,EAA6B;AACvD,EAAA,OAAO,OAAO,UAAA,CAAW,MAAA,CAAO,aAAa,MAAA,CAAO,GAAA,IAAO,GAAG,CAAA,IAAK,CAAA;AACrE;AAEO,SAAS,aAAa,QAAA,EAAyB;AACpD,EAAA,MAAM,MAAA,uBAAa,GAAA,EAAyB;AAC5C,EAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,IAAA,MAAA,CAAO,GAAA,CAAI,OAAA,EAAS,gBAAA,CAAiB,OAAO,CAAC,CAAA;AAAA,EAC/C;AACA,EAAA,OAAO,MAAA;AACT;AAEO,SAAS,cAAA,CACd,MAAA,EACA,OAAA,EACA,SAAA,EACA,UAAU,aAAA,EACV;AACA,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,GAAA,CAAI,OAAO,CAAA;AACxC,EAAA,MAAA,CAAO,GAAA,CAAI,SAAS,SAAS,CAAA;AAE7B,EAAA,IAAI,kBAAkB,MAAA,EAAW;AAC/B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,aAAA,GAAgB,SAAS,CAAA,GAAI,OAAA;AAC/C;;;;"}
|
package/dist-es/tree/Tree.css.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var css_248z = ".saltTree {\n list-style: none;\n margin: 0;\n padding: 0;\n outline: none;\n width: 100%;\n box-sizing: border-box;\n}\n\n.saltTree-disabled {\n cursor: var(--salt-cursor-disabled);\n}\n";
|
|
1
|
+
var css_248z = ".saltTree {\n display: flex;\n flex-direction: column;\n gap: var(--salt-spacing-fixed-100);\n list-style: none;\n margin: 0;\n padding: 0;\n outline: none;\n width: 100%;\n box-sizing: border-box;\n}\n\n.saltTree-disabled {\n cursor: var(--salt-cursor-disabled);\n}\n";
|
|
2
2
|
|
|
3
3
|
export { css_248z as default };
|
|
4
4
|
//# sourceMappingURL=Tree.css.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var css_248z = ".saltTreeNode {\n list-style: none;\n position: relative;\n cursor: var(--salt-cursor-hover);\n}\n\n.saltTreeNode:focus {\n outline: none;\n}\n\n/* Focus visible styles - applied when keyboard navigation is used */\n.saltTreeNode:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n outline: var(--salt-focused-outline);\n position: relative;\n z-index: calc(var(--salt-zIndex-default) + 1);\n}\n\n/* Selected + focus visible */\n.saltTreeNode-selected:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-selected.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n outline: var(--salt-focused-outline);\n z-index: calc(var(--salt-zIndex-default) + 1);\n}\n\n.saltTreeNode-group {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.saltTreeNode-checkbox {\n flex-shrink: 0;\n height: var(--salt-size-selectable);\n}\n\n.saltTreeNode-icon {\n display: flex;\n align-items:
|
|
1
|
+
var css_248z = ".saltTreeNode {\n list-style: none;\n position: relative;\n cursor: var(--salt-cursor-hover);\n}\n\n.saltTreeNode:focus {\n outline: none;\n}\n\n/* Focus visible styles - applied when keyboard navigation is used */\n.saltTreeNode:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n outline: var(--salt-focused-outline);\n outline-offset: calc(var(--salt-size-fixed-100) * -2);\n position: relative;\n z-index: calc(var(--salt-zIndex-default) + 1);\n}\n\n/* Selected + focus visible */\n.saltTreeNode-selected:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-selected.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n outline: var(--salt-focused-outline);\n outline-offset: calc(var(--salt-size-fixed-100) * -2);\n z-index: calc(var(--salt-zIndex-default) + 1);\n}\n\n.saltTreeNode-group {\n display: flex;\n flex-direction: column;\n gap: var(--salt-spacing-fixed-100);\n list-style: none;\n margin: 0;\n padding: 0;\n padding-top: var(--salt-spacing-fixed-100);\n}\n\n.saltTreeNode-checkbox {\n flex-shrink: 0;\n height: var(--salt-size-selectable);\n}\n\n.saltTreeNode-icon {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: var(--salt-size-selectable);\n min-width: var(--salt-size-selectable);\n height: var(--salt-size-selectable);\n flex-shrink: 0;\n}\n\n.saltTreeNode-icon > * {\n color: var(--salt-content-primary-foreground);\n}\n";
|
|
2
2
|
|
|
3
3
|
export { css_248z as default };
|
|
4
4
|
//# sourceMappingURL=TreeNode.css.js.map
|
package/dist-es/tree/TreeNode.js
CHANGED
|
@@ -86,7 +86,7 @@ const TreeNode = forwardRef(
|
|
|
86
86
|
]
|
|
87
87
|
);
|
|
88
88
|
const defaultContent = usesLabelProp ? /* @__PURE__ */ jsxs(TreeNodeTrigger, { children: [
|
|
89
|
-
Icon ? /* @__PURE__ */ jsx(Icon, { "aria-hidden": true
|
|
89
|
+
Icon ? /* @__PURE__ */ jsx("span", { className: withBaseName("icon"), children: /* @__PURE__ */ jsx(Icon, { "aria-hidden": true }) }) : null,
|
|
90
90
|
/* @__PURE__ */ jsx(TreeNodeLabel, { children: label })
|
|
91
91
|
] }) : null;
|
|
92
92
|
return /* @__PURE__ */ jsx(TreeNodeProvider, { value: nodeContext, children: usesLabelProp ? defaultContent : contentChildren });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNode.js","sources":["../src/tree/TreeNode.tsx"],"sourcesContent":["import { makePrefixer, useId } from \"@salt-ds/core\";\nimport type { IconProps } from \"@salt-ds/icons\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n Children,\n type ComponentType,\n forwardRef,\n isValidElement,\n type ReactNode,\n useImperativeHandle,\n useMemo,\n} from \"react\";\nimport {\n TreeNodeProvider,\n useTreeContext,\n useTreeNodeContext,\n} from \"./TreeContext\";\nimport treeNodeCss from \"./TreeNode.css\";\nimport { TreeNodeLabel } from \"./TreeNodeLabel\";\nimport { TreeNodeTrigger } from \"./TreeNodeTrigger\";\n\nexport interface TreeNodeProps {\n /**\n * Unique value representing this node within the tree\n */\n value: string;\n /**\n * Label for the node. When provided, TreeNode automatically renders a TreeNodeTrigger.\n */\n label?: ReactNode;\n /**\n * Optional icon to display before the label\n */\n icon?: ComponentType<IconProps>;\n /**\n * Whether the node is disabled.\n */\n disabled?: boolean;\n /**\n * Child nodes or content.\n */\n children?: ReactNode;\n}\n\nconst withBaseName = makePrefixer(\"saltTreeNode\");\n\n// Need to take another look at this because its slightly brittle - alternative could be:\n// TreeNode having a 'content' prop that takes <TreeNodeTrigger> etc. and then `children` is reserved for other <TreeNode>'s\n// or a 'render' prop if we want to pass any state down. Simplifies it massively because then its clear children is for sub trees.\nfunction separateChildren(children: ReactNode): {\n contentChildren: ReactNode[];\n nodeChildren: ReactNode[];\n} {\n const contentChildren: ReactNode[] = [];\n const nodeChildren: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (isValidElement(child) && typeof child.props.value === \"string\") {\n nodeChildren.push(child);\n } else if (child != null) {\n contentChildren.push(child);\n }\n });\n\n return { contentChildren, nodeChildren };\n}\n\nexport const TreeNode = forwardRef<HTMLLIElement, TreeNodeProps>(\n function TreeNode(props, ref) {\n const {\n value,\n label,\n icon: Icon,\n disabled: disabledProp,\n children,\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree-node\",\n css: treeNodeCss,\n window: targetWindow,\n });\n\n const id = useId(value) ?? value;\n\n const {\n expandedState,\n selectedSet,\n disabled: treeDisabled,\n disabledIdsSet,\n indeterminateState,\n getElement,\n } = useTreeContext();\n\n const parentContext = useTreeNodeContext();\n const level = (parentContext?.level ?? 0) + 1;\n\n const disabled = treeDisabled || disabledProp || disabledIdsSet.has(value);\n const expanded = expandedState.has(value);\n const selected = selectedSet.has(value);\n const indeterminate = indeterminateState.has(value);\n\n const usesLabelProp = label !== undefined;\n const { contentChildren, nodeChildren } = useMemo(\n () =>\n usesLabelProp\n ? { contentChildren: [], nodeChildren: Children.toArray(children) }\n : separateChildren(children),\n [children, usesLabelProp],\n );\n\n const hasChildren = nodeChildren.length > 0;\n\n // Forward ref to the <li> element rendered by TreeNodeTrigger\n useImperativeHandle(ref, () => getElement(value) as HTMLLIElement, [\n getElement,\n value,\n ]);\n\n const nodeContext = useMemo(\n () => ({\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n }),\n [\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n ],\n );\n\n const defaultContent = usesLabelProp ? (\n <TreeNodeTrigger>\n {Icon ? <
|
|
1
|
+
{"version":3,"file":"TreeNode.js","sources":["../src/tree/TreeNode.tsx"],"sourcesContent":["import { makePrefixer, useId } from \"@salt-ds/core\";\nimport type { IconProps } from \"@salt-ds/icons\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n Children,\n type ComponentType,\n forwardRef,\n isValidElement,\n type ReactNode,\n useImperativeHandle,\n useMemo,\n} from \"react\";\nimport {\n TreeNodeProvider,\n useTreeContext,\n useTreeNodeContext,\n} from \"./TreeContext\";\nimport treeNodeCss from \"./TreeNode.css\";\nimport { TreeNodeLabel } from \"./TreeNodeLabel\";\nimport { TreeNodeTrigger } from \"./TreeNodeTrigger\";\n\nexport interface TreeNodeProps {\n /**\n * Unique value representing this node within the tree\n */\n value: string;\n /**\n * Label for the node. When provided, TreeNode automatically renders a TreeNodeTrigger.\n */\n label?: ReactNode;\n /**\n * Optional icon to display before the label\n */\n icon?: ComponentType<IconProps>;\n /**\n * Whether the node is disabled.\n */\n disabled?: boolean;\n /**\n * Child nodes or content.\n */\n children?: ReactNode;\n}\n\nconst withBaseName = makePrefixer(\"saltTreeNode\");\n\n// Need to take another look at this because its slightly brittle - alternative could be:\n// TreeNode having a 'content' prop that takes <TreeNodeTrigger> etc. and then `children` is reserved for other <TreeNode>'s\n// or a 'render' prop if we want to pass any state down. Simplifies it massively because then its clear children is for sub trees.\nfunction separateChildren(children: ReactNode): {\n contentChildren: ReactNode[];\n nodeChildren: ReactNode[];\n} {\n const contentChildren: ReactNode[] = [];\n const nodeChildren: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (isValidElement(child) && typeof child.props.value === \"string\") {\n nodeChildren.push(child);\n } else if (child != null) {\n contentChildren.push(child);\n }\n });\n\n return { contentChildren, nodeChildren };\n}\n\nexport const TreeNode = forwardRef<HTMLLIElement, TreeNodeProps>(\n function TreeNode(props, ref) {\n const {\n value,\n label,\n icon: Icon,\n disabled: disabledProp,\n children,\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree-node\",\n css: treeNodeCss,\n window: targetWindow,\n });\n\n const id = useId(value) ?? value;\n\n const {\n expandedState,\n selectedSet,\n disabled: treeDisabled,\n disabledIdsSet,\n indeterminateState,\n getElement,\n } = useTreeContext();\n\n const parentContext = useTreeNodeContext();\n const level = (parentContext?.level ?? 0) + 1;\n\n const disabled = treeDisabled || disabledProp || disabledIdsSet.has(value);\n const expanded = expandedState.has(value);\n const selected = selectedSet.has(value);\n const indeterminate = indeterminateState.has(value);\n\n const usesLabelProp = label !== undefined;\n const { contentChildren, nodeChildren } = useMemo(\n () =>\n usesLabelProp\n ? { contentChildren: [], nodeChildren: Children.toArray(children) }\n : separateChildren(children),\n [children, usesLabelProp],\n );\n\n const hasChildren = nodeChildren.length > 0;\n\n // Forward ref to the <li> element rendered by TreeNodeTrigger\n useImperativeHandle(ref, () => getElement(value) as HTMLLIElement, [\n getElement,\n value,\n ]);\n\n const nodeContext = useMemo(\n () => ({\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n }),\n [\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n ],\n );\n\n const defaultContent = usesLabelProp ? (\n <TreeNodeTrigger>\n {Icon ? (\n <span className={withBaseName(\"icon\")}>\n <Icon aria-hidden />\n </span>\n ) : null}\n <TreeNodeLabel>{label}</TreeNodeLabel>\n </TreeNodeTrigger>\n ) : null;\n\n return (\n <TreeNodeProvider value={nodeContext}>\n {usesLabelProp ? defaultContent : contentChildren}\n </TreeNodeProvider>\n );\n },\n);\n"],"names":["TreeNode","treeNodeCss"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var css_248z = ".saltTreeNodeExpansionIcon {\n display: flex;\n align-items:
|
|
1
|
+
var css_248z = ".saltTreeNodeExpansionIcon {\n display: flex;\n align-items: flex-start;\n justify-content: center;\n width: var(--salt-size-selectable);\n min-width: var(--salt-size-selectable);\n height: var(--salt-size-selectable);\n flex-shrink: 0;\n position: relative;\n}\n\n.saltTreeNodeExpansionIcon-icon {\n color: var(--salt-content-primary-foreground);\n}\n\n.saltTreeNodeExpansionIcon::before {\n content: \"\";\n display: block;\n position: absolute;\n width: var(--salt-size-base);\n height: var(--salt-size-base);\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n";
|
|
2
2
|
|
|
3
3
|
export { css_248z as default };
|
|
4
4
|
//# sourceMappingURL=TreeNodeExpansionIcon.css.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var css_248z = ".saltTreeNodeTrigger {\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n gap: var(--salt-spacing-100);\n width: 100%;\n min-height: var(--salt-size-base);\n\n padding-top: calc((var(--salt-size-base) - var(--salt-size-selectable)) / 2);\n padding-bottom: calc((var(--salt-size-base) - var(--salt-size-selectable)) / 2);\n padding-right: var(--salt-spacing-100);\n /*
|
|
1
|
+
var css_248z = ".saltTreeNodeTrigger {\n box-sizing: border-box;\n display: flex;\n align-items: flex-start;\n gap: var(--salt-spacing-100);\n width: 100%;\n min-height: var(--salt-size-base);\n\n padding-top: calc((var(--salt-size-base) - var(--salt-size-selectable)) / 2);\n padding-bottom: calc((var(--salt-size-base) - var(--salt-size-selectable)) / 2);\n padding-right: var(--salt-spacing-100);\n /* Keep a fixed spacing-100 outer left padding for all nodes, then add one\n indent step per additional level. Each indent step = (selectable element\n width + inter-item gap).\n Level-1 nodes get no extra indent; level-2 gets 1 step, level-3 gets 2, etc.\n */\n --saltTreeNodeTrigger-indentStep: calc(var(--salt-size-selectable) + var(--salt-spacing-100));\n /* Icons clamp to 12px minimum in Icon, so align against the rendered size. */\n --saltTreeNodeTrigger-iconOffsetY: calc((var(--salt-text-lineHeight) - max(var(--salt-size-icon), 12px)) / 2);\n --saltTreeNodeTrigger-directIconInsetX: max(0px, calc((var(--salt-size-selectable) - max(var(--salt-size-icon), 12px)) / 2));\n padding-left: calc(var(--salt-spacing-100) + (var(--saltTreeNodeTrigger-indentStep) * (var(--saltTreeNode-level, 1) - 1)));\n background: var(--salt-selectable-background);\n color: var(--salt-content-primary-foreground);\n}\n\n.saltTreeNodeTrigger:hover {\n background: var(--salt-selectable-background-hover);\n}\n\n.saltTreeNode:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n background: var(--salt-selectable-background-hover);\n}\n\n.saltTreeNode-selected > .saltTreeNodeTrigger {\n background: var(--salt-selectable-background-selected);\n box-shadow:\n 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),\n 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);\n position: relative;\n z-index: var(--salt-zIndex-default);\n}\n\n.saltTreeNode-selected:focus-visible > .saltTreeNodeTrigger,\n.saltTreeNode-selected.saltTreeNode-focusVisible > .saltTreeNodeTrigger {\n background: var(--salt-selectable-background-selected);\n}\n\n.saltTreeNode-disabled > .saltTreeNodeTrigger,\n.saltTreeNode-disabled:hover > .saltTreeNodeTrigger {\n opacity: 0.4;\n cursor: var(--salt-cursor-disabled);\n\n background: var(--salt-selectable-background);\n color: var(--salt-content-primary-foreground);\n}\n\n.saltTreeNodeTrigger > .saltTreeNode-checkbox {\n margin-block: calc((var(--salt-text-lineHeight) - var(--salt-size-selectable)) / 2);\n}\n\n.saltTreeNodeTrigger > .saltTreeNodeExpansionIcon > .saltTreeNodeExpansionIcon-icon,\n.saltTreeNodeTrigger > .saltTreeNode-icon > .saltIcon {\n --saltIcon-margin: var(--saltTreeNodeTrigger-iconOffsetY) 0 0 0;\n}\n\n.saltTreeNodeTrigger > .saltIcon {\n --saltIcon-margin: var(--saltTreeNodeTrigger-iconOffsetY) 0 0 0;\n box-sizing: content-box;\n padding-inline: var(--saltTreeNodeTrigger-directIconInsetX);\n flex-shrink: 0;\n color: var(--salt-content-primary-foreground);\n}\n";
|
|
2
2
|
|
|
3
3
|
export { css_248z as default };
|
|
4
4
|
//# sourceMappingURL=TreeNodeTrigger.css.js.map
|
|
@@ -75,8 +75,8 @@ const TreeNodeTrigger = forwardRef(function TreeNodeTrigger2(props, ref) {
|
|
|
75
75
|
select(event, value);
|
|
76
76
|
};
|
|
77
77
|
const handleFocus = (event) => {
|
|
78
|
-
onFocus == null ? void 0 : onFocus(event);
|
|
79
78
|
if (event.target !== event.currentTarget) return;
|
|
79
|
+
onFocus == null ? void 0 : onFocus(event);
|
|
80
80
|
if (!wasMouseDownRef.current) {
|
|
81
81
|
setFocusVisible(true);
|
|
82
82
|
}
|
|
@@ -84,8 +84,8 @@ const TreeNodeTrigger = forwardRef(function TreeNodeTrigger2(props, ref) {
|
|
|
84
84
|
setActiveNode(value);
|
|
85
85
|
};
|
|
86
86
|
const handleBlur = (event) => {
|
|
87
|
-
onBlur == null ? void 0 : onBlur(event);
|
|
88
87
|
if (event.target !== event.currentTarget) return;
|
|
88
|
+
onBlur == null ? void 0 : onBlur(event);
|
|
89
89
|
setFocusVisible(false);
|
|
90
90
|
};
|
|
91
91
|
const handleMouseDown = (event) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNodeTrigger.js","sources":["../src/tree/TreeNodeTrigger.tsx"],"sourcesContent":["import { CheckboxIcon, makePrefixer, useForkRef } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type FocusEvent,\n forwardRef,\n type MouseEvent,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useTreeContext, useTreeNodeContext } from \"./TreeContext\";\nimport { TreeNodeExpansionIcon } from \"./TreeNodeExpansionIcon\";\nimport treeNodeTriggerCss from \"./TreeNodeTrigger.css\";\n\nexport interface TreeNodeTriggerProps extends ComponentPropsWithoutRef<\"li\"> {}\n\nconst withBaseName = makePrefixer(\"saltTreeNodeTrigger\");\nconst withNodeBaseName = makePrefixer(\"saltTreeNode\");\n\n/**\n * The forwarded ref points to the inner trigger content span (for tooltip positioning),\n * while the <li> handles focus, ARIA, and event handling.\n */\nexport const TreeNodeTrigger = forwardRef<\n HTMLSpanElement,\n TreeNodeTriggerProps\n>(function TreeNodeTrigger(props, ref) {\n const {\n className,\n children,\n style,\n onClick,\n onFocus,\n onBlur,\n onMouseDown,\n onKeyDown,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree-node-trigger\",\n css: treeNodeTriggerCss,\n window: targetWindow,\n });\n\n const nodeContext = useTreeNodeContext();\n if (!nodeContext) {\n throw new Error(\"TreeNodeTrigger must be used within a TreeNode\");\n }\n\n const {\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n } = nodeContext;\n\n const {\n multiselect,\n activeNode,\n setActiveNode,\n select,\n tabbableNodeId,\n registerElement,\n } = useTreeContext();\n\n const nodeRef = useRef<HTMLLIElement>(null);\n const triggerContentRef = useForkRef(useRef<HTMLSpanElement>(null), ref);\n const wasMouseDownRef = useRef(false);\n const [focusVisible, setFocusVisible] = useState(false);\n\n const isActive = activeNode === value;\n\n const isTabbable = tabbableNodeId === value;\n\n useEffect(() => {\n if (nodeRef.current) {\n return registerElement(value, nodeRef.current);\n }\n }, [value, registerElement]);\n\n const handleClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n if (disabled) return;\n const target = event.target as HTMLElement;\n if (target.closest(\".saltTreeNodeExpansionIcon\")) return;\n const nestedTreeItem = target.closest('[role=\"treeitem\"]');\n if (nestedTreeItem && nestedTreeItem !== nodeRef.current) {\n return;\n }\n setActiveNode(value);\n select(event, value);\n };\n\n const handleFocus = (event: FocusEvent<HTMLLIElement>) => {\n
|
|
1
|
+
{"version":3,"file":"TreeNodeTrigger.js","sources":["../src/tree/TreeNodeTrigger.tsx"],"sourcesContent":["import { CheckboxIcon, makePrefixer, useForkRef } from \"@salt-ds/core\";\nimport { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type FocusEvent,\n forwardRef,\n type MouseEvent,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { useTreeContext, useTreeNodeContext } from \"./TreeContext\";\nimport { TreeNodeExpansionIcon } from \"./TreeNodeExpansionIcon\";\nimport treeNodeTriggerCss from \"./TreeNodeTrigger.css\";\n\nexport interface TreeNodeTriggerProps extends ComponentPropsWithoutRef<\"li\"> {}\n\nconst withBaseName = makePrefixer(\"saltTreeNodeTrigger\");\nconst withNodeBaseName = makePrefixer(\"saltTreeNode\");\n\n/**\n * The forwarded ref points to the inner trigger content span (for tooltip positioning),\n * while the <li> handles focus, ARIA, and event handling.\n */\nexport const TreeNodeTrigger = forwardRef<\n HTMLSpanElement,\n TreeNodeTriggerProps\n>(function TreeNodeTrigger(props, ref) {\n const {\n className,\n children,\n style,\n onClick,\n onFocus,\n onBlur,\n onMouseDown,\n onKeyDown,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-tree-node-trigger\",\n css: treeNodeTriggerCss,\n window: targetWindow,\n });\n\n const nodeContext = useTreeNodeContext();\n if (!nodeContext) {\n throw new Error(\"TreeNodeTrigger must be used within a TreeNode\");\n }\n\n const {\n value,\n level,\n hasChildren,\n expanded,\n disabled,\n id,\n selected,\n indeterminate,\n nodeChildren,\n } = nodeContext;\n\n const {\n multiselect,\n activeNode,\n setActiveNode,\n select,\n tabbableNodeId,\n registerElement,\n } = useTreeContext();\n\n const nodeRef = useRef<HTMLLIElement>(null);\n const triggerContentRef = useForkRef(useRef<HTMLSpanElement>(null), ref);\n const wasMouseDownRef = useRef(false);\n const [focusVisible, setFocusVisible] = useState(false);\n\n const isActive = activeNode === value;\n\n const isTabbable = tabbableNodeId === value;\n\n useEffect(() => {\n if (nodeRef.current) {\n return registerElement(value, nodeRef.current);\n }\n }, [value, registerElement]);\n\n const handleClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n if (disabled) return;\n const target = event.target as HTMLElement;\n if (target.closest(\".saltTreeNodeExpansionIcon\")) return;\n const nestedTreeItem = target.closest('[role=\"treeitem\"]');\n if (nestedTreeItem && nestedTreeItem !== nodeRef.current) {\n return;\n }\n setActiveNode(value);\n select(event, value);\n };\n\n const handleFocus = (event: FocusEvent<HTMLLIElement>) => {\n if (event.target !== event.currentTarget) return;\n onFocus?.(event);\n if (!wasMouseDownRef.current) {\n setFocusVisible(true);\n }\n wasMouseDownRef.current = false;\n setActiveNode(value);\n };\n\n const handleBlur = (event: FocusEvent<HTMLLIElement>) => {\n if (event.target !== event.currentTarget) return;\n onBlur?.(event);\n setFocusVisible(false);\n };\n\n const handleMouseDown = (event: MouseEvent<HTMLLIElement>) => {\n wasMouseDownRef.current = true;\n onMouseDown?.(event);\n };\n\n return (\n <li\n ref={nodeRef}\n id={id}\n role=\"treeitem\"\n aria-expanded={hasChildren ? expanded : undefined}\n aria-selected={multiselect ? undefined : selected}\n aria-checked={\n multiselect ? (indeterminate ? \"mixed\" : selected) : undefined\n }\n aria-level={level}\n aria-disabled={disabled || undefined}\n tabIndex={isTabbable ? 0 : -1}\n className={clsx(\n withNodeBaseName(),\n {\n [withNodeBaseName(\"expanded\")]: expanded,\n [withNodeBaseName(\"selected\")]: selected && !multiselect,\n [withNodeBaseName(\"active\")]: isActive,\n [withNodeBaseName(\"disabled\")]: disabled,\n [withNodeBaseName(\"hasChildren\")]: hasChildren,\n [withNodeBaseName(\"focusVisible\")]: focusVisible,\n },\n className,\n )}\n style={\n {\n \"--saltTreeNode-level\": level,\n ...style,\n } as CSSProperties\n }\n onClick={handleClick}\n onFocus={handleFocus}\n onBlur={handleBlur}\n onMouseDown={handleMouseDown}\n onKeyDown={onKeyDown}\n {...rest}\n >\n <span ref={triggerContentRef} className={withBaseName()}>\n <TreeNodeExpansionIcon />\n {multiselect && (\n <CheckboxIcon\n checked={selected}\n indeterminate={indeterminate}\n disabled={disabled}\n className={withNodeBaseName(\"checkbox\")}\n />\n )}\n {children}\n </span>\n\n {hasChildren && expanded && (\n <ul role=\"group\" className={withNodeBaseName(\"group\")}>\n {nodeChildren}\n </ul>\n )}\n </li>\n );\n});\n"],"names":["TreeNodeTrigger","treeNodeTriggerCss"],"mappings":"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"}
|
|
@@ -5,12 +5,12 @@ function useEventCallback(fn) {
|
|
|
5
5
|
const ref = useRef(fn);
|
|
6
6
|
useIsomorphicLayoutEffect(() => {
|
|
7
7
|
ref.current = fn;
|
|
8
|
-
});
|
|
8
|
+
}, [fn]);
|
|
9
9
|
return useCallback(
|
|
10
|
-
(...args) =>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
),
|
|
10
|
+
((...args) => {
|
|
11
|
+
const latestFn = ref.current;
|
|
12
|
+
return latestFn(...args);
|
|
13
|
+
}),
|
|
14
14
|
[]
|
|
15
15
|
);
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEventCallback.js","sources":["../src/utils/useEventCallback.ts"],"sourcesContent":["import { useIsomorphicLayoutEffect } from \"@salt-ds/core\";\nimport { useCallback, useRef } from \"react\";\n\n/**\n * https://github.com/facebook/react/issues/14099#issuecomment-440013892\n */\nexport function useEventCallback<
|
|
1
|
+
{"version":3,"file":"useEventCallback.js","sources":["../src/utils/useEventCallback.ts"],"sourcesContent":["import { useIsomorphicLayoutEffect } from \"@salt-ds/core\";\nimport { useCallback, useRef } from \"react\";\n\n/**\n * https://github.com/facebook/react/issues/14099#issuecomment-440013892\n */\nexport function useEventCallback<const T extends (...args: any[]) => void>(\n fn: T,\n): T {\n const ref = useRef<T>(fn);\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback(\n ((...args: any[]) => {\n const latestFn = ref.current;\n return latestFn(...args);\n }) as T,\n [],\n );\n}\n"],"names":[],"mappings":";;;AAMO,SAAS,iBACd,EAAA,EACG;AACH,EAAA,MAAM,GAAA,GAAM,OAAU,EAAE,CAAA;AAExB,EAAA,yBAAA,CAA0B,MAAM;AAC9B,IAAA,GAAA,CAAI,OAAA,GAAU,EAAA;AAAA,EAChB,CAAA,EAAG,CAAC,EAAE,CAAC,CAAA;AAEP,EAAA,OAAO,WAAA;AAAA,KACJ,IAAI,IAAA,KAAgB;AACnB,MAAA,MAAM,WAAW,GAAA,CAAI,OAAA;AACrB,MAAA,OAAO,QAAA,CAAS,GAAG,IAAI,CAAA;AAAA,IACzB,CAAA;AAAA,IACA;AAAC,GACH;AACF;;;;"}
|
|
@@ -12,5 +12,5 @@ interface useMenuTriggerHandlersProps {
|
|
|
12
12
|
rootMenuId: string | undefined;
|
|
13
13
|
menusDataById: Record<string, menuState>;
|
|
14
14
|
}
|
|
15
|
-
export declare function useMenuTriggerHandlers({ dispatch, children, setIsNavigatingWithKeyboard, openCloseMenu, rootMenuState, rootMenuId, menusDataById, }: useMenuTriggerHandlersProps): readonly [(event: MouseEvent<HTMLElement
|
|
15
|
+
export declare function useMenuTriggerHandlers({ dispatch, children, setIsNavigatingWithKeyboard, openCloseMenu, rootMenuState, rootMenuId, menusDataById, }: useMenuTriggerHandlersProps): readonly [(event: MouseEvent<HTMLElement>) => void, (event: KeyboardEvent<HTMLElement>) => void];
|
|
16
16
|
export {};
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
interface ListStateContextValue {
|
|
2
|
+
state: any;
|
|
3
|
+
helpers: any;
|
|
4
|
+
}
|
|
5
|
+
export declare const ListStateContext: import("react").Context<ListStateContextValue | undefined>;
|
|
6
|
+
export declare const useListStateContext: () => ListStateContextValue;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type TabSlotLocation = "hidden" | "main" | "overflow";
|
|
2
|
+
export interface TabListLayoutContextValue {
|
|
3
|
+
getLocation: (value: string) => TabSlotLocation;
|
|
4
|
+
overflowActiveValue: string | null;
|
|
5
|
+
setOverflowActiveValue: (value: string | null) => void;
|
|
6
|
+
moveOverflowFocus: (key: "ArrowDown" | "ArrowUp" | "Home" | "End", value: string) => boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare const TabListLayoutContext: import("react").Context<TabListLayoutContextValue | null>;
|
|
9
|
+
export declare function useTabListLayout(): TabListLayoutContextValue | null;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ComponentPropsWithoutRef } from "react";
|
|
2
2
|
export interface TabNextPanelProps extends ComponentPropsWithoutRef<"div"> {
|
|
3
3
|
/**
|
|
4
|
-
* The value of the panel
|
|
4
|
+
* The value of the panel. This should map to the corresponding tab and must
|
|
5
|
+
* be unique within a `TabsNext` instance.
|
|
5
6
|
*/
|
|
6
7
|
value: string;
|
|
7
8
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { type ComponentPropsWithoutRef, type Dispatch, type
|
|
1
|
+
import { type ComponentPropsWithoutRef, type Dispatch, type Ref, type SetStateAction } from "react";
|
|
2
2
|
interface TabOverflowListProps extends ComponentPropsWithoutRef<"button"> {
|
|
3
3
|
buttonRef?: Ref<HTMLButtonElement>;
|
|
4
|
-
|
|
5
|
-
children?: ReactNode;
|
|
6
|
-
isMeasuring?: boolean;
|
|
4
|
+
hiddenValues: string[];
|
|
7
5
|
open: boolean;
|
|
8
6
|
setOpen: Dispatch<SetStateAction<boolean>>;
|
|
7
|
+
order: number;
|
|
9
8
|
}
|
|
10
9
|
export declare const TabOverflowList: import("react").ForwardRefExoticComponent<TabOverflowListProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
11
10
|
export {};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ComponentPropsWithoutRef } from "react";
|
|
2
|
+
export interface TabSlotProps extends ComponentPropsWithoutRef<"div"> {
|
|
3
|
+
slotId: string;
|
|
4
|
+
value: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function TabSlot({ slotId, value, ...rest }: TabSlotProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export interface TabSlotRegistryContextValue {
|
|
2
|
+
registerSlot: (slotId: string, element: HTMLDivElement | null) => void;
|
|
3
|
+
}
|
|
4
|
+
export declare const TabSlotRegistryContext: import("react").Context<TabSlotRegistryContextValue | null>;
|
|
5
|
+
export declare function useTabSlotRegistry(): TabSlotRegistryContextValue | null;
|
|
@@ -10,7 +10,8 @@ export interface TabsNextProps extends Omit<ComponentPropsWithoutRef<"div">, "on
|
|
|
10
10
|
*/
|
|
11
11
|
value?: string;
|
|
12
12
|
/**
|
|
13
|
-
* Callback fired when the selection changes. The event will be null when
|
|
13
|
+
* Callback fired when the selection changes. The event will be null when
|
|
14
|
+
* selection is moved automatically.
|
|
14
15
|
*/
|
|
15
16
|
onChange?: (event: SyntheticEvent | null, value: string) => void;
|
|
16
17
|
}
|
|
@@ -3,17 +3,39 @@ import type { useCollection } from "./hooks/useCollection";
|
|
|
3
3
|
export interface Item {
|
|
4
4
|
id: string;
|
|
5
5
|
value: string;
|
|
6
|
-
element: HTMLElement;
|
|
6
|
+
element: HTMLElement | null;
|
|
7
|
+
location?: "hidden" | "main" | "overflow";
|
|
8
|
+
order?: number;
|
|
7
9
|
}
|
|
8
|
-
export interface
|
|
10
|
+
export interface RenderedTab {
|
|
11
|
+
host: HTMLDivElement;
|
|
12
|
+
id: string;
|
|
13
|
+
marker: HTMLElement | null;
|
|
14
|
+
root: HTMLElement | null;
|
|
15
|
+
trigger: HTMLButtonElement | null;
|
|
16
|
+
value: string;
|
|
17
|
+
width: number;
|
|
18
|
+
}
|
|
19
|
+
export type TabsNextRenderMode = "inline" | "portal";
|
|
20
|
+
export interface TabsNextContextValue extends Omit<ReturnType<typeof useCollection>, "registerItem" | "updateItem"> {
|
|
21
|
+
renderMode: TabsNextRenderMode;
|
|
22
|
+
registerBootstrapTab: (value: string) => () => void;
|
|
23
|
+
setBootstrapTabReady: (value: string, ready: boolean) => void;
|
|
24
|
+
setBootstrapOverflowReady: (ready: boolean) => void;
|
|
9
25
|
registerTab: (item: Item) => () => void;
|
|
26
|
+
updateTab: (id: string, updates: Partial<Omit<Item, "id" | "value">>) => void;
|
|
27
|
+
registerRenderedTab: (tab: RenderedTab) => () => void;
|
|
28
|
+
updateRenderedTab: (value: string, updates: Partial<Omit<RenderedTab, "value">>) => void;
|
|
29
|
+
getRenderedTab: (value: string) => RenderedTab | undefined;
|
|
30
|
+
getRenderedTabOrder: (value: string) => number;
|
|
31
|
+
renderedTabs: RenderedTab[];
|
|
10
32
|
registerPanel: (id: string, value: string) => () => void;
|
|
11
33
|
getPanelId: (value: string) => string | undefined;
|
|
12
34
|
getTabId: (value: string) => string | undefined;
|
|
13
35
|
selected?: string;
|
|
14
|
-
setSelected: (event: SyntheticEvent, value: string) => void;
|
|
36
|
+
setSelected: (event: SyntheticEvent | null, value: string, source?: "main" | "overflow") => void;
|
|
15
37
|
activeTab: MutableRefObject<Pick<Item, "id" | "value"> | undefined>;
|
|
16
|
-
|
|
38
|
+
selectionFromOverflowValueRef: MutableRefObject<string | null>;
|
|
17
39
|
menuOpen: boolean;
|
|
18
40
|
setMenuOpen: Dispatch<SetStateAction<boolean>>;
|
|
19
41
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isHTMLElement(node: unknown): node is HTMLElement;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const MIN_TRUSTED_TAB_WIDTH = 0.5;
|
|
2
|
+
export interface MeasuredOverflowTab {
|
|
3
|
+
value: string;
|
|
4
|
+
width: number | null;
|
|
5
|
+
}
|
|
6
|
+
interface CalculateVisibleCountProps {
|
|
7
|
+
gap: number;
|
|
8
|
+
maxWidth: number;
|
|
9
|
+
overflowWidth: number;
|
|
10
|
+
pinnedValue?: string;
|
|
11
|
+
tabs: MeasuredOverflowTab[];
|
|
12
|
+
}
|
|
13
|
+
export declare function calculateVisibleCount({ gap, maxWidth: initialMaxWidth, overflowWidth, pinnedValue, tabs, }: CalculateVisibleCountProps): number | null;
|
|
14
|
+
export declare function partitionVisibleValues(orderedValues: string[], visibleCount: number, pinnedValue?: string): {
|
|
15
|
+
visibleValues: string[];
|
|
16
|
+
hiddenValues: string[];
|
|
17
|
+
};
|
|
18
|
+
export {};
|
|
@@ -2,17 +2,29 @@ export interface Item {
|
|
|
2
2
|
id: string;
|
|
3
3
|
element?: HTMLElement | null;
|
|
4
4
|
value: string;
|
|
5
|
+
location?: "hidden" | "main" | "overflow";
|
|
6
|
+
order?: number;
|
|
7
|
+
stale?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface StaleItem extends Item {
|
|
10
|
+
staleIndex?: number;
|
|
5
11
|
}
|
|
6
12
|
interface UseCollectionProps {
|
|
13
|
+
targetWindow: Window | null | undefined;
|
|
7
14
|
wrap: boolean;
|
|
8
15
|
}
|
|
9
|
-
export declare function useCollection({ wrap }: UseCollectionProps): {
|
|
10
|
-
registerItem: (item: Item) => () =>
|
|
16
|
+
export declare function useCollection({ wrap, targetWindow }: UseCollectionProps): {
|
|
17
|
+
registerItem: (item: Item) => () => void;
|
|
11
18
|
item: (id?: string | null) => Item | null;
|
|
12
19
|
getNext: (current: string) => Item | null;
|
|
13
20
|
getPrevious: (current: string) => Item | null;
|
|
14
21
|
getFirst: () => Item | null;
|
|
15
22
|
getLast: () => Item | null;
|
|
16
|
-
|
|
23
|
+
getIndex: (current: string) => number;
|
|
24
|
+
itemAt: (index: number) => Item | null;
|
|
25
|
+
updateItem: (id: string, updates: Partial<Omit<Item, "id" | "value">>) => void;
|
|
26
|
+
getRemovedItems: () => Map<string, StaleItem>;
|
|
27
|
+
removalVersion: number;
|
|
28
|
+
sortItems: () => void;
|
|
17
29
|
};
|
|
18
30
|
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface UseFocusWithRetryArgs {
|
|
2
|
+
maxAttempts?: number;
|
|
3
|
+
targetWindow: Window | null | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare function useFocusWithRetry({ maxAttempts, targetWindow, }: UseFocusWithRetryArgs): {
|
|
6
|
+
cancelScheduledFocus: () => void;
|
|
7
|
+
focusElementWithRetry: (getElement: () => HTMLElement | null | undefined) => void;
|
|
8
|
+
};
|
|
9
|
+
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type {
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import type { RenderedTab } from "../TabsNextContext";
|
|
3
3
|
interface UseOverflowProps {
|
|
4
4
|
container: RefObject<HTMLElement>;
|
|
5
5
|
selected?: string;
|
|
6
|
-
|
|
7
|
-
tabs: Item[];
|
|
6
|
+
tabs: RenderedTab[];
|
|
8
7
|
overflowButton: RefObject<HTMLButtonElement>;
|
|
8
|
+
menuOpen: boolean;
|
|
9
9
|
}
|
|
10
|
-
export declare function useOverflow({
|
|
10
|
+
export declare function useOverflow({ container, overflowButton, tabs, selected, menuOpen, }: UseOverflowProps): readonly [string[], string[], boolean];
|
|
11
11
|
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TabListLayoutContextValue } from "../TabListLayoutContext";
|
|
2
|
+
interface UseOverflowLayoutStateArgs {
|
|
3
|
+
hiddenValues: string[];
|
|
4
|
+
menuOpen: boolean;
|
|
5
|
+
overflowMenuOpen: boolean;
|
|
6
|
+
visibleValues: string[];
|
|
7
|
+
}
|
|
8
|
+
interface UseOverflowLayoutStateResult {
|
|
9
|
+
resolvedOverflowActiveValue: string | null;
|
|
10
|
+
tabListLayoutContext: TabListLayoutContextValue;
|
|
11
|
+
}
|
|
12
|
+
export declare function useOverflowLayoutState({ hiddenValues, menuOpen, overflowMenuOpen, visibleValues, }: UseOverflowLayoutStateArgs): UseOverflowLayoutStateResult;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type Dispatch, type MutableRefObject, type SetStateAction, type SyntheticEvent } from "react";
|
|
2
|
+
interface UseOverflowSelectionStateArgs {
|
|
3
|
+
commitSelection: (event: SyntheticEvent | null, value: string) => void;
|
|
4
|
+
menuOpen: boolean;
|
|
5
|
+
selected?: string;
|
|
6
|
+
setMenuOpen: Dispatch<SetStateAction<boolean>>;
|
|
7
|
+
}
|
|
8
|
+
interface UseOverflowSelectionStateResult {
|
|
9
|
+
selectionFromOverflowValueRef: MutableRefObject<string | null>;
|
|
10
|
+
setSelected: (event: SyntheticEvent | null, value: string, source?: "main" | "overflow") => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function useOverflowSelectionState({ commitSelection, menuOpen, selected, setMenuOpen, }: UseOverflowSelectionStateArgs): UseOverflowSelectionStateResult;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
import type { TabsNextContextValue, TabsNextRenderMode } from "../TabsNextContext";
|
|
3
|
+
interface UseRenderedTabWidthProps {
|
|
4
|
+
hostElement: HTMLDivElement | null;
|
|
5
|
+
renderMode: TabsNextRenderMode;
|
|
6
|
+
tabRootRef: RefObject<HTMLDivElement>;
|
|
7
|
+
targetWindow: Window | null | undefined;
|
|
8
|
+
updateRenderedTab: TabsNextContextValue["updateRenderedTab"];
|
|
9
|
+
value: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function useRenderedTabWidth({ hostElement, renderMode, tabRootRef, targetWindow, updateRenderedTab, value, }: UseRenderedTabWidthProps): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RenderedTab, TabsNextRenderMode } from "../TabsNextContext";
|
|
2
|
+
export declare function useRenderedTabsRegistry(): {
|
|
3
|
+
renderMode: TabsNextRenderMode;
|
|
4
|
+
registerBootstrapTab: (tabValue: string) => () => void;
|
|
5
|
+
setBootstrapTabReady: (tabValue: string, ready: boolean) => void;
|
|
6
|
+
setBootstrapOverflowReady: (ready: boolean) => void;
|
|
7
|
+
registerRenderedTab: (tab: RenderedTab) => () => void;
|
|
8
|
+
updateRenderedTab: (value: string, updates: Partial<Omit<RenderedTab, "value">>) => void;
|
|
9
|
+
getRenderedTab: (value: string) => RenderedTab | undefined;
|
|
10
|
+
getRenderedTabOrder: (value: string) => number;
|
|
11
|
+
renderedTabs: RenderedTab[];
|
|
12
|
+
};
|