@salt-ds/lab 1.0.0-alpha.98 → 1.0.0-alpha.99

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 (52) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/css/salt-lab.css +147 -1
  3. package/dist-cjs/breadcrumbs-next/BreadcrumbNext.css.js +6 -0
  4. package/dist-cjs/breadcrumbs-next/BreadcrumbNext.css.js.map +1 -0
  5. package/dist-cjs/breadcrumbs-next/BreadcrumbNext.js +99 -0
  6. package/dist-cjs/breadcrumbs-next/BreadcrumbNext.js.map +1 -0
  7. package/dist-cjs/breadcrumbs-next/BreadcrumbNextLabel.js +21 -0
  8. package/dist-cjs/breadcrumbs-next/BreadcrumbNextLabel.js.map +1 -0
  9. package/dist-cjs/breadcrumbs-next/BreadcrumbNextTrigger.js +55 -0
  10. package/dist-cjs/breadcrumbs-next/BreadcrumbNextTrigger.js.map +1 -0
  11. package/dist-cjs/breadcrumbs-next/BreadcrumbsNext.css.js +6 -0
  12. package/dist-cjs/breadcrumbs-next/BreadcrumbsNext.css.js.map +1 -0
  13. package/dist-cjs/breadcrumbs-next/BreadcrumbsNext.js +146 -0
  14. package/dist-cjs/breadcrumbs-next/BreadcrumbsNext.js.map +1 -0
  15. package/dist-cjs/breadcrumbs-next/internal/BreadcrumbNextContext.js +12 -0
  16. package/dist-cjs/breadcrumbs-next/internal/BreadcrumbNextContext.js.map +1 -0
  17. package/dist-cjs/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.js +236 -0
  18. package/dist-cjs/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.js.map +1 -0
  19. package/dist-cjs/breadcrumbs-next/internal/breadcrumbItems.js +21 -0
  20. package/dist-cjs/breadcrumbs-next/internal/breadcrumbItems.js.map +1 -0
  21. package/dist-cjs/index.js +8 -0
  22. package/dist-cjs/index.js.map +1 -1
  23. package/dist-es/breadcrumbs-next/BreadcrumbNext.css.js +4 -0
  24. package/dist-es/breadcrumbs-next/BreadcrumbNext.css.js.map +1 -0
  25. package/dist-es/breadcrumbs-next/BreadcrumbNext.js +97 -0
  26. package/dist-es/breadcrumbs-next/BreadcrumbNext.js.map +1 -0
  27. package/dist-es/breadcrumbs-next/BreadcrumbNextLabel.js +19 -0
  28. package/dist-es/breadcrumbs-next/BreadcrumbNextLabel.js.map +1 -0
  29. package/dist-es/breadcrumbs-next/BreadcrumbNextTrigger.js +53 -0
  30. package/dist-es/breadcrumbs-next/BreadcrumbNextTrigger.js.map +1 -0
  31. package/dist-es/breadcrumbs-next/BreadcrumbsNext.css.js +4 -0
  32. package/dist-es/breadcrumbs-next/BreadcrumbsNext.css.js.map +1 -0
  33. package/dist-es/breadcrumbs-next/BreadcrumbsNext.js +144 -0
  34. package/dist-es/breadcrumbs-next/BreadcrumbsNext.js.map +1 -0
  35. package/dist-es/breadcrumbs-next/internal/BreadcrumbNextContext.js +9 -0
  36. package/dist-es/breadcrumbs-next/internal/BreadcrumbNextContext.js.map +1 -0
  37. package/dist-es/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.js +234 -0
  38. package/dist-es/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.js.map +1 -0
  39. package/dist-es/breadcrumbs-next/internal/breadcrumbItems.js +19 -0
  40. package/dist-es/breadcrumbs-next/internal/breadcrumbItems.js.map +1 -0
  41. package/dist-es/index.js +4 -0
  42. package/dist-es/index.js.map +1 -1
  43. package/dist-types/breadcrumbs-next/BreadcrumbNext.d.ts +23 -0
  44. package/dist-types/breadcrumbs-next/BreadcrumbNextLabel.d.ts +4 -0
  45. package/dist-types/breadcrumbs-next/BreadcrumbNextTrigger.d.ts +8 -0
  46. package/dist-types/breadcrumbs-next/BreadcrumbsNext.d.ts +32 -0
  47. package/dist-types/breadcrumbs-next/index.d.ts +4 -0
  48. package/dist-types/breadcrumbs-next/internal/BreadcrumbNextContext.d.ts +14 -0
  49. package/dist-types/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.d.ts +9 -0
  50. package/dist-types/breadcrumbs-next/internal/breadcrumbItems.d.ts +9 -0
  51. package/dist-types/index.d.ts +1 -0
  52. package/package.json +3 -3
