@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.
Files changed (195) hide show
  1. package/dist/components/DataTable/CollectionEditorsLazy.js +2 -1
  2. package/dist/components/DataTable/CollectionEditorsLazy.js.map +1 -1
  3. package/dist/components/DataTable/DataTable.d.ts +49 -14
  4. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  5. package/dist/components/DataTable/DataTable.js +32 -24
  6. package/dist/components/DataTable/DataTable.js.map +1 -1
  7. package/dist/components/DataTable/DeleteSavedViewAlertDialog.d.ts +14 -0
  8. package/dist/components/DataTable/DeleteSavedViewAlertDialog.d.ts.map +1 -0
  9. package/dist/components/DataTable/DeleteSavedViewAlertDialog.js +10 -0
  10. package/dist/components/DataTable/DeleteSavedViewAlertDialog.js.map +1 -0
  11. package/dist/components/DataTable/ManageSavedViewsButton.d.ts +4 -1
  12. package/dist/components/DataTable/ManageSavedViewsButton.d.ts.map +1 -1
  13. package/dist/components/DataTable/ManageSavedViewsButton.js +3 -7
  14. package/dist/components/DataTable/ManageSavedViewsButton.js.map +1 -1
  15. package/dist/components/DataTable/ManageSavedViewsModal.d.ts +11 -1
  16. package/dist/components/DataTable/ManageSavedViewsModal.d.ts.map +1 -1
  17. package/dist/components/DataTable/ManageSavedViewsModal.js +265 -5
  18. package/dist/components/DataTable/ManageSavedViewsModal.js.map +1 -1
  19. package/dist/components/DataTable/ManageSavedViewsModal.module.css.js +4 -0
  20. package/dist/components/DataTable/ManageSavedViewsModal.module.css.js.map +1 -0
  21. package/dist/components/DataTable/NewSavedViewModal.d.ts +4 -1
  22. package/dist/components/DataTable/NewSavedViewModal.d.ts.map +1 -1
  23. package/dist/components/DataTable/NewSavedViewModal.js.map +1 -1
  24. package/dist/components/DataTable/ResultsCount.d.ts +9 -0
  25. package/dist/components/DataTable/ResultsCount.d.ts.map +1 -1
  26. package/dist/components/DataTable/ResultsCount.js +1 -1
  27. package/dist/components/DataTable/ResultsCount.js.map +1 -1
  28. package/dist/components/DataTable/SavedViewsBar.d.ts +14 -6
  29. package/dist/components/DataTable/SavedViewsBar.d.ts.map +1 -1
  30. package/dist/components/DataTable/SavedViewsBar.js +176 -45
  31. package/dist/components/DataTable/SavedViewsBar.js.map +1 -1
  32. package/dist/components/DataTable/TableActions.d.ts.map +1 -1
  33. package/dist/components/DataTable/TableActions.js +4 -6
  34. package/dist/components/DataTable/TableActions.js.map +1 -1
  35. package/dist/components/DataTable/ViewSettingsToggle.d.ts.map +1 -1
  36. package/dist/components/DataTable/ViewSettingsToggle.js +2 -4
  37. package/dist/components/DataTable/ViewSettingsToggle.js.map +1 -1
  38. package/dist/components/DataTable/index.d.ts +1 -1
  39. package/dist/components/DataTable/index.d.ts.map +1 -1
  40. package/dist/components/DataTable/savedViews.d.ts +40 -15
  41. package/dist/components/DataTable/savedViews.d.ts.map +1 -1
  42. package/dist/components/DataTable/savedViews.js +85 -6
  43. package/dist/components/DataTable/savedViews.js.map +1 -1
  44. package/dist/components/DataTable/useActiveSavedView.d.ts +1 -1
  45. package/dist/components/DataTable/useActiveSavedView.d.ts.map +1 -1
  46. package/dist/components/DataTable/useActiveSavedView.js +9 -3
  47. package/dist/components/DataTable/useActiveSavedView.js.map +1 -1
  48. package/dist/components/DataTable/useFilterAnnouncement.d.ts +24 -0
  49. package/dist/components/DataTable/useFilterAnnouncement.d.ts.map +1 -0
  50. package/dist/components/DataTable/useFilterAnnouncement.js +49 -0
  51. package/dist/components/DataTable/useFilterAnnouncement.js.map +1 -0
  52. package/dist/components/DataTable/useUpdateSavedViewName.d.ts +7 -0
  53. package/dist/components/DataTable/useUpdateSavedViewName.d.ts.map +1 -0
  54. package/dist/components/DataTable/useUpdateSavedViewName.js +12 -0
  55. package/dist/components/DataTable/useUpdateSavedViewName.js.map +1 -0
  56. package/dist/components/button/ActionsDropdownIconButton.d.ts +18 -9
  57. package/dist/components/button/ActionsDropdownIconButton.d.ts.map +1 -1
  58. package/dist/components/button/ActionsDropdownIconButton.js +5 -2
  59. package/dist/components/button/ActionsDropdownIconButton.js.map +1 -1
  60. package/dist/components/button/BaseButton.d.ts.map +1 -1
  61. package/dist/components/button/BaseButton.js +2 -1
  62. package/dist/components/button/BaseButton.js.map +1 -1
  63. package/dist/components/button/DropdownIconButton.d.ts +4 -5
  64. package/dist/components/button/DropdownIconButton.d.ts.map +1 -1
  65. package/dist/components/button/DropdownIconButton.js +2 -1
  66. package/dist/components/button/DropdownIconButton.js.map +1 -1
  67. package/dist/components/button/IconButton.d.ts +31 -10
  68. package/dist/components/button/IconButton.d.ts.map +1 -1
  69. package/dist/components/button/IconButton.js +8 -2
  70. package/dist/components/button/IconButton.js.map +1 -1
  71. package/dist/components/button/ToggleIconButton.d.ts +4 -1
  72. package/dist/components/button/ToggleIconButton.d.ts.map +1 -1
  73. package/dist/components/button/ToggleIconButton.js +1 -0
  74. package/dist/components/button/ToggleIconButton.js.map +1 -1
  75. package/dist/components/button/index.d.ts +1 -0
  76. package/dist/components/button/index.d.ts.map +1 -1
  77. package/dist/components/combo-box/ComboBox.d.ts +8 -0
  78. package/dist/components/combo-box/ComboBox.d.ts.map +1 -1
  79. package/dist/components/combo-box/ComboBox.js +31 -5
  80. package/dist/components/combo-box/ComboBox.js.map +1 -1
  81. package/dist/components/date-picker/DatePicker.d.ts.map +1 -1
  82. package/dist/components/date-picker/DatePicker.js +18 -14
  83. package/dist/components/date-picker/DatePicker.js.map +1 -1
  84. package/dist/components/internal/LoadingAnnouncement.d.ts +11 -0
  85. package/dist/components/internal/LoadingAnnouncement.d.ts.map +1 -0
  86. package/dist/components/internal/LoadingAnnouncement.js +21 -0
  87. package/dist/components/internal/LoadingAnnouncement.js.map +1 -0
  88. package/dist/components/internal/alert-dialog/AlertDialog.d.ts +56 -0
  89. package/dist/components/internal/alert-dialog/AlertDialog.d.ts.map +1 -0
  90. package/dist/components/internal/alert-dialog/AlertDialog.js +68 -0
  91. package/dist/components/internal/alert-dialog/AlertDialog.js.map +1 -0
  92. package/dist/components/internal/alert-dialog/index.d.ts +5 -0
  93. package/dist/components/internal/alert-dialog/index.d.ts.map +1 -0
  94. package/dist/components/internal/index.d.ts +1 -0
  95. package/dist/components/internal/index.d.ts.map +1 -1
  96. package/dist/components/internal/tooltip/Tooltip.d.ts +13 -5
  97. package/dist/components/internal/tooltip/Tooltip.d.ts.map +1 -1
  98. package/dist/components/internal/tooltip/Tooltip.js +63 -8
  99. package/dist/components/internal/tooltip/Tooltip.js.map +1 -1
  100. package/dist/components/internal/tooltip/TooltipTriggerContext.d.ts +3 -3
  101. package/dist/components/internal/tooltip/TooltipTriggerContext.d.ts.map +1 -1
  102. package/dist/components/internal/tooltip/TooltipTriggerContext.js +1 -1
  103. package/dist/components/internal/tooltip/TooltipTriggerContext.js.map +1 -1
  104. package/dist/components/internal/tooltip/index.d.ts +1 -1
  105. package/dist/components/internal/tooltip/index.d.ts.map +1 -1
  106. package/dist/components/link/BaseLink.d.ts.map +1 -1
  107. package/dist/components/link/BaseLink.js +15 -3
  108. package/dist/components/link/BaseLink.js.map +1 -1
  109. package/dist/components/link/IconLink.d.ts +28 -290
  110. package/dist/components/link/IconLink.d.ts.map +1 -1
  111. package/dist/components/link/IconLink.js +9 -2
  112. package/dist/components/link/IconLink.js.map +1 -1
  113. package/dist/components/page-header/defineElements.js +1 -1
  114. package/dist/components/pane/Pane.d.ts +1 -1
  115. package/dist/components/pane/Pane.js +1 -1
  116. package/dist/components/pane/Pane.js.map +1 -1
  117. package/dist/components/pane/PaneBody.d.ts +1 -1
  118. package/dist/components/pane/PaneBody.js +1 -1
  119. package/dist/components/pane/PaneBody.js.map +1 -1
  120. package/dist/components/pane/PaneDivider.d.ts +6 -3
  121. package/dist/components/pane/PaneDivider.d.ts.map +1 -1
  122. package/dist/components/pane/PaneDivider.js +3 -3
  123. package/dist/components/pane/PaneDivider.js.map +1 -1
  124. package/dist/components/pane/PaneFooter.d.ts +1 -1
  125. package/dist/components/pane/PaneFooter.js +1 -1
  126. package/dist/components/pane/PaneFooter.js.map +1 -1
  127. package/dist/components/pane/PaneHeader.d.ts +1 -1
  128. package/dist/components/pane/PaneHeader.js +1 -1
  129. package/dist/components/pane/PaneHeader.js.map +1 -1
  130. package/dist/components/pane/PaneHeaderActions.d.ts +1 -1
  131. package/dist/components/pane/PaneHeaderActions.js +1 -1
  132. package/dist/components/pane/PaneHeaderActions.js.map +1 -1
  133. package/dist/components/sidenav/defineElements.js +1 -1
  134. package/dist/components/time-field/TimeField.d.ts.map +1 -1
  135. package/dist/components/time-field/TimeField.js +7 -3
  136. package/dist/components/time-field/TimeField.js.map +1 -1
  137. package/dist/index.css +169 -27
  138. package/dist/index.css.map +1 -1
  139. package/dist/index.d.ts +1 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +6 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/packages/tapestry-wc/dist/components/{p-np7vhMVg.js → p-A1JK45WV.js} +3 -3
  144. package/dist/packages/tapestry-wc/dist/components/p-A1JK45WV.js.map +1 -0
  145. package/dist/packages/tapestry-wc/dist/components/{p-BVvtAaVT.js → p-BbuNAv9q.js} +3 -3
  146. package/dist/packages/tapestry-wc/dist/components/p-BbuNAv9q.js.map +1 -0
  147. package/dist/packages/tapestry-wc/dist/components/{p-B2xqMgNQ.js → p-CBFtMIxJ.js} +2 -2
  148. package/dist/packages/tapestry-wc/dist/components/p-CBFtMIxJ.js.map +1 -0
  149. package/dist/packages/tapestry-wc/dist/components/{p-Rn6lOB18.js → p-CY_DC4d_.js} +3 -3
  150. package/dist/packages/tapestry-wc/dist/components/p-CY_DC4d_.js.map +1 -0
  151. package/dist/packages/tapestry-wc/dist/components/{p-6NO22Vi_.js → p-DNHgMtxw.js} +2 -2
  152. package/dist/packages/tapestry-wc/dist/components/p-DNHgMtxw.js.map +1 -0
  153. package/dist/packages/tapestry-wc/dist/components/tds-page-header-nav.js +2 -2
  154. package/dist/packages/tapestry-wc/dist/components/tds-page-header-nav.js.map +1 -1
  155. package/dist/packages/tapestry-wc/dist/components/tds-page-header.js +3 -3
  156. package/dist/packages/tapestry-wc/dist/components/tds-page-header.js.map +1 -1
  157. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-item.js +3 -3
  158. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-item.js.map +1 -1
  159. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-responsive-header.js +2 -2
  160. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-responsive-header.js.map +1 -1
  161. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-section.js +3 -3
  162. package/dist/packages/tapestry-wc/dist/components/tds-sidenav-section.js.map +1 -1
  163. package/dist/packages/tapestry-wc/dist/components/tds-sidenav.js +5 -5
  164. package/dist/packages/tapestry-wc/dist/components/tds-sidenav.js.map +1 -1
  165. package/dist/reactRender.css +756 -574
  166. package/dist/reactRender.css.map +1 -1
  167. package/dist/reactRenderLegacy.css +756 -574
  168. package/dist/reactRenderLegacy.css.map +1 -1
  169. package/dist/tapestryMount.css +756 -574
  170. package/dist/tapestryMount.css.map +1 -1
  171. package/dist/tapestryMountLegacy.css +756 -574
  172. package/dist/tapestryMountLegacy.css.map +1 -1
  173. package/dist/unstable.css +309 -127
  174. package/dist/unstable.css.map +1 -1
  175. package/dist/unstable.d.ts +0 -1
  176. package/dist/unstable.d.ts.map +1 -1
  177. package/dist/unstable.js +6 -6
  178. package/dist/utilities/dateFieldLocale.d.ts +2 -0
  179. package/dist/utilities/dateFieldLocale.d.ts.map +1 -0
  180. package/dist/utilities/dateFieldLocale.js +32 -0
  181. package/dist/utilities/dateFieldLocale.js.map +1 -0
  182. package/dist/utilities/useAnnounce.d.ts +22 -0
  183. package/dist/utilities/useAnnounce.d.ts.map +1 -0
  184. package/dist/utilities/useAnnounce.js +27 -0
  185. package/dist/utilities/useAnnounce.js.map +1 -0
  186. package/dist/utilities/useDateFieldLocale.d.ts +2 -0
  187. package/dist/utilities/useDateFieldLocale.d.ts.map +1 -0
  188. package/dist/utilities/useDateFieldLocale.js +11 -0
  189. package/dist/utilities/useDateFieldLocale.js.map +1 -0
  190. package/package.json +4 -4
  191. package/dist/packages/tapestry-wc/dist/components/p-6NO22Vi_.js.map +0 -1
  192. package/dist/packages/tapestry-wc/dist/components/p-B2xqMgNQ.js.map +0 -1
  193. package/dist/packages/tapestry-wc/dist/components/p-BVvtAaVT.js.map +0 -1
  194. package/dist/packages/tapestry-wc/dist/components/p-Rn6lOB18.js.map +0 -1
  195. package/dist/packages/tapestry-wc/dist/components/p-np7vhMVg.js.map +0 -1
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ import type { SavedView } from "./savedViews";
3
+ export interface DeleteSavedViewAlertDialogProps {
4
+ onCancel: () => void;
5
+ onConfirm: () => void;
6
+ open: boolean;
7
+ /** Keep it set after closing, so the text holds during the exit animation. */
8
+ view: SavedView | null;
9
+ }
10
+ export declare function DeleteSavedViewAlertDialog({ onCancel, onConfirm, open, view, }: DeleteSavedViewAlertDialogProps): React.JSX.Element;
11
+ export declare namespace DeleteSavedViewAlertDialog {
12
+ var displayName: string;
13
+ }
14
+ //# sourceMappingURL=DeleteSavedViewAlertDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSavedViewAlertDialog.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/DeleteSavedViewAlertDialog.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,IAAI,EAAE,OAAO,CAAA;IACb,8EAA8E;IAC9E,IAAI,EAAE,SAAS,GAAG,IAAI,CAAA;CACvB;AAED,wBAAgB,0BAA0B,CAAC,EACzC,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,IAAI,GACL,EAAE,+BAA+B,qBAajC;yBAlBe,0BAA0B"}
@@ -0,0 +1,10 @@
1
+ import { AlertDialog } from '../internal/alert-dialog/AlertDialog.js';
2
+ import React__default from 'react';
3
+
4
+ function DeleteSavedViewAlertDialog({ onCancel, onConfirm, open, view, }) {
5
+ return (React__default.createElement(AlertDialog, { confirmButtonLabel: "Delete", open: open, title: "Delete view?", type: "danger", onCancel: onCancel, onConfirm: onConfirm }, `“${view?.name}” will be deleted. This can’t be undone.`));
6
+ }
7
+ DeleteSavedViewAlertDialog.displayName = "DeleteSavedViewAlertDialog";
8
+
9
+ export { DeleteSavedViewAlertDialog };
10
+ //# sourceMappingURL=DeleteSavedViewAlertDialog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteSavedViewAlertDialog.js","sources":["../../../src/components/DataTable/DeleteSavedViewAlertDialog.tsx"],"sourcesContent":["import { AlertDialog } from \"@components/internal/alert-dialog\"\nimport React from \"react\"\n\nimport type { SavedView } from \"./savedViews\"\n\nexport interface DeleteSavedViewAlertDialogProps {\n onCancel: () => void\n onConfirm: () => void\n open: boolean\n /** Keep it set after closing, so the text holds during the exit animation. */\n view: SavedView | null\n}\n\nexport function DeleteSavedViewAlertDialog({\n onCancel,\n onConfirm,\n open,\n view,\n}: DeleteSavedViewAlertDialogProps) {\n return (\n <AlertDialog\n confirmButtonLabel=\"Delete\"\n open={open}\n title=\"Delete view?\"\n type=\"danger\"\n onCancel={onCancel}\n onConfirm={onConfirm}\n >\n {`“${view?.name}” will be deleted. This can’t be undone.`}\n </AlertDialog>\n )\n}\n\nDeleteSavedViewAlertDialog.displayName = \"DeleteSavedViewAlertDialog\"\n"],"names":["React"],"mappings":";;;AAaM,SAAU,0BAA0B,CAAC,EACzC,QAAQ,EACR,SAAS,EACT,IAAI,EACJ,IAAI,GAC4B,EAAA;AAChC,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EACV,kBAAkB,EAAC,QAAQ,EAC3B,IAAI,EAAE,IAAI,EACV,KAAK,EAAC,cAAc,EACpB,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,EAAA,EAEnB,CAAA,CAAA,EAAI,IAAI,EAAE,IAAI,CAAA,wCAAA,CAA0C,CAC7C;AAElB;AAEA,0BAA0B,CAAC,WAAW,GAAG,4BAA4B;;;;"}
@@ -1,5 +1,8 @@
1
1
  import React from "react";
