@salt-ds/core 1.53.0 → 1.54.1

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 (122) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/css/salt-core.css +47 -45
  3. package/dist-cjs/avatar/Avatar.css.js +1 -1
  4. package/dist-cjs/badge/Badge.css.js +1 -1
  5. package/dist-cjs/collapsible/CollapsibleTrigger.js +3 -2
  6. package/dist-cjs/collapsible/CollapsibleTrigger.js.map +1 -1
  7. package/dist-cjs/combo-box/ComboBox.js +2 -1
  8. package/dist-cjs/combo-box/ComboBox.js.map +1 -1
  9. package/dist-cjs/index.js +2 -0
  10. package/dist-cjs/index.js.map +1 -1
  11. package/dist-cjs/list-control/ListControlState.js +108 -87
  12. package/dist-cjs/list-control/ListControlState.js.map +1 -1
  13. package/dist-cjs/menu/MenuBase.js +5 -2
  14. package/dist-cjs/menu/MenuBase.js.map +1 -1
  15. package/dist-cjs/menu/MenuContext.js +3 -1
  16. package/dist-cjs/menu/MenuContext.js.map +1 -1
  17. package/dist-cjs/menu/MenuItem.js +5 -0
  18. package/dist-cjs/menu/MenuItem.js.map +1 -1
  19. package/dist-cjs/menu/MenuTrigger.js +3 -2
  20. package/dist-cjs/menu/MenuTrigger.js.map +1 -1
  21. package/dist-cjs/multiline-input/MultilineInput.js +2 -1
  22. package/dist-cjs/multiline-input/MultilineInput.js.map +1 -1
  23. package/dist-cjs/number-input/NumberInput.js +7 -7
  24. package/dist-cjs/number-input/NumberInput.js.map +1 -1
  25. package/dist-cjs/number-input/internal/useLongPressPointerAction.js +63 -0
  26. package/dist-cjs/number-input/internal/useLongPressPointerAction.js.map +1 -0
  27. package/dist-cjs/overlay/OverlayTrigger.js +2 -2
  28. package/dist-cjs/overlay/OverlayTrigger.js.map +1 -1
  29. package/dist-cjs/pill/Pill.js +72 -9
  30. package/dist-cjs/pill/Pill.js.map +1 -1
  31. package/dist-cjs/pill/PillCheckIcon.css.js +6 -0
  32. package/dist-cjs/pill/PillCheckIcon.css.js.map +1 -0
  33. package/dist-cjs/pill/PillCheckIcon.js +48 -0
  34. package/dist-cjs/pill/PillCheckIcon.js.map +1 -0
  35. package/dist-cjs/pill/PillGroup.css.js +6 -0
  36. package/dist-cjs/pill/PillGroup.css.js.map +1 -0
  37. package/dist-cjs/pill/PillGroup.js +83 -0
  38. package/dist-cjs/pill/PillGroup.js.map +1 -0
  39. package/dist-cjs/pill/PillGroupContext.js +27 -0
  40. package/dist-cjs/pill/PillGroupContext.js.map +1 -0
  41. package/dist-cjs/pill-input/PillInput.js +1 -0
  42. package/dist-cjs/pill-input/PillInput.js.map +1 -1
  43. package/dist-cjs/salt-provider/ProviderContext.js +11 -0
  44. package/dist-cjs/salt-provider/ProviderContext.js.map +1 -0
  45. package/dist-cjs/salt-provider/SaltProvider.js +24 -132
  46. package/dist-cjs/salt-provider/SaltProvider.js.map +1 -1
  47. package/dist-cjs/salt-provider/ThemeApplicator.js +115 -0
  48. package/dist-cjs/salt-provider/ThemeApplicator.js.map +1 -0
  49. package/dist-cjs/slider/internal/useRangeSliderThumb.js +14 -5
  50. package/dist-cjs/slider/internal/useRangeSliderThumb.js.map +1 -1
  51. package/dist-cjs/slider/internal/useSliderThumb.js +14 -5
  52. package/dist-cjs/slider/internal/useSliderThumb.js.map +1 -1
  53. package/dist-cjs/tag/Tag.css.js +1 -1
  54. package/dist-cjs/toggle-button/ToggleButton.css.js +1 -1
  55. package/dist-es/avatar/Avatar.css.js +1 -1
  56. package/dist-es/badge/Badge.css.js +1 -1
  57. package/dist-es/collapsible/CollapsibleTrigger.js +3 -2
  58. package/dist-es/collapsible/CollapsibleTrigger.js.map +1 -1
  59. package/dist-es/combo-box/ComboBox.js +3 -2
  60. package/dist-es/combo-box/ComboBox.js.map +1 -1
  61. package/dist-es/index.js +1 -0
  62. package/dist-es/index.js.map +1 -1
  63. package/dist-es/list-control/ListControlState.js +108 -87
  64. package/dist-es/list-control/ListControlState.js.map +1 -1
  65. package/dist-es/menu/MenuBase.js +5 -2
  66. package/dist-es/menu/MenuBase.js.map +1 -1
  67. package/dist-es/menu/MenuContext.js +3 -1
  68. package/dist-es/menu/MenuContext.js.map +1 -1
  69. package/dist-es/menu/MenuItem.js +6 -1
  70. package/dist-es/menu/MenuItem.js.map +1 -1
  71. package/dist-es/menu/MenuTrigger.js +3 -2
  72. package/dist-es/menu/MenuTrigger.js.map +1 -1
  73. package/dist-es/multiline-input/MultilineInput.js +3 -2
  74. package/dist-es/multiline-input/MultilineInput.js.map +1 -1
  75. package/dist-es/number-input/NumberInput.js +7 -7
  76. package/dist-es/number-input/NumberInput.js.map +1 -1
  77. package/dist-es/number-input/internal/useLongPressPointerAction.js +61 -0
  78. package/dist-es/number-input/internal/useLongPressPointerAction.js.map +1 -0
  79. package/dist-es/overlay/OverlayTrigger.js +2 -2
  80. package/dist-es/overlay/OverlayTrigger.js.map +1 -1
  81. package/dist-es/pill/Pill.js +74 -11
  82. package/dist-es/pill/Pill.js.map +1 -1
  83. package/dist-es/pill/PillCheckIcon.css.js +4 -0
  84. package/dist-es/pill/PillCheckIcon.css.js.map +1 -0
  85. package/dist-es/pill/PillCheckIcon.js +46 -0
  86. package/dist-es/pill/PillCheckIcon.js.map +1 -0
  87. package/dist-es/pill/PillGroup.css.js +4 -0
  88. package/dist-es/pill/PillGroup.css.js.map +1 -0
  89. package/dist-es/pill/PillGroup.js +81 -0
  90. package/dist-es/pill/PillGroup.js.map +1 -0
  91. package/dist-es/pill/PillGroupContext.js +24 -0
  92. package/dist-es/pill/PillGroupContext.js.map +1 -0
  93. package/dist-es/pill-input/PillInput.js +1 -0
  94. package/dist-es/pill-input/PillInput.js.map +1 -1
  95. package/dist-es/salt-provider/ProviderContext.js +9 -0
  96. package/dist-es/salt-provider/ProviderContext.js.map +1 -0
  97. package/dist-es/salt-provider/SaltProvider.js +25 -133
  98. package/dist-es/salt-provider/SaltProvider.js.map +1 -1
  99. package/dist-es/salt-provider/ThemeApplicator.js +113 -0
  100. package/dist-es/salt-provider/ThemeApplicator.js.map +1 -0
  101. package/dist-es/slider/internal/useRangeSliderThumb.js +14 -5
  102. package/dist-es/slider/internal/useRangeSliderThumb.js.map +1 -1
  103. package/dist-es/slider/internal/useSliderThumb.js +14 -5
  104. package/dist-es/slider/internal/useSliderThumb.js.map +1 -1
  105. package/dist-es/tag/Tag.css.js +1 -1
  106. package/dist-es/toggle-button/ToggleButton.css.js +1 -1
  107. package/dist-types/menu/MenuContext.d.ts +2 -0
  108. package/dist-types/number-input/internal/useLongPressPointerAction.d.ts +2 -0
  109. package/dist-types/pill/Pill.d.ts +1 -0
  110. package/dist-types/pill/PillCheckIcon.d.ts +7 -0
  111. package/dist-types/pill/PillGroup.d.ts +34 -0
  112. package/dist-types/pill/PillGroupContext.d.ts +9 -0
  113. package/dist-types/pill/index.d.ts +1 -0
  114. package/dist-types/salt-provider/ProviderContext.d.ts +5 -0
  115. package/dist-types/salt-provider/SaltProvider.d.ts +5 -56
  116. package/dist-types/salt-provider/ThemeApplicator.d.ts +56 -0
  117. package/package.json +2 -2
  118. package/dist-cjs/number-input/internal/useActivateWhileMouseDown.js +0 -50
  119. package/dist-cjs/number-input/internal/useActivateWhileMouseDown.js.map +0 -1
  120. package/dist-es/number-input/internal/useActivateWhileMouseDown.js +0 -48
  121. package/dist-es/number-input/internal/useActivateWhileMouseDown.js.map +0 -1
  122. package/dist-types/number-input/internal/useActivateWhileMouseDown.d.ts +0 -5
@@ -9,9 +9,10 @@ require('../aria-announcer/AriaAnnouncerContext.js');
9
9
  var AriaAnnouncerProvider = require('../aria-announcer/AriaAnnouncerProvider.js');
10
10
  var BreakpointProvider = require('../breakpoints/BreakpointProvider.js');
11
11
  var Breakpoints = require('../breakpoints/Breakpoints.js');
12
- var useIsomorphicLayoutEffect = require('../utils/useIsomorphicLayoutEffect.js');
13
12
  var ViewportProvider = require('../viewport/ViewportProvider.js');
13
+ var ProviderContext = require('./ProviderContext.js');
14
14
  var SaltProvider$1 = require('./SaltProvider.css.js');
15
+ var ThemeApplicator = require('./ThemeApplicator.js');
15
16
 
16
17
  const DEFAULT_DENSITY = "medium";
17
18
  const DEFAULT_THEME_NAME = "salt-theme";
@@ -36,70 +37,6 @@ const ThemeContext = React.createContext({
36
37
  UNSTABLE_actionFont: DEFAULT_ACTION_FONT
37
38
  });