@@ -0,0 +1,144 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { makePrefixer, useIcon } from '@salt-ds/core';
3
+ import { useComponentCssInjection } from '@salt-ds/styles';
4
+ import { useWindow } from '@salt-ds/window';
5
+ import { clsx } from 'clsx';
6
+ import { forwardRef, isValidElement } from 'react';
7
+ import { BreadcrumbNext } from './BreadcrumbNext.js';
8
+ import css_248z from './BreadcrumbsNext.css.js';
9
+ import { BreadcrumbNextContext } from './internal/BreadcrumbNextContext.js';
10
+ import { BreadcrumbOverflowDisclosure } from './internal/BreadcrumbOverflowDisclosure.js';
11
+ import { flattenBreadcrumbItems } from './internal/breadcrumbItems.js';
12
+
13
+ const withBaseName = makePrefixer("saltBreadcrumbsNext");
14
+ const withItemBaseName = makePrefixer("saltBreadcrumbNext");
15
+ function isBreadcrumbNextElement(child) {
16
+ return isValidElement(child) && child.type === BreadcrumbNext;
17
+ }
18
+ function getCurrentIndex(items) {
19
+ const explicitCurrentIndex = items.findIndex(({ props }) => props.current);
20
+ return explicitCurrentIndex === -1 ? Math.max(items.length - 1, 0) : explicitCurrentIndex;
21
+ }
22
+ function getCollapseRange({
23
+ currentIndex,
24
+ items,
25
+ itemsAfterCollapse,
26
+ itemsBeforeCollapse
27
+ }) {
28
+ const itemCount = items.length;
29
+ const effectiveItemsAfterCollapse = Math.max(
30
+ itemsAfterCollapse,
31
+ itemCount - currentIndex
32
+ );
33
+ if (itemsBeforeCollapse + effectiveItemsAfterCollapse >= itemCount) {
34
+ return void 0;
35
+ }
36
+ const hiddenStart = itemsBeforeCollapse;
37
+ const hiddenEnd = itemCount - effectiveItemsAfterCollapse;
38
+ const hiddenItems = items.slice(hiddenStart, hiddenEnd);
39
+ return {
40
+ hiddenItems,
41
+ visibleAfter: items.slice(hiddenEnd),
42
+ visibleBefore: items.slice(0, hiddenStart)
43
+ };
44
+ }
45
+ function renderSeparator(SeparatorIcon) {
46
+ return /* @__PURE__ */ jsx(SeparatorIcon, { "aria-hidden": true, className: withItemBaseName("separator") });
47
+ }
48
+ const BreadcrumbsNext = forwardRef(
49
+ function BreadcrumbsNext2(props, ref) {
50
+ const {
51
+ children,
52
+ className,
53
+ itemsAfterCollapse = 1,
54
+ itemsBeforeCollapse = 1,
55
+ maxItems,
56
+ render,
57
+ wrap = false,
58
+ ...rest
59
+ } = props;
60
+ const targetWindow = useWindow();
61
+ const { LevelSeparatorIcon } = useIcon();
62
+ useComponentCssInjection({
63
+ testId: "salt-breadcrumbs-next",
64
+ css: css_248z,
65
+ window: targetWindow
66
+ });
67
+ const items = flattenBreadcrumbItems(children).filter(isBreadcrumbNextElement).map((element, index) => ({
68
+ element,
69
+ index,
70
+ key: element.key ?? index,
71
+ props: element.props
72
+ }));
73
+ const currentIndex = getCurrentIndex(items);
74
+ const shouldCollapse = !wrap && maxItems !== void 0 && items.length > maxItems;
75
+ const collapseRange = shouldCollapse ? getCollapseRange({
76
+ currentIndex,
77
+ items,
78
+ itemsAfterCollapse,
79
+ itemsBeforeCollapse
80
+ }) : void 0;
81
+ const renderParts = collapseRange ? [
82
+ ...collapseRange.visibleBefore.map(
83
+ (item) => ({ item, type: "breadcrumb" })
84
+ ),
85
+ {
86
+ hiddenItems: collapseRange.hiddenItems,
87
+ type: "collapse"
88
+ },
89
+ ...collapseRange.visibleAfter.map(
90
+ (item) => ({ item, type: "breadcrumb" })
91
+ )
92
+ ] : items.map((item) => ({ item, type: "breadcrumb" }));
93
+ return /* @__PURE__ */ jsx("nav", { ref, className: clsx(withBaseName(), className), ...rest, children: /* @__PURE__ */ jsx(
94
+ "ol",
95
+ {
96
+ className: clsx(withBaseName("ol"), {
97
+ [withBaseName("ol-wrap")]: wrap
98
+ }),
99
+ children: renderParts.map((part, index) => {
100
+ const showSeparator = index < renderParts.length - 1;
101
+ if (part.type === "collapse") {
102
+ return /* @__PURE__ */ jsxs(
103
+ "li",
104
+ {
105
+ className: clsx(
106
+ withItemBaseName(),
107
+ withBaseName("collapseItem")
108
+ ),
109
+ children: [
110
+ /* @__PURE__ */ jsx(
111
+ BreadcrumbOverflowDisclosure,
112
+ {
113
+ currentIndex,
114
+ items: part.hiddenItems,
115
+ render
116
+ }
117
+ ),
118
+ showSeparator ? renderSeparator(LevelSeparatorIcon) : null
119
+ ]
120
+ },
121
+ "breadcrumbs-next-collapse"
122
+ );
123
+ }
124
+ return /* @__PURE__ */ jsx(
125
+ BreadcrumbNextContext.Provider,
126
+ {
127
+ value: {
128
+ current: part.item.index === currentIndex,
129
+ placement: "trail",
130
+ render,
131
+ showSeparator
132
+ },
133
+ children: part.item.element
134
+ },
135
+ part.item.key
136
+ );
137
+ })
138
+ }
139
+ ) });
140
+ }
141
+ );
142
+
143
+ export { BreadcrumbsNext };
144
+ //# sourceMappingURL=BreadcrumbsNext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BreadcrumbsNext.js","sources":["../src/breadcrumbs-next/BreadcrumbsNext.tsx"],"sourcesContent":["import { makePrefixer, type RenderPropsType, useIcon } 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 ElementType,\n forwardRef,\n isValidElement,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { BreadcrumbNext, type BreadcrumbNextProps } from \"./BreadcrumbNext\";\nimport breadcrumbsNextCss from \"./BreadcrumbsNext.css\";\nimport { BreadcrumbNextContext } from \"./internal/BreadcrumbNextContext\";\nimport { BreadcrumbOverflowDisclosure } from \"./internal/BreadcrumbOverflowDisclosure\";\nimport {\n flattenBreadcrumbItems,\n type NormalizedBreadcrumb,\n} from \"./internal/breadcrumbItems\";\n\nconst withBaseName = makePrefixer(\"saltBreadcrumbsNext\");\nconst withItemBaseName = makePrefixer(\"saltBreadcrumbNext\");\n\ninterface CollapseRange {\n hiddenItems: NormalizedBreadcrumb[];\n visibleAfter: NormalizedBreadcrumb[];\n visibleBefore: NormalizedBreadcrumb[];\n}\n\ntype RenderPart =\n | {\n item: NormalizedBreadcrumb;\n type: \"breadcrumb\";\n }\n | {\n hiddenItems: NormalizedBreadcrumb[];\n type: \"collapse\";\n };\n\nexport interface BreadcrumbsNextProps\n extends Omit<ComponentPropsWithoutRef<\"nav\">, \"children\"> {\n /**\n * Breadcrumb items.\n */\n children?: ReactNode;\n /**\n * The number of items to keep after the collapse point.\n * Defaults to 1.\n */\n itemsAfterCollapse?: number;\n /**\n * The number of items to keep before the collapse point.\n * Defaults to 1.\n */\n itemsBeforeCollapse?: number;\n /**\n * The maximum number of breadcrumbs to render before collapsing.\n */\n maxItems?: number;\n /**\n * Render prop to enable customization of the underlying link elements.\n */\n render?: RenderPropsType[\"render\"];\n /**\n * If `true`, breadcrumbs can wrap onto multiple lines.\n * Defaults to `false`.\n */\n wrap?: boolean;\n}\n\nfunction isBreadcrumbNextElement(\n child: ReactNode,\n): child is ReactElement<BreadcrumbNextProps> {\n return (\n isValidElement<BreadcrumbNextProps>(child) && child.type === BreadcrumbNext\n );\n}\n\nfunction getCurrentIndex(items: NormalizedBreadcrumb[]) {\n const explicitCurrentIndex = items.findIndex(({ props }) => props.current);\n\n return explicitCurrentIndex === -1\n ? Math.max(items.length - 1, 0)\n : explicitCurrentIndex;\n}\n\nfunction getCollapseRange({\n currentIndex,\n items,\n itemsAfterCollapse,\n itemsBeforeCollapse,\n}: {\n currentIndex: number;\n items: NormalizedBreadcrumb[];\n itemsAfterCollapse: number;\n itemsBeforeCollapse: number;\n}): CollapseRange | undefined {\n const itemCount = items.length;\n const effectiveItemsAfterCollapse = Math.max(\n itemsAfterCollapse,\n itemCount - currentIndex,\n );\n\n if (itemsBeforeCollapse + effectiveItemsAfterCollapse >= itemCount) {\n return undefined;\n }\n\n const hiddenStart = itemsBeforeCollapse;\n const hiddenEnd = itemCount - effectiveItemsAfterCollapse;\n const hiddenItems = items.slice(hiddenStart, hiddenEnd);\n\n return {\n hiddenItems,\n visibleAfter: items.slice(hiddenEnd),\n visibleBefore: items.slice(0, hiddenStart),\n };\n}\n\nfunction renderSeparator(SeparatorIcon: ElementType) {\n return (\n <SeparatorIcon aria-hidden className={withItemBaseName(\"separator\")} />\n );\n}\n\nexport const BreadcrumbsNext = forwardRef<HTMLElement, BreadcrumbsNextProps>(\n function BreadcrumbsNext(props, ref) {\n const {\n children,\n className,\n itemsAfterCollapse = 1,\n itemsBeforeCollapse = 1,\n maxItems,\n render,\n wrap = false,\n ...rest\n } = props;\n const targetWindow = useWindow();\n const { LevelSeparatorIcon } = useIcon();\n\n useComponentCssInjection({\n testId: \"salt-breadcrumbs-next\",\n css: breadcrumbsNextCss,\n window: targetWindow,\n });\n\n const items = flattenBreadcrumbItems(children)\n .filter(isBreadcrumbNextElement)\n .map((element, index) => ({\n element,\n index,\n key: element.key ?? index,\n props: element.props,\n }));\n\n const currentIndex = getCurrentIndex(items);\n const shouldCollapse =\n !wrap && maxItems !== undefined && items.length > maxItems;\n\n const collapseRange = shouldCollapse\n ? getCollapseRange({\n currentIndex,\n items,\n itemsAfterCollapse,\n itemsBeforeCollapse,\n })\n : undefined;\n\n const renderParts: RenderPart[] = collapseRange\n ? [\n ...collapseRange.visibleBefore.map(\n (item): RenderPart => ({ item, type: \"breadcrumb\" }),\n ),\n {\n hiddenItems: collapseRange.hiddenItems,\n type: \"collapse\",\n },\n ...collapseRange.visibleAfter.map(\n (item): RenderPart => ({ item, type: \"breadcrumb\" }),\n ),\n ]\n : items.map((item): RenderPart => ({ item, type: \"breadcrumb\" }));\n\n return (\n <nav ref={ref} className={clsx(withBaseName(), className)} {...rest}>\n <ol\n className={clsx(withBaseName(\"ol\"), {\n [withBaseName(\"ol-wrap\")]: wrap,\n })}\n >\n {renderParts.map((part, index) => {\n const showSeparator = index < renderParts.length - 1;\n\n if (part.type === \"collapse\") {\n return (\n <li\n className={clsx(\n withItemBaseName(),\n withBaseName(\"collapseItem\"),\n )}\n key=\"breadcrumbs-next-collapse\"\n >\n <BreadcrumbOverflowDisclosure\n currentIndex={currentIndex}\n items={part.hiddenItems}\n render={render}\n />\n {showSeparator ? renderSeparator(LevelSeparatorIcon) : null}\n </li>\n );\n }\n\n return (\n <BreadcrumbNextContext.Provider\n key={part.item.key}\n value={{\n current: part.item.index === currentIndex,\n placement: \"trail\",\n render,\n showSeparator,\n }}\n >\n {part.item.element}\n </BreadcrumbNextContext.Provider>\n );\n })}\n </ol>\n </nav>\n );\n },\n);\n"],"names":["BreadcrumbsNext","breadcrumbsNextCss"],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import { createContext, useContext } from 'react';
2
+
3
+ const BreadcrumbNextContext = createContext(void 0);
4
+ function useBreadcrumbNextContext() {
5
+ return useContext(BreadcrumbNextContext);
6
+ }
7
+
8
+ export { BreadcrumbNextContext, useBreadcrumbNextContext };
9
+ //# sourceMappingURL=BreadcrumbNextContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BreadcrumbNextContext.js","sources":["../src/breadcrumbs-next/internal/BreadcrumbNextContext.ts"],"sourcesContent":["import type { RenderPropsType } from \"@salt-ds/core\";\nimport { createContext, type Ref, useContext } from \"react\";\n\nexport type BreadcrumbNextPlacement = \"disclosure\" | \"trail\";\n\nexport interface BreadcrumbNextContextValue {\n current: boolean;\n href?: string;\n onNavigate?: () => void;\n placement: BreadcrumbNextPlacement;\n render?: RenderPropsType[\"render\"];\n showSeparator: boolean;\n triggerRef?: Ref<HTMLAnchorElement>;\n}\n\nexport const BreadcrumbNextContext = createContext<\n BreadcrumbNextContextValue | undefined\n>(undefined);\n\nexport function useBreadcrumbNextContext() {\n return useContext(BreadcrumbNextContext);\n}\n"],"names":[],"mappings":";;AAeO,MAAM,qBAAA,GAAwB,cAEnC,MAAS;AAEJ,SAAS,wBAAA,GAA2B;AACzC,EAAA,OAAO,WAAW,qBAAqB,CAAA;AACzC;;;;"}
@@ -0,0 +1,234 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { offset, size, flip, shift, useInteractions, useClick, useDismiss } from '@floating-ui/react';
3
+ import { makePrefixer, useId, useFloatingComponent, useFloatingUI, useForkRef, Button } from '@salt-ds/core';
4
+ import { OverflowMenuIcon } from '@salt-ds/icons';
5
+ import { useWindow } from '@salt-ds/window';
6
+ import { useState, useRef, useCallback } from 'react';
7
+ import { BreadcrumbNextContext } from './BreadcrumbNextContext.js';
8
+
9
+ const withBaseName = makePrefixer("saltBreadcrumbsNext");
10
+ function BreadcrumbOverflowDisclosure({
11
+ currentIndex,
12
+ items,
13
+ render
14
+ }) {
15
+ var _a, _b;
16
+ const [open, setOpen] = useState(false);
17
+ const targetWindow = useWindow();
18
+ const itemElements = useRef(/* @__PURE__ */ new Map());
19
+ const triggerRef = useRef(null);
20
+ const disclosureId = useId();
21
+ const { Component: FloatingComponent } = useFloatingComponent();
22
+ const focusTrigger = useCallback(() => {
23
+ targetWindow == null ? void 0 : targetWindow.requestAnimationFrame(() => {
24
+ var _a2;
25
+ (_a2 = triggerRef.current) == null ? void 0 : _a2.focus({ preventScroll: true });
26
+ });
27
+ }, [targetWindow]);
28
+ const getFocusableItems = useCallback(
29
+ () => items.map((_, index) => itemElements.current.get(index)).filter((item) => item !== void 0),
30
+ [items]
31
+ );
32
+ const focusItem = useCallback(
33
+ (position) => {
34
+ const focusableItems = getFocusableItems();
35
+ const item = position === "first" ? focusableItems[0] : focusableItems[focusableItems.length - 1];
36
+ item == null ? void 0 : item.focus({ preventScroll: true });
37
+ return item !== void 0;
38
+ },
39
+ [getFocusableItems]
40
+ );
41
+ const focusItemByOffset = useCallback(
42
+ (offset2) => {
43
+ var _a2;
44
+ const focusableItems = getFocusableItems();
45
+ const activeIndex = focusableItems.indexOf(
46
+ targetWindow == null ? void 0 : targetWindow.document.activeElement
47
+ );
48
+ if (activeIndex === -1) {
49
+ return focusItem(offset2 > 0 ? "first" : "last");
50
+ }
51
+ const nextIndex = Math.min(
52
+ Math.max(activeIndex + offset2, 0),
53
+ focusableItems.length - 1
54
+ );
55
+ (_a2 = focusableItems[nextIndex]) == null ? void 0 : _a2.focus({ preventScroll: true });
56
+ return focusableItems[nextIndex] !== void 0;
57
+ },
58
+ [focusItem, getFocusableItems, targetWindow]
59
+ );
60
+ const { context, elements, refs, strategy, x, y } = useFloatingUI({
61
+ open,
62
+ onOpenChange(nextOpen, _event, reason) {
63
+ setOpen(nextOpen);
64
+ if (!nextOpen && reason === "escape-key") {
65
+ focusTrigger();
66
+ }
67
+ },
68
+ placement: "bottom-start",
69
+ middleware: [
70
+ offset(1),
71
+ size({
72
+ apply({ availableHeight, elements: elements2 }) {
73
+ Object.assign(elements2.floating.style, {
74
+ maxHeight: `${availableHeight}px`
75
+ });
76
+ }
77
+ }),
78
+ flip(),
79
+ shift({
80
+ padding: 8
81
+ })
82
+ ]
83
+ });
84
+ const { getFloatingProps, getReferenceProps } = useInteractions([
85
+ useClick(context),
86
+ useDismiss(context)
87
+ ]);
88
+ const handleTriggerRef = useForkRef(
89
+ triggerRef,
90
+ refs.setReference
91
+ );
92
+ const handleTriggerKeyDown = (event) => {
93
+ if (open && (event.key === "ArrowDown" || event.key === "ArrowRight")) {
94
+ event.preventDefault();
95
+ focusItem("first");
96
+ return;
97
+ }
98
+ if (open && (event.key === "ArrowUp" || event.key === "ArrowLeft")) {
99
+ event.preventDefault();
100
+ focusItem("last");
101
+ return;
102
+ }
103
+ if (event.key === "Tab" && open && !event.shiftKey) {
104
+ if (focusItem("first")) {
105
+ event.preventDefault();
106
+ }
107
+ return;
108
+ }
109
+ };
110
+ const handleTriggerBlur = (event) => {
111
+ var _a2;
112
+ const nextFocusedElement = event.relatedTarget;
113
+ if (nextFocusedElement && ((_a2 = elements.floating) == null ? void 0 : _a2.contains(nextFocusedElement))) {
114
+ return;
115
+ }
116
+ setOpen(false);
117
+ };
118
+ const handleDisclosureKeyDown = (event) => {
119
+ if (event.key === "Tab") {
120
+ const focusableItems = getFocusableItems();
121
+ const activeIndex = focusableItems.indexOf(
122
+ targetWindow == null ? void 0 : targetWindow.document.activeElement
123
+ );
124
+ const shouldReturnToTrigger = event.shiftKey ? activeIndex === 0 : activeIndex === focusableItems.length - 1;
125
+ if (shouldReturnToTrigger) {
126
+ event.preventDefault();
127
+ setOpen(false);
128
+ focusTrigger();
129
+ }
130
+ return;
131
+ }
132
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") {
133
+ event.preventDefault();
134
+ focusItemByOffset(1);
135
+ return;
136
+ }
137
+ if (event.key === "ArrowUp" || event.key === "ArrowLeft") {
138
+ event.preventDefault();
139
+ focusItemByOffset(-1);
140
+ return;
141
+ }
142
+ if (event.key === "Home") {
143
+ event.preventDefault();
144
+ focusItem("first");
145
+ return;
146
+ }
147
+ if (event.key === "End") {
148
+ event.preventDefault();
149
+ focusItem("last");
150
+ }
151
+ };
152
+ const handleDisclosureBlur = (event) => {
153
+ var _a2;
154
+ const nextFocusedElement = event.relatedTarget;
155
+ if (nextFocusedElement && (event.currentTarget.contains(nextFocusedElement) || ((_a2 = triggerRef.current) == null ? void 0 : _a2.contains(nextFocusedElement)))) {
156
+ return;
157
+ }
158
+ setOpen(false);
159
+ };
160
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
161
+ /* @__PURE__ */ jsx(
162
+ Button,
163
+ {
164
+ "aria-controls": disclosureId,
165
+ "aria-expanded": open,
166
+ "aria-label": "Additional breadcrumbs",
167
+ appearance: "transparent",
168
+ className: withBaseName("collapseButton"),
169
+ ref: handleTriggerRef,
170
+ ...getReferenceProps({
171
+ onBlur: handleTriggerBlur,
172
+ onKeyDown: handleTriggerKeyDown
173
+ }),
174
+ children: /* @__PURE__ */ jsx(OverflowMenuIcon, { "aria-hidden": true })
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsx(
178
+ FloatingComponent,
179
+ {
180
+ className: withBaseName("disclosure"),
181
+ focusManagerProps: context ? {
182
+ closeOnFocusOut: true,
183
+ context,
184
+ initialFocus: -1,
185
+ modal: false,
186
+ returnFocus: false
187
+ } : void 0,
188
+ height: (_a = elements.floating) == null ? void 0 : _a.offsetHeight,
189
+ left: x ?? 0,
190
+ open,
191
+ position: strategy,
192
+ ref: refs.setFloating,
193
+ top: y ?? 0,
194
+ width: (_b = elements.floating) == null ? void 0 : _b.offsetWidth,
195
+ ...getFloatingProps({
196
+ id: disclosureId,
197
+ onBlur: handleDisclosureBlur,
198
+ onKeyDown: handleDisclosureKeyDown
199
+ }),
200
+ children: /* @__PURE__ */ jsx(
201
+ "ol",
202
+ {
203
+ "aria-label": "Hidden breadcrumb levels",
204
+ className: withBaseName("disclosureList"),
205
+ children: items.map((item, index) => /* @__PURE__ */ jsx(
206
+ BreadcrumbNextContext.Provider,
207
+ {
208
+ value: {
209
+ current: item.index === currentIndex,
210
+ onNavigate: () => setOpen(false),
211
+ placement: "disclosure",
212
+ render,
213
+ showSeparator: false,
214
+ triggerRef: (element) => {
215
+ if ((element == null ? void 0 : element.tagName) === "A" && element.hasAttribute("href")) {
216
+ itemElements.current.set(index, element);
217
+ } else {
218
+ itemElements.current.delete(index);
219
+ }
220
+ }
221
+ },
222
+ children: item.element
223
+ },
224
+ item.key
225
+ ))
226
+ }
227
+ )
228
+ }
229
+ )
230
+ ] });
231
+ }
232
+
233
+ export { BreadcrumbOverflowDisclosure };
234
+ //# sourceMappingURL=BreadcrumbOverflowDisclosure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BreadcrumbOverflowDisclosure.js","sources":["../src/breadcrumbs-next/internal/BreadcrumbOverflowDisclosure.tsx"],"sourcesContent":["import {\n flip,\n offset,\n shift,\n size,\n useClick,\n useDismiss,\n useInteractions,\n} from \"@floating-ui/react\";\nimport {\n Button,\n makePrefixer,\n type RenderPropsType,\n useFloatingComponent,\n useFloatingUI,\n useForkRef,\n useId,\n} from \"@salt-ds/core\";\nimport { OverflowMenuIcon } from \"@salt-ds/icons\";\nimport { useWindow } from \"@salt-ds/window\";\nimport {\n type FocusEvent,\n type KeyboardEvent,\n useCallback,\n useRef,\n useState,\n} from \"react\";\nimport { BreadcrumbNextContext } from \"./BreadcrumbNextContext\";\nimport type { NormalizedBreadcrumb } from \"./breadcrumbItems\";\n\nconst withBaseName = makePrefixer(\"saltBreadcrumbsNext\");\n\ninterface BreadcrumbOverflowDisclosureProps {\n currentIndex: number;\n items: NormalizedBreadcrumb[];\n render?: RenderPropsType[\"render\"];\n}\n\nexport function BreadcrumbOverflowDisclosure({\n currentIndex,\n items,\n render,\n}: BreadcrumbOverflowDisclosureProps) {\n const [open, setOpen] = useState(false);\n const targetWindow = useWindow();\n const itemElements = useRef(new Map<number, HTMLAnchorElement>());\n const triggerRef = useRef<HTMLButtonElement>(null);\n const disclosureId = useId();\n const { Component: FloatingComponent } = useFloatingComponent();\n\n const focusTrigger = useCallback(() => {\n targetWindow?.requestAnimationFrame(() => {\n triggerRef.current?.focus({ preventScroll: true });\n });\n }, [targetWindow]);\n\n const getFocusableItems = useCallback(\n () =>\n items\n .map((_, index) => itemElements.current.get(index))\n .filter((item): item is HTMLAnchorElement => item !== undefined),\n [items],\n );\n\n const focusItem = useCallback(\n (position: \"first\" | \"last\") => {\n const focusableItems = getFocusableItems();\n const item =\n position === \"first\"\n ? focusableItems[0]\n : focusableItems[focusableItems.length - 1];\n\n item?.focus({ preventScroll: true });\n return item !== undefined;\n },\n [getFocusableItems],\n );\n\n const focusItemByOffset = useCallback(\n (offset: number) => {\n const focusableItems = getFocusableItems();\n const activeIndex = focusableItems.indexOf(\n targetWindow?.document.activeElement as HTMLAnchorElement,\n );\n\n if (activeIndex === -1) {\n return focusItem(offset > 0 ? \"first\" : \"last\");\n }\n\n const nextIndex = Math.min(\n Math.max(activeIndex + offset, 0),\n focusableItems.length - 1,\n );\n\n focusableItems[nextIndex]?.focus({ preventScroll: true });\n return focusableItems[nextIndex] !== undefined;\n },\n [focusItem, getFocusableItems, targetWindow],\n );\n\n const { context, elements, refs, strategy, x, y } = useFloatingUI({\n open,\n onOpenChange(nextOpen, _event, reason) {\n setOpen(nextOpen);\n\n if (!nextOpen && reason === \"escape-key\") {\n focusTrigger();\n }\n },\n placement: \"bottom-start\",\n middleware: [\n offset(1),\n size({\n apply({ availableHeight, elements }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n }),\n flip(),\n shift({\n padding: 8,\n }),\n ],\n });\n\n const { getFloatingProps, getReferenceProps } = useInteractions([\n useClick(context),\n useDismiss(context),\n ]);\n const handleTriggerRef = useForkRef<HTMLButtonElement>(\n triggerRef,\n refs.setReference,\n );\n\n const handleTriggerKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n if (open && (event.key === \"ArrowDown\" || event.key === \"ArrowRight\")) {\n event.preventDefault();\n focusItem(\"first\");\n return;\n }\n\n if (open && (event.key === \"ArrowUp\" || event.key === \"ArrowLeft\")) {\n event.preventDefault();\n focusItem(\"last\");\n return;\n }\n\n if (event.key === \"Tab\" && open && !event.shiftKey) {\n if (focusItem(\"first\")) {\n event.preventDefault();\n }\n return;\n }\n };\n\n const handleTriggerBlur = (event: FocusEvent<HTMLButtonElement>) => {\n const nextFocusedElement = event.relatedTarget as Node | null;\n\n if (nextFocusedElement && elements.floating?.contains(nextFocusedElement)) {\n return;\n }\n\n setOpen(false);\n };\n\n const handleDisclosureKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Tab\") {\n const focusableItems = getFocusableItems();\n const activeIndex = focusableItems.indexOf(\n targetWindow?.document.activeElement as HTMLAnchorElement,\n );\n const shouldReturnToTrigger = event.shiftKey\n ? activeIndex === 0\n : activeIndex === focusableItems.length - 1;\n\n if (shouldReturnToTrigger) {\n event.preventDefault();\n setOpen(false);\n focusTrigger();\n }\n\n return;\n }\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowRight\") {\n event.preventDefault();\n focusItemByOffset(1);\n return;\n }\n\n if (event.key === \"ArrowUp\" || event.key === \"ArrowLeft\") {\n event.preventDefault();\n focusItemByOffset(-1);\n return;\n }\n\n if (event.key === \"Home\") {\n event.preventDefault();\n focusItem(\"first\");\n return;\n }\n\n if (event.key === \"End\") {\n event.preventDefault();\n focusItem(\"last\");\n }\n };\n\n const handleDisclosureBlur = (event: FocusEvent<HTMLDivElement>) => {\n const nextFocusedElement = event.relatedTarget as Node | null;\n\n if (\n nextFocusedElement &&\n (event.currentTarget.contains(nextFocusedElement) ||\n triggerRef.current?.contains(nextFocusedElement))\n ) {\n return;\n }\n\n setOpen(false);\n };\n\n return (\n <>\n <Button\n aria-controls={disclosureId}\n aria-expanded={open}\n aria-label=\"Additional breadcrumbs\"\n appearance=\"transparent\"\n className={withBaseName(\"collapseButton\")}\n ref={handleTriggerRef}\n {...getReferenceProps({\n onBlur: handleTriggerBlur,\n onKeyDown: handleTriggerKeyDown,\n })}\n >\n <OverflowMenuIcon aria-hidden />\n </Button>\n <FloatingComponent\n className={withBaseName(\"disclosure\")}\n focusManagerProps={\n context\n ? {\n closeOnFocusOut: true,\n context,\n initialFocus: -1,\n modal: false,\n returnFocus: false,\n }\n : undefined\n }\n height={elements.floating?.offsetHeight}\n left={x ?? 0}\n open={open}\n position={strategy}\n ref={refs.setFloating}\n top={y ?? 0}\n width={elements.floating?.offsetWidth}\n {...getFloatingProps({\n id: disclosureId,\n onBlur: handleDisclosureBlur,\n onKeyDown: handleDisclosureKeyDown,\n })}\n >\n <ol\n aria-label=\"Hidden breadcrumb levels\"\n className={withBaseName(\"disclosureList\")}\n >\n {items.map((item, index) => (\n <BreadcrumbNextContext.Provider\n key={item.key}\n value={{\n current: item.index === currentIndex,\n onNavigate: () => setOpen(false),\n placement: \"disclosure\",\n render,\n showSeparator: false,\n triggerRef: (element) => {\n // Placeholder anchors (no href) are not focusable, so only\n // navigable items take part in disclosure focus movement.\n if (\n element?.tagName === \"A\" &&\n element.hasAttribute(\"href\")\n ) {\n itemElements.current.set(index, element);\n } else {\n itemElements.current.delete(index);\n }\n },\n }}\n >\n {item.element}\n </BreadcrumbNextContext.Provider>\n ))}\n </ol>\n </FloatingComponent>\n </>\n );\n}\n"],"names":["_a","offset","elements"],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Children, isValidElement, Fragment } from 'react';
2
+
3
+ function isFragmentElement(child) {
4
+ return isValidElement(child) && child.type === Fragment;
5
+ }
6
+ function flattenBreadcrumbItems(children) {
7
+ const flattenedChildren = [];
8
+ Children.forEach(children, (child) => {
9
+ if (isFragmentElement(child)) {
10
+ flattenedChildren.push(...flattenBreadcrumbItems(child.props.children));
11
+ } else if (child !== null && child !== void 0 && typeof child !== "boolean") {
12
+ flattenedChildren.push(child);
13
+ }
14
+ });
15
+ return flattenedChildren;
16
+ }
17
+
18
+ export { flattenBreadcrumbItems };
19
+ //# sourceMappingURL=breadcrumbItems.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breadcrumbItems.js","sources":["../src/breadcrumbs-next/internal/breadcrumbItems.ts"],"sourcesContent":["import {\n Children,\n Fragment,\n isValidElement,\n type Key,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport type { BreadcrumbNextProps } from \"../BreadcrumbNext\";\n\nexport interface NormalizedBreadcrumb {\n element: ReactElement<BreadcrumbNextProps>;\n index: number;\n key: Key;\n props: BreadcrumbNextProps;\n}\n\nfunction isFragmentElement(\n child: ReactNode,\n): child is ReactElement<{ children?: ReactNode }> {\n return (\n isValidElement<{ children?: ReactNode }>(child) && child.type === Fragment\n );\n}\n\nexport function flattenBreadcrumbItems(children: ReactNode): ReactNode[] {\n const flattenedChildren: ReactNode[] = [];\n\n Children.forEach(children, (child) => {\n if (isFragmentElement(child)) {\n flattenedChildren.push(...flattenBreadcrumbItems(child.props.children));\n } else if (\n child !== null &&\n child !== undefined &&\n typeof child !== \"boolean\"\n ) {\n flattenedChildren.push(child);\n }\n });\n\n return flattenedChildren;\n}\n"],"names":[],"mappings":";;AAiBA,SAAS,kBACP,KAAA,EACiD;AACjD,EAAA,OACE,cAAA,CAAyC,KAAK,CAAA,IAAK,KAAA,CAAM,IAAA,KAAS,QAAA;AAEtE;AAEO,SAAS,uBAAuB,QAAA,EAAkC;AACvE,EAAA,MAAM,oBAAiC,EAAC;AAExC,EAAA,QAAA,CAAS,OAAA,CAAQ,QAAA,EAAU,CAAC,KAAA,KAAU;AACpC,IAAA,IAAI,iBAAA,CAAkB,KAAK,CAAA,EAAG;AAC5B,MAAA,iBAAA,CAAkB,KAAK,GAAG,sBAAA,CAAuB,KAAA,CAAM,KAAA,CAAM,QAAQ,CAAC,CAAA;AAAA,IACxE,WACE,KAAA,KAAU,IAAA,IACV,UAAU,MAAA,IACV,OAAO,UAAU,SAAA,EACjB;AACA,MAAA,iBAAA,CAAkB,KAAK,KAAK,CAAA;AAAA,IAC9B;AAAA,EACF,CAAC,CAAA;AAED,EAAA,OAAO,iBAAA;AACT;;;;"}
package/dist-es/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  export { AppHeader } from './app-header/AppHeader.js';
2
2
  export { Breadcrumb } from './breadcrumbs/Breadcrumb.js';
