@planningcenter/tapestry 4.11.0 → 4.12.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/CollectionEditorsLazy.js +2 -1
- package/dist/components/DataTable/CollectionEditorsLazy.js.map +1 -1
- package/dist/components/DataTable/DataTable.d.ts +49 -14
- package/dist/components/DataTable/DataTable.d.ts.map +1 -1
- package/dist/components/DataTable/DataTable.js +32 -24
- 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 +11 -1
- package/dist/components/DataTable/ManageSavedViewsModal.d.ts.map +1 -1
- package/dist/components/DataTable/ManageSavedViewsModal.js +265 -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 +176 -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 +40 -15
- package/dist/components/DataTable/savedViews.d.ts.map +1 -1
- package/dist/components/DataTable/savedViews.js +85 -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 +18 -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/BaseButton.d.ts.map +1 -1
- package/dist/components/button/BaseButton.js +2 -1
- package/dist/components/button/BaseButton.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 +31 -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 +4 -1
- package/dist/components/button/ToggleIconButton.d.ts.map +1 -1
- package/dist/components/button/ToggleIconButton.js +1 -0
- 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 +8 -0
- package/dist/components/combo-box/ComboBox.d.ts.map +1 -1
- package/dist/components/combo-box/ComboBox.js +31 -5
- package/dist/components/combo-box/ComboBox.js.map +1 -1
- package/dist/components/date-picker/DatePicker.d.ts.map +1 -1
- package/dist/components/date-picker/DatePicker.js +18 -14
- package/dist/components/date-picker/DatePicker.js.map +1 -1
- package/dist/components/internal/LoadingAnnouncement.d.ts +11 -0
- package/dist/components/internal/LoadingAnnouncement.d.ts.map +1 -0
- package/dist/components/internal/LoadingAnnouncement.js +21 -0
- package/dist/components/internal/LoadingAnnouncement.js.map +1 -0
- 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/index.d.ts +1 -0
- package/dist/components/internal/index.d.ts.map +1 -1
- package/dist/components/internal/tooltip/Tooltip.d.ts +13 -5
- 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/internal/tooltip/TooltipTriggerContext.d.ts +3 -3
- package/dist/components/internal/tooltip/TooltipTriggerContext.d.ts.map +1 -1
- package/dist/components/internal/tooltip/TooltipTriggerContext.js +1 -1
- package/dist/components/internal/tooltip/TooltipTriggerContext.js.map +1 -1
- package/dist/components/internal/tooltip/index.d.ts +1 -1
- package/dist/components/internal/tooltip/index.d.ts.map +1 -1
- package/dist/components/link/BaseLink.d.ts.map +1 -1
- package/dist/components/link/BaseLink.js +15 -3
- package/dist/components/link/BaseLink.js.map +1 -1
- package/dist/components/link/IconLink.d.ts +28 -290
- package/dist/components/link/IconLink.d.ts.map +1 -1
- package/dist/components/link/IconLink.js +9 -2
- package/dist/components/link/IconLink.js.map +1 -1
- package/dist/components/page-header/defineElements.js +1 -1
- package/dist/components/pane/Pane.d.ts +1 -1
- package/dist/components/pane/Pane.js +1 -1
- package/dist/components/pane/Pane.js.map +1 -1
- package/dist/components/pane/PaneBody.d.ts +1 -1
- package/dist/components/pane/PaneBody.js +1 -1
- package/dist/components/pane/PaneBody.js.map +1 -1
- package/dist/components/pane/PaneDivider.d.ts +6 -3
- package/dist/components/pane/PaneDivider.d.ts.map +1 -1
- package/dist/components/pane/PaneDivider.js +3 -3
- package/dist/components/pane/PaneDivider.js.map +1 -1
- package/dist/components/pane/PaneFooter.d.ts +1 -1
- package/dist/components/pane/PaneFooter.js +1 -1
- package/dist/components/pane/PaneFooter.js.map +1 -1
- package/dist/components/pane/PaneHeader.d.ts +1 -1
- package/dist/components/pane/PaneHeader.js +1 -1
- package/dist/components/pane/PaneHeader.js.map +1 -1
- package/dist/components/pane/PaneHeaderActions.d.ts +1 -1
- package/dist/components/pane/PaneHeaderActions.js +1 -1
- package/dist/components/pane/PaneHeaderActions.js.map +1 -1
- package/dist/components/sidenav/defineElements.js +1 -1
- package/dist/components/time-field/TimeField.d.ts.map +1 -1
- package/dist/components/time-field/TimeField.js +7 -3
- package/dist/components/time-field/TimeField.js.map +1 -1
- package/dist/index.css +169 -27
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/{p-np7vhMVg.js → p-A1JK45WV.js} +3 -3
- package/dist/packages/tapestry-wc/dist/components/p-A1JK45WV.js.map +1 -0
- package/dist/packages/tapestry-wc/dist/components/{p-BVvtAaVT.js → p-BbuNAv9q.js} +3 -3
- package/dist/packages/tapestry-wc/dist/components/p-BbuNAv9q.js.map +1 -0
- package/dist/packages/tapestry-wc/dist/components/{p-B2xqMgNQ.js → p-CBFtMIxJ.js} +2 -2
- package/dist/packages/tapestry-wc/dist/components/p-CBFtMIxJ.js.map +1 -0
- package/dist/packages/tapestry-wc/dist/components/{p-Rn6lOB18.js → p-CY_DC4d_.js} +3 -3
- package/dist/packages/tapestry-wc/dist/components/p-CY_DC4d_.js.map +1 -0
- package/dist/packages/tapestry-wc/dist/components/{p-6NO22Vi_.js → p-DNHgMtxw.js} +2 -2
- package/dist/packages/tapestry-wc/dist/components/p-DNHgMtxw.js.map +1 -0
- package/dist/packages/tapestry-wc/dist/components/tds-page-header-nav.js +2 -2
- package/dist/packages/tapestry-wc/dist/components/tds-page-header-nav.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/tds-page-header.js +3 -3
- package/dist/packages/tapestry-wc/dist/components/tds-page-header.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-item.js +3 -3
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-item.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-responsive-header.js +2 -2
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-responsive-header.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-section.js +3 -3
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav-section.js.map +1 -1
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav.js +5 -5
- package/dist/packages/tapestry-wc/dist/components/tds-sidenav.js.map +1 -1
- package/dist/reactRender.css +756 -574
- package/dist/reactRender.css.map +1 -1
- package/dist/reactRenderLegacy.css +756 -574
- package/dist/reactRenderLegacy.css.map +1 -1
- package/dist/tapestryMount.css +756 -574
- package/dist/tapestryMount.css.map +1 -1
- package/dist/tapestryMountLegacy.css +756 -574
- package/dist/tapestryMountLegacy.css.map +1 -1
- package/dist/unstable.css +309 -127
- package/dist/unstable.css.map +1 -1
- package/dist/unstable.d.ts +0 -1
- package/dist/unstable.d.ts.map +1 -1
- package/dist/unstable.js +6 -6
- package/dist/utilities/dateFieldLocale.d.ts +2 -0
- package/dist/utilities/dateFieldLocale.d.ts.map +1 -0
- package/dist/utilities/dateFieldLocale.js +32 -0
- package/dist/utilities/dateFieldLocale.js.map +1 -0
- package/dist/utilities/useAnnounce.d.ts +22 -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/dist/utilities/useDateFieldLocale.d.ts +2 -0
- package/dist/utilities/useDateFieldLocale.d.ts.map +1 -0
- package/dist/utilities/useDateFieldLocale.js +11 -0
- package/dist/utilities/useDateFieldLocale.js.map +1 -0
- package/package.json +4 -4
- package/dist/packages/tapestry-wc/dist/components/p-6NO22Vi_.js.map +0 -1
- package/dist/packages/tapestry-wc/dist/components/p-B2xqMgNQ.js.map +0 -1
- package/dist/packages/tapestry-wc/dist/components/p-BVvtAaVT.js.map +0 -1
- package/dist/packages/tapestry-wc/dist/components/p-Rn6lOB18.js.map +0 -1
- package/dist/packages/tapestry-wc/dist/components/p-np7vhMVg.js.map +0 -1
|
@@ -2,33 +2,58 @@ 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;
|
|
12
|
+
/**
|
|
13
|
+
* The view's position, as a fractional index. Views without one are listed
|
|
14
|
+
* after those with one.
|
|
15
|
+
*/
|
|
16
|
+
sortKey?: string;
|
|
15
17
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
/** An app-provided view. Read-only. */
|
|
19
|
+
export type StaticView = SavedView & {
|
|
20
|
+
id: number | string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Always listed, so there's a view to fall back to. Added before the static
|
|
24
|
+
* views unless one of them uses its id, which replaces it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const initialView: StaticView;
|
|
27
|
+
/**
|
|
28
|
+
* Views by `sortKey`, then views without one, each in array order. Compares
|
|
29
|
+
* by code unit rather than locale, since keys mix upper and lower case.
|
|
30
|
+
*/
|
|
31
|
+
export declare function sortSavedViews(savedViews: SavedView[]): SavedView[];
|
|
32
|
+
/**
|
|
33
|
+
* A `sortKey` after every view's, for a view added at the end. Undefined
|
|
34
|
+
* while any view has no key, since those are listed last, so a view added
|
|
35
|
+
* without one stays at the end.
|
|
36
|
+
*/
|
|
37
|
+
export declare function sortKeyAfter(savedViews: SavedView[]): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* The views to update so the view at `from` is dropped before or after the
|
|
40
|
+
* view at `target`, both positions in the order. Usually just the dropped
|
|
41
|
+
* view, with a key between its new neighbors'. Dropping among views without
|
|
42
|
+
* a key also gives a key to those before it, since they come after every
|
|
43
|
+
* view with one.
|
|
44
|
+
*/
|
|
45
|
+
export declare function savedViewUpdatesForReorder(savedViews: SavedView[], from: number, target: number, dropPosition: "after" | "before"): SavedView[];
|
|
22
46
|
interface SavedViewState {
|
|
23
47
|
activeFilters: ActiveFilter[];
|
|
24
48
|
hiddenColumnNames: string[];
|
|
25
49
|
sort: Sort | undefined;
|
|
26
50
|
}
|
|
27
51
|
/**
|
|
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
|
|
52
|
+
* The most specific view matching the current state, or undefined. Only
|
|
53
|
+
* picks the initially selected view. Filters match regardless of order,
|
|
54
|
+
* ignoring display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
55
|
+
* only compared when the view sets them, so a view that sets more of them is
|
|
56
|
+
* more specific. Among equally specific matches, the first wins.
|
|
32
57
|
*/
|
|
33
58
|
export declare function findActiveSavedView(savedViews: SavedView[], state: SavedViewState): SavedView | undefined;
|
|
34
59
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"savedViews.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/savedViews.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"savedViews.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/savedViews.ts"],"names":[],"mappings":"AAEA,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;IACX;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;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;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,SAAS,EAAE,CAOnE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,GAAG,SAAS,CAOxE;AAED;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,SAAS,EAAE,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,GAAG,QAAQ,GAC/B,SAAS,EAAE,CAmBb;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,90 @@
|
|
|
1
|
+
import { generateNKeysBetween, generateKeyBetween } from 'fractional-indexing';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Always listed, so there's a view to fall back to. Added before the static
|
|
5
|
+
* views unless one of them uses its id, which replaces it.
|
|
6
|
+
*/
|
|
7
|
+
const initialView = {
|
|
8
|
+
activeFilters: [],
|
|
9
|
+
id: "initial",
|
|
10
|
+
name: "All",
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Views by `sortKey`, then views without one, each in array order. Compares
|
|
14
|
+
* by code unit rather than locale, since keys mix upper and lower case.
|
|
15
|
+
*/
|
|
16
|
+
function sortSavedViews(savedViews) {
|
|
17
|
+
return [...savedViews].sort((a, b) => {
|
|
18
|
+
if (a.sortKey === b.sortKey)
|
|
19
|
+
return 0;
|
|
20
|
+
if (a.sortKey === undefined)
|
|
21
|
+
return 1;
|
|
22
|
+
if (b.sortKey === undefined)
|
|
23
|
+
return -1;
|
|
24
|
+
return a.sortKey < b.sortKey ? -1 : 1;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A `sortKey` after every view's, for a view added at the end. Undefined
|
|
29
|
+
* while any view has no key, since those are listed last, so a view added
|
|
30
|
+
* without one stays at the end.
|
|
31
|
+
*/
|
|
32
|
+
function sortKeyAfter(savedViews) {
|
|
33
|
+
let lastSortKey = null;
|
|
34
|
+
for (const { sortKey } of savedViews) {
|
|
35
|
+
if (sortKey === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
if (lastSortKey === null || sortKey > lastSortKey)
|
|
38
|
+
lastSortKey = sortKey;
|
|
39
|
+
}
|
|
40
|
+
return generateKeyBetween(lastSortKey, null);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The views to update so the view at `from` is dropped before or after the
|
|
44
|
+
* view at `target`, both positions in the order. Usually just the dropped
|
|
45
|
+
* view, with a key between its new neighbors'. Dropping among views without
|
|
46
|
+
* a key also gives a key to those before it, since they come after every
|
|
47
|
+
* view with one.
|
|
48
|
+
*/
|
|
49
|
+
function savedViewUpdatesForReorder(savedViews, from, target, dropPosition) {
|
|
50
|
+
let to = dropPosition === "after" ? target + 1 : target;
|
|
51
|
+
// Taking the view out shifts the views after it up one.
|
|
52
|
+
if (from < to)
|
|
53
|
+
to--;
|
|
54
|
+
if (from === to)
|
|
55
|
+
return [];
|
|
56
|
+
const newOrder = [...savedViews];
|
|
57
|
+
const [view] = newOrder.splice(from, 1);
|
|
58
|
+
newOrder.splice(to, 0, view);
|
|
59
|
+
let start = to;
|
|
60
|
+
while (start > 0 && newOrder[start - 1].sortKey === undefined)
|
|
61
|
+
start--;
|
|
62
|
+
const keys = generateNKeysBetween(newOrder[start - 1]?.sortKey ?? null, newOrder[to + 1]?.sortKey ?? null, to - start + 1);
|
|
63
|
+
return newOrder
|
|
64
|
+
.slice(start, to + 1)
|
|
65
|
+
.map((view, index) => ({ ...view, sortKey: keys[index] }));
|
|
66
|
+
}
|
|
1
67
|
/**
|
|
2
|
-
* The
|
|
3
|
-
* initially selected view. Filters match regardless of order,
|
|
4
|
-
* display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
5
|
-
* compared when the view sets them
|
|
68
|
+
* The most specific view matching the current state, or undefined. Only
|
|
69
|
+
* picks the initially selected view. Filters match regardless of order,
|
|
70
|
+
* ignoring display-only labels. A view's `sort` and `hiddenColumnNames` are
|
|
71
|
+
* only compared when the view sets them, so a view that sets more of them is
|
|
72
|
+
* more specific. Among equally specific matches, the first wins.
|
|
6
73
|
*/
|
|
7
74
|
function findActiveSavedView(savedViews, state) {
|
|
8
|
-
|
|
75
|
+
let mostSpecificMatch;
|
|
76
|
+
for (const view of savedViews) {
|
|
77
|
+
if (!savedViewMatches(view, state))
|
|
78
|
+
continue;
|
|
79
|
+
if (!mostSpecificMatch ||
|
|
80
|
+
specificity(view) > specificity(mostSpecificMatch)) {
|
|
81
|
+
mostSpecificMatch = view;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return mostSpecificMatch;
|
|
85
|
+
}
|
|
86
|
+
function specificity(view) {
|
|
87
|
+
return Number(Boolean(view.sort)) + Number(Boolean(view.hiddenColumnNames));
|
|
9
88
|
}
|
|
10
89
|
function savedViewMatches(view, state) {
|
|
11
90
|
if (!filtersMatch(view.activeFilters, state.activeFilters))
|
|
@@ -47,5 +126,5 @@ function namesMatch(a, b) {
|
|
|
47
126
|
return new Set(a).size === names.size && a.every((name) => names.has(name));
|
|
48
127
|
}
|
|
49
128
|
|
|
50
|
-
export { findActiveSavedView };
|
|
129
|
+
export { findActiveSavedView, initialView, savedViewUpdatesForReorder, sortKeyAfter, sortSavedViews };
|
|
51
130
|
//# sourceMappingURL=savedViews.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"savedViews.js","sources":["../../../src/components/DataTable/savedViews.ts"],"sourcesContent":["import type { Sort } from \"./DataTable\"\nimport type { ActiveFilter } from \"./FilterTypes\"\n\nexport interface SavedView {\n activeFilters: ActiveFilter[]\n /**
|
|
1
|
+
{"version":3,"file":"savedViews.js","sources":["../../../src/components/DataTable/savedViews.ts"],"sourcesContent":["import { generateKeyBetween, generateNKeysBetween } from \"fractional-indexing\"\n\nimport type { Sort } from \"./DataTable\"\nimport type { ActiveFilter } from \"./FilterTypes\"\n\nexport interface SavedView {\n activeFilters: ActiveFilter[]\n /** Omit to leave the current column visibility unchanged when applied. */\n hiddenColumnNames?: string[]\n /** Assigned by the consumer once the view is saved. */\n id?: number | string\n name: string\n /** Omit to leave the current sort unchanged when applied. */\n sort?: Sort\n /**\n * The view's position, as a fractional index. Views without one are listed\n * after those with one.\n */\n sortKey?: string\n}\n\n/** An app-provided view. Read-only. */\nexport type StaticView = SavedView & { id: number | string }\n\n/**\n * Always listed, so there's a view to fall back to. Added before the static\n * views unless one of them uses its id, which replaces it.\n */\nexport const initialView: StaticView = {\n activeFilters: [],\n id: \"initial\",\n name: \"All\",\n}\n\n/**\n * Views by `sortKey`, then views without one, each in array order. Compares\n * by code unit rather than locale, since keys mix upper and lower case.\n */\nexport function sortSavedViews(savedViews: SavedView[]): SavedView[] {\n return [...savedViews].sort((a, b) => {\n if (a.sortKey === b.sortKey) return 0\n if (a.sortKey === undefined) return 1\n if (b.sortKey === undefined) return -1\n return a.sortKey < b.sortKey ? -1 : 1\n })\n}\n\n/**\n * A `sortKey` after every view's, for a view added at the end. Undefined\n * while any view has no key, since those are listed last, so a view added\n * without one stays at the end.\n */\nexport function sortKeyAfter(savedViews: SavedView[]): string | undefined {\n let lastSortKey: string | null = null\n for (const { sortKey } of savedViews) {\n if (sortKey === undefined) return undefined\n if (lastSortKey === null || sortKey > lastSortKey) lastSortKey = sortKey\n }\n return generateKeyBetween(lastSortKey, null)\n}\n\n/**\n * The views to update so the view at `from` is dropped before or after the\n * view at `target`, both positions in the order. Usually just the dropped\n * view, with a key between its new neighbors'. Dropping among views without\n * a key also gives a key to those before it, since they come after every\n * view with one.\n */\nexport function savedViewUpdatesForReorder(\n savedViews: SavedView[],\n from: number,\n target: number,\n dropPosition: \"after\" | \"before\"\n): SavedView[] {\n let to = dropPosition === \"after\" ? target + 1 : target\n // Taking the view out shifts the views after it up one.\n if (from < to) to--\n if (from === to) return []\n const newOrder = [...savedViews]\n const [view] = newOrder.splice(from, 1)\n newOrder.splice(to, 0, view)\n\n let start = to\n while (start > 0 && newOrder[start - 1].sortKey === undefined) start--\n const keys = generateNKeysBetween(\n newOrder[start - 1]?.sortKey ?? null,\n newOrder[to + 1]?.sortKey ?? null,\n to - start + 1\n )\n return newOrder\n .slice(start, to + 1)\n .map((view, index) => ({ ...view, sortKey: keys[index] }))\n}\n\ninterface SavedViewState {\n activeFilters: ActiveFilter[]\n hiddenColumnNames: string[]\n sort: Sort | undefined\n}\n\n/**\n * The most specific view matching the current state, or undefined. Only\n * picks the initially selected view. Filters match regardless of order,\n * ignoring display-only labels. A view's `sort` and `hiddenColumnNames` are\n * only compared when the view sets them, so a view that sets more of them is\n * more specific. Among equally specific matches, the first wins.\n */\nexport function findActiveSavedView(\n savedViews: SavedView[],\n state: SavedViewState\n): SavedView | undefined {\n let mostSpecificMatch: SavedView | undefined\n for (const view of savedViews) {\n if (!savedViewMatches(view, state)) continue\n if (\n !mostSpecificMatch ||\n specificity(view) > specificity(mostSpecificMatch)\n ) {\n mostSpecificMatch = view\n }\n }\n return mostSpecificMatch\n}\n\nfunction specificity(view: SavedView): number {\n return Number(Boolean(view.sort)) + Number(Boolean(view.hiddenColumnNames))\n}\n\nfunction savedViewMatches(view: SavedView, state: SavedViewState): boolean {\n if (!filtersMatch(view.activeFilters, state.activeFilters)) return false\n if (view.sort && !sortMatches(view.sort, state.sort)) return false\n return (\n !view.hiddenColumnNames ||\n namesMatch(view.hiddenColumnNames, state.hiddenColumnNames)\n )\n}\n\nfunction filtersMatch(a: ActiveFilter[], b: ActiveFilter[]): boolean {\n if (a.length !== b.length) return false\n const unmatched = [...b]\n return a.every((filter) => {\n const index = unmatched.findIndex((other) => filterMatches(filter, other))\n if (index === -1) return false\n unmatched.splice(index, 1)\n return true\n })\n}\n\nfunction filterMatches(a: ActiveFilter, b: ActiveFilter): boolean {\n return (\n a.name === b.name &&\n a.operator === b.operator &&\n a.scope === b.scope &&\n valueMatches(a.value, b.value)\n )\n}\n\nfunction valueMatches(a: unknown, b: unknown): boolean {\n if (Array.isArray(a) && Array.isArray(b)) {\n return a.length === b.length && a.every((item, i) => item === b[i])\n }\n return a === b\n}\n\nfunction sortMatches(a: Sort, b: Sort | undefined): boolean {\n return a.column === b?.column && a.direction === b?.direction\n}\n\nfunction namesMatch(a: string[], b: string[]): boolean {\n const names = new Set(b)\n return new Set(a).size === names.size && a.every((name) => names.has(name))\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@ import type { SavedView } from "./savedViews";
|
|
|
2
2
|
export declare function useActiveSavedView(savedViews: SavedView[], getInitialView: () => SavedView | undefined): {
|
|
3
3
|
activeSavedView: SavedView | undefined;
|
|
4
4
|
select: (view: SavedView) => void;
|
|
5
|
-
selectWhenSaved: (
|
|
5
|
+
selectWhenSaved: (savedView: Promise<SavedView> | SavedView) => Promise<void>;
|
|
6
6
|
};
|
|
7
7
|
//# sourceMappingURL=useActiveSavedView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActiveSavedView.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useActiveSavedView.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,SAAS,EAAE,EACvB,cAAc,EAAE,MAAM,SAAS,GAAG,SAAS;;
|
|
1
|
+
{"version":3,"file":"useActiveSavedView.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useActiveSavedView.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,SAAS,EAAE,EACvB,cAAc,EAAE,MAAM,SAAS,GAAG,SAAS;;mBAY1B,SAAS;iCAIW,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS;EAQpE"}
|
|
@@ -5,14 +5,20 @@ function useActiveSavedView(savedViews, getInitialView) {
|
|
|
5
5
|
// Lets a slow save skip selecting its view if the user picked another.
|
|
6
6
|
const selectionCount = useRef(0);
|
|
7
7
|
return {
|
|
8
|
-
|
|
8
|
+
// A view without an id isn't saved yet, so it can't be the active one.
|
|
9
|
+
activeSavedView: activeId === undefined
|
|
10
|
+
? undefined
|
|
11
|
+
: savedViews.find(({ id }) => id === activeId),
|
|
9
12
|
select: (view) => {
|
|
10
13
|
selectionCount.current++;
|
|
11
14
|
setActiveId(view.id);
|
|
12
15
|
},
|
|
13
|
-
selectWhenSaved: async (
|
|
16
|
+
selectWhenSaved: async (savedView) => {
|
|
14
17
|
const selection = ++selectionCount.current;
|
|
15
|
-
|
|
18
|
+
// Tolerates a consumer that returns nothing, leaving the selection as is.
|
|
19
|
+
const id = (await savedView)?.id;
|
|
20
|
+
if (id === undefined)
|
|
21
|
+
return;
|
|
16
22
|
if (selection === selectionCount.current)
|
|
17
23
|
setActiveId(id);
|
|
18
24
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useActiveSavedView.js","sources":["../../../src/components/DataTable/useActiveSavedView.ts"],"sourcesContent":["import { useRef, useState } from \"react\"\n\nimport type { SavedView } from \"./savedViews\"\n\nexport function useActiveSavedView(\n savedViews: SavedView[],\n getInitialView: () => SavedView | undefined\n) {\n const [activeId, setActiveId] = useState(() => getInitialView()?.id)\n // Lets a slow save skip selecting its view if the user picked another.\n const selectionCount = useRef(0)\n\n return {\n activeSavedView: savedViews.find(({ id }) => id === activeId),\n select: (view: SavedView) => {\n selectionCount.current++\n setActiveId(view.id)\n },\n selectWhenSaved: async (
|
|
1
|
+
{"version":3,"file":"useActiveSavedView.js","sources":["../../../src/components/DataTable/useActiveSavedView.ts"],"sourcesContent":["import { useRef, useState } from \"react\"\n\nimport type { SavedView } from \"./savedViews\"\n\nexport function useActiveSavedView(\n savedViews: SavedView[],\n getInitialView: () => SavedView | undefined\n) {\n const [activeId, setActiveId] = useState(() => getInitialView()?.id)\n // Lets a slow save skip selecting its view if the user picked another.\n const selectionCount = useRef(0)\n\n return {\n // A view without an id isn't saved yet, so it can't be the active one.\n activeSavedView:\n activeId === undefined\n ? undefined\n : savedViews.find(({ id }) => id === activeId),\n select: (view: SavedView) => {\n selectionCount.current++\n setActiveId(view.id)\n },\n selectWhenSaved: async (savedView: Promise<SavedView> | SavedView) => {\n const selection = ++selectionCount.current\n // Tolerates a consumer that returns nothing, leaving the selection as is.\n const id = (await savedView)?.id\n if (id === undefined) return\n if (selection === selectionCount.current) setActiveId(id)\n },\n }\n}\n"],"names":[],"mappings":";;AAIM,SAAU,kBAAkB,CAChC,UAAuB,EACvB,cAA2C,EAAA;AAE3C,IAAA,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,MAAM,cAAc,EAAE,EAAE,EAAE,CAAC;;AAEpE,IAAA,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC;IAEhC,OAAO;;QAEL,eAAe,EACb,QAAQ,KAAK;AACX,cAAE;AACF,cAAE,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,QAAQ,CAAC;AAClD,QAAA,MAAM,EAAE,CAAC,IAAe,KAAI;YAC1B,cAAc,CAAC,OAAO,EAAE;AACxB,YAAA,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,CAAC;AACD,QAAA,eAAe,EAAE,OAAO,SAAyC,KAAI;AACnE,YAAA,MAAM,SAAS,GAAG,EAAE,cAAc,CAAC,OAAO;;YAE1C,MAAM,EAAE,GAAG,CAAC,MAAM,SAAS,GAAG,EAAE;YAChC,IAAI,EAAE,KAAK,SAAS;gBAAE;AACtB,YAAA,IAAI,SAAS,KAAK,cAAc,CAAC,OAAO;gBAAE,WAAW,CAAC,EAAE,CAAC;QAC3D,CAAC;KACF;AACH;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DataTableLoadingState } from "./DataTable";
|
|
2
|
+
import type { ActiveFilter } from "./FilterTypes";
|
|
3
|
+
import { type ResultNoun } from "./ResultsCount";
|
|
4
|
+
export declare const FILTER_ANNOUNCEMENT_DELAY_MS = 500;
|
|
5
|
+
/**
|
|
6
|
+
* Announces the results count to screen reader users after each filter
|
|
7
|
+
* change, once the results settle: `loadingState` is not `"loading"`, and
|
|
8
|
+
* neither it nor the count has changed for
|
|
9
|
+
* {@link FILTER_ANNOUNCEMENT_DELAY_MS}. A change to `"error"` cancels the
|
|
10
|
+
* message, because the error is announced on its own. An `"error"` left over
|
|
11
|
+
* from an earlier request only delays it.
|
|
12
|
+
*
|
|
13
|
+
* Returns an `onActiveFiltersChange` to use in place of the caller's, so only
|
|
14
|
+
* changes the user makes are announced.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useFilterAnnouncement({ isPageCount, loadingState, onActiveFiltersChange, resultNoun, totalCount, }: {
|
|
17
|
+
/** Whether `totalCount` covers only the current page, not the whole set. */
|
|
18
|
+
isPageCount: boolean;
|
|
19
|
+
loadingState: DataTableLoadingState;
|
|
20
|
+
onActiveFiltersChange: (activeFilters: ActiveFilter[]) => void;
|
|
21
|
+
resultNoun: ResultNoun | undefined;
|
|
22
|
+
totalCount: number;
|
|
23
|
+
}): (activeFilters: ActiveFilter[]) => void;
|
|
24
|
+
//# sourceMappingURL=useFilterAnnouncement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFilterAnnouncement.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useFilterAnnouncement.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAwB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAEtE,eAAO,MAAM,4BAA4B,MAAM,CAAA;AAE/C;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,EACpC,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,UAAU,EACV,UAAU,GACX,EAAE;IACD,4EAA4E;IAC5E,WAAW,EAAE,OAAO,CAAA;IACpB,YAAY,EAAE,qBAAqB,CAAA;IACnC,qBAAqB,EAAE,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,IAAI,CAAA;IAC9D,UAAU,EAAE,UAAU,GAAG,SAAS,CAAA;IAClC,UAAU,EAAE,MAAM,CAAA;CACnB,GAAG,CAAC,aAAa,EAAE,YAAY,EAAE,KAAK,IAAI,CA8B1C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useAnnounce } from '../../utilities/useAnnounce.js';
|
|
2
|
+
import { useRef, useState, useEffect } from 'react';
|
|
3
|
+
import { getResultsCountLabel } from './ResultsCount.js';
|
|
4
|
+
|
|
5
|
+
const FILTER_ANNOUNCEMENT_DELAY_MS = 500;
|
|
6
|
+
/**
|
|
7
|
+
* Announces the results count to screen reader users after each filter
|
|
8
|
+
* change, once the results settle: `loadingState` is not `"loading"`, and
|
|
9
|
+
* neither it nor the count has changed for
|
|
10
|
+
* {@link FILTER_ANNOUNCEMENT_DELAY_MS}. A change to `"error"` cancels the
|
|
11
|
+
* message, because the error is announced on its own. An `"error"` left over
|
|
12
|
+
* from an earlier request only delays it.
|
|
13
|
+
*
|
|
14
|
+
* Returns an `onActiveFiltersChange` to use in place of the caller's, so only
|
|
15
|
+
* changes the user makes are announced.
|
|
16
|
+
*/
|
|
17
|
+
function useFilterAnnouncement({ isPageCount, loadingState, onActiveFiltersChange, resultNoun, totalCount, }) {
|
|
18
|
+
const announce = useAnnounce();
|
|
19
|
+
const isDue = useRef(false);
|
|
20
|
+
const previousLoadingState = useRef(loadingState);
|
|
21
|
+
const [changeCount, setChangeCount] = useState(0);
|
|
22
|
+
const countLabel = getResultsCountLabel(totalCount, resultNoun || true);
|
|
23
|
+
const message = isPageCount ? `${countLabel} on this page` : countLabel;
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const failed = loadingState === "error" && previousLoadingState.current !== "error";
|
|
26
|
+
previousLoadingState.current = loadingState;
|
|
27
|
+
if (!isDue.current)
|
|
28
|
+
return;
|
|
29
|
+
if (failed) {
|
|
30
|
+
isDue.current = false;
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (loadingState !== "idle")
|
|
34
|
+
return;
|
|
35
|
+
const timeout = setTimeout(() => {
|
|
36
|
+
isDue.current = false;
|
|
37
|
+
announce(message);
|
|
38
|
+
}, FILTER_ANNOUNCEMENT_DELAY_MS);
|
|
39
|
+
return () => clearTimeout(timeout);
|
|
40
|
+
}, [announce, changeCount, loadingState, message]);
|
|
41
|
+
return (activeFilters) => {
|
|
42
|
+
isDue.current = true;
|
|
43
|
+
setChangeCount((count) => count + 1);
|
|
44
|
+
onActiveFiltersChange(activeFilters);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export { FILTER_ANNOUNCEMENT_DELAY_MS, useFilterAnnouncement };
|
|
49
|
+
//# sourceMappingURL=useFilterAnnouncement.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFilterAnnouncement.js","sources":["../../../src/components/DataTable/useFilterAnnouncement.ts"],"sourcesContent":["import { useAnnounce } from \"@utilities/useAnnounce\"\nimport { useEffect, useRef, useState } from \"react\"\n\nimport type { DataTableLoadingState } from \"./DataTable\"\nimport type { ActiveFilter } from \"./FilterTypes\"\nimport { getResultsCountLabel, type ResultNoun } from \"./ResultsCount\"\n\nexport const FILTER_ANNOUNCEMENT_DELAY_MS = 500\n\n/**\n * Announces the results count to screen reader users after each filter\n * change, once the results settle: `loadingState` is not `\"loading\"`, and\n * neither it nor the count has changed for\n * {@link FILTER_ANNOUNCEMENT_DELAY_MS}. A change to `\"error\"` cancels the\n * message, because the error is announced on its own. An `\"error\"` left over\n * from an earlier request only delays it.\n *\n * Returns an `onActiveFiltersChange` to use in place of the caller's, so only\n * changes the user makes are announced.\n */\nexport function useFilterAnnouncement({\n isPageCount,\n loadingState,\n onActiveFiltersChange,\n resultNoun,\n totalCount,\n}: {\n /** Whether `totalCount` covers only the current page, not the whole set. */\n isPageCount: boolean\n loadingState: DataTableLoadingState\n onActiveFiltersChange: (activeFilters: ActiveFilter[]) => void\n resultNoun: ResultNoun | undefined\n totalCount: number\n}): (activeFilters: ActiveFilter[]) => void {\n const announce = useAnnounce()\n const isDue = useRef(false)\n const previousLoadingState = useRef(loadingState)\n const [changeCount, setChangeCount] = useState(0)\n const countLabel = getResultsCountLabel(totalCount, resultNoun || true)\n const message = isPageCount ? `${countLabel} on this page` : countLabel\n\n useEffect(() => {\n const failed =\n loadingState === \"error\" && previousLoadingState.current !== \"error\"\n previousLoadingState.current = loadingState\n if (!isDue.current) return\n if (failed) {\n isDue.current = false\n return\n }\n if (loadingState !== \"idle\") return\n const timeout = setTimeout(() => {\n isDue.current = false\n announce(message)\n }, FILTER_ANNOUNCEMENT_DELAY_MS)\n return () => clearTimeout(timeout)\n }, [announce, changeCount, loadingState, message])\n\n return (activeFilters) => {\n isDue.current = true\n setChangeCount((count) => count + 1)\n onActiveFiltersChange(activeFilters)\n }\n}\n"],"names":[],"mappings":";;;;AAOO,MAAM,4BAA4B,GAAG;AAE5C;;;;;;;;;;AAUG;AACG,SAAU,qBAAqB,CAAC,EACpC,WAAW,EACX,YAAY,EACZ,qBAAqB,EACrB,UAAU,EACV,UAAU,GAQX,EAAA;AACC,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;AAC9B,IAAA,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AAC3B,IAAA,MAAM,oBAAoB,GAAG,MAAM,CAAC,YAAY,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,oBAAoB,CAAC,UAAU,EAAE,UAAU,IAAI,IAAI,CAAC;AACvE,IAAA,MAAM,OAAO,GAAG,WAAW,GAAG,CAAA,EAAG,UAAU,CAAA,aAAA,CAAe,GAAG,UAAU;IAEvE,SAAS,CAAC,MAAK;QACb,MAAM,MAAM,GACV,YAAY,KAAK,OAAO,IAAI,oBAAoB,CAAC,OAAO,KAAK,OAAO;AACtE,QAAA,oBAAoB,CAAC,OAAO,GAAG,YAAY;QAC3C,IAAI,CAAC,KAAK,CAAC,OAAO;YAAE;QACpB,IAAI,MAAM,EAAE;AACV,YAAA,KAAK,CAAC,OAAO,GAAG,KAAK;YACrB;QACF;QACA,IAAI,YAAY,KAAK,MAAM;YAAE;AAC7B,QAAA,MAAM,OAAO,GAAG,UAAU,CAAC,MAAK;AAC9B,YAAA,KAAK,CAAC,OAAO,GAAG,KAAK;YACrB,QAAQ,CAAC,OAAO,CAAC;QACnB,CAAC,EAAE,4BAA4B,CAAC;AAChC,QAAA,OAAO,MAAM,YAAY,CAAC,OAAO,CAAC;IACpC,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IAElD,OAAO,CAAC,aAAa,KAAI;AACvB,QAAA,KAAK,CAAC,OAAO,GAAG,IAAI;QACpB,cAAc,CAAC,CAAC,KAAK,KAAK,KAAK,GAAG,CAAC,CAAC;QACpC,qBAAqB,CAAC,aAAa,CAAC;AACtC,IAAA,CAAC;AACH;;;;"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SavedView } from "./savedViews";
|
|
2
|
+
/**
|
|
3
|
+
* Saves a view's new name, trimmed. Callers skip blank and unchanged names,
|
|
4
|
+
* since `view.name` is out of date while a save is pending.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useUpdateSavedViewName(onUpdate?: (savedView: SavedView) => Promise<SavedView> | SavedView): (view: SavedView, name: string) => Promise<void>;
|
|
7
|
+
//# sourceMappingURL=useUpdateSavedViewName.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUpdateSavedViewName.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/useUpdateSavedViewName.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,IAErD,MAAM,SAAS,EAAE,MAAM,MAAM,mBAG5C"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Saves a view's new name, trimmed. Callers skip blank and unchanged names,
|
|
3
|
+
* since `view.name` is out of date while a save is pending.
|
|
4
|
+
*/
|
|
5
|
+
function useUpdateSavedViewName(onUpdate) {
|
|
6
|
+
return async (view, name) => {
|
|
7
|
+
await onUpdate?.({ ...view, name: name.trim() });
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export { useUpdateSavedViewName };
|
|
12
|
+
//# sourceMappingURL=useUpdateSavedViewName.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUpdateSavedViewName.js","sources":["../../../src/components/DataTable/useUpdateSavedViewName.ts"],"sourcesContent":["import type { SavedView } from \"./savedViews\"\n\n/**\n * Saves a view's new name, trimmed. Callers skip blank and unchanged names,\n * since `view.name` is out of date while a save is pending.\n */\nexport function useUpdateSavedViewName(\n onUpdate?: (savedView: SavedView) => Promise<SavedView> | SavedView\n) {\n return async (view: SavedView, name: string) => {\n await onUpdate?.({ ...view, name: name.trim() })\n }\n}\n"],"names":[],"mappings":"AAEA;;;AAGG;AACG,SAAU,sBAAsB,CACpC,QAAmE,EAAA;AAEnE,IAAA,OAAO,OAAO,IAAe,EAAE,IAAY,KAAI;AAC7C,QAAA,MAAM,QAAQ,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;AAClD,IAAA,CAAC;AACH;;;;"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import { type TooltipPlacement } from "../internal/tooltip";
|
|
1
2
|
import { ComponentSize } from "../../utilities/buttonLinkShared";
|
|
2
3
|
import React from "react";
|
|
3
|
-
import {
|
|
4
|
-
export type ActionsDropdownIconButtonProps = Omit<
|
|
4
|
+
import { IconButtonBaseProps } from "./IconButton";
|
|
5
|
+
export type ActionsDropdownIconButtonProps = Omit<IconButtonBaseProps, "aria-label" | "icon" | "kind" | "loading" | "size"> & {
|
|
5
6
|
/**
|
|
6
|
-
* Accessible name. Defaults to `"Actions"
|
|
7
|
-
* several actions menus that need
|
|
8
|
-
* Jane Doe"`).
|
|
7
|
+
* Accessible name. Defaults to `"Actions"` when `tooltip` is not set.
|
|
8
|
+
* Override when a page has several actions menus that need
|
|
9
|
+
* distinguishing (e.g. `"Actions for Jane Doe"`).
|
|
9
10
|
*/
|
|
10
11
|
"aria-label"?: string;
|
|
11
12
|
/**
|
|
@@ -38,6 +39,10 @@ export type ActionsDropdownIconButtonProps = Omit<IconButtonProps, "aria-label"
|
|
|
38
39
|
size?: Exclude<ComponentSize, "xs">;
|
|
39
40
|
/** Not supported — no caret, and nothing else in the suffix slot. */
|
|
40
41
|
suffix?: never;
|
|
42
|
+
/** Text shown on hover and focus. Without `aria-label`, it is also used as the `aria-label`. With `aria-label`, start the `aria-label` with the same text (e.g. tooltip `"Delete"`, aria-label `"Delete, 3 selected"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */
|
|
43
|
+
tooltip?: string;
|
|
44
|
+
/** Where the tooltip renders relative to the button. Default `"bottom"`. Has no effect without `tooltip`. */
|
|
45
|
+
tooltipPlacement?: TooltipPlacement;
|
|
41
46
|
};
|
|
42
47
|
/**
|
|
43
48
|
* An icon-only dropdown trigger with a vertical-ellipsis glyph and no
|
|
@@ -45,11 +50,11 @@ export type ActionsDropdownIconButtonProps = Omit<IconButtonProps, "aria-label"
|
|
|
45
50
|
*
|
|
46
51
|
* @component
|
|
47
52
|
*/
|
|
48
|
-
export declare const ActionsDropdownIconButton: React.ForwardRefExoticComponent<Omit<
|
|
53
|
+
export declare const ActionsDropdownIconButton: React.ForwardRefExoticComponent<Omit<IconButtonBaseProps, "size" | "icon" | "aria-label" | "kind" | "loading"> & {
|
|
49
54
|
/**
|
|
50
|
-
* Accessible name. Defaults to `"Actions"
|
|
51
|
-
* several actions menus that need
|
|
52
|
-
* Jane Doe"`).
|
|
55
|
+
* Accessible name. Defaults to `"Actions"` when `tooltip` is not set.
|
|
56
|
+
* Override when a page has several actions menus that need
|
|
57
|
+
* distinguishing (e.g. `"Actions for Jane Doe"`).
|
|
53
58
|
*/
|
|
54
59
|
"aria-label"?: string;
|
|
55
60
|
/**
|
|
@@ -82,5 +87,9 @@ export declare const ActionsDropdownIconButton: React.ForwardRefExoticComponent<
|
|
|
82
87
|
size?: Exclude<ComponentSize, "xs">;
|
|
83
88
|
/** Not supported — no caret, and nothing else in the suffix slot. */
|
|
84
89
|
suffix?: never;
|
|
90
|
+
/** Text shown on hover and focus. Without `aria-label`, it is also used as the `aria-label`. With `aria-label`, start the `aria-label` with the same text (e.g. tooltip `"Delete"`, aria-label `"Delete, 3 selected"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */
|
|
91
|
+
tooltip?: string;
|
|
92
|
+
/** Where the tooltip renders relative to the button. Default `"bottom"`. Has no effect without `tooltip`. */
|
|
93
|
+
tooltipPlacement?: TooltipPlacement;
|
|
85
94
|
} & React.RefAttributes<HTMLButtonElement>>;
|
|
86
95
|
//# sourceMappingURL=ActionsDropdownIconButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionsDropdownIconButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/ActionsDropdownIconButton.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAG3D,OAAO,KAAiC,MAAM,OAAO,CAAA;AAErD,OAAO,EAAc,
|
|
1
|
+
{"version":3,"file":"ActionsDropdownIconButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/ActionsDropdownIconButton.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAG3D,OAAO,KAAiC,MAAM,OAAO,CAAA;AAErD,OAAO,EAAc,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAE9D,MAAM,MAAM,8BAA8B,GAAG,IAAI,CAC/C,mBAAmB,EACnB,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CACpD,GAAG;IACF;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;OAGG;IACH,SAAS,CAAC,EAAE,KAAK,CAAA;IACjB,yEAAyE;IACzE,IAAI,CAAC,EAAE,KAAK,CAAA;IACZ;;;OAGG;IACH,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;IAC1B;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,CAAA;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,KAAK,CAAA;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAA;IACnC,qEAAqE;IACrE,MAAM,CAAC,EAAE,KAAK,CAAA;IACd,wSAAwS;IACxS,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6GAA6G;IAC7G,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;CACpC,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB;IAhDpC;;;;OAIG;mBACY,MAAM;IACrB;;;OAGG;gBACS,KAAK;IACjB,yEAAyE;WAClE,KAAK;IACZ;;;OAGG;WACI,OAAO,GAAG,SAAS;IAC1B;;;OAGG;cACO,KAAK;IACf;;;OAGG;aACM,KAAK;IACd;;;;OAIG;WACI,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC;IACnC,qEAAqE;aAC5D,KAAK;IACd,wSAAwS;cAC9R,MAAM;IAChB,6GAA6G;uBAC1F,gBAAgB;2CAiDpC,CAAA"}
|
|
@@ -10,9 +10,12 @@ import { IconButton } from './IconButton.js';
|
|
|
10
10
|
*
|
|
11
11
|
* @component
|
|
12
12
|
*/
|
|
13
|
-
const ActionsDropdownIconButton = forwardRef(({ "aria-label": ariaLabel
|
|
13
|
+
const ActionsDropdownIconButton = forwardRef(({ "aria-label": ariaLabel, className, kind = "ghost", tooltip, ...restProps }, ref) => {
|
|
14
14
|
const contextProps = useContext(DropdownTriggerContext);
|
|
15
|
-
|
|
15
|
+
const nameProps = tooltip
|
|
16
|
+
? { "aria-label": ariaLabel, tooltip }
|
|
17
|
+
: { "aria-label": ariaLabel ?? "Actions" };
|
|
18
|
+
return (React.createElement(IconButton, { ref: ref, ...restProps, ...contextProps, ...nameProps, className: classNames(className, "tds-btn--actions-dropdown"), fullWidth: false, icon: React.createElement(Icon, { className: "actions-icon", symbol: "general#three-dots", "aria-hidden": true }), kind: kind, loading: undefined, prefix: undefined, suffix: undefined }));
|
|
16
19
|
});
|
|
17
20
|
ActionsDropdownIconButton.displayName = "ActionsDropdownIconButton";
|
|
18
21
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActionsDropdownIconButton.js","sources":["../../../src/components/button/ActionsDropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport { ComponentSize } from \"@utilities/buttonLinkShared\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { IconButton,
|
|
1
|
+
{"version":3,"file":"ActionsDropdownIconButton.js","sources":["../../../src/components/button/ActionsDropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport { type TooltipPlacement } from \"@components/internal/tooltip\"\nimport { ComponentSize } from \"@utilities/buttonLinkShared\"\nimport Icon from \"@utilities/Icon\"\nimport classNames from \"classnames\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { IconButton, IconButtonBaseProps } from \"./IconButton\"\n\nexport type ActionsDropdownIconButtonProps = Omit<\n IconButtonBaseProps,\n \"aria-label\" | \"icon\" | \"kind\" | \"loading\" | \"size\"\n> & {\n /**\n * Accessible name. Defaults to `\"Actions\"` when `tooltip` is not set.\n * Override when a page has several actions menus that need\n * distinguishing (e.g. `\"Actions for Jane Doe\"`).\n */\n \"aria-label\"?: string\n /**\n * Not supported — an actions trigger is a fixed-size icon button and\n * shouldn't stretch to fill a container. Always rendered as `false`.\n */\n fullWidth?: never\n /** Not supported — the vertical ellipsis is the component's identity. */\n icon?: never\n /**\n * Only `\"ghost\"` and `\"neutral\"` are supported treatments for an actions\n * trigger. Defaults to `\"ghost\"`.\n */\n kind?: \"ghost\" | \"neutral\"\n /**\n * Not supported — `.tds-btn--loading` hides every non-spinner child, so a\n * loading actions button would render a bare spinner with no glyph.\n */\n loading?: never\n /**\n * Not supported — same reasoning as `suffix`: total control over the\n * button's contents, and no slot besides the fixed ellipsis icon.\n */\n prefix?: never\n /**\n * `xs` is excluded — at 20px effective height it falls below the WCAG 2.2\n * AA 24×24 minimum target size, and an icon-only button has no text\n * content to widen it past the minimum.\n */\n size?: Exclude<ComponentSize, \"xs\">\n /** Not supported — no caret, and nothing else in the suffix slot. */\n suffix?: never\n /** Text shown on hover and focus. Without `aria-label`, it is also used as the `aria-label`. With `aria-label`, start the `aria-label` with the same text (e.g. tooltip `\"Delete\"`, aria-label `\"Delete, 3 selected\"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */\n tooltip?: string\n /** Where the tooltip renders relative to the button. Default `\"bottom\"`. Has no effect without `tooltip`. */\n tooltipPlacement?: TooltipPlacement\n}\n\n/**\n * An icon-only dropdown trigger with a vertical-ellipsis glyph and no\n * caret, for action menus where a caret is visually redundant.\n *\n * @component\n */\nexport const ActionsDropdownIconButton = forwardRef<\n HTMLButtonElement,\n ActionsDropdownIconButtonProps\n>(\n (\n {\n \"aria-label\": ariaLabel,\n className,\n kind = \"ghost\",\n tooltip,\n ...restProps\n }: ActionsDropdownIconButtonProps,\n ref\n ) => {\n const contextProps = useContext(DropdownTriggerContext)\n const nameProps = tooltip\n ? { \"aria-label\": ariaLabel, tooltip }\n : { \"aria-label\": ariaLabel ?? \"Actions\" }\n return (\n <IconButton\n ref={ref}\n {...restProps}\n {...contextProps}\n {...nameProps}\n className={classNames(className, \"tds-btn--actions-dropdown\")}\n fullWidth={false}\n icon={\n <Icon\n className=\"actions-icon\"\n symbol=\"general#three-dots\"\n aria-hidden\n />\n }\n kind={kind}\n loading={undefined}\n prefix={undefined}\n suffix={undefined}\n />\n )\n }\n)\n\nActionsDropdownIconButton.displayName = \"ActionsDropdownIconButton\"\n"],"names":[],"mappings":";;;;;;AAuDA;;;;;AAKG;AACI,MAAM,yBAAyB,GAAG,UAAU,CAIjD,CACE,EACE,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,IAAI,GAAG,OAAO,EACd,OAAO,EACP,GAAG,SAAS,EACmB,EACjC,GAAG,KACD;AACF,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC,sBAAsB,CAAC;IACvD,MAAM,SAAS,GAAG;AAChB,UAAE,EAAE,YAAY,EAAE,SAAS,EAAE,OAAO;UAClC,EAAE,YAAY,EAAE,SAAS,IAAI,SAAS,EAAE;IAC5C,QACE,KAAA,CAAA,aAAA,CAAC,UAAU,EAAA,EACT,GAAG,EAAE,GAAG,EAAA,GACJ,SAAS,EAAA,GACT,YAAY,EAAA,GACZ,SAAS,EACb,SAAS,EAAE,UAAU,CAAC,SAAS,EAAE,2BAA2B,CAAC,EAC7D,SAAS,EAAE,KAAK,EAChB,IAAI,EACF,oBAAC,IAAI,EAAA,EACH,SAAS,EAAC,cAAc,EACxB,MAAM,EAAC,oBAAoB,EAAA,aAAA,EAAA,IAAA,EAAA,CAE3B,EAEJ,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,SAAS,EAClB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,SAAS,EAAA,CACjB;AAEN,CAAC;AAGH,yBAAyB,CAAC,WAAW,GAAG,2BAA2B;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/BaseButton.tsx"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAIlB,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAEd,MAAM,6BAA6B,CAAA;AAEpC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"BaseButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/BaseButton.tsx"],"names":[],"mappings":"AAAA,OAAO,WAAW,CAAA;AAIlB,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAEd,MAAM,6BAA6B,CAAA;AAEpC,OAAO,KAAK,EAAE,EACZ,oBAAoB,EAIrB,MAAM,OAAO,CAAA;AAId,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACvE,sCAAsC;IACtC,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,sCAAsC;IACtC,KAAK,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,+GAA+G;IAC/G,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,mEAAmE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,MAAM,MAAM,sBAAsB,GAAG,IAAI,CACvC,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,eAAe,GAAG,UAAU,CACnC,GACC,eAAe,CAAA;AAEjB,eAAO,MAAM,UAAU,qLAkEtB,CAAA"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import LoadingSpinner from '../internal/LoadingSpinner.js';
|
|
2
|
+
import React, { forwardRef, useContext } from 'react';
|
|
3
|
+
import 'react-aria/private/live-announcer/LiveAnnouncer';
|
|
2
4
|
import '../internal/tooltip/Tooltip.js';
|
|
3
5
|
import { TooltipTriggerContext } from '../internal/tooltip/TooltipTriggerContext.js';
|
|
4
6
|
import { COMPONENT_SIZE_CLASS_MAP, COMPONENT_KIND_CLASS_MAP, wrapStringWithSpan } from '../../utilities/buttonLinkShared.js';
|
|
5
7
|
import classNames from 'classnames';
|
|
6
|
-
import React, { forwardRef, useContext } from 'react';
|
|
7
8
|
import { mergeProps } from 'react-aria/mergeProps';
|
|
8
9
|
import { mergeRefs } from 'react-aria/mergeRefs';
|
|
9
10
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseButton.js","sources":["../../../src/components/button/BaseButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { TooltipTriggerContext } from \"@components/internal/tooltip/TooltipTriggerContext\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport classNames from \"classnames\"\nimport React, {
|
|
1
|
+
{"version":3,"file":"BaseButton.js","sources":["../../../src/components/button/BaseButton.tsx"],"sourcesContent":["import \"./btn.css\"\n\nimport { LoadingSpinner } from \"@components/internal\"\nimport { TooltipTriggerContext } from \"@components/internal/tooltip/TooltipTriggerContext\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport classNames from \"classnames\"\nimport React, {\n ButtonHTMLAttributes,\n forwardRef,\n RefObject,\n useContext,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { mergeRefs } from \"react-aria/mergeRefs\"\n\nexport interface BaseButtonProps extends Omit<BaseComponentProps, \"kind\"> {\n /** The visual style of the button. */\n kind?: ComponentKind\n /** The text content of the button. */\n label: React.ReactNode\n /** Whether the button is in a loading state. When true, the button is disabled and shows a loading spinner. */\n loading?: boolean\n /** Accessible label to use when the button is in loading state. */\n loadingAriaLabel?: string\n}\n\nexport type BaseButtonElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n keyof BaseButtonProps | \"children\"\n> &\n BaseButtonProps\n\nexport const BaseButton = forwardRef<HTMLButtonElement, BaseButtonElementProps>(\n (\n {\n \"aria-describedby\": ariaDescribedBy,\n \"aria-label\": ariaLabel,\n className,\n disabled = false,\n fullWidth,\n kind = \"secondary\",\n label,\n loading = false,\n loadingAriaLabel = \"Loading...\",\n prefix,\n size,\n suffix,\n ...restProps\n }: BaseButtonElementProps,\n ref\n ) => {\n const tooltip = useContext(TooltipTriggerContext)\n const { \"aria-describedby\": tooltipId, ...tooltipTriggerProps } =\n tooltip?.triggerProps ?? {}\n\n const mergedProps = tooltip\n ? mergeProps(restProps, tooltipTriggerProps)\n : restProps\n const mergedRef = tooltip\n ? mergeRefs<HTMLButtonElement>(\n ref,\n tooltip.ref as RefObject<HTMLButtonElement>\n )\n : ref\n const describedBy =\n [ariaDescribedBy, tooltipId].filter(Boolean).join(\" \") || undefined\n\n const combinedClassName = classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n fullWidth && \"tds-btn--full-width\",\n loading && \"tds-btn--loading\",\n className,\n { \"tds-btn--prefix\": prefix, \"tds-btn--suffix\": suffix }\n )\n\n const isDisabled = disabled || loading\n\n return (\n <button\n type=\"button\"\n className={combinedClassName}\n ref={mergedRef}\n {...mergedProps}\n aria-busy={loading || undefined}\n aria-describedby={describedBy}\n aria-disabled={isDisabled || undefined}\n disabled={isDisabled}\n aria-label={loading ? loadingAriaLabel : ariaLabel}\n >\n {loading && <LoadingSpinner />}\n {wrapStringWithSpan(prefix)}\n {loading ? <span>{label}</span> : label}\n {wrapStringWithSpan(suffix)}\n </button>\n )\n }\n)\n\nBaseButton.displayName = \"BaseButton\"\n"],"names":[],"mappings":";;;;;;;;;;MAsCa,UAAU,GAAG,UAAU,CAClC,CACE,EACE,kBAAkB,EAAE,eAAe,EACnC,YAAY,EAAE,SAAS,EACvB,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,IAAI,GAAG,WAAW,EAClB,KAAK,EACL,OAAO,GAAG,KAAK,EACf,gBAAgB,GAAG,YAAY,EAC/B,MAAM,EACN,IAAI,EACJ,MAAM,EACN,GAAG,SAAS,EACW,EACzB,GAAG,KACD;AACF,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,qBAAqB,CAAC;AACjD,IAAA,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,mBAAmB,EAAE,GAC7D,OAAO,EAAE,YAAY,IAAI,EAAE;IAE7B,MAAM,WAAW,GAAG;AAClB,UAAE,UAAU,CAAC,SAAS,EAAE,mBAAmB;UACzC,SAAS;IACb,MAAM,SAAS,GAAG;UACd,SAAS,CACP,GAAG,EACH,OAAO,CAAC,GAAmC;UAE7C,GAAG;AACP,IAAA,MAAM,WAAW,GACf,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS;IAErE,MAAM,iBAAiB,GAAG,UAAU,CAClC,IAAI,IAAI,SAAS,EACjB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACvD,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,IAAI,qBAAqB,EAClC,OAAO,IAAI,kBAAkB,EAC7B,SAAS,EACT,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CACzD;AAED,IAAA,MAAM,UAAU,GAAG,QAAQ,IAAI,OAAO;AAEtC,IAAA,QACE,KAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,SAAS,KACV,WAAW,EAAA,WAAA,EACJ,OAAO,IAAI,SAAS,EAAA,kBAAA,EACb,WAAW,mBACd,UAAU,IAAI,SAAS,EACtC,QAAQ,EAAE,UAAU,EAAA,YAAA,EACR,OAAO,GAAG,gBAAgB,GAAG,SAAS,EAAA;QAEjD,OAAO,IAAI,KAAA,CAAA,aAAA,CAAC,cAAc,EAAA,IAAA,CAAG;QAC7B,kBAAkB,CAAC,MAAM,CAAC;QAC1B,OAAO,GAAG,KAAA,CAAA,aAAA,CAAA,MAAA,EAAA,IAAA,EAAO,KAAK,CAAQ,GAAG,KAAK;AACtC,QAAA,kBAAkB,CAAC,MAAM,CAAC,CACpB;AAEb,CAAC;AAGH,UAAU,CAAC,WAAW,GAAG,YAAY;;;;"}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { DropdownButtonProps } from "./DropdownButton";
|
|
3
|
+
import { IconButtonProps } from "./IconButton";
|
|
3
4
|
/**
|
|
4
5
|
* An icon-only button that toggles a dropdown menu or popover. Appends a
|
|
5
6
|
* caret suffix to the icon and wires up `aria-controls` and `aria-expanded`
|
|
6
|
-
* to the controlled element. Requires an `aria-label` for
|
|
7
|
+
* to the controlled element. Requires an `aria-label` or `tooltip` for
|
|
8
|
+
* accessibility.
|
|
7
9
|
*
|
|
8
10
|
* @component
|
|
9
11
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/buttons-dropdown-icon-button--docs | Storybook Documentation}
|
|
10
12
|
* @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}
|
|
11
13
|
*/
|
|
12
|
-
export declare const DropdownIconButton: React.ForwardRefExoticComponent<
|
|
13
|
-
"aria-label": string;
|
|
14
|
-
icon: React.ReactNode;
|
|
15
|
-
} & DropdownButtonProps & React.RefAttributes<HTMLButtonElement>>;
|
|
14
|
+
export declare const DropdownIconButton: React.ForwardRefExoticComponent<(IconButtonProps & DropdownButtonProps) & React.RefAttributes<HTMLButtonElement>>;
|
|
16
15
|
//# sourceMappingURL=DropdownIconButton.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownIconButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/DropdownIconButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiC,MAAM,OAAO,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAiB,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"DropdownIconButton.d.ts","sourceRoot":"","sources":["../../../src/components/button/DropdownIconButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiC,MAAM,OAAO,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAiB,MAAM,kBAAkB,CAAA;AACrE,OAAO,EAAc,eAAe,EAAE,MAAM,cAAc,CAAA;AAE1D;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,mHAa7B,CAAA"}
|
|
@@ -6,7 +6,8 @@ import { IconButton } from './IconButton.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* An icon-only button that toggles a dropdown menu or popover. Appends a
|
|
8
8
|
* caret suffix to the icon and wires up `aria-controls` and `aria-expanded`
|
|
9
|
-
* to the controlled element. Requires an `aria-label` for
|
|
9
|
+
* to the controlled element. Requires an `aria-label` or `tooltip` for
|
|
10
|
+
* accessibility.
|
|
10
11
|
*
|
|
11
12
|
* @component
|
|
12
13
|
* @see {@link https://planningcenter.github.io/tapestry/?path=/docs/buttons-dropdown-icon-button--docs | Storybook Documentation}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownIconButton.js","sources":["../../../src/components/button/DropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { DropdownButtonProps, dropdownProps } from \"./DropdownButton\"\nimport { IconButton, IconButtonProps } from \"./IconButton\"\n\n/**\n * An icon-only button that toggles a dropdown menu or popover. Appends a\n * caret suffix to the icon and wires up `aria-controls` and `aria-expanded`\n * to the controlled element. Requires an `aria-label` for accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/buttons-dropdown-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownIconButton = forwardRef<\n HTMLButtonElement,\n IconButtonProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <IconButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownIconButton.displayName = \"DropdownIconButton\"\n"],"names":[],"mappings":";;;;;AAMA
|
|
1
|
+
{"version":3,"file":"DropdownIconButton.js","sources":["../../../src/components/button/DropdownIconButton.tsx"],"sourcesContent":["import { DropdownTriggerContext } from \"@components/dropdown/DropdownTriggerContext\"\nimport React, { forwardRef, useContext } from \"react\"\n\nimport { DropdownButtonProps, dropdownProps } from \"./DropdownButton\"\nimport { IconButton, IconButtonProps } from \"./IconButton\"\n\n/**\n * An icon-only button that toggles a dropdown menu or popover. Appends a\n * caret suffix to the icon and wires up `aria-controls` and `aria-expanded`\n * to the controlled element. Requires an `aria-label` or `tooltip` for\n * accessibility.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/buttons-dropdown-icon-button--docs | Storybook Documentation}\n * @see {@link https://github.com/planningcenter/tapestry/tree/main/packages/tapestry-migration-cli | Migration CLI: Available}\n */\nexport const DropdownIconButton = forwardRef<\n HTMLButtonElement,\n IconButtonProps & DropdownButtonProps\n>((props, ref) => {\n const contextProps = useContext(DropdownTriggerContext)\n return (\n <IconButton\n ref={ref}\n {...props}\n {...contextProps}\n {...dropdownProps(props)}\n />\n )\n})\n\nDropdownIconButton.displayName = \"DropdownIconButton\"\n"],"names":[],"mappings":";;;;;AAMA;;;;;;;;;AASG;AACI,MAAM,kBAAkB,GAAG,UAAU,CAG1C,CAAC,KAAK,EAAE,GAAG,KAAI;AACf,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC,sBAAsB,CAAC;AACvD,IAAA,QACE,KAAA,CAAA,aAAA,CAAC,UAAU,IACT,GAAG,EAAE,GAAG,EAAA,GACJ,KAAK,EAAA,GACL,YAAY,KACZ,aAAa,CAAC,KAAK,CAAC,EAAA,CACxB;AAEN,CAAC;AAED,kBAAkB,CAAC,WAAW,GAAG,oBAAoB;;;;"}
|