@salt-ds/core 1.69.0 → 1.71.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 (136) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/css/salt-core.css +298 -34
  3. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js +8 -0
  4. package/dist-cjs/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  5. package/dist-cjs/avatar/Avatar.css.js +1 -1
  6. package/dist-cjs/avatar/Avatar.js +2 -2
  7. package/dist-cjs/avatar/Avatar.js.map +1 -1
  8. package/dist-cjs/card/Card.css.js +1 -1
  9. package/dist-cjs/card/Card.js +4 -0
  10. package/dist-cjs/card/Card.js.map +1 -1
  11. package/dist-cjs/drawer/Drawer.css.js +1 -1
  12. package/dist-cjs/drawer/Drawer.js +30 -5
  13. package/dist-cjs/drawer/Drawer.js.map +1 -1
  14. package/dist-cjs/drawer/DrawerCloseButton.js +1 -1
  15. package/dist-cjs/drawer/DrawerCloseButton.js.map +1 -1
  16. package/dist-cjs/drawer/DrawerContent.css.js +6 -0
  17. package/dist-cjs/drawer/DrawerContent.css.js.map +1 -0
  18. package/dist-cjs/drawer/DrawerContent.js +75 -0
  19. package/dist-cjs/drawer/DrawerContent.js.map +1 -0
  20. package/dist-cjs/drawer/DrawerContext.js +30 -0
  21. package/dist-cjs/drawer/DrawerContext.js.map +1 -0
  22. package/dist-cjs/drawer/DrawerFooter.css.js +6 -0
  23. package/dist-cjs/drawer/DrawerFooter.css.js.map +1 -0
  24. package/dist-cjs/drawer/DrawerFooter.js +30 -0
  25. package/dist-cjs/drawer/DrawerFooter.js.map +1 -0
  26. package/dist-cjs/drawer/DrawerHeader.css.js +6 -0
  27. package/dist-cjs/drawer/DrawerHeader.css.js.map +1 -0
  28. package/dist-cjs/drawer/DrawerHeader.js +95 -0
  29. package/dist-cjs/drawer/DrawerHeader.js.map +1 -0
  30. package/dist-cjs/drawer/hasDrawerSection.js +22 -0
  31. package/dist-cjs/drawer/hasDrawerSection.js.map +1 -0
  32. package/dist-cjs/form-field/FormField.css.js +1 -1
  33. package/dist-cjs/form-field/FormField.js +15 -0
  34. package/dist-cjs/form-field/FormField.js.map +1 -1
  35. package/dist-cjs/form-field/FormFieldLabel.css.js +1 -1
  36. package/dist-cjs/index.js +8 -0
  37. package/dist-cjs/index.js.map +1 -1
  38. package/dist-cjs/interactable-card/InteractableCard.css.js +1 -1
  39. package/dist-cjs/interactable-card/InteractableCard.js +5 -0
  40. package/dist-cjs/interactable-card/InteractableCard.js.map +1 -1
  41. package/dist-cjs/link/Link.js +6 -8
  42. package/dist-cjs/link/Link.js.map +1 -1
  43. package/dist-cjs/link/LinkAction.js +14 -2
  44. package/dist-cjs/link/LinkAction.js.map +1 -1
  45. package/dist-cjs/link-button/LinkButton.css.js +6 -0
  46. package/dist-cjs/link-button/LinkButton.css.js.map +1 -0
  47. package/dist-cjs/link-button/LinkButton.js +87 -0
  48. package/dist-cjs/link-button/LinkButton.js.map +1 -0
  49. package/dist-cjs/link-card/LinkCard.css.js +1 -1
  50. package/dist-cjs/link-card/LinkCard.js +4 -0
  51. package/dist-cjs/link-card/LinkCard.js.map +1 -1
  52. package/dist-cjs/menu/MenuItem.js +0 -1
  53. package/dist-cjs/menu/MenuItem.js.map +1 -1
  54. package/dist-cjs/panel/Panel.css.js +1 -1
  55. package/dist-cjs/panel/Panel.js +13 -2
  56. package/dist-cjs/panel/Panel.js.map +1 -1
  57. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js +10 -2
  58. package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -1
  59. package/dist-cjs/vertical-navigation/VerticalNavigationItemTrigger.js +3 -3
  60. package/dist-cjs/vertical-navigation/VerticalNavigationItemTrigger.js.map +1 -1
  61. package/dist-es/aria-announcer/AriaAnnouncerProvider.js +8 -0
  62. package/dist-es/aria-announcer/AriaAnnouncerProvider.js.map +1 -1
  63. package/dist-es/avatar/Avatar.css.js +1 -1
  64. package/dist-es/avatar/Avatar.js +2 -2
  65. package/dist-es/avatar/Avatar.js.map +1 -1
  66. package/dist-es/card/Card.css.js +1 -1
  67. package/dist-es/card/Card.js +4 -0
  68. package/dist-es/card/Card.js.map +1 -1
  69. package/dist-es/drawer/Drawer.css.js +1 -1
  70. package/dist-es/drawer/Drawer.js +31 -6
  71. package/dist-es/drawer/Drawer.js.map +1 -1
  72. package/dist-es/drawer/DrawerCloseButton.js +1 -1
  73. package/dist-es/drawer/DrawerCloseButton.js.map +1 -1
  74. package/dist-es/drawer/DrawerContent.css.js +4 -0
  75. package/dist-es/drawer/DrawerContent.css.js.map +1 -0
  76. package/dist-es/drawer/DrawerContent.js +73 -0
  77. package/dist-es/drawer/DrawerContent.js.map +1 -0
  78. package/dist-es/drawer/DrawerContext.js +27 -0
  79. package/dist-es/drawer/DrawerContext.js.map +1 -0
  80. package/dist-es/drawer/DrawerFooter.css.js +4 -0
  81. package/dist-es/drawer/DrawerFooter.css.js.map +1 -0
  82. package/dist-es/drawer/DrawerFooter.js +28 -0
  83. package/dist-es/drawer/DrawerFooter.js.map +1 -0
  84. package/dist-es/drawer/DrawerHeader.css.js +4 -0
  85. package/dist-es/drawer/DrawerHeader.css.js.map +1 -0
  86. package/dist-es/drawer/DrawerHeader.js +93 -0
  87. package/dist-es/drawer/DrawerHeader.js.map +1 -0
  88. package/dist-es/drawer/hasDrawerSection.js +20 -0
  89. package/dist-es/drawer/hasDrawerSection.js.map +1 -0
  90. package/dist-es/form-field/FormField.css.js +1 -1
  91. package/dist-es/form-field/FormField.js +16 -1
  92. package/dist-es/form-field/FormField.js.map +1 -1
  93. package/dist-es/form-field/FormFieldLabel.css.js +1 -1
  94. package/dist-es/index.js +4 -0
  95. package/dist-es/index.js.map +1 -1
  96. package/dist-es/interactable-card/InteractableCard.css.js +1 -1
  97. package/dist-es/interactable-card/InteractableCard.js +5 -0
  98. package/dist-es/interactable-card/InteractableCard.js.map +1 -1
  99. package/dist-es/link/Link.js +7 -9
  100. package/dist-es/link/Link.js.map +1 -1
  101. package/dist-es/link/LinkAction.js +15 -3
  102. package/dist-es/link/LinkAction.js.map +1 -1
  103. package/dist-es/link-button/LinkButton.css.js +4 -0
  104. package/dist-es/link-button/LinkButton.css.js.map +1 -0
  105. package/dist-es/link-button/LinkButton.js +85 -0
  106. package/dist-es/link-button/LinkButton.js.map +1 -0
  107. package/dist-es/link-card/LinkCard.css.js +1 -1
  108. package/dist-es/link-card/LinkCard.js +4 -0
  109. package/dist-es/link-card/LinkCard.js.map +1 -1
  110. package/dist-es/menu/MenuItem.js +0 -1
  111. package/dist-es/menu/MenuItem.js.map +1 -1
  112. package/dist-es/panel/Panel.css.js +1 -1
  113. package/dist-es/panel/Panel.js +13 -2
  114. package/dist-es/panel/Panel.js.map +1 -1
  115. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js +10 -2
  116. package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -1
  117. package/dist-es/vertical-navigation/VerticalNavigationItemTrigger.js +3 -3
  118. package/dist-es/vertical-navigation/VerticalNavigationItemTrigger.js.map +1 -1
  119. package/dist-types/card/Card.d.ts +10 -0
  120. package/dist-types/drawer/Drawer.d.ts +1 -1
  121. package/dist-types/drawer/DrawerCloseButton.d.ts +3 -0
  122. package/dist-types/drawer/DrawerContent.d.ts +3 -0
  123. package/dist-types/drawer/DrawerContext.d.ts +9 -0
  124. package/dist-types/drawer/DrawerFooter.d.ts +3 -0
  125. package/dist-types/drawer/DrawerHeader.d.ts +24 -0
  126. package/dist-types/drawer/hasDrawerSection.d.ts +2 -0
  127. package/dist-types/drawer/index.d.ts +3 -0
  128. package/dist-types/index.d.ts +1 -0
  129. package/dist-types/interactable-card/InteractableCard.d.ts +9 -1
  130. package/dist-types/link/LinkAction.d.ts +2 -1
  131. package/dist-types/link-button/LinkButton.d.ts +26 -0
  132. package/dist-types/link-button/index.d.ts +1 -0
  133. package/dist-types/link-card/LinkCard.d.ts +8 -0
  134. package/dist-types/panel/Panel.d.ts +4 -0
  135. package/dist-types/utils/useIsomorphicLayoutEffect.d.ts +2 -2
  136. package/package.json +11 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,88 @@