38
39
  const BreakpointContext = React.createContext(Breakpoints.DEFAULT_BREAKPOINTS);
39
- const getThemeNames = (themeName, themeNext) => {
40
- if (themeNext) {
41
- return themeName === DEFAULT_THEME_NAME ? clsx.clsx(DEFAULT_THEME_NAME, DEFAULT_THEME_NAME_NEXT) : clsx.clsx(DEFAULT_THEME_NAME, DEFAULT_THEME_NAME_NEXT, themeName);
42
- }
43
- return themeName === DEFAULT_THEME_NAME ? themeName : clsx.clsx(DEFAULT_THEME_NAME, themeName);
44
- };
45
- const createThemedChildren = ({
46
- children,
47
- themeName,
48
- density,
49
- mode,
50
- applyClassesTo,
51
- themeNext,
52
- corner,
53
- headingFont,
54
- accent,
55
- actionFont
56
- }) => {
57
- var _a;
58
- const themeNamesString = getThemeNames(themeName, themeNext);
59
- const themeNextProps = {
60
- "data-corner": corner,
61
- "data-heading-font": headingFont,
62
- "data-accent": accent,
63
- "data-action-font": actionFont
64
- };
65
- if (applyClassesTo === "root") {
66
- return children;
67
- }
68
- if (applyClassesTo === "child") {
69
- if (React.isValidElement(children)) {
70
- return React.cloneElement(children, {
71
- className: clsx.clsx(
72
- (_a = children.props) == null ? void 0 : _a.className,
73
- themeNamesString,
74
- `salt-density-${density}`
75
- ),
76
- // @ts-expect-error
77
- "data-mode": mode,
78
- ...themeNext ? themeNextProps : {}
79
- });
80
- }
81
- console.warn(
82
- `
83
- SaltProvider can only apply CSS classes for theming to a single nested child element of the SaltProvider.
84
- Either wrap elements with a single container or consider removing the applyClassesToChild prop, in which case a
85
- div element will wrap your child elements`
86
- );
87
- return children;
88
- }
89
- return /* @__PURE__ */ jsxRuntime.jsx(
90
- "div",
91
- {
92
- className: clsx.clsx(
93
- "salt-provider",
94
- themeNamesString,
95
- `salt-density-${density}`
96
- ),
97
- "data-mode": mode,
98
- ...themeNext ? themeNextProps : {},
99
- children
100
- }
101
- );
102
- };
103
40
  function InternalSaltProvider({
104
41
  applyClassesTo: applyClassesToProp,
105
42
  children,
@@ -113,26 +50,26 @@ function InternalSaltProvider({
113
50
  accent: accentProp,
114
51
  actionFont: actionFontProp
115
52
  }) {
53
+ const prevProvider = React.useContext(ProviderContext.ProviderContext);
116
54
  const inheritedDensity = React.useContext(DensityContext);
117
55
  const {
118
56
  theme: inheritedTheme,
119
57
  mode: inheritedMode,
120
- window: inheritedWindow,
121
58
  corner: inheritedCorner,
122
59
  headingFont: inheritedHeadingFont,
123
60
  accent: inheritedAccent,
124
61
  actionFont: inheritedActionFont
125
62
  } = React.useContext(ThemeContext);
126
- const isRootProvider = inheritedTheme === void 0 || inheritedTheme === "";
63
+ const isRootProvider = prevProvider === null;
127
64
  const density = densityProp ?? inheritedDensity ?? DEFAULT_DENSITY;
128
- const themeName = themeProp ?? (inheritedTheme === "" ? DEFAULT_THEME_NAME : inheritedTheme);
65
+ const inheritedThemeName = inheritedTheme === "" ? DEFAULT_THEME_NAME : inheritedTheme;
66
+ const themeName = themeProp ?? inheritedThemeName;
129
67
  const mode = modeProp ?? inheritedMode;
130
68
  const breakpoints = breakpointsProp ?? Breakpoints.DEFAULT_BREAKPOINTS;
131
69
  const corner = cornerProp ?? inheritedCorner ?? DEFAULT_CORNER;
132
70
  const headingFont = headingFontProp ?? inheritedHeadingFont ?? DEFAULT_HEADING_FONT;
133
71
  const accent = accentProp ?? inheritedAccent ?? DEFAULT_ACCENT;
134
72
  const actionFont = actionFontProp ?? inheritedActionFont ?? DEFAULT_ACTION_FONT;
135
- const applyClassesTo = applyClassesToProp ?? (isRootProvider ? "root" : "scope");
136
73
  const targetWindow = window.useWindow();
137
74
  styles.useComponentCssInjection({
138
75
  testId: "salt-provider",
@@ -166,70 +103,25 @@ function InternalSaltProvider({
166
103
  actionFont
167
104
  ]
168
105
  );
169
- const themedChildren = createThemedChildren({
170
- children,
171
- themeName,
172
- density,
173
- mode,
174
- applyClassesTo,
175
- themeNext,
176
- corner,
177
- headingFont,
178
- accent,
179
- actionFont
180
- });
181
- useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
182
- const themeNamesString = getThemeNames(themeName, themeNext);
183
- const themeNames = themeNamesString.split(" ");
184
- if (applyClassesTo === "root" && targetWindow) {
185
- if (inheritedWindow !== targetWindow) {
186
- targetWindow.document.documentElement.classList.add(
187
- ...themeNames,
188
- `salt-density-${density}`
189
- );
190
- targetWindow.document.documentElement.dataset.mode = mode;
191
- if (themeNext) {
192
- targetWindow.document.documentElement.dataset.corner = corner;
193
- targetWindow.document.documentElement.dataset.headingFont = headingFont;
194
- targetWindow.document.documentElement.dataset.accent = accent;
195
- targetWindow.document.documentElement.dataset.actionFont = actionFont;
196
- }
197
- } else {
198
- console.warn(
199
- "SaltProvider can only apply CSS classes to the root if it is the root level SaltProvider."
200
- );
201
- }
202
- }
203
- return () => {
204
- if (applyClassesTo === "root" && targetWindow) {
205
- targetWindow.document.documentElement.classList.remove(
206
- ...themeNames,
207
- `salt-density-${density}`
208
- );
209
- targetWindow.document.documentElement.dataset.mode = void 0;
210
- if (themeNext) {
211
- delete targetWindow.document.documentElement.dataset.corner;
212
- delete targetWindow.document.documentElement.dataset.headingFont;
213
- delete targetWindow.document.documentElement.dataset.accent;
214
- delete targetWindow.document.documentElement.dataset.actionFont;
215
- }
216
- }
217
- };
218
- }, [
219
- applyClassesTo,
220
- density,
221
- mode,
222
- themeName,
223
- targetWindow,
224
- inheritedWindow,
225
- themeNext,
226
- corner,
227
- headingFont,
228
- accent,
229
- actionFont
230
- ]);
231
106
  const matchedBreakpoints = BreakpointProvider.useMatchedBreakpoints(breakpoints);
232
- const saltProvider = /* @__PURE__ */ jsxRuntime.jsx(DensityContext.Provider, { value: density, children: /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: themeContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(BreakpointProvider.BreakpointProvider, { matchedBreakpoints, children: /* @__PURE__ */ jsxRuntime.jsx(BreakpointContext.Provider, { value: breakpoints, children: /* @__PURE__ */ jsxRuntime.jsx(ViewportProvider.ViewportProvider, { children: themedChildren }) }) }) }) });
107
+ const saltProvider = /* @__PURE__ */ jsxRuntime.jsx(ProviderContext.ProviderContext.Provider, { value: { targetWindow }, children: /* @__PURE__ */ jsxRuntime.jsx(DensityContext.Provider, { value: density, children: /* @__PURE__ */ jsxRuntime.jsx(ThemeContext.Provider, { value: themeContextValue, children: /* @__PURE__ */ jsxRuntime.jsx(BreakpointProvider.BreakpointProvider, { matchedBreakpoints, children: /* @__PURE__ */ jsxRuntime.jsx(BreakpointContext.Provider, { value: breakpoints, children: /* @__PURE__ */ jsxRuntime.jsx(ViewportProvider.ViewportProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
108
+ ThemeApplicator.ThemeApplicator,
109
+ {
110
+ applyClassesTo: applyClassesToProp ?? (isRootProvider ? "root" : "scope"),
111
+ density,
112
+ theme: clsx.clsx(
113
+ DEFAULT_THEME_NAME,
114
+ { [DEFAULT_THEME_NAME_NEXT]: themeNext },
115
+ themeProp
116
+ ),
117
+ mode,
118
+ accent: themeNext ? accent : void 0,
119
+ actionFont: themeNext ? actionFont : void 0,
120
+ headingFont: themeNext ? headingFont : void 0,
121
+ corner: themeNext ? corner : void 0,
122
+ children
123
+ }
124
+ ) }) }) }) }) }) });
233
125
  if (isRootProvider) {
234
126
  return /* @__PURE__ */ jsxRuntime.jsx(AriaAnnouncerProvider.AriaAnnouncerProvider, { children: saltProvider });
235
127
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SaltProvider.js","sources":["../src/salt-provider/SaltProvider.tsx"],"sourcesContent":["import {\n StyleInjectionProvider,\n useComponentCssInjection,\n} from \"@salt-ds/styles\";\nimport { useWindow, type WindowContextType } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n cloneElement,\n createContext,\n type HTMLAttributes,\n isValidElement,\n type ReactElement,\n type ReactNode,\n useContext,\n useMemo,\n} from \"react\";\nimport { AriaAnnouncerProvider } from \"../aria-announcer\";\nimport {\n BreakpointProvider,\n type Breakpoints,\n DEFAULT_BREAKPOINTS,\n useMatchedBreakpoints,\n} from \"../breakpoints\";\nimport type {\n Accent,\n ActionFont,\n Corner,\n Density,\n HeadingFont,\n Mode,\n ThemeName,\n} from \"../theme\";\nimport { useIsomorphicLayoutEffect } from \"../utils/useIsomorphicLayoutEffect\";\nimport { ViewportProvider } from \"../viewport\";\nimport saltProviderCss from \"./SaltProvider.css\";\n\nexport const DEFAULT_DENSITY = \"medium\";\n\nconst DEFAULT_THEME_NAME = \"salt-theme\";\nconst DEFAULT_THEME_NAME_NEXT = \"salt-theme-next\";\n\nconst DEFAULT_MODE = \"light\";\nconst DEFAULT_CORNER: Corner = \"sharp\";\nconst DEFAULT_HEADING_FONT: HeadingFont = \"Open Sans\";\nconst DEFAULT_ACCENT: Accent = \"blue\";\nconst DEFAULT_ACTION_FONT: ActionFont = \"Open Sans\";\nexport interface ThemeContextProps {\n theme: ThemeName;\n mode: Mode;\n window?: WindowContextType;\n /** Only available when using SaltProviderNext. */\n themeNext: boolean;\n corner: Corner;\n /** @deprecated use `corner`*/\n UNSTABLE_corner: Corner;\n headingFont: HeadingFont;\n /** @deprecated use `headingFont` */\n UNSTABLE_headingFont: HeadingFont;\n accent: Accent;\n /** @deprecated use `accent` */\n UNSTABLE_accent: Accent;\n actionFont: ActionFont;\n /** @deprecated use `actionFont` */\n UNSTABLE_actionFont: ActionFont;\n}\n\nexport const DensityContext = createContext<Density>(DEFAULT_DENSITY);\n\nexport const ThemeContext = createContext<ThemeContextProps>({\n theme: \"\",\n mode: DEFAULT_MODE,\n themeNext: false,\n corner: DEFAULT_CORNER,\n UNSTABLE_corner: DEFAULT_CORNER,\n headingFont: DEFAULT_HEADING_FONT,\n UNSTABLE_headingFont: DEFAULT_HEADING_FONT,\n accent: DEFAULT_ACCENT,\n UNSTABLE_accent: DEFAULT_ACCENT,\n actionFont: DEFAULT_ACTION_FONT,\n UNSTABLE_actionFont: DEFAULT_ACTION_FONT,\n});\n\nexport const BreakpointContext =\n createContext<Breakpoints>(DEFAULT_BREAKPOINTS);\n\n/**\n * We're relying `DEFAULT_THEME_NAME` to determine whether the provider is a root.\n */\nconst getThemeNames = (\n themeName: ThemeName,\n themeNext?: boolean,\n): ThemeName => {\n if (themeNext) {\n return themeName === DEFAULT_THEME_NAME\n ? clsx(DEFAULT_THEME_NAME, DEFAULT_THEME_NAME_NEXT)\n : clsx(DEFAULT_THEME_NAME, DEFAULT_THEME_NAME_NEXT, themeName);\n }\n return themeName === DEFAULT_THEME_NAME\n ? themeName\n : clsx(DEFAULT_THEME_NAME, themeName);\n};\n\ninterface ThemeNextProps {\n themeNext?: boolean;\n}\n\nconst createThemedChildren = ({\n children,\n themeName,\n density,\n mode,\n applyClassesTo,\n themeNext,\n corner,\n headingFont,\n accent,\n actionFont,\n}: {\n children: ReactNode;\n themeName: ThemeName;\n density: Density;\n mode: Mode;\n applyClassesTo?: TargetElement;\n} & ThemeNextProps &\n SaltProviderNextAdditionalProps) => {\n const themeNamesString = getThemeNames(themeName, themeNext);\n const themeNextProps = {\n \"data-corner\": corner,\n \"data-heading-font\": headingFont,\n \"data-accent\": accent,\n \"data-action-font\": actionFont,\n };\n if (applyClassesTo === \"root\") {\n return children;\n }\n if (applyClassesTo === \"child\") {\n if (isValidElement<HTMLAttributes<HTMLElement>>(children)) {\n return cloneElement(children, {\n className: clsx(\n children.props?.className,\n themeNamesString,\n `salt-density-${density}`,\n ),\n // @ts-expect-error\n \"data-mode\": mode,\n ...(themeNext ? themeNextProps : {}),\n });\n }\n console.warn(\n `\\nSaltProvider can only apply CSS classes for theming to a single nested child element of the SaltProvider.\n Either wrap elements with a single container or consider removing the applyClassesToChild prop, in which case a\n div element will wrap your child elements`,\n );\n return children;\n }\n return (\n <div\n className={clsx(\n \"salt-provider\",\n themeNamesString,\n `salt-density-${density}`,\n )}\n data-mode={mode}\n {...(themeNext ? themeNextProps : {})}\n >\n {children}\n </div>\n );\n};\n\ntype TargetElement = \"root\" | \"scope\" | \"child\";\n\ninterface SaltProviderBaseProps {\n /**\n * Either \"root\", \"scope\" or \"child\".\n * Specifies the location of salt theme class and attributes should be applied to.\n *\n * Defaults to \"root\" for a root provider, otherwise \"scope\".\n */\n applyClassesTo?: TargetElement;\n /**\n * Either \"high\", \"medium\", \"low\" or \"touch\".\n * Determines the amount of content that can fit on a screen based on the size and spacing of components.\n * Refer to [density](https://www.saltdesignsystem.com/salt/foundations/density) doc for more detail.\n *\n * @default \"medium\"\n */\n density?: Density;\n /**\n * A string. Specifies custom theme name(s) you want to apply, similar to `className`.\n */\n theme?: ThemeName;\n /**\n * Either \"light\" or \"dark\". Enable the color palette to change from light to dark.\n * Refer to [modes](https://www.saltdesignsystem.com/salt/foundations/modes) doc for more detail.\n *\n * @default \"light\"\n */\n mode?: Mode;\n /**\n * Shape of `{ xs: number; sm: number; md: number; lg: number; xl: number; }`.\n * Determines breakpoints used in responsive calculation for layout components.\n */\n breakpoints?: Breakpoints;\n /**\n * A boolean. Enables dynamic style injection for each component.\n *\n * If `false`, you'll need to include component CSS yourself.\n *\n * @default true\n */\n enableStyleInjection?: boolean;\n}\n\ninterface SaltProviderThatAppliesClassesToChild extends SaltProviderBaseProps {\n children: ReactElement;\n applyClassesTo: \"child\";\n}\n\ninterface SaltProviderThatInjectsThemeElement extends SaltProviderBaseProps {\n children: ReactNode;\n}\n\ninterface SaltProviderThatClassesToRoot\n extends SaltProviderThatInjectsThemeElement {\n applyClassesTo: \"root\";\n}\n\ntype SaltProviderProps =\n | SaltProviderThatAppliesClassesToChild\n | SaltProviderThatInjectsThemeElement\n | SaltProviderThatClassesToRoot;\n\nfunction InternalSaltProvider({\n applyClassesTo: applyClassesToProp,\n children,\n density: densityProp,\n theme: themeProp,\n mode: modeProp,\n breakpoints: breakpointsProp,\n themeNext,\n corner: cornerProp,\n headingFont: headingFontProp,\n accent: accentProp,\n actionFont: actionFontProp,\n}: Omit<\n SaltProviderProps & ThemeNextProps & SaltProviderNextProps,\n \"enableStyleInjection\"\n>) {\n const inheritedDensity = useContext(DensityContext);\n const {\n theme: inheritedTheme,\n mode: inheritedMode,\n window: inheritedWindow,\n corner: inheritedCorner,\n headingFont: inheritedHeadingFont,\n accent: inheritedAccent,\n actionFont: inheritedActionFont,\n } = useContext(ThemeContext);\n\n const isRootProvider = inheritedTheme === undefined || inheritedTheme === \"\";\n const density = densityProp ?? inheritedDensity ?? DEFAULT_DENSITY;\n const themeName =\n themeProp ?? (inheritedTheme === \"\" ? DEFAULT_THEME_NAME : inheritedTheme);\n const mode = modeProp ?? inheritedMode;\n const breakpoints = breakpointsProp ?? DEFAULT_BREAKPOINTS;\n const corner = cornerProp ?? inheritedCorner ?? DEFAULT_CORNER;\n const headingFont =\n headingFontProp ?? inheritedHeadingFont ?? DEFAULT_HEADING_FONT;\n const accent = accentProp ?? inheritedAccent ?? DEFAULT_ACCENT;\n const actionFont =\n actionFontProp ?? inheritedActionFont ?? DEFAULT_ACTION_FONT;\n\n const applyClassesTo =\n applyClassesToProp ?? (isRootProvider ? \"root\" : \"scope\");\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-provider\",\n css: saltProviderCss,\n window: targetWindow,\n });\n\n const themeContextValue = useMemo(\n () => ({\n theme: themeName,\n mode,\n window: targetWindow,\n themeNext: Boolean(themeNext),\n corner: corner,\n headingFont: headingFont,\n accent: accent,\n actionFont: actionFont,\n // Backward compatibility\n UNSTABLE_corner: corner,\n UNSTABLE_headingFont: headingFont,\n UNSTABLE_accent: accent,\n UNSTABLE_actionFont: actionFont,\n }),\n [\n themeName,\n mode,\n targetWindow,\n themeNext,\n corner,\n headingFont,\n accent,\n actionFont,\n ],\n );\n\n const themedChildren = createThemedChildren({\n children,\n themeName,\n density,\n mode,\n applyClassesTo,\n themeNext,\n corner: corner,\n headingFont,\n accent,\n actionFont,\n });\n\n useIsomorphicLayoutEffect(() => {\n const themeNamesString = getThemeNames(themeName, themeNext);\n const themeNames = themeNamesString.split(\" \");\n\n if (applyClassesTo === \"root\" && targetWindow) {\n if (inheritedWindow !== targetWindow) {\n // add the styles we want to apply\n targetWindow.document.documentElement.classList.add(\n ...themeNames,\n `salt-density-${density}`,\n );\n targetWindow.document.documentElement.dataset.mode = mode;\n if (themeNext) {\n targetWindow.document.documentElement.dataset.corner = corner;\n targetWindow.document.documentElement.dataset.headingFont =\n headingFont;\n targetWindow.document.documentElement.dataset.accent = accent;\n targetWindow.document.documentElement.dataset.actionFont = actionFont;\n }\n } else {\n console.warn(\n \"SaltProvider can only apply CSS classes to the root if it is the root level SaltProvider.\",\n );\n }\n }\n return () => {\n if (applyClassesTo === \"root\" && targetWindow) {\n // When unmounting/remounting, remove the applied styles from the root\n targetWindow.document.documentElement.classList.remove(\n ...themeNames,\n `salt-density-${density}`,\n );\n targetWindow.document.documentElement.dataset.mode = undefined;\n if (themeNext) {\n delete targetWindow.document.documentElement.dataset.corner;\n delete targetWindow.document.documentElement.dataset.headingFont;\n delete targetWindow.document.documentElement.dataset.accent;\n delete targetWindow.document.documentElement.dataset.actionFont;\n }\n }\n };\n }, [\n applyClassesTo,\n density,\n mode,\n themeName,\n targetWindow,\n inheritedWindow,\n themeNext,\n corner,\n headingFont,\n accent,\n actionFont,\n ]);\n\n const matchedBreakpoints = useMatchedBreakpoints(breakpoints);\n\n const saltProvider = (\n <DensityContext.Provider value={density}>\n <ThemeContext.Provider value={themeContextValue}>\n <BreakpointProvider matchedBreakpoints={matchedBreakpoints}>\n <BreakpointContext.Provider value={breakpoints}>\n <ViewportProvider>{themedChildren}</ViewportProvider>\n </BreakpointContext.Provider>\n </BreakpointProvider>\n </ThemeContext.Provider>\n </DensityContext.Provider>\n );\n\n if (isRootProvider) {\n return <AriaAnnouncerProvider>{saltProvider}</AriaAnnouncerProvider>;\n }\n return saltProvider;\n}\n\nexport function SaltProvider({\n enableStyleInjection,\n ...restProps\n}: SaltProviderProps) {\n return (\n <StyleInjectionProvider value={enableStyleInjection}>\n <InternalSaltProvider {...restProps} />\n </StyleInjectionProvider>\n );\n}\n\ninterface SaltProviderNextAdditionalProps {\n /**\n * Either \"sharp\" or \"rounded\".\n * Determines selected components corner radius.\n * @default \"sharp\"\n */\n corner?: Corner;\n /**\n * Either \"Open Sans\" or \"Amplitude\".\n * Determines font family of display and heading text.\n * @default \"Open Sans\"\n */\n headingFont?: HeadingFont;\n /**\n * Either \"blue\" or \"teal\".\n * Determines accent color used across components, e.g. Accent Button, List, Calendar.\n * @default \"blue\"\n */\n accent?: Accent;\n /**\n * Either \"Open Sans\" or \"Amplitude\".\n * Determines font family of action components, mostly Buttons.\n * @default \"Open Sans\"\n */\n actionFont?: ActionFont;\n}\n\nexport type SaltProviderNextProps = SaltProviderProps &\n SaltProviderNextAdditionalProps;\n/** @deprecated use `SaltProviderNextProps` */\nexport type UNSTABLE_SaltProviderNextProps = SaltProviderNextProps;\n\nexport function SaltProviderNext({\n enableStyleInjection,\n ...restProps\n}: SaltProviderNextProps) {\n return (\n <StyleInjectionProvider value={enableStyleInjection}>\n {/* Leveraging InternalSaltProvider being not exported, so we can pass more props than previously supported */}\n <InternalSaltProvider {...restProps} themeNext={true} />\n </StyleInjectionProvider>\n );\n}\n/** @deprecated use `SaltProviderNext` */\nexport const UNSTABLE_SaltProviderNext = SaltProviderNext;\n\nexport const useTheme = (): ThemeContextProps => {\n const { window: _window, ...contextWithoutWindow } = useContext(ThemeContext);\n\n return contextWithoutWindow;\n};\n\n/**\n * `useDensity` merges density value from `DensityContext` with the one from component's props.\n */\nexport function useDensity(density?: Density): Density {\n const densityFromContext = useContext(DensityContext);\n return density ?? densityFromContext ?? DEFAULT_DENSITY;\n}\n\nexport const useBreakpoints = (): Breakpoints => {\n return useContext(BreakpointContext);\n};\n"],"names":["createContext","DEFAULT_BREAKPOINTS","clsx","isValidElement","cloneElement","jsx","useContext","useWindow","useComponentCssInjection","saltProviderCss","useMemo","useIsomorphicLayoutEffect","useMatchedBreakpoints","BreakpointProvider","ViewportProvider","AriaAnnouncerProvider","StyleInjectionProvider"],"mappings":"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"}
1
+ {"version":3,"file":"SaltProvider.js","sources":["../src/salt-provider/SaltProvider.tsx"],"sourcesContent":["import {\n StyleInjectionProvider,\n useComponentCssInjection,\n} from \"@salt-ds/styles\";\nimport { useWindow, type WindowContextType } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n createContext,\n type ReactElement,\n type ReactNode,\n useContext,\n useMemo,\n} from \"react\";\nimport { AriaAnnouncerProvider } from \"../aria-announcer\";\nimport {\n BreakpointProvider,\n type Breakpoints,\n DEFAULT_BREAKPOINTS,\n useMatchedBreakpoints,\n} from \"../breakpoints\";\nimport type {\n Accent,\n ActionFont,\n Corner,\n Density,\n HeadingFont,\n Mode,\n ThemeName,\n} from \"../theme\";\nimport { ViewportProvider } from \"../viewport\";\nimport { ProviderContext } from \"./ProviderContext\";\nimport saltProviderCss from \"./SaltProvider.css\";\nimport { ThemeApplicator, type ThemeApplicatorProps } from \"./ThemeApplicator\";\n\nexport const DEFAULT_DENSITY = \"medium\";\n\nconst DEFAULT_THEME_NAME = \"salt-theme\";\nconst DEFAULT_THEME_NAME_NEXT = \"salt-theme-next\";\n\nconst DEFAULT_MODE = \"light\";\nconst DEFAULT_CORNER: Corner = \"sharp\";\nconst DEFAULT_HEADING_FONT: HeadingFont = \"Open Sans\";\nconst DEFAULT_ACCENT: Accent = \"blue\";\nconst DEFAULT_ACTION_FONT: ActionFont = \"Open Sans\";\nexport interface ThemeContextProps {\n theme: ThemeName;\n mode: Mode;\n window?: WindowContextType;\n /** Only available when using SaltProviderNext. */\n themeNext: boolean;\n corner: Corner;\n /** @deprecated use `corner`*/\n UNSTABLE_corner: Corner;\n headingFont: HeadingFont;\n /** @deprecated use `headingFont` */\n UNSTABLE_headingFont: HeadingFont;\n accent: Accent;\n /** @deprecated use `accent` */\n UNSTABLE_accent: Accent;\n actionFont: ActionFont;\n /** @deprecated use `actionFont` */\n UNSTABLE_actionFont: ActionFont;\n}\n\nexport const DensityContext = createContext<Density>(DEFAULT_DENSITY);\n\nexport const ThemeContext = createContext<ThemeContextProps>({\n theme: \"\",\n mode: DEFAULT_MODE,\n themeNext: false,\n corner: DEFAULT_CORNER,\n UNSTABLE_corner: DEFAULT_CORNER,\n headingFont: DEFAULT_HEADING_FONT,\n UNSTABLE_headingFont: DEFAULT_HEADING_FONT,\n accent: DEFAULT_ACCENT,\n UNSTABLE_accent: DEFAULT_ACCENT,\n actionFont: DEFAULT_ACTION_FONT,\n UNSTABLE_actionFont: DEFAULT_ACTION_FONT,\n});\n\nexport const BreakpointContext =\n createContext<Breakpoints>(DEFAULT_BREAKPOINTS);\n\ntype ThemeNextOnlyAttributes =\n | \"accent\"\n | \"corner\"\n | \"actionFont\"\n | \"headingFont\";\n\ninterface SaltProviderBaseProps\n extends Partial<\n Omit<ThemeApplicatorProps, \"children\" | ThemeNextOnlyAttributes>\n > {\n /**\n * Shape of `{ xs: number; sm: number; md: number; lg: number; xl: number; }`.\n * Determines breakpoints used in responsive calculation for layout components.\n */\n breakpoints?: Breakpoints;\n /**\n * A boolean. Enables dynamic style injection for each component.\n *\n * If `false`, you'll need to include component CSS yourself.\n *\n * @default true\n */\n enableStyleInjection?: boolean;\n}\n\ninterface SaltProviderThatAppliesClassesToChild extends SaltProviderBaseProps {\n children: ReactElement;\n applyClassesTo: \"child\";\n}\n\ninterface SaltProviderThatInjectsThemeElement extends SaltProviderBaseProps {\n children: ReactNode;\n}\n\ninterface SaltProviderThatClassesToRoot\n extends SaltProviderThatInjectsThemeElement {\n applyClassesTo: \"root\";\n}\n\ntype SaltProviderProps =\n | SaltProviderThatAppliesClassesToChild\n | SaltProviderThatInjectsThemeElement\n | SaltProviderThatClassesToRoot;\n\nfunction InternalSaltProvider({\n applyClassesTo: applyClassesToProp,\n children,\n density: densityProp,\n theme: themeProp,\n mode: modeProp,\n breakpoints: breakpointsProp,\n themeNext,\n corner: cornerProp,\n headingFont: headingFontProp,\n accent: accentProp,\n actionFont: actionFontProp,\n}: Omit<\n SaltProviderProps & {\n themeNext?: boolean;\n } & SaltProviderNextProps,\n \"enableStyleInjection\"\n>) {\n const prevProvider = useContext(ProviderContext);\n const inheritedDensity = useContext(DensityContext);\n const {\n theme: inheritedTheme,\n mode: inheritedMode,\n corner: inheritedCorner,\n headingFont: inheritedHeadingFont,\n accent: inheritedAccent,\n actionFont: inheritedActionFont,\n } = useContext(ThemeContext);\n\n const isRootProvider = prevProvider === null;\n\n const density = densityProp ?? inheritedDensity ?? DEFAULT_DENSITY;\n const inheritedThemeName =\n inheritedTheme === \"\" ? DEFAULT_THEME_NAME : inheritedTheme;\n const themeName = themeProp ?? inheritedThemeName;\n const mode = modeProp ?? inheritedMode;\n const breakpoints = breakpointsProp ?? DEFAULT_BREAKPOINTS;\n\n const corner = cornerProp ?? inheritedCorner ?? DEFAULT_CORNER;\n const headingFont =\n headingFontProp ?? inheritedHeadingFont ?? DEFAULT_HEADING_FONT;\n const accent = accentProp ?? inheritedAccent ?? DEFAULT_ACCENT;\n const actionFont =\n actionFontProp ?? inheritedActionFont ?? DEFAULT_ACTION_FONT;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-provider\",\n css: saltProviderCss,\n window: targetWindow,\n });\n\n const themeContextValue = useMemo(\n () => ({\n theme: themeName,\n mode,\n window: targetWindow,\n themeNext: Boolean(themeNext),\n corner: corner,\n headingFont: headingFont,\n accent: accent,\n actionFont: actionFont,\n // Backward compatibility\n UNSTABLE_corner: corner,\n UNSTABLE_headingFont: headingFont,\n UNSTABLE_accent: accent,\n UNSTABLE_actionFont: actionFont,\n }),\n [\n themeName,\n mode,\n targetWindow,\n themeNext,\n corner,\n headingFont,\n accent,\n actionFont,\n ],\n );\n\n const matchedBreakpoints = useMatchedBreakpoints(breakpoints);\n\n const saltProvider = (\n <ProviderContext.Provider value={{ targetWindow }}>\n <DensityContext.Provider value={density}>\n <ThemeContext.Provider value={themeContextValue}>\n <BreakpointProvider matchedBreakpoints={matchedBreakpoints}>\n <BreakpointContext.Provider value={breakpoints}>\n <ViewportProvider>\n <ThemeApplicator\n applyClassesTo={\n applyClassesToProp ?? (isRootProvider ? \"root\" : \"scope\")\n }\n density={density}\n theme={clsx(\n DEFAULT_THEME_NAME,\n { [DEFAULT_THEME_NAME_NEXT]: themeNext },\n themeProp,\n )}\n mode={mode}\n accent={themeNext ? accent : undefined}\n actionFont={themeNext ? actionFont : undefined}\n headingFont={themeNext ? headingFont : undefined}\n corner={themeNext ? corner : undefined}\n >\n {children}\n </ThemeApplicator>\n </ViewportProvider>\n </BreakpointContext.Provider>\n </BreakpointProvider>\n </ThemeContext.Provider>\n </DensityContext.Provider>\n </ProviderContext.Provider>\n );\n\n if (isRootProvider) {\n return <AriaAnnouncerProvider>{saltProvider}</AriaAnnouncerProvider>;\n }\n return saltProvider;\n}\n\nexport function SaltProvider({\n enableStyleInjection,\n ...restProps\n}: SaltProviderProps) {\n return (\n <StyleInjectionProvider value={enableStyleInjection}>\n <InternalSaltProvider {...restProps} />\n </StyleInjectionProvider>\n );\n}\n\nexport type SaltProviderNextProps = SaltProviderProps &\n Pick<ThemeApplicatorProps, ThemeNextOnlyAttributes>;\nexport function SaltProviderNext({\n enableStyleInjection,\n ...restProps\n}: SaltProviderNextProps) {\n return (\n <StyleInjectionProvider value={enableStyleInjection}>\n {/* Leveraging InternalSaltProvider being not exported, so we can pass more props than previously supported */}\n <InternalSaltProvider {...restProps} themeNext={true} />\n </StyleInjectionProvider>\n );\n}\n\n/** @deprecated use `SaltProviderNextProps` */\nexport type UNSTABLE_SaltProviderNextProps = SaltProviderNextProps;\n\n/** @deprecated use `SaltProviderNext` */\nexport const UNSTABLE_SaltProviderNext = SaltProviderNext;\n\nexport const useTheme = (): ThemeContextProps => {\n const { window: _window, ...contextWithoutWindow } = useContext(ThemeContext);\n\n return contextWithoutWindow;\n};\n\n/**\n * `useDensity` merges density value from `DensityContext` with the one from component's props.\n */\nexport function useDensity(density?: Density): Density {\n const densityFromContext = useContext(DensityContext);\n return density ?? densityFromContext ?? DEFAULT_DENSITY;\n}\n\nexport const useBreakpoints = (): Breakpoints => {\n return useContext(BreakpointContext);\n};\n"],"names":["createContext","DEFAULT_BREAKPOINTS","useContext","ProviderContext","useWindow","useComponentCssInjection","saltProviderCss","useMemo","useMatchedBreakpoints","jsx","BreakpointProvider","ViewportProvider","ThemeApplicator","clsx","AriaAnnouncerProvider","StyleInjectionProvider"],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('react/jsx-runtime');
4
+ var window = require('@salt-ds/window');
5
+ var clsx = require('clsx');
6
+ var React = require('react');
7
+ var useId = require('../utils/useId.js');
8
+ var useIsomorphicLayoutEffect = require('../utils/useIsomorphicLayoutEffect.js');
9
+
10
+ const providerSymbol = Symbol.for("salt-provider");
11
+ function ThemeApplicator({
12
+ applyClassesTo,
13
+ children,
14
+ density,
15
+ mode,
16
+ theme,
17
+ corner,
18
+ headingFont,
19
+ accent,
20
+ actionFont
21
+ }) {
22
+ var _a;
23
+ const targetWindow = window.useWindow();
24
+ const providerId = useId.useId();
25
+ useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
26
+ if (applyClassesTo !== "root" || !targetWindow || !providerId) return;
27
+ const targetDocument = targetWindow.document;
28
+ if (!targetDocument[providerSymbol]) {
29
+ targetDocument[providerSymbol] = providerId;
30
+ }
31
+ if (providerId !== targetDocument[providerSymbol]) {
32
+ console.warn(
33
+ "Multiple providers targeting the same window. There can be only one level root level SaltProvider per window."
34
+ );
35
+ return;
36
+ }
37
+ const themeNames = theme.split(" ");
38
+ targetDocument.documentElement.classList.add(
39
+ ...themeNames,
40
+ `salt-density-${density}`
41
+ );
42
+ targetDocument.documentElement.dataset.mode = mode;
43
+ if (corner) targetDocument.documentElement.dataset.corner = corner;
44
+ if (headingFont)
45
+ targetDocument.documentElement.dataset.headingFont = headingFont;
46
+ if (accent) targetDocument.documentElement.dataset.accent = accent;
47
+ if (actionFont)
48
+ targetDocument.documentElement.dataset.actionFont = actionFont;
49
+ return () => {
50
+ delete targetDocument[providerSymbol];
51
+ targetDocument.documentElement.classList.remove(
52
+ ...themeNames,
53
+ `salt-density-${density}`
54
+ );
55
+ targetDocument.documentElement.dataset.mode = void 0;
56
+ delete targetDocument.documentElement.dataset.corner;
57
+ delete targetDocument.documentElement.dataset.headingFont;
58
+ delete targetDocument.documentElement.dataset.accent;
59
+ delete targetDocument.documentElement.dataset.actionFont;
60
+ };
61
+ }, [
62
+ providerId,
63
+ applyClassesTo,
64
+ density,
65
+ mode,
66
+ theme,
67
+ targetWindow,
68
+ corner,
69
+ headingFont,
70
+ accent,
71
+ actionFont
72
+ ]);
73
+ const themeNextProps = {
74
+ "data-corner": corner,
75
+ "data-heading-font": headingFont,
76
+ "data-accent": accent,
77
+ "data-action-font": actionFont
78
+ };
79
+ if (applyClassesTo === "child") {
80
+ if (React.isValidElement(children)) {
81
+ return React.cloneElement(children, {
82
+ className: clsx.clsx(
83
+ (_a = children.props) == null ? void 0 : _a.className,
84
+ theme,
85
+ `salt-density-${density}`
86
+ ),
87
+ // @ts-expect-error
88
+ "data-mode": mode,
89
+ ...themeNextProps
90
+ });
91
+ }
92
+ console.warn(
93
+ `
94
+ SaltProvider can only apply CSS classes for theming to a single nested child element of the SaltProvider.
95
+ Either wrap elements with a single container or consider removing the applyClassesToChild prop, in which case a
96
+ div element will wrap your child elements`
97
+ );
98
+ return children;
99
+ }
100
+ if (applyClassesTo === "scope") {
101
+ return /* @__PURE__ */ jsxRuntime.jsx(
102
+ "div",
103
+ {
104
+ className: clsx.clsx("salt-provider", theme, `salt-density-${density}`),
105
+ "data-mode": mode,
106
+ ...themeNextProps,
107
+ children
108
+ }
109
+ );
110
+ }
111
+ return children;
112
+ }
113
+
114
+ exports.ThemeApplicator = ThemeApplicator;
115
+ //# sourceMappingURL=ThemeApplicator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThemeApplicator.js","sources":["../src/salt-provider/ThemeApplicator.tsx"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n cloneElement,\n type HTMLAttributes,\n isValidElement,\n type ReactNode,\n} from \"react\";\nimport type {\n Accent,\n ActionFont,\n Corner,\n Density,\n HeadingFont,\n Mode,\n ThemeName,\n} from \"../theme/index\";\nimport { useId } from \"../utils/useId\";\nimport { useIsomorphicLayoutEffect } from \"../utils/useIsomorphicLayoutEffect\";\n\nexport interface ThemeApplicatorProps {\n /**\n * Either \"root\", \"scope\" or \"child\".\n * Specifies the location of salt theme class and attributes should be applied to.\n *\n * Defaults to \"root\" for a root provider, otherwise \"scope\".\n */\n applyClassesTo: \"root\" | \"scope\" | \"child\";\n /**\n * Either \"high\", \"medium\", \"low\" or \"touch\".\n * Determines the amount of content that can fit on a screen based on the size and spacing of components.\n * Refer to [density](https://www.saltdesignsystem.com/salt/foundations/density) doc for more detail.\n *\n * @default \"medium\"\n */\n density: Density;\n /**\n * A string. Specifies custom theme name(s) you want to apply, similar to `className`.\n */\n theme: ThemeName;\n /**\n * Either \"light\" or \"dark\". Enable the color palette to change from light to dark.\n * Refer to [modes](https://www.saltdesignsystem.com/salt/foundations/modes) doc for more detail.\n *\n * @default \"light\"\n */\n mode: Mode;\n /**\n * Either \"sharp\" or \"rounded\".\n * Determines selected components corner radius.\n * @default \"sharp\"\n */\n corner?: Corner;\n /**\n * Either \"Open Sans\" or \"Amplitude\".\n * Determines font family of display and heading text.\n * @default \"Open Sans\"\n */\n headingFont?: HeadingFont;\n /**\n * Either \"blue\" or \"teal\".\n * Determines accent color used across components, e.g. Accent Button, List, Calendar.\n * @default \"blue\"\n */\n accent?: Accent;\n /**\n * Either \"Open Sans\" or \"Amplitude\".\n * Determines font family of action components, mostly Buttons.\n * @default \"Open Sans\"\n */\n actionFont?: ActionFont;\n children?: ReactNode;\n}\n\nconst providerSymbol = Symbol.for(\"salt-provider\");\n\nexport function ThemeApplicator({\n applyClassesTo,\n children,\n density,\n mode,\n theme,\n corner,\n headingFont,\n accent,\n actionFont,\n}: ThemeApplicatorProps) {\n const targetWindow = useWindow();\n\n const providerId = useId();\n\n useIsomorphicLayoutEffect(() => {\n if (applyClassesTo !== \"root\" || !targetWindow || !providerId) return;\n\n const targetDocument: Document & { [providerSymbol]?: string } =\n targetWindow.document;\n\n // Claim the document if no other provider has already. The symbol is used so the lock isn't enumerable and guarantees it won't clash with anything else.\n if (!targetDocument[providerSymbol]) {\n targetDocument[providerSymbol] = providerId;\n }\n\n if (providerId !== targetDocument[providerSymbol]) {\n console.warn(\n \"Multiple providers targeting the same window. There can be only one level root level SaltProvider per window.\",\n );\n return;\n }\n\n const themeNames = theme.split(\" \");\n\n // add the styles we want to apply\n targetDocument.documentElement.classList.add(\n ...themeNames,\n `salt-density-${density}`,\n );\n targetDocument.documentElement.dataset.mode = mode;\n\n // Theme Next\n if (corner) targetDocument.documentElement.dataset.corner = corner;\n if (headingFont)\n targetDocument.documentElement.dataset.headingFont = headingFont;\n if (accent) targetDocument.documentElement.dataset.accent = accent;\n if (actionFont)\n targetDocument.documentElement.dataset.actionFont = actionFont;\n\n return () => {\n // Delete lock\n delete targetDocument[providerSymbol];\n\n // When unmounting/remounting, remove the applied styles from the root\n targetDocument.documentElement.classList.remove(\n ...themeNames,\n `salt-density-${density}`,\n );\n targetDocument.documentElement.dataset.mode = undefined;\n\n // Theme Next\n delete targetDocument.documentElement.dataset.corner;\n delete targetDocument.documentElement.dataset.headingFont;\n delete targetDocument.documentElement.dataset.accent;\n delete targetDocument.documentElement.dataset.actionFont;\n };\n }, [\n providerId,\n applyClassesTo,\n density,\n mode,\n theme,\n targetWindow,\n corner,\n headingFont,\n accent,\n actionFont,\n ]);\n\n const themeNextProps = {\n \"data-corner\": corner,\n \"data-heading-font\": headingFont,\n \"data-accent\": accent,\n \"data-action-font\": actionFont,\n };\n\n if (applyClassesTo === \"child\") {\n if (isValidElement<HTMLAttributes<HTMLElement>>(children)) {\n return cloneElement(children, {\n className: clsx(\n children.props?.className,\n theme,\n `salt-density-${density}`,\n ),\n // @ts-expect-error\n \"data-mode\": mode,\n ...themeNextProps,\n });\n }\n console.warn(\n `\\nSaltProvider can only apply CSS classes for theming to a single nested child element of the SaltProvider.\n Either wrap elements with a single container or consider removing the applyClassesToChild prop, in which case a\n div element will wrap your child elements`,\n );\n return children;\n }\n\n if (applyClassesTo === \"scope\") {\n return (\n <div\n className={clsx(\"salt-provider\", theme, `salt-density-${density}`)}\n data-mode={mode}\n {...themeNextProps}\n >\n {children}\n </div>\n );\n }\n\n return children;\n}\n"],"names":["useWindow","useId","useIsomorphicLayoutEffect","isValidElement","cloneElement","clsx","jsx"],"mappings":"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"}
@@ -78,7 +78,7 @@ const useRangeSliderThumb = ({
78
78
  onChange
79
79
  ]
80
80
  );
