@planningcenter/tapestry 4.12.0 → 4.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/componentRegistrars.d.ts +1 -0
  2. package/dist/componentRegistrars.d.ts.map +1 -1
  3. package/dist/componentRegistrars.js +6 -2
  4. package/dist/componentRegistrars.js.map +1 -1
  5. package/dist/components/DataTable/ActiveFilters.d.ts +23 -1
  6. package/dist/components/DataTable/ActiveFilters.d.ts.map +1 -1
  7. package/dist/components/DataTable/ActiveFilters.js +49 -4
  8. package/dist/components/DataTable/ActiveFilters.js.map +1 -1
  9. package/dist/components/DataTable/CollectionEditorsLazy.d.ts.map +1 -1
  10. package/dist/components/DataTable/CollectionEditorsLazy.js +20 -18
  11. package/dist/components/DataTable/CollectionEditorsLazy.js.map +1 -1
  12. package/dist/components/DataTable/DataTable.d.ts +66 -50
  13. package/dist/components/DataTable/DataTable.d.ts.map +1 -1
  14. package/dist/components/DataTable/DataTable.js +78 -17
  15. package/dist/components/DataTable/DataTable.js.map +1 -1
  16. package/dist/components/DataTable/ManageSavedViewsModal.d.ts +18 -7
  17. package/dist/components/DataTable/ManageSavedViewsModal.d.ts.map +1 -1
  18. package/dist/components/DataTable/ManageSavedViewsModal.js +120 -104
  19. package/dist/components/DataTable/ManageSavedViewsModal.js.map +1 -1
  20. package/dist/components/DataTable/ManageSavedViewsModal.module.css.js +1 -1
  21. package/dist/components/DataTable/NewSavedViewButton.d.ts.map +1 -1
  22. package/dist/components/DataTable/NewSavedViewButton.js +1 -1
  23. package/dist/components/DataTable/NewSavedViewButton.js.map +1 -1
  24. package/dist/components/DataTable/SavedViewActions.d.ts +19 -0
  25. package/dist/components/DataTable/SavedViewActions.d.ts.map +1 -0
  26. package/dist/components/DataTable/SavedViewActions.js +34 -0
  27. package/dist/components/DataTable/SavedViewActions.js.map +1 -0
  28. package/dist/components/DataTable/SavedViewMenu.d.ts +18 -0
  29. package/dist/components/DataTable/SavedViewMenu.d.ts.map +1 -0
  30. package/dist/components/DataTable/SavedViewMenu.js +25 -0
  31. package/dist/components/DataTable/SavedViewMenu.js.map +1 -0
  32. package/dist/components/DataTable/SavedViewsBar.d.ts +25 -13
  33. package/dist/components/DataTable/SavedViewsBar.d.ts.map +1 -1
  34. package/dist/components/DataTable/SavedViewsBar.js +81 -93
  35. package/dist/components/DataTable/SavedViewsBar.js.map +1 -1
  36. package/dist/components/DataTable/TableActions.d.ts +4 -2
  37. package/dist/components/DataTable/TableActions.d.ts.map +1 -1
  38. package/dist/components/DataTable/TableActions.js +11 -14
  39. package/dist/components/DataTable/TableActions.js.map +1 -1
  40. package/dist/components/DataTable/index.d.ts +2 -0
  41. package/dist/components/DataTable/index.d.ts.map +1 -1
  42. package/dist/components/DataTable/saveErrorMessage.d.ts +3 -0
  43. package/dist/components/DataTable/saveErrorMessage.d.ts.map +1 -0
  44. package/dist/components/DataTable/saveErrorMessage.js +9 -0
  45. package/dist/components/DataTable/saveErrorMessage.js.map +1 -0
  46. package/dist/components/DataTable/savedViews.d.ts +15 -30
  47. package/dist/components/DataTable/savedViews.d.ts.map +1 -1
  48. package/dist/components/DataTable/savedViews.js +51 -98
  49. package/dist/components/DataTable/savedViews.js.map +1 -1
  50. package/dist/components/DataTable/useActiveSavedView.d.ts +1 -1
  51. package/dist/components/DataTable/useActiveSavedView.d.ts.map +1 -1
  52. package/dist/components/DataTable/useActiveSavedView.js +5 -4
  53. package/dist/components/DataTable/useActiveSavedView.js.map +1 -1
  54. package/dist/components/DataTable/useColumnVisibility.d.ts +7 -7
  55. package/dist/components/DataTable/useColumnVisibility.d.ts.map +1 -1
  56. package/dist/components/DataTable/useColumnVisibility.js +14 -14
  57. package/dist/components/DataTable/useColumnVisibility.js.map +1 -1
  58. package/dist/components/DataTable/useResultsAnnouncement.d.ts +26 -0
  59. package/dist/components/DataTable/useResultsAnnouncement.d.ts.map +1 -0
  60. package/dist/components/DataTable/{useFilterAnnouncement.js → useResultsAnnouncement.js} +16 -12
  61. package/dist/components/DataTable/useResultsAnnouncement.js.map +1 -0
  62. package/dist/components/DataTable/useSaveStatus.d.ts +32 -0
  63. package/dist/components/DataTable/useSaveStatus.d.ts.map +1 -0
  64. package/dist/components/DataTable/useSaveStatus.js +80 -0
  65. package/dist/components/DataTable/useSaveStatus.js.map +1 -0
  66. package/dist/components/DataTable/useSavedViewNameModal.d.ts +14 -0
  67. package/dist/components/DataTable/useSavedViewNameModal.d.ts.map +1 -0
  68. package/dist/components/DataTable/useSavedViewNameModal.js +43 -0
  69. package/dist/components/DataTable/useSavedViewNameModal.js.map +1 -0
  70. package/dist/components/DataTable/useSavedViewsClient.d.ts +58 -0
  71. package/dist/components/DataTable/useSavedViewsClient.d.ts.map +1 -0
  72. package/dist/components/DataTable/useSavedViewsClient.js +87 -0
  73. package/dist/components/DataTable/useSavedViewsClient.js.map +1 -0
  74. package/dist/components/DataTable/useSavedViewsState.d.ts +35 -0
  75. package/dist/components/DataTable/useSavedViewsState.d.ts.map +1 -0
  76. package/dist/components/DataTable/useSavedViewsState.js +192 -0
  77. package/dist/components/DataTable/useSavedViewsState.js.map +1 -0
  78. package/dist/components/DataTable/useUpdateSavedViewName.d.ts +2 -3
  79. package/dist/components/DataTable/useUpdateSavedViewName.d.ts.map +1 -1
  80. package/dist/components/DataTable/useUpdateSavedViewName.js +1 -2
  81. package/dist/components/DataTable/useUpdateSavedViewName.js.map +1 -1
  82. package/dist/components/DataTable/useVisibleSavedViews.d.ts +31 -0
  83. package/dist/components/DataTable/useVisibleSavedViews.d.ts.map +1 -0
  84. package/dist/components/DataTable/useVisibleSavedViews.js +178 -0
  85. package/dist/components/DataTable/useVisibleSavedViews.js.map +1 -0
  86. package/dist/components/button/BaseButton.d.ts +2 -0
  87. package/dist/components/button/BaseButton.d.ts.map +1 -1
  88. package/dist/components/button/BaseButton.js +8 -17
  89. package/dist/components/button/BaseButton.js.map +1 -1
  90. package/dist/components/internal/LoadingAnnouncement.d.ts +6 -0
  91. package/dist/components/internal/LoadingAnnouncement.d.ts.map +1 -1
  92. package/dist/components/internal/LoadingAnnouncement.js +12 -3
  93. package/dist/components/internal/LoadingAnnouncement.js.map +1 -1
  94. package/dist/components/internal/index.d.ts +1 -1
  95. package/dist/components/internal/index.d.ts.map +1 -1
  96. package/dist/components/internal/reorderable-list-box/ReorderableListBox.d.ts +6 -0
  97. package/dist/components/internal/reorderable-list-box/ReorderableListBox.d.ts.map +1 -1
  98. package/dist/components/internal/reorderable-list-box/ReorderableListBox.js +9 -2
  99. package/dist/components/internal/reorderable-list-box/ReorderableListBox.js.map +1 -1
  100. package/dist/components/internal/tooltip/useTooltipTriggerProps.d.ts +13 -0
  101. package/dist/components/internal/tooltip/useTooltipTriggerProps.d.ts.map +1 -0
  102. package/dist/components/internal/tooltip/useTooltipTriggerProps.js +24 -0
  103. package/dist/components/internal/tooltip/useTooltipTriggerProps.js.map +1 -0
  104. package/dist/components/link/BaseLink.d.ts.map +1 -1
  105. package/dist/components/link/BaseLink.js +3 -13
  106. package/dist/components/link/BaseLink.js.map +1 -1
  107. package/dist/components/segmented-control/IconSegment.d.ts +30 -8
  108. package/dist/components/segmented-control/IconSegment.d.ts.map +1 -1
  109. package/dist/components/segmented-control/IconSegment.js +10 -3
  110. package/dist/components/segmented-control/IconSegment.js.map +1 -1
  111. package/dist/components/segmented-control/SegmentBase.d.ts.map +1 -1
  112. package/dist/components/segmented-control/SegmentBase.js +4 -2
  113. package/dist/components/segmented-control/SegmentBase.js.map +1 -1
  114. package/dist/components/segmented-control/SegmentedControl.d.ts.map +1 -1
  115. package/dist/components/segmented-control/SegmentedControl.js +10 -3
  116. package/dist/components/segmented-control/SegmentedControl.js.map +1 -1
  117. package/dist/index.css +28 -12
  118. package/dist/index.css.map +1 -1
  119. package/dist/packages/tapestry-render/dist/{buildComponent-C5PfOgH9.js → buildComponent-DzY2PDMT.js} +23 -23
  120. package/dist/packages/tapestry-render/dist/buildComponent-DzY2PDMT.js.map +1 -0
  121. package/dist/packages/tapestry-render/dist/index.js +2 -2
  122. package/dist/packages/tapestry-render/dist/index.js.map +1 -1
  123. package/dist/packages/tapestry-render/dist/legacy.js +2 -2
  124. package/dist/packages/tapestry-render/dist/legacy.js.map +1 -1
  125. package/dist/product-tokens/giving.css +1 -0
  126. package/dist/reactRender.css +773 -658
  127. package/dist/reactRender.css.map +1 -1
  128. package/dist/reactRender.js +1 -1
  129. package/dist/reactRenderLegacy.css +773 -658
  130. package/dist/reactRenderLegacy.css.map +1 -1
  131. package/dist/reactRenderLegacy.js +1 -1
  132. package/dist/tapestryMount.css +773 -658
  133. package/dist/tapestryMount.css.map +1 -1
  134. package/dist/tapestryMount.js +1 -1
  135. package/dist/tapestryMountLegacy.css +773 -658
  136. package/dist/tapestryMountLegacy.css.map +1 -1
  137. package/dist/tapestryMountLegacy.js +1 -1
  138. package/dist/tokens-dark.css +2 -2
  139. package/dist/tokens-dark.css.map +1 -1
  140. package/dist/tokens.css +11 -10
  141. package/dist/tokens.css.map +1 -1
  142. package/dist/unstable.css +418 -303
  143. package/dist/unstable.css.map +1 -1
  144. package/dist/unstable.js +1 -0
  145. package/dist/unstable.js.map +1 -1
  146. package/package.json +8 -9
  147. package/dist/components/DataTable/useFilterAnnouncement.d.ts +0 -24
  148. package/dist/components/DataTable/useFilterAnnouncement.d.ts.map +0 -1
  149. package/dist/components/DataTable/useFilterAnnouncement.js.map +0 -1
  150. package/dist/packages/tapestry-render/dist/buildComponent-C5PfOgH9.js.map +0 -1
@@ -1,7 +1,13 @@
1
1
  import { useAnnounce } from '../../utilities/useAnnounce.js';
2
- import { useEffect } from 'react';
2
+ import { createContext, useContext, useEffect } from 'react';
3
3
 
4
4
  const LOADING_ANNOUNCEMENT_DELAY_MS = 500;
5
+ /**
6
+ * Turns off every {@link LoadingAnnouncement} inside it while `true`. Use it
7
+ * when focus moves into a field during the load, because the screen reader
8
+ * then speaks the message only after the results appear.
9
+ */
10
+ const SuppressLoadingAnnouncementContext = createContext(false);
5
11
  /**
6
12
  * Announces `message` to screen reader users while a loading indicator is
7
13
  * shown. Render it next to the spinner, only while loading. It waits
@@ -10,12 +16,15 @@ const LOADING_ANNOUNCEMENT_DELAY_MS = 500;
10
16
  */
11
17
  function LoadingAnnouncement({ message }) {
12
18
  const announce = useAnnounce();
19
+ const isSuppressed = useContext(SuppressLoadingAnnouncementContext);
13
20
  useEffect(() => {
21
+ if (isSuppressed)
22
+ return;
14
23
  const timeout = setTimeout(() => announce(message), LOADING_ANNOUNCEMENT_DELAY_MS);
15
24
  return () => clearTimeout(timeout);
16
- }, [announce, message]);
25
+ }, [announce, isSuppressed, message]);
17
26
  return null;
18
27
  }
19
28
 