1
1
  # @salt-ds/core
2
2
 
3
+ ## 1.71.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5da6723: Added `LinkButton`, a button-styled link for prominent navigation. Supports neutral and accented sentiments, icons, icon-only labels, and routing-library integration via the `render` prop.
8
+
9
+ ```tsx
10
+ import { LinkButton } from "@salt-ds/core";
11
+
12
+ <LinkButton href="/reports">View reports</LinkButton>;
13
+ ```
14
+
15
+ - 0f92b84: Added `elevation` support to `Card`, `InteractableCard`, `LinkCard`, and `Panel`. Cards default to raised elevation to preserve their existing appearance, while `Panel` defaults to flat elevation. Added `borderColor` support to `Card`, `InteractableCard`, and `LinkCard`, including `borderColor="none"` for ghost cards.
16
+ - d7e777c: Added `DrawerHeader`, `DrawerContent` and `DrawerFooter`, implementing header and footer blocks in core `Drawer`. Composing a `Drawer` from `DrawerHeader`, `DrawerContent` and `DrawerFooter` is the recommended approach.
17
+
18
+ `DrawerHeader` takes optional `header`, `preheader`, `description` and `actions`, and displays an accent bar unless `disableAccent` is set. A close action should be passed to `actions` as a `Button`. `DrawerHeader` stays pinned to the top, `DrawerContent` is scrollable.
19
+
20
+ `DrawerHeader` names `Drawer` with its `header` and `preheader`, and describes it with its `description`, so `aria-labelledby` and `aria-describedby` no longer need to be set manually.
21
+
22
+ ```tsx
23
+ import {
24
+ Button,
25
+ Drawer,
26
+ DrawerContent,
27
+ DrawerFooter,
28
+ DrawerHeader,
29
+ } from "@salt-ds/core";
30
+ import { CloseIcon } from "@salt-ds/icons";
31
+
32
+ <Drawer open={open} onOpenChange={setOpen}>
33
+ <DrawerHeader
34
+ header="Check deposit #1278"
35
+ actions={
36
+ <Button
37
+ aria-label="Close drawer"
38
+ appearance="transparent"
39
+ onClick={() => setOpen(false)}
40
+ >
41
+ <CloseIcon aria-hidden />
42
+ </Button>
43
+ }
44
+ />
45
+ <DrawerContent>{content}</DrawerContent>
46
+ <DrawerFooter>
47
+ <Button appearance="transparent">Cancel</Button>
48
+ <Button sentiment="accented">Save</Button>
49
+ </DrawerFooter>
50
+ </Drawer>;
51
+ ```
52
+
53
+ Deprecated `DrawerCloseButton`. Use a `Button` with a `CloseIcon` in `DrawerHeader`'s `actions` instead.
54
+
55
+ ### Patch Changes
56
+
57
+ - 0f92b84: Prevented disabled `Card` and `InteractableCard` components from receiving hover styling.
58
+ - 1417fa9: Fixed Tabs from announcing an ignored overflow selection when that value was later selected externally.
59
+ - dd17c26: Fixed duplicate menu close notifications during keyboard activation and prevented announcements from being queued after `AriaAnnouncerProvider` unmounts.
60
+ - d7e777c: Fixed `disableDismiss` on `Drawer` also preventing Escape from closing the drawer. It now only prevents dismissal on click away, matching its documentation and `Dialog`.
61
+ - 86080e7: Changed flat `Panel` instances to use sharp corners.
62
+ - f705932: Deprecated the `hoverable` prop on `Card`. Use `LinkCard` or `InteractableCard` when the entire card is interactive.
63
+ - 5ab650a: Fixed vertical alignment of smaller controls with larger controls in FormField.
64
+
65
+ ## 1.70.0
66
+
67
+ ### Minor Changes
68
+
69
+ - 6c12378: Added `--saltAvatar-size` for sizing an Avatar from a CSS length. Images, fallback icons and initials stay proportional to that length across densities, matching the existing `size` multiplier ratio.
70
+
71
+ ### Patch Changes
72
+
73
+ - 2892934: Fixed `Avatar` so consumer `style` can override `--saltAvatar-size-multiplier`.
74
+ - 416d4b8: Fixed `VerticalNavigationItemTrigger` dropping its forwarded ref.
75
+
76
+ The internal action element was a plain function component, so the ref passed to `VerticalNavigationItemTrigger` never reached the rendered element on React 18 and below. This broke consumers that need the underlying node, such as wrapping the trigger in a `Tooltip`.
77
+
78
+ ```tsx
79
+ <Tooltip content="Products" placement="right">
80
+ <VerticalNavigationItemTrigger render={<Link to="/products" />}>
81
+ <VerticalNavigationItemLabel>Products</VerticalNavigationItemLabel>
82
+ </VerticalNavigationItemTrigger>
83
+ </Tooltip>
84
+ ```
85
+
3
86
  ## 1.69.0