3
3
  export { Breadcrumbs } from './breadcrumbs/Breadcrumbs.js';
4
+ export { BreadcrumbNext } from './breadcrumbs-next/BreadcrumbNext.js';
5
+ export { BreadcrumbNextLabel } from './breadcrumbs-next/BreadcrumbNextLabel.js';
6
+ export { BreadcrumbNextTrigger } from './breadcrumbs-next/BreadcrumbNextTrigger.js';
7
+ export { BreadcrumbsNext } from './breadcrumbs-next/BreadcrumbsNext.js';
4
8
  export { ButtonBar, DefaultButtonsOrderByVariant } from './button-bar/ButtonBar.js';
5
9
  export { OrderedButton } from './button-bar/OrderedButton.js';
6
10
  export { CascadingMenu } from './cascading-menu/CascadingMenu.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -0,0 +1,23 @@
1
+ import { type RenderPropsType } from "@salt-ds/core";
2
+ import { type ComponentPropsWithoutRef, type ReactNode } from "react";
3
+ export interface BreadcrumbNextProps extends Omit<ComponentPropsWithoutRef<"li">, "children"> {
4
+ /**
5
+ * Custom breadcrumb content. Use this for advanced composition with
6
+ * `BreadcrumbNextTrigger` and `BreadcrumbNextLabel`.
7
+ */
8
+ children?: ReactNode;
9
+ /**
10
+ * If `true`, the breadcrumb represents the current page.
11
+ */
12
+ current?: boolean;
13
+ /**
14
+ * The URL for the breadcrumb. Provide this for the current breadcrumb so it
15
+ * renders as a focusable link with `aria-current="page"`.
16
+ */
17
+ href?: string;
18
+ /**
19
+ * Render prop to enable customization of the underlying link element.
20
+ */
21
+ render?: RenderPropsType["render"];
22
+ }
23
+ export declare const BreadcrumbNext: import("react").ForwardRefExoticComponent<BreadcrumbNextProps & import("react").RefAttributes<HTMLLIElement>>;
@@ -0,0 +1,4 @@
1
+ import { type ComponentPropsWithoutRef } from "react";
2
+ export interface BreadcrumbNextLabelProps extends ComponentPropsWithoutRef<"span"> {
3
+ }
4
+ export declare const BreadcrumbNextLabel: import("react").ForwardRefExoticComponent<BreadcrumbNextLabelProps & import("react").RefAttributes<HTMLSpanElement>>;
@@ -0,0 +1,8 @@
1
+ import { type ComponentPropsWithoutRef, type ReactNode } from "react";
2
+ export interface BreadcrumbNextTriggerProps extends Omit<ComponentPropsWithoutRef<"a">, "children" | "color" | "href"> {
3
+ /**
4
+ * Breadcrumb trigger content.
5
+ */
6
+ children?: ReactNode;
7
+ }
8
+ export declare const BreadcrumbNextTrigger: import("react").ForwardRefExoticComponent<BreadcrumbNextTriggerProps & import("react").RefAttributes<HTMLAnchorElement>>;
@@ -0,0 +1,32 @@
1
+ import { type RenderPropsType } from "@salt-ds/core";
2
+ import { type ComponentPropsWithoutRef, type ReactNode } from "react";
3
+ export interface BreadcrumbsNextProps extends Omit<ComponentPropsWithoutRef<"nav">, "children"> {
4
+ /**
5
+ * Breadcrumb items.
6
+ */
7
+ children?: ReactNode;
8
+ /**
9
+ * The number of items to keep after the collapse point.
10
+ * Defaults to 1.
11
+ */
12
+ itemsAfterCollapse?: number;
13
+ /**
14
+ * The number of items to keep before the collapse point.
15
+ * Defaults to 1.
16
+ */
17
+ itemsBeforeCollapse?: number;
18
+ /**
19
+ * The maximum number of breadcrumbs to render before collapsing.
20
+ */
21
+ maxItems?: number;
22
+ /**
23
+ * Render prop to enable customization of the underlying link elements.
24
+ */
25
+ render?: RenderPropsType["render"];
26
+ /**
27
+ * If `true`, breadcrumbs can wrap onto multiple lines.
28
+ * Defaults to `false`.
29
+ */
30
+ wrap?: boolean;
31
+ }
32
+ export declare const BreadcrumbsNext: import("react").ForwardRefExoticComponent<BreadcrumbsNextProps & import("react").RefAttributes<HTMLElement>>;
@@ -0,0 +1,4 @@
1
+ export * from "./BreadcrumbNext";
2
+ export * from "./BreadcrumbNextLabel";
3
+ export * from "./BreadcrumbNextTrigger";
4
+ export * from "./BreadcrumbsNext";
@@ -0,0 +1,14 @@
1
+ import type { RenderPropsType } from "@salt-ds/core";
2
+ import { type Ref } from "react";
3
+ export type BreadcrumbNextPlacement = "disclosure" | "trail";
4
+ export interface BreadcrumbNextContextValue {
5
+ current: boolean;
6
+ href?: string;
7
+ onNavigate?: () => void;
8
+ placement: BreadcrumbNextPlacement;
9
+ render?: RenderPropsType["render"];
10
+ showSeparator: boolean;
11
+ triggerRef?: Ref<HTMLAnchorElement>;
12
+ }
13
+ export declare const BreadcrumbNextContext: import("react").Context<BreadcrumbNextContextValue | undefined>;
14
+ export declare function useBreadcrumbNextContext(): BreadcrumbNextContextValue | undefined;
@@ -0,0 +1,9 @@
1
+ import { type RenderPropsType } from "@salt-ds/core";
2
+ import type { NormalizedBreadcrumb } from "./breadcrumbItems";
3
+ interface BreadcrumbOverflowDisclosureProps {
4
+ currentIndex: number;
5
+ items: NormalizedBreadcrumb[];
6
+ render?: RenderPropsType["render"];
7
+ }
8
+ export declare function BreadcrumbOverflowDisclosure({ currentIndex, items, render, }: BreadcrumbOverflowDisclosureProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,9 @@
1
+ import { type Key, type ReactElement, type ReactNode } from "react";
2
+ import type { BreadcrumbNextProps } from "../BreadcrumbNext";
3
+ export interface NormalizedBreadcrumb {
4
+ element: ReactElement<BreadcrumbNextProps>;
5
+ index: number;
6
+ key: Key;
7
+ props: BreadcrumbNextProps;
8
+ }
9
+ export declare function flattenBreadcrumbItems(children: ReactNode): ReactNode[];
@@ -1,5 +1,6 @@
1
1
  export * from "./app-header";
2
2
  export * from "./breadcrumbs";
3
+ export * from "./breadcrumbs-next";
3
4
  export * from "./button-bar";
4
5
  export * from "./cascading-menu";
5
6
  export * from "./color-chooser";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salt-ds/lab",
3
- "version": "1.0.0-alpha.98",
3
+ "version": "1.0.0-alpha.99",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,8 +20,8 @@
20
20
  "*.css"
21
21
  ],
22
22
  "dependencies": {
23
- "@floating-ui/react": "^0.26.28",
24
- "@salt-ds/core": "^1.66.0",
23
+ "@floating-ui/react": "^0.27.19",
24
+ "@salt-ds/core": "^1.67.0",
25
25
  "@salt-ds/icons": "^1.18.0",
26
26
  "@salt-ds/styles": "0.3.0",
27
27
  "@salt-ds/window": "0.1.1",