20
- export { LOADING_ANNOUNCEMENT_DELAY_MS, LoadingAnnouncement };
29
+ export { LOADING_ANNOUNCEMENT_DELAY_MS, LoadingAnnouncement, SuppressLoadingAnnouncementContext };
21
30
  //# sourceMappingURL=LoadingAnnouncement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingAnnouncement.js","sources":["../../../src/components/internal/LoadingAnnouncement.tsx"],"sourcesContent":["import { useAnnounce } from \"@utilities/useAnnounce\"\nimport { useEffect } from \"react\"\n\nexport const LOADING_ANNOUNCEMENT_DELAY_MS = 500\n\n/**\n * Announces `message` to screen reader users while a loading indicator is\n * shown. Render it next to the spinner, only while loading. It waits\n * {@link LOADING_ANNOUNCEMENT_DELAY_MS} after mount, so a fast load says\n * nothing, and it cancels if it unmounts first.\n */\nexport function LoadingAnnouncement({ message }: { message: string }) {\n const announce = useAnnounce()\n\n useEffect(() => {\n const timeout = setTimeout(\n () => announce(message),\n LOADING_ANNOUNCEMENT_DELAY_MS\n )\n return () => clearTimeout(timeout)\n }, [announce, message])\n\n return null\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,6BAA6B,GAAG;AAE7C;;;;;AAKG;AACG,SAAU,mBAAmB,CAAC,EAAE,OAAO,EAAuB,EAAA;AAClE,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;IAE9B,SAAS,CAAC,MAAK;AACb,QAAA,MAAM,OAAO,GAAG,UAAU,CACxB,MAAM,QAAQ,CAAC,OAAO,CAAC,EACvB,6BAA6B,CAC9B;AACD,QAAA,OAAO,MAAM,YAAY,CAAC,OAAO,CAAC;AACpC,IAAA,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAEvB,IAAA,OAAO,IAAI;AACb;;;;"}
1
+ {"version":3,"file":"LoadingAnnouncement.js","sources":["../../../src/components/internal/LoadingAnnouncement.tsx"],"sourcesContent":["import { useAnnounce } from \"@utilities/useAnnounce\"\nimport { createContext, useContext, useEffect } from \"react\"\n\nexport const LOADING_ANNOUNCEMENT_DELAY_MS = 500\n\n/**\n * Turns off every {@link LoadingAnnouncement} inside it while `true`. Use it\n * when focus moves into a field during the load, because the screen reader\n * then speaks the message only after the results appear.\n */\nexport const SuppressLoadingAnnouncementContext = createContext(false)\n\n/**\n * Announces `message` to screen reader users while a loading indicator is\n * shown. Render it next to the spinner, only while loading. It waits\n * {@link LOADING_ANNOUNCEMENT_DELAY_MS} after mount, so a fast load says\n * nothing, and it cancels if it unmounts first.\n */\nexport function LoadingAnnouncement({ message }: { message: string }) {\n const announce = useAnnounce()\n const isSuppressed = useContext(SuppressLoadingAnnouncementContext)\n\n useEffect(() => {\n if (isSuppressed) return\n const timeout = setTimeout(\n () => announce(message),\n LOADING_ANNOUNCEMENT_DELAY_MS\n )\n return () => clearTimeout(timeout)\n }, [announce, isSuppressed, message])\n\n return null\n}\n"],"names":[],"mappings":";;;AAGO,MAAM,6BAA6B,GAAG;AAE7C;;;;AAIG;MACU,kCAAkC,GAAG,aAAa,CAAC,KAAK;AAErE;;;;;AAKG;AACG,SAAU,mBAAmB,CAAC,EAAE,OAAO,EAAuB,EAAA;AAClE,IAAA,MAAM,QAAQ,GAAG,WAAW,EAAE;AAC9B,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC,kCAAkC,CAAC;IAEnE,SAAS,CAAC,MAAK;AACb,QAAA,IAAI,YAAY;YAAE;AAClB,QAAA,MAAM,OAAO,GAAG,UAAU,CACxB,MAAM,QAAQ,CAAC,OAAO,CAAC,EACvB,6BAA6B,CAC9B;AACD,QAAA,OAAO,MAAM,YAAY,CAAC,OAAO,CAAC;IACpC,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;AAErC,IAAA,OAAO,IAAI;AACb;;;;"}
@@ -1,5 +1,5 @@
1
1
  import LoadingSpinner from "./LoadingSpinner";
2
- export { LoadingAnnouncement } from "./LoadingAnnouncement";
2
+ export { LoadingAnnouncement, SuppressLoadingAnnouncementContext, } from "./LoadingAnnouncement";
3
3
  export type { TooltipProps } from "./tooltip";
4
4
  export { Tooltip } from "./tooltip";
5
5
  export { LoadingSpinner };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAC3D,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/internal/index.ts"],"names":[],"mappings":"AAAA,OAAO,cAAc,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EACL,mBAAmB,EACnB,kCAAkC,GACnC,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,cAAc,EAAE,CAAA"}