4
87
 
5
88
  ### Minor Changes
package/css/salt-core.css CHANGED
@@ -116,11 +116,27 @@
116
116
  }
117
117
 
118
118
  /* src/avatar/Avatar.css */
119
+ .salt-density-high {
120
+ --avatar-fontSize-ratio: calc(8 / 20);
121
+ }
122
+ .salt-density-medium {
123
+ --avatar-fontSize-ratio: calc(10 / 28);
124
+ }
125
+ .salt-density-low {
126
+ --avatar-fontSize-ratio: calc(12 / 36);
127
+ }
128
+ .salt-density-touch {
129
+ --avatar-fontSize-ratio: calc(14 / 44);
130
+ }
131
+ .salt-density-mobile {
132
+ --avatar-fontSize-ratio: calc(12 / 44);
133
+ }
119
134
  .saltAvatar {
120
135
  --avatar-size-multiplier: var(--saltAvatar-size-multiplier, 1);
121
136
  --avatar-base-size: var(--salt-size-base);
122
- --avatar-base-fontSize: var(--saltAvatar-fontSize, var(--salt-text-notation-fontSize));
123
- --avatar-container-size: calc(var(--avatar-base-size) * var(--avatar-size-multiplier));
137
+ --avatar-direct-fontSize: calc(var(--saltAvatar-size) * var(--avatar-fontSize-ratio) / var(--avatar-size-multiplier));
138
+ --avatar-base-fontSize: var(--saltAvatar-fontSize, var(--avatar-direct-fontSize, var(--salt-text-notation-fontSize)));
139
+ --avatar-container-size: var(--saltAvatar-size, calc(var(--avatar-base-size) * var(--avatar-size-multiplier)));
124
140
  --avatar-fontSize: calc(var(--avatar-base-fontSize) * var(--avatar-size-multiplier));
125
141
  --saltIcon-size: calc(var(--avatar-container-size) / 2);
126
142
  }
