@planningcenter/tapestry 4.11.0 → 4.12.0-rc.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.
- package/dist/components/DataTable/DataTable.d.ts +47 -13
- package/dist/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/components/DataTable/DataTable.js +29 -23
- package/dist/components/DataTable/DataTable.js.map +1 -1
- package/dist/components/DataTable/DeleteSavedViewAlertDialog.d.ts +14 -0
- package/dist/components/DataTable/DeleteSavedViewAlertDialog.d.ts.map +1 -0
- package/dist/components/DataTable/DeleteSavedViewAlertDialog.js +10 -0
- package/dist/components/DataTable/DeleteSavedViewAlertDialog.js.map +1 -0
- package/dist/components/DataTable/ManageSavedViewsButton.d.ts +4 -1
- package/dist/components/DataTable/ManageSavedViewsButton.d.ts.map +1 -1
- package/dist/components/DataTable/ManageSavedViewsButton.js +3 -7
- package/dist/components/DataTable/ManageSavedViewsButton.js.map +1 -1
- package/dist/components/DataTable/ManageSavedViewsModal.d.ts +8 -1
- package/dist/components/DataTable/ManageSavedViewsModal.d.ts.map +1 -1
- package/dist/components/DataTable/ManageSavedViewsModal.js +116 -5
- package/dist/components/DataTable/ManageSavedViewsModal.js.map +1 -1
- package/dist/components/DataTable/ManageSavedViewsModal.module.css.js +4 -0
- package/dist/components/DataTable/ManageSavedViewsModal.module.css.js.map +1 -0
- package/dist/components/DataTable/NewSavedViewModal.d.ts +4 -1
- package/dist/components/DataTable/NewSavedViewModal.d.ts.map +1 -1
- package/dist/components/DataTable/NewSavedViewModal.js.map +1 -1
- package/dist/components/DataTable/ResultsCount.d.ts +9 -0
- package/dist/components/DataTable/ResultsCount.d.ts.map +1 -1
- package/dist/components/DataTable/ResultsCount.js +1 -1
- package/dist/components/DataTable/ResultsCount.js.map +1 -1
- package/dist/components/DataTable/SavedViewsBar.d.ts +14 -6
- package/dist/components/DataTable/SavedViewsBar.d.ts.map +1 -1
- package/dist/components/DataTable/SavedViewsBar.js +162 -45
- package/dist/components/DataTable/SavedViewsBar.js.map +1 -1
- package/dist/components/DataTable/TableActions.d.ts.map +1 -1
- package/dist/components/DataTable/TableActions.js +4 -6
- package/dist/components/DataTable/TableActions.js.map +1 -1
- package/dist/components/DataTable/ViewSettingsToggle.d.ts.map +1 -1
- package/dist/components/DataTable/ViewSettingsToggle.js +2 -4
- package/dist/components/DataTable/ViewSettingsToggle.js.map +1 -1
- package/dist/components/DataTable/index.d.ts +1 -1
- package/dist/components/DataTable/index.d.ts.map +1 -1
- package/dist/components/DataTable/savedViews.d.ts +16 -15
- package/dist/components/DataTable/savedViews.d.ts.map +1 -1
- package/dist/components/DataTable/savedViews.js +28 -6
- package/dist/components/DataTable/savedViews.js.map +1 -1
- package/dist/components/DataTable/useActiveSavedView.d.ts +1 -1
- package/dist/components/DataTable/useActiveSavedView.d.ts.map +1 -1
- package/dist/components/DataTable/useActiveSavedView.js +9 -3
- package/dist/components/DataTable/useActiveSavedView.js.map +1 -1
- package/dist/components/DataTable/useFilterAnnouncement.d.ts +24 -0
- package/dist/components/DataTable/useFilterAnnouncement.d.ts.map +1 -0
- package/dist/components/DataTable/useFilterAnnouncement.js +49 -0
- package/dist/components/DataTable/useFilterAnnouncement.js.map +1 -0
- package/dist/components/DataTable/useUpdateSavedViewName.d.ts +7 -0
- package/dist/components/DataTable/useUpdateSavedViewName.d.ts.map +1 -0
- package/dist/components/DataTable/useUpdateSavedViewName.js +12 -0
- package/dist/components/DataTable/useUpdateSavedViewName.js.map +1 -0
- package/dist/components/button/ActionsDropdownIconButton.d.ts +17 -9
- package/dist/components/button/ActionsDropdownIconButton.d.ts.map +1 -1
- package/dist/components/button/ActionsDropdownIconButton.js +5 -2
- package/dist/components/button/ActionsDropdownIconButton.js.map +1 -1
- package/dist/components/button/DropdownIconButton.d.ts +4 -5
- package/dist/components/button/DropdownIconButton.d.ts.map +1 -1
- package/dist/components/button/DropdownIconButton.js +2 -1
- package/dist/components/button/DropdownIconButton.js.map +1 -1
- package/dist/components/button/IconButton.d.ts +33 -10
- package/dist/components/button/IconButton.d.ts.map +1 -1
- package/dist/components/button/IconButton.js +8 -2
- package/dist/components/button/IconButton.js.map +1 -1
- package/dist/components/button/ToggleIconButton.d.ts +2 -2
- package/dist/components/button/ToggleIconButton.d.ts.map +1 -1
- package/dist/components/button/ToggleIconButton.js.map +1 -1
- package/dist/components/button/index.d.ts +1 -0
- package/dist/components/button/index.d.ts.map +1 -1
- package/dist/components/combo-box/ComboBox.d.ts +6 -0
- package/dist/components/combo-box/ComboBox.d.ts.map +1 -1
- package/dist/components/combo-box/ComboBox.js.map +1 -1
- package/dist/components/internal/alert-dialog/AlertDialog.d.ts +56 -0
- package/dist/components/internal/alert-dialog/AlertDialog.d.ts.map +1 -0
- package/dist/components/internal/alert-dialog/AlertDialog.js +68 -0
- package/dist/components/internal/alert-dialog/AlertDialog.js.map +1 -0
- package/dist/components/internal/alert-dialog/index.d.ts +5 -0
- package/dist/components/internal/alert-dialog/index.d.ts.map +1 -0
- package/dist/components/internal/tooltip/Tooltip.d.ts +9 -3
- package/dist/components/internal/tooltip/Tooltip.d.ts.map +1 -1
- package/dist/components/internal/tooltip/Tooltip.js +63 -8
- package/dist/components/internal/tooltip/Tooltip.js.map +1 -1
- package/dist/components/pane/PaneDivider.d.ts +5 -2
- package/dist/components/pane/PaneDivider.d.ts.map +1 -1
- package/dist/components/pane/PaneDivider.js +2 -2
- package/dist/components/pane/PaneDivider.js.map +1 -1
- package/dist/index.css +27 -27
- package/dist/index.css.map +1 -1
- package/dist/reactRender.css +1301 -1189
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +1301 -1189
- package/dist/reactRenderLegacy.css.map +1 -1
- package/dist/tapestryMount.css +1301 -1189
- package/dist/tapestryMount.css.map +1 -1
- package/dist/tapestryMountLegacy.css +1301 -1189
- package/dist/tapestryMountLegacy.css.map +1 -1
- package/dist/unstable.css +112 -0
- package/dist/unstable.css.map +1 -1
- package/dist/utilities/useAnnounce.d.ts +15 -0
- package/dist/utilities/useAnnounce.d.ts.map +1 -0
- package/dist/utilities/useAnnounce.js +27 -0
- package/dist/utilities/useAnnounce.js.map +1 -0
- package/package.json +3 -4
|
@@ -1,84 +1,193 @@
|
|
|
1
|
-
import { DropdownMenu, DropdownAction } from '../dropdown/Dropdown.js';
|
|
1
|
+
import { DropdownMenu, DropdownAction, DropdownSeparator } from '../dropdown/Dropdown.js';
|
|
2
2
|
import { ReorderableListBox, ReorderableListBoxItem } from '../internal/reorderable-list-box/ReorderableListBox.js';
|
|
3
|
-
import
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
import React__default, { createContext, useRef, useState, useEffect, useContext, useCallback, Fragment } from 'react';
|
|
4
5
|
import { mergeProps } from 'react-aria/mergeProps';
|
|
5
6
|
import { MenuTrigger, Pressable } from 'react-aria-components/Menu';
|
|
7
|
+
import { DeleteSavedViewAlertDialog } from './DeleteSavedViewAlertDialog.js';
|
|
6
8
|
import { ManageSavedViewsButton } from './ManageSavedViewsButton.js';
|
|
9
|
+
import { ManageSavedViewsModal } from './ManageSavedViewsModal.js';
|
|
7
10
|
import { NewSavedViewButton } from './NewSavedViewButton.js';
|
|
8
11
|
import { NewSavedViewModal } from './NewSavedViewModal.js';
|
|
9
|
-
import { findActiveSavedView } from './savedViews.js';
|
|
12
|
+
import { initialView, findActiveSavedView } from './savedViews.js';
|
|
10
13
|
import { useActiveSavedView } from './useActiveSavedView.js';
|
|
14
|
+
import { useUpdateSavedViewName } from './useUpdateSavedViewName.js';
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The id of the view the delete alert returns focus to. Read through context
|
|
18
|
+
* so the list's cached items see it without rebuilding the collection.
|
|
19
|
+
*/
|
|
20
|
+
const ReturningFocusViewIdContext = createContext(null);
|
|
21
|
+
function SavedViewsBar({ defaultViewId, onApply, onCreate, onDelete, onSetDefault, onUpdate, savedViews, staticViews, activeFilters, hideableColumns, isColumnVisible, sortBy, }) {
|
|
13
22
|
const closeOpenContextMenuRef = useRef(null);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
const hasInitialView = staticViews.some(({ id }) => id === initialView.id);
|
|
24
|
+
const staticViewsWithInitial = hasInitialView
|
|
25
|
+
? staticViews
|
|
26
|
+
: [initialView, ...staticViews];
|
|
27
|
+
const views = [...staticViewsWithInitial, ...savedViews];
|
|
28
|
+
// The list needs a key for every view, including ones not yet saved.
|
|
29
|
+
const items = views.map((view, index) => ({
|
|
30
|
+
id: view.id ?? `unsaved-view-${index}`,
|
|
31
|
+
view,
|
|
32
|
+
}));
|
|
33
|
+
// What the name modal saves, under the name entered there: a new view, a
|
|
34
|
+
// duplicate, or a rename. It outlives the modal's open state so the title
|
|
35
|
+
// holds while the modal fades out.
|
|
17
36
|
const [draft, setDraft] = useState();
|
|
18
37
|
const [isDraftOpen, setIsDraftOpen] = useState(false);
|
|
38
|
+
const [isManageOpen, setIsManageOpen] = useState(false);
|
|
39
|
+
const barRef = useRef(null);
|
|
40
|
+
// Kept after the alert closes, so its text holds during the exit animation,
|
|
41
|
+
// and its view keeps the tab stop until focus returns to it on cancel.
|
|
42
|
+
const [viewToDelete, setViewToDelete] = useState(null);
|
|
43
|
+
const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false);
|
|
44
|
+
const [isReturningFocus, setIsReturningFocus] = useState(false);
|
|
19
45
|
const hiddenColumnNames = hideableColumns
|
|
20
46
|
.filter((column) => !isColumnVisible(column))
|
|
21
47
|
.map(({ name }) => name);
|
|
22
|
-
|
|
48
|
+
// Static views come first, so they win ties with saved views.
|
|
49
|
+
const { activeSavedView, select, selectWhenSaved } = useActiveSavedView(views, () => findActiveSavedView(views, {
|
|
23
50
|
activeFilters,
|
|
24
51
|
hiddenColumnNames,
|
|
25
52
|
sort: sortBy,
|
|
26
53
|
}));
|
|
27
|
-
const
|
|
28
|
-
|
|
54
|
+
const updateSavedViewName = useUpdateSavedViewName(onUpdate);
|
|
55
|
+
const openDraft = (title, defaultName, save) => {
|
|
56
|
+
setDraft({ defaultName, save, title });
|
|
29
57
|
setIsDraftOpen(true);
|
|
30
58
|
};
|
|
59
|
+
const createSavedView = (view) => {
|
|
60
|
+
if (onCreate)
|
|
61
|
+
selectWhenSaved(onCreate(view));
|
|
62
|
+
};
|
|
31
63
|
const openNewSavedView = () => {
|
|
32
|
-
openDraft("New view", {
|
|
64
|
+
openDraft("New view", "", (name) => createSavedView({
|
|
33
65
|
activeFilters,
|
|
34
|
-
name
|
|
66
|
+
name,
|
|
35
67
|
...(hideableColumns.length > 0 && { hiddenColumnNames }),
|
|
36
68
|
...(sortBy && { sort: sortBy }),
|
|
37
|
-
});
|
|
69
|
+
}));
|
|
38
70
|
};
|
|
39
|
-
// The copy is a new view, so it doesn't keep the original's id
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
71
|
+
// The copy is a new view, so it doesn't keep the original's id.
|
|
72
|
+
const duplicateSavedView = ({ id: _id, ...view }) => {
|
|
73
|
+
openDraft("Duplicate view", `${view.name} copy`, (name) => createSavedView({ ...view, name }));
|
|
74
|
+
};
|
|
75
|
+
const renameSavedView = (view) => {
|
|
76
|
+
openDraft("Rename view", view.name, (name) => {
|
|
77
|
+
if (name !== view.name)
|
|
78
|
+
updateSavedViewName(view, name);
|
|
79
|
+
});
|
|
43
80
|
};
|
|
44
81
|
const saveDraft = (name) => {
|
|
45
82
|
setIsDraftOpen(false);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
83
|
+
draft?.save(name);
|
|
84
|
+
};
|
|
85
|
+
// Updates and deletes are matched by id, so an unsaved view can't be
|
|
86
|
+
// renamed or deleted. Static views can't be edited at all.
|
|
87
|
+
const isEditable = (view) => view.id !== undefined && savedViews.includes(view);
|
|
88
|
+
// The menu item Delete was chosen from is gone by now, so the view takes
|
|
89
|
+
// focus first for the alert to return it to on cancel.
|
|
90
|
+
const requestDelete = (view) => {
|
|
91
|
+
barRef.current
|
|
92
|
+
?.querySelector(`[role="option"][data-key="${CSS.escape(String(view.id))}"]`)
|
|
93
|
+
?.focus();
|
|
94
|
+
setViewToDelete(view);
|
|
95
|
+
setIsDeleteAlertOpen(true);
|
|
96
|
+
setIsReturningFocus(true);
|
|
97
|
+
};
|
|
98
|
+
// Lets the tab stop go back to the selected view, where focus lands.
|
|
99
|
+
// Deleting the default view hands the default back to "initial".
|
|
100
|
+
const confirmDelete = () => {
|
|
101
|
+
if (viewToDelete) {
|
|
102
|
+
onDelete?.(viewToDelete);
|
|
103
|
+
if (viewToDelete.id === defaultViewId)
|
|
104
|
+
onSetDefault?.("initial");
|
|
105
|
+
}
|
|
106
|
+
setIsDeleteAlertOpen(false);
|
|
107
|
+
setIsReturningFocus(false);
|
|
108
|
+
};
|
|
109
|
+
const focusSelectedViewAfterClose = useFocusSelectedViewAfterClose(barRef, isManageOpen);
|
|
110
|
+
// Deleting down to one view hides the button the modal returns focus to.
|
|
111
|
+
const closeManageViews = () => {
|
|
112
|
+
if (views.length <= 1)
|
|
113
|
+
focusSelectedViewAfterClose();
|
|
114
|
+
setIsManageOpen(false);
|
|
115
|
+
};
|
|
116
|
+
// Focus from inside the open alert reaches here too, through the portal.
|
|
117
|
+
const handleFocus = () => {
|
|
118
|
+
if (!isDeleteAlertOpen)
|
|
119
|
+
setIsReturningFocus(false);
|
|
49
120
|
};
|
|
50
121
|
const renderContextMenu = (view) => {
|
|
51
|
-
|
|
122
|
+
const canRename = onUpdate && isEditable(view);
|
|
123
|
+
const canDelete = onDelete && isEditable(view);
|
|
124
|
+
// The default is matched by id, so an unsaved view can't be made the
|
|
125
|
+
// default. Static views can.
|
|
126
|
+
const { id } = view;
|
|
127
|
+
const canSetDefault = onSetDefault && id !== undefined;
|
|
128
|
+
const isDefault = id === defaultViewId;
|
|
129
|
+
const hasActions = canRename || onCreate || canSetDefault;
|
|
130
|
+
if (!hasActions && !canDelete)
|
|
52
131
|
return null;
|
|
53
132
|
return (React__default.createElement(DropdownMenu, null,
|
|
54
|
-
React__default.createElement(DropdownAction, { id: "
|
|
133
|
+
canRename && (React__default.createElement(DropdownAction, { id: "rename", onAction: () => renameSavedView(view) }, "Rename")),
|
|
134
|
+
onCreate && (React__default.createElement(DropdownAction, { id: "duplicate", onAction: () => duplicateSavedView(view) }, "Duplicate")),
|
|
135
|
+
canSetDefault && (
|
|
136
|
+
// Stays in the menu for the default view, disabled, so the user can
|
|
137
|
+
// see which view is the default.
|
|
138
|
+
React__default.createElement(DropdownAction, { disabled: isDefault, id: "set-default", onAction: () => onSetDefault(id) }, isDefault ? "Default view" : "Set as default")),
|
|
139
|
+
hasActions && canDelete && React__default.createElement(DropdownSeparator, null),
|
|
140
|
+
canDelete && (React__default.createElement(DropdownAction, { destructive: true, id: "delete", onAction: () => queueMicrotask(() => requestDelete(view)) }, "Delete"))));
|
|
55
141
|
};
|
|
56
|
-
return (React__default.createElement("div", { className: "tds-data-table-saved-views" },
|
|
142
|
+
return (React__default.createElement("div", { ref: barRef, className: "tds-data-table-saved-views", onFocus: isReturningFocus ? handleFocus : undefined },
|
|
57
143
|
React__default.createElement("div", { className: "tds-data-table-saved-views-list" },
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
144
|
+
React__default.createElement(ReturningFocusViewIdContext.Provider, { value: isReturningFocus ? (viewToDelete?.id ?? null) : null },
|
|
145
|
+
React__default.createElement(ReorderableListBox, { items: items, label: "Views", selectedKey: activeSavedView?.id ?? null, onSelectionChange: (key) => {
|
|
146
|
+
const view = items.find(({ id }) => id === key)?.view;
|
|
147
|
+
if (!view)
|
|
148
|
+
return;
|
|
149
|
+
select(view);
|
|
150
|
+
onApply(view);
|
|
151
|
+
} }, ({ id, view }) => {
|
|
152
|
+
const menu = renderContextMenu(view);
|
|
153
|
+
return (React__default.createElement(ReorderableListBoxItem, { className: classNames("tds-data-table-saved-view-list-item", {
|
|
154
|
+
"tds-data-table-saved-view-list-item--default": view.id === defaultViewId,
|
|
155
|
+
}), id: id, render: menu
|
|
156
|
+
? (props) => (React__default.createElement(ContextMenuTrigger, { id: view.id, closeOpenContextMenuRef: closeOpenContextMenuRef, menu: menu, optionProps: props }))
|
|
157
|
+
: undefined }, view.name));
|
|
158
|
+
})),
|
|
159
|
+
onCreate && React__default.createElement(NewSavedViewButton, { onClick: openNewSavedView }),
|
|
160
|
+
React__default.createElement(NewSavedViewModal, { defaultName: draft?.defaultName, open: isDraftOpen, title: draft?.title, onClose: () => setIsDraftOpen(false), onSave: saveDraft })),
|
|
161
|
+
views.length > 1 && (React__default.createElement(ManageSavedViewsButton, { onClick: () => setIsManageOpen(true) })),
|
|
162
|
+
React__default.createElement(ManageSavedViewsModal, { open: isManageOpen, savedViews: savedViews, staticViews: staticViewsWithInitial, onClose: closeManageViews, onDelete: onDelete, onUpdate: onUpdate }),
|
|
163
|
+
onDelete && (React__default.createElement(DeleteSavedViewAlertDialog, { open: isDeleteAlertOpen, view: viewToDelete, onCancel: () => setIsDeleteAlertOpen(false), onConfirm: confirmDelete }))));
|
|
74
164
|
}
|
|
75
165
|
SavedViewsBar.displayName = "SavedViewsBar";
|
|
166
|
+
/**
|
|
167
|
+
* Once the manage views modal starts closing, focuses the selected view, or
|
|
168
|
+
* the first one.
|
|
169
|
+
*/
|
|
170
|
+
function useFocusSelectedViewAfterClose(barRef, isManageOpen) {
|
|
171
|
+
const shouldFocusRef = useRef(false);
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
if (isManageOpen || !shouldFocusRef.current)
|
|
174
|
+
return;
|
|
175
|
+
shouldFocusRef.current = false;
|
|
176
|
+
const bar = barRef.current;
|
|
177
|
+
(bar?.querySelector('[role="option"][aria-selected="true"]') ?? bar?.querySelector('[role="option"]'))?.focus();
|
|
178
|
+
}, [barRef, isManageOpen]);
|
|
179
|
+
return () => {
|
|
180
|
+
shouldFocusRef.current = true;
|
|
181
|
+
};
|
|
182
|
+
}
|
|
76
183
|
/**
|
|
77
184
|
* Makes a saved view's option element itself the context menu trigger, so
|
|
78
185
|
* the menu opens by right click, long press, or the keyboard context menu
|
|
79
|
-
* shortcut (Shift+F10
|
|
80
|
-
* focus to it on close. `Pressable` hands the trigger's
|
|
81
|
-
*
|
|
186
|
+
* shortcut (Shift+F10, the Menu key, or Ctrl+Enter on macOS), is named by
|
|
187
|
+
* the view, and returns focus to it on close. `Pressable` hands the trigger's
|
|
188
|
+
* handlers to the option element. The option ignores Ctrl+Enter, so the
|
|
189
|
+
* macOS shortcut opens the menu without also selecting the view. The
|
|
190
|
+
* `data-popup-open` attribute keeps the list from moving its tab
|
|
82
191
|
* stop to the selected view while the menu is open. Opening the menu closes
|
|
83
192
|
* any other view's menu, since a right click elsewhere in the list doesn't
|
|
84
193
|
* count as an outside interaction. The open state stays here rather than in
|
|
@@ -87,8 +196,11 @@ SavedViewsBar.displayName = "SavedViewsBar";
|
|
|
87
196
|
* `contextmenu` event remounts the menu, because React Aria only positions
|
|
88
197
|
* an open menu once and would leave it at the first click point.
|
|
89
198
|
*/
|
|
90
|
-
function ContextMenuTrigger({ closeOpenContextMenuRef, menu, optionProps, }) {
|
|
199
|
+
function ContextMenuTrigger({ closeOpenContextMenuRef, id, menu, optionProps, }) {
|
|
200
|
+
const { onKeyDown, ...restOptionProps } = optionProps;
|
|
91
201
|
const [isOpen, setIsOpen] = useState(false);
|
|
202
|
+
// Such as the delete alert, which returns focus to this view on cancel.
|
|
203
|
+
const hasOtherPopup = useContext(ReturningFocusViewIdContext) === id;
|
|
92
204
|
const [menuKey, setMenuKey] = useState(0);
|
|
93
205
|
const close = useCallback(() => setIsOpen(false), []);
|
|
94
206
|
const handleOpenChange = (nextIsOpen) => {
|
|
@@ -103,9 +215,14 @@ function ContextMenuTrigger({ closeOpenContextMenuRef, menu, optionProps, }) {
|
|
|
103
215
|
};
|
|
104
216
|
return (React__default.createElement(MenuTrigger, { isOpen: isOpen, onOpenChange: handleOpenChange, trigger: "contextMenu" },
|
|
105
217
|
React__default.createElement(Pressable, null,
|
|
106
|
-
React__default.createElement("div", { ...mergeProps(
|
|
107
|
-
"data-popup-open": isOpen || undefined,
|
|
218
|
+
React__default.createElement("div", { ...mergeProps(restOptionProps, {
|
|
219
|
+
"data-popup-open": isOpen || hasOtherPopup || undefined,
|
|
108
220
|
onContextMenu: () => setMenuKey((key) => key + 1),
|
|
221
|
+
onKeyDown: (event) => {
|
|
222
|
+
if (event.ctrlKey && event.key === "Enter")
|
|
223
|
+
return;
|
|
224
|
+
onKeyDown?.(event);
|
|
225
|
+
},
|
|
109
226
|
}) })),
|
|
110
227
|
React__default.createElement(Fragment, { key: menuKey }, menu)));
|
|
111
228
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SavedViewsBar.js","sources":["../../../src/components/DataTable/SavedViewsBar.tsx"],"sourcesContent":["import { DropdownAction, DropdownMenu } from \"@components/dropdown\"\nimport {\n ReorderableListBox,\n ReorderableListBoxItem,\n} from \"@components/internal/reorderable-list-box\"\nimport React, {\n type ComponentProps,\n Fragment,\n type MutableRefObject,\n type ReactElement,\n useCallback,\n useRef,\n useState,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { MenuTrigger, Pressable } from \"react-aria-components/Menu\"\n\nimport type { Sort } from \"./DataTable\"\nimport type { DataTableColumn } from \"./DataTableColumn\"\nimport type { ActiveFilter } from \"./FilterTypes\"\nimport { ManageSavedViewsButton } from \"./ManageSavedViewsButton\"\nimport { NewSavedViewButton } from \"./NewSavedViewButton\"\nimport { NewSavedViewModal } from \"./NewSavedViewModal\"\nimport {\n findActiveSavedView,\n type SavedView,\n type SavedViewsOptions,\n} from \"./savedViews\"\nimport { useActiveSavedView } from \"./useActiveSavedView\"\n\nexport interface SavedViewsBarProps {\n activeFilters: ActiveFilter[]\n hideableColumns: DataTableColumn[]\n isColumnVisible: (column: DataTableColumn) => boolean\n onApply: (savedView: SavedView) => void\n /**\n * Returns the new view's id. Omit to hide the new view button and the\n * context menu.\n */\n onCreate?: (\n savedView: Omit<SavedView, \"id\">\n ) => Promise<SavedView[\"id\"]> | SavedView[\"id\"]\n savedViews: SavedView[]\n savedViewsOptions?: SavedViewsOptions\n sortBy: Sort | undefined\n}\n\nexport function SavedViewsBar({\n onApply,\n onCreate,\n savedViews,\n activeFilters,\n hideableColumns,\n isColumnVisible,\n sortBy,\n}: SavedViewsBarProps) {\n const closeOpenContextMenuRef = useRef<(() => void) | null>(null)\n // The view the new view modal will save, under the name entered there. It\n // outlives the modal's open state so the title holds while the modal fades\n // out.\n const [draft, setDraft] = useState<{\n title: string\n view: Omit<SavedView, \"id\">\n }>()\n const [isDraftOpen, setIsDraftOpen] = useState(false)\n const hiddenColumnNames = hideableColumns\n .filter((column) => !isColumnVisible(column))\n .map(({ name }) => name)\n const { activeSavedView, select, selectWhenSaved } = useActiveSavedView(\n savedViews,\n () =>\n findActiveSavedView(savedViews, {\n activeFilters,\n hiddenColumnNames,\n sort: sortBy,\n })\n )\n\n const openDraft = (title: string, view: Omit<SavedView, \"id\">) => {\n setDraft({ title, view })\n setIsDraftOpen(true)\n }\n\n const openNewSavedView = () => {\n openDraft(\"New view\", {\n activeFilters,\n name: \"\",\n ...(hideableColumns.length > 0 && { hiddenColumnNames }),\n ...(sortBy && { sort: sortBy }),\n })\n }\n\n // The copy is a new view, so it doesn't keep the original's id or its\n // per-view permission overrides.\n const duplicateSavedView = ({\n deletable: _deletable,\n editable: _editable,\n id: _id,\n ...view\n }: SavedView) => {\n openDraft(\"Duplicate view\", { ...view, name: `${view.name} copy` })\n }\n\n const saveDraft = (name: string) => {\n setIsDraftOpen(false)\n if (!draft || !onCreate) return\n selectWhenSaved(onCreate({ ...draft.view, name }))\n }\n\n const renderContextMenu = (view: SavedView) => {\n if (!onCreate) return null\n return (\n <DropdownMenu>\n <DropdownAction\n id=\"duplicate\"\n onAction={() => duplicateSavedView(view)}\n >\n Duplicate\n </DropdownAction>\n </DropdownMenu>\n )\n }\n\n return (\n <div className=\"tds-data-table-saved-views\">\n <div className=\"tds-data-table-saved-views-list\">\n {savedViews.length > 0 && (\n <ReorderableListBox\n items={savedViews}\n label=\"Saved views\"\n selectedKey={activeSavedView?.id ?? null}\n onSelectionChange={(key) => {\n const view = savedViews.find(({ id }) => id === key)\n if (!view) return\n select(view)\n onApply(view)\n }}\n >\n {(view) => {\n const menu = renderContextMenu(view)\n return (\n <ReorderableListBoxItem\n className=\"tds-data-table-saved-view-list-item\"\n id={view.id}\n render={\n menu\n ? (props) => (\n <ContextMenuTrigger\n closeOpenContextMenuRef={closeOpenContextMenuRef}\n menu={menu}\n optionProps={props as ComponentProps<\"div\">}\n />\n )\n : undefined\n }\n >\n {view.name}\n </ReorderableListBoxItem>\n )\n }}\n </ReorderableListBox>\n )}\n {onCreate && (\n <>\n <NewSavedViewButton onClick={openNewSavedView} />\n <NewSavedViewModal\n defaultName={draft?.view.name}\n open={isDraftOpen}\n title={draft?.title}\n onClose={() => setIsDraftOpen(false)}\n onSave={saveDraft}\n />\n </>\n )}\n </div>\n {savedViews.length > 0 && <ManageSavedViewsButton />}\n </div>\n )\n}\n\nSavedViewsBar.displayName = \"SavedViewsBar\"\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 or the Menu key), is named by the view, and returns\n * focus to it on close. `Pressable` hands the trigger's handlers to the\n * option element, and `data-popup-open` 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 menu,\n optionProps,\n}: {\n closeOpenContextMenuRef: MutableRefObject<(() => void) | null>\n menu: ReactElement\n optionProps: ComponentProps<\"div\">\n}) {\n const [isOpen, setIsOpen] = useState(false)\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(optionProps, {\n \"data-popup-open\": isOpen || undefined,\n onContextMenu: () => setMenuKey((key) => key + 1),\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 {\n DropdownAction,\n DropdownMenu,\n DropdownSeparator,\n} from \"@components/dropdown\"\nimport {\n ReorderableListBox,\n ReorderableListBoxItem,\n} from \"@components/internal/reorderable-list-box\"\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 type { Sort } from \"./DataTable\"\nimport type { DataTableColumn } from \"./DataTableColumn\"\nimport { DeleteSavedViewAlertDialog } from \"./DeleteSavedViewAlertDialog\"\nimport type { ActiveFilter } from \"./FilterTypes\"\nimport { ManageSavedViewsButton } from \"./ManageSavedViewsButton\"\nimport { ManageSavedViewsModal } from \"./ManageSavedViewsModal\"\nimport { NewSavedViewButton } from \"./NewSavedViewButton\"\nimport { NewSavedViewModal } from \"./NewSavedViewModal\"\nimport {\n findActiveSavedView,\n initialView,\n type SavedView,\n type StaticView,\n} from \"./savedViews\"\nimport { useActiveSavedView } from \"./useActiveSavedView\"\nimport { useUpdateSavedViewName } from \"./useUpdateSavedViewName\"\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 activeFilters: ActiveFilter[]\n defaultViewId: NonNullable<SavedView[\"id\"]>\n hideableColumns: DataTableColumn[]\n isColumnVisible: (column: DataTableColumn) => 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> | SavedView\n /** Called once the user confirms. Omit to leave out the Delete action. */\n onDelete?: (savedView: SavedView) => void\n /** Omit to leave out the Set as default action. */\n onSetDefault?: (id: NonNullable<SavedView[\"id\"]>) => void\n /** Omit to leave out the Rename action. */\n onUpdate?: (savedView: SavedView) => Promise<SavedView> | SavedView\n savedViews: SavedView[]\n sortBy: Sort | undefined\n /** Listed before `savedViews` and can't be edited. */\n staticViews: StaticView[]\n}\n\nexport function SavedViewsBar({\n defaultViewId,\n onApply,\n onCreate,\n onDelete,\n onSetDefault,\n onUpdate,\n savedViews,\n staticViews,\n activeFilters,\n hideableColumns,\n isColumnVisible,\n sortBy,\n}: SavedViewsBarProps) {\n const closeOpenContextMenuRef = useRef<(() => void) | null>(null)\n const hasInitialView = staticViews.some(({ id }) => id === initialView.id)\n const staticViewsWithInitial = hasInitialView\n ? staticViews\n : [initialView, ...staticViews]\n const views = [...staticViewsWithInitial, ...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 // What the name modal saves, under the name entered there: a new view, a\n // duplicate, or a rename. It outlives the modal's open state so the title\n // holds while the modal fades out.\n const [draft, setDraft] = useState<{\n defaultName: string\n save: (name: string) => void\n title: string\n }>()\n const [isDraftOpen, setIsDraftOpen] = useState(false)\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 const hiddenColumnNames = hideableColumns\n .filter((column) => !isColumnVisible(column))\n .map(({ name }) => name)\n // Static views come first, so they win ties with saved views.\n const { activeSavedView, select, selectWhenSaved } = useActiveSavedView(\n views,\n () =>\n findActiveSavedView(views, {\n activeFilters,\n hiddenColumnNames,\n sort: sortBy,\n })\n )\n\n const updateSavedViewName = useUpdateSavedViewName(onUpdate)\n\n const openDraft = (\n title: string,\n defaultName: string,\n save: (name: string) => void\n ) => {\n setDraft({ defaultName, save, title })\n setIsDraftOpen(true)\n }\n\n const createSavedView = (view: Omit<SavedView, \"id\">) => {\n if (onCreate) selectWhenSaved(onCreate(view))\n }\n\n const openNewSavedView = () => {\n openDraft(\"New view\", \"\", (name) =>\n createSavedView({\n activeFilters,\n name,\n ...(hideableColumns.length > 0 && { hiddenColumnNames }),\n ...(sortBy && { sort: sortBy }),\n })\n )\n }\n\n // The copy is a new view, so it doesn't keep the original's id.\n const duplicateSavedView = ({ id: _id, ...view }: SavedView) => {\n openDraft(\"Duplicate view\", `${view.name} copy`, (name) =>\n createSavedView({ ...view, name })\n )\n }\n\n const renameSavedView = (view: SavedView) => {\n openDraft(\"Rename view\", view.name, (name) => {\n if (name !== view.name) updateSavedViewName(view, name)\n })\n }\n\n const saveDraft = (name: string) => {\n setIsDraftOpen(false)\n draft?.save(name)\n }\n\n // Updates and deletes are matched by id, so an unsaved view can't be\n // renamed or deleted. Static views can't be edited at all.\n const isEditable = (view: SavedView) =>\n view.id !== undefined && savedViews.includes(view)\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.\n // Deleting the default view hands the default back to \"initial\".\n const confirmDelete = () => {\n if (viewToDelete) {\n onDelete?.(viewToDelete)\n if (viewToDelete.id === defaultViewId) onSetDefault?.(\"initial\")\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 const canRename = onUpdate && isEditable(view)\n const canDelete = onDelete && isEditable(view)\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 canSetDefault = onSetDefault && id !== undefined\n const isDefault = id === defaultViewId\n const hasActions = canRename || onCreate || canSetDefault\n if (!hasActions && !canDelete) return null\n return (\n <DropdownMenu>\n {canRename && (\n <DropdownAction id=\"rename\" onAction={() => renameSavedView(view)}>\n Rename\n </DropdownAction>\n )}\n {onCreate && (\n <DropdownAction\n id=\"duplicate\"\n onAction={() => duplicateSavedView(view)}\n >\n Duplicate\n </DropdownAction>\n )}\n {canSetDefault && (\n // Stays in the menu for the default view, disabled, so the user can\n // see which view is the default.\n <DropdownAction\n disabled={isDefault}\n id=\"set-default\"\n onAction={() => onSetDefault(id)}\n >\n {isDefault ? \"Default view\" : \"Set as default\"}\n </DropdownAction>\n )}\n {hasActions && canDelete && <DropdownSeparator />}\n {canDelete && (\n <DropdownAction\n destructive\n id=\"delete\"\n onAction={() => queueMicrotask(() => requestDelete(view))}\n >\n Delete\n </DropdownAction>\n )}\n </DropdownMenu>\n )\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 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 render={\n menu\n ? (props) => (\n <ContextMenuTrigger\n id={view.id}\n closeOpenContextMenuRef={closeOpenContextMenuRef}\n menu={menu}\n optionProps={props as ComponentProps<\"div\">}\n />\n )\n : undefined\n }\n >\n {view.name}\n </ReorderableListBoxItem>\n )\n }}\n </ReorderableListBox>\n </ReturningFocusViewIdContext.Provider>\n {onCreate && <NewSavedViewButton onClick={openNewSavedView} />}\n <NewSavedViewModal\n defaultName={draft?.defaultName}\n open={isDraftOpen}\n title={draft?.title}\n onClose={() => setIsDraftOpen(false)}\n onSave={saveDraft}\n />\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 open={isManageOpen}\n savedViews={savedViews}\n staticViews={staticViewsWithInitial}\n onClose={closeManageViews}\n onDelete={onDelete}\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableActions.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/TableActions.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"TableActions.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/TableActions.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,EAA4B,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAC1E,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAA;AAEhC;;;;;GAKG;AACH,MAAM,MAAM,WAAW,CACrB,cAAc,SAAS,kBAAkB,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,IAC7D;IACF,sEAAsE;IACtE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,CAAA;IAC9C,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,yDAAyD;IACzD,IAAI,EAAE,SAAS,CAAA;IACf,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAA;IACb,8EAA8E;IAC9E,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,iBAAiB,CAAC,CAAA;CACrD,CAAA;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,OAAO,EAAE,WAAW,CAAC,kBAAkB,CAAC,EAAE,CAAA;IAC1C;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;CACxB;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY;8BAA6B,iBAAiB;;CAwBtE,CAAA"}
|
|
@@ -6,7 +6,6 @@ import { IconButton } from '../button/IconButton.js';
|
|
|
6
6
|
import '../button/LoadingButton.js';
|
|
7
7
|
import '../button/PageHeaderActionsDropdownButton.js';
|
|
8
8
|
import { ButtonGroup } from '../button-group/ButtonGroup.js';
|
|
9
|
-
import { Tooltip } from '../internal/tooltip/Tooltip.js';
|
|
10
9
|
import React__default from 'react';
|
|
11
10
|
import { resolveNoun, formatCount } from './ResultsCount.js';
|
|
12
11
|
import { useDataTableSelectionContext } from './useDataTableSelection.js';
|
|
@@ -21,11 +20,10 @@ const TableActions = ({ actions, resultNoun }) => {
|
|
|
21
20
|
// The count/noun suffix is the same for every table action, so compute it once
|
|
22
21
|
// here rather than per-button inside the map below.
|
|
23
22
|
const countSuffix = getTableActionCountSuffix(selectedCount, resultNoun);
|
|
24
|
-
return (React__default.createElement(ButtonGroup, { "aria-label": "Table actions" }, actions.map(({ callback, disabled, icon, label, onClick }) => (React__default.createElement(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
} }))))));
|
|
23
|
+
return (React__default.createElement(ButtonGroup, { "aria-label": "Table actions" }, actions.map(({ callback, disabled, icon, label, onClick }) => (React__default.createElement(IconButton, { key: label, "aria-label": `${label}${countSuffix}`, disabled: disabled, icon: icon, onClick: (event) => {
|
|
24
|
+
onClick?.(event);
|
|
25
|
+
callback?.(selection);
|
|
26
|
+
}, tooltip: label, tooltipPlacement: "bottom" })))));
|
|
29
27
|
};
|
|
30
28
|
TableActions.displayName = "TableActions";
|
|
31
29
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableActions.js","sources":["../../../src/components/DataTable/TableActions.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport { ButtonGroup } from \"@components/button-group\"\nimport
|
|
1
|
+
{"version":3,"file":"TableActions.js","sources":["../../../src/components/DataTable/TableActions.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport { ButtonGroup } from \"@components/button-group\"\nimport React, { type ReactNode } from \"react\"\n\nimport { formatCount, resolveNoun, type ResultNoun } from \"./ResultsCount\"\nimport {\n type DataTableSelection,\n useDataTableSelectionContext,\n} from \"./useDataTableSelection\"\n\n/**\n * A table action rendered as an `IconButton` in the button group above the\n * table. Replaces the original RFC's `{ buttonProps; callback }` shape with a\n * narrower, more controllable API so the design can evolve without exposing the\n * full button surface.\n */\nexport type TableAction<\n SelectionValue extends DataTableSelection = (number | string)[],\n> = {\n /** Called with the current selection when the action is triggered. */\n callback?: (selection: SelectionValue) => void\n /** Whether the action's button is disabled. */\n disabled?: boolean\n /** The icon rendered inside the action's icon button. */\n icon: ReactNode\n /** Accessible label for the icon-only action button. */\n label: string\n /** Standard click handler, invoked with the click event before `callback`. */\n onClick?: React.MouseEventHandler<HTMLButtonElement>\n}\n\nexport interface TableActionsProps {\n /** The table actions to render as an `IconButton` group. */\n actions: TableAction<DataTableSelection>[]\n /**\n * The noun used to describe the selection in each action's `aria-label`.\n * See {@link ResultNoun}.\n */\n resultNoun?: ResultNoun\n}\n\n/**\n * Renders the table actions as an `IconButton` group displayed directly after\n * the results count, above the table. Each entry becomes an icon button whose\n * `callback` receives the current selection.\n */\nexport const TableActions = ({ actions, resultNoun }: TableActionsProps) => {\n const { selectedCount, selection } = useDataTableSelectionContext()\n // The count/noun suffix is the same for every table action, so compute it once\n // here rather than per-button inside the map below.\n const countSuffix = getTableActionCountSuffix(selectedCount, resultNoun)\n\n return (\n <ButtonGroup aria-label=\"Table actions\">\n {actions.map(({ callback, disabled, icon, label, onClick }) => (\n <IconButton\n key={label}\n aria-label={`${label}${countSuffix}`}\n disabled={disabled}\n icon={icon}\n onClick={(event) => {\n onClick?.(event)\n callback?.(selection)\n }}\n tooltip={label}\n tooltipPlacement=\"bottom\"\n />\n ))}\n </ButtonGroup>\n )\n}\n\nTableActions.displayName = \"TableActions\"\n\n/**\n * The count/noun suffix appended to each table action's `aria-label` when rows\n * are selected, e.g. `\" (2 selected people)\"` — so `\"Email\"` reads as\n * `\"Email (2 selected people)\"`. Empty when nothing is selected. Falls back to\n * the default `\"result\"` noun when `resultNoun` isn't provided. Shared across\n * every action, so it's computed once rather than per-button.\n */\nfunction getTableActionCountSuffix(\n count: number,\n resultNoun: ResultNoun | undefined\n): string {\n if (!count) return \"\"\n // An absent or `true` noun both default to `\"result\"`/`\"results\"`.\n const noun = resolveNoun(count, resultNoun || true)\n return ` (${formatCount(count)} selected ${noun})`\n}\n"],"names":["React"],"mappings":";;;;;;;;;;;;AAyCA;;;;AAIG;AACI,MAAM,YAAY,GAAG,CAAC,EAAE,OAAO,EAAE,UAAU,EAAqB,KAAI;IACzE,MAAM,EAAE,aAAa,EAAE,SAAS,EAAE,GAAG,4BAA4B,EAAE;;;IAGnE,MAAM,WAAW,GAAG,yBAAyB,CAAC,aAAa,EAAE,UAAU,CAAC;IAExE,QACEA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,YAAA,EAAY,eAAe,IACpC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,MACxDA,6BAAC,UAAU,EAAA,EACT,GAAG,EAAE,KAAK,EAAA,YAAA,EACE,GAAG,KAAK,CAAA,EAAG,WAAW,CAAA,CAAE,EACpC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,CAAC,KAAK,KAAI;AACjB,YAAA,OAAO,GAAG,KAAK,CAAC;AAChB,YAAA,QAAQ,GAAG,SAAS,CAAC;AACvB,QAAA,CAAC,EACD,OAAO,EAAE,KAAK,EACd,gBAAgB,EAAC,QAAQ,EAAA,CACzB,CACH,CAAC,CACU;AAElB;AAEA,YAAY,CAAC,WAAW,GAAG,cAAc;AAEzC;;;;;;AAMG;AACH,SAAS,yBAAyB,CAChC,KAAa,EACb,UAAkC,EAAA;AAElC,IAAA,IAAI,CAAC,KAAK;AAAE,QAAA,OAAO,EAAE;;IAErB,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,IAAI,IAAI,CAAC;IACnD,OAAO,CAAA,EAAA,EAAK,WAAW,CAAC,KAAK,CAAC,CAAA,UAAA,EAAa,IAAI,GAAG;AACpD;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewSettingsToggle.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ViewSettingsToggle.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ViewSettingsToggle.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ViewSettingsToggle.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACtC,iEAAiE;IACjE,OAAO,EAAE,eAAe,EAAE,CAAA;IAC1B,wBAAwB,EAAE,CAAC,kBAAkB,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;IAChE,kBAAkB,EAAE,MAAM,EAAE,CAAA;CAC7B;AAUD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,OAAO,EACP,wBAAwB,EACxB,kBAAkB,GACnB,EAAE,uBAAuB,qBAmCzB;yBAvCe,kBAAkB"}
|
|
@@ -9,7 +9,6 @@ import { FilterableListBox, FilterableListBoxItem } from '../internal/filterable
|
|
|
9
9
|
import { Popover, PopoverTrigger, PopoverContent } from '../popover/Popover.js';
|
|
10
10
|
import Icon from '../../utilities/Icon.js';
|
|
11
11
|
import React__default from 'react';
|
|
12
|
-
import { Tooltip } from '../internal/tooltip/Tooltip.js';
|
|
13
12
|
|
|
14
13
|
function renderColumnItem(column) {
|
|
15
14
|
return (React__default.createElement(FilterableListBoxItem, { id: column.name }, column.headerLabel));
|
|
@@ -22,9 +21,8 @@ function renderColumnItem(column) {
|
|
|
22
21
|
*/
|
|
23
22
|
function ViewSettingsToggle({ columns, onColumnVisibilityChange, visibleColumnNames, }) {
|
|
24
23
|
return (React__default.createElement(Popover, null,
|
|
25
|
-
React__default.createElement(
|
|
26
|
-
React__default.createElement(
|
|
27
|
-
React__default.createElement(IconButton, { "aria-label": "View settings", className: "tds-data-table-popover-trigger", icon: React__default.createElement(Icon, { "aria-hidden": true, symbol: "general#faders" }) }))),
|
|
24
|
+
React__default.createElement(PopoverTrigger, null,
|
|
25
|
+
React__default.createElement(IconButton, { className: "tds-data-table-popover-trigger", icon: React__default.createElement(Icon, { "aria-hidden": true, symbol: "general#faders" }), tooltip: "View settings", tooltipPlacement: "bottom end" })),
|
|
28
26
|
React__default.createElement(PopoverContent, { className: "tds-data-table-popover", modal: false, placement: "bottom end" }, columns.length > 0 && (React__default.createElement(FilterableListBox, { hideLabel: true, items: columns, label: "Column visibility", onSelectionChange: (keys) => onColumnVisibilityChange(keys), placeholder: "Search columns", selectedKeys: visibleColumnNames, selectionMode: "multiple", showBulkActions: true }, renderColumnItem)))));
|
|
29
27
|
}
|
|
30
28
|
ViewSettingsToggle.displayName = "ViewSettingsToggle";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewSettingsToggle.js","sources":["../../../src/components/DataTable/ViewSettingsToggle.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport {\n FilterableListBox,\n FilterableListBoxItem,\n} from \"@components/internal/filterable-list-box\"\nimport { Popover, PopoverContent, PopoverTrigger } from \"@components/popover\"\nimport Icon from \"@utilities/Icon\"\nimport React from \"react\"\n\nimport
|
|
1
|
+
{"version":3,"file":"ViewSettingsToggle.js","sources":["../../../src/components/DataTable/ViewSettingsToggle.tsx"],"sourcesContent":["import { IconButton } from \"@components/button\"\nimport {\n FilterableListBox,\n FilterableListBoxItem,\n} from \"@components/internal/filterable-list-box\"\nimport { Popover, PopoverContent, PopoverTrigger } from \"@components/popover\"\nimport Icon from \"@utilities/Icon\"\nimport React from \"react\"\n\nimport type { DataTableColumn } from \"./DataTableColumn\"\n\nexport interface ViewSettingsToggleProps {\n /** The columns opted into visibility toggling via `hideable`. */\n columns: DataTableColumn[]\n onColumnVisibilityChange: (visibleColumnNames: string[]) => void\n visibleColumnNames: string[]\n}\n\nfunction renderColumnItem(column: DataTableColumn) {\n return (\n <FilterableListBoxItem id={column.name}>\n {column.headerLabel}\n </FilterableListBoxItem>\n )\n}\n\n/**\n * A trigger + popover for table view settings. Today it only holds column\n * visibility (via `FilterableListBox`), but the panel is meant to grow to\n * include other view-related settings (e.g. a Table/Card display toggle, a\n * Compact View switch) as siblings inside the same dialog.\n */\nexport function ViewSettingsToggle({\n columns,\n onColumnVisibilityChange,\n visibleColumnNames,\n}: ViewSettingsToggleProps) {\n return (\n <Popover>\n <PopoverTrigger>\n <IconButton\n className=\"tds-data-table-popover-trigger\"\n icon={<Icon aria-hidden symbol=\"general#faders\" />}\n tooltip=\"View settings\"\n tooltipPlacement=\"bottom end\"\n />\n </PopoverTrigger>\n <PopoverContent\n className=\"tds-data-table-popover\"\n modal={false}\n placement=\"bottom end\"\n >\n {columns.length > 0 && (\n <FilterableListBox\n hideLabel\n items={columns}\n label=\"Column visibility\"\n onSelectionChange={(keys) =>\n onColumnVisibilityChange(keys as string[])\n }\n placeholder=\"Search columns\"\n selectedKeys={visibleColumnNames}\n selectionMode=\"multiple\"\n showBulkActions\n >\n {renderColumnItem}\n </FilterableListBox>\n )}\n </PopoverContent>\n </Popover>\n )\n}\n\nViewSettingsToggle.displayName = \"ViewSettingsToggle\"\n"],"names":["React"],"mappings":";;;;;;;;;;;;AAkBA,SAAS,gBAAgB,CAAC,MAAuB,EAAA;AAC/C,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,qBAAqB,EAAA,EAAC,EAAE,EAAE,MAAM,CAAC,IAAI,IACnC,MAAM,CAAC,WAAW,CACG;AAE5B;AAEA;;;;;AAKG;AACG,SAAU,kBAAkB,CAAC,EACjC,OAAO,EACP,wBAAwB,EACxB,kBAAkB,GACM,EAAA;IACxB,QACEA,6BAAC,OAAO,EAAA,IAAA;AACN,QAAAA,cAAA,CAAA,aAAA,CAAC,cAAc,EAAA,IAAA;YACbA,cAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,SAAS,EAAC,gCAAgC,EAC1C,IAAI,EAAEA,cAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAA,aAAA,EAAA,IAAA,EAAa,MAAM,EAAC,gBAAgB,EAAA,CAAG,EAClD,OAAO,EAAC,eAAe,EACvB,gBAAgB,EAAC,YAAY,EAAA,CAC7B,CACa;AACjB,QAAAA,cAAA,CAAA,aAAA,CAAC,cAAc,EAAA,EACb,SAAS,EAAC,wBAAwB,EAClC,KAAK,EAAE,KAAK,EACZ,SAAS,EAAC,YAAY,EAAA,EAErB,OAAO,CAAC,MAAM,GAAG,CAAC,KACjBA,6BAAC,iBAAiB,EAAA,EAChB,SAAS,EAAA,IAAA,EACT,KAAK,EAAE,OAAO,EACd,KAAK,EAAC,mBAAmB,EACzB,iBAAiB,EAAE,CAAC,IAAI,KACtB,wBAAwB,CAAC,IAAgB,CAAC,EAE5C,WAAW,EAAC,gBAAgB,EAC5B,YAAY,EAAE,kBAAkB,EAChC,aAAa,EAAC,UAAU,EACxB,eAAe,EAAA,IAAA,EAAA,EAEd,gBAAgB,CACC,CACrB,CACc,CACT;AAEd;AAEA,kBAAkB,CAAC,WAAW,GAAG,oBAAoB;;;;"}
|
|
@@ -11,7 +11,7 @@ export * from "./filters";
|
|
|
11
11
|
export type { ActiveFilter, ActiveFilterValue, FilterItemConfig, FilterNode, FilterNodeGroup, FilterNodeItem, FilterNodeScoped, Operator, } from "./FilterTypes";
|
|
12
12
|
export type { NumberActiveFilter, NumberFilterValue, NumberOperatorName, } from "./numberFilter";
|
|
13
13
|
export type { PresenceActiveFilter, PresenceFilterConfig, PresenceFilterValue, PresenceOperatorName, } from "./presenceFilter";
|
|
14
|
-
export type { SavedView,
|
|
14
|
+
export type { SavedView, StaticView } from "./savedViews";
|
|
15
15
|
export type { ScopedFilterConfig, ScopedFilterOptions } from "./scopedFilter";
|
|
16
16
|
export type { TextActiveFilter, TextFilterValue, TextOperatorName, } from "./textFilter";
|
|
17
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,eAAe,CAAA;AAEtB,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,YAAY,EACV,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,IAAI,GACL,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,eAAe,EACf,cAAc,EACd,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,cAAc,WAAW,CAAA;AACzB,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,SAAS,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/index.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AACpB,OAAO,eAAe,CAAA;AAEtB,YAAY,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACtE,YAAY,EACV,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,IAAI,GACL,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,YAAY,EACV,aAAa,EACb,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,UAAU,EACV,cAAc,EACd,UAAU,EACV,YAAY,EACZ,YAAY,GACb,MAAM,mBAAmB,CAAA;AAC1B,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,cAAc,CAAA;AACrB,YAAY,EACV,eAAe,EACf,cAAc,EACd,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,cAAc,WAAW,CAAA;AACzB,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,QAAQ,GACT,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAC7E,YAAY,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,GACjB,MAAM,cAAc,CAAA"}
|
|
@@ -2,33 +2,34 @@ import type { Sort } from "./DataTable";
|
|
|
2
2
|
import type { ActiveFilter } from "./FilterTypes";
|
|
3
3
|
export interface SavedView {
|
|
4
4
|
activeFilters: ActiveFilter[];
|
|
5
|
-
/** Overrides `savedViewsOptions.deletable` for this view. */
|
|
6
|
-
deletable?: boolean;
|
|
7
|
-
/** Overrides `savedViewsOptions.editable` for this view. */
|
|
8
|
-
editable?: boolean;
|
|
9
5
|
/** Omit to leave the current column visibility unchanged when applied. */
|
|
10
6
|
hiddenColumnNames?: string[];
|
|
11
|
-
|
|
7
|
+
/** Assigned by the consumer once the view is saved. */
|
|
8
|
+
id?: number | string;
|
|
12
9
|
name: string;
|
|
13
10
|
/** Omit to leave the current sort unchanged when applied. */
|
|
14
11
|
sort?: Sort;
|
|
15
12
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
/** An app-provided view. Read-only. */
|
|
14
|
+
export type StaticView = SavedView & {
|
|
15
|
+
id: number | string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Always listed, so there's a view to fall back to. Added before the static
|
|
19
|
+
* views unless one of them uses its id, which replaces it.
|
|
20
|
+
*/
|
|
21
|
+
export declare const initialView: StaticView;
|
|
22
22
|
interface SavedViewState {
|
|
23
23
|
activeFilters: ActiveFilter[];
|
|
24
24
|
hiddenColumnNames: string[];
|
|
25
25
|
sort: Sort | undefined;
|
|
26
26
|
}
|
|
27
27
|
/**
|
|
28
|
-
* The
|
|
29
|
-
* initially selected view. Filters match regardless of order,
|
|
30
|
-
* display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
31
|
-
* compared when the view sets them
|
|
28
|
+
* The most specific view matching the current state, or undefined. Only
|
|
29
|
+
* picks the initially selected view. Filters match regardless of order,
|
|
30
|
+
* ignoring display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
31
|
+
* only compared when the view sets them, so a view that sets more of them is
|
|
32
|
+
* more specific. Among equally specific matches, the first wins.
|
|
32
33
|
*/
|
|
33
34
|
export declare function findActiveSavedView(savedViews: SavedView[], state: SavedViewState): SavedView | undefined;
|
|
34
35
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"savedViews.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/savedViews.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,
|
|
1
|
+
{"version":3,"file":"savedViews.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/savedViews.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAEjD,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,0EAA0E;IAC1E,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,6DAA6D;IAC7D,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ;AAED,uCAAuC;AACvC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAA;AAE5D;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,UAIzB,CAAA;AAED,UAAU,cAAc;IACtB,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,IAAI,EAAE,IAAI,GAAG,SAAS,CAAA;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,SAAS,EAAE,EACvB,KAAK,EAAE,cAAc,GACpB,SAAS,GAAG,SAAS,CAYvB"}
|
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
* Always listed, so there's a view to fall back to. Added before the static
|
|
3
|
+
* views unless one of them uses its id, which replaces it.
|
|
4
|
+
*/
|
|
5
|
+
const initialView = {
|
|
6
|
+
activeFilters: [],
|
|
7
|
+
id: "initial",
|
|
8
|
+
name: "All",
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The most specific view matching the current state, or undefined. Only
|
|
12
|
+
* picks the initially selected view. Filters match regardless of order,
|
|
13
|
+
* ignoring display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
14
|
+
* only compared when the view sets them, so a view that sets more of them is
|
|
15
|
+
* more specific. Among equally specific matches, the first wins.
|
|
6
16
|
*/
|
|
7
17
|
function findActiveSavedView(savedViews, state) {
|
|
8
|
-
|
|
18
|
+
let mostSpecificMatch;
|
|
19
|
+
for (const view of savedViews) {
|
|
20
|
+
if (!savedViewMatches(view, state))
|
|
21
|
+
continue;
|
|
22
|
+
if (!mostSpecificMatch ||
|
|
23
|
+
specificity(view) > specificity(mostSpecificMatch)) {
|
|
24
|
+
mostSpecificMatch = view;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return mostSpecificMatch;
|
|
28
|
+
}
|
|
29
|
+
function specificity(view) {
|
|
30
|
+
return Number(Boolean(view.sort)) + Number(Boolean(view.hiddenColumnNames));
|
|
9
31
|
}
|
|
10
32
|
function savedViewMatches(view, state) {
|
|
11
33
|
if (!filtersMatch(view.activeFilters, state.activeFilters))
|
|
@@ -47,5 +69,5 @@ function namesMatch(a, b) {
|
|
|
47
69
|
return new Set(a).size === names.size && a.every((name) => names.has(name));
|
|
48
70
|
}
|
|
49
71
|
|
|
50
|
-
export { findActiveSavedView };
|
|
72
|
+
export { findActiveSavedView, initialView };
|
|
51
73
|
//# sourceMappingURL=savedViews.js.map
|