@planningcenter/tapestry 4.13.0-rc.0 → 4.13.0

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 (34) hide show
  1. package/dist/components/DataTable/SavedViewsBar.d.ts.map +1 -1
  2. package/dist/components/DataTable/SavedViewsBar.js +42 -14
  3. package/dist/components/DataTable/SavedViewsBar.js.map +1 -1
  4. package/dist/components/DataTable/useVisibleSavedViews.d.ts +31 -0
  5. package/dist/components/DataTable/useVisibleSavedViews.d.ts.map +1 -0
  6. package/dist/components/DataTable/useVisibleSavedViews.js +178 -0
  7. package/dist/components/DataTable/useVisibleSavedViews.js.map +1 -0
  8. package/dist/components/internal/reorderable-list-box/ReorderableListBox.d.ts +6 -0
  9. package/dist/components/internal/reorderable-list-box/ReorderableListBox.d.ts.map +1 -1
  10. package/dist/components/internal/reorderable-list-box/ReorderableListBox.js +9 -2
  11. package/dist/components/internal/reorderable-list-box/ReorderableListBox.js.map +1 -1
  12. package/dist/index.css +8 -7
  13. package/dist/index.css.map +1 -1
  14. package/dist/packages/tapestry-render/dist/{buildComponent-C5PfOgH9.js → buildComponent-DzY2PDMT.js} +23 -23
  15. package/dist/packages/tapestry-render/dist/buildComponent-DzY2PDMT.js.map +1 -0
  16. package/dist/packages/tapestry-render/dist/index.js +2 -2
  17. package/dist/packages/tapestry-render/dist/index.js.map +1 -1
  18. package/dist/packages/tapestry-render/dist/legacy.js +2 -2
  19. package/dist/packages/tapestry-render/dist/legacy.js.map +1 -1
  20. package/dist/product-tokens/giving.css +1 -0
  21. package/dist/reactRender.css +1269 -1244
  22. package/dist/reactRender.css.map +1 -1
  23. package/dist/reactRenderLegacy.css +1269 -1244
  24. package/dist/reactRenderLegacy.css.map +1 -1
  25. package/dist/tapestryMount.css +1269 -1244
  26. package/dist/tapestryMount.css.map +1 -1
  27. package/dist/tapestryMountLegacy.css +1269 -1244
  28. package/dist/tapestryMountLegacy.css.map +1 -1
  29. package/dist/tokens.css +8 -7
  30. package/dist/tokens.css.map +1 -1
  31. package/dist/unstable.css +33 -8
  32. package/dist/unstable.css.map +1 -1
  33. package/package.json +5 -5
  34. package/dist/packages/tapestry-render/dist/buildComponent-C5PfOgH9.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SavedViewsBar.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/SavedViewsBar.tsx"],"names":[],"mappings":"AAMA,OAAO,KAaN,MAAM,OAAO,CAAA;AAUd,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAQ9E,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,eAAe,EAAE,SAAS,GAAG,SAAS,CAAA;IACtC,6DAA6D;IAC7D,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC,CAAA;IAC5C,aAAa,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CACT,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAC7B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,mDAAmD;IACnD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,CACT,SAAS,EAAE,SAAS,KACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC/C,wEAAwE;IACxE,UAAU,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC5C,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,wCAAwC;IACxC,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACtC,2EAA2E;IAC3E,eAAe,EAAE,CACf,SAAS,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,KAClD,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;IACnC;;;OAGG;IACH,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,MAAM,EACN,eAAe,EACf,WAAW,GACZ,EAAE,kBAAkB,qBA4NpB;yBA5Oe,aAAa"}
1
+ {"version":3,"file":"SavedViewsBar.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/SavedViewsBar.tsx"],"names":[],"mappings":"AAaA,OAAO,KAaN,MAAM,OAAO,CAAA;AAWd,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,UAAU,EAChB,MAAM,cAAc,CAAA;AAErB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAS9E,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,eAAe,EAAE,SAAS,GAAG,SAAS,CAAA;IACtC,6DAA6D;IAC7D,YAAY,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,CAAC,CAAA;IAC5C,aAAa,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,OAAO,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACvC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CACT,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAC7B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,oEAAoE;IACpE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,mDAAmD;IACnD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAClE,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,CACT,SAAS,EAAE,SAAS,KACjB,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,CAAA;IAC/C,wEAAwE;IACxE,UAAU,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAA;IAC5C,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,wCAAwC;IACxC,MAAM,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACtC,2EAA2E;IAC3E,eAAe,EAAE,CACf,SAAS,EAAE,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,SAAS,KAClD,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAA;IACnC;;;OAGG;IACH,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,eAAe,EACf,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,MAAM,EACN,eAAe,EACf,WAAW,GACZ,EAAE,kBAAkB,qBA2QpB;yBA3Re,aAAa"}
@@ -1,3 +1,11 @@
1
+ import '../button/ActionsDropdownIconButton.js';
2
+ import '../button/Button.js';
3
+ import { DropdownButton } from '../button/DropdownButton.js';
4
+ import '../button/DropdownIconButton.js';
5
+ import '../button/IconButton.js';
6
+ import '../button/LoadingButton.js';
7
+ import '../button/PageHeaderActionsDropdownButton.js';
8
+ import { Dropdown, DropdownTrigger, DropdownMenu, DropdownAction } from '../dropdown/Dropdown.js';
1
9
  import { ReorderableListBox, ReorderableListBoxItem } from '../internal/reorderable-list-box/ReorderableListBox.js';
2
10
  import Icon from '../../utilities/Icon.js';
3
11
  import classNames from 'classnames';
@@ -13,6 +21,7 @@ import { hasSavedViewMenuActions, SavedViewMenu } from './SavedViewMenu.js';
13
21
  import { isSavedViewEditable } from './savedViews.js';
14
22
  import { useSavedViewNameModal } from './useSavedViewNameModal.js';
15
23
  import { SaveStatusIcon, NEW_VIEW } from './useSaveStatus.js';
24
+ import { useVisibleSavedViews } from './useVisibleSavedViews.js';
16
25
 