@@ -849,14 +865,17 @@ a.saltAvatar::after {
849
865
  .saltCard {
850
866
  border-width: var(--saltCard-borderWidth, var(--salt-size-fixed-100));
851
867
  border-style: var(--salt-borderStyle-solid);
868
+ border-color: var(--saltCard-borderColor, var(--card-borderColor));
852
869
  padding: var(--saltCard-padding, var(--card-padding));
853
870
  position: relative;
854
- box-shadow: var(--salt-overlayable-shadow);
855
871
  transition: box-shadow var(--salt-duration-instant) ease-in-out;
856
872
  box-sizing: border-box;
857
873
  border-radius: var(--saltCard-borderRadius, var(--salt-palette-corner, 0));
858
874
  overflow: hidden;
859
875
  --card-accent-color: var(--salt-sentiment-accent-background);
876
+ --card-borderColor: var(--salt-container-borderColor);
877
+ --card-borderColor-strong: var(--salt-container-bold-borderColor);
878
+ --card-borderColor-subtle: var(--salt-container-subtle-borderColor);
860
879
  --card-padding: var(--salt-spacing-200);
861
880
  }
862
881
  .saltCard.saltCard-sectioned {
@@ -873,19 +892,33 @@ a.saltAvatar::after {
873
892
  }
874
893
  .saltCard-primary {
875
894
  background: var(--saltCard-background, var(--salt-container-primary-background));
876
- border-color: var(--salt-container-bold-borderColor);
877
895
  }
878
896
  .saltCard-secondary {
879
897
  background: var(--saltCard-background, var(--salt-container-secondary-background));
880
- border-color: var(--salt-container-bold-borderColor);
881
898
  }
882
899
  .saltCard-tertiary {
883
900
  background: var(--saltCard-background, var(--salt-container-tertiary-background));
884
- border-color: var(--salt-container-bold-borderColor);
885
901
  }
886
902
  .saltCard-ghost {
887
903
  background: var(--saltCard-background, var(--salt-container-ghost-background));
888
- border-color: var(--salt-container-ghost-borderColor);
904
+ --card-borderColor: var(--salt-container-ghost-borderColor);
905
+ --card-borderColor-strong: var(--salt-container-ghost-bold-borderColor);
906
+ --card-borderColor-subtle: var(--salt-container-ghost-subtle-borderColor);
907
+ }
908
+ .saltCard-flat {
909
+ box-shadow: var(--saltCard-boxShadow-flat, none);
910
+ }
911
+ .saltCard-raised {
912
+ box-shadow: var(--saltCard-boxShadow, var(--salt-overlayable-shadow));
913
+ }
914
+ .saltCard-borderColorStrong {
915
+ --card-borderColor: var(--card-borderColor-strong);
916
+ }
917
+ .saltCard-borderColorSubtle {
918
+ --card-borderColor: var(--card-borderColor-subtle);
919
+ }
920
+ .saltCard-borderColorNone {
921
+ --card-borderColor: transparent;
889
922
  }
890
923
  .saltCard-accent::after {
891
924
  content: "";
@@ -925,10 +958,9 @@ a:focus .saltCard-interactable,
925
958
  box-shadow: var(--saltCard-boxShadow-hover, var(--salt-overlayable-shadow-hover));
926
959
  cursor: var(--saltCard-cursor-hover, var(--salt-cursor-hover));
927
960
  border-color: var(--salt-actionable-accented-borderColor-hover);
928
- position: relative;
929
961
  }
930
962
  @media (hover: hover) {
931
- .saltCard-hoverable:hover {
963
+ .saltCard-hoverable:not(.saltCard-disabled):hover {
932
964
  box-shadow: var(--saltCard-boxShadow-hover, var(--salt-overlayable-shadow-hover));
933
965
  border-color: var(--salt-actionable-accented-borderColor-hover);
934
966
  }
@@ -1464,6 +1496,14 @@ a:focus .saltCard-interactable.saltCard-disabled {
1464
1496
  top: 0;
1465
1497
  box-sizing: border-box;
1466
1498
  }
1499
+ .saltDrawer.saltDrawer-sectioned {
1500
+ padding: 0;
1501
+ }
1502
+ @supports selector(:has(*)) {
1503
+ .saltDrawer:has(> .saltDrawerHeader, > .saltDrawerContent, > .saltDrawerFooter) {
1504
+ padding: 0;
1505
+ }
1506
+ }
1467
1507
  .saltDrawer-primary {
1468
1508
  --drawer-background: var(--salt-container-primary-background);
1469
1509
  }
@@ -1531,6 +1571,94 @@ a:focus .saltCard-interactable.saltCard-disabled {
1531
1571
  margin-right: calc(var(--salt-spacing-300) * -1);
1532
1572
  }
1533
1573
 
1574
+ /* src/drawer/DrawerContent.css */
1575
+ .saltDrawerContent {
1576
+ color: var(--salt-content-primary-foreground);
1577
+ padding: 0 var(--salt-spacing-300);
1578
+ flex: 1 1 auto;
1579
+ min-height: var(--salt-text-lineHeight);
1580
+ display: flex;
1581
+ box-sizing: border-box;
1582
+ }
1583
+ .saltDrawerContent:first-child {
1584
+ padding-top: var(--salt-spacing-300);
1585
+ }
1586
+ .saltDrawerContent:last-child {
1587
+ padding-bottom: var(--salt-spacing-300);
1588
+ }
1589
+ .saltDrawerContent-inner {
1590
+ flex: 1;
1591
+ min-width: 0;
1592
+ overflow-y: auto;
1593
+ border-top: var(--salt-size-fixed-100) var(--salt-borderStyle-solid) transparent;
1594
+ border-bottom: var(--salt-size-fixed-100) var(--salt-borderStyle-solid) transparent;
1595
+ box-sizing: border-box;
1596
+ }
1597
+ .saltDrawerContent-inner:focus-visible {
1598
+ outline: var(--salt-focused-outline);
1599
+ outline-offset: calc(-1 * var(--salt-focused-outlineWidth));
1600
+ }
1601
+ .saltDrawerContent-inner.saltDrawerContent-scrollTop {
1602
+ border-top-color: var(--salt-separable-tertiary-borderColor);
1603
+ }
1604
+ .saltDrawerContent-inner.saltDrawerContent-scrollBottom {
1605
+ border-bottom-color: var(--salt-separable-tertiary-borderColor);
1606
+ }
1607
+
1608
+ /* src/drawer/DrawerFooter.css */
1609
+ .saltDrawerFooter {
1610
+ padding: var(--salt-spacing-300);
1611
+ display: flex;
1612
+ justify-content: flex-end;
1613
+ align-items: center;
1614
+ gap: var(--salt-spacing-100);
1615
+ flex-shrink: 0;
1616
+ box-sizing: border-box;
1617
+ }
1618
+
1619
+ /* src/drawer/DrawerHeader.css */
1620
+ .saltDrawerHeader {
1621
+ padding: var(--salt-spacing-300);
1622
+ display: flex;
1623
+ gap: var(--salt-spacing-100);
1624
+ flex-shrink: 0;
1625
+ box-sizing: border-box;
1626
+ }
1627
+ .saltDrawerHeader-header {
1628
+ margin: 0;
1629
+ }
1630
+ .saltDrawerHeader-container {
1631
+ flex-grow: 1;
1632
+ margin: 0;
1633
+ display: flex;
1634
+ flex-direction: column;
1635
+ gap: var(--salt-spacing-50);
1636
+ padding-top: calc((var(--salt-size-base) - var(--salt-text-h2-lineHeight)) / 2);
1637
+ align-items: flex-start;
1638
+ min-width: 0;
1639
+ word-break: break-word;
1640
+ }
1641
+ .saltDrawerHeader-header > .saltText {
1642
+ display: block;
1643
+ margin: 0;
1644
+ }
1645
+ .saltDrawerHeader-actionsContainer {
1646
+ align-self: flex-start;
1647
+ display: flex;
1648
+ }
1649
+ .saltDrawerHeader-withAccent {
1650
+ position: relative;
1651
+ }
1652
+ .saltDrawerHeader-withAccent::before {
1653
+ content: "";
1654
+ position: absolute;
1655
+ top: var(--salt-spacing-300);
1656
+ bottom: var(--salt-spacing-300);
1657
+ left: 0;
1658
+ width: var(--salt-size-bar);
1659
+ background: var(--salt-sentiment-accent-background);
1660
+ }
1661
+
1534
1662
  /* src/dropdown/Dropdown.css */
1535
1663
  .saltDropdown {
1536
1664
  all: unset;
@@ -1839,6 +1967,10 @@ a:focus .saltCard-interactable.saltCard-disabled {
1839
1967
  grid-auto-rows: min-content;
1840
1968
  grid-template-areas: "label" "controls";
1841
1969
  }
1970
+ .saltFormField-labelTop.saltFormField-hasControls {
1971
+ align-content: start;
1972
+ grid-template-rows: min-content minmax(var(--salt-size-base), auto);
1973
+ }
1842
1974
  .saltFormField-labelTop .saltFormFieldHelperText {
1843
1975
  grid-area: 3 / 1;
1844
1976
  }
@@ -1846,10 +1978,16 @@ a:focus .saltCard-interactable.saltCard-disabled {
1846
1978
  grid-template-columns: var(--saltFormField-label-width, var(--formField-label-width, 40%)) 1fr;
1847
1979
  grid-template-areas: "label controls";
1848
1980
  }
1981
+ .saltFormField-labelLeft.saltFormField-hasControls {
1982
+ grid-template-rows: minmax(var(--salt-size-base), auto);
1983
+ }
1849
1984
  .saltFormField-labelRight {
1850
1985
  grid-template-columns: var(--saltFormField-label-width, var(--formField-label-width, 40%)) 1fr;
1851
1986
  grid-template-areas: "label controls";
1852
1987
  }
1988
+ .saltFormField-labelRight.saltFormField-hasControls {
1989
+ grid-template-rows: minmax(var(--salt-size-base), auto);
1990
+ }
1853
1991
  .saltFormField-labelLeft .saltFormFieldHelperText,
1854
1992
  .saltFormField-labelRight .saltFormFieldHelperText {
1855
1993
  grid-area: 2 / 2;
@@ -1861,19 +1999,15 @@ a:focus .saltCard-interactable.saltCard-disabled {
1861
1999
  .saltFormField-labelRight .saltFormFieldLabel {
1862
2000
  text-align: right;
1863
2001
  }
1864
- .saltFormField-controls {
1865
- align-items: center;
1866
- display: grid;
1867
- grid-auto-columns: minmax(0, 1fr);
1868
- grid-auto-flow: column;
1869
- grid-column-gap: var(--salt-spacing-100);
1870
- }
1871
2002
  .saltFormFieldLabel {
1872
2003
  grid-area: label;
1873
2004
  }
1874
2005
  .saltFormFieldHelperText {
1875
2006
  grid-area: helperText;
1876
2007
  }
2008
+ .saltFormField-labelTop > :not(.saltFormFieldLabel):not(.saltFormFieldHelperText) {
2009
+ align-self: center;
2010
+ }
1877
2011
  .saltFormField-disabled {
1878
2012
  --saltInput-outline: none;
1879
2013
  --saltCheckbox-outline: none;
@@ -1883,6 +2017,9 @@ a:focus .saltCard-interactable.saltCard-disabled {
1883
2017
  .saltFormField:not(:has(.saltFormFieldLabel)) {
1884
2018
  grid-template-areas: "controls";
1885
2019
  }
2020
+ .saltFormField-hasControls:not(:has(.saltFormFieldLabel)) {
2021
+ grid-template-rows: minmax(var(--salt-size-base), auto);
2022
+ }
1886
2023
  }
1887
2024
 
1888
2025
  /* src/form-field/FormFieldHelperText.css */
@@ -1907,9 +2044,6 @@ a:focus .saltCard-interactable.saltCard-disabled {
1907
2044
  font-weight: var(--saltFormField-label-fontWeight, var(--salt-text-fontWeight-strong));
1908
2045
  width: 100%;
1909
2046
  }
1910
- .saltFormFieldLabel:hover + .saltFormField-controls * {
1911
- --input-borderColor: var(--input-borderColor-hover);
1912
- }
1913
2047
  .saltFormField-labelLeft .saltFormFieldLabel.saltText {
1914
2048
  align-self: baseline;
1915
2049
  padding-top: var(--salt-spacing-100);
@@ -2170,8 +2304,8 @@ a:focus .saltCard-interactable.saltCard-disabled {
2170
2304
  .saltInteractableCard {
2171
2305
  border-width: var(--saltInteractableCard-borderWidth, var(--salt-size-fixed-100));
2172
2306
  border-style: var(--saltInteractableCard-borderStyle, var(--salt-borderStyle-solid));
2307
+ border-color: var(--saltInteractableCard-borderColor, var(--interactableCard-borderColor));
2173
2308
  border-radius: var(--saltInteractableCard-borderRadius, var(--salt-palette-corner, 0));
2174
- box-shadow: var(--salt-overlayable-shadow);
2175
2309
  display: block;
2176
2310
  padding: var(--saltInteractableCard-padding, var(--card-padding));
2177
2311
  position: relative;
@@ -2179,6 +2313,7 @@ a:focus .saltCard-interactable.saltCard-disabled {
2179
2313
  transition: box-shadow var(--salt-duration-instant) ease-in-out;
2180
2314
  overflow: hidden;
2181
2315
  --card-accent-color: var(--salt-sentiment-accent-background);
2316
+ --interactableCard-borderColor: var(--salt-container-borderColor);
2182
2317
  --card-padding: var(--salt-spacing-200);
2183
2318
  }
2184
2319
  .saltInteractableCard.saltInteractableCard-sectioned {
@@ -2195,15 +2330,27 @@ a:focus .saltCard-interactable.saltCard-disabled {
2195
2330
  }
2196
2331
  .saltInteractableCard-primary {
2197
2332
  background: var(--saltInteractableCard-background, var(--salt-container-primary-background));
2198
- border-color: var(--salt-container-bold-borderColor);
2199
2333
  }
2200
2334
  .saltInteractableCard-secondary {
2201
2335
  background: var(--saltInteractableCard-background, var(--salt-container-secondary-background));
2202
- border-color: var(--salt-container-bold-borderColor);
2203
2336
  }
2204
2337
  .saltInteractableCard-tertiary {
2205
2338
  background: var(--saltInteractableCard-background, var(--salt-container-tertiary-background));
2206
- border-color: var(--salt-container-bold-borderColor);
2339
+ }
2340
+ .saltInteractableCard-flat {
2341
+ box-shadow: var(--saltInteractableCard-boxShadow-flat, none);
2342
+ }
2343
+ .saltInteractableCard-raised {
2344
+ box-shadow: var(--saltInteractableCard-boxShadow, var(--salt-overlayable-shadow));
2345
+ }
2346
+ .saltInteractableCard-borderColorStrong {
2347
+ --interactableCard-borderColor: var(--salt-container-bold-borderColor);
2348
+ }
2349
+ .saltInteractableCard-borderColorSubtle {
2350
+ --interactableCard-borderColor: var(--salt-container-subtle-borderColor);
2351
+ }
2352
+ .saltInteractableCard-borderColorNone {
2353
+ --interactableCard-borderColor: transparent;
2207
2354
  }
2208
2355
  .saltInteractableCard-accent::after {
2209
2356
  content: "";
@@ -2244,15 +2391,11 @@ a:focus .saltCard-interactable.saltCard-disabled {
2244
2391
  outline-offset: var(--salt-focused-outlineOffset);
2245
2392
  }
2246
2393
  @media (hover: hover) {
2247
- .saltInteractableCard:hover {
2394
+ .saltInteractableCard:not(.saltInteractableCard-disabled):hover {
2248
2395
  cursor: var(--salt-cursor-hover);
2249
2396
  box-shadow: var(--salt-overlayable-shadow-hover);
2250
2397
  border-color: var(--salt-actionable-accented-borderColor-hover);
2251
2398
  }
2252
- .saltInteractableCard-disabled:hover {
2253
- cursor: var(--salt-cursor-disabled);
2254
- box-shadow: none;
2255
- }
2256
2399
  }
2257
2400
  .saltInteractableCard-selected,
2258
2401
  .saltInteractableCard:active,
@@ -2401,12 +2544,117 @@ a:focus .saltCard-interactable.saltCard-disabled {
2401
2544
  -webkit-user-select: none;
2402
2545
  }
2403
2546
 
2547
+ /* src/link-button/LinkButton.css */
2548
+ .saltLinkButton {
2549
+ --linkButton-borderWidth: var(--salt-size-fixed-100);
2550
+ align-items: var(--saltLinkButton-alignItems, center);
2551
+ appearance: none;
2552
+ background: var(--saltLinkButton-background, var(--linkButton-background));
2553
+ border-color: var(--saltLinkButton-borderColor, var(--linkButton-borderColor, transparent));
2554
+ border-style: var(--saltLinkButton-borderStyle, solid);
2555
+ border-width: var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth));
2556
+ border-radius: var(--saltLinkButton-borderRadius, var(--salt-palette-corner-weak, 0));
2557
+ color: var(--saltLinkButton-text-color, var(--linkButton-text-color));
2558
+ display: inline-flex;
2559
+ gap: var(--salt-spacing-50);
2560
+ justify-content: var(--saltLinkButton-justifyContent, center);
2561
+ font-size: var(--saltLinkButton-fontSize, var(--salt-text-fontSize));
2562
+ font-family: var(--saltLinkButton-fontFamily, var(--salt-text-action-fontFamily));
2563
+ line-height: var(--saltLinkButton-lineHeight, var(--salt-text-lineHeight));
2564
+ letter-spacing: var(--saltLinkButton-letterSpacing, var(--salt-text-action-letterSpacing));
2565
+ text-transform: var(--saltLinkButton-textTransform, var(--salt-text-action-textTransform));
2566
+ padding: 0 var(--saltLinkButton-padding, calc(var(--salt-spacing-100) - var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth))));
2567
+ margin: var(--saltLinkButton-margin, 0);
2568
+ height: var(--saltLinkButton-height, var(--salt-size-base));
2569
+ min-width: var(--saltLinkButton-minWidth, unset);
2570
+ position: relative;
2571
+ text-align: var(--saltLinkButton-textAlign, var(--salt-text-action-textAlign));
2572
+ text-decoration: var(--linkButton-textDecoration, var(--salt-typography-textDecoration-underline));
2573
+ text-underline-offset: var(--salt-spacing-fixed-200);
2574
+ transition: none;
2575
+ width: var(--saltLinkButton-width, auto);
2576
+ -webkit-appearance: none;
2577
+ -webkit-tap-highlight-color: transparent;
2578
+ font-weight: var(--saltLinkButton-fontWeight, var(--salt-text-action-fontWeight));
2579
+ }
2580
+ .saltLinkButton-underlineDefault {
2581
+ --linkButton-textDecoration: var(--salt-typography-textDecoration-underline);
2582
+ --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);
2583
+ --linkButton-textDecoration-focus: var(--linkButton-textDecoration-hover);
2584
+ }
2585
+ .saltLinkButton-underlineNever {
2586
+ --linkButton-textDecoration: var(--salt-typography-textDecoration-none);
2587
+ --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);
2588
+ --linkButton-textDecoration-focus: var(--salt-typography-textDecoration-none);
2589
+ }
2590
+ .saltLinkButton-externalLinkADA {
2591
+ position: absolute;
2592
+ width: 1px;
2593
+ height: 1px;
2594
+ padding: 0;
2595
+ margin: -1px;
2596
+ overflow: hidden;
2597
+ clip: rect(0, 0, 0, 0);
2598
+ clip-path: inset(50%);
2599
+ white-space: nowrap;
2600
+ border: 0;
2601
+ user-select: none;
2602
+ -webkit-user-select: none;
2603
+ }
2604
+ @media (hover: hover) {
2605
+ .saltLinkButton:hover {
2606
+ background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));
2607
+ color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));
2608
+ border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));
2609
+ cursor: var(--salt-cursor-hover);
2610
+ text-decoration: var(--linkButton-textDecoration-hover, var(--salt-typography-textDecoration-none));
2611
+ }
2612
+ }
2613
+ .saltLinkButton:focus-visible {
2614
+ outline: var(--salt-focused-outline);
2615
+ background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));
2616
+ color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));
2617
+ border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));
2618
+ text-decoration: var(--linkButton-textDecoration-focus, var(--salt-typography-textDecoration-none));
2619
+ }
2620
+ .saltLinkButton.saltLinkButton-active:focus-visible,
2621
+ .saltLinkButton:focus-visible:active,
2622
+ .saltLinkButton:active,
2623
+ .saltLinkButton.saltLinkButton-active {
2624
+ background: var(--saltLinkButton-background-active, var(--linkButton-background-active));
2625
+ color: var(--saltLinkButton-text-color-active, var(--linkButton-text-color-active));
2626
+ border-color: var(--saltLinkButton-borderColor-active, var(--linkButton-borderColor-active));
2627
+ cursor: var(--salt-cursor-active);
2628
+ }
2629
+ .saltLinkButton-neutral {
2630
+ --linkButton-text-color: var(--salt-actionable-subtle-foreground);
2631
+ --linkButton-text-color-hover: var(--salt-actionable-subtle-foreground-hover);
2632
+ --linkButton-text-color-active: var(--salt-actionable-subtle-foreground-active);
2633
+ --linkButton-background: var(--salt-actionable-subtle-background);
2634
+ --linkButton-background-hover: var(--salt-actionable-subtle-background-hover);
2635
+ --linkButton-background-active: var(--salt-actionable-subtle-background-active);
2636
+ --linkButton-borderColor: var(--salt-actionable-subtle-borderColor);
2637
+ --linkButton-borderColor-hover: var(--salt-actionable-subtle-borderColor-hover);
2638
+ --linkButton-borderColor-active: var(--salt-actionable-subtle-borderColor-active);
2639
+ }
2640
+ .saltLinkButton-accented {
2641
+ --linkButton-text-color: var(--salt-actionable-accented-subtle-foreground);
2642
+ --linkButton-text-color-hover: var(--salt-actionable-accented-subtle-foreground-hover);
2643
+ --linkButton-text-color-active: var(--salt-actionable-accented-subtle-foreground-active);
2644
+ --linkButton-background: var(--salt-actionable-accented-subtle-background);
2645
+ --linkButton-background-hover: var(--salt-actionable-accented-subtle-background-hover);
2646
+ --linkButton-background-active: var(--salt-actionable-accented-subtle-background-active);
2647
+ --linkButton-borderColor: var(--salt-actionable-accented-subtle-borderColor);
2648
+ --linkButton-borderColor-hover: var(--salt-actionable-accented-subtle-borderColor-hover);
2649
+ --linkButton-borderColor-active: var(--salt-actionable-accented-subtle-borderColor-active);
2650
+ }
2651
+
2404
2652
  /* src/link-card/LinkCard.css */