2
- export declare function ManageSavedViewsButton(): React.JSX.Element;
2
+ export interface ManageSavedViewsButtonProps {
3
+ onClick: () => void;
4
+ }
5
+ export declare function ManageSavedViewsButton({ onClick, }: ManageSavedViewsButtonProps): React.JSX.Element;
3
6
  export declare namespace ManageSavedViewsButton {
4
7
  var displayName: string;
5
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ManageSavedViewsButton.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ManageSavedViewsButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAIvC,wBAAgB,sBAAsB,sBAarC;yBAbe,sBAAsB"}
1
+ {"version":3,"file":"ManageSavedViewsButton.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ManageSavedViewsButton.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,wBAAgB,sBAAsB,CAAC,EACrC,OAAO,GACR,EAAE,2BAA2B,qBAQ7B;yBAVe,sBAAsB"}
@@ -5,14 +5,10 @@ import '../button/DropdownIconButton.js';
5
5
  import '../button/IconButton.js';
6
6
  import '../button/LoadingButton.js';
7
7
  import '../button/PageHeaderActionsDropdownButton.js';
8
- import React__default, { useState } from 'react';
9
- import { ManageSavedViewsModal } from './ManageSavedViewsModal.js';
8
+ import React__default from 'react';
10
9
 
11
- function ManageSavedViewsButton() {
12
- const [open, setOpen] = useState(false);
13
- return (React__default.createElement(React__default.Fragment, null,
14
- React__default.createElement(Button, { className: "tds-btn--data-table-saved-views-manage-views", label: "Manage views", onClick: () => setOpen(true) }),
15
- React__default.createElement(ManageSavedViewsModal, { open: open, onClose: () => setOpen(false) })));
10
+ function ManageSavedViewsButton({ onClick, }) {
11
+ return (React__default.createElement(Button, { className: "tds-btn--data-table-saved-views-manage-views", label: "Manage views", onClick: onClick }));
16
12
  }
17
13
  ManageSavedViewsButton.displayName = "ManageSavedViewsButton";
18
14
 
@@ -1 +1 @@
1
- {"version":3,"file":"ManageSavedViewsButton.js","sources":["../../../src/components/DataTable/ManageSavedViewsButton.tsx"],"sourcesContent":["import { Button } from \"@components/button\"\nimport React, { useState } from \"react\"\n\nimport { ManageSavedViewsModal } from \"./ManageSavedViewsModal\"\n\nexport function ManageSavedViewsButton() {\n const [open, setOpen] = useState(false)\n\n return (\n <>\n <Button\n className=\"tds-btn--data-table-saved-views-manage-views\"\n label=\"Manage views\"\n onClick={() => setOpen(true)}\n />\n <ManageSavedViewsModal open={open} onClose={() => setOpen(false)} />\n </>\n )\n}\n\nManageSavedViewsButton.displayName = \"ManageSavedViewsButton\"\n"],"names":["React"],"mappings":";;;;;;;;;;SAKgB,sBAAsB,GAAA;IACpC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AAEvC,IAAA,QACEA,cAAA,CAAA,aAAA,CAAAA,cAAA,CAAA,QAAA,EAAA,IAAA;AACE,QAAAA,cAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EACL,SAAS,EAAC,8CAA8C,EACxD,KAAK,EAAC,cAAc,EACpB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAAA,CAC5B;AACF,QAAAA,cAAA,CAAA,aAAA,CAAC,qBAAqB,EAAA,EAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,EAAA,CAAI,CACnE;AAEP;AAEA,sBAAsB,CAAC,WAAW,GAAG,wBAAwB;;;;"}
1
+ {"version":3,"file":"ManageSavedViewsButton.js","sources":["../../../src/components/DataTable/ManageSavedViewsButton.tsx"],"sourcesContent":["import { Button } from \"@components/button\"\nimport React from \"react\"\n\nexport interface ManageSavedViewsButtonProps {\n onClick: () => void\n}\n\nexport function ManageSavedViewsButton({\n onClick,\n}: ManageSavedViewsButtonProps) {\n return (\n <Button\n className=\"tds-btn--data-table-saved-views-manage-views\"\n label=\"Manage views\"\n onClick={onClick}\n />\n )\n}\n\nManageSavedViewsButton.displayName = \"ManageSavedViewsButton\"\n"],"names":["React"],"mappings":";;;;;;;;;AAOM,SAAU,sBAAsB,CAAC,EACrC,OAAO,GACqB,EAAA;AAC5B,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EACL,SAAS,EAAC,8CAA8C,EACxD,KAAK,EAAC,cAAc,EACpB,OAAO,EAAE,OAAO,EAAA,CAChB;AAEN;AAEA,sBAAsB,CAAC,WAAW,GAAG,wBAAwB;;;;"}
@@ -1,9 +1,19 @@
1
1
  import React from "react";
2
+ import { type SavedView, type StaticView } from "./savedViews";
2
3
  export interface ManageSavedViewsModalProps {
4
+ defaultViewId: NonNullable<SavedView["id"]>;
3
5
  onClose: () => void;
6
+ /** Called once the user confirms. Omit to leave out the delete buttons. */
7
+ onDelete?: (savedView: SavedView) => void;
8
+ /** Omit to leave out the default view buttons. */
9
+ onSetDefault?: (id: NonNullable<SavedView["id"]>) => void;
10
+ onUpdate?: (savedView: SavedView) => Promise<SavedView> | SavedView;
4
11
  open: boolean;
12
+ savedViews: SavedView[];
13
+ /** Listed by name before `savedViews`, since they can't be renamed. */
14
+ staticViews: StaticView[];
5
15
  }
6
- export declare function ManageSavedViewsModal({ onClose, open, }: ManageSavedViewsModalProps): React.JSX.Element;
16
+ export declare function ManageSavedViewsModal({ defaultViewId, onClose, onDelete, onSetDefault, onUpdate, open, savedViews, staticViews, }: ManageSavedViewsModalProps): React.JSX.Element;
7
17
  export declare namespace ManageSavedViewsModal {
8
18
  var displayName: string;
9
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ManageSavedViewsModal.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ManageSavedViewsModal.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,IAAI,EAAE,OAAO,CAAA;CACd;AAED,wBAAgB,qBAAqB,CAAC,EACpC,OAAO,EACP,IAAI,GACL,EAAE,0BAA0B,qBAU5B;yBAbe,qBAAqB"}
1
+ {"version":3,"file":"ManageSavedViewsModal.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ManageSavedViewsModal.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAsD,MAAM,OAAO,CAAA;AA8B1E,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,UAAU,EAChB,MAAM,cAAc,CAAA;AAGrB,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAA;IACzC,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,WAAW,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;IACzD,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAA;IACnE,IAAI,EAAE,OAAO,CAAA;IACb,UAAU,EAAE,SAAS,EAAE,CAAA;IACvB,uEAAuE;IACvE,WAAW,EAAE,UAAU,EAAE,CAAA;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,aAAa,EACb,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,WAAW,GACZ,EAAE,0BAA0B,qBA2F5B;yBApGe,qBAAqB"}
@@ -2,23 +2,283 @@ import '../button/ActionsDropdownIconButton.js';
2
2
  import { Button } from '../button/Button.js';
3
3
  import '../button/DropdownButton.js';
4
4
  import '../button/DropdownIconButton.js';
5
- import '../button/IconButton.js';
5
+ import { IconButton } from '../button/IconButton.js';
6
6
  import '../button/LoadingButton.js';
7
7
  import '../button/PageHeaderActionsDropdownButton.js';
8
+ import { ToggleIconButton } from '../button/ToggleIconButton.js';
9
+ import { Input } from '../input/Input.js';
8
10
  import { Modal } from '../modal/Modal.js';
9
11
  import { ModalBody } from '../modal/ModalBody.js';
10
12
  import { ModalFooter } from '../modal/ModalFooter.js';
11
13
  import { ModalHeader } from '../modal/ModalHeader.js';
12
- import React__default from 'react';
14
+ import Icon from '../../utilities/Icon.js';
15
+ import React__default, { useState, useRef, useEffect } from 'react';
16
+ import { ListDropTargetDelegate } from 'react-aria/ListDropTargetDelegate';
17
+ import { ListKeyboardDelegate } from 'react-aria/ListKeyboardDelegate';
18
+ import { mergeProps } from 'react-aria/mergeProps';
19
+ import { useButton } from 'react-aria/useButton';
20
+ import { useDraggableCollection, useDraggableItem } from 'react-aria/useDraggableCollection';
21
+ import { useDroppableCollection, useDropIndicator } from 'react-aria/useDroppableCollection';
22
+ import { useVisuallyHidden } from 'react-aria/VisuallyHidden';
23
+ import { Item } from 'react-stately/Item';
24
+ import { useDraggableCollectionState } from 'react-stately/useDraggableCollectionState';
25
+ import { useDroppableCollectionState } from 'react-stately/useDroppableCollectionState';
26
+ import { useListState } from 'react-stately/useListState';
27
+ import { DeleteSavedViewAlertDialog } from './DeleteSavedViewAlertDialog.js';
28
+ import styles from './ManageSavedViewsModal.module.css.js';
29
+ import { savedViewUpdatesForReorder } from './savedViews.js';
30
+ import { useUpdateSavedViewName } from './useUpdateSavedViewName.js';
13
31
 
14
- function ManageSavedViewsModal({ onClose, open, }) {
32
+ function ManageSavedViewsModal({ defaultViewId, onClose, onDelete, onSetDefault, onUpdate, open, savedViews, staticViews, }) {
33
+ const updateSavedViewName = useUpdateSavedViewName(onUpdate);
34
+ // Kept after the alert closes, so its text holds during the exit animation.
35
+ const [viewToDelete, setViewToDelete] = useState(null);
36
+ const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false);
37
+ // Without this, focus would go to the modal's close button, since the
38
+ // alert returns it to the delete button, which is gone with its row.
39
+ const { doneButtonRef, focusAfterDelete, listRef } = useFocusAfterDelete(savedViews, isDeleteAlertOpen);
40
+ const requestDelete = (view) => {
41
+ setViewToDelete(view);
42
+ setIsDeleteAlertOpen(true);
43
+ };
44
+ // Deleting the default view hands the default back to "initial".
45
+ const confirmDelete = () => {
46
+ if (viewToDelete) {
47
+ focusAfterDelete(viewToDelete);
48
+ onDelete?.(viewToDelete);
49
+ if (viewToDelete.id === defaultViewId)
50
+ onSetDefault?.("initial");
51
+ }
52
+ setIsDeleteAlertOpen(false);
53
+ };
54
+ // The default is matched by id, so an unsaved view can't be made the
55
+ // default. Unsetting the default hands it back to "initial".
56
+ const renderDefaultViewToggle = ({ id, name }) => onSetDefault && id !== undefined ? (React__default.createElement(DefaultViewToggle, { isDefault: id === defaultViewId, name: name, onChange: (isDefault) => onSetDefault(isDefault ? id : "initial") })) : null;
15
57
  return (React__default.createElement(Modal, { dismissible: true, open: open, onClose: onClose },
16
58
  React__default.createElement(ModalHeader, { title: "Manage views" }),
17
- React__default.createElement(ModalBody, null, null),
59
+ React__default.createElement(ModalBody, null,
60
+ React__default.createElement(SavedViewsList, { listRef: listRef, renderStaticViewActions: (view) => (React__default.createElement(React__default.Fragment, null,
61
+ renderDefaultViewToggle(view),
62
+ onDelete && React__default.createElement(DeleteViewButton, { disabled: true, name: view.name }))), savedViews: savedViews, staticViews: staticViews, onUpdate: onUpdate }, (view) => (React__default.createElement(SavedViewRow, { defaultViewToggle: renderDefaultViewToggle(view), hasDeleteButton: Boolean(onDelete),
63
+ // Updates and deletes are matched by id, so an unsaved view
64
+ // can't be renamed or deleted.
65
+ readOnly: !onUpdate || view.id === undefined, view: view, onDelete: onDelete && view.id !== undefined
66
+ ? (name) => requestDelete({ ...view, name })
67
+ : undefined, onRename: (name) => updateSavedViewName(view, name) })))),
18
68
  React__default.createElement(ModalFooter, null,
19
- React__default.createElement(Button, { kind: "primary", label: "Done", onClick: onClose }))));
69
+ React__default.createElement(Button, { ref: doneButtonRef, kind: "primary", label: "Done", onClick: onClose })),
70
+ onDelete && (React__default.createElement(DeleteSavedViewAlertDialog, { open: isDeleteAlertOpen, view: viewToDelete, onCancel: () => setIsDeleteAlertOpen(false), onConfirm: confirmDelete }))));
20
71
  }