17
26
  /**
18
27
  * The id of the view the delete alert returns focus to. Read through context
@@ -29,11 +38,30 @@ function SavedViewsBar({ activeSavedView, currentState, defaultViewId, isReorder
29
38
  }));
30
39
  const [isManageOpen, setIsManageOpen] = useState(false);
31
40
  const barRef = useRef(null);
41
+ const listRef = useRef(null);
42
+ const newViewRef = useRef(null);
32
43
  // Kept after the alert closes, so its text holds during the exit animation,
33
44
  // and its view keeps the tab stop until focus returns to it on cancel.
34
45
  const [viewToDelete, setViewToDelete] = useState(null);
35
46
  const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false);
36
47
  const [isReturningFocus, setIsReturningFocus] = useState(false);
48
+ const { isCollapsed, isMeasuring, measure, overflowItems, visibleItems } = useVisibleSavedViews({
49
+ activeKey: activeSavedView?.id ?? null,
50
+ items,
51
+ listRef,
52
+ newViewRef,
53
+ });
54
+ // While measuring, the most it can hold, for its widest width.
55
+ const overflowCount = isMeasuring ? items.length : overflowItems.length;
56
+ const applyView = (view) => {
57
+ select(view);
58
+ onApply(view);
59
+ };
60
+ // The first view is the default unless another is marked.
61
+ const renderLabel = (id, view) => (React__default.createElement(React__default.Fragment, null,
62
+ React__default.createElement("span", { className: "tds-data-table-saved-view-name" }, view.name),
63
+ view.id === defaultViewId && id !== items[0].id && (React__default.createElement(Icon, { "aria-hidden": true, className: "tds-data-table-saved-view-default-indicator", symbol: "general#pin" })),
64
+ React__default.createElement(SaveStatusIcon, { status: saveStatus.statusFor(view.id) })));
37
65
  const nameModal = useSavedViewNameModal(onUpdate);
38
66
  // Not in the list until it saves, so its status shows by the new view
39
67
  // button.
@@ -102,18 +130,16 @@ function SavedViewsBar({ activeSavedView, currentState, defaultViewId, isReorder
102
130
  return hasSavedViewMenuActions(menuProps) ? (React__default.createElement(SavedViewMenu, { ...menuProps })) : null;
103
131
  };
104
132
  return (React__default.createElement("div", { ref: barRef, className: "tds-data-table-saved-views", onFocus: isReturningFocus ? handleFocus : undefined },
105
- React__default.createElement("div", { className: "tds-data-table-saved-views-list" },
133
+ React__default.createElement("div", { ref: listRef, className: classNames("tds-data-table-saved-views-list", {
134
+ "tds-data-table-saved-views-list--collapsed": isCollapsed,
135
+ }) },
106
136
  React__default.createElement(ReturningFocusViewIdContext.Provider, { value: isReturningFocus ? (viewToDelete?.id ?? null) : null },
107
- React__default.createElement(ReorderableListBox, { items: items, label: "Views", selectedKey: activeSavedView?.id ?? null, onSelectionChange: (key) => {
137
+ React__default.createElement(ReorderableListBox, { items: visibleItems, label: "Views", selectedKey: activeSavedView?.id ?? null, onItemsRendered: measure, onSelectionChange: (key) => {
108
138
  const view = items.find(({ id }) => id === key)?.view;
109
- if (!view)
110
- return;
111
- select(view);
112
- onApply(view);
139
+ if (view)
140
+ applyView(view);
113
141
  } }, ({ id, view }) => {
114
142
  const menu = renderContextMenu(view);
115
- // The first view is the default unless another is marked.
116
- const pin = view.id === defaultViewId && id !== items[0].id && (React__default.createElement(Icon, { "aria-hidden": true, className: "tds-data-table-saved-view-default-indicator", symbol: "general#pin" }));
117
143
  return (React__default.createElement(ReorderableListBoxItem, { className: classNames("tds-data-table-saved-view-list-item", {
118
144
  "tds-data-table-saved-view-list-item--default": view.id === defaultViewId,
119
145
  }), id: id,
@@ -121,16 +147,18 @@ function SavedViewsBar({ activeSavedView, currentState, defaultViewId, isReorder
121
147
  render: (props) => {
122
148
  const optionProps = {
123
149
  ...props,
124
- children: (React__default.createElement(React__default.Fragment, null,
125
- view.name,
126
- pin,
127
- React__default.createElement(SaveStatusIcon, { status: saveStatus.statusFor(view.id) }))),
150
+ children: renderLabel(id, view),
128
151
  };
129
152
  return menu ? (React__default.createElement(ContextMenuTrigger, { id: view.id, closeOpenContextMenuRef: closeOpenContextMenuRef, menu: menu, optionProps: optionProps })) : (React__default.createElement("div", { ...optionProps }));
130
153
  } }, view.name));
131
154
  })),
132
- onCreate && React__default.createElement(NewSavedViewButton, { onClick: openNewSavedView }),
133
- React__default.createElement(SaveStatusIcon, { label: "View not saved", status: saveStatus.statusFor(NEW_VIEW) }),
155
+ (isMeasuring || overflowItems.length > 0) && (React__default.createElement(Dropdown, null,
156
+ React__default.createElement(DropdownTrigger, null,
157
+ React__default.createElement(DropdownButton, { "aria-label": `${overflowCount} more views`, className: "tds-btn--data-table-saved-views-overflow", kind: "pill", label: `${overflowCount} more` })),
158
+ React__default.createElement(DropdownMenu, null, overflowItems.map(({ id, view }) => (React__default.createElement(DropdownAction, { key: id, id: id, textValue: view.name, onAction: () => applyView(view) }, renderLabel(id, view))))))),
159
+ React__default.createElement("div", { ref: newViewRef, className: "tds-data-table-saved-views-new-view" },
160
+ onCreate && React__default.createElement(NewSavedViewButton, { onClick: openNewSavedView }),
161
+ React__default.createElement(SaveStatusIcon, { label: "View not saved", status: saveStatus.statusFor(NEW_VIEW) })),
134
162
  React__default.createElement(NewSavedViewModal, { ...nameModal.modalProps })),
135
163
  views.length > 1 && (React__default.createElement(ManageSavedViewsButton, { onClick: () => setIsManageOpen(true) })),
136
164
  React__default.createElement(ManageSavedViewsModal, { defaultViewId: defaultViewId, isReordering: isReordering, open: isManageOpen, savedViews: savedViews, staticViews: staticViews, onClose: closeManageViews, onCreate: onCreate, onDelete: onDelete, onReorder: onReorder, onSetDefault: onSetDefault, onUpdate: onUpdate }),
@@ -1 +1 @@
1
- {"version":3,"file":"SavedViewsBar.js","sources":["../../../src/components/DataTable/SavedViewsBar.tsx"],"sourcesContent":["import {\n ReorderableListBox,\n ReorderableListBoxItem,\n} from \"@components/internal/reorderable-list-box\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n createContext,\n Fragment,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactElement,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { MenuTrigger, Pressable } from \"react-aria-components/Menu\"\n\nimport { DeleteSavedViewAlertDialog } from \"./DeleteSavedViewAlertDialog\"\nimport { ManageSavedViewsButton } from \"./ManageSavedViewsButton\"\nimport { ManageSavedViewsModal } from \"./ManageSavedViewsModal\"\nimport { NewSavedViewButton } from \"./NewSavedViewButton\"\nimport { NewSavedViewModal } from \"./NewSavedViewModal\"\nimport { hasSavedViewMenuActions, SavedViewMenu } from \"./SavedViewMenu\"\nimport {\n isSavedViewEditable,\n type SavedView,\n type StaticView,\n} from \"./savedViews\"\nimport { useSavedViewNameModal } from \"./useSavedViewNameModal\"\nimport type { ReorderTarget } from \"./useSavedViewsState\"\nimport { NEW_VIEW, SaveStatusIcon, type useSaveStatus } from \"./useSaveStatus\"\n\n/**\n * The id of the view the delete alert returns focus to. Read through context\n * so the list's cached items see it without rebuilding the collection.\n */\nconst ReturningFocusViewIdContext = createContext<SavedView[\"id\"] | null>(null)\n\nexport interface SavedViewsBarProps {\n /** The selected view, if any. */\n activeSavedView: SavedView | undefined\n /** What New view saves. Its filters leave out the search. */\n currentState: Omit<SavedView, \"id\" | \"name\">\n defaultViewId: NonNullable<SavedView[\"id\"]>\n /** Disables the drag handles while a reorder saves. */\n isReordering?: boolean\n onApply: (savedView: SavedView) => void\n /**\n * Returns the saved view with its new id. Omit to hide the new view button\n * and the Duplicate action.\n */\n onCreate?: (\n savedView: Omit<SavedView, \"id\">\n ) => Promise<SavedView | undefined> | SavedView\n /** Called once the user confirms. Omit to leave out the Delete action. */\n onDelete?: (savedView: SavedView) => Promise<void>\n /** Omit to leave out the drag handles in the manage views modal. */\n onReorder?: (savedView: SavedView, target: ReorderTarget) => Promise<void>\n /** Omit to leave out the Set as default action. */\n onSetDefault?: (id: NonNullable<SavedView[\"id\"]>) => Promise<void>\n /** Omit to leave out the Rename action. */\n onUpdate?: (\n savedView: SavedView\n ) => Promise<SavedView | undefined> | SavedView\n /** Tracks saves, shared with the filters shelf's saved view actions. */\n saveStatus: ReturnType<typeof useSaveStatus>\n savedViews: SavedView[]\n /** Selects the view the user picked. */\n select: (savedView: SavedView) => void\n /** Selects a created view once it's saved, resolving to it if selected. */\n selectWhenSaved: (\n savedView: Promise<SavedView | undefined> | SavedView\n ) => Promise<SavedView | undefined>\n /**\n * Listed before `savedViews` and can't be edited. Starts with the initial\n * view unless one replaces it.\n */\n staticViews: StaticView[]\n}\n\nexport function SavedViewsBar({\n activeSavedView,\n currentState,\n defaultViewId,\n isReordering,\n onApply,\n onCreate,\n onDelete,\n onReorder,\n onSetDefault,\n onUpdate,\n saveStatus,\n savedViews,\n select,\n selectWhenSaved,\n staticViews,\n}: SavedViewsBarProps) {\n const closeOpenContextMenuRef = useRef<(() => void) | null>(null)\n const views = [...staticViews, ...savedViews]\n // The list needs a key for every view, including ones not yet saved.\n const items = views.map((view, index) => ({\n id: view.id ?? `unsaved-view-${index}`,\n view,\n }))\n const [isManageOpen, setIsManageOpen] = useState(false)\n const barRef = useRef<HTMLDivElement>(null)\n // Kept after the alert closes, so its text holds during the exit animation,\n // and its view keeps the tab stop until focus returns to it on cancel.\n const [viewToDelete, setViewToDelete] = useState<SavedView | null>(null)\n const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false)\n const [isReturningFocus, setIsReturningFocus] = useState(false)\n\n const nameModal = useSavedViewNameModal(onUpdate)\n\n // Not in the list until it saves, so its status shows by the new view\n // button.\n const createSavedView = (view: Omit<SavedView, \"id\">) => {\n if (onCreate)\n saveStatus.track(NEW_VIEW, selectWhenSaved(onCreate(view)), view.name)\n }\n\n // A duplicate of another view has other settings than the table, so it's\n // applied once it's selected.\n const duplicateSavedView = (view: Omit<SavedView, \"id\">) => {\n if (onCreate)\n saveStatus.track(\n NEW_VIEW,\n selectWhenSaved(onCreate(view)).then(\n (selected) => selected && onApply(selected)\n ),\n view.name\n )\n }\n\n const openNewSavedView = () => {\n nameModal.open(\"New view\", \"\", (name) =>\n createSavedView({ ...currentState, name })\n )\n }\n\n // The menu item Delete was chosen from is gone by now, so the view takes\n // focus first for the alert to return it to on cancel.\n const requestDelete = (view: SavedView) => {\n barRef.current\n ?.querySelector<HTMLElement>(\n `[role=\"option\"][data-key=\"${CSS.escape(String(view.id))}\"]`\n )\n ?.focus()\n setViewToDelete(view)\n setIsDeleteAlertOpen(true)\n setIsReturningFocus(true)\n }\n\n // Lets the tab stop go back to the selected view, where focus lands. A\n // failed delete puts the view back, showing its status.\n const confirmDelete = () => {\n if (viewToDelete && onDelete)\n saveStatus.track(\n viewToDelete.id,\n onDelete(viewToDelete),\n viewToDelete.name\n )\n setIsDeleteAlertOpen(false)\n setIsReturningFocus(false)\n }\n\n const focusSelectedViewAfterClose = useFocusSelectedViewAfterClose(\n barRef,\n isManageOpen\n )\n\n // Deleting down to one view hides the button the modal returns focus to.\n const closeManageViews = () => {\n if (views.length <= 1) focusSelectedViewAfterClose()\n setIsManageOpen(false)\n }\n\n // Focus from inside the open alert reaches here too, through the portal.\n const handleFocus = () => {\n if (!isDeleteAlertOpen) setIsReturningFocus(false)\n }\n\n const renderContextMenu = (view: SavedView) => {\n // The default is matched by id, so an unsaved view can't be made the\n // default. Static views can.\n const { id } = view\n const menuProps = {\n isDefault: id === defaultViewId,\n onDelete:\n onDelete && isSavedViewEditable(view, savedViews)\n ? () => queueMicrotask(() => requestDelete(view))\n : undefined,\n onDuplicate: onCreate\n ? () => nameModal.openDuplicate(view, duplicateSavedView)\n : undefined,\n onRename:\n onUpdate && isSavedViewEditable(view, savedViews)\n ? () =>\n nameModal.openRename(view, (saving) =>\n saveStatus.track(view.id, saving, view.name)\n )\n : undefined,\n onSetDefault:\n onSetDefault && id !== undefined\n ? () => saveStatus.track(id, onSetDefault(id), view.name)\n : undefined,\n }\n return hasSavedViewMenuActions(menuProps) ? (\n <SavedViewMenu {...menuProps} />\n ) : null\n }\n\n return (\n <div\n ref={barRef}\n className=\"tds-data-table-saved-views\"\n onFocus={isReturningFocus ? handleFocus : undefined}\n >\n <div className=\"tds-data-table-saved-views-list\">\n <ReturningFocusViewIdContext.Provider\n value={isReturningFocus ? (viewToDelete?.id ?? null) : null}\n >\n <ReorderableListBox\n items={items}\n label=\"Views\"\n selectedKey={activeSavedView?.id ?? null}\n onSelectionChange={(key) => {\n const view = items.find(({ id }) => id === key)?.view\n if (!view) return\n select(view)\n onApply(view)\n }}\n >\n {({ id, view }) => {\n const menu = renderContextMenu(view)\n // The first view is the default unless another is marked.\n const pin = view.id === defaultViewId && id !== items[0].id && (\n <Icon\n aria-hidden\n className=\"tds-data-table-saved-view-default-indicator\"\n symbol=\"general#pin\"\n />\n )\n return (\n <ReorderableListBoxItem\n className={classNames(\"tds-data-table-saved-view-list-item\", {\n \"tds-data-table-saved-view-list-item--default\":\n view.id === defaultViewId,\n })}\n id={id}\n // The list item only takes text, so the pin goes in here.\n render={(props) => {\n const optionProps = {\n ...(props as ComponentProps<\"div\">),\n children: (\n <>\n {view.name}\n {pin}\n <SaveStatusIcon\n status={saveStatus.statusFor(view.id)}\n />\n </>\n ),\n }\n return menu ? (\n <ContextMenuTrigger\n id={view.id}\n closeOpenContextMenuRef={closeOpenContextMenuRef}\n menu={menu}\n optionProps={optionProps}\n />\n ) : (\n <div {...optionProps} />\n )\n }}\n >\n {view.name}\n </ReorderableListBoxItem>\n )\n }}\n </ReorderableListBox>\n </ReturningFocusViewIdContext.Provider>\n {onCreate && <NewSavedViewButton onClick={openNewSavedView} />}\n <SaveStatusIcon\n label=\"View not saved\"\n status={saveStatus.statusFor(NEW_VIEW)}\n />\n <NewSavedViewModal {...nameModal.modalProps} />\n </div>\n {views.length > 1 && (\n <ManageSavedViewsButton onClick={() => setIsManageOpen(true)} />\n )}\n {/* Rendered apart from the button, so a delete that hides the button doesn't remove the open modal. */}\n <ManageSavedViewsModal\n defaultViewId={defaultViewId}\n isReordering={isReordering}\n open={isManageOpen}\n savedViews={savedViews}\n staticViews={staticViews}\n onClose={closeManageViews}\n onCreate={onCreate}\n onDelete={onDelete}\n onReorder={onReorder}\n onSetDefault={onSetDefault}\n onUpdate={onUpdate}\n />\n {onDelete && (\n <DeleteSavedViewAlertDialog\n open={isDeleteAlertOpen}\n view={viewToDelete}\n onCancel={() => setIsDeleteAlertOpen(false)}\n onConfirm={confirmDelete}\n />\n )}\n </div>\n )\n}\n\nSavedViewsBar.displayName = \"SavedViewsBar\"\n\n/**\n * Once the manage views modal starts closing, focuses the selected view, or\n * the first one.\n */\nfunction useFocusSelectedViewAfterClose(\n barRef: RefObject<HTMLDivElement>,\n isManageOpen: boolean\n) {\n const shouldFocusRef = useRef(false)\n\n useEffect(() => {\n if (isManageOpen || !shouldFocusRef.current) return\n shouldFocusRef.current = false\n const bar = barRef.current\n ;(\n bar?.querySelector<HTMLElement>(\n '[role=\"option\"][aria-selected=\"true\"]'\n ) ?? bar?.querySelector<HTMLElement>('[role=\"option\"]')\n )?.focus()\n }, [barRef, isManageOpen])\n\n return () => {\n shouldFocusRef.current = true\n }\n}\n\n/**\n * Makes a saved view's option element itself the context menu trigger, so\n * the menu opens by right click, long press, or the keyboard context menu\n * shortcut (Shift+F10, the Menu key, or Ctrl+Enter on macOS), is named by\n * the view, and returns focus to it on close. `Pressable` hands the trigger's\n * handlers to the option element. The option ignores Ctrl+Enter, so the\n * macOS shortcut opens the menu without also selecting the view. The\n * `data-popup-open` attribute keeps the list from moving its tab\n * stop to the selected view while the menu is open. Opening the menu closes\n * any other view's menu, since a right click elsewhere in the list doesn't\n * count as an outside interaction. The open state stays here rather than in\n * the bar, because re-rendering the bar rebuilds the list's collection and\n * moves its tab stop before focus can return to this view. Each\n * `contextmenu` event remounts the menu, because React Aria only positions\n * an open menu once and would leave it at the first click point.\n */\nfunction ContextMenuTrigger({\n closeOpenContextMenuRef,\n id,\n menu,\n optionProps,\n}: {\n closeOpenContextMenuRef: MutableRefObject<(() => void) | null>\n id: SavedView[\"id\"]\n menu: ReactElement\n optionProps: ComponentProps<\"div\">\n}) {\n const { onKeyDown, ...restOptionProps } = optionProps\n const [isOpen, setIsOpen] = useState(false)\n // Such as the delete alert, which returns focus to this view on cancel.\n const hasOtherPopup = useContext(ReturningFocusViewIdContext) === id\n const [menuKey, setMenuKey] = useState(0)\n\n const close = useCallback(() => setIsOpen(false), [])\n const handleOpenChange = (nextIsOpen: boolean) => {\n setIsOpen(nextIsOpen)\n if (nextIsOpen) {\n closeOpenContextMenuRef.current?.()\n closeOpenContextMenuRef.current = close\n } else if (closeOpenContextMenuRef.current === close) {\n closeOpenContextMenuRef.current = null\n }\n }\n\n return (\n <MenuTrigger\n isOpen={isOpen}\n onOpenChange={handleOpenChange}\n trigger=\"contextMenu\"\n >\n <Pressable>\n <div\n {...mergeProps(restOptionProps, {\n \"data-popup-open\": isOpen || hasOtherPopup || undefined,\n onContextMenu: () => setMenuKey((key) => key + 1),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.ctrlKey && event.key === \"Enter\") return\n onKeyDown?.(event)\n },\n })}\n />\n </Pressable>\n <Fragment key={menuKey}>{menu}</Fragment>\n </MenuTrigger>\n )\n}\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"SavedViewsBar.js","sources":["../../../src/components/DataTable/SavedViewsBar.tsx"],"sourcesContent":["import { DropdownButton } from \"@components/button\"\nimport {\n Dropdown,\n DropdownAction,\n DropdownMenu,\n DropdownTrigger,\n} from \"@components/dropdown\"\nimport {\n ReorderableListBox,\n ReorderableListBoxItem,\n} from \"@components/internal/reorderable-list-box\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, {\n type ComponentProps,\n createContext,\n Fragment,\n type KeyboardEvent,\n type MutableRefObject,\n type ReactElement,\n type RefObject,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport type { Key } from \"react-aria-components/ListBox\"\nimport { MenuTrigger, Pressable } from \"react-aria-components/Menu\"\n\nimport { DeleteSavedViewAlertDialog } from \"./DeleteSavedViewAlertDialog\"\nimport { ManageSavedViewsButton } from \"./ManageSavedViewsButton\"\nimport { ManageSavedViewsModal } from \"./ManageSavedViewsModal\"\nimport { NewSavedViewButton } from \"./NewSavedViewButton\"\nimport { NewSavedViewModal } from \"./NewSavedViewModal\"\nimport { hasSavedViewMenuActions, SavedViewMenu } from \"./SavedViewMenu\"\nimport {\n isSavedViewEditable,\n type SavedView,\n type StaticView,\n} from \"./savedViews\"\nimport { useSavedViewNameModal } from \"./useSavedViewNameModal\"\nimport type { ReorderTarget } from \"./useSavedViewsState\"\nimport { NEW_VIEW, SaveStatusIcon, type useSaveStatus } from \"./useSaveStatus\"\nimport { useVisibleSavedViews } from \"./useVisibleSavedViews\"\n\n/**\n * The id of the view the delete alert returns focus to. Read through context\n * so the list's cached items see it without rebuilding the collection.\n */\nconst ReturningFocusViewIdContext = createContext<SavedView[\"id\"] | null>(null)\n\nexport interface SavedViewsBarProps {\n /** The selected view, if any. */\n activeSavedView: SavedView | undefined\n /** What New view saves. Its filters leave out the search. */\n currentState: Omit<SavedView, \"id\" | \"name\">\n defaultViewId: NonNullable<SavedView[\"id\"]>\n /** Disables the drag handles while a reorder saves. */\n isReordering?: boolean\n onApply: (savedView: SavedView) => void\n /**\n * Returns the saved view with its new id. Omit to hide the new view button\n * and the Duplicate action.\n */\n onCreate?: (\n savedView: Omit<SavedView, \"id\">\n ) => Promise<SavedView | undefined> | SavedView\n /** Called once the user confirms. Omit to leave out the Delete action. */\n onDelete?: (savedView: SavedView) => Promise<void>\n /** Omit to leave out the drag handles in the manage views modal. */\n onReorder?: (savedView: SavedView, target: ReorderTarget) => Promise<void>\n /** Omit to leave out the Set as default action. */\n onSetDefault?: (id: NonNullable<SavedView[\"id\"]>) => Promise<void>\n /** Omit to leave out the Rename action. */\n onUpdate?: (\n savedView: SavedView\n ) => Promise<SavedView | undefined> | SavedView\n /** Tracks saves, shared with the filters shelf's saved view actions. */\n saveStatus: ReturnType<typeof useSaveStatus>\n savedViews: SavedView[]\n /** Selects the view the user picked. */\n select: (savedView: SavedView) => void\n /** Selects a created view once it's saved, resolving to it if selected. */\n selectWhenSaved: (\n savedView: Promise<SavedView | undefined> | SavedView\n ) => Promise<SavedView | undefined>\n /**\n * Listed before `savedViews` and can't be edited. Starts with the initial\n * view unless one replaces it.\n */\n staticViews: StaticView[]\n}\n\nexport function SavedViewsBar({\n activeSavedView,\n currentState,\n defaultViewId,\n isReordering,\n onApply,\n onCreate,\n onDelete,\n onReorder,\n onSetDefault,\n onUpdate,\n saveStatus,\n savedViews,\n select,\n selectWhenSaved,\n staticViews,\n}: SavedViewsBarProps) {\n const closeOpenContextMenuRef = useRef<(() => void) | null>(null)\n const views = [...staticViews, ...savedViews]\n // The list needs a key for every view, including ones not yet saved.\n const items = views.map((view, index) => ({\n id: view.id ?? `unsaved-view-${index}`,\n view,\n }))\n const [isManageOpen, setIsManageOpen] = useState(false)\n const barRef = useRef<HTMLDivElement>(null)\n const listRef = useRef<HTMLDivElement>(null)\n const newViewRef = useRef<HTMLDivElement>(null)\n // Kept after the alert closes, so its text holds during the exit animation,\n // and its view keeps the tab stop until focus returns to it on cancel.\n const [viewToDelete, setViewToDelete] = useState<SavedView | null>(null)\n const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false)\n const [isReturningFocus, setIsReturningFocus] = useState(false)\n\n const { isCollapsed, isMeasuring, measure, overflowItems, visibleItems } =\n useVisibleSavedViews({\n activeKey: activeSavedView?.id ?? null,\n items,\n listRef,\n newViewRef,\n })\n // While measuring, the most it can hold, for its widest width.\n const overflowCount = isMeasuring ? items.length : overflowItems.length\n\n const applyView = (view: SavedView) => {\n select(view)\n onApply(view)\n }\n\n // The first view is the default unless another is marked.\n const renderLabel = (id: Key, view: SavedView) => (\n <>\n <span className=\"tds-data-table-saved-view-name\">{view.name}</span>\n {view.id === defaultViewId && id !== items[0].id && (\n <Icon\n aria-hidden\n className=\"tds-data-table-saved-view-default-indicator\"\n symbol=\"general#pin\"\n />\n )}\n <SaveStatusIcon status={saveStatus.statusFor(view.id)} />\n </>\n )\n\n const nameModal = useSavedViewNameModal(onUpdate)\n\n // Not in the list until it saves, so its status shows by the new view\n // button.\n const createSavedView = (view: Omit<SavedView, \"id\">) => {\n if (onCreate)\n saveStatus.track(NEW_VIEW, selectWhenSaved(onCreate(view)), view.name)\n }\n\n // A duplicate of another view has other settings than the table, so it's\n // applied once it's selected.\n const duplicateSavedView = (view: Omit<SavedView, \"id\">) => {\n if (onCreate)\n saveStatus.track(\n NEW_VIEW,\n selectWhenSaved(onCreate(view)).then(\n (selected) => selected && onApply(selected)\n ),\n view.name\n )\n }\n\n const openNewSavedView = () => {\n nameModal.open(\"New view\", \"\", (name) =>\n createSavedView({ ...currentState, name })\n )\n }\n\n // The menu item Delete was chosen from is gone by now, so the view takes\n // focus first for the alert to return it to on cancel.\n const requestDelete = (view: SavedView) => {\n barRef.current\n ?.querySelector<HTMLElement>(\n `[role=\"option\"][data-key=\"${CSS.escape(String(view.id))}\"]`\n )\n ?.focus()\n setViewToDelete(view)\n setIsDeleteAlertOpen(true)\n setIsReturningFocus(true)\n }\n\n // Lets the tab stop go back to the selected view, where focus lands. A\n // failed delete puts the view back, showing its status.\n const confirmDelete = () => {\n if (viewToDelete && onDelete)\n saveStatus.track(\n viewToDelete.id,\n onDelete(viewToDelete),\n viewToDelete.name\n )\n setIsDeleteAlertOpen(false)\n setIsReturningFocus(false)\n }\n\n const focusSelectedViewAfterClose = useFocusSelectedViewAfterClose(\n barRef,\n isManageOpen\n )\n\n // Deleting down to one view hides the button the modal returns focus to.\n const closeManageViews = () => {\n if (views.length <= 1) focusSelectedViewAfterClose()\n setIsManageOpen(false)\n }\n\n // Focus from inside the open alert reaches here too, through the portal.\n const handleFocus = () => {\n if (!isDeleteAlertOpen) setIsReturningFocus(false)\n }\n\n const renderContextMenu = (view: SavedView) => {\n // The default is matched by id, so an unsaved view can't be made the\n // default. Static views can.\n const { id } = view\n const menuProps = {\n isDefault: id === defaultViewId,\n onDelete:\n onDelete && isSavedViewEditable(view, savedViews)\n ? () => queueMicrotask(() => requestDelete(view))\n : undefined,\n onDuplicate: onCreate\n ? () => nameModal.openDuplicate(view, duplicateSavedView)\n : undefined,\n onRename:\n onUpdate && isSavedViewEditable(view, savedViews)\n ? () =>\n nameModal.openRename(view, (saving) =>\n saveStatus.track(view.id, saving, view.name)\n )\n : undefined,\n onSetDefault:\n onSetDefault && id !== undefined\n ? () => saveStatus.track(id, onSetDefault(id), view.name)\n : undefined,\n }\n return hasSavedViewMenuActions(menuProps) ? (\n <SavedViewMenu {...menuProps} />\n ) : null\n }\n\n return (\n <div\n ref={barRef}\n className=\"tds-data-table-saved-views\"\n onFocus={isReturningFocus ? handleFocus : undefined}\n >\n <div\n ref={listRef}\n className={classNames(\"tds-data-table-saved-views-list\", {\n \"tds-data-table-saved-views-list--collapsed\": isCollapsed,\n })}\n >\n <ReturningFocusViewIdContext.Provider\n value={isReturningFocus ? (viewToDelete?.id ?? null) : null}\n >\n <ReorderableListBox\n items={visibleItems}\n label=\"Views\"\n selectedKey={activeSavedView?.id ?? null}\n onItemsRendered={measure}\n onSelectionChange={(key) => {\n const view = items.find(({ id }) => id === key)?.view\n if (view) applyView(view)\n }}\n >\n {({ id, view }) => {\n const menu = renderContextMenu(view)\n return (\n <ReorderableListBoxItem\n className={classNames(\"tds-data-table-saved-view-list-item\", {\n \"tds-data-table-saved-view-list-item--default\":\n view.id === defaultViewId,\n })}\n id={id}\n // The list item only takes text, so the pin goes in here.\n render={(props) => {\n const optionProps = {\n ...(props as ComponentProps<\"div\">),\n children: renderLabel(id, view),\n }\n return menu ? (\n <ContextMenuTrigger\n id={view.id}\n closeOpenContextMenuRef={closeOpenContextMenuRef}\n menu={menu}\n optionProps={optionProps}\n />\n ) : (\n <div {...optionProps} />\n )\n }}\n >\n {view.name}\n </ReorderableListBoxItem>\n )\n }}\n </ReorderableListBox>\n </ReturningFocusViewIdContext.Provider>\n {(isMeasuring || overflowItems.length > 0) && (\n <Dropdown>\n <DropdownTrigger>\n <DropdownButton\n aria-label={`${overflowCount} more views`}\n className=\"tds-btn--data-table-saved-views-overflow\"\n kind=\"pill\"\n label={`${overflowCount} more`}\n />\n </DropdownTrigger>\n <DropdownMenu>\n {overflowItems.map(({ id, view }) => (\n <DropdownAction\n key={id}\n id={id}\n textValue={view.name}\n onAction={() => applyView(view)}\n >\n {renderLabel(id, view)}\n </DropdownAction>\n ))}\n </DropdownMenu>\n </Dropdown>\n )}\n {/* Kept beside the views, so its width comes off theirs. */}\n <div ref={newViewRef} className=\"tds-data-table-saved-views-new-view\">\n {onCreate && <NewSavedViewButton onClick={openNewSavedView} />}\n <SaveStatusIcon\n label=\"View not saved\"\n status={saveStatus.statusFor(NEW_VIEW)}\n />\n </div>\n <NewSavedViewModal {...nameModal.modalProps} />\n </div>\n {views.length > 1 && (\n <ManageSavedViewsButton onClick={() => setIsManageOpen(true)} />\n )}\n {/* Rendered apart from the button, so a delete that hides the button doesn't remove the open modal. */}\n <ManageSavedViewsModal\n defaultViewId={defaultViewId}\n isReordering={isReordering}\n open={isManageOpen}\n savedViews={savedViews}\n staticViews={staticViews}\n onClose={closeManageViews}\n onCreate={onCreate}\n onDelete={onDelete}\n onReorder={onReorder}\n onSetDefault={onSetDefault}\n onUpdate={onUpdate}\n />\n {onDelete && (\n <DeleteSavedViewAlertDialog\n open={isDeleteAlertOpen}\n view={viewToDelete}\n onCancel={() => setIsDeleteAlertOpen(false)}\n onConfirm={confirmDelete}\n />\n )}\n </div>\n )\n}\n\nSavedViewsBar.displayName = \"SavedViewsBar\"\n\n/**\n * Once the manage views modal starts closing, focuses the selected view, or\n * the first one.\n */\nfunction useFocusSelectedViewAfterClose(\n barRef: RefObject<HTMLDivElement>,\n isManageOpen: boolean\n) {\n const shouldFocusRef = useRef(false)\n\n useEffect(() => {\n if (isManageOpen || !shouldFocusRef.current) return\n shouldFocusRef.current = false\n const bar = barRef.current\n ;(\n bar?.querySelector<HTMLElement>(\n '[role=\"option\"][aria-selected=\"true\"]'\n ) ?? bar?.querySelector<HTMLElement>('[role=\"option\"]')\n )?.focus()\n }, [barRef, isManageOpen])\n\n return () => {\n shouldFocusRef.current = true\n }\n}\n\n/**\n * Makes a saved view's option element itself the context menu trigger, so\n * the menu opens by right click, long press, or the keyboard context menu\n * shortcut (Shift+F10, the Menu key, or Ctrl+Enter on macOS), is named by\n * the view, and returns focus to it on close. `Pressable` hands the trigger's\n * handlers to the option element. The option ignores Ctrl+Enter, so the\n * macOS shortcut opens the menu without also selecting the view. The\n * `data-popup-open` attribute keeps the list from moving its tab\n * stop to the selected view while the menu is open. Opening the menu closes\n * any other view's menu, since a right click elsewhere in the list doesn't\n * count as an outside interaction. The open state stays here rather than in\n * the bar, because re-rendering the bar rebuilds the list's collection and\n * moves its tab stop before focus can return to this view. Each\n * `contextmenu` event remounts the menu, because React Aria only positions\n * an open menu once and would leave it at the first click point.\n */\nfunction ContextMenuTrigger({\n closeOpenContextMenuRef,\n id,\n menu,\n optionProps,\n}: {\n closeOpenContextMenuRef: MutableRefObject<(() => void) | null>\n id: SavedView[\"id\"]\n menu: ReactElement\n optionProps: ComponentProps<\"div\">\n}) {\n const { onKeyDown, ...restOptionProps } = optionProps\n const [isOpen, setIsOpen] = useState(false)\n // Such as the delete alert, which returns focus to this view on cancel.\n const hasOtherPopup = useContext(ReturningFocusViewIdContext) === id\n const [menuKey, setMenuKey] = useState(0)\n\n const close = useCallback(() => setIsOpen(false), [])\n const handleOpenChange = (nextIsOpen: boolean) => {\n setIsOpen(nextIsOpen)\n if (nextIsOpen) {\n closeOpenContextMenuRef.current?.()\n closeOpenContextMenuRef.current = close\n } else if (closeOpenContextMenuRef.current === close) {\n closeOpenContextMenuRef.current = null\n }\n }\n\n return (\n <MenuTrigger\n isOpen={isOpen}\n onOpenChange={handleOpenChange}\n trigger=\"contextMenu\"\n >\n <Pressable>\n <div\n {...mergeProps(restOptionProps, {\n \"data-popup-open\": isOpen || hasOtherPopup || undefined,\n onContextMenu: () => setMenuKey((key) => key + 1),\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.ctrlKey && event.key === \"Enter\") return\n onKeyDown?.(event)\n },\n })}\n />\n </Pressable>\n <Fragment key={menuKey}>{menu}</Fragment>\n </MenuTrigger>\n )\n}\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ import { type RefObject } from "react";
2
+ import type { Key } from "react-aria-components/ListBox";
3
+ /**
4
+ * Splits `items` into the ones that fit on one line in `listRef` and the
5
+ * ones that go in the overflow menu. Items keep their order. The active item
6
+ * always shows, taking the last visible slot when it would otherwise
7
+ * overflow.
8
+ *
9
+ * Item widths are kept from when each item last rendered, and a resize
10
+ * observer on the rendered items, the overflow trigger, the list, and
11
+ * `newViewRef` keeps them current. An item with no width yet, such as a new
12
+ * one, renders every item and the overflow trigger for one measuring pass.
13
+ * The list's items land a render after the list, so call `measure` once
14
+ * they're in the DOM.
15
+ */
16
+ export declare function useVisibleSavedViews<T extends {
17
+ id: Key;
18
+ }>({ activeKey, items, listRef, newViewRef, }: {
19
+ activeKey: Key | null;
20
+ items: T[];
21
+ listRef: RefObject<HTMLElement>;
22
+ /** The new view button and its save status, which follow the items. */
23
+ newViewRef: RefObject<HTMLElement>;
24
+ }): {
25
+ isCollapsed: boolean;
26
+ isMeasuring: boolean;
27
+ measure: () => void;
28
+ overflowItems: T[];
29
+ visibleItems: T[];
30
+ };
31
+ //# sourceMappingURL=useVisibleSavedViews.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVisibleSavedViews.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useVisibleSavedViews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAqC,MAAM,OAAO,CAAA;AACzE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,+BAA+B,CAAA;AAExD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,EAC1D,SAAS,EACT,KAAK,EACL,OAAO,EACP,UAAU,GACX,EAAE;IACD,SAAS,EAAE,GAAG,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,CAAC,EAAE,CAAA;IACV,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;IAC/B,uEAAuE;IACvE,UAAU,EAAE,SAAS,CAAC,WAAW,CAAC,CAAA;CACnC;;;;;;EAiHA"}
@@ -0,0 +1,178 @@
1
+ import { useState, useRef, useLayoutEffect } from 'react';
2
+
3
+ /**
4
+ * Splits `items` into the ones that fit on one line in `listRef` and the
5
+ * ones that go in the overflow menu. Items keep their order. The active item
6
+ * always shows, taking the last visible slot when it would otherwise
7
+ * overflow.
8
+ *
9
+ * Item widths are kept from when each item last rendered, and a resize
10
+ * observer on the rendered items, the overflow trigger, the list, and
11
+ * `newViewRef` keeps them current. An item with no width yet, such as a new
12
+ * one, renders every item and the overflow trigger for one measuring pass.
13
+ * The list's items land a render after the list, so call `measure` once
14
+ * they're in the DOM.
15
+ */
16
+ function useVisibleSavedViews({ activeKey, items, listRef, newViewRef, }) {
17
+ // By `data-key`, which is a string.
18
+ const [widths, setWidths] = useState(() => new Map());
19
+ const [overflowWidth, setOverflowWidth] = useState();
20
+ const [available, setAvailable] = useState(0);
21
+ const [gap, setGap] = useState(0);
22
+ const observerRef = useRef();
23
+ const observedRef = useRef(new Set());
24
+ const isMeasuring = overflowWidth === undefined ||
25
+ items.some(({ id }) => !widths.has(String(id)));
26
+ // Only reads refs and sets state, so the observer can keep the first one.
27
+ const read = () => {
28
+ const list = listRef.current;
29
+ if (!list)
30
+ return;
31
+ // Hidden, everything reads 0, so widths from before are kept.
32
+ const isHidden = list.clientWidth === 0;
33
+ if (!isHidden) {
34
+ const gap = readGap(list);
35
+ setAvailable(readAvailable(list, newViewRef.current, gap));
36
+ setGap(gap);
37
+ }
38
+ // Its count changes its width, which changes the count, so keep the
39
+ // widest to settle on one count.
40
+ const overflow = list.querySelector(OVERFLOW_SELECTOR);
41
+ if (overflow) {
42
+ const width = widthOf(overflow);
43
+ setOverflowWidth((current) => Math.max(current ?? 0, width));
44
+ }
45
+ const itemElements = list.querySelectorAll(ITEM_SELECTOR);
46
+ setWidths((current) => {
47
+ let next = current;
48
+ for (const itemElement of itemElements) {
49
+ const key = itemElement.dataset.key;
50
+ const width = fullWidthOf(itemElement);
51
+ if (key === undefined || current.get(key) === width)
52
+ continue;
53
+ if (isHidden && current.has(key))
54
+ continue;
55
+ if (next === current)
56
+ next = new Map(current);
57
+ next.set(key, width);
58
+ }
59
+ return next;
60
+ });
61
+ };
62
+ const measure = () => {
63
+ const list = listRef.current;
64
+ if (!list)
65
+ return;
66
+ const elements = new Set([
67
+ list,
68
+ ...(newViewRef.current ? [newViewRef.current] : []),
69
+ ...list.querySelectorAll(`${ITEM_SELECTOR}, ${OVERFLOW_SELECTOR}`),
70
+ ]);
71
+ const observed = observedRef.current;
72
+ // The observer reads size changes, so only added or removed elements
73
+ // need reading here.
74
+ const isSame = elements.size === observed.size &&
75
+ [...elements].every((element) => observed.has(element));
76
+ if (isSame)
77
+ return;
78
+ observedRef.current = elements;
79
+ read();
80
+ if (typeof ResizeObserver === "undefined")
81
+ return;
82
+ observerRef.current ??= new ResizeObserver(read);
83
+ for (const element of observed) {
84
+ if (!elements.has(element))
85
+ observerRef.current.unobserve(element);
86
+ }
87
+ for (const element of elements) {
88
+ if (!observed.has(element))
89
+ observerRef.current.observe(element);
90
+ }
91
+ };
92
+ // Cleared too, so a remount, such as StrictMode's, observes again.
93
+ useLayoutEffect(() => () => {
94
+ observerRef.current?.disconnect();
95
+ observerRef.current = undefined;
96
+ observedRef.current = new Set();
97
+ }, []);
98
+ // Drops the widths of deleted items.
99
+ useLayoutEffect(() => {
100
+ const keys = new Set(items.map(({ id }) => String(id)));
101
+ if ([...widths.keys()].some((key) => !keys.has(key))) {
102
+ setWidths(new Map([...widths].filter(([key]) => keys.has(key))));
103
+ }
104
+ }, [items, widths]);
105
+ let visibleItems = items;
106
+ let overflowItems = [];
107
+ if (!isMeasuring) {
108
+ let remaining = countFitting({
109
+ activeIndex: items.findIndex(({ id }) => id === activeKey),
110
+ available,
111
+ gap,
112
+ overflowWidth,
113
+ widths: items.map(({ id }) => widths.get(String(id)) ?? 0),
114
+ });
115
+ visibleItems = [];
116
+ overflowItems = [];
117
+ for (const item of items) {
118
+ if (item.id === activeKey || remaining-- > 0)
119
+ visibleItems.push(item);
120
+ else
121
+ overflowItems.push(item);
122
+ }
123
+ }
124
+ // Alone, the view truncates rather than overflow, whether the rest are in
125
+ // the overflow menu or it's the only one.
126
+ const isCollapsed = visibleItems.length === 1;
127
+ return { isCollapsed, isMeasuring, measure, overflowItems, visibleItems };
128
+ }
129
+ const ITEM_SELECTOR = ".tds-data-table-saved-view-list-item";
130
+ const NAME_SELECTOR = ".tds-data-table-saved-view-name";
131
+ const OVERFLOW_SELECTOR = ".tds-btn--data-table-saved-views-overflow";
132
+ /** The list's width, less the new view button, its save status, and a gap. */
133
+ function readAvailable(list, newView, gap) {
134
+ const newViewWidth = widthOf(newView);
135
+ return list.clientWidth - (newViewWidth ? newViewWidth + gap : 0);
136
+ }
137
+ function readGap(element) {
138
+ return parseFloat(getComputedStyle(element).columnGap) || 0;
139
+ }
140
+ function widthOf(element) {
141
+ return element?.getBoundingClientRect().width ?? 0;
142
+ }
143
+ /** Includes the part of its name cut off by truncation. */
144
+ function fullWidthOf(itemElement) {
145
+ const name = itemElement.querySelector(NAME_SELECTOR);
146
+ const truncated = name ? name.scrollWidth - name.clientWidth : 0;
147
+ return widthOf(itemElement) + truncated;
148
+ }
149
+ // Measured widths can be fractional, but the list's width is rounded.
150
+ const SUBPIXEL_SLACK = 1;
151
+ function countFitting({ activeIndex, available, gap, overflowWidth, widths, }) {
152
+ const limit = available + SUBPIXEL_SLACK;
153
+ // Each item counts with the gap after it, which comes before the overflow
154
+ // trigger, or after the last item doesn't exist. The active item's width is
155
+ // set aside first so it always shows.
156
+ let used = activeIndex === -1 ? 0 : widths[activeIndex] + gap;
157
+ // Items that still fit with the overflow trigger beside them.
158
+ let fitsWithOverflow = 0;
159
+ for (let index = 0; index < widths.length; index++) {
160
+ if (index === activeIndex)
161
+ continue;
162
+ used += widths[index] + gap;
163
+ // Out of room, so the overflow trigger is needed. With no active item,
164
+ // the first item shows anyway.
165
+ if (used - gap > limit) {
166
+ return activeIndex === -1
167
+ ? Math.max(fitsWithOverflow, 1)
168
+ : fitsWithOverflow;
169
+ }
170
+ if (used + overflowWidth <= limit)
171
+ fitsWithOverflow++;
172
+ }
173
+ // Every item fits, so there's no overflow trigger.
174
+ return Infinity;
175
+ }
176
+
177
+ export { useVisibleSavedViews };
178
+ //# sourceMappingURL=useVisibleSavedViews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVisibleSavedViews.js","sources":["../../../src/components/DataTable/useVisibleSavedViews.ts"],"sourcesContent":["import { type RefObject, useLayoutEffect, useRef, useState } from \"react\"\nimport type { Key } from \"react-aria-components/ListBox\"\n\n/**\n * Splits `items` into the ones that fit on one line in `listRef` and the\n * ones that go in the overflow menu. Items keep their order. The active item\n * always shows, taking the last visible slot when it would otherwise\n * overflow.\n *\n * Item widths are kept from when each item last rendered, and a resize\n * observer on the rendered items, the overflow trigger, the list, and\n * `newViewRef` keeps them current. An item with no width yet, such as a new\n * one, renders every item and the overflow trigger for one measuring pass.\n * The list's items land a render after the list, so call `measure` once\n * they're in the DOM.\n */\nexport function useVisibleSavedViews<T extends { id: Key }>({\n activeKey,\n items,\n listRef,\n newViewRef,\n}: {\n activeKey: Key | null\n items: T[]\n listRef: RefObject<HTMLElement>\n /** The new view button and its save status, which follow the items. */\n newViewRef: RefObject<HTMLElement>\n}) {\n // By `data-key`, which is a string.\n const [widths, setWidths] = useState(() => new Map<string, number>())\n const [overflowWidth, setOverflowWidth] = useState<number>()\n const [available, setAvailable] = useState(0)\n const [gap, setGap] = useState(0)\n const observerRef = useRef<ResizeObserver>()\n const observedRef = useRef(new Set<Element>())\n\n const isMeasuring =\n overflowWidth === undefined ||\n items.some(({ id }) => !widths.has(String(id)))\n\n // Only reads refs and sets state, so the observer can keep the first one.\n const read = () => {\n const list = listRef.current\n if (!list) return\n // Hidden, everything reads 0, so widths from before are kept.\n const isHidden = list.clientWidth === 0\n if (!isHidden) {\n const gap = readGap(list)\n setAvailable(readAvailable(list, newViewRef.current, gap))\n setGap(gap)\n }\n // Its count changes its width, which changes the count, so keep the\n // widest to settle on one count.\n const overflow = list.querySelector(OVERFLOW_SELECTOR)\n if (overflow) {\n const width = widthOf(overflow)\n setOverflowWidth((current) => Math.max(current ?? 0, width))\n }\n const itemElements = list.querySelectorAll<HTMLElement>(ITEM_SELECTOR)\n setWidths((current) => {\n let next = current\n for (const itemElement of itemElements) {\n const key = itemElement.dataset.key\n const width = fullWidthOf(itemElement)\n if (key === undefined || current.get(key) === width) continue\n if (isHidden && current.has(key)) continue\n if (next === current) next = new Map(current)\n next.set(key, width)\n }\n return next\n })\n }\n\n const measure = () => {\n const list = listRef.current\n if (!list) return\n const elements = new Set<Element>([\n list,\n ...(newViewRef.current ? [newViewRef.current] : []),\n ...list.querySelectorAll(`${ITEM_SELECTOR}, ${OVERFLOW_SELECTOR}`),\n ])\n const observed = observedRef.current\n // The observer reads size changes, so only added or removed elements\n // need reading here.\n const isSame =\n elements.size === observed.size &&\n [...elements].every((element) => observed.has(element))\n if (isSame) return\n observedRef.current = elements\n read()\n if (typeof ResizeObserver === \"undefined\") return\n observerRef.current ??= new ResizeObserver(read)\n for (const element of observed) {\n if (!elements.has(element)) observerRef.current.unobserve(element)\n }\n for (const element of elements) {\n if (!observed.has(element)) observerRef.current.observe(element)\n }\n }\n\n // Cleared too, so a remount, such as StrictMode's, observes again.\n useLayoutEffect(\n () => () => {\n observerRef.current?.disconnect()\n observerRef.current = undefined\n observedRef.current = new Set()\n },\n []\n )\n\n // Drops the widths of deleted items.\n useLayoutEffect(() => {\n const keys = new Set(items.map(({ id }) => String(id)))\n if ([...widths.keys()].some((key) => !keys.has(key))) {\n setWidths(new Map([...widths].filter(([key]) => keys.has(key))))\n }\n }, [items, widths])\n\n let visibleItems = items\n let overflowItems: T[] = []\n if (!isMeasuring) {\n let remaining = countFitting({\n activeIndex: items.findIndex(({ id }) => id === activeKey),\n available,\n gap,\n overflowWidth,\n widths: items.map(({ id }) => widths.get(String(id)) ?? 0),\n })\n visibleItems = []\n overflowItems = []\n for (const item of items) {\n if (item.id === activeKey || remaining-- > 0) visibleItems.push(item)\n else overflowItems.push(item)\n }\n }\n // Alone, the view truncates rather than overflow, whether the rest are in\n // the overflow menu or it's the only one.\n const isCollapsed = visibleItems.length === 1\n\n return { isCollapsed, isMeasuring, measure, overflowItems, visibleItems }\n}\n\nconst ITEM_SELECTOR = \".tds-data-table-saved-view-list-item\"\nconst NAME_SELECTOR = \".tds-data-table-saved-view-name\"\nconst OVERFLOW_SELECTOR = \".tds-btn--data-table-saved-views-overflow\"\n\n/** The list's width, less the new view button, its save status, and a gap. */\nfunction readAvailable(\n list: HTMLElement,\n newView: HTMLElement | null,\n gap: number\n) {\n const newViewWidth = widthOf(newView)\n return list.clientWidth - (newViewWidth ? newViewWidth + gap : 0)\n}\n\nfunction readGap(element: Element) {\n return parseFloat(getComputedStyle(element).columnGap) || 0\n}\n\nfunction widthOf(element: Element | null) {\n return element?.getBoundingClientRect().width ?? 0\n}\n\n/** Includes the part of its name cut off by truncation. */\nfunction fullWidthOf(itemElement: Element) {\n const name = itemElement.querySelector(NAME_SELECTOR)\n const truncated = name ? name.scrollWidth - name.clientWidth : 0\n return widthOf(itemElement) + truncated\n}\n\n// Measured widths can be fractional, but the list's width is rounded.\nconst SUBPIXEL_SLACK = 1\n\nfunction countFitting({\n activeIndex,\n available,\n gap,\n overflowWidth,\n widths,\n}: {\n activeIndex: number\n available: number\n gap: number\n overflowWidth: number\n widths: number[]\n}) {\n const limit = available + SUBPIXEL_SLACK\n // Each item counts with the gap after it, which comes before the overflow\n // trigger, or after the last item doesn't exist. The active item's width is\n // set aside first so it always shows.\n let used = activeIndex === -1 ? 0 : widths[activeIndex] + gap\n // Items that still fit with the overflow trigger beside them.\n let fitsWithOverflow = 0\n for (let index = 0; index < widths.length; index++) {\n if (index === activeIndex) continue\n used += widths[index] + gap\n // Out of room, so the overflow trigger is needed. With no active item,\n // the first item shows anyway.\n if (used - gap > limit) {\n return activeIndex === -1\n ? Math.max(fitsWithOverflow, 1)\n : fitsWithOverflow\n }\n if (used + overflowWidth <= limit) fitsWithOverflow++\n }\n // Every item fits, so there's no overflow trigger.\n return Infinity\n}\n"],"names":[],"mappings":"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"}
@@ -24,6 +24,12 @@ export interface ReorderableListBoxProps<T extends {
24
24
  items: readonly T[];
25
25
  /** Accessible label for the list. */
26
26
  label: string;
27
+ /**
28
+ * Called once the items are in the DOM, before paint. React Aria builds
29
+ * the collection after the list renders, so the items land a render later
30
+ * than the list.
31
+ */
32
+ onItemsRendered?: () => void;
27
33
  /**
28
34
  * Called with all items in their new order after the user moves an item.
29
35
  * Omit to turn off reordering.
@@ -1 +1 @@
1
- {"version":3,"file":"ReorderableListBox.d.ts","sourceRoot":"","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA;AAEhF,OAAO,KAAK,EAAE,EAAE,KAAK,YAAY,EAAqB,MAAM,OAAO,CAAA;AAKnE,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAEL,KAAK,+BAA+B,EAErC,MAAM,sCAAsC,CAAA;AAG7C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,+BAA+B,GAChD,CAAC,EAAE,CAgBL;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE;IAC1E,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,CAAA;IACnC,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,GAAG,CAAA;IACxB,mEAAmE;IACnE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAChC,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IACtC,sEAAsE;IACtE,WAAW,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,MAAM,8BAA8B,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,IACjC,+BAA+B,CACjC,YAAY,CAAC,CAAC,CAAC,EACf,uBAAuB,CAAC,CAAC,CAAC,EAC1B,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,MAAM,CACxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,EACtE,QAAQ,EACR,KAAK,EACL,GAAG,SAAS,EACb,EAAE,8BAA8B,CAAC,CAAC,CAAC,qBAcnC;yBAlBe,kBAAkB;;;AA6HlC,MAAM,WAAW,2BAA2B;IAC1C,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,EAAE,EAAE,GAAG,CAAA;IACP;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,SAAS,EACT,EAAE,EACF,MAAM,GACP,EAAE,2BAA2B,qBAW7B;yBAhBe,sBAAsB"}
1
+ {"version":3,"file":"ReorderableListBox.d.ts","sourceRoot":"","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA;AAEhF,OAAO,KAAK,EAAE,EACZ,KAAK,YAAY,EAIlB,MAAM,OAAO,CAAA;AAKd,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAEL,KAAK,+BAA+B,EAErC,MAAM,sCAAsC,CAAA;AAG7C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,+BAA+B,GAChD,CAAC,EAAE,CAgBL;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE;IAC1E,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,CAAA;IACnC,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,GAAG,CAAA;IACxB,mEAAmE;IACnE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAChC,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IACtC,sEAAsE;IACtE,WAAW,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,MAAM,8BAA8B,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,IACjC,+BAA+B,CACjC,YAAY,CAAC,CAAC,CAAC,EACf,uBAAuB,CAAC,CAAC,CAAC,EAC1B,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,MAAM,CACxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,EACtE,QAAQ,EACR,KAAK,EACL,GAAG,SAAS,EACb,EAAE,8BAA8B,CAAC,CAAC,CAAC,qBAcnC;yBAlBe,kBAAkB;;;AAqIlC,MAAM,WAAW,2BAA2B;IAC1C,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,EAAE,EAAE,GAAG,CAAA;IACP;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,SAAS,EACT,EAAE,EACF,MAAM,GACP,EAAE,2BAA2B,qBAW7B;yBAhBe,sBAAsB"}
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import React__default, { useRef, useEffect } from 'react';
2
+ import React__default, { useRef, useLayoutEffect, useEffect } from 'react';
3
3
  import { useLocale } from 'react-aria/I18nProvider';
4
4
  import { ListDropTargetDelegate } from 'react-aria/ListDropTargetDelegate';
5
5
  import { Collection } from 'react-aria-components/Collection';
@@ -49,8 +49,15 @@ ReorderableListBox.displayName = "ReorderableListBox";
49
49
  * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears
50
50
  * `isFocused` while focus stays in the list.
51
51
  */
52
- function ReorderableListBoxWithState({ className, collection, defaultSelectedKey, items, label, onReorder, onSelectionChange, selectedKey, ...restProps }) {
52
+ function ReorderableListBoxWithState({ className, collection, defaultSelectedKey, items, label, onItemsRendered, onReorder, onSelectionChange, selectedKey, ...restProps }) {
53
53
  const listRef = useRef(null);
54
+ // Read when the collection changes, not when the callback does, since the
55
+ // callback can change before the items do.
56
+ const onItemsRenderedRef = useRef(onItemsRendered);
57
+ onItemsRenderedRef.current = onItemsRendered;
58
+ useLayoutEffect(() => {
59
+ onItemsRenderedRef.current?.();
60
+ }, [collection]);
54
61
  const { direction } = useLocale();
55
62
  const handleSelectionChange = (keys) => {
56
63
  if (keys === "all")
@@ -1 +1 @@
1
- {"version":3,"file":"ReorderableListBox.js","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"sourcesContent":["import type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, { type ReactElement, useEffect, useRef } from \"react\"\nimport { useLocale } from \"react-aria/I18nProvider\"\nimport { ListDropTargetDelegate } from \"react-aria/ListDropTargetDelegate\"\nimport { Collection } from \"react-aria-components/Collection\"\nimport { CollectionBuilder } from \"react-aria-components/CollectionBuilder\"\nimport {\n type Key,\n ListBox,\n ListBoxItem,\n type ListBoxItemProps,\n type ListBoxProps,\n ListStateContext,\n type Selection,\n} from \"react-aria-components/ListBox\"\nimport {\n DropIndicator,\n type DroppableCollectionReorderEvent,\n useDragAndDrop,\n} from \"react-aria-components/useDragAndDrop\"\nimport { type ListState, useListState } from \"react-stately/useListState\"\n\n/**\n * Returns `items` with the moved item placed before or after the drop\n * target. Single selection means only one item moves at a time.\n */\nexport function reorderItems<T extends { id: Key }>(\n items: readonly T[],\n { keys, target }: DroppableCollectionReorderEvent\n): T[] {\n const [movedKey] = keys\n const reordered = [...items]\n const fromIndex = reordered.findIndex((item) => item.id === movedKey)\n const hasTarget = reordered.some((item) => item.id === target.key)\n if (fromIndex === -1 || !hasTarget || target.key === movedKey) {\n return reordered\n }\n\n const [movedItem] = reordered.splice(fromIndex, 1)\n const targetIndex = reordered.findIndex((item) => item.id === target.key)\n\n const insertIndex =\n target.dropPosition === \"after\" ? targetIndex + 1 : targetIndex\n reordered.splice(insertIndex, 0, movedItem)\n return reordered\n}\n\nexport interface ReorderableListBoxProps<T extends { id: Key } = { id: Key }> {\n /** Renders each item as a `ReorderableListBoxItem`. */\n children: (item: T) => ReactElement\n /** Custom class name for the list. */\n className?: string\n /** Uncontrolled initially selected item's `id`. */\n defaultSelectedKey?: Key\n /** Items to render, in display order. Each needs a unique `id`. */\n items: readonly T[]\n /** Accessible label for the list. */\n label: string\n /**\n * Called with all items in their new order after the user moves an item.\n * Omit to turn off reordering.\n */\n onReorder?: (items: T[]) => void\n /** Called with the newly selected item's `id`. */\n onSelectionChange?: (key: Key) => void\n /** Controlled selected item's `id`. Pass `null` to select no item. */\n selectedKey?: Key | null\n}\n\nexport type ReorderableListBoxElementProps<\n T extends { id: Key } = { id: Key },\n> = CombineAriaPropsWithCustomProps<\n ListBoxProps<T>,\n ReorderableListBoxProps<T>,\n \"aria-label\" | \"aria-labelledby\" | \"autoFocus\" | \"slot\"\n>\n\n/**\n * A list of items where the user selects one item and cannot clear the\n * selection, and which the user can reorder by drag or by keyboard. Tab\n * enters the list on the selected item. Internal to `DataTable` saved views.\n *\n * @component\n */\nexport function ReorderableListBox<T extends { id: Key } = { id: Key }>({\n children,\n items,\n ...restProps\n}: ReorderableListBoxElementProps<T>) {\n return (\n <CollectionBuilder\n content={<Collection items={items}>{children}</Collection>}\n >\n {(collection) => (\n <ReorderableListBoxWithState\n {...restProps}\n collection={collection}\n items={items}\n />\n )}\n </CollectionBuilder>\n )\n}\n\nReorderableListBox.displayName = \"ReorderableListBox\"\n\ntype ReorderableListBoxWithStateProps<T extends { id: Key }> = Omit<\n ReorderableListBoxElementProps<T>,\n \"children\"\n> & {\n collection: ListState<T>[\"collection\"]\n}\n\n/**\n * Owns the list state and hands it to `ListBox` through `ListStateContext`,\n * the same way React Aria's `Select` does. The drop target delegate needs the\n * state's collection. While DOM focus is outside the list, it keeps the\n * selected item as the tab stop. With no selection, the item that last had\n * focus stays the tab stop, or else the first item. The list itself can\n * then never be the tab stop, which it cannot be while it has no box of its\n * own. It skips this while an item marked `data-popup-open` has a popup,\n * such as a context menu, open, so focus returns to that item, not the\n * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears\n * `isFocused` while focus stays in the list.\n */\nfunction ReorderableListBoxWithState<T extends { id: Key }>({\n className,\n collection,\n defaultSelectedKey,\n items,\n label,\n onReorder,\n onSelectionChange,\n selectedKey,\n ...restProps\n}: ReorderableListBoxWithStateProps<T>) {\n const listRef = useRef<HTMLDivElement>(null)\n const { direction } = useLocale()\n\n const handleSelectionChange = (keys: Selection) => {\n if (keys === \"all\") return\n const [key] = keys\n if (key !== undefined) onSelectionChange?.(key)\n }\n\n const state = useListState<T>({\n collection,\n defaultSelectedKeys:\n defaultSelectedKey === undefined ? undefined : [defaultSelectedKey],\n disallowEmptySelection: true,\n onSelectionChange: handleSelectionChange,\n selectedKeys:\n selectedKey === undefined\n ? undefined\n : selectedKey === null\n ? []\n : [selectedKey],\n selectionMode: \"single\",\n })\n\n const { selectionManager } = state\n useEffect(() => {\n if (listRef.current?.contains(document.activeElement)) return\n if (listRef.current?.querySelector(\"[data-popup-open]\")) return\n const { collection, focusedKey, selectedKeys } = selectionManager\n const [key] = selectedKeys\n const tabStopKey = key ?? focusedKey ?? collection.getFirstKey()\n if (tabStopKey !== null && focusedKey !== tabStopKey) {\n selectionManager.setFocusedKey(tabStopKey)\n }\n }, [selectionManager])\n\n const { dragAndDropHooks } = useDragAndDrop<T>({\n dropTargetDelegate: new ListDropTargetDelegate(state.collection, listRef, {\n direction,\n layout: \"grid\",\n orientation: \"vertical\",\n }),\n getItems: (keys) =>\n [...keys].map((key) => ({\n \"text/plain\": state.collection.getItem(key)?.textValue ?? String(key),\n })),\n onReorder: (event) => {\n const reordered = reorderItems(items, event)\n const isMoved = reordered.some((item, index) => item !== items[index])\n if (isMoved) onReorder?.(reordered)\n },\n renderDropIndicator: (target) => (\n <DropIndicator\n className=\"tds-reorderable-list-box-drop-indicator\"\n target={target}\n />\n ),\n })\n\n return (\n <ListStateContext.Provider value={state}>\n <ListBox\n {...restProps}\n aria-label={label}\n className={classNames(\"tds-reorderable-list-box\", className)}\n dragAndDropHooks={onReorder ? dragAndDropHooks : undefined}\n orientation=\"horizontal\"\n ref={listRef}\n />\n </ListStateContext.Provider>\n )\n}\n\nexport interface ReorderableListBoxItemProps {\n /** Plain-text item label. */\n children: string\n /** Custom class name for the item, such as a pill look. */\n className?: string\n /** Identifies the item. */\n id: Key\n /**\n * Renders the option element in place of the default `<div>`, such as to\n * wrap it in a context menu trigger.\n */\n render?: ListBoxItemProps[\"render\"]\n}\n\n/**\n * A single item within a {@link ReorderableListBox}.\n *\n * @component\n */\nexport function ReorderableListBoxItem({\n children,\n className,\n id,\n render,\n}: ReorderableListBoxItemProps) {\n return (\n <ListBoxItem\n className={classNames(\"tds-reorderable-list-box-item\", className)}\n id={id}\n render={render}\n textValue={children}\n >\n {children}\n </ListBoxItem>\n )\n}\n\nReorderableListBoxItem.displayName = \"ReorderableListBoxItem\"\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"ReorderableListBox.js","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"sourcesContent":["import type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ReactElement,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\"\nimport { useLocale } from \"react-aria/I18nProvider\"\nimport { ListDropTargetDelegate } from \"react-aria/ListDropTargetDelegate\"\nimport { Collection } from \"react-aria-components/Collection\"\nimport { CollectionBuilder } from \"react-aria-components/CollectionBuilder\"\nimport {\n type Key,\n ListBox,\n ListBoxItem,\n type ListBoxItemProps,\n type ListBoxProps,\n ListStateContext,\n type Selection,\n} from \"react-aria-components/ListBox\"\nimport {\n DropIndicator,\n type DroppableCollectionReorderEvent,\n useDragAndDrop,\n} from \"react-aria-components/useDragAndDrop\"\nimport { type ListState, useListState } from \"react-stately/useListState\"\n\n/**\n * Returns `items` with the moved item placed before or after the drop\n * target. Single selection means only one item moves at a time.\n */\nexport function reorderItems<T extends { id: Key }>(\n items: readonly T[],\n { keys, target }: DroppableCollectionReorderEvent\n): T[] {\n const [movedKey] = keys\n const reordered = [...items]\n const fromIndex = reordered.findIndex((item) => item.id === movedKey)\n const hasTarget = reordered.some((item) => item.id === target.key)\n if (fromIndex === -1 || !hasTarget || target.key === movedKey) {\n return reordered\n }\n\n const [movedItem] = reordered.splice(fromIndex, 1)\n const targetIndex = reordered.findIndex((item) => item.id === target.key)\n\n const insertIndex =\n target.dropPosition === \"after\" ? targetIndex + 1 : targetIndex\n reordered.splice(insertIndex, 0, movedItem)\n return reordered\n}\n\nexport interface ReorderableListBoxProps<T extends { id: Key } = { id: Key }> {\n /** Renders each item as a `ReorderableListBoxItem`. */\n children: (item: T) => ReactElement\n /** Custom class name for the list. */\n className?: string\n /** Uncontrolled initially selected item's `id`. */\n defaultSelectedKey?: Key\n /** Items to render, in display order. Each needs a unique `id`. */\n items: readonly T[]\n /** Accessible label for the list. */\n label: string\n /**\n * Called once the items are in the DOM, before paint. React Aria builds\n * the collection after the list renders, so the items land a render later\n * than the list.\n */\n onItemsRendered?: () => void\n /**\n * Called with all items in their new order after the user moves an item.\n * Omit to turn off reordering.\n */\n onReorder?: (items: T[]) => void\n /** Called with the newly selected item's `id`. */\n onSelectionChange?: (key: Key) => void\n /** Controlled selected item's `id`. Pass `null` to select no item. */\n selectedKey?: Key | null\n}\n\nexport type ReorderableListBoxElementProps<\n T extends { id: Key } = { id: Key },\n> = CombineAriaPropsWithCustomProps<\n ListBoxProps<T>,\n ReorderableListBoxProps<T>,\n \"aria-label\" | \"aria-labelledby\" | \"autoFocus\" | \"slot\"\n>\n\n/**\n * A list of items where the user selects one item and cannot clear the\n * selection, and which the user can reorder by drag or by keyboard. Tab\n * enters the list on the selected item. Internal to `DataTable` saved views.\n *\n * @component\n */\nexport function ReorderableListBox<T extends { id: Key } = { id: Key }>({\n children,\n items,\n ...restProps\n}: ReorderableListBoxElementProps<T>) {\n return (\n <CollectionBuilder\n content={<Collection items={items}>{children}</Collection>}\n >\n {(collection) => (\n <ReorderableListBoxWithState\n {...restProps}\n collection={collection}\n items={items}\n />\n )}\n </CollectionBuilder>\n )\n}\n\nReorderableListBox.displayName = \"ReorderableListBox\"\n\ntype ReorderableListBoxWithStateProps<T extends { id: Key }> = Omit<\n ReorderableListBoxElementProps<T>,\n \"children\"\n> & {\n collection: ListState<T>[\"collection\"]\n}\n\n/**\n * Owns the list state and hands it to `ListBox` through `ListStateContext`,\n * the same way React Aria's `Select` does. The drop target delegate needs the\n * state's collection. While DOM focus is outside the list, it keeps the\n * selected item as the tab stop. With no selection, the item that last had\n * focus stays the tab stop, or else the first item. The list itself can\n * then never be the tab stop, which it cannot be while it has no box of its\n * own. It skips this while an item marked `data-popup-open` has a popup,\n * such as a context menu, open, so focus returns to that item, not the\n * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears\n * `isFocused` while focus stays in the list.\n */\nfunction ReorderableListBoxWithState<T extends { id: Key }>({\n className,\n collection,\n defaultSelectedKey,\n items,\n label,\n onItemsRendered,\n onReorder,\n onSelectionChange,\n selectedKey,\n ...restProps\n}: ReorderableListBoxWithStateProps<T>) {\n const listRef = useRef<HTMLDivElement>(null)\n // Read when the collection changes, not when the callback does, since the\n // callback can change before the items do.\n const onItemsRenderedRef = useRef(onItemsRendered)\n onItemsRenderedRef.current = onItemsRendered\n useLayoutEffect(() => {\n onItemsRenderedRef.current?.()\n }, [collection])\n const { direction } = useLocale()\n\n const handleSelectionChange = (keys: Selection) => {\n if (keys === \"all\") return\n const [key] = keys\n if (key !== undefined) onSelectionChange?.(key)\n }\n\n const state = useListState<T>({\n collection,\n defaultSelectedKeys:\n defaultSelectedKey === undefined ? undefined : [defaultSelectedKey],\n disallowEmptySelection: true,\n onSelectionChange: handleSelectionChange,\n selectedKeys:\n selectedKey === undefined\n ? undefined\n : selectedKey === null\n ? []\n : [selectedKey],\n selectionMode: \"single\",\n })\n\n const { selectionManager } = state\n useEffect(() => {\n if (listRef.current?.contains(document.activeElement)) return\n if (listRef.current?.querySelector(\"[data-popup-open]\")) return\n const { collection, focusedKey, selectedKeys } = selectionManager\n const [key] = selectedKeys\n const tabStopKey = key ?? focusedKey ?? collection.getFirstKey()\n if (tabStopKey !== null && focusedKey !== tabStopKey) {\n selectionManager.setFocusedKey(tabStopKey)\n }\n }, [selectionManager])\n\n const { dragAndDropHooks } = useDragAndDrop<T>({\n dropTargetDelegate: new ListDropTargetDelegate(state.collection, listRef, {\n direction,\n layout: \"grid\",\n orientation: \"vertical\",\n }),\n getItems: (keys) =>\n [...keys].map((key) => ({\n \"text/plain\": state.collection.getItem(key)?.textValue ?? String(key),\n })),\n onReorder: (event) => {\n const reordered = reorderItems(items, event)\n const isMoved = reordered.some((item, index) => item !== items[index])\n if (isMoved) onReorder?.(reordered)\n },\n renderDropIndicator: (target) => (\n <DropIndicator\n className=\"tds-reorderable-list-box-drop-indicator\"\n target={target}\n />\n ),\n })\n\n return (\n <ListStateContext.Provider value={state}>\n <ListBox\n {...restProps}\n aria-label={label}\n className={classNames(\"tds-reorderable-list-box\", className)}\n dragAndDropHooks={onReorder ? dragAndDropHooks : undefined}\n orientation=\"horizontal\"\n ref={listRef}\n />\n </ListStateContext.Provider>\n )\n}\n\nexport interface ReorderableListBoxItemProps {\n /** Plain-text item label. */\n children: string\n /** Custom class name for the item, such as a pill look. */\n className?: string\n /** Identifies the item. */\n id: Key\n /**\n * Renders the option element in place of the default `<div>`, such as to\n * wrap it in a context menu trigger.\n */\n render?: ListBoxItemProps[\"render\"]\n}\n\n/**\n * A single item within a {@link ReorderableListBox}.\n *\n * @component\n */\nexport function ReorderableListBoxItem({\n children,\n className,\n id,\n render,\n}: ReorderableListBoxItemProps) {\n return (\n <ListBoxItem\n className={classNames(\"tds-reorderable-list-box-item\", className)}\n id={id}\n render={render}\n textValue={children}\n >\n {children}\n </ListBoxItem>\n )\n}\n\nReorderableListBoxItem.displayName = \"ReorderableListBoxItem\"\n"],"names":["React"],"mappings":"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"}
package/dist/index.css CHANGED
@@ -160,14 +160,15 @@
160
160
  --t-fill-color-product-checkins-060:hsl(283, 27%, 42%);
161
161
  --t-fill-color-product-checkins-070:hsl(284, 33%, 34%);
162
162
  --t-fill-color-product-checkins-080:hsl(283, 33%, 27%);
163
- --t-fill-color-product-giving-010:hsl(41, 95%, 93%);
164
- --t-fill-color-product-giving-020:hsl(42, 95%, 83%);
165
- --t-fill-color-product-giving-030:hsl(43, 95%, 75%);
166
- --t-fill-color-product-giving-040:hsl(43, 88%, 70%);
163
+ --t-fill-color-product-giving-010:hsl(42, 81%, 94%);
164
+ --t-fill-color-product-giving-020:hsl(41, 75%, 83%);
165
+ --t-fill-color-product-giving-030:hsl(41, 80%, 76%);
166
+ --t-fill-color-product-giving-040:hsl(42, 87%, 70%);
167
167
  --t-fill-color-product-giving-050:hsl(43, 88%, 64%);
168
- --t-fill-color-product-giving-060:hsl(42, 84%, 55%);
169
- --t-fill-color-product-giving-070:hsl(42, 84%, 48%);
170
- --t-fill-color-product-giving-080:hsl(42, 100%, 40%);
168
+ --t-fill-color-product-giving-060:hsl(46, 100%, 29%);
169
+ --t-fill-color-product-giving-070:hsl(45, 100%, 22%);
170
+ --t-fill-color-product-giving-080:hsl(44, 100%, 17%);
171
+ --t-fill-color-product-giving-090:hsl(41, 25%, 13%);
171
172
  --t-fill-color-product-groups-010:hsl(18, 95%, 92%);
172
173
  --t-fill-color-product-groups-020:hsl(17, 96%, 80%);
173
174
  --t-fill-color-product-groups-030:hsl(17, 96%, 70%);