@@ -24,6 +24,12 @@ export interface ReorderableListBoxProps<T extends {
24
24
  items: readonly T[];
25
25
  /** Accessible label for the list. */
26
26
  label: string;
27
+ /**
28
+ * Called once the items are in the DOM, before paint. React Aria builds
29
+ * the collection after the list renders, so the items land a render later
30
+ * than the list.
31
+ */
32
+ onItemsRendered?: () => void;
27
33
  /**
28
34
  * Called with all items in their new order after the user moves an item.
29
35
  * Omit to turn off reordering.
@@ -1 +1 @@
1
- {"version":3,"file":"ReorderableListBox.d.ts","sourceRoot":"","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA;AAEhF,OAAO,KAAK,EAAE,EAAE,KAAK,YAAY,EAAqB,MAAM,OAAO,CAAA;AAKnE,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAEL,KAAK,+BAA+B,EAErC,MAAM,sCAAsC,CAAA;AAG7C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,+BAA+B,GAChD,CAAC,EAAE,CAgBL;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE;IAC1E,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,CAAA;IACnC,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,GAAG,CAAA;IACxB,mEAAmE;IACnE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAChC,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IACtC,sEAAsE;IACtE,WAAW,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,MAAM,8BAA8B,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,IACjC,+BAA+B,CACjC,YAAY,CAAC,CAAC,CAAC,EACf,uBAAuB,CAAC,CAAC,CAAC,EAC1B,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,MAAM,CACxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,EACtE,QAAQ,EACR,KAAK,EACL,GAAG,SAAS,EACb,EAAE,8BAA8B,CAAC,CAAC,CAAC,qBAcnC;yBAlBe,kBAAkB;;;AA6HlC,MAAM,WAAW,2BAA2B;IAC1C,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,EAAE,EAAE,GAAG,CAAA;IACP;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,SAAS,EACT,EAAE,EACF,MAAM,GACP,EAAE,2BAA2B,qBAW7B;yBAhBe,sBAAsB"}
1
+ {"version":3,"file":"ReorderableListBox.d.ts","sourceRoot":"","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAA;AAEhF,OAAO,KAAK,EAAE,EACZ,KAAK,YAAY,EAIlB,MAAM,OAAO,CAAA;AAKd,OAAO,EACL,KAAK,GAAG,EAGR,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAGlB,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAEL,KAAK,+BAA+B,EAErC,MAAM,sCAAsC,CAAA;AAG7C;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAChD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,+BAA+B,GAChD,CAAC,EAAE,CAgBL;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE;IAC1E,uDAAuD;IACvD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,CAAA;IACnC,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,GAAG,CAAA;IACxB,mEAAmE;IACnE,KAAK,EAAE,SAAS,CAAC,EAAE,CAAA;IACnB,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAA;IACb;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAA;IAChC,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IACtC,sEAAsE;IACtE,WAAW,CAAC,EAAE,GAAG,GAAG,IAAI,CAAA;CACzB;AAED,MAAM,MAAM,8BAA8B,CACxC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,IACjC,+BAA+B,CACjC,YAAY,CAAC,CAAC,CAAC,EACf,uBAAuB,CAAC,CAAC,CAAC,EAC1B,YAAY,GAAG,iBAAiB,GAAG,WAAW,GAAG,MAAM,CACxD,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,GAAG,CAAA;CAAE,EAAE,EACtE,QAAQ,EACR,KAAK,EACL,GAAG,SAAS,EACb,EAAE,8BAA8B,CAAC,CAAC,CAAC,qBAcnC;yBAlBe,kBAAkB;;;AAqIlC,MAAM,WAAW,2BAA2B;IAC1C,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,2BAA2B;IAC3B,EAAE,EAAE,GAAG,CAAA;IACP;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAA;CACpC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,SAAS,EACT,EAAE,EACF,MAAM,GACP,EAAE,2BAA2B,qBAW7B;yBAhBe,sBAAsB"}
@@ -1,5 +1,5 @@
1
1
  import classNames from 'classnames';
2
- import React__default, { useRef, useEffect } from 'react';
2
+ import React__default, { useRef, useLayoutEffect, useEffect } from 'react';
3
3
  import { useLocale } from 'react-aria/I18nProvider';
4
4
  import { ListDropTargetDelegate } from 'react-aria/ListDropTargetDelegate';
5
5
  import { Collection } from 'react-aria-components/Collection';
@@ -49,8 +49,15 @@ ReorderableListBox.displayName = "ReorderableListBox";
49
49
  * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears
50
50
  * `isFocused` while focus stays in the list.
51
51
  */
52
- function ReorderableListBoxWithState({ className, collection, defaultSelectedKey, items, label, onReorder, onSelectionChange, selectedKey, ...restProps }) {
52
+ function ReorderableListBoxWithState({ className, collection, defaultSelectedKey, items, label, onItemsRendered, onReorder, onSelectionChange, selectedKey, ...restProps }) {
53
53
  const listRef = useRef(null);
54
+ // Read when the collection changes, not when the callback does, since the
55
+ // callback can change before the items do.
56
+ const onItemsRenderedRef = useRef(onItemsRendered);
57
+ onItemsRenderedRef.current = onItemsRendered;
58
+ useLayoutEffect(() => {
59
+ onItemsRenderedRef.current?.();
60
+ }, [collection]);
54
61
  const { direction } = useLocale();
55
62
  const handleSelectionChange = (keys) => {
56
63
  if (keys === "all")
@@ -1 +1 @@
1
- {"version":3,"file":"ReorderableListBox.js","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"sourcesContent":["import type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, { type ReactElement, useEffect, useRef } from \"react\"\nimport { useLocale } from \"react-aria/I18nProvider\"\nimport { ListDropTargetDelegate } from \"react-aria/ListDropTargetDelegate\"\nimport { Collection } from \"react-aria-components/Collection\"\nimport { CollectionBuilder } from \"react-aria-components/CollectionBuilder\"\nimport {\n type Key,\n ListBox,\n ListBoxItem,\n type ListBoxItemProps,\n type ListBoxProps,\n ListStateContext,\n type Selection,\n} from \"react-aria-components/ListBox\"\nimport {\n DropIndicator,\n type DroppableCollectionReorderEvent,\n useDragAndDrop,\n} from \"react-aria-components/useDragAndDrop\"\nimport { type ListState, useListState } from \"react-stately/useListState\"\n\n/**\n * Returns `items` with the moved item placed before or after the drop\n * target. Single selection means only one item moves at a time.\n */\nexport function reorderItems<T extends { id: Key }>(\n items: readonly T[],\n { keys, target }: DroppableCollectionReorderEvent\n): T[] {\n const [movedKey] = keys\n const reordered = [...items]\n const fromIndex = reordered.findIndex((item) => item.id === movedKey)\n const hasTarget = reordered.some((item) => item.id === target.key)\n if (fromIndex === -1 || !hasTarget || target.key === movedKey) {\n return reordered\n }\n\n const [movedItem] = reordered.splice(fromIndex, 1)\n const targetIndex = reordered.findIndex((item) => item.id === target.key)\n\n const insertIndex =\n target.dropPosition === \"after\" ? targetIndex + 1 : targetIndex\n reordered.splice(insertIndex, 0, movedItem)\n return reordered\n}\n\nexport interface ReorderableListBoxProps<T extends { id: Key } = { id: Key }> {\n /** Renders each item as a `ReorderableListBoxItem`. */\n children: (item: T) => ReactElement\n /** Custom class name for the list. */\n className?: string\n /** Uncontrolled initially selected item's `id`. */\n defaultSelectedKey?: Key\n /** Items to render, in display order. Each needs a unique `id`. */\n items: readonly T[]\n /** Accessible label for the list. */\n label: string\n /**\n * Called with all items in their new order after the user moves an item.\n * Omit to turn off reordering.\n */\n onReorder?: (items: T[]) => void\n /** Called with the newly selected item's `id`. */\n onSelectionChange?: (key: Key) => void\n /** Controlled selected item's `id`. Pass `null` to select no item. */\n selectedKey?: Key | null\n}\n\nexport type ReorderableListBoxElementProps<\n T extends { id: Key } = { id: Key },\n> = CombineAriaPropsWithCustomProps<\n ListBoxProps<T>,\n ReorderableListBoxProps<T>,\n \"aria-label\" | \"aria-labelledby\" | \"autoFocus\" | \"slot\"\n>\n\n/**\n * A list of items where the user selects one item and cannot clear the\n * selection, and which the user can reorder by drag or by keyboard. Tab\n * enters the list on the selected item. Internal to `DataTable` saved views.\n *\n * @component\n */\nexport function ReorderableListBox<T extends { id: Key } = { id: Key }>({\n children,\n items,\n ...restProps\n}: ReorderableListBoxElementProps<T>) {\n return (\n <CollectionBuilder\n content={<Collection items={items}>{children}</Collection>}\n >\n {(collection) => (\n <ReorderableListBoxWithState\n {...restProps}\n collection={collection}\n items={items}\n />\n )}\n </CollectionBuilder>\n )\n}\n\nReorderableListBox.displayName = \"ReorderableListBox\"\n\ntype ReorderableListBoxWithStateProps<T extends { id: Key }> = Omit<\n ReorderableListBoxElementProps<T>,\n \"children\"\n> & {\n collection: ListState<T>[\"collection\"]\n}\n\n/**\n * Owns the list state and hands it to `ListBox` through `ListStateContext`,\n * the same way React Aria's `Select` does. The drop target delegate needs the\n * state's collection. While DOM focus is outside the list, it keeps the\n * selected item as the tab stop. With no selection, the item that last had\n * focus stays the tab stop, or else the first item. The list itself can\n * then never be the tab stop, which it cannot be while it has no box of its\n * own. It skips this while an item marked `data-popup-open` has a popup,\n * such as a context menu, open, so focus returns to that item, not the\n * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears\n * `isFocused` while focus stays in the list.\n */\nfunction ReorderableListBoxWithState<T extends { id: Key }>({\n className,\n collection,\n defaultSelectedKey,\n items,\n label,\n onReorder,\n onSelectionChange,\n selectedKey,\n ...restProps\n}: ReorderableListBoxWithStateProps<T>) {\n const listRef = useRef<HTMLDivElement>(null)\n const { direction } = useLocale()\n\n const handleSelectionChange = (keys: Selection) => {\n if (keys === \"all\") return\n const [key] = keys\n if (key !== undefined) onSelectionChange?.(key)\n }\n\n const state = useListState<T>({\n collection,\n defaultSelectedKeys:\n defaultSelectedKey === undefined ? undefined : [defaultSelectedKey],\n disallowEmptySelection: true,\n onSelectionChange: handleSelectionChange,\n selectedKeys:\n selectedKey === undefined\n ? undefined\n : selectedKey === null\n ? []\n : [selectedKey],\n selectionMode: \"single\",\n })\n\n const { selectionManager } = state\n useEffect(() => {\n if (listRef.current?.contains(document.activeElement)) return\n if (listRef.current?.querySelector(\"[data-popup-open]\")) return\n const { collection, focusedKey, selectedKeys } = selectionManager\n const [key] = selectedKeys\n const tabStopKey = key ?? focusedKey ?? collection.getFirstKey()\n if (tabStopKey !== null && focusedKey !== tabStopKey) {\n selectionManager.setFocusedKey(tabStopKey)\n }\n }, [selectionManager])\n\n const { dragAndDropHooks } = useDragAndDrop<T>({\n dropTargetDelegate: new ListDropTargetDelegate(state.collection, listRef, {\n direction,\n layout: \"grid\",\n orientation: \"vertical\",\n }),\n getItems: (keys) =>\n [...keys].map((key) => ({\n \"text/plain\": state.collection.getItem(key)?.textValue ?? String(key),\n })),\n onReorder: (event) => {\n const reordered = reorderItems(items, event)\n const isMoved = reordered.some((item, index) => item !== items[index])\n if (isMoved) onReorder?.(reordered)\n },\n renderDropIndicator: (target) => (\n <DropIndicator\n className=\"tds-reorderable-list-box-drop-indicator\"\n target={target}\n />\n ),\n })\n\n return (\n <ListStateContext.Provider value={state}>\n <ListBox\n {...restProps}\n aria-label={label}\n className={classNames(\"tds-reorderable-list-box\", className)}\n dragAndDropHooks={onReorder ? dragAndDropHooks : undefined}\n orientation=\"horizontal\"\n ref={listRef}\n />\n </ListStateContext.Provider>\n )\n}\n\nexport interface ReorderableListBoxItemProps {\n /** Plain-text item label. */\n children: string\n /** Custom class name for the item, such as a pill look. */\n className?: string\n /** Identifies the item. */\n id: Key\n /**\n * Renders the option element in place of the default `<div>`, such as to\n * wrap it in a context menu trigger.\n */\n render?: ListBoxItemProps[\"render\"]\n}\n\n/**\n * A single item within a {@link ReorderableListBox}.\n *\n * @component\n */\nexport function ReorderableListBoxItem({\n children,\n className,\n id,\n render,\n}: ReorderableListBoxItemProps) {\n return (\n <ListBoxItem\n className={classNames(\"tds-reorderable-list-box-item\", className)}\n id={id}\n render={render}\n textValue={children}\n >\n {children}\n </ListBoxItem>\n )\n}\n\nReorderableListBoxItem.displayName = \"ReorderableListBoxItem\"\n"],"names":["React"],"mappings":"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"}
1
+ {"version":3,"file":"ReorderableListBox.js","sources":["../../../../src/components/internal/reorderable-list-box/ReorderableListBox.tsx"],"sourcesContent":["import type { CombineAriaPropsWithCustomProps } from \"@utilities/reactAriaProps\"\nimport classNames from \"classnames\"\nimport React, {\n type ReactElement,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\"\nimport { useLocale } from \"react-aria/I18nProvider\"\nimport { ListDropTargetDelegate } from \"react-aria/ListDropTargetDelegate\"\nimport { Collection } from \"react-aria-components/Collection\"\nimport { CollectionBuilder } from \"react-aria-components/CollectionBuilder\"\nimport {\n type Key,\n ListBox,\n ListBoxItem,\n type ListBoxItemProps,\n type ListBoxProps,\n ListStateContext,\n type Selection,\n} from \"react-aria-components/ListBox\"\nimport {\n DropIndicator,\n type DroppableCollectionReorderEvent,\n useDragAndDrop,\n} from \"react-aria-components/useDragAndDrop\"\nimport { type ListState, useListState } from \"react-stately/useListState\"\n\n/**\n * Returns `items` with the moved item placed before or after the drop\n * target. Single selection means only one item moves at a time.\n */\nexport function reorderItems<T extends { id: Key }>(\n items: readonly T[],\n { keys, target }: DroppableCollectionReorderEvent\n): T[] {\n const [movedKey] = keys\n const reordered = [...items]\n const fromIndex = reordered.findIndex((item) => item.id === movedKey)\n const hasTarget = reordered.some((item) => item.id === target.key)\n if (fromIndex === -1 || !hasTarget || target.key === movedKey) {\n return reordered\n }\n\n const [movedItem] = reordered.splice(fromIndex, 1)\n const targetIndex = reordered.findIndex((item) => item.id === target.key)\n\n const insertIndex =\n target.dropPosition === \"after\" ? targetIndex + 1 : targetIndex\n reordered.splice(insertIndex, 0, movedItem)\n return reordered\n}\n\nexport interface ReorderableListBoxProps<T extends { id: Key } = { id: Key }> {\n /** Renders each item as a `ReorderableListBoxItem`. */\n children: (item: T) => ReactElement\n /** Custom class name for the list. */\n className?: string\n /** Uncontrolled initially selected item's `id`. */\n defaultSelectedKey?: Key\n /** Items to render, in display order. Each needs a unique `id`. */\n items: readonly T[]\n /** Accessible label for the list. */\n label: string\n /**\n * Called once the items are in the DOM, before paint. React Aria builds\n * the collection after the list renders, so the items land a render later\n * than the list.\n */\n onItemsRendered?: () => void\n /**\n * Called with all items in their new order after the user moves an item.\n * Omit to turn off reordering.\n */\n onReorder?: (items: T[]) => void\n /** Called with the newly selected item's `id`. */\n onSelectionChange?: (key: Key) => void\n /** Controlled selected item's `id`. Pass `null` to select no item. */\n selectedKey?: Key | null\n}\n\nexport type ReorderableListBoxElementProps<\n T extends { id: Key } = { id: Key },\n> = CombineAriaPropsWithCustomProps<\n ListBoxProps<T>,\n ReorderableListBoxProps<T>,\n \"aria-label\" | \"aria-labelledby\" | \"autoFocus\" | \"slot\"\n>\n\n/**\n * A list of items where the user selects one item and cannot clear the\n * selection, and which the user can reorder by drag or by keyboard. Tab\n * enters the list on the selected item. Internal to `DataTable` saved views.\n *\n * @component\n */\nexport function ReorderableListBox<T extends { id: Key } = { id: Key }>({\n children,\n items,\n ...restProps\n}: ReorderableListBoxElementProps<T>) {\n return (\n <CollectionBuilder\n content={<Collection items={items}>{children}</Collection>}\n >\n {(collection) => (\n <ReorderableListBoxWithState\n {...restProps}\n collection={collection}\n items={items}\n />\n )}\n </CollectionBuilder>\n )\n}\n\nReorderableListBox.displayName = \"ReorderableListBox\"\n\ntype ReorderableListBoxWithStateProps<T extends { id: Key }> = Omit<\n ReorderableListBoxElementProps<T>,\n \"children\"\n> & {\n collection: ListState<T>[\"collection\"]\n}\n\n/**\n * Owns the list state and hands it to `ListBox` through `ListStateContext`,\n * the same way React Aria's `Select` does. The drop target delegate needs the\n * state's collection. While DOM focus is outside the list, it keeps the\n * selected item as the tab stop. With no selection, the item that last had\n * focus stays the tab stop, or else the first item. The list itself can\n * then never be the tab stop, which it cannot be while it has no box of its\n * own. It skips this while an item marked `data-popup-open` has a popup,\n * such as a context menu, open, so focus returns to that item, not the\n * selected one, when the popup closes. It checks DOM focus, not `isFocused`, because a keyboard drag clears\n * `isFocused` while focus stays in the list.\n */\nfunction ReorderableListBoxWithState<T extends { id: Key }>({\n className,\n collection,\n defaultSelectedKey,\n items,\n label,\n onItemsRendered,\n onReorder,\n onSelectionChange,\n selectedKey,\n ...restProps\n}: ReorderableListBoxWithStateProps<T>) {\n const listRef = useRef<HTMLDivElement>(null)\n // Read when the collection changes, not when the callback does, since the\n // callback can change before the items do.\n const onItemsRenderedRef = useRef(onItemsRendered)\n onItemsRenderedRef.current = onItemsRendered\n useLayoutEffect(() => {\n onItemsRenderedRef.current?.()\n }, [collection])\n const { direction } = useLocale()\n\n const handleSelectionChange = (keys: Selection) => {\n if (keys === \"all\") return\n const [key] = keys\n if (key !== undefined) onSelectionChange?.(key)\n }\n\n const state = useListState<T>({\n collection,\n defaultSelectedKeys:\n defaultSelectedKey === undefined ? undefined : [defaultSelectedKey],\n disallowEmptySelection: true,\n onSelectionChange: handleSelectionChange,\n selectedKeys:\n selectedKey === undefined\n ? undefined\n : selectedKey === null\n ? []\n : [selectedKey],\n selectionMode: \"single\",\n })\n\n const { selectionManager } = state\n useEffect(() => {\n if (listRef.current?.contains(document.activeElement)) return\n if (listRef.current?.querySelector(\"[data-popup-open]\")) return\n const { collection, focusedKey, selectedKeys } = selectionManager\n const [key] = selectedKeys\n const tabStopKey = key ?? focusedKey ?? collection.getFirstKey()\n if (tabStopKey !== null && focusedKey !== tabStopKey) {\n selectionManager.setFocusedKey(tabStopKey)\n }\n }, [selectionManager])\n\n const { dragAndDropHooks } = useDragAndDrop<T>({\n dropTargetDelegate: new ListDropTargetDelegate(state.collection, listRef, {\n direction,\n layout: \"grid\",\n orientation: \"vertical\",\n }),\n getItems: (keys) =>\n [...keys].map((key) => ({\n \"text/plain\": state.collection.getItem(key)?.textValue ?? String(key),\n })),\n onReorder: (event) => {\n const reordered = reorderItems(items, event)\n const isMoved = reordered.some((item, index) => item !== items[index])\n if (isMoved) onReorder?.(reordered)\n },\n renderDropIndicator: (target) => (\n <DropIndicator\n className=\"tds-reorderable-list-box-drop-indicator\"\n target={target}\n />\n ),\n })\n\n return (\n <ListStateContext.Provider value={state}>\n <ListBox\n {...restProps}\n aria-label={label}\n className={classNames(\"tds-reorderable-list-box\", className)}\n dragAndDropHooks={onReorder ? dragAndDropHooks : undefined}\n orientation=\"horizontal\"\n ref={listRef}\n />\n </ListStateContext.Provider>\n )\n}\n\nexport interface ReorderableListBoxItemProps {\n /** Plain-text item label. */\n children: string\n /** Custom class name for the item, such as a pill look. */\n className?: string\n /** Identifies the item. */\n id: Key\n /**\n * Renders the option element in place of the default `<div>`, such as to\n * wrap it in a context menu trigger.\n */\n render?: ListBoxItemProps[\"render\"]\n}\n\n/**\n * A single item within a {@link ReorderableListBox}.\n *\n * @component\n */\nexport function ReorderableListBoxItem({\n children,\n className,\n id,\n render,\n}: ReorderableListBoxItemProps) {\n return (\n <ListBoxItem\n className={classNames(\"tds-reorderable-list-box-item\", className)}\n id={id}\n render={render}\n textValue={children}\n >\n {children}\n </ListBoxItem>\n )\n}\n\nReorderableListBoxItem.displayName = \"ReorderableListBoxItem\"\n"],"names":["React"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type ForwardedRef, type HTMLAttributes, type Ref } from "react";
2
+ /**
3
+ * Wires an element to a surrounding `<Tooltip>`. Merges the tooltip's
4
+ * trigger props and ref into the element's own, and joins the tooltip's
5
+ * `aria-describedby` with the caller's. Outside a `<Tooltip>`, returns the
6
+ * element's own props and ref unchanged.
7
+ */
8
+ export declare function useTooltipTriggerProps<E extends HTMLElement>(props: HTMLAttributes<E>, ref: ForwardedRef<E>, ariaDescribedBy?: string): {
9
+ describedBy: string | undefined;
10
+ mergedProps: HTMLAttributes<E>;
11
+ mergedRef: Ref<E>;
12
+ };
13
+ //# sourceMappingURL=useTooltipTriggerProps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltipTriggerProps.d.ts","sourceRoot":"","sources":["../../../../src/components/internal/tooltip/useTooltipTriggerProps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,GAAG,EAGT,MAAM,OAAO,CAAA;AAMd;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,WAAW,EAC1D,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB;IACD,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;IAC/B,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,CAAA;IAC9B,SAAS,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;CAClB,CAaA"}
@@ -0,0 +1,24 @@
1
+ import { useContext } from 'react';
2
+ import { mergeProps } from 'react-aria/mergeProps';
3
+ import { mergeRefs } from 'react-aria/mergeRefs';
4
+ import { TooltipTriggerContext } from './TooltipTriggerContext.js';
5
+
6
+ /**
7
+ * Wires an element to a surrounding `<Tooltip>`. Merges the tooltip's
8
+ * trigger props and ref into the element's own, and joins the tooltip's
9
+ * `aria-describedby` with the caller's. Outside a `<Tooltip>`, returns the
10
+ * element's own props and ref unchanged.
11
+ */
12
+ function useTooltipTriggerProps(props, ref, ariaDescribedBy) {
13
+ const tooltip = useContext(TooltipTriggerContext);
14
+ const { "aria-describedby": tooltipId, ...tooltipTriggerProps } = tooltip?.triggerProps ?? {};
15
+ const mergedProps = tooltip ? mergeProps(props, tooltipTriggerProps) : props;
16
+ const mergedRef = tooltip
17
+ ? mergeRefs(ref, tooltip.ref)
18
+ : ref;
19
+ const describedBy = [ariaDescribedBy, tooltipId].filter(Boolean).join(" ") || undefined;
20
+ return { describedBy, mergedProps, mergedRef };
21
+ }
22
+
23
+ export { useTooltipTriggerProps };
24
+ //# sourceMappingURL=useTooltipTriggerProps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useTooltipTriggerProps.js","sources":["../../../../src/components/internal/tooltip/useTooltipTriggerProps.ts"],"sourcesContent":["import {\n type ForwardedRef,\n type HTMLAttributes,\n type Ref,\n type RefObject,\n useContext,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { mergeRefs } from \"react-aria/mergeRefs\"\n\nimport { TooltipTriggerContext } from \"./TooltipTriggerContext\"\n\n/**\n * Wires an element to a surrounding `<Tooltip>`. Merges the tooltip's\n * trigger props and ref into the element's own, and joins the tooltip's\n * `aria-describedby` with the caller's. Outside a `<Tooltip>`, returns the\n * element's own props and ref unchanged.\n */\nexport function useTooltipTriggerProps<E extends HTMLElement>(\n props: HTMLAttributes<E>,\n ref: ForwardedRef<E>,\n ariaDescribedBy?: string\n): {\n describedBy: string | undefined\n mergedProps: HTMLAttributes<E>\n mergedRef: Ref<E>\n} {\n const tooltip = useContext(TooltipTriggerContext)\n const { \"aria-describedby\": tooltipId, ...tooltipTriggerProps } =\n tooltip?.triggerProps ?? {}\n\n const mergedProps = tooltip ? mergeProps(props, tooltipTriggerProps) : props\n const mergedRef = tooltip\n ? mergeRefs<E>(ref, tooltip.ref as RefObject<E>)\n : ref\n const describedBy =\n [ariaDescribedBy, tooltipId].filter(Boolean).join(\" \") || undefined\n\n return { describedBy, mergedProps, mergedRef }\n}\n"],"names":[],"mappings":";;;;;AAYA;;;;;AAKG;SACa,sBAAsB,CACpC,KAAwB,EACxB,GAAoB,EACpB,eAAwB,EAAA;AAMxB,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;AAE7B,IAAA,MAAM,WAAW,GAAG,OAAO,GAAG,UAAU,CAAC,KAAK,EAAE,mBAAmB,CAAC,GAAG,KAAK;IAC5E,MAAM,SAAS,GAAG;UACd,SAAS,CAAI,GAAG,EAAE,OAAO,CAAC,GAAmB;UAC7C,GAAG;AACP,IAAA,MAAM,WAAW,GACf,CAAC,eAAe,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,SAAS;AAErE,IAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE;AAChD;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"BaseLink.d.ts","sourceRoot":"","sources":["../../../src/components/link/BaseLink.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAI1B,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAEd,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,OAAO,KAAK,EAAE,EACZ,oBAAoB,EAIrB,MAAM,OAAO,CAAA;AAId,KAAK,iBAAiB,GAAG,kBAAkB,GACzC,IAAI,CACF,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,kBAAkB,GAAG,UAAU,GAAG,MAAM,CAC/C,GAAG;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,CAAA;AAEH,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CACN,iBAAiB,GAAG;IAClB;;;;;OAKG;IACH,OAAO,EAAE,IAAI,CAAA;IACb,IAAI,CAAC,EAAE,KAAK,CAAA;CACb,CACF,GACD,QAAQ,CAAC,iBAAiB,GAAG;IAAE,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEnE,eAAO,MAAM,QAAQ,gGAiEpB,CAAA"}
1
+ {"version":3,"file":"BaseLink.d.ts","sourceRoot":"","sources":["../../../src/components/link/BaseLink.tsx"],"names":[],"mappings":"AAAA,OAAO,mBAAmB,CAAA;AAI1B,OAAO,EACL,kBAAkB,EAGlB,aAAa,EAEd,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AAE/C,OAAO,KAAK,EAAE,EAAE,oBAAoB,EAAc,MAAM,OAAO,CAAA;AAE/D,KAAK,iBAAiB,GAAG,kBAAkB,GACzC,IAAI,CACF,oBAAoB,CAAC,iBAAiB,CAAC,EACvC,MAAM,kBAAkB,GAAG,UAAU,GAAG,MAAM,CAC/C,GAAG;IACF,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACxB,CAAA;AAEH,MAAM,MAAM,oBAAoB,GAC5B,QAAQ,CACN,iBAAiB,GAAG;IAClB;;;;;OAKG;IACH,OAAO,EAAE,IAAI,CAAA;IACb,IAAI,CAAC,EAAE,KAAK,CAAA;CACb,CACF,GACD,QAAQ,CAAC,iBAAiB,GAAG;IAAE,OAAO,CAAC,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEnE,eAAO,MAAM,QAAQ,gGAuDpB,CAAA"}
@@ -1,21 +1,11 @@
1
- import { TooltipTriggerContext } from '../internal/tooltip/TooltipTriggerContext.js';
1
+ import { useTooltipTriggerProps } from '../internal/tooltip/useTooltipTriggerProps.js';
2
2
  import { Slot, Slottable } from '@radix-ui/react-slot';
3
3
  import { COMPONENT_SIZE_CLASS_MAP, COMPONENT_KIND_CLASS_MAP, wrapStringWithSpan } from '../../utilities/buttonLinkShared.js';
4
4
  import classNames from 'classnames';
5
- import React__default, { forwardRef, useContext } from 'react';
6
- import { mergeProps } from 'react-aria/mergeProps';
7
- import { mergeRefs } from 'react-aria/mergeRefs';
5
+ import React__default, { forwardRef } from 'react';
8
6
 
9
7
  const BaseLink = forwardRef(({ asChild = false, "aria-describedby": ariaDescribedBy, children, className, external = false, fullWidth, href, kind, label, prefix, size, suffix, ...restProps }, ref) => {
10
- const tooltip = useContext(TooltipTriggerContext);
11
- const { "aria-describedby": tooltipId, ...tooltipTriggerProps } = tooltip?.triggerProps ?? {};
12
- const mergedProps = tooltip
13
- ? mergeProps(restProps, tooltipTriggerProps)
14
- : restProps;
15
- const mergedRef = tooltip
16
- ? mergeRefs(ref, tooltip.ref)
17
- : ref;
18
- const describedBy = [ariaDescribedBy, tooltipId].filter(Boolean).join(" ") || undefined;
8
+ const { describedBy, mergedProps, mergedRef } = useTooltipTriggerProps(restProps, ref, ariaDescribedBy);
19
9
  const combinedClassName = classNames(kind && "tds-btn", size && size !== "md" && kind && COMPONENT_SIZE_CLASS_MAP[size], kind && COMPONENT_KIND_CLASS_MAP[kind], fullWidth && "tds-btn--full-width", className, { "tds-btn--prefix": prefix, "tds-btn--suffix": suffix });
20
10
  const externalProps = external
21
11
  ? { rel: "noopener noreferrer", target: "_blank" }
@@ -1 +1 @@
1
- {"version":3,"file":"BaseLink.js","sources":["../../../src/components/link/BaseLink.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport { TooltipTriggerContext } from \"@components/internal/tooltip/TooltipTriggerContext\"\nimport { Slot, Slottable } from \"@radix-ui/react-slot\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport { Simplify } from \"@utilities/typeUtils\"\nimport classNames from \"classnames\"\nimport React, {\n AnchorHTMLAttributes,\n forwardRef,\n RefObject,\n useContext,\n} from \"react\"\nimport { mergeProps } from \"react-aria/mergeProps\"\nimport { mergeRefs } from \"react-aria/mergeRefs\"\n\ntype BaseLinkBaseProps = BaseComponentProps &\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof BaseComponentProps | \"children\" | \"href\"\n > & {\n children?: React.ReactNode\n external?: boolean\n kind?: ComponentKind\n label?: React.ReactNode\n }\n\nexport type BaseLinkElementProps =\n | Simplify<\n BaseLinkBaseProps & {\n /**\n * When true, merges the link's styling onto the child element instead\n * of rendering an `<a>`. Use to wrap a router link (e.g. react-router,\n * Next.js) or any link-like component. The `external` prop still\n * applies — it spreads `rel`/`target` onto the child element.\n */\n asChild: true\n href?: never\n }\n >\n | Simplify<BaseLinkBaseProps & { asChild?: false; href: string }>\n\nexport const BaseLink = forwardRef<HTMLAnchorElement, BaseLinkElementProps>(\n (\n {\n asChild = false,\n \"aria-describedby\": ariaDescribedBy,\n children,\n className,\n external = false,\n fullWidth,\n href,\n kind,\n label,\n prefix,\n size,\n suffix,\n ...restProps\n }: BaseLinkElementProps,\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<HTMLAnchorElement>(\n ref,\n tooltip.ref as RefObject<HTMLAnchorElement>\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\" && kind && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n fullWidth && \"tds-btn--full-width\",\n className,\n { \"tds-btn--prefix\": prefix, \"tds-btn--suffix\": suffix }\n )\n\n const externalProps = external\n ? { rel: \"noopener noreferrer\", target: \"_blank\" }\n : {}\n\n const Comp = asChild ? Slot : \"a\"\n\n return (\n <Comp\n {...(!asChild && { href })}\n className={combinedClassName}\n ref={mergedRef}\n {...mergedProps}\n aria-describedby={describedBy}\n {...externalProps}\n >\n {wrapStringWithSpan(prefix)}\n <Slottable>{label || children}</Slottable>\n {wrapStringWithSpan(suffix)}\n </Comp>\n )\n }\n)\n\nBaseLink.displayName = \"BaseLink\"\n"],"names":["React"],"mappings":";;;;;;;;MAgDa,QAAQ,GAAG,UAAU,CAChC,CACE,EACE,OAAO,GAAG,KAAK,EACf,kBAAkB,EAAE,eAAe,EACnC,QAAQ,EACR,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAM,EACN,IAAI,EACJ,MAAM,EACN,GAAG,SAAS,EACS,EACvB,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,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAC/D,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,IAAI,qBAAqB,EAClC,SAAS,EACT,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CACzD;IAED,MAAM,aAAa,GAAG;UAClB,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ;UAC9C,EAAE;IAEN,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,GAAG,GAAG;IAEjC,QACEA,cAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAA,IACE,CAAC,OAAO,IAAI,EAAE,IAAI,EAAE,CAAC,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,SAAS,EAAA,GACV,WAAW,EAAA,kBAAA,EACG,WAAW,EAAA,GACzB,aAAa,EAAA;QAEhB,kBAAkB,CAAC,MAAM,CAAC;AAC3B,QAAAA,cAAA,CAAA,aAAA,CAAC,SAAS,EAAA,IAAA,EAAE,KAAK,IAAI,QAAQ,CAAa;AACzC,QAAA,kBAAkB,CAAC,MAAM,CAAC,CACtB;AAEX,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
1
+ {"version":3,"file":"BaseLink.js","sources":["../../../src/components/link/BaseLink.tsx"],"sourcesContent":["import \"../button/btn.css\"\n\nimport { useTooltipTriggerProps } from \"@components/internal/tooltip/useTooltipTriggerProps\"\nimport { Slot, Slottable } from \"@radix-ui/react-slot\"\nimport {\n BaseComponentProps,\n COMPONENT_KIND_CLASS_MAP,\n COMPONENT_SIZE_CLASS_MAP,\n ComponentKind,\n wrapStringWithSpan,\n} from \"@utilities/buttonLinkShared\"\nimport { Simplify } from \"@utilities/typeUtils\"\nimport classNames from \"classnames\"\nimport React, { AnchorHTMLAttributes, forwardRef } from \"react\"\n\ntype BaseLinkBaseProps = BaseComponentProps &\n Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n keyof BaseComponentProps | \"children\" | \"href\"\n > & {\n children?: React.ReactNode\n external?: boolean\n kind?: ComponentKind\n label?: React.ReactNode\n }\n\nexport type BaseLinkElementProps =\n | Simplify<\n BaseLinkBaseProps & {\n /**\n * When true, merges the link's styling onto the child element instead\n * of rendering an `<a>`. Use to wrap a router link (e.g. react-router,\n * Next.js) or any link-like component. The `external` prop still\n * applies — it spreads `rel`/`target` onto the child element.\n */\n asChild: true\n href?: never\n }\n >\n | Simplify<BaseLinkBaseProps & { asChild?: false; href: string }>\n\nexport const BaseLink = forwardRef<HTMLAnchorElement, BaseLinkElementProps>(\n (\n {\n asChild = false,\n \"aria-describedby\": ariaDescribedBy,\n children,\n className,\n external = false,\n fullWidth,\n href,\n kind,\n label,\n prefix,\n size,\n suffix,\n ...restProps\n }: BaseLinkElementProps,\n ref\n ) => {\n const { describedBy, mergedProps, mergedRef } = useTooltipTriggerProps(\n restProps,\n ref,\n ariaDescribedBy\n )\n\n const combinedClassName = classNames(\n kind && \"tds-btn\",\n size && size !== \"md\" && kind && COMPONENT_SIZE_CLASS_MAP[size],\n kind && COMPONENT_KIND_CLASS_MAP[kind],\n fullWidth && \"tds-btn--full-width\",\n className,\n { \"tds-btn--prefix\": prefix, \"tds-btn--suffix\": suffix }\n )\n\n const externalProps = external\n ? { rel: \"noopener noreferrer\", target: \"_blank\" }\n : {}\n\n const Comp = asChild ? Slot : \"a\"\n\n return (\n <Comp\n {...(!asChild && { href })}\n className={combinedClassName}\n ref={mergedRef}\n {...mergedProps}\n aria-describedby={describedBy}\n {...externalProps}\n >\n {wrapStringWithSpan(prefix)}\n <Slottable>{label || children}</Slottable>\n {wrapStringWithSpan(suffix)}\n </Comp>\n )\n }\n)\n\nBaseLink.displayName = \"BaseLink\"\n"],"names":["React"],"mappings":";;;;;;MAyCa,QAAQ,GAAG,UAAU,CAChC,CACE,EACE,OAAO,GAAG,KAAK,EACf,kBAAkB,EAAE,eAAe,EACnC,QAAQ,EACR,SAAS,EACT,QAAQ,GAAG,KAAK,EAChB,SAAS,EACT,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAM,EACN,IAAI,EACJ,MAAM,EACN,GAAG,SAAS,EACS,EACvB,GAAG,KACD;AACF,IAAA,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,sBAAsB,CACpE,SAAS,EACT,GAAG,EACH,eAAe,CAChB;IAED,MAAM,iBAAiB,GAAG,UAAU,CAClC,IAAI,IAAI,SAAS,EACjB,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EAC/D,IAAI,IAAI,wBAAwB,CAAC,IAAI,CAAC,EACtC,SAAS,IAAI,qBAAqB,EAClC,SAAS,EACT,EAAE,iBAAiB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,CACzD;IAED,MAAM,aAAa,GAAG;UAClB,EAAE,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,QAAQ;UAC9C,EAAE;IAEN,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,GAAG,GAAG;IAEjC,QACEA,cAAA,CAAA,aAAA,CAAC,IAAI,EAAA,EAAA,IACE,CAAC,OAAO,IAAI,EAAE,IAAI,EAAE,CAAC,EAC1B,SAAS,EAAE,iBAAiB,EAC5B,GAAG,EAAE,SAAS,EAAA,GACV,WAAW,EAAA,kBAAA,EACG,WAAW,EAAA,GACzB,aAAa,EAAA;QAEhB,kBAAkB,CAAC,MAAM,CAAC;AAC3B,QAAAA,cAAA,CAAA,aAAA,CAAC,SAAS,EAAA,IAAA,EAAE,KAAK,IAAI,QAAQ,CAAa;AACzC,QAAA,kBAAkB,CAAC,MAAM,CAAC,CACtB;AAEX,CAAC;AAGH,QAAQ,CAAC,WAAW,GAAG,UAAU;;;;"}
@@ -1,9 +1,8 @@
1
1
  import "./index.css";
2
+ import { type TooltipPlacement } from "../internal/tooltip";
2
3
  import React, { type ButtonHTMLAttributes } from "react";
3
4
  import { type SegmentKind } from "./SegmentBase";
4
- export interface IconSegmentProps {
5
- /** Accessible label — required since there's no visible text. */
6
- "aria-label": string;
5
+ type IconSegmentSharedProps = {
7
6
  /** Disables this item only. */
8
7
  disabled?: boolean;
9
8
  /** The icon to display. */
@@ -12,17 +11,40 @@ export interface IconSegmentProps {
12
11
  * This segment's color when selected. Default `'interaction-subtle'`.
13
12
  */
14
13
  kind?: SegmentKind;
14
+ /** Where the tooltip renders relative to the segment. Default `"bottom"`. Has no effect without `tooltip`. */
15
+ tooltipPlacement?: TooltipPlacement;
15
16
  /** Unique identifier for this item. */
16
17
  value: string;
17
- }
18
- export type IconSegmentElementProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof IconSegmentProps | "aria-checked" | "children" | "onClick" | "onKeyDown" | "role" | "tabIndex" | "type"> & IconSegmentProps;
18
+ };
19
+ type IconSegmentTooltipProps = {
20
+ /** Accessible label. Required for icon-only segments to provide context about the segment's purpose. Not required when `tooltip` is set. When both are set, this is the name and the tooltip is visual only. */
21
+ "aria-label"?: string;
22
+ /** 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 `"Grid"`, aria-label `"Grid view"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */
23
+ tooltip: string;
24
+ };
25
+ type IconSegmentAriaLabelProps = {
26
+ /** Accessible label. Required for icon-only segments to provide context about the segment's purpose. Not required when `tooltip` is set. When both are set, this is the name and the tooltip is visual only. */
27
+ "aria-label": string;
28
+ /** 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 `"Grid"`, aria-label `"Grid view"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */
29
+ tooltip?: string;
30
+ };
31
+ /**
32
+ * An icon-only segment needs a name: `aria-label`, `tooltip`, or both.
33
+ * `IconSegmentAriaLabelProps` is declared last so that a missing name
34
+ * reports "aria-label is missing", not "tooltip is missing".
35
+ */
36
+ type IconSegmentNameProps = IconSegmentAriaLabelProps | IconSegmentTooltipProps;
37
+ export type IconSegmentProps = IconSegmentSharedProps & IconSegmentNameProps;
38
+ export type IconSegmentElementProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof IconSegmentSharedProps | "aria-checked" | "aria-label" | "children" | "onClick" | "onKeyDown" | "role" | "tabIndex" | "tooltip" | "type"> & IconSegmentProps;
19
39
  /**
20
40
  * An icon-only item within a `SegmentedControl`, mirroring `IconButton`'s
21
- * shape. Must be rendered as a direct child of `SegmentedControl` — it reads
22
- * selection state, group `disabled`, and roving tabindex from that context.
41
+ * shape. Requires an `aria-label` or `tooltip` for accessibility. Must be
42
+ * rendered as a direct child of `SegmentedControl` — it reads selection
43
+ * state, group `disabled`, and roving tabindex from that context.
23
44
  *
24
45
  * @component
25
46
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}
26
47
  */
27
- export declare const IconSegment: React.ForwardRefExoticComponent<Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "children" | "type" | "tabIndex" | "role" | "aria-checked" | "onKeyDown" | "onClick" | keyof IconSegmentProps> & IconSegmentProps & React.RefAttributes<HTMLButtonElement>>;
48
+ export declare const IconSegment: React.ForwardRefExoticComponent<IconSegmentElementProps & React.RefAttributes<HTMLButtonElement>>;
49
+ export {};
28
50
  //# sourceMappingURL=IconSegment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"IconSegment.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/IconSegment.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,EAAE,KAAK,oBAAoB,EAAc,MAAM,OAAO,CAAA;AAEpE,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAE7D,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAA;IACpB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2BAA2B;IAC3B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB;;OAEG;IACH,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,oBAAoB,CAAC,iBAAiB,CAAC,EACrC,MAAM,gBAAgB,GACtB,cAAc,GACd,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,UAAU,GACV,MAAM,CACT,GACC,gBAAgB,CAAA;AAElB;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,iQAKtB,CAAA"}
1
+ {"version":3,"file":"IconSegment.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/IconSegment.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAAW,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAC7E,OAAO,KAAK,EAAE,EAAE,KAAK,oBAAoB,EAAc,MAAM,OAAO,CAAA;AAEpE,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,eAAe,CAAA;AAE7D,KAAK,sBAAsB,GAAG;IAC5B,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2BAA2B;IAC3B,IAAI,EAAE,KAAK,CAAC,SAAS,CAAA;IACrB;;OAEG;IACH,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,8GAA8G;IAC9G,gBAAgB,CAAC,EAAE,gBAAgB,CAAA;IACnC,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,KAAK,uBAAuB,GAAG;IAC7B,gNAAgN;IAChN,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6RAA6R;IAC7R,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,KAAK,yBAAyB,GAAG;IAC/B,gNAAgN;IAChN,YAAY,EAAE,MAAM,CAAA;IACpB,6RAA6R;IAC7R,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED;;;;GAIG;AACH,KAAK,oBAAoB,GAAG,yBAAyB,GAAG,uBAAuB,CAAA;AAE/E,MAAM,MAAM,gBAAgB,GAAG,sBAAsB,GAAG,oBAAoB,CAAA;AAE5E,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,oBAAoB,CAAC,iBAAiB,CAAC,EACrC,MAAM,sBAAsB,GAC5B,cAAc,GACd,YAAY,GACZ,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,UAAU,GACV,SAAS,GACT,MAAM,CACT,GACC,gBAAgB,CAAA;AAElB;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,mGAiCtB,CAAA"}
@@ -1,15 +1,22 @@
1
+ import { Tooltip } from '../internal/tooltip/Tooltip.js';
1
2
  import React__default, { forwardRef } from 'react';
2
3
  import { SegmentBase } from './SegmentBase.js';
3
4
 
4
5
  /**
5
6
  * An icon-only item within a `SegmentedControl`, mirroring `IconButton`'s
6
- * shape. Must be rendered as a direct child of `SegmentedControl` — it reads
7
- * selection state, group `disabled`, and roving tabindex from that context.
7
+ * shape. Requires an `aria-label` or `tooltip` for accessibility. Must be
8
+ * rendered as a direct child of `SegmentedControl` — it reads selection
9
+ * state, group `disabled`, and roving tabindex from that context.
8
10
  *
9
11
  * @component
10
12
  * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}
11
13
  */
12
- const IconSegment = forwardRef(function IconSegment({ icon, ...restProps }, ref) {
14
+ const IconSegment = forwardRef(function IconSegment({ icon, tooltip, tooltipPlacement = "bottom", ...restProps }, ref) {
15
+ if (tooltip) {
16
+ const { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...segmentProps } = restProps;
17
+ return (React__default.createElement(Tooltip, { content: tooltip, placement: tooltipPlacement, visualOnly: true },
18
+ React__default.createElement(SegmentBase, { ...segmentProps, "aria-label": ariaLabel || tooltip, content: icon, iconOnly: true, ref: ref })));
19
+ }
13
20
  return React__default.createElement(SegmentBase, { ...restProps, content: icon, iconOnly: true, ref: ref });
14
21
  });
15
22
  IconSegment.displayName = "IconSegment";
@@ -1 +1 @@
1
- {"version":3,"file":"IconSegment.js","sources":["../../../src/components/segmented-control/IconSegment.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport React, { type ButtonHTMLAttributes, forwardRef } from \"react\"\n\nimport { SegmentBase, type SegmentKind } from \"./SegmentBase\"\n\nexport interface IconSegmentProps {\n /** Accessible label — required since there's no visible text. */\n \"aria-label\": string\n /** Disables this item only. */\n disabled?: boolean\n /** The icon to display. */\n icon: React.ReactNode\n /**\n * This segment's color when selected. Default `'interaction-subtle'`.\n */\n kind?: SegmentKind\n /** Unique identifier for this item. */\n value: string\n}\n\nexport type IconSegmentElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n | keyof IconSegmentProps\n | \"aria-checked\"\n | \"children\"\n | \"onClick\"\n | \"onKeyDown\"\n | \"role\"\n | \"tabIndex\"\n | \"type\"\n> &\n IconSegmentProps\n\n/**\n * An icon-only item within a `SegmentedControl`, mirroring `IconButton`'s\n * shape. Must be rendered as a direct child of `SegmentedControl` — it reads\n * selection state, group `disabled`, and roving tabindex from that context.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}\n */\nexport const IconSegment = forwardRef<\n HTMLButtonElement,\n IconSegmentElementProps\n>(function IconSegment({ icon, ...restProps }: IconSegmentElementProps, ref) {\n return <SegmentBase {...restProps} content={icon} iconOnly ref={ref} />\n})\n\nIconSegment.displayName = \"IconSegment\"\n"],"names":["React"],"mappings":";;;AAkCA;;;;;;;AAOG;AACI,MAAM,WAAW,GAAG,UAAU,CAGnC,SAAS,WAAW,CAAC,EAAE,IAAI,EAAE,GAAG,SAAS,EAA2B,EAAE,GAAG,EAAA;AACzE,IAAA,OAAOA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,GAAK,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAA,IAAA,EAAC,GAAG,EAAE,GAAG,GAAI;AACzE,CAAC;AAED,WAAW,CAAC,WAAW,GAAG,aAAa;;;;"}
1
+ {"version":3,"file":"IconSegment.js","sources":["../../../src/components/segmented-control/IconSegment.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { Tooltip, type TooltipPlacement } from \"@components/internal/tooltip\"\nimport React, { type ButtonHTMLAttributes, forwardRef } from \"react\"\n\nimport { SegmentBase, type SegmentKind } from \"./SegmentBase\"\n\ntype IconSegmentSharedProps = {\n /** Disables this item only. */\n disabled?: boolean\n /** The icon to display. */\n icon: React.ReactNode\n /**\n * This segment's color when selected. Default `'interaction-subtle'`.\n */\n kind?: SegmentKind\n /** Where the tooltip renders relative to the segment. Default `\"bottom\"`. Has no effect without `tooltip`. */\n tooltipPlacement?: TooltipPlacement\n /** Unique identifier for this item. */\n value: string\n}\n\ntype IconSegmentTooltipProps = {\n /** Accessible label. Required for icon-only segments to provide context about the segment's purpose. Not required when `tooltip` is set. When both are set, this is the name and the tooltip is visual only. */\n \"aria-label\"?: string\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 `\"Grid\"`, aria-label `\"Grid view\"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */\n tooltip: string\n}\n\ntype IconSegmentAriaLabelProps = {\n /** Accessible label. Required for icon-only segments to provide context about the segment's purpose. Not required when `tooltip` is set. When both are set, this is the name and the tooltip is visual only. */\n \"aria-label\": string\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 `\"Grid\"`, aria-label `\"Grid view\"`). The tooltip itself is hidden from screen readers. Ignores `aria-labelledby`. */\n tooltip?: string\n}\n\n/**\n * An icon-only segment needs a name: `aria-label`, `tooltip`, or both.\n * `IconSegmentAriaLabelProps` is declared last so that a missing name\n * reports \"aria-label is missing\", not \"tooltip is missing\".\n */\ntype IconSegmentNameProps = IconSegmentAriaLabelProps | IconSegmentTooltipProps\n\nexport type IconSegmentProps = IconSegmentSharedProps & IconSegmentNameProps\n\nexport type IconSegmentElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n | keyof IconSegmentSharedProps\n | \"aria-checked\"\n | \"aria-label\"\n | \"children\"\n | \"onClick\"\n | \"onKeyDown\"\n | \"role\"\n | \"tabIndex\"\n | \"tooltip\"\n | \"type\"\n> &\n IconSegmentProps\n\n/**\n * An icon-only item within a `SegmentedControl`, mirroring `IconButton`'s\n * shape. Requires an `aria-label` or `tooltip` for accessibility. Must be\n * rendered as a direct child of `SegmentedControl` — it reads selection\n * state, group `disabled`, and roving tabindex from that context.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}\n */\nexport const IconSegment = forwardRef<\n HTMLButtonElement,\n IconSegmentElementProps\n>(function IconSegment(\n {\n icon,\n tooltip,\n tooltipPlacement = \"bottom\",\n ...restProps\n }: IconSegmentElementProps,\n ref\n) {\n if (tooltip) {\n const {\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...segmentProps\n } = restProps\n\n return (\n <Tooltip content={tooltip} placement={tooltipPlacement} visualOnly>\n <SegmentBase\n {...segmentProps}\n aria-label={ariaLabel || tooltip}\n content={icon}\n iconOnly\n ref={ref}\n />\n </Tooltip>\n )\n }\n\n return <SegmentBase {...restProps} content={icon} iconOnly ref={ref} />\n})\n\nIconSegment.displayName = \"IconSegment\"\n"],"names":["React"],"mappings":";;;;AA4DA;;;;;;;;AAQG;MACU,WAAW,GAAG,UAAU,CAGnC,SAAS,WAAW,CACpB,EACE,IAAI,EACJ,OAAO,EACP,gBAAgB,GAAG,QAAQ,EAC3B,GAAG,SAAS,EACY,EAC1B,GAAG,EAAA;IAEH,IAAI,OAAO,EAAE;AACX,QAAA,MAAM,EACJ,YAAY,EAAE,SAAS,EACvB,iBAAiB,EAAE,cAAc,EACjC,GAAG,YAAY,EAChB,GAAG,SAAS;AAEb,QAAA,QACEA,cAAA,CAAA,aAAA,CAAC,OAAO,EAAA,EAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,UAAU,EAAA,IAAA,EAAA;YAChEA,cAAA,CAAA,aAAA,CAAC,WAAW,OACN,YAAY,EAAA,YAAA,EACJ,SAAS,IAAI,OAAO,EAChC,OAAO,EAAE,IAAI,EACb,QAAQ,QACR,GAAG,EAAE,GAAG,EAAA,CACR,CACM;IAEd;AAEA,IAAA,OAAOA,cAAA,CAAA,aAAA,CAAC,WAAW,EAAA,EAAA,GAAK,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAA,IAAA,EAAC,GAAG,EAAE,GAAG,GAAI;AACzE,CAAC;AAED,WAAW,CAAC,WAAW,GAAG,aAAa;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentBase.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/SegmentBase.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,KAAK,oBAAoB,EAA0B,MAAM,OAAO,CAAA;AAIhF,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,SAAS,GACT,SAAS,CAAA;AAWb,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,oBAAoB,CAAC,iBAAiB,CAAC,EACrC,MAAM,gBAAgB,GACtB,cAAc,GACd,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,UAAU,GACV,MAAM,CACT,GACC,gBAAgB,CAAA;AAElB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,iQAuFtB,CAAA"}
1
+ {"version":3,"file":"SegmentBase.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/SegmentBase.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,KAAK,oBAAoB,EAA0B,MAAM,OAAO,CAAA;AAIhF,MAAM,MAAM,WAAW,GACnB,OAAO,GACP,kBAAkB,GAClB,oBAAoB,GACpB,gBAAgB,GAChB,SAAS,GACT,SAAS,CAAA;AAWb,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,KAAK,CAAC,SAAS,CAAA;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,uBAAuB,GAAG,IAAI,CACxC,oBAAoB,CAAC,iBAAiB,CAAC,EACrC,MAAM,gBAAgB,GACtB,cAAc,GACd,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,UAAU,GACV,MAAM,CACT,GACC,gBAAgB,CAAA;AAElB;;;;;GAKG;AACH,eAAO,MAAM,WAAW,iQA6FtB,CAAA"}
@@ -1,3 +1,4 @@
1
+ import { useTooltipTriggerProps } from '../internal/tooltip/useTooltipTriggerProps.js';
1
2
  import classNames from 'classnames';
2
3
  import React__default, { forwardRef, useContext } from 'react';
3
4
  import { SegmentedControlContext } from './SegmentedControlContext.js';
@@ -16,7 +17,7 @@ const ARROW_KEYS = [
16
17
  * and disabled propagation all live here so the two public components only
17
18
  * differ in what they render inside the button.
18
19
  */
19
- const SegmentBase = forwardRef(function SegmentBase({ className, content, disabled = false, iconOnly = false, kind = "interaction-subtle", value, ...restProps }, ref) {
20
+ const SegmentBase = forwardRef(function SegmentBase({ "aria-describedby": ariaDescribedBy, className, content, disabled = false, iconOnly = false, kind = "interaction-subtle", value, ...restProps }, ref) {
20
21
  const context = useContext(SegmentedControlContext);
21
22
  const isDisabled = disabled || (context?.disabled ?? false);
22
23
  const isChecked = context?.value === value;
@@ -62,7 +63,8 @@ const SegmentBase = forwardRef(function SegmentBase({ className, content, disabl
62
63
  if (nextValue)
63
64
  context?.onSelect(nextValue);
64
65
  };
65
- return (React__default.createElement("button", { ...restProps, "aria-checked": isChecked ? "true" : "false", className: combinedClassName, "data-segment-value": value, disabled: isDisabled, onClick: handleClick, onKeyDown: handleKeyDown, ref: ref, role: "radio", tabIndex: value === context?.tabbableValue ? 0 : -1, type: "button" }, content));
66
+ const { describedBy, mergedProps, mergedRef } = useTooltipTriggerProps({ ...restProps, onClick: handleClick, onKeyDown: handleKeyDown }, ref, ariaDescribedBy);
67
+ return (React__default.createElement("button", { ...mergedProps, "aria-checked": isChecked ? "true" : "false", "aria-describedby": describedBy, className: combinedClassName, "data-segment-value": value, disabled: isDisabled, ref: mergedRef, role: "radio", tabIndex: value === context?.tabbableValue ? 0 : -1, type: "button" }, content));
66
68
  });
67
69
  SegmentBase.displayName = "SegmentBase";
68
70
 
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentBase.js","sources":["../../../src/components/segmented-control/SegmentBase.tsx"],"sourcesContent":["import classNames from \"classnames\"\nimport React, { type ButtonHTMLAttributes, forwardRef, useContext } from \"react\"\n\nimport { SegmentedControlContext } from \"./SegmentedControlContext\"\n\nexport type SegmentKind =\n | \"error\"\n | \"interaction-bold\"\n | \"interaction-subtle\"\n | \"neutral-subtle\"\n | \"success\"\n | \"warning\"\n\nconst ARROW_KEYS = [\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n]\n\nexport interface SegmentBaseProps {\n content: React.ReactNode\n disabled?: boolean\n iconOnly?: boolean\n kind?: SegmentKind\n value: string\n}\n\nexport type SegmentBaseElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n | keyof SegmentBaseProps\n | \"aria-checked\"\n | \"children\"\n | \"onClick\"\n | \"onKeyDown\"\n | \"role\"\n | \"tabIndex\"\n | \"type\"\n> &\n SegmentBaseProps\n\n/**\n * Shared `role=\"radio\"` button implementation for `Segment` and\n * `IconSegment` — selection state, roving tabindex, arrow-key navigation,\n * and disabled propagation all live here so the two public components only\n * differ in what they render inside the button.\n */\nexport const SegmentBase = forwardRef<\n HTMLButtonElement,\n SegmentBaseElementProps\n>(function SegmentBase(\n {\n className,\n content,\n disabled = false,\n iconOnly = false,\n kind = \"interaction-subtle\",\n value,\n ...restProps\n }: SegmentBaseElementProps,\n ref\n) {\n const context = useContext(SegmentedControlContext)\n const isDisabled = disabled || (context?.disabled ?? false)\n const isChecked = context?.value === value\n\n const combinedClassName = classNames(\n \"tds-segmented-control-segment\",\n iconOnly && \"tds-segmented-control-segment--icon-only\",\n `tds-segmented-control-segment--${kind}`,\n className\n )\n\n const handleClick = () => {\n if (isDisabled) return\n context?.onSelect(value)\n }\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!ARROW_KEYS.includes(event.key)) return\n\n const track = event.currentTarget.closest('[role=\"radiogroup\"]')\n if (!track) return\n\n const segments = Array.from(\n track.querySelectorAll<HTMLButtonElement>('[role=\"radio\"]:not(:disabled)')\n )\n const currentIndex = segments.indexOf(event.currentTarget)\n if (currentIndex === -1) return\n\n let nextIndex = currentIndex\n switch (event.key) {\n case \"ArrowLeft\":\n case \"ArrowUp\":\n nextIndex = currentIndex === 0 ? segments.length - 1 : currentIndex - 1\n break\n case \"ArrowRight\":\n case \"ArrowDown\":\n nextIndex = currentIndex === segments.length - 1 ? 0 : currentIndex + 1\n break\n case \"Home\":\n nextIndex = 0\n break\n case \"End\":\n nextIndex = segments.length - 1\n break\n }\n\n const nextSegment = segments[nextIndex]\n if (!nextSegment || nextSegment === event.currentTarget) return\n\n event.preventDefault()\n nextSegment.focus()\n const nextValue = nextSegment.dataset.segmentValue\n if (nextValue) context?.onSelect(nextValue)\n }\n\n return (\n <button\n {...restProps}\n aria-checked={isChecked ? \"true\" : \"false\"}\n className={combinedClassName}\n data-segment-value={value}\n disabled={isDisabled}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n ref={ref}\n role=\"radio\"\n tabIndex={value === context?.tabbableValue ? 0 : -1}\n type=\"button\"\n >\n {content}\n </button>\n )\n})\n\nSegmentBase.displayName = \"SegmentBase\"\n"],"names":["React"],"mappings":";;;;AAaA,MAAM,UAAU,GAAG;IACjB,WAAW;IACX,YAAY;IACZ,SAAS;IACT,WAAW;IACX,MAAM;IACN,KAAK;CACN;AAuBD;;;;;AAKG;AACI,MAAM,WAAW,GAAG,UAAU,CAGnC,SAAS,WAAW,CACpB,EACE,SAAS,EACT,OAAO,EACP,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,EAChB,IAAI,GAAG,oBAAoB,EAC3B,KAAK,EACL,GAAG,SAAS,EACY,EAC1B,GAAG,EAAA;AAEH,IAAA,MAAM,OAAO,GAAG,UAAU,CAAC,uBAAuB,CAAC;IACnD,MAAM,UAAU,GAAG,QAAQ,KAAK,OAAO,EAAE,QAAQ,IAAI,KAAK,CAAC;AAC3D,IAAA,MAAM,SAAS,GAAG,OAAO,EAAE,KAAK,KAAK,KAAK;AAE1C,IAAA,MAAM,iBAAiB,GAAG,UAAU,CAClC,+BAA+B,EAC/B,QAAQ,IAAI,0CAA0C,EACtD,kCAAkC,IAAI,CAAA,CAAE,EACxC,SAAS,CACV;IAED,MAAM,WAAW,GAAG,MAAK;AACvB,QAAA,IAAI,UAAU;YAAE;AAChB,QAAA,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC;AAC1B,IAAA,CAAC;AAED,IAAA,MAAM,aAAa,GAAG,CAAC,KAA6C,KAAI;QACtE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC;YAAE;QAErC,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,qBAAqB,CAAC;AAChE,QAAA,IAAI,CAAC,KAAK;YAAE;AAEZ,QAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CACzB,KAAK,CAAC,gBAAgB,CAAoB,+BAA+B,CAAC,CAC3E;QACD,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC;QAC1D,IAAI,YAAY,KAAK,EAAE;YAAE;QAEzB,IAAI,SAAS,GAAG,YAAY;AAC5B,QAAA,QAAQ,KAAK,CAAC,GAAG;AACf,YAAA,KAAK,WAAW;AAChB,YAAA,KAAK,SAAS;AACZ,gBAAA,SAAS,GAAG,YAAY,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC;gBACvE;AACF,YAAA,KAAK,YAAY;AACjB,YAAA,KAAK,WAAW;AACd,gBAAA,SAAS,GAAG,YAAY,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,GAAG,CAAC;gBACvE;AACF,YAAA,KAAK,MAAM;gBACT,SAAS,GAAG,CAAC;gBACb;AACF,YAAA,KAAK,KAAK;AACR,gBAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC;gBAC/B;;AAGJ,QAAA,MAAM,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC;AACvC,QAAA,IAAI,CAAC,WAAW,IAAI,WAAW,KAAK,KAAK,CAAC,aAAa;YAAE;QAEzD,KAAK,CAAC,cAAc,EAAE;QACtB,WAAW,CAAC,KAAK,EAAE;AACnB,QAAA,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,YAAY;AAClD,QAAA,IAAI,SAAS;AAAE,YAAA,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC;AAC7C,IAAA,CAAC;AAED,IAAA,QACEA,cAAA,CAAA,aAAA,CAAA,QAAA,EAAA,EAAA,GACM,SAAS,EAAA,cAAA,EACC,SAAS,GAAG,MAAM,GAAG,OAAO,EAC1C,SAAS,EAAE,iBAAiB,EAAA,oBAAA,EACR,KAAK,EACzB,QAAQ,EAAE,UAAU,EACpB,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,OAAO,EACZ,QAAQ,EAAE,KAAK,KAAK,OAAO,EAAE,aAAa,GAAG,CAAC,GAAG,EAAE,EACnD,IAAI,EAAC,QAAQ,EAAA,EAEZ,OAAO,CACD;AAEb,CAAC;AAED,WAAW,CAAC,WAAW,GAAG,aAAa;;;;"}
1
+ {"version":3,"file":"SegmentBase.js","sources":["../../../src/components/segmented-control/SegmentBase.tsx"],"sourcesContent":["import { useTooltipTriggerProps } from \"@components/internal/tooltip/useTooltipTriggerProps\"\nimport classNames from \"classnames\"\nimport React, { type ButtonHTMLAttributes, forwardRef, useContext } from \"react\"\n\nimport { SegmentedControlContext } from \"./SegmentedControlContext\"\n\nexport type SegmentKind =\n | \"error\"\n | \"interaction-bold\"\n | \"interaction-subtle\"\n | \"neutral-subtle\"\n | \"success\"\n | \"warning\"\n\nconst ARROW_KEYS = [\n \"ArrowLeft\",\n \"ArrowRight\",\n \"ArrowUp\",\n \"ArrowDown\",\n \"Home\",\n \"End\",\n]\n\nexport interface SegmentBaseProps {\n content: React.ReactNode\n disabled?: boolean\n iconOnly?: boolean\n kind?: SegmentKind\n value: string\n}\n\nexport type SegmentBaseElementProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n | keyof SegmentBaseProps\n | \"aria-checked\"\n | \"children\"\n | \"onClick\"\n | \"onKeyDown\"\n | \"role\"\n | \"tabIndex\"\n | \"type\"\n> &\n SegmentBaseProps\n\n/**\n * Shared `role=\"radio\"` button implementation for `Segment` and\n * `IconSegment` — selection state, roving tabindex, arrow-key navigation,\n * and disabled propagation all live here so the two public components only\n * differ in what they render inside the button.\n */\nexport const SegmentBase = forwardRef<\n HTMLButtonElement,\n SegmentBaseElementProps\n>(function SegmentBase(\n {\n \"aria-describedby\": ariaDescribedBy,\n className,\n content,\n disabled = false,\n iconOnly = false,\n kind = \"interaction-subtle\",\n value,\n ...restProps\n }: SegmentBaseElementProps,\n ref\n) {\n const context = useContext(SegmentedControlContext)\n const isDisabled = disabled || (context?.disabled ?? false)\n const isChecked = context?.value === value\n\n const combinedClassName = classNames(\n \"tds-segmented-control-segment\",\n iconOnly && \"tds-segmented-control-segment--icon-only\",\n `tds-segmented-control-segment--${kind}`,\n className\n )\n\n const handleClick = () => {\n if (isDisabled) return\n context?.onSelect(value)\n }\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (!ARROW_KEYS.includes(event.key)) return\n\n const track = event.currentTarget.closest('[role=\"radiogroup\"]')\n if (!track) return\n\n const segments = Array.from(\n track.querySelectorAll<HTMLButtonElement>('[role=\"radio\"]:not(:disabled)')\n )\n const currentIndex = segments.indexOf(event.currentTarget)\n if (currentIndex === -1) return\n\n let nextIndex = currentIndex\n switch (event.key) {\n case \"ArrowLeft\":\n case \"ArrowUp\":\n nextIndex = currentIndex === 0 ? segments.length - 1 : currentIndex - 1\n break\n case \"ArrowRight\":\n case \"ArrowDown\":\n nextIndex = currentIndex === segments.length - 1 ? 0 : currentIndex + 1\n break\n case \"Home\":\n nextIndex = 0\n break\n case \"End\":\n nextIndex = segments.length - 1\n break\n }\n\n const nextSegment = segments[nextIndex]\n if (!nextSegment || nextSegment === event.currentTarget) return\n\n event.preventDefault()\n nextSegment.focus()\n const nextValue = nextSegment.dataset.segmentValue\n if (nextValue) context?.onSelect(nextValue)\n }\n\n const { describedBy, mergedProps, mergedRef } = useTooltipTriggerProps(\n { ...restProps, onClick: handleClick, onKeyDown: handleKeyDown },\n ref,\n ariaDescribedBy\n )\n\n return (\n <button\n {...mergedProps}\n aria-checked={isChecked ? \"true\" : \"false\"}\n aria-describedby={describedBy}\n className={combinedClassName}\n data-segment-value={value}\n disabled={isDisabled}\n ref={mergedRef}\n role=\"radio\"\n tabIndex={value === context?.tabbableValue ? 0 : -1}\n type=\"button\"\n >\n {content}\n </button>\n )\n})\n\nSegmentBase.displayName = \"SegmentBase\"\n"],"names":["React"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/SegmentedControl.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAIpB,OAAO,KAAK,EAAE,EAAE,KAAK,cAAc,EAAY,MAAM,OAAO,CAAA;AAI5D,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAAA;AAE9C,UAAU,2BAA2B;IACnC,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,sBAAsB;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAA;CAC5B;AAED,UAAU,+BAAgC,SAAQ,2BAA2B;IAC3E,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,iCACR,SAAQ,2BAA2B;IACnC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,qBAAqB,GAC7B,+BAA+B,GAC/B,iCAAiC,CAAA;AAErC,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAC7C,cAAc,CAAC,cAAc,CAAC,EAC9B,MAAM,qBAAqB,GAAG,UAAU,GAAG,MAAM,CAClD,GACC,qBAAqB,CAAA;AAEvB;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;4HAa1B,4BAA4B;;CAqD9B,CAAA"}
1
+ {"version":3,"file":"SegmentedControl.d.ts","sourceRoot":"","sources":["../../../src/components/segmented-control/SegmentedControl.tsx"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAIpB,OAAO,KAAK,EAAE,EACZ,KAAK,cAAc,EAIpB,MAAM,OAAO,CAAA;AAId,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAAA;AAE9C,UAAU,2BAA2B;IACnC,wCAAwC;IACxC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;IAClC,sBAAsB;IACtB,IAAI,CAAC,EAAE,oBAAoB,CAAA;CAC5B;AAED,UAAU,+BAAgC,SAAQ,2BAA2B;IAC3E,YAAY,CAAC,EAAE,KAAK,CAAA;IACpB,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAA;CACd;AAED,UAAU,iCACR,SAAQ,2BAA2B;IACnC;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd;AAED,MAAM,MAAM,qBAAqB,GAC7B,+BAA+B,GAC/B,iCAAiC,CAAA;AAErC,MAAM,MAAM,4BAA4B,GAAG,IAAI,CAC7C,cAAc,CAAC,cAAc,CAAC,EAC9B,MAAM,qBAAqB,GAAG,UAAU,GAAG,MAAM,CAClD,GACC,qBAAqB,CAAA;AAEvB;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB;4HAa1B,4BAA4B;;CAyE9B,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { useId } from '../../utilities/useId.js';
2
2
  import classNames from 'classnames';
3
- import React__default, { useState } from 'react';
3
+ import React__default, { useState, useRef, useLayoutEffect } from 'react';
4
4
  import { SegmentedControlContext } from './SegmentedControlContext.js';
5
5
 
6
6
  /**
@@ -22,10 +22,17 @@ const SegmentedControl = ({ children, className, defaultValue, disabled = false,
22
22
  setUncontrolledValue(nextValue);
23
23
  onChange?.(nextValue);
24
24
  };
25
+ const trackRef = useRef(null);
26
+ const [fallbackTabbableValue, setFallbackTabbableValue] = useState();
27
+ useLayoutEffect(() => {
28
+ const enabledSegments = Array.from(trackRef.current?.querySelectorAll('[role="radio"]:not(:disabled)') ?? []);
29
+ const selectedIsEnabled = enabledSegments.some((segment) => segment.dataset.segmentValue === selectedValue);
30
+ setFallbackTabbableValue(selectedIsEnabled ? undefined : enabledSegments[0]?.dataset.segmentValue);
31
+ }, [children, disabled, selectedValue]);
25
32
  const contextValue = {
26
33
  disabled,
27
34
  onSelect,
28
- tabbableValue: selectedValue,
35
+ tabbableValue: fallbackTabbableValue ?? selectedValue,
29
36
  value: selectedValue,
30
37
  };
31
38
  const stableId = useId();
@@ -37,7 +44,7 @@ const SegmentedControl = ({ children, className, defaultValue, disabled = false,
37
44
  }, className);
38
45
  return (React__default.createElement("div", { ...restProps, className: combinedClassName, id: componentId },
39
46
  React__default.createElement("div", { className: classNames("tds-segmented-control-label", hideLabel && "tds-segmented-control-label--hidden"), id: labelId }, label),
40
- React__default.createElement("div", { "aria-labelledby": labelId, className: "tds-segmented-control-track", role: "radiogroup" },
47
+ React__default.createElement("div", { "aria-labelledby": labelId, className: "tds-segmented-control-track", ref: trackRef, role: "radiogroup" },
41
48
  React__default.createElement(SegmentedControlContext.Provider, { value: contextValue }, children))));
42
49
  };
43
50
  SegmentedControl.displayName = "SegmentedControl";
@@ -1 +1 @@
1
- {"version":3,"file":"SegmentedControl.js","sources":["../../../src/components/segmented-control/SegmentedControl.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, { type HTMLAttributes, useState } from \"react\"\n\nimport { SegmentedControlContext } from \"./SegmentedControlContext\"\n\nexport type SegmentedControlSize = \"md\" | \"sm\"\n\ninterface SegmentedControlSharedProps {\n /** `Segment`/`IconSegment` elements. */\n children: React.ReactNode\n /** Disables the whole group. */\n disabled?: boolean\n /**\n * If `true`, the group spans 100% of its container and items split the\n * width evenly. Intended for a primary mode switch at the top of a\n * section/modal/pane — not for a control nested deep in a form.\n */\n fullWidth?: boolean\n /**\n * If `true`, renders `label` visually hidden instead of a visible\n * element.\n */\n hideLabel?: boolean\n /**\n * Accessible label for the group. Rendered as a visible element by\n * default.\n */\n label: string\n /** Called with the newly selected item's `value`. */\n onChange?: (value: string) => void\n /** Default `'md'`. */\n size?: SegmentedControlSize\n}\n\ninterface SegmentedControlControlledProps extends SegmentedControlSharedProps {\n defaultValue?: never\n /** Controlled selected item's `value`. */\n value: string\n}\n\ninterface SegmentedControlUncontrolledProps\n extends SegmentedControlSharedProps {\n /**\n * Uncontrolled initial selected item's `value` — a segmented control\n * always reflects a current mode, so one item must start selected.\n */\n defaultValue: string\n value?: never\n}\n\nexport type SegmentedControlProps =\n | SegmentedControlControlledProps\n | SegmentedControlUncontrolledProps\n\nexport type SegmentedControlElementProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n keyof SegmentedControlProps | \"children\" | \"role\"\n> &\n SegmentedControlProps\n\n/**\n * A single-select group of items — Table/Card, Yes/No, Tag/Tag group —\n * where exactly one `Segment`/`IconSegment` is selected at a time. Arrow keys\n * move the selection, and the group is one tab stop.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}\n */\nexport const SegmentedControl = ({\n children,\n className,\n defaultValue,\n disabled = false,\n fullWidth = false,\n hideLabel = false,\n id,\n label,\n onChange,\n size = \"md\",\n value,\n ...restProps\n}: SegmentedControlElementProps) => {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue)\n const isControlled = value !== undefined\n const selectedValue = isControlled ? value : uncontrolledValue\n\n const onSelect = (nextValue: string) => {\n if (nextValue === selectedValue) return\n if (!isControlled) setUncontrolledValue(nextValue)\n onChange?.(nextValue)\n }\n\n const contextValue = {\n disabled,\n onSelect,\n tabbableValue: selectedValue,\n value: selectedValue,\n }\n\n const stableId = useId()\n const componentId = id || `tds-segmented-control-${stableId}`\n const labelId = `${componentId}-label`\n\n const combinedClassName = classNames(\n \"tds-segmented-control\",\n {\n \"tds-segmented-control--full-width\": fullWidth,\n \"tds-segmented-control--sm\": size === \"sm\",\n },\n className\n )\n\n return (\n <div {...restProps} className={combinedClassName} id={componentId}>\n <div\n className={classNames(\n \"tds-segmented-control-label\",\n hideLabel && \"tds-segmented-control-label--hidden\"\n )}\n id={labelId}\n >\n {label}\n </div>\n <div\n aria-labelledby={labelId}\n className=\"tds-segmented-control-track\"\n role=\"radiogroup\"\n >\n <SegmentedControlContext.Provider value={contextValue}>\n {children}\n </SegmentedControlContext.Provider>\n </div>\n </div>\n )\n}\n\nSegmentedControl.displayName = \"SegmentedControl\"\n"],"names":["React"],"mappings":";;;;;AA+DA;;;;;;;AAOG;AACI,MAAM,gBAAgB,GAAG,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,KAAK,EACjB,SAAS,GAAG,KAAK,EACjB,EAAE,EACF,KAAK,EACL,QAAQ,EACR,IAAI,GAAG,IAAI,EACX,KAAK,EACL,GAAG,SAAS,EACiB,KAAI;IACjC,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC;AACxE,IAAA,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS;IACxC,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,iBAAiB;AAE9D,IAAA,MAAM,QAAQ,GAAG,CAAC,SAAiB,KAAI;QACrC,IAAI,SAAS,KAAK,aAAa;YAAE;AACjC,QAAA,IAAI,CAAC,YAAY;YAAE,oBAAoB,CAAC,SAAS,CAAC;AAClD,QAAA,QAAQ,GAAG,SAAS,CAAC;AACvB,IAAA,CAAC;AAED,IAAA,MAAM,YAAY,GAAG;QACnB,QAAQ;QACR,QAAQ;AACR,QAAA,aAAa,EAAE,aAAa;AAC5B,QAAA,KAAK,EAAE,aAAa;KACrB;AAED,IAAA,MAAM,QAAQ,GAAG,KAAK,EAAE;AACxB,IAAA,MAAM,WAAW,GAAG,EAAE,IAAI,CAAA,sBAAA,EAAyB,QAAQ,EAAE;AAC7D,IAAA,MAAM,OAAO,GAAG,CAAA,EAAG,WAAW,QAAQ;AAEtC,IAAA,MAAM,iBAAiB,GAAG,UAAU,CAClC,uBAAuB,EACvB;AACE,QAAA,mCAAmC,EAAE,SAAS;QAC9C,2BAA2B,EAAE,IAAI,KAAK,IAAI;KAC3C,EACD,SAAS,CACV;IAED,QACEA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,GAAS,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,EAAA;AAC/D,QAAAA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CACnB,6BAA6B,EAC7B,SAAS,IAAI,qCAAqC,CACnD,EACD,EAAE,EAAE,OAAO,EAAA,EAEV,KAAK,CACF;QACNA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,iBAAA,EACmB,OAAO,EACxB,SAAS,EAAC,6BAA6B,EACvC,IAAI,EAAC,YAAY,EAAA;AAEjB,YAAAA,cAAA,CAAA,aAAA,CAAC,uBAAuB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,EAClD,QAAQ,CACwB,CAC/B,CACF;AAEV;AAEA,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}
1
+ {"version":3,"file":"SegmentedControl.js","sources":["../../../src/components/segmented-control/SegmentedControl.tsx"],"sourcesContent":["import \"./index.css\"\n\nimport { useId } from \"@utilities/useId\"\nimport classNames from \"classnames\"\nimport React, {\n type HTMLAttributes,\n useLayoutEffect,\n useRef,\n useState,\n} from \"react\"\n\nimport { SegmentedControlContext } from \"./SegmentedControlContext\"\n\nexport type SegmentedControlSize = \"md\" | \"sm\"\n\ninterface SegmentedControlSharedProps {\n /** `Segment`/`IconSegment` elements. */\n children: React.ReactNode\n /** Disables the whole group. */\n disabled?: boolean\n /**\n * If `true`, the group spans 100% of its container and items split the\n * width evenly. Intended for a primary mode switch at the top of a\n * section/modal/pane — not for a control nested deep in a form.\n */\n fullWidth?: boolean\n /**\n * If `true`, renders `label` visually hidden instead of a visible\n * element.\n */\n hideLabel?: boolean\n /**\n * Accessible label for the group. Rendered as a visible element by\n * default.\n */\n label: string\n /** Called with the newly selected item's `value`. */\n onChange?: (value: string) => void\n /** Default `'md'`. */\n size?: SegmentedControlSize\n}\n\ninterface SegmentedControlControlledProps extends SegmentedControlSharedProps {\n defaultValue?: never\n /** Controlled selected item's `value`. */\n value: string\n}\n\ninterface SegmentedControlUncontrolledProps\n extends SegmentedControlSharedProps {\n /**\n * Uncontrolled initial selected item's `value` — a segmented control\n * always reflects a current mode, so one item must start selected.\n */\n defaultValue: string\n value?: never\n}\n\nexport type SegmentedControlProps =\n | SegmentedControlControlledProps\n | SegmentedControlUncontrolledProps\n\nexport type SegmentedControlElementProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n keyof SegmentedControlProps | \"children\" | \"role\"\n> &\n SegmentedControlProps\n\n/**\n * A single-select group of items — Table/Card, Yes/No, Tag/Tag group —\n * where exactly one `Segment`/`IconSegment` is selected at a time. Arrow keys\n * move the selection, and the group is one tab stop.\n *\n * @component\n * @see {@link https://planningcenter.github.io/tapestry/?path=/docs/forms-segmentedcontrol--docs | Storybook Documentation}\n */\nexport const SegmentedControl = ({\n children,\n className,\n defaultValue,\n disabled = false,\n fullWidth = false,\n hideLabel = false,\n id,\n label,\n onChange,\n size = \"md\",\n value,\n ...restProps\n}: SegmentedControlElementProps) => {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue)\n const isControlled = value !== undefined\n const selectedValue = isControlled ? value : uncontrolledValue\n\n const onSelect = (nextValue: string) => {\n if (nextValue === selectedValue) return\n if (!isControlled) setUncontrolledValue(nextValue)\n onChange?.(nextValue)\n }\n\n const trackRef = useRef<HTMLDivElement>(null)\n const [fallbackTabbableValue, setFallbackTabbableValue] = useState<\n string | undefined\n >()\n\n useLayoutEffect(() => {\n const enabledSegments = Array.from(\n trackRef.current?.querySelectorAll<HTMLButtonElement>(\n '[role=\"radio\"]:not(:disabled)'\n ) ?? []\n )\n const selectedIsEnabled = enabledSegments.some(\n (segment) => segment.dataset.segmentValue === selectedValue\n )\n setFallbackTabbableValue(\n selectedIsEnabled ? undefined : enabledSegments[0]?.dataset.segmentValue\n )\n }, [children, disabled, selectedValue])\n\n const contextValue = {\n disabled,\n onSelect,\n tabbableValue: fallbackTabbableValue ?? selectedValue,\n value: selectedValue,\n }\n\n const stableId = useId()\n const componentId = id || `tds-segmented-control-${stableId}`\n const labelId = `${componentId}-label`\n\n const combinedClassName = classNames(\n \"tds-segmented-control\",\n {\n \"tds-segmented-control--full-width\": fullWidth,\n \"tds-segmented-control--sm\": size === \"sm\",\n },\n className\n )\n\n return (\n <div {...restProps} className={combinedClassName} id={componentId}>\n <div\n className={classNames(\n \"tds-segmented-control-label\",\n hideLabel && \"tds-segmented-control-label--hidden\"\n )}\n id={labelId}\n >\n {label}\n </div>\n <div\n aria-labelledby={labelId}\n className=\"tds-segmented-control-track\"\n ref={trackRef}\n role=\"radiogroup\"\n >\n <SegmentedControlContext.Provider value={contextValue}>\n {children}\n </SegmentedControlContext.Provider>\n </div>\n </div>\n )\n}\n\nSegmentedControl.displayName = \"SegmentedControl\"\n"],"names":["React"],"mappings":";;;;;AAoEA;;;;;;;AAOG;AACI,MAAM,gBAAgB,GAAG,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,QAAQ,GAAG,KAAK,EAChB,SAAS,GAAG,KAAK,EACjB,SAAS,GAAG,KAAK,EACjB,EAAE,EACF,KAAK,EACL,QAAQ,EACR,IAAI,GAAG,IAAI,EACX,KAAK,EACL,GAAG,SAAS,EACiB,KAAI;IACjC,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC;AACxE,IAAA,MAAM,YAAY,GAAG,KAAK,KAAK,SAAS;IACxC,MAAM,aAAa,GAAG,YAAY,GAAG,KAAK,GAAG,iBAAiB;AAE9D,IAAA,MAAM,QAAQ,GAAG,CAAC,SAAiB,KAAI;QACrC,IAAI,SAAS,KAAK,aAAa;YAAE;AACjC,QAAA,IAAI,CAAC,YAAY;YAAE,oBAAoB,CAAC,SAAS,CAAC;AAClD,QAAA,QAAQ,GAAG,SAAS,CAAC;AACvB,IAAA,CAAC;AAED,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAiB,IAAI,CAAC;IAC7C,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,EAE/D;IAEH,eAAe,CAAC,MAAK;AACnB,QAAA,MAAM,eAAe,GAAG,KAAK,CAAC,IAAI,CAChC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAChC,+BAA+B,CAChC,IAAI,EAAE,CACR;AACD,QAAA,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAC5C,CAAC,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,YAAY,KAAK,aAAa,CAC5D;AACD,QAAA,wBAAwB,CACtB,iBAAiB,GAAG,SAAS,GAAG,eAAe,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,YAAY,CACzE;IACH,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAEvC,IAAA,MAAM,YAAY,GAAG;QACnB,QAAQ;QACR,QAAQ;QACR,aAAa,EAAE,qBAAqB,IAAI,aAAa;AACrD,QAAA,KAAK,EAAE,aAAa;KACrB;AAED,IAAA,MAAM,QAAQ,GAAG,KAAK,EAAE;AACxB,IAAA,MAAM,WAAW,GAAG,EAAE,IAAI,CAAA,sBAAA,EAAyB,QAAQ,EAAE;AAC7D,IAAA,MAAM,OAAO,GAAG,CAAA,EAAG,WAAW,QAAQ;AAEtC,IAAA,MAAM,iBAAiB,GAAG,UAAU,CAClC,uBAAuB,EACvB;AACE,QAAA,mCAAmC,EAAE,SAAS;QAC9C,2BAA2B,EAAE,IAAI,KAAK,IAAI;KAC3C,EACD,SAAS,CACV;IAED,QACEA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,GAAS,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,EAAE,EAAE,WAAW,EAAA;AAC/D,QAAAA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EACE,SAAS,EAAE,UAAU,CACnB,6BAA6B,EAC7B,SAAS,IAAI,qCAAqC,CACnD,EACD,EAAE,EAAE,OAAO,EAAA,EAEV,KAAK,CACF;AACN,QAAAA,cAAA,CAAA,aAAA,CAAA,KAAA,EAAA,EAAA,iBAAA,EACmB,OAAO,EACxB,SAAS,EAAC,6BAA6B,EACvC,GAAG,EAAE,QAAQ,EACb,IAAI,EAAC,YAAY,EAAA;AAEjB,YAAAA,cAAA,CAAA,aAAA,CAAC,uBAAuB,CAAC,QAAQ,EAAA,EAAC,KAAK,EAAE,YAAY,EAAA,EAClD,QAAQ,CACwB,CAC/B,CACF;AAEV;AAEA,gBAAgB,CAAC,WAAW,GAAG,kBAAkB;;;;"}