21
72
  ManageSavedViewsModal.displayName = "ManageSavedViewsModal";
73
+ /**
74
+ * The static views, then the saved views with drag handles. Mounts with the
75
+ * modal's content, since React Aria registers the list as a drop target when
76
+ * its hooks mount, and the modal stays mounted while closed.
77
+ */
78
+ function SavedViewsList({ children, listRef, onUpdate, renderStaticViewActions, savedViews, staticViews, }) {
79
+ const { collectionProps, dragState, dropState } = useSavedViewsDragAndDrop(savedViews, listRef, onUpdate);
80
+ return (React__default.createElement("ol", { ref: listRef, ...collectionProps, className: styles["views-list"] },
81
+ staticViews.map((view) => (React__default.createElement("li", { key: view.id, className: styles["views-list-item--static"] },
82
+ React__default.createElement("span", { className: styles["view-list-item-static-name"] }, view.name),
83
+ renderStaticViewActions(view)))),
84
+ savedViews.map((view, index) => {
85
+ const key = savedViewKey(view, index);
86
+ return (React__default.createElement("li", { key: key, className: styles["views-list-item"], "data-dragging": dragState.isDragging(key) || undefined, "data-key": key },
87
+ React__default.createElement(SavedViewDropIndicator, { dropState: dropState, target: { dropPosition: "before", key, type: "item" } }),
88
+ savedViews.length > 1 && onUpdate && view.id !== undefined && (React__default.createElement(SavedViewDragHandle, { dragState: dragState, itemKey: key, name: view.name })),
89
+ children(view),
90
+ index === savedViews.length - 1 && (React__default.createElement(SavedViewDropIndicator, { dropState: dropState, target: { dropPosition: "after", key, type: "item" } }))));
91
+ })));
92
+ }
93
+ /** A string, since React Aria's collection keys an `Item` by its React key. */
94
+ function savedViewKey(view, index) {
95
+ return String(view.id ?? `unsaved-view-${index}`);
96
+ }
97
+ /**
98
+ * Drag and drop for the saved views' rows, which React Aria finds by their
99
+ * `data-key`. A drop sends the views with new sort keys to `onUpdate`, and
100
+ * the row moves once they're passed back in.
101
+ */
102
+ function useSavedViewsDragAndDrop(savedViews, listRef, onUpdate) {
103
+ const { collection, selectionManager } = useListState({
104
+ children: savedViews.map((view, index) => (React__default.createElement(Item, { key: savedViewKey(view, index), textValue: view.name }, view.name))),
105
+ selectionMode: "none",
106
+ });
107
+ const dragState = useDraggableCollectionState({
108
+ collection,
109
+ getItems: (keys) => [...keys].map((key) => ({
110
+ "text/plain": collection.getItem(key)?.textValue ?? String(key),
111
+ })),
112
+ // A drop removes the drop target that had focus, and rows can't take
113
+ // focus, so it goes back to the handle that started the drag.
114
+ onDragEnd: ({ keys }) => {
115
+ const [key] = keys;
116
+ listRef.current
117
+ ?.querySelector(`[data-key="${CSS.escape(String(key))}"] .${styles["view-list-item-drag-handle"]}`)
118
+ ?.focus();
119
+ },
120
+ // A keyboard drag starts after the focused row, which the rows can't
121
+ // set themselves, since they can't take focus.
122
+ onDragStart: ({ keys }) => {
123
+ const [key] = keys;
124
+ selectionManager.setFocusedKey(key);
125
+ },
126
+ selectionManager,
127
+ });
128
+ useDraggableCollection({}, dragState, listRef);
129
+ const onReorder = ({ keys, target }) => {
130
+ const indexOf = (key) => savedViews.findIndex((view, index) => savedViewKey(view, index) === key);
131
+ // Rows only offer drop targets between them, not on them.
132
+ if (target.dropPosition === "on")
133
+ return;
134
+ const [key] = keys;
135
+ const updates = savedViewUpdatesForReorder(savedViews, indexOf(key), indexOf(target.key), target.dropPosition);
136
+ // Updates are matched by id, so a reorder that needs to update an unsaved
137
+ // view can't be saved in full. Saving part of it would leave the order
138
+ // unchanged anyway.
139
+ if (updates.some((view) => view.id === undefined))
140
+ return;
141
+ for (const view of updates)
142
+ onUpdate?.(view);
143
+ };
144
+ const dropState = useDroppableCollectionState({
145
+ collection,
146
+ onReorder,
147
+ selectionManager,
148
+ });
149
+ const { collectionProps } = useDroppableCollection({
150
+ dropTargetDelegate: new ListDropTargetDelegate(collection, listRef),
151
+ keyboardDelegate: new ListKeyboardDelegate({ collection, ref: listRef }),
152
+ onReorder,
153
+ }, dropState, listRef);
154
+ return { collectionProps, dragState, dropState };
155
+ }
156
+ /**
157
+ * Starts a drag with a pointer, or with Enter or Space. A pointer drag shows
158
+ * the whole row, held where the pointer grabbed it, rather than the handle.
159
+ */
160
+ function SavedViewDragHandle({ dragState, itemKey, name, }) {
161
+ const ref = useRef(null);
162
+ const { dragButtonProps, dragProps } = useDraggableItem({ hasDragButton: true, key: itemKey }, dragState);
163
+ const { buttonProps } = useButton(dragButtonProps, ref);
164
+ return (React__default.createElement(IconButton, { ref: ref, ...mergeProps(buttonProps, dragProps, {
165
+ onDragStart: (event) => {
166
+ const row = event.currentTarget.closest("li");
167
+ if (!row)
168
+ return;
169
+ const { left, top } = row.getBoundingClientRect();
170
+ // The browser snapshots the row once this handler returns, so the
171
+ // ghost styles apply only to the snapshot.
172
+ const className = styles["views-list-item--drag-ghost"];
173
+ row.classList.add(className);
174
+ requestAnimationFrame(() => row.classList.remove(className));
175
+ event.dataTransfer.setDragImage(row, event.clientX - left, event.clientY - top);
176
+ },
177
+ }), "aria-label": `Reorder ${name}`, className: styles["view-list-item-drag-handle"], icon: React__default.createElement(Icon, { "aria-hidden": true, symbol: "general#drag-handle" }), kind: "ghost" }));
178
+ }
179
+ /**
180
+ * A line at a row's edge while dragging. Screen readers reach the hidden
181
+ * button inside it as a drop target.
182
+ */
183
+ function SavedViewDropIndicator({ dropState, target, }) {
184
+ const ref = useRef(null);
185
+ const { dropIndicatorProps, isDropTarget, isHidden } = useDropIndicator({ target }, dropState, ref);
186
+ const { visuallyHiddenProps } = useVisuallyHidden();
187
+ if (isHidden)
188
+ return null;
189
+ return (React__default.createElement("div", { className: styles["view-list-drop-indicator"], "data-drop-position": target.type === "item" ? target.dropPosition : undefined, "data-drop-target": isDropTarget || undefined },
190
+ React__default.createElement("div", { ...visuallyHiddenProps, role: "button", ...dropIndicatorProps, ref: ref })));
191
+ }
192
+ /**
193
+ * Moves focus off a deleted view's row in two steps: `focusAfterDelete` picks
194
+ * the target while the row is still there, and focus moves to it once the
195
+ * alert starts closing.
196
+ */
197
+ function useFocusAfterDelete(savedViews, isDeleteAlertOpen) {
198
+ const listRef = useRef(null);
199
+ const doneButtonRef = useRef(null);
200
+ const focusTargetRef = useRef(null);
201
+ // Step 1: the next view's row, or the previous one's if the deleted view is
202
+ // last, or Done if it's the only one.
203
+ const focusAfterDelete = (view) => {
204
+ const rows = listRef.current?.querySelectorAll(`.${styles["views-list-item"]}`) ?? [];
205
+ const index = savedViews.findIndex(({ id }) => id === view.id);
206
+ const row = rows[index + 1] ?? rows[index - 1];
207
+ // The row's last enabled button is its delete button, when it has one.
208
+ const buttons = row?.querySelectorAll(`button:not(.${styles["view-list-item-drag-handle"]}, :disabled)`);
209
+ focusTargetRef.current =
210
+ buttons?.[buttons.length - 1] ??
211
+ row?.querySelector("input") ??
212
+ doneButtonRef.current;
213
+ };
214
+ // Step 2: a closing alert no longer holds focus, and doesn't take it back
215
+ // once focus is outside it.
216
+ useEffect(() => {
217
+ if (isDeleteAlertOpen)
218
+ return;
219
+ focusTargetRef.current?.focus();
220
+ focusTargetRef.current = null;
221
+ }, [isDeleteAlertOpen]);
222
+ return { doneButtonRef, focusAfterDelete, listRef };
223
+ }
224
+ /**
225
+ * A saved view's name field, default view toggle, and delete button. Renames on blur or Enter. An
226
+ * empty name reverts to the current one. Tracks the last name it sent, so
227
+ * Enter followed by blur renames once. Deleting sends a pending rename first,
228
+ * then passes along the name, so the alert shows what the field does.
229
+ */
230
+ function SavedViewRow({ defaultViewToggle, hasDeleteButton, onDelete, onRename, readOnly, view, }) {
231
+ const [name, setName] = useState(view.name);
232
+ const committedName = useRef(view.name);
233
+ // Picks up names changed outside this field, including once a rename saves,
234
+ // unless the field has newer edits, which its next blur or Enter sends.
235
+ useEffect(() => {
236
+ const previousName = committedName.current;
237
+ committedName.current = view.name;
238
+ setName((currentName) => currentName === previousName ? view.name : currentName);
239
+ }, [view.name]);
240
+ const commit = () => {
241
+ const trimmedName = name.trim();
242
+ if (!trimmedName) {
243
+ setName(committedName.current);
244
+ return;
245
+ }
246
+ setName(trimmedName);
247
+ if (trimmedName === committedName.current)
248
+ return;
249
+ committedName.current = trimmedName;
250
+ onRename(trimmedName);
251
+ };
252
+ return (React__default.createElement(React__default.Fragment, null,
253
+ React__default.createElement(Input, { autoComplete: "off", className: styles["view-list-item-input"], hideLabel: true, label: `Name for ${view.name}`, readOnly: readOnly, required: !readOnly, value: name, onBlur: readOnly ? undefined : commit, onChange: (event) => setName(event.target.value), onKeyDown: (event) => {
254
+ if (!readOnly &&
255
+ event.key === "Enter" &&
256
+ !event.repeat &&
257
+ !event.nativeEvent.isComposing) {
258
+ commit();
259
+ }
260
+ } }),
261
+ defaultViewToggle,
262
+ hasDeleteButton && (React__default.createElement(DeleteViewButton, { disabled: !onDelete, name: view.name, onClick: (event) => {
263
+ // Safari doesn't focus a button on click, and the alert returns
264
+ // focus to whatever had it when it opened. Focusing also blurs
265
+ // the field, which sends a pending rename.
266
+ event.currentTarget.focus();
267
+ onDelete?.(committedName.current);
268
+ } }))));
269
+ }
270
+ function DeleteViewButton({ disabled, name, onClick, }) {
271
+ return (React__default.createElement(IconButton, { "aria-label": `Delete ${name}`, disabled: disabled, icon: React__default.createElement(Icon, { "aria-hidden": true, symbol: "general#trash" }), kind: "ghost", tooltip: "Delete", onClick: onClick }));
272
+ }
273
+ /** Makes a view the default, or hands the default back to "initial". */
274
+ function DefaultViewToggle({ isDefault, name, onChange, }) {
275
+ return (React__default.createElement(ToggleIconButton
276
+ // Only one view is the default, so its label doesn't need the view's
277
+ // name to be unique.
278
+ , { "aria-label": isDefault ? "Default view" : `Set ${name} as default`, icon: React__default.createElement(Icon, { "aria-hidden": true, symbol: isDefault ? "general#pin" : "general#outlined-pin" }),
279
+ // Only the default's pin is blue.
280
+ kind: isDefault ? "ghost-interaction" : "ghost", pressed: isDefault, tooltip: isDefault ? "Default view" : "Set as default", onChange: onChange }));
281
+ }
22
282
 