2405
2653
  .saltLinkCard {
2406
2654
  border-radius: var(--saltLinkCard-borderRadius, var(--salt-palette-corner, 0));
2407
2655
  border-style: var(--saltLinkCard-borderStyle, var(--salt-borderStyle-solid));
2408
2656
  border-width: var(--saltLinkCard-borderWidth, var(--salt-size-fixed-100));
2409
- box-shadow: var(--salt-overlayable-shadow);
2657
+ border-color: var(--saltLinkCard-borderColor, var(--linkCard-borderColor));
2410
2658
  display: block;
2411
2659
  overflow: hidden;
2412
2660
  padding: var(--saltLinkCard-padding, var(--card-padding));
@@ -2414,6 +2662,7 @@ a:focus .saltCard-interactable.saltCard-disabled {
2414
2662
  text-decoration: none;
2415
2663
  transition: box-shadow var(--salt-duration-instant) ease-in-out;
2416
2664
  --linkCard-accent-color: var(--salt-sentiment-accent-background);
2665
+ --linkCard-borderColor: var(--salt-container-borderColor);
2417
2666
  --card-padding: var(--salt-spacing-200);
2418
2667
  }
2419
2668
  .saltLinkCard.saltLinkCard-sectioned {
@@ -2430,15 +2679,27 @@ a:focus .saltCard-interactable.saltCard-disabled {
2430
2679
  }
2431
2680
  .saltLinkCard-primary {
2432
2681
  background: var(--saltLinkCard-background, var(--salt-container-primary-background));
2433
- border-color: var(--salt-container-bold-borderColor);
2434
2682
  }
2435
2683
  .saltLinkCard-secondary {
2436
2684
  background: var(--saltLinkCard-background, var(--salt-container-secondary-background));
2437
- border-color: var(--salt-container-bold-borderColor);
2438
2685
  }
2439
2686
  .saltLinkCard-tertiary {
2440
2687
  background: var(--saltLinkCard-background, var(--salt-container-tertiary-background));
2441
- border-color: var(--salt-container-bold-borderColor);
2688
+ }
2689
+ .saltLinkCard-flat {
2690
+ box-shadow: var(--saltLinkCard-boxShadow-flat, none);
2691
+ }
2692
+ .saltLinkCard-raised {
2693
+ box-shadow: var(--saltLinkCard-boxShadow, var(--salt-overlayable-shadow));
2694
+ }
2695
+ .saltLinkCard-borderColorStrong {
2696
+ --linkCard-borderColor: var(--salt-container-bold-borderColor);
2697
+ }
2698
+ .saltLinkCard-borderColorSubtle {
2699
+ --linkCard-borderColor: var(--salt-container-subtle-borderColor);
2700
+ }
2701
+ .saltLinkCard-borderColorNone {
2702
+ --linkCard-borderColor: transparent;
2442
2703
  }
2443
2704
  .saltLinkCard-accent::after {
2444
2705
  content: "";
@@ -3608,9 +3869,12 @@ a:focus .saltCard-interactable.saltCard-disabled {
3608
3869
  overflow: auto;
3609
3870
  padding: var(--saltPanel-padding, var(--salt-spacing-300));
3610
3871
  width: var(--saltPanel-width, 100%);
3611
- border-radius: var(--saltPanel-borderRadius, var(--salt-palette-corner, 0));
3612
3872
  box-sizing: border-box;
3613
3873
  }
3874
+ .saltPanel-raised {
3875
+ border-radius: var(--saltPanel-borderRadius, var(--salt-palette-corner, 0));
3876
+ box-shadow: var(--saltPanel-boxShadow, var(--salt-overlayable-shadow));
3877
+ }
3614
3878
 
3615
3879
  /* src/parent-child-layout/ParentChildLayout.css */
3616
3880
  .saltParentChildLayout {
@@ -7141,4 +7405,4 @@ label.saltText small,
7141
7405
  box-shadow: 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected), 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);
7142
7406
  }
7143
7407
 
7144
- /* src/c5e3d709-38a6-4a0c-a69c-6a4d66821241.css */
7408
+ /* src/cb166099-faaf-4d81-b955-72294da7c0cb.css */
@@ -23,6 +23,7 @@ const AriaAnnouncerProvider = React.forwardRef(function AriaAnnouncerProvider2({
23
23
  const [politeAnnouncements, setPoliteAnnouncements] = React.useState([]);
24
24
  const [assertiveAnnouncements, setAssertiveAnnouncements] = React.useState([]);
25
25
  const idCounterRef = React.useRef(0);
26
+ const isMountedRef = React.useRef(true);
26
27
  const timeoutsRef = React.useRef(/* @__PURE__ */ new Set());
27
28
  const scheduleRemoval = React.useCallback(
28
29
  (id, assertiveness, duration) => {
@@ -40,6 +41,7 @@ const AriaAnnouncerProvider = React.forwardRef(function AriaAnnouncerProvider2({
40
41
  );
41
42
  const makeAnnouncement = React.useCallback(
42
43
  (message, assertiveness = "polite", duration = ANNOUNCEMENT_TIME_IN_DOM) => {
44
+ if (!isMountedRef.current) return;
43
45
  idCounterRef.current += 1;
44
46
  const id = `announce-${assertiveness}-${Date.now()}-${idCounterRef.current}`;
45
47
  if (assertiveness === "polite") {
@@ -55,6 +57,12 @@ const AriaAnnouncerProvider = React.forwardRef(function AriaAnnouncerProvider2({
55
57
  },
56
58
  [scheduleRemoval]
57
59
  );
60
+ React.useEffect(() => {
61
+ isMountedRef.current = true;
62
+ return () => {
63
+ isMountedRef.current = false;
64
+ };
65
+ }, []);
58
66
  React.useEffect(() => {
59
67
  const timeouts = timeoutsRef.current;
60
68
  return () => {
@@ -1 +1 @@
1
- {"version":3,"file":"AriaAnnouncerProvider.js","sources":["../src/aria-announcer/AriaAnnouncerProvider.tsx"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ComponentPropsWithRef,\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../utils/useIsomorphicLayoutEffect\";\nimport {\n type AnnounceFnOptions,\n AriaAnnouncerContext,\n} from \"./AriaAnnouncerContext\";\nimport { registerAnnouncementTarget } from \"./announcementRegistry\";\n\nexport const ANNOUNCEMENT_TIME_IN_DOM = 300; // time between DOM updates\n\nexport interface AriaAnnouncerProviderProps\n extends ComponentPropsWithRef<\"div\"> {\n /**\n * Optional target key used to route announcements to this provider.\n */\n target?: string;\n}\n\nconst AnnouncementRegion = forwardRef<\n HTMLDivElement,\n ComponentPropsWithRef<\"div\">\n>(function AnnouncementRegion(props, ref) {\n return (\n <div\n // Keep the region simple for maximum assistive-tech compatibility.\n // aria-live is applied by the caller (polite/assertive).\n aria-atomic={false}\n ref={ref}\n {...props}\n />\n );\n});\n\ntype AnnouncementMessage = {\n id: string;\n message: string;\n};\n\nexport const AriaAnnouncerProvider = forwardRef<\n HTMLDivElement,\n AriaAnnouncerProviderProps\n>(function AriaAnnouncerProvider({ children, style, target, ...rest }, ref) {\n const targetWindow = useWindow();\n\n const [politeAnnouncements, setPoliteAnnouncements] = useState<\n AnnouncementMessage[]\n >([]);\n const [assertiveAnnouncements, setAssertiveAnnouncements] = useState<\n AnnouncementMessage[]\n >([]);\n\n const idCounterRef = useRef(0);\n const timeoutsRef = useRef<Set<number>>(new Set());\n\n const scheduleRemoval = useCallback(\n (id: string, assertiveness: \"polite\" | \"assertive\", duration: number) => {\n if (!targetWindow) return;\n\n const setter =\n assertiveness === \"polite\"\n ? setPoliteAnnouncements\n : setAssertiveAnnouncements;\n const handle = targetWindow.setTimeout(() => {\n timeoutsRef.current.delete(handle);\n setter((previous) =>\n previous.filter((announcement) => announcement.id !== id),\n );\n }, duration);\n timeoutsRef.current.add(handle);\n },\n [targetWindow],\n );\n\n const makeAnnouncement = useCallback(\n (\n message: string,\n assertiveness: \"polite\" | \"assertive\" = \"polite\",\n duration: number = ANNOUNCEMENT_TIME_IN_DOM,\n ) => {\n idCounterRef.current += 1;\n // Date.now() can collide when multiple announcements are created in the same millisecond\n // (e.g. tests with cy.clock, batching, or multiple announces during one tick).\n // Add a monotonic counter suffix to guarantee uniqueness.\n const id = `announce-${assertiveness}-${Date.now()}-${idCounterRef.current}`;\n if (assertiveness === \"polite\") {\n setPoliteAnnouncements((previous) => {\n return previous.concat({ id, message });\n });\n } else {\n setAssertiveAnnouncements((previous) => {\n return previous.concat({ id, message });\n });\n }\n scheduleRemoval(id, assertiveness, duration);\n },\n [scheduleRemoval],\n );\n\n useEffect(() => {\n const timeouts = timeoutsRef.current;\n return () => {\n for (const handle of timeouts) {\n targetWindow?.clearTimeout(handle);\n }\n timeouts.clear();\n };\n }, [targetWindow]);\n\n const announce = useCallback(\n (\n announcement: string,\n legacyDelayOrOptions: number | AnnounceFnOptions | undefined = {},\n ) => {\n // Legacy delay (number arg) is handled by useAriaAnnouncer; if we also delayed\n // here we'd apply it twice. Keep supporting the signature but ignore the delay.\n const options: AnnounceFnOptions =\n typeof legacyDelayOrOptions === \"object\" && legacyDelayOrOptions\n ? legacyDelayOrOptions\n : {};\n\n makeAnnouncement(\n announcement,\n options.ariaLive,\n options.duration ?? ANNOUNCEMENT_TIME_IN_DOM,\n );\n },\n [makeAnnouncement],\n );\n\n const value = useMemo(() => ({ announce }), [announce]);\n\n useIsomorphicLayoutEffect(() => {\n if (!target) {\n return;\n }\n return registerAnnouncementTarget(target, announce);\n }, [announce, target]);\n\n return (\n <AriaAnnouncerContext.Provider value={value}>\n {children}\n <div\n // hidden styling based on https://tailwindcss.com/docs/screen-readers\n style={{\n position: \"absolute\",\n height: 1,\n width: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n ...style,\n }}\n {...rest}\n ref={ref}\n >\n <AnnouncementRegion aria-live=\"polite\">\n {politeAnnouncements.map((announcement) => (\n <div key={`polite-${announcement.id}`}>{announcement.message}</div>\n ))}\n </AnnouncementRegion>\n <AnnouncementRegion aria-live=\"assertive\">\n {assertiveAnnouncements.map((announcement) => (\n <div key={`assertive-${announcement.id}`}>\n {announcement.message}\n </div>\n ))}\n </AnnouncementRegion>\n </div>\n </AriaAnnouncerContext.Provider>\n );\n});\n"],"names":["forwardRef","AnnouncementRegion","jsx","AriaAnnouncerProvider","useWindow","useState","useRef","useCallback","useEffect","useMemo","useIsomorphicLayoutEffect","registerAnnouncementTarget","jsxs","AriaAnnouncerContext"],"mappings":"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"}
1
+ {"version":3,"file":"AriaAnnouncerProvider.js","sources":["../src/aria-announcer/AriaAnnouncerProvider.tsx"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ComponentPropsWithRef,\n forwardRef,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useIsomorphicLayoutEffect } from \"../utils/useIsomorphicLayoutEffect\";\nimport {\n type AnnounceFnOptions,\n AriaAnnouncerContext,\n} from \"./AriaAnnouncerContext\";\nimport { registerAnnouncementTarget } from \"./announcementRegistry\";\n\nexport const ANNOUNCEMENT_TIME_IN_DOM = 300; // time between DOM updates\n\nexport interface AriaAnnouncerProviderProps\n extends ComponentPropsWithRef<\"div\"> {\n /**\n * Optional target key used to route announcements to this provider.\n */\n target?: string;\n}\n\nconst AnnouncementRegion = forwardRef<\n HTMLDivElement,\n ComponentPropsWithRef<\"div\">\n>(function AnnouncementRegion(props, ref) {\n return (\n <div\n // Keep the region simple for maximum assistive-tech compatibility.\n // aria-live is applied by the caller (polite/assertive).\n aria-atomic={false}\n ref={ref}\n {...props}\n />\n );\n});\n\ntype AnnouncementMessage = {\n id: string;\n message: string;\n};\n\nexport const AriaAnnouncerProvider = forwardRef<\n HTMLDivElement,\n AriaAnnouncerProviderProps\n>(function AriaAnnouncerProvider({ children, style, target, ...rest }, ref) {\n const targetWindow = useWindow();\n\n const [politeAnnouncements, setPoliteAnnouncements] = useState<\n AnnouncementMessage[]\n >([]);\n const [assertiveAnnouncements, setAssertiveAnnouncements] = useState<\n AnnouncementMessage[]\n >([]);\n\n const idCounterRef = useRef(0);\n const isMountedRef = useRef(true);\n const timeoutsRef = useRef<Set<number>>(new Set());\n\n const scheduleRemoval = useCallback(\n (id: string, assertiveness: \"polite\" | \"assertive\", duration: number) => {\n if (!targetWindow) return;\n\n const setter =\n assertiveness === \"polite\"\n ? setPoliteAnnouncements\n : setAssertiveAnnouncements;\n const handle = targetWindow.setTimeout(() => {\n timeoutsRef.current.delete(handle);\n setter((previous) =>\n previous.filter((announcement) => announcement.id !== id),\n );\n }, duration);\n timeoutsRef.current.add(handle);\n },\n [targetWindow],\n );\n\n const makeAnnouncement = useCallback(\n (\n message: string,\n assertiveness: \"polite\" | \"assertive\" = \"polite\",\n duration: number = ANNOUNCEMENT_TIME_IN_DOM,\n ) => {\n if (!isMountedRef.current) return;\n\n idCounterRef.current += 1;\n // Date.now() can collide when multiple announcements are created in the same millisecond\n // (e.g. tests with fake timers, batching, or multiple announces during one tick).\n // Add a monotonic counter suffix to guarantee uniqueness.\n const id = `announce-${assertiveness}-${Date.now()}-${idCounterRef.current}`;\n if (assertiveness === \"polite\") {\n setPoliteAnnouncements((previous) => {\n return previous.concat({ id, message });\n });\n } else {\n setAssertiveAnnouncements((previous) => {\n return previous.concat({ id, message });\n });\n }\n scheduleRemoval(id, assertiveness, duration);\n },\n [scheduleRemoval],\n );\n\n useEffect(() => {\n isMountedRef.current = true;\n return () => {\n isMountedRef.current = false;\n };\n }, []);\n\n useEffect(() => {\n const timeouts = timeoutsRef.current;\n return () => {\n for (const handle of timeouts) {\n targetWindow?.clearTimeout(handle);\n }\n timeouts.clear();\n };\n }, [targetWindow]);\n\n const announce = useCallback(\n (\n announcement: string,\n legacyDelayOrOptions: number | AnnounceFnOptions | undefined = {},\n ) => {\n // Legacy delay (number arg) is handled by useAriaAnnouncer; if we also delayed\n // here we'd apply it twice. Keep supporting the signature but ignore the delay.\n const options: AnnounceFnOptions =\n typeof legacyDelayOrOptions === \"object\" && legacyDelayOrOptions\n ? legacyDelayOrOptions\n : {};\n\n makeAnnouncement(\n announcement,\n options.ariaLive,\n options.duration ?? ANNOUNCEMENT_TIME_IN_DOM,\n );\n },\n [makeAnnouncement],\n );\n\n const value = useMemo(() => ({ announce }), [announce]);\n\n useIsomorphicLayoutEffect(() => {\n if (!target) {\n return;\n }\n return registerAnnouncementTarget(target, announce);\n }, [announce, target]);\n\n return (\n <AriaAnnouncerContext.Provider value={value}>\n {children}\n <div\n // hidden styling based on https://tailwindcss.com/docs/screen-readers\n style={{\n position: \"absolute\",\n height: 1,\n width: 1,\n padding: 0,\n margin: -1,\n overflow: \"hidden\",\n clip: \"rect(0, 0, 0, 0)\",\n whiteSpace: \"nowrap\",\n borderWidth: 0,\n ...style,\n }}\n {...rest}\n ref={ref}\n >\n <AnnouncementRegion aria-live=\"polite\">\n {politeAnnouncements.map((announcement) => (\n <div key={`polite-${announcement.id}`}>{announcement.message}</div>\n ))}\n </AnnouncementRegion>\n <AnnouncementRegion aria-live=\"assertive\">\n {assertiveAnnouncements.map((announcement) => (\n <div key={`assertive-${announcement.id}`}>\n {announcement.message}\n </div>\n ))}\n </AnnouncementRegion>\n </div>\n </AriaAnnouncerContext.Provider>\n );\n});\n"],"names":["forwardRef","AnnouncementRegion","jsx","AriaAnnouncerProvider","useWindow","useState","useRef","useCallback","useEffect","useMemo","useIsomorphicLayoutEffect","registerAnnouncementTarget","jsxs","AriaAnnouncerContext"],"mappings":"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"}