81
- const handlePointerUp = React.useCallback(
81
+ const handleDragEnd = React.useCallback(
82
82
  (event) => {
83
83
  setIsDragging(false);
84
84
  setIsFocusVisible(false);
@@ -89,16 +89,25 @@ const useRangeSliderThumb = ({
89
89
  React.useEffect(() => {
90
90
  if (isDragging) {
91
91
  targetWindow == null ? void 0 : targetWindow.addEventListener("pointermove", handlePointerMove);
92
- targetWindow == null ? void 0 : targetWindow.addEventListener("pointerup", handlePointerUp);
92
+ targetWindow == null ? void 0 : targetWindow.addEventListener("pointerup", handleDragEnd);
93
+ targetWindow == null ? void 0 : targetWindow.addEventListener("pointercancel", handleDragEnd);
94
+ targetWindow == null ? void 0 : targetWindow.addEventListener("blur", handleDragEnd);
95
+ targetWindow == null ? void 0 : targetWindow.addEventListener("contextmenu", handleDragEnd);
93
96
  } else {
94
97
  targetWindow == null ? void 0 : targetWindow.removeEventListener("pointermove", handlePointerMove);
95
- targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handlePointerUp);
98
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handleDragEnd);
99
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointercancel", handleDragEnd);
100
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("blur", handleDragEnd);
101
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("contextmenu", handleDragEnd);
96
102
  }
97
103
  return () => {
98
104
  targetWindow == null ? void 0 : targetWindow.removeEventListener("pointermove", handlePointerMove);
99
- targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handlePointerUp);
105
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handleDragEnd);
106
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointercancel", handleDragEnd);
107
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("blur", handleDragEnd);
108
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("contextmenu", handleDragEnd);
100
109
  };
101
- }, [handlePointerMove, handlePointerUp, isDragging, targetWindow]);
110
+ }, [isDragging, targetWindow, handlePointerMove, handleDragEnd]);
102
111
  const handlePointerDownOnThumb = React.useCallback(
103
112
  (event, thumbIndex) => {
104
113
  var _a;
@@ -1 +1 @@
1
- {"version":3,"file":"useRangeSliderThumb.js","sources":["../src/slider/internal/useRangeSliderThumb.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type RefObject,\n type SetStateAction,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { SliderProps } from \"../Slider\";\nimport { getClickedPosition, getKeyboardValue } from \"./utils\";\n\ntype UseRangeSliderThumbProps = Pick<SliderProps, \"min\" | \"max\" | \"step\"> & {\n decimalPlaces: number;\n handleInputChange: (\n event: ChangeEvent<HTMLInputElement>,\n thumbIndex: number,\n ) => void;\n inputRefs: RefObject<HTMLInputElement>[];\n marks?: { label: string; value: number }[];\n onChange?: (event: Event, value: [number, number]) => void;\n onChangeEnd?: (event: Event, value: [number, number]) => void;\n restrictToMarks?: boolean;\n setValue: Dispatch<SetStateAction<[number, number]>>;\n stepMultiplier: number;\n value: [number, number];\n};\n\nexport const useRangeSliderThumb = ({\n decimalPlaces,\n handleInputChange,\n inputRefs,\n marks,\n min = 0,\n max = 10,\n step = 1,\n onChange,\n onChangeEnd,\n restrictToMarks,\n setValue,\n stepMultiplier,\n value,\n}: UseRangeSliderThumbProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n const [thumbIndexState, setIsThumbIndex] = useState<number>(0);\n const lastValueRef = useRef<[number, number]>(value);\n const sliderRef = useRef<HTMLDivElement>(null);\n const targetWindow = useWindow();\n\n const preventThumbOverlap = useCallback(\n (currentValue: number, value: [number, number], thumbIndex: number) => {\n const values = [...value] as [number, number];\n if (thumbIndex === 0 && currentValue >= values[1]) {\n values[0] = values[1];\n } else if (thumbIndex === 1 && currentValue <= values[0]) {\n values[1] = values[0];\n } else {\n values[thumbIndex] = currentValue;\n }\n return values;\n },\n [],\n );\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n if (!sliderRef.current) return;\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined) return;\n const newValues = preventThumbOverlap(\n newValue,\n value as [number, number],\n thumbIndexState,\n );\n\n if (\n newValues[0] !== lastValueRef.current[0] ||\n newValues[1] !== lastValueRef.current[1]\n ) {\n lastValueRef.current = newValues;\n setValue(newValues);\n onChange?.(event, newValues);\n }\n },\n [\n decimalPlaces,\n marks,\n max,\n min,\n step,\n preventThumbOverlap,\n restrictToMarks,\n value,\n thumbIndexState,\n setValue,\n onChange,\n ],\n );\n\n const handlePointerUp = useCallback(\n (event: PointerEvent) => {\n setIsDragging(false);\n setIsFocusVisible(false);\n onChangeEnd?.(event, lastValueRef.current);\n },\n [onChangeEnd],\n );\n\n useEffect(() => {\n if (isDragging) {\n targetWindow?.addEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.addEventListener(\"pointerup\", handlePointerUp);\n } else {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handlePointerUp);\n }\n return () => {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handlePointerUp);\n };\n }, [handlePointerMove, handlePointerUp, isDragging, targetWindow]);\n\n const handlePointerDownOnThumb = useCallback(\n (event: React.PointerEvent<HTMLDivElement>, thumbIndex: number) => {\n event.preventDefault();\n // To prevent the pointerdown event from bubbling up to the slider track\n // and triggering its pointerdown event\n event.stopPropagation();\n\n inputRefs[thumbIndex].current?.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n if (thumbIndex !== undefined) {\n setIsThumbIndex(thumbIndex);\n }\n },\n [inputRefs],\n );\n\n const handlePointerDownOnTrack = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n setIsDragging(true);\n\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n let closestThumbIndex = 0;\n\n if (newValue === undefined) return;\n const newValues = [...value] as [number, number];\n // Find nearest thumb\n const distanceToThumb0 = Math.abs(newValue - newValues[0]);\n const distanceToThumb1 = Math.abs(newValue - newValues[1]);\n if (distanceToThumb0 > distanceToThumb1) {\n // Move the second thumb\n newValues[1] = newValue;\n closestThumbIndex = 1;\n } else if (distanceToThumb0 < distanceToThumb1) {\n // Move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n } else {\n // If distances are equal, determine based on the click position\n if (newValue < newValues[0]) {\n // Clicked position is before both thumbs, move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n } else if (newValue > newValues[1]) {\n // Clicked position is after both thumbs, move the second thumb\n newValues[1] = newValue;\n closestThumbIndex = 1;\n } else {\n // Clicked position is between the thumbs, move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n }\n }\n setIsThumbIndex(closestThumbIndex);\n inputRefs[closestThumbIndex].current?.focus();\n setIsFocusVisible(false);\n\n if (\n newValues[0] !== lastValueRef.current[0] ||\n newValues[1] !== lastValueRef.current[1]\n ) {\n lastValueRef.current = newValues;\n setValue(newValues);\n onChange?.(event.nativeEvent, newValues);\n }\n },\n [\n decimalPlaces,\n marks,\n value,\n max,\n min,\n inputRefs,\n onChange,\n restrictToMarks,\n setValue,\n step,\n ],\n );\n\n const handleKeydownOnThumb = useCallback(\n (event: React.KeyboardEvent, thumbIndex: number) => {\n const newValue = getKeyboardValue(\n event,\n value[thumbIndex],\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n );\n if (\n newValue === undefined ||\n newValue === lastValueRef.current[thumbIndex]\n ) {\n return;\n }\n setIsFocusVisible(true);\n lastValueRef.current[thumbIndex] = newValue;\n handleInputChange(\n {\n target: { value: newValue.toString() },\n } as ChangeEvent<HTMLInputElement>,\n thumbIndex,\n );\n },\n [\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n handleInputChange,\n ],\n );\n\n const handleFocus = (thumbIndex: number) => {\n setIsThumbIndex(thumbIndex);\n setIsFocusVisible(true);\n };\n\n const handleBlur = (thumbIndex: number) => {\n setIsThumbIndex(thumbIndex);\n setIsFocusVisible(false);\n };\n\n return {\n handleBlur,\n handleFocus,\n handleKeydownOnThumb,\n handlePointerDownOnThumb,\n handlePointerDownOnTrack,\n isDragging,\n isFocusVisible,\n preventThumbOverlap,\n sliderRef,\n thumbIndexState,\n };\n};\n"],"names":["useState","useRef","useWindow","useCallback","value","getClickedPosition","useEffect","getKeyboardValue"],"mappings":"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"}
1
+ {"version":3,"file":"useRangeSliderThumb.js","sources":["../src/slider/internal/useRangeSliderThumb.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type RefObject,\n type SetStateAction,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { SliderProps } from \"../Slider\";\nimport { getClickedPosition, getKeyboardValue } from \"./utils\";\n\ntype UseRangeSliderThumbProps = Pick<SliderProps, \"min\" | \"max\" | \"step\"> & {\n decimalPlaces: number;\n handleInputChange: (\n event: ChangeEvent<HTMLInputElement>,\n thumbIndex: number,\n ) => void;\n inputRefs: RefObject<HTMLInputElement>[];\n marks?: { label: string; value: number }[];\n onChange?: (event: Event, value: [number, number]) => void;\n onChangeEnd?: (event: Event, value: [number, number]) => void;\n restrictToMarks?: boolean;\n setValue: Dispatch<SetStateAction<[number, number]>>;\n stepMultiplier: number;\n value: [number, number];\n};\n\nexport const useRangeSliderThumb = ({\n decimalPlaces,\n handleInputChange,\n inputRefs,\n marks,\n min = 0,\n max = 10,\n step = 1,\n onChange,\n onChangeEnd,\n restrictToMarks,\n setValue,\n stepMultiplier,\n value,\n}: UseRangeSliderThumbProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n const [thumbIndexState, setIsThumbIndex] = useState<number>(0);\n const lastValueRef = useRef<[number, number]>(value);\n const sliderRef = useRef<HTMLDivElement>(null);\n const targetWindow = useWindow();\n\n const preventThumbOverlap = useCallback(\n (currentValue: number, value: [number, number], thumbIndex: number) => {\n const values = [...value] as [number, number];\n if (thumbIndex === 0 && currentValue >= values[1]) {\n values[0] = values[1];\n } else if (thumbIndex === 1 && currentValue <= values[0]) {\n values[1] = values[0];\n } else {\n values[thumbIndex] = currentValue;\n }\n return values;\n },\n [],\n );\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n if (!sliderRef.current) return;\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined) return;\n const newValues = preventThumbOverlap(\n newValue,\n value as [number, number],\n thumbIndexState,\n );\n\n if (\n newValues[0] !== lastValueRef.current[0] ||\n newValues[1] !== lastValueRef.current[1]\n ) {\n lastValueRef.current = newValues;\n setValue(newValues);\n onChange?.(event, newValues);\n }\n },\n [\n decimalPlaces,\n marks,\n max,\n min,\n step,\n preventThumbOverlap,\n restrictToMarks,\n value,\n thumbIndexState,\n setValue,\n onChange,\n ],\n );\n\n const handleDragEnd = useCallback(\n (event: Event) => {\n setIsDragging(false);\n setIsFocusVisible(false);\n onChangeEnd?.(event, lastValueRef.current);\n },\n [onChangeEnd],\n );\n\n useEffect(() => {\n if (isDragging) {\n targetWindow?.addEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.addEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.addEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.addEventListener(\"blur\", handleDragEnd);\n targetWindow?.addEventListener(\"contextmenu\", handleDragEnd);\n } else {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.removeEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.removeEventListener(\"blur\", handleDragEnd);\n targetWindow?.removeEventListener(\"contextmenu\", handleDragEnd);\n }\n return () => {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.removeEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.removeEventListener(\"blur\", handleDragEnd);\n targetWindow?.removeEventListener(\"contextmenu\", handleDragEnd);\n };\n }, [isDragging, targetWindow, handlePointerMove, handleDragEnd]);\n\n const handlePointerDownOnThumb = useCallback(\n (event: React.PointerEvent<HTMLDivElement>, thumbIndex: number) => {\n event.preventDefault();\n // To prevent the pointerdown event from bubbling up to the slider track\n // and triggering its pointerdown event\n event.stopPropagation();\n\n inputRefs[thumbIndex].current?.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n if (thumbIndex !== undefined) {\n setIsThumbIndex(thumbIndex);\n }\n },\n [inputRefs],\n );\n\n const handlePointerDownOnTrack = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n setIsDragging(true);\n\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n let closestThumbIndex = 0;\n\n if (newValue === undefined) return;\n const newValues = [...value] as [number, number];\n // Find nearest thumb\n const distanceToThumb0 = Math.abs(newValue - newValues[0]);\n const distanceToThumb1 = Math.abs(newValue - newValues[1]);\n if (distanceToThumb0 > distanceToThumb1) {\n // Move the second thumb\n newValues[1] = newValue;\n closestThumbIndex = 1;\n } else if (distanceToThumb0 < distanceToThumb1) {\n // Move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n } else {\n // If distances are equal, determine based on the click position\n if (newValue < newValues[0]) {\n // Clicked position is before both thumbs, move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n } else if (newValue > newValues[1]) {\n // Clicked position is after both thumbs, move the second thumb\n newValues[1] = newValue;\n closestThumbIndex = 1;\n } else {\n // Clicked position is between the thumbs, move the first thumb\n newValues[0] = newValue;\n closestThumbIndex = 0;\n }\n }\n setIsThumbIndex(closestThumbIndex);\n inputRefs[closestThumbIndex].current?.focus();\n setIsFocusVisible(false);\n\n if (\n newValues[0] !== lastValueRef.current[0] ||\n newValues[1] !== lastValueRef.current[1]\n ) {\n lastValueRef.current = newValues;\n setValue(newValues);\n onChange?.(event.nativeEvent, newValues);\n }\n },\n [\n decimalPlaces,\n marks,\n value,\n max,\n min,\n inputRefs,\n onChange,\n restrictToMarks,\n setValue,\n step,\n ],\n );\n\n const handleKeydownOnThumb = useCallback(\n (event: React.KeyboardEvent, thumbIndex: number) => {\n const newValue = getKeyboardValue(\n event,\n value[thumbIndex],\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n );\n if (\n newValue === undefined ||\n newValue === lastValueRef.current[thumbIndex]\n ) {\n return;\n }\n setIsFocusVisible(true);\n lastValueRef.current[thumbIndex] = newValue;\n handleInputChange(\n {\n target: { value: newValue.toString() },\n } as ChangeEvent<HTMLInputElement>,\n thumbIndex,\n );\n },\n [\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n handleInputChange,\n ],\n );\n\n const handleFocus = (thumbIndex: number) => {\n setIsThumbIndex(thumbIndex);\n setIsFocusVisible(true);\n };\n\n const handleBlur = (thumbIndex: number) => {\n setIsThumbIndex(thumbIndex);\n setIsFocusVisible(false);\n };\n\n return {\n handleBlur,\n handleFocus,\n handleKeydownOnThumb,\n handlePointerDownOnThumb,\n handlePointerDownOnTrack,\n isDragging,\n isFocusVisible,\n preventThumbOverlap,\n sliderRef,\n thumbIndexState,\n };\n};\n"],"names":["useState","useRef","useWindow","useCallback","value","getClickedPosition","useEffect","getKeyboardValue"],"mappings":"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"}
@@ -46,7 +46,7 @@ const useSliderThumb = ({
46
46
  },
47
47
  [decimalPlaces, marks, max, min, onChange, setValue, restrictToMarks, step]
48
48
  );
49
- const handlePointerUp = React.useCallback(
49
+ const handleDragEnd = React.useCallback(
50
50
  (event) => {
51
51
  setIsDragging(false);
52
52
  setIsFocusVisible(false);
@@ -57,16 +57,25 @@ const useSliderThumb = ({
57
57
  React.useEffect(() => {
58
58
  if (isDragging) {
59
59
  targetWindow == null ? void 0 : targetWindow.addEventListener("pointermove", handlePointerMove);
60
- targetWindow == null ? void 0 : targetWindow.addEventListener("pointerup", handlePointerUp);
60
+ targetWindow == null ? void 0 : targetWindow.addEventListener("pointerup", handleDragEnd);
61
+ targetWindow == null ? void 0 : targetWindow.addEventListener("pointercancel", handleDragEnd);
62
+ targetWindow == null ? void 0 : targetWindow.addEventListener("blur", handleDragEnd);
63
+ targetWindow == null ? void 0 : targetWindow.addEventListener("contextmenu", handleDragEnd);
61
64
  } else {
62
65
  targetWindow == null ? void 0 : targetWindow.removeEventListener("pointermove", handlePointerMove);
63
- targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handlePointerUp);
66
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handleDragEnd);
67
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointercancel", handleDragEnd);
68
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("blur", handleDragEnd);
69
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("contextmenu", handleDragEnd);
64
70
  }
65
71
  return () => {
66
72
  targetWindow == null ? void 0 : targetWindow.removeEventListener("pointermove", handlePointerMove);
67
- targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handlePointerUp);
73
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointerup", handleDragEnd);
74
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("pointercancel", handleDragEnd);
75
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("blur", handleDragEnd);
76
+ targetWindow == null ? void 0 : targetWindow.removeEventListener("contextmenu", handleDragEnd);
68
77
  };
69
- }, [handlePointerMove, handlePointerUp, isDragging, targetWindow]);
78
+ }, [isDragging, targetWindow, handlePointerMove, handleDragEnd]);
70
79
  const handlePointerDownOnThumb = React.useCallback(
71
80
  (event) => {
72
81
  event.preventDefault();
@@ -1 +1 @@
1
- {"version":3,"file":"useSliderThumb.js","sources":["../src/slider/internal/useSliderThumb.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type RefObject,\n type SetStateAction,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { SliderProps } from \"../Slider\";\nimport { getClickedPosition, getKeyboardValue } from \"./utils\";\n\ntype UseSliderThumbProps = Pick<SliderProps, \"min\" | \"max\" | \"step\"> & {\n decimalPlaces: number;\n handleInputChange: (event: ChangeEvent<HTMLInputElement>) => void;\n inputRef: RefObject<HTMLInputElement>;\n marks?: { label: string; value: number }[];\n onChange?: (event: Event, value: number) => void;\n onChangeEnd?: (event: Event, value: number) => void;\n restrictToMarks?: boolean;\n setValue: Dispatch<SetStateAction<number>>;\n stepMultiplier: number;\n value: number;\n};\n\nexport const useSliderThumb = ({\n decimalPlaces,\n handleInputChange,\n inputRef,\n marks,\n min = 0,\n max = 10,\n step = 1,\n onChange,\n onChangeEnd,\n restrictToMarks,\n setValue,\n stepMultiplier,\n value,\n}: UseSliderThumbProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n const lastValueRef = useRef<number>(value);\n const sliderRef = useRef<HTMLDivElement>(null);\n const targetWindow = useWindow();\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n if (!sliderRef.current) return;\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n lastValueRef.current = newValue;\n setValue(newValue);\n onChange?.(event, newValue);\n },\n [decimalPlaces, marks, max, min, onChange, setValue, restrictToMarks, step],\n );\n\n const handlePointerUp = useCallback(\n (event: PointerEvent) => {\n setIsDragging(false);\n setIsFocusVisible(false);\n onChangeEnd?.(event, lastValueRef.current);\n },\n [onChangeEnd],\n );\n\n useEffect(() => {\n if (isDragging) {\n targetWindow?.addEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.addEventListener(\"pointerup\", handlePointerUp);\n } else {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handlePointerUp);\n }\n return () => {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handlePointerUp);\n };\n }, [handlePointerMove, handlePointerUp, isDragging, targetWindow]);\n\n const handlePointerDownOnThumb = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n // To prevent the pointerdown event from bubbling up to the slider track\n // and triggering its pointerdown event\n event.stopPropagation();\n if (inputRef.current) inputRef.current.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n },\n [inputRef],\n );\n\n const handlePointerDownOnTrack = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n if (inputRef.current) inputRef.current.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n lastValueRef.current = newValue;\n setValue(newValue);\n onChange?.(event.nativeEvent, newValue);\n },\n [\n decimalPlaces,\n inputRef,\n marks,\n max,\n min,\n onChange,\n restrictToMarks,\n setValue,\n step,\n ],\n );\n\n const handleKeydownOnThumb = useCallback(\n (event: React.KeyboardEvent) => {\n const newValue = getKeyboardValue(\n event,\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n setIsFocusVisible(true);\n lastValueRef.current = newValue;\n handleInputChange({\n target: { value: newValue.toString() },\n } as ChangeEvent<HTMLInputElement>);\n },\n [\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n handleInputChange,\n ],\n );\n\n const handleFocus = () => setIsFocusVisible(true);\n\n const handleBlur = () => setIsFocusVisible(false);\n\n return {\n handleBlur,\n handleFocus,\n handleKeydownOnThumb,\n handlePointerDownOnThumb,\n handlePointerDownOnTrack,\n isDragging,\n isFocusVisible,\n sliderRef,\n };\n};\n"],"names":["useState","useRef","useWindow","useCallback","getClickedPosition","useEffect","getKeyboardValue"],"mappings":"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"}
1
+ {"version":3,"file":"useSliderThumb.js","sources":["../src/slider/internal/useSliderThumb.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport {\n type ChangeEvent,\n type Dispatch,\n type RefObject,\n type SetStateAction,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { SliderProps } from \"../Slider\";\nimport { getClickedPosition, getKeyboardValue } from \"./utils\";\n\ntype UseSliderThumbProps = Pick<SliderProps, \"min\" | \"max\" | \"step\"> & {\n decimalPlaces: number;\n handleInputChange: (event: ChangeEvent<HTMLInputElement>) => void;\n inputRef: RefObject<HTMLInputElement>;\n marks?: { label: string; value: number }[];\n onChange?: (event: Event, value: number) => void;\n onChangeEnd?: (event: Event, value: number) => void;\n restrictToMarks?: boolean;\n setValue: Dispatch<SetStateAction<number>>;\n stepMultiplier: number;\n value: number;\n};\n\nexport const useSliderThumb = ({\n decimalPlaces,\n handleInputChange,\n inputRef,\n marks,\n min = 0,\n max = 10,\n step = 1,\n onChange,\n onChangeEnd,\n restrictToMarks,\n setValue,\n stepMultiplier,\n value,\n}: UseSliderThumbProps) => {\n const [isDragging, setIsDragging] = useState(false);\n const [isFocusVisible, setIsFocusVisible] = useState(false);\n const lastValueRef = useRef<number>(value);\n const sliderRef = useRef<HTMLDivElement>(null);\n const targetWindow = useWindow();\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n if (!sliderRef.current) return;\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n lastValueRef.current = newValue;\n setValue(newValue);\n onChange?.(event, newValue);\n },\n [decimalPlaces, marks, max, min, onChange, setValue, restrictToMarks, step],\n );\n\n const handleDragEnd = useCallback(\n (event: Event) => {\n setIsDragging(false);\n setIsFocusVisible(false);\n onChangeEnd?.(event, lastValueRef.current);\n },\n [onChangeEnd],\n );\n\n useEffect(() => {\n if (isDragging) {\n targetWindow?.addEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.addEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.addEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.addEventListener(\"blur\", handleDragEnd);\n targetWindow?.addEventListener(\"contextmenu\", handleDragEnd);\n } else {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.removeEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.removeEventListener(\"blur\", handleDragEnd);\n targetWindow?.removeEventListener(\"contextmenu\", handleDragEnd);\n }\n\n return () => {\n targetWindow?.removeEventListener(\"pointermove\", handlePointerMove);\n targetWindow?.removeEventListener(\"pointerup\", handleDragEnd);\n targetWindow?.removeEventListener(\"pointercancel\", handleDragEnd);\n targetWindow?.removeEventListener(\"blur\", handleDragEnd);\n targetWindow?.removeEventListener(\"contextmenu\", handleDragEnd);\n };\n }, [isDragging, targetWindow, handlePointerMove, handleDragEnd]);\n\n const handlePointerDownOnThumb = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n event.stopPropagation();\n if (inputRef.current) inputRef.current.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n },\n [inputRef],\n );\n\n const handlePointerDownOnTrack = useCallback(\n (event: React.PointerEvent<HTMLDivElement>) => {\n event.preventDefault();\n if (inputRef.current) inputRef.current.focus();\n setIsDragging(true);\n setIsFocusVisible(false);\n const newValue = getClickedPosition(\n sliderRef,\n event.clientX,\n max,\n min,\n step,\n decimalPlaces,\n marks,\n restrictToMarks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n lastValueRef.current = newValue;\n setValue(newValue);\n onChange?.(event.nativeEvent, newValue);\n },\n [\n decimalPlaces,\n inputRef,\n marks,\n max,\n min,\n onChange,\n restrictToMarks,\n setValue,\n step,\n ],\n );\n\n const handleKeydownOnThumb = useCallback(\n (event: React.KeyboardEvent) => {\n const newValue = getKeyboardValue(\n event,\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n );\n if (newValue === undefined || lastValueRef.current === newValue) {\n return;\n }\n setIsFocusVisible(true);\n lastValueRef.current = newValue;\n handleInputChange({\n target: { value: newValue.toString() },\n } as ChangeEvent<HTMLInputElement>);\n },\n [\n value,\n step,\n stepMultiplier,\n max,\n min,\n restrictToMarks,\n marks,\n handleInputChange,\n ],\n );\n\n const handleFocus = () => setIsFocusVisible(true);\n const handleBlur = () => setIsFocusVisible(false);\n\n return {\n handleBlur,\n handleFocus,\n handleKeydownOnThumb,\n handlePointerDownOnThumb,\n handlePointerDownOnTrack,\n isDragging,\n isFocusVisible,\n sliderRef,\n };\n};\n"],"names":["useState","useRef","useWindow","useCallback","getClickedPosition","useEffect","getKeyboardValue"],"mappings":"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"}