23
283
  export { ManageSavedViewsModal };
24
284
  //# sourceMappingURL=ManageSavedViewsModal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ManageSavedViewsModal.js","sources":["../../../src/components/DataTable/ManageSavedViewsModal.tsx"],"sourcesContent":["import { Button } from \"@components/button\"\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from \"@components/modal\"\nimport React from \"react\"\n\nexport interface ManageSavedViewsModalProps {\n onClose: () => void\n open: boolean\n}\n\nexport function ManageSavedViewsModal({\n onClose,\n open,\n}: ManageSavedViewsModalProps) {\n return (\n <Modal dismissible open={open} onClose={onClose}>\n <ModalHeader title=\"Manage views\" />\n <ModalBody>{null}</ModalBody>\n <ModalFooter>\n <Button kind=\"primary\" label=\"Done\" onClick={onClose} />\n </ModalFooter>\n </Modal>\n )\n}\n\nManageSavedViewsModal.displayName = \"ManageSavedViewsModal\"\n"],"names":["React"],"mappings":";;;;;;;;;;;;;SASgB,qBAAqB,CAAC,EACpC,OAAO,EACP,IAAI,GACuB,EAAA;AAC3B,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,KAAK,EAAA,EAAC,WAAW,EAAA,IAAA,EAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAA;AAC7C,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAC,KAAK,EAAC,cAAc,EAAA,CAAG;QACpCA,cAAA,CAAA,aAAA,CAAC,SAAS,EAAA,IAAA,EAAE,IAAI,CAAa;AAC7B,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,IAAA;AACV,YAAAA,cAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EAAC,IAAI,EAAC,SAAS,EAAC,KAAK,EAAC,MAAM,EAAC,OAAO,EAAE,OAAO,GAAI,CAC5C,CACR;AAEZ;AAEA,qBAAqB,CAAC,WAAW,GAAG,uBAAuB;;;;"}
1
+ {"version":3,"file":"ManageSavedViewsModal.js","sources":["../../../src/components/DataTable/ManageSavedViewsModal.tsx"],"sourcesContent":["import { Button, IconButton } from \"@components/button\"\nimport { ToggleIconButton } from \"@components/button/ToggleIconButton\"\nimport { Input } from \"@components/input\"\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from \"@components/modal\"\nimport Icon from \"@utilities/Icon\"\nimport React, { type ReactNode, useEffect, useRef, useState } from \"react\"\nimport { ListDropTargetDelegate } from \"react-aria/ListDropTargetDelegate\"\nimport { ListKeyboardDelegate } from \"react-aria/ListKeyboardDelegate\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { useButton } from \"react-aria/useButton\"\nimport {\n useDraggableCollection,\n useDraggableItem,\n} from \"react-aria/useDraggableCollection\"\nimport {\n type DroppableCollectionReorderEvent,\n type DropTarget,\n useDropIndicator,\n useDroppableCollection,\n} from \"react-aria/useDroppableCollection\"\nimport { useVisuallyHidden } from \"react-aria/VisuallyHidden\"\nimport type { Key } from \"react-aria-components/ListBox\"\nimport { Item } from \"react-stately/Item\"\nimport {\n type DraggableCollectionState,\n useDraggableCollectionState,\n} from \"react-stately/useDraggableCollectionState\"\nimport {\n type DroppableCollectionState,\n useDroppableCollectionState,\n} from \"react-stately/useDroppableCollectionState\"\nimport { useListState } from \"react-stately/useListState\"\n\nimport { DeleteSavedViewAlertDialog } from \"./DeleteSavedViewAlertDialog\"\nimport styles from \"./ManageSavedViewsModal.module.css\"\nimport {\n type SavedView,\n savedViewUpdatesForReorder,\n type StaticView,\n} from \"./savedViews\"\nimport { useUpdateSavedViewName } from \"./useUpdateSavedViewName\"\n\nexport interface ManageSavedViewsModalProps {\n defaultViewId: NonNullable<SavedView[\"id\"]>\n onClose: () => void\n /** Called once the user confirms. Omit to leave out the delete buttons. */\n onDelete?: (savedView: SavedView) => void\n /** Omit to leave out the default view buttons. */\n onSetDefault?: (id: NonNullable<SavedView[\"id\"]>) => void\n onUpdate?: (savedView: SavedView) => Promise<SavedView> | SavedView\n open: boolean\n savedViews: SavedView[]\n /** Listed by name before `savedViews`, since they can't be renamed. */\n staticViews: StaticView[]\n}\n\nexport function ManageSavedViewsModal({\n defaultViewId,\n onClose,\n onDelete,\n onSetDefault,\n onUpdate,\n open,\n savedViews,\n staticViews,\n}: ManageSavedViewsModalProps) {\n const updateSavedViewName = useUpdateSavedViewName(onUpdate)\n // Kept after the alert closes, so its text holds during the exit animation.\n const [viewToDelete, setViewToDelete] = useState<SavedView | null>(null)\n const [isDeleteAlertOpen, setIsDeleteAlertOpen] = useState(false)\n // Without this, focus would go to the modal's close button, since the\n // alert returns it to the delete button, which is gone with its row.\n const { doneButtonRef, focusAfterDelete, listRef } = useFocusAfterDelete(\n savedViews,\n isDeleteAlertOpen\n )\n\n const requestDelete = (view: SavedView) => {\n setViewToDelete(view)\n setIsDeleteAlertOpen(true)\n }\n\n // Deleting the default view hands the default back to \"initial\".\n const confirmDelete = () => {\n if (viewToDelete) {\n focusAfterDelete(viewToDelete)\n onDelete?.(viewToDelete)\n if (viewToDelete.id === defaultViewId) onSetDefault?.(\"initial\")\n }\n setIsDeleteAlertOpen(false)\n }\n\n // The default is matched by id, so an unsaved view can't be made the\n // default. Unsetting the default hands it back to \"initial\".\n const renderDefaultViewToggle = ({ id, name }: SavedView) =>\n onSetDefault && id !== undefined ? (\n <DefaultViewToggle\n isDefault={id === defaultViewId}\n name={name}\n onChange={(isDefault) => onSetDefault(isDefault ? id : \"initial\")}\n />\n ) : null\n\n return (\n <Modal dismissible open={open} onClose={onClose}>\n <ModalHeader title=\"Manage views\" />\n <ModalBody>\n <SavedViewsList\n listRef={listRef}\n renderStaticViewActions={(view) => (\n <>\n {renderDefaultViewToggle(view)}\n {/* Static views can't be deleted, but keep the column lined up. */}\n {onDelete && <DeleteViewButton disabled name={view.name} />}\n </>\n )}\n savedViews={savedViews}\n staticViews={staticViews}\n onUpdate={onUpdate}\n >\n {(view) => (\n <SavedViewRow\n defaultViewToggle={renderDefaultViewToggle(view)}\n hasDeleteButton={Boolean(onDelete)}\n // Updates and deletes are matched by id, so an unsaved view\n // can't be renamed or deleted.\n readOnly={!onUpdate || view.id === undefined}\n view={view}\n onDelete={\n onDelete && view.id !== undefined\n ? (name) => requestDelete({ ...view, name })\n : undefined\n }\n onRename={(name) => updateSavedViewName(view, name)}\n />\n )}\n </SavedViewsList>\n </ModalBody>\n <ModalFooter>\n <Button\n ref={doneButtonRef}\n kind=\"primary\"\n label=\"Done\"\n onClick={onClose}\n />\n </ModalFooter>\n {onDelete && (\n <DeleteSavedViewAlertDialog\n open={isDeleteAlertOpen}\n view={viewToDelete}\n onCancel={() => setIsDeleteAlertOpen(false)}\n onConfirm={confirmDelete}\n />\n )}\n </Modal>\n )\n}\n\nManageSavedViewsModal.displayName = \"ManageSavedViewsModal\"\n\n/**\n * The static views, then the saved views with drag handles. Mounts with the\n * modal's content, since React Aria registers the list as a drop target when\n * its hooks mount, and the modal stays mounted while closed.\n */\nfunction SavedViewsList({\n children,\n listRef,\n onUpdate,\n renderStaticViewActions,\n savedViews,\n staticViews,\n}: {\n children: (view: SavedView) => ReactNode\n listRef: React.RefObject<HTMLOListElement>\n onUpdate?: ManageSavedViewsModalProps[\"onUpdate\"]\n renderStaticViewActions: (view: StaticView) => ReactNode\n savedViews: SavedView[]\n staticViews: StaticView[]\n}) {\n const { collectionProps, dragState, dropState } = useSavedViewsDragAndDrop(\n savedViews,\n listRef,\n onUpdate\n )\n\n return (\n <ol ref={listRef} {...collectionProps} className={styles[\"views-list\"]}>\n {staticViews.map((view) => (\n <li key={view.id} className={styles[\"views-list-item--static\"]}>\n <span className={styles[\"view-list-item-static-name\"]}>\n {view.name}\n </span>\n {renderStaticViewActions(view)}\n </li>\n ))}\n {savedViews.map((view, index) => {\n const key = savedViewKey(view, index)\n return (\n <li\n key={key}\n className={styles[\"views-list-item\"]}\n data-dragging={dragState.isDragging(key) || undefined}\n data-key={key}\n >\n <SavedViewDropIndicator\n dropState={dropState}\n target={{ dropPosition: \"before\", key, type: \"item\" }}\n />\n {/* A single view has no order to change, and updates are matched\n by id, so an unsaved view can't be reordered. */}\n {savedViews.length > 1 && onUpdate && view.id !== undefined && (\n <SavedViewDragHandle\n dragState={dragState}\n itemKey={key}\n name={view.name}\n />\n )}\n {children(view)}\n {index === savedViews.length - 1 && (\n <SavedViewDropIndicator\n dropState={dropState}\n target={{ dropPosition: \"after\", key, type: \"item\" }}\n />\n )}\n </li>\n )\n })}\n </ol>\n )\n}\n\n/** A string, since React Aria's collection keys an `Item` by its React key. */\nfunction savedViewKey(view: SavedView, index: number): Key {\n return String(view.id ?? `unsaved-view-${index}`)\n}\n\n/**\n * Drag and drop for the saved views' rows, which React Aria finds by their\n * `data-key`. A drop sends the views with new sort keys to `onUpdate`, and\n * the row moves once they're passed back in.\n */\nfunction useSavedViewsDragAndDrop(\n savedViews: SavedView[],\n listRef: React.RefObject<HTMLOListElement | null>,\n onUpdate?: ManageSavedViewsModalProps[\"onUpdate\"]\n) {\n const { collection, selectionManager } = useListState({\n children: savedViews.map((view, index) => (\n <Item key={savedViewKey(view, index)} textValue={view.name}>\n {view.name}\n </Item>\n )),\n selectionMode: \"none\",\n })\n\n const dragState = useDraggableCollectionState({\n collection,\n getItems: (keys) =>\n [...keys].map((key) => ({\n \"text/plain\": collection.getItem(key)?.textValue ?? String(key),\n })),\n\n // A drop removes the drop target that had focus, and rows can't take\n // focus, so it goes back to the handle that started the drag.\n onDragEnd: ({ keys }) => {\n const [key] = keys\n listRef.current\n ?.querySelector<HTMLElement>(\n `[data-key=\"${CSS.escape(String(key))}\"] .${styles[\"view-list-item-drag-handle\"]}`\n )\n ?.focus()\n },\n\n // A keyboard drag starts after the focused row, which the rows can't\n // set themselves, since they can't take focus.\n onDragStart: ({ keys }) => {\n const [key] = keys\n selectionManager.setFocusedKey(key)\n },\n selectionManager,\n })\n useDraggableCollection({}, dragState, listRef)\n\n const onReorder = ({ keys, target }: DroppableCollectionReorderEvent) => {\n const indexOf = (key: Key) =>\n savedViews.findIndex((view, index) => savedViewKey(view, index) === key)\n // Rows only offer drop targets between them, not on them.\n if (target.dropPosition === \"on\") return\n const [key] = keys\n const updates = savedViewUpdatesForReorder(\n savedViews,\n indexOf(key),\n indexOf(target.key),\n target.dropPosition\n )\n // Updates are matched by id, so a reorder that needs to update an unsaved\n // view can't be saved in full. Saving part of it would leave the order\n // unchanged anyway.\n if (updates.some((view) => view.id === undefined)) return\n for (const view of updates) onUpdate?.(view)\n }\n const dropState = useDroppableCollectionState({\n collection,\n onReorder,\n selectionManager,\n })\n const { collectionProps } = useDroppableCollection(\n {\n dropTargetDelegate: new ListDropTargetDelegate(collection, listRef),\n keyboardDelegate: new ListKeyboardDelegate({ collection, ref: listRef }),\n onReorder,\n },\n dropState,\n listRef\n )\n\n return { collectionProps, dragState, dropState }\n}\n\n/**\n * Starts a drag with a pointer, or with Enter or Space. A pointer drag shows\n * the whole row, held where the pointer grabbed it, rather than the handle.\n */\nfunction SavedViewDragHandle({\n dragState,\n itemKey,\n name,\n}: {\n dragState: DraggableCollectionState\n itemKey: Key\n name: string\n}) {\n const ref = useRef<HTMLButtonElement>(null)\n const { dragButtonProps, dragProps } = useDraggableItem(\n { hasDragButton: true, key: itemKey },\n dragState\n )\n const { buttonProps } = useButton(dragButtonProps, ref)\n\n return (\n <IconButton\n ref={ref}\n {...mergeProps(buttonProps, dragProps, {\n onDragStart: (event: React.DragEvent<HTMLButtonElement>) => {\n const row = event.currentTarget.closest(\"li\")\n if (!row) return\n const { left, top } = row.getBoundingClientRect()\n // The browser snapshots the row once this handler returns, so the\n // ghost styles apply only to the snapshot.\n const className = styles[\"views-list-item--drag-ghost\"]\n row.classList.add(className)\n requestAnimationFrame(() => row.classList.remove(className))\n event.dataTransfer.setDragImage(\n row,\n event.clientX - left,\n event.clientY - top\n )\n },\n })}\n aria-label={`Reorder ${name}`}\n className={styles[\"view-list-item-drag-handle\"]}\n icon={<Icon aria-hidden symbol=\"general#drag-handle\" />}\n kind=\"ghost\"\n />\n )\n}\n\n/**\n * A line at a row's edge while dragging. Screen readers reach the hidden\n * button inside it as a drop target.\n */\nfunction SavedViewDropIndicator({\n dropState,\n target,\n}: {\n dropState: DroppableCollectionState\n target: DropTarget\n}) {\n const ref = useRef<HTMLDivElement>(null)\n const { dropIndicatorProps, isDropTarget, isHidden } = useDropIndicator(\n { target },\n dropState,\n ref\n )\n const { visuallyHiddenProps } = useVisuallyHidden()\n if (isHidden) return null\n\n return (\n <div\n className={styles[\"view-list-drop-indicator\"]}\n data-drop-position={\n target.type === \"item\" ? target.dropPosition : undefined\n }\n data-drop-target={isDropTarget || undefined}\n >\n <div\n {...visuallyHiddenProps}\n role=\"button\"\n {...dropIndicatorProps}\n ref={ref}\n />\n </div>\n )\n}\n\n/**\n * Moves focus off a deleted view's row in two steps: `focusAfterDelete` picks\n * the target while the row is still there, and focus moves to it once the\n * alert starts closing.\n */\nfunction useFocusAfterDelete(\n savedViews: SavedView[],\n isDeleteAlertOpen: boolean\n) {\n const listRef = useRef<HTMLOListElement>(null)\n const doneButtonRef = useRef<HTMLButtonElement>(null)\n const focusTargetRef = useRef<HTMLElement | null>(null)\n\n // Step 1: the next view's row, or the previous one's if the deleted view is\n // last, or Done if it's the only one.\n const focusAfterDelete = (view: SavedView) => {\n const rows =\n listRef.current?.querySelectorAll(`.${styles[\"views-list-item\"]}`) ?? []\n const index = savedViews.findIndex(({ id }) => id === view.id)\n const row = rows[index + 1] ?? rows[index - 1]\n // The row's last enabled button is its delete button, when it has one.\n const buttons = row?.querySelectorAll<HTMLElement>(\n `button:not(.${styles[\"view-list-item-drag-handle\"]}, :disabled)`\n )\n focusTargetRef.current =\n buttons?.[buttons.length - 1] ??\n row?.querySelector(\"input\") ??\n doneButtonRef.current\n }\n\n // Step 2: a closing alert no longer holds focus, and doesn't take it back\n // once focus is outside it.\n useEffect(() => {\n if (isDeleteAlertOpen) return\n focusTargetRef.current?.focus()\n focusTargetRef.current = null\n }, [isDeleteAlertOpen])\n\n return { doneButtonRef, focusAfterDelete, listRef }\n}\n\n/**\n * A saved view's name field, default view toggle, and delete button. Renames on blur or Enter. An\n * empty name reverts to the current one. Tracks the last name it sent, so\n * Enter followed by blur renames once. Deleting sends a pending rename first,\n * then passes along the name, so the alert shows what the field does.\n */\nfunction SavedViewRow({\n defaultViewToggle,\n hasDeleteButton,\n onDelete,\n onRename,\n readOnly,\n view,\n}: {\n defaultViewToggle: ReactNode\n /** Shows the delete button, disabled without `onDelete`. */\n hasDeleteButton: boolean\n onDelete?: (name: string) => void\n onRename: (name: string) => void\n readOnly: boolean\n view: SavedView\n}) {\n const [name, setName] = useState(view.name)\n const committedName = useRef(view.name)\n\n // Picks up names changed outside this field, including once a rename saves,\n // unless the field has newer edits, which its next blur or Enter sends.\n useEffect(() => {\n const previousName = committedName.current\n committedName.current = view.name\n setName((currentName) =>\n currentName === previousName ? view.name : currentName\n )\n }, [view.name])\n\n const commit = () => {\n const trimmedName = name.trim()\n if (!trimmedName) {\n setName(committedName.current)\n return\n }\n setName(trimmedName)\n if (trimmedName === committedName.current) return\n committedName.current = trimmedName\n onRename(trimmedName)\n }\n\n return (\n <>\n <Input\n autoComplete=\"off\"\n className={styles[\"view-list-item-input\"]}\n hideLabel\n label={`Name for ${view.name}`}\n readOnly={readOnly}\n required={!readOnly}\n value={name}\n onBlur={readOnly ? undefined : commit}\n onChange={(event) => setName(event.target.value)}\n onKeyDown={(event) => {\n if (\n !readOnly &&\n event.key === \"Enter\" &&\n !event.repeat &&\n !event.nativeEvent.isComposing\n ) {\n commit()\n }\n }}\n />\n {defaultViewToggle}\n {hasDeleteButton && (\n <DeleteViewButton\n disabled={!onDelete}\n name={view.name}\n onClick={(event) => {\n // Safari doesn't focus a button on click, and the alert returns\n // focus to whatever had it when it opened. Focusing also blurs\n // the field, which sends a pending rename.\n event.currentTarget.focus()\n onDelete?.(committedName.current)\n }}\n />\n )}\n </>\n )\n}\n\nfunction DeleteViewButton({\n disabled,\n name,\n onClick,\n}: {\n disabled?: boolean\n name: string\n onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void\n}) {\n return (\n <IconButton\n aria-label={`Delete ${name}`}\n disabled={disabled}\n icon={<Icon aria-hidden symbol=\"general#trash\" />}\n kind=\"ghost\"\n tooltip=\"Delete\"\n onClick={onClick}\n />\n )\n}\n\n/** Makes a view the default, or hands the default back to \"initial\". */\nfunction DefaultViewToggle({\n isDefault,\n name,\n onChange,\n}: {\n isDefault: boolean\n name: string\n onChange: (isDefault: boolean) => void\n}) {\n return (\n <ToggleIconButton\n // Only one view is the default, so its label doesn't need the view's\n // name to be unique.\n aria-label={isDefault ? \"Default view\" : `Set ${name} as default`}\n icon={\n <Icon\n aria-hidden\n symbol={isDefault ? \"general#pin\" : \"general#outlined-pin\"}\n />\n }\n // Only the default's pin is blue.\n kind={isDefault ? \"ghost-interaction\" : \"ghost\"}\n pressed={isDefault}\n tooltip={isDefault ? \"Default view\" : \"Set as default\"}\n onChange={onChange}\n />\n )\n}\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ var styles = {"views-list":"views-list-3AMVI","views-list-item":"views-list-item-cWGsC","view-list-drop-indicator":"view-list-drop-indicator-zyDIt","view-list-item-drag-handle":"view-list-item-drag-handle-fiO5Z","views-list-item--drag-ghost":"views-list-item--drag-ghost-zEVbL","view-list-item-input":"view-list-item-input-dowHY","views-list-item--static":"views-list-item--static-9zGpJ","view-list-item-static-name":"view-list-item-static-name-nxBiG"};
2
+
3
+ export { styles as default };
4
+ //# sourceMappingURL=ManageSavedViewsModal.module.css.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManageSavedViewsModal.module.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
@@ -1,6 +1,9 @@
1
1
  import React from "react";
2
2
  export interface NewSavedViewModalProps {
3
- /** Prefills the name field, e.g. with "Active copy" when duplicating. */
3
+ /**
4
+ * Prefills the name field, e.g. with "Active copy" when duplicating or the
5
+ * current name when renaming.
6
+ */
4
7
  defaultName?: string;
5
8
  onClose: () => void;
6
9
  onSave: (name: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"NewSavedViewModal.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/NewSavedViewModal.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAE1D,MAAM,WAAW,sBAAsB;IACrC,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,iBAAiB,CAAC,EAChC,WAAgB,EAChB,OAAO,EACP,MAAM,EACN,IAAI,EACJ,KAAkB,GACnB,EAAE,sBAAsB,qBAWxB;yBAjBe,iBAAiB"}
1
+ {"version":3,"file":"NewSavedViewModal.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/NewSavedViewModal.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAsC,MAAM,OAAO,CAAA;AAE1D,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,IAAI,EAAE,OAAO,CAAA;IACb,4BAA4B;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,iBAAiB,CAAC,EAChC,WAAgB,EAChB,OAAO,EACP,MAAM,EACN,IAAI,EACJ,KAAkB,GACnB,EAAE,sBAAsB,qBAWxB;yBAjBe,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"NewSavedViewModal.js","sources":["../../../src/components/DataTable/NewSavedViewModal.tsx"],"sourcesContent":["import { Button } from \"@components/button\"\nimport { Input } from \"@components/input\"\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from \"@components/modal\"\nimport { useId } from \"@utilities/useId\"\nimport React, { useEffect, useRef, useState } from \"react\"\n\nexport interface NewSavedViewModalProps {\n /** Prefills the name field, e.g. with \"Active copy\" when duplicating. */\n defaultName?: string\n onClose: () => void\n onSave: (name: string) => void\n open: boolean\n /** Default `\"New view\"`. */\n title?: string\n}\n\nexport function NewSavedViewModal({\n defaultName = \"\",\n onClose,\n onSave,\n open,\n title = \"New view\",\n}: NewSavedViewModalProps) {\n return (\n <Modal dismissible open={open} size=\"sm\" onClose={onClose}>\n <ModalHeader title={title} />\n <NewSavedViewForm\n defaultName={defaultName}\n onClose={onClose}\n onSave={onSave}\n />\n </Modal>\n )\n}\n\nNewSavedViewModal.displayName = \"NewSavedViewModal\"\n\n/**\n * Holds the field's state below the modal, which unmounts its contents when\n * closed, so each open starts over from `defaultName`.\n */\nfunction NewSavedViewForm({\n defaultName,\n onClose,\n onSave,\n}: Required<Omit<NewSavedViewModalProps, \"open\" | \"title\">>) {\n const formId = `tds-data-table-new-saved-view-${useId()}`\n const [name, setName] = useState(defaultName)\n const [invalid, setInvalid] = useState(false)\n const inputRef = useRef<HTMLInputElement>(null)\n\n // Focuses in an effect rather than with `autoFocus`, which runs before a\n // closing context menu releases focus and so gets pulled back into it.\n useEffect(() => {\n inputRef.current?.focus()\n }, [])\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n const trimmedName = name.trim()\n if (!trimmedName) {\n setInvalid(true)\n return\n }\n onSave(trimmedName)\n onClose()\n }\n\n return (\n <>\n <ModalBody>\n <form id={formId} noValidate onSubmit={handleSubmit}>\n <Input\n ref={inputRef}\n autoComplete=\"off\"\n description={invalid ? \"Enter a name for this view.\" : undefined}\n invalid={invalid}\n label=\"Name\"\n required\n selectTextOnFocus\n value={name}\n onChange={(event) => {\n setName(event.target.value)\n setInvalid(false)\n }}\n />\n </form>\n </ModalBody>\n <ModalFooter>\n <Button kind=\"ghost\" label=\"Cancel\" onClick={onClose} />\n <Button form={formId} kind=\"primary\" label=\"Save\" type=\"submit\" />\n </ModalFooter>\n </>\n )\n}\n"],"names":["React"],"mappings":";;;;;;;;;;;;;;;SAgBgB,iBAAiB,CAAC,EAChC,WAAW,GAAG,EAAE,EAChB,OAAO,EACP,MAAM,EACN,IAAI,EACJ,KAAK,GAAG,UAAU,GACK,EAAA;AACvB,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,KAAK,EAAA,EAAC,WAAW,QAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,OAAO,EAAA;AACvD,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,CAAI;AAC7B,QAAAA,cAAA,CAAA,aAAA,CAAC,gBAAgB,EAAA,EACf,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EAAA,CACd,CACI;AAEZ;AAEA,iBAAiB,CAAC,WAAW,GAAG,mBAAmB;AAEnD;;;AAGG;AACH,SAAS,gBAAgB,CAAC,EACxB,WAAW,EACX,OAAO,EACP,MAAM,GACmD,EAAA;AACzD,IAAA,MAAM,MAAM,GAAG,CAAA,8BAAA,EAAiC,KAAK,EAAE,EAAE;IACzD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC7C,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC;;;IAI/C,SAAS,CAAC,MAAK;AACb,QAAA,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE;IAC3B,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,YAAY,GAAG,CAAC,KAAuC,KAAI;QAC/D,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE;QAC/B,IAAI,CAAC,WAAW,EAAE;YAChB,UAAU,CAAC,IAAI,CAAC;YAChB;QACF;QACA,MAAM,CAAC,WAAW,CAAC;AACnB,QAAA,OAAO,EAAE;AACX,IAAA,CAAC;AAED,IAAA,QACEA,cAAA,CAAA,aAAA,CAAAA,cAAA,CAAA,QAAA,EAAA,IAAA;AACE,QAAAA,cAAA,CAAA,aAAA,CAAC,SAAS,EAAA,IAAA;YACRA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAE,MAAM,EAAE,UAAU,EAAA,IAAA,EAAC,QAAQ,EAAE,YAAY,EAAA;AACjD,gBAAAA,cAAA,CAAA,aAAA,CAAC,KAAK,EAAA,EACJ,GAAG,EAAE,QAAQ,EACb,YAAY,EAAC,KAAK,EAClB,WAAW,EAAE,OAAO,GAAG,6BAA6B,GAAG,SAAS,EAChE,OAAO,EAAE,OAAO,EAChB,KAAK,EAAC,MAAM,EACZ,QAAQ,EAAA,IAAA,EACR,iBAAiB,QACjB,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,KAAK,KAAI;AAClB,wBAAA,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;wBAC3B,UAAU,CAAC,KAAK,CAAC;oBACnB,CAAC,EAAA,CACD,CACG,CACG;AACZ,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,IAAA;AACV,YAAAA,cAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,EAAA,CAAI;YACxDA,cAAA,CAAA,aAAA,CAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,SAAS,EAAC,KAAK,EAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAA,CAAG,CACtD,CACb;AAEP;;;;"}
1
+ {"version":3,"file":"NewSavedViewModal.js","sources":["../../../src/components/DataTable/NewSavedViewModal.tsx"],"sourcesContent":["import { Button } from \"@components/button\"\nimport { Input } from \"@components/input\"\nimport { Modal, ModalBody, ModalFooter, ModalHeader } from \"@components/modal\"\nimport { useId } from \"@utilities/useId\"\nimport React, { useEffect, useRef, useState } from \"react\"\n\nexport interface NewSavedViewModalProps {\n /**\n * Prefills the name field, e.g. with \"Active copy\" when duplicating or the\n * current name when renaming.\n */\n defaultName?: string\n onClose: () => void\n onSave: (name: string) => void\n open: boolean\n /** Default `\"New view\"`. */\n title?: string\n}\n\nexport function NewSavedViewModal({\n defaultName = \"\",\n onClose,\n onSave,\n open,\n title = \"New view\",\n}: NewSavedViewModalProps) {\n return (\n <Modal dismissible open={open} size=\"sm\" onClose={onClose}>\n <ModalHeader title={title} />\n <NewSavedViewForm\n defaultName={defaultName}\n onClose={onClose}\n onSave={onSave}\n />\n </Modal>\n )\n}\n\nNewSavedViewModal.displayName = \"NewSavedViewModal\"\n\n/**\n * Holds the field's state below the modal, which unmounts its contents when\n * closed, so each open starts over from `defaultName`.\n */\nfunction NewSavedViewForm({\n defaultName,\n onClose,\n onSave,\n}: Required<Omit<NewSavedViewModalProps, \"open\" | \"title\">>) {\n const formId = `tds-data-table-new-saved-view-${useId()}`\n const [name, setName] = useState(defaultName)\n const [invalid, setInvalid] = useState(false)\n const inputRef = useRef<HTMLInputElement>(null)\n\n // Focuses in an effect rather than with `autoFocus`, which runs before a\n // closing context menu releases focus and so gets pulled back into it.\n useEffect(() => {\n inputRef.current?.focus()\n }, [])\n\n const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n const trimmedName = name.trim()\n if (!trimmedName) {\n setInvalid(true)\n return\n }\n onSave(trimmedName)\n onClose()\n }\n\n return (\n <>\n <ModalBody>\n <form id={formId} noValidate onSubmit={handleSubmit}>\n <Input\n ref={inputRef}\n autoComplete=\"off\"\n description={invalid ? \"Enter a name for this view.\" : undefined}\n invalid={invalid}\n label=\"Name\"\n required\n selectTextOnFocus\n value={name}\n onChange={(event) => {\n setName(event.target.value)\n setInvalid(false)\n }}\n />\n </form>\n </ModalBody>\n <ModalFooter>\n <Button kind=\"ghost\" label=\"Cancel\" onClick={onClose} />\n <Button form={formId} kind=\"primary\" label=\"Save\" type=\"submit\" />\n </ModalFooter>\n </>\n )\n}\n"],"names":["React"],"mappings":";;;;;;;;;;;;;;;SAmBgB,iBAAiB,CAAC,EAChC,WAAW,GAAG,EAAE,EAChB,OAAO,EACP,MAAM,EACN,IAAI,EACJ,KAAK,GAAG,UAAU,GACK,EAAA;AACvB,IAAA,QACEA,cAAA,CAAA,aAAA,CAAC,KAAK,EAAA,EAAC,WAAW,QAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAC,IAAI,EAAC,OAAO,EAAE,OAAO,EAAA;AACvD,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAC,KAAK,EAAE,KAAK,EAAA,CAAI;AAC7B,QAAAA,cAAA,CAAA,aAAA,CAAC,gBAAgB,EAAA,EACf,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EAAA,CACd,CACI;AAEZ;AAEA,iBAAiB,CAAC,WAAW,GAAG,mBAAmB;AAEnD;;;AAGG;AACH,SAAS,gBAAgB,CAAC,EACxB,WAAW,EACX,OAAO,EACP,MAAM,GACmD,EAAA;AACzD,IAAA,MAAM,MAAM,GAAG,CAAA,8BAAA,EAAiC,KAAK,EAAE,EAAE;IACzD,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC;IAC7C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC;AAC7C,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAmB,IAAI,CAAC;;;IAI/C,SAAS,CAAC,MAAK;AACb,QAAA,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE;IAC3B,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,YAAY,GAAG,CAAC,KAAuC,KAAI;QAC/D,KAAK,CAAC,cAAc,EAAE;AACtB,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE;QAC/B,IAAI,CAAC,WAAW,EAAE;YAChB,UAAU,CAAC,IAAI,CAAC;YAChB;QACF;QACA,MAAM,CAAC,WAAW,CAAC;AACnB,QAAA,OAAO,EAAE;AACX,IAAA,CAAC;AAED,IAAA,QACEA,cAAA,CAAA,aAAA,CAAAA,cAAA,CAAA,QAAA,EAAA,IAAA;AACE,QAAAA,cAAA,CAAA,aAAA,CAAC,SAAS,EAAA,IAAA;YACRA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAM,EAAE,EAAE,MAAM,EAAE,UAAU,EAAA,IAAA,EAAC,QAAQ,EAAE,YAAY,EAAA;AACjD,gBAAAA,cAAA,CAAA,aAAA,CAAC,KAAK,EAAA,EACJ,GAAG,EAAE,QAAQ,EACb,YAAY,EAAC,KAAK,EAClB,WAAW,EAAE,OAAO,GAAG,6BAA6B,GAAG,SAAS,EAChE,OAAO,EAAE,OAAO,EAChB,KAAK,EAAC,MAAM,EACZ,QAAQ,EAAA,IAAA,EACR,iBAAiB,QACjB,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,KAAK,KAAI;AAClB,wBAAA,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC;wBAC3B,UAAU,CAAC,KAAK,CAAC;oBACnB,CAAC,EAAA,CACD,CACG,CACG;AACZ,QAAAA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,IAAA;AACV,YAAAA,cAAA,CAAA,aAAA,CAAC,MAAM,EAAA,EAAC,IAAI,EAAC,OAAO,EAAC,KAAK,EAAC,QAAQ,EAAC,OAAO,EAAE,OAAO,EAAA,CAAI;YACxDA,cAAA,CAAA,aAAA,CAAC,MAAM,IAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAC,SAAS,EAAC,KAAK,EAAC,MAAM,EAAC,IAAI,EAAC,QAAQ,EAAA,CAAG,CACtD,CACb;AAEP;;;;"}
@@ -56,6 +56,15 @@ export declare const ResultsCount: {
56
56
  * rendered above the table groups digits the same way.
57
57
  */
58
58
  export declare function formatCount(count: number): string;
59
+ /**
60
+ * Builds the results-count label, e.g. `"1 result"`, `"1,234 results"`, or
61
+ * `"2 people"`. The count is formatted with `Intl.NumberFormat` and the
62
+ * singular noun is used only when the count is 1, every other count uses the
63
+ * plural. `resultNoun` may be a string (the plural appends `"s"`), a
64
+ * `[singular, plural]` tuple (the plural is supplied explicitly), or `true`
65
+ * (the noun defaults to `"result"`).
66
+ */
67
+ export declare function getResultsCountLabel(count: number, resultNoun: Exclude<ResultNoun, false>): string;
59
68
  /**
60
69
  * Picks the singular or plural noun for `count` (singular only when `count` is
61
70
  * 1, matching English pluralization).
@@ -1 +1 @@
1
- {"version":3,"file":"ResultsCount.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ResultsCount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9E,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,uCAAuC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAE3E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;iEAMtB,iBAAiB;;CAuBnB,CAAA;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAmBD;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,GACrC,MAAM,CAOR"}
1
+ {"version":3,"file":"ResultsCount.d.ts","sourceRoot":"","sources":["../../../src/components/DataTable/ResultsCount.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;AAE9E,MAAM,WAAW,iBAAiB;IAChC,wFAAwF;IACxF,EAAE,EAAE,MAAM,CAAA;IACV;;;OAGG;IACH,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,uCAAuC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,6CAA6C;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAE3E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,UAAU,GAAG,SAAS,GACjC,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,YAAY;iEAMtB,iBAAiB;;CAuBnB,CAAA;AAMD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,GACrC,MAAM,CAIR;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC,GACrC,MAAM,CAOR"}
@@ -90,5 +90,5 @@ function resolveNoun(count, resultNoun) {
90
90
  return count === 1 ? singular : plural;
91
91
  }
92
92
 
93
- export { ResultsCount, formatCount, hasResultsCount, resolveNoun, resolveResultNounLabel };
93
+ export { ResultsCount, formatCount, getResultsCountLabel, hasResultsCount, resolveNoun, resolveResultNounLabel };
94
94
  //# sourceMappingURL=ResultsCount.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ResultsCount.js","sources":["../../../src/components/DataTable/ResultsCount.tsx"],"sourcesContent":["import React from \"react\"\n\n/**\n * A noun for the results count. A string uses it as the singular and appends\n * `\"s\"` for the plural; a `[singular, plural]` tuple supplies an irregular\n * plural; `true` defaults the noun to `\"result\"`; `false` renders no count.\n */\nexport type ResultNoun = boolean | string | [singular: string, plural: string]\n\nexport interface ResultsCountProps {\n /** An `id` for the rendered element so the table can link it via `aria-describedby`. */\n id: string\n /**\n * The noun (and whether to render a count at all). See {@link ResultNoun}.\n * When `false` or omitted, nothing renders.\n */\n resultNoun?: ResultNoun\n /** Whether the table is selectable. */\n selectable?: boolean\n /** The number of currently selected rows. */\n selectedCount?: number\n /**\n * The total number of results: the caller's explicit `resultCount` when\n * supplied, otherwise `data.length`.\n */\n totalCount: number\n}\n\n/**\n * Whether a {@link ResultsCount} will render anything for the given\n * `resultNoun`. A count is shown only when a noun is supplied, so callers can\n * use this to decide whether to link the count via `aria-describedby`.\n */\nexport function hasResultsCount(resultNoun: ResultNoun | undefined): boolean {\n return Boolean(resultNoun)\n}\n\n/**\n * Resolves a {@link ResultNoun} to a plain string usable as the table's\n * `aria-label`, e.g. `\"people\"` or `\"items\"`. Uses the plural form — appending\n * `\"s\"` to a string noun and taking the second element of a `[singular,\n * plural]` tuple — to match the count label. Returns `undefined` when no\n * meaningful noun is supplied — including the `true` default, which carries no\n * caller-provided label — so callers can fall back to their own `aria-label`.\n */\nexport function resolveResultNounLabel(\n resultNoun: ResultNoun | undefined\n): string | undefined {\n if (!resultNoun || resultNoun === true) return undefined\n // A count other than 1 selects the plural form.\n return resolveNoun(2, resultNoun)\n}\n\n/**\n * Renders the results count displayed above the table, e.g. `\"1 result\"`,\n * `\"1,234 results\"`, or `\"2 people\"`. When the table is `selectable` and rows\n * are selected, the count reflects the selection as `\"{selected} of {total}\"`,\n * e.g. `\"2 of 100\"`. That terse visible form is ambiguous on its own, so a\n * visually-hidden suffix names what the numbers refer to for assistive tech —\n * `\"2 of 100 people selected\"`. Renders nothing when `resultNoun` is `false` or\n * omitted.\n */\nexport const ResultsCount = ({\n id,\n resultNoun,\n selectable,\n selectedCount = 0,\n totalCount,\n}: ResultsCountProps) => {\n if (!resultNoun) return null\n\n // When the table is selectable and rows are selected, the count reflects the\n // selection as `\"{selected} of {total}\"` (e.g. `\"2 of 100\"`) rather than the\n // total row count.\n const hasSelection = Boolean(selectable && selectedCount)\n const label = hasSelection\n ? `${formatCount(selectedCount)} of ${formatCount(totalCount)}`\n : getResultsCountLabel(totalCount, resultNoun)\n\n return (\n <p id={id} className=\"tds-data-table-results-count\">\n {label}\n {hasSelection && (\n // The noun agrees with the total rather than the selected count, so a\n // single selection out of many still reads `\"1 of 57 people selected\"`.\n <span className=\"tds-data-table-results-count-label--hidden\">\n &nbsp;{`${resolveNoun(totalCount, resultNoun)} selected`}\n </span>\n )}\n </p>\n )\n}\n\nResultsCount.displayName = \"ResultsCount\"\n\nconst numberFormatter = new Intl.NumberFormat()\n\n/**\n * Formats a count for display, e.g. `1234` as `\"1,234\"`. Shared so every count\n * rendered above the table groups digits the same way.\n */\nexport function formatCount(count: number): string {\n return numberFormatter.format(count)\n}\n\n/**\n * Builds the results-count label, e.g. `\"1 result\"`, `\"1,234 results\"`, or\n * `\"2 people\"`. The count is formatted with `Intl.NumberFormat` and the\n * singular noun is used only when the count is 1, every other count uses the\n * plural. `resultNoun` may be a string (the plural appends `\"s\"`), a\n * `[singular, plural]` tuple (the plural is supplied explicitly), or `true`\n * (the noun defaults to `\"result\"`).\n */\nfunction getResultsCountLabel(\n count: number,\n resultNoun: Exclude<ResultNoun, false>\n): string {\n const noun = resolveNoun(count, resultNoun)\n const formattedCount = formatCount(count)\n return `${formattedCount} ${noun}`\n}\n\n/**\n * Picks the singular or plural noun for `count` (singular only when `count` is\n * 1, matching English pluralization).\n * `resultNoun` may be a string (the plural appends `\"s\"`), a\n * `[singular, plural]` tuple, or `true` (the noun defaults to `\"result\"`).\n *\n * Shared with the table actions' `aria-label` suffix so every count rendered\n * above the table pluralizes identically.\n */\nexport function resolveNoun(\n count: number,\n resultNoun: Exclude<ResultNoun, false>\n): string {\n const [singular, plural] = Array.isArray(resultNoun)\n ? resultNoun\n : resultNoun === true\n ? [\"result\", \"results\"]\n : [resultNoun, `${resultNoun}s`]\n return count === 1 ? singular : plural\n}\n"],"names":["React"],"mappings":";;AA4BA;;;;AAIG;AACG,SAAU,eAAe,CAAC,UAAkC,EAAA;AAChE,IAAA,OAAO,OAAO,CAAC,UAAU,CAAC;AAC5B;AAEA;;;;;;;AAOG;AACG,SAAU,sBAAsB,CACpC,UAAkC,EAAA;AAElC,IAAA,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,IAAI;AAAE,QAAA,OAAO,SAAS;;AAExD,IAAA,OAAO,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC;AACnC;AAEA;;;;;;;;AAQG;AACI,MAAM,YAAY,GAAG,CAAC,EAC3B,EAAE,EACF,UAAU,EACV,UAAU,EACV,aAAa,GAAG,CAAC,EACjB,UAAU,GACQ,KAAI;AACtB,IAAA,IAAI,CAAC,UAAU;AAAE,QAAA,OAAO,IAAI;;;;IAK5B,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC;IACzD,MAAM,KAAK,GAAG;UACV,CAAA,EAAG,WAAW,CAAC,aAAa,CAAC,CAAA,IAAA,EAAO,WAAW,CAAC,UAAU,CAAC,CAAA;AAC7D,UAAE,oBAAoB,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhD,QACEA,oCAAG,EAAE,EAAE,EAAE,EAAE,SAAS,EAAC,8BAA8B,EAAA;QAChD,KAAK;AACL,QAAA,YAAY;;;QAGXA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,4CAA4C,EAAA;;YACnD,CAAA,EAAG,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA,SAAA,CAAW,CACnD,CACR,CACC;AAER;AAEA,YAAY,CAAC,WAAW,GAAG,cAAc;AAEzC,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE;AAE/C;;;AAGG;AACG,SAAU,WAAW,CAAC,KAAa,EAAA;AACvC,IAAA,OAAO,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC;AAEA;;;;;;;AAOG;AACH,SAAS,oBAAoB,CAC3B,KAAa,EACb,UAAsC,EAAA;IAEtC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC;AAC3C,IAAA,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC;AACzC,IAAA,OAAO,CAAA,EAAG,cAAc,CAAA,CAAA,EAAI,IAAI,EAAE;AACpC;AAEA;;;;;;;;AAQG;AACG,SAAU,WAAW,CACzB,KAAa,EACb,UAAsC,EAAA;IAEtC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU;AACjD,UAAE;UACA,UAAU,KAAK;AACf,cAAE,CAAC,QAAQ,EAAE,SAAS;cACpB,CAAC,UAAU,EAAE,GAAG,UAAU,CAAA,CAAA,CAAG,CAAC;IACpC,OAAO,KAAK,KAAK,CAAC,GAAG,QAAQ,GAAG,MAAM;AACxC;;;;"}
1
+ {"version":3,"file":"ResultsCount.js","sources":["../../../src/components/DataTable/ResultsCount.tsx"],"sourcesContent":["import React from \"react\"\n\n/**\n * A noun for the results count. A string uses it as the singular and appends\n * `\"s\"` for the plural; a `[singular, plural]` tuple supplies an irregular\n * plural; `true` defaults the noun to `\"result\"`; `false` renders no count.\n */\nexport type ResultNoun = boolean | string | [singular: string, plural: string]\n\nexport interface ResultsCountProps {\n /** An `id` for the rendered element so the table can link it via `aria-describedby`. */\n id: string\n /**\n * The noun (and whether to render a count at all). See {@link ResultNoun}.\n * When `false` or omitted, nothing renders.\n */\n resultNoun?: ResultNoun\n /** Whether the table is selectable. */\n selectable?: boolean\n /** The number of currently selected rows. */\n selectedCount?: number\n /**\n * The total number of results: the caller's explicit `resultCount` when\n * supplied, otherwise `data.length`.\n */\n totalCount: number\n}\n\n/**\n * Whether a {@link ResultsCount} will render anything for the given\n * `resultNoun`. A count is shown only when a noun is supplied, so callers can\n * use this to decide whether to link the count via `aria-describedby`.\n */\nexport function hasResultsCount(resultNoun: ResultNoun | undefined): boolean {\n return Boolean(resultNoun)\n}\n\n/**\n * Resolves a {@link ResultNoun} to a plain string usable as the table's\n * `aria-label`, e.g. `\"people\"` or `\"items\"`. Uses the plural form — appending\n * `\"s\"` to a string noun and taking the second element of a `[singular,\n * plural]` tuple — to match the count label. Returns `undefined` when no\n * meaningful noun is supplied — including the `true` default, which carries no\n * caller-provided label — so callers can fall back to their own `aria-label`.\n */\nexport function resolveResultNounLabel(\n resultNoun: ResultNoun | undefined\n): string | undefined {\n if (!resultNoun || resultNoun === true) return undefined\n // A count other than 1 selects the plural form.\n return resolveNoun(2, resultNoun)\n}\n\n/**\n * Renders the results count displayed above the table, e.g. `\"1 result\"`,\n * `\"1,234 results\"`, or `\"2 people\"`. When the table is `selectable` and rows\n * are selected, the count reflects the selection as `\"{selected} of {total}\"`,\n * e.g. `\"2 of 100\"`. That terse visible form is ambiguous on its own, so a\n * visually-hidden suffix names what the numbers refer to for assistive tech —\n * `\"2 of 100 people selected\"`. Renders nothing when `resultNoun` is `false` or\n * omitted.\n */\nexport const ResultsCount = ({\n id,\n resultNoun,\n selectable,\n selectedCount = 0,\n totalCount,\n}: ResultsCountProps) => {\n if (!resultNoun) return null\n\n // When the table is selectable and rows are selected, the count reflects the\n // selection as `\"{selected} of {total}\"` (e.g. `\"2 of 100\"`) rather than the\n // total row count.\n const hasSelection = Boolean(selectable && selectedCount)\n const label = hasSelection\n ? `${formatCount(selectedCount)} of ${formatCount(totalCount)}`\n : getResultsCountLabel(totalCount, resultNoun)\n\n return (\n <p id={id} className=\"tds-data-table-results-count\">\n {label}\n {hasSelection && (\n // The noun agrees with the total rather than the selected count, so a\n // single selection out of many still reads `\"1 of 57 people selected\"`.\n <span className=\"tds-data-table-results-count-label--hidden\">\n &nbsp;{`${resolveNoun(totalCount, resultNoun)} selected`}\n </span>\n )}\n </p>\n )\n}\n\nResultsCount.displayName = \"ResultsCount\"\n\nconst numberFormatter = new Intl.NumberFormat()\n\n/**\n * Formats a count for display, e.g. `1234` as `\"1,234\"`. Shared so every count\n * rendered above the table groups digits the same way.\n */\nexport function formatCount(count: number): string {\n return numberFormatter.format(count)\n}\n\n/**\n * Builds the results-count label, e.g. `\"1 result\"`, `\"1,234 results\"`, or\n * `\"2 people\"`. The count is formatted with `Intl.NumberFormat` and the\n * singular noun is used only when the count is 1, every other count uses the\n * plural. `resultNoun` may be a string (the plural appends `\"s\"`), a\n * `[singular, plural]` tuple (the plural is supplied explicitly), or `true`\n * (the noun defaults to `\"result\"`).\n */\nexport function getResultsCountLabel(\n count: number,\n resultNoun: Exclude<ResultNoun, false>\n): string {\n const noun = resolveNoun(count, resultNoun)\n const formattedCount = formatCount(count)\n return `${formattedCount} ${noun}`\n}\n\n/**\n * Picks the singular or plural noun for `count` (singular only when `count` is\n * 1, matching English pluralization).\n * `resultNoun` may be a string (the plural appends `\"s\"`), a\n * `[singular, plural]` tuple, or `true` (the noun defaults to `\"result\"`).\n *\n * Shared with the table actions' `aria-label` suffix so every count rendered\n * above the table pluralizes identically.\n */\nexport function resolveNoun(\n count: number,\n resultNoun: Exclude<ResultNoun, false>\n): string {\n const [singular, plural] = Array.isArray(resultNoun)\n ? resultNoun\n : resultNoun === true\n ? [\"result\", \"results\"]\n : [resultNoun, `${resultNoun}s`]\n return count === 1 ? singular : plural\n}\n"],"names":["React"],"mappings":";;AA4BA;;;;AAIG;AACG,SAAU,eAAe,CAAC,UAAkC,EAAA;AAChE,IAAA,OAAO,OAAO,CAAC,UAAU,CAAC;AAC5B;AAEA;;;;;;;AAOG;AACG,SAAU,sBAAsB,CACpC,UAAkC,EAAA;AAElC,IAAA,IAAI,CAAC,UAAU,IAAI,UAAU,KAAK,IAAI;AAAE,QAAA,OAAO,SAAS;;AAExD,IAAA,OAAO,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC;AACnC;AAEA;;;;;;;;AAQG;AACI,MAAM,YAAY,GAAG,CAAC,EAC3B,EAAE,EACF,UAAU,EACV,UAAU,EACV,aAAa,GAAG,CAAC,EACjB,UAAU,GACQ,KAAI;AACtB,IAAA,IAAI,CAAC,UAAU;AAAE,QAAA,OAAO,IAAI;;;;IAK5B,MAAM,YAAY,GAAG,OAAO,CAAC,UAAU,IAAI,aAAa,CAAC;IACzD,MAAM,KAAK,GAAG;UACV,CAAA,EAAG,WAAW,CAAC,aAAa,CAAC,CAAA,IAAA,EAAO,WAAW,CAAC,UAAU,CAAC,CAAA;AAC7D,UAAE,oBAAoB,CAAC,UAAU,EAAE,UAAU,CAAC;IAEhD,QACEA,oCAAG,EAAE,EAAE,EAAE,EAAE,SAAS,EAAC,8BAA8B,EAAA;QAChD,KAAK;AACL,QAAA,YAAY;;;QAGXA,cAAA,CAAA,aAAA,CAAA,MAAA,EAAA,EAAM,SAAS,EAAC,4CAA4C,EAAA;;YACnD,CAAA,EAAG,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA,SAAA,CAAW,CACnD,CACR,CACC;AAER;AAEA,YAAY,CAAC,WAAW,GAAG,cAAc;AAEzC,MAAM,eAAe,GAAG,IAAI,IAAI,CAAC,YAAY,EAAE;AAE/C;;;AAGG;AACG,SAAU,WAAW,CAAC,KAAa,EAAA;AACvC,IAAA,OAAO,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC;AACtC;AAEA;;;;;;;AAOG;AACG,SAAU,oBAAoB,CAClC,KAAa,EACb,UAAsC,EAAA;IAEtC,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,EAAE,UAAU,CAAC;AAC3C,IAAA,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,CAAC;AACzC,IAAA,OAAO,CAAA,EAAG,cAAc,CAAA,CAAA,EAAI,IAAI,EAAE;AACpC;AAEA;;;;;;;;AAQG;AACG,SAAU,WAAW,CACzB,KAAa,EACb,UAAsC,EAAA;IAEtC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU;AACjD,UAAE;UACA,UAAU,KAAK;AACf,cAAE,CAAC,QAAQ,EAAE,SAAS;cACpB,CAAC,UAAU,EAAE,GAAG,UAAU,CAAA,CAAA,CAAG,CAAC;IACpC,OAAO,KAAK,KAAK,CAAC,GAAG,QAAQ,GAAG,MAAM;AACxC;;;;"}