@salt-ds/core 1.60.0 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +61 -0
- package/css/salt-core.css +492 -1
- package/dist-cjs/index.js +32 -0
- package/dist-cjs/index.js.map +1 -1
- package/dist-cjs/navigation-item/NavigationItem.js +2 -0
- package/dist-cjs/navigation-item/NavigationItem.js.map +1 -1
- package/dist-cjs/rating/Rating.css.js +6 -0
- package/dist-cjs/rating/Rating.css.js.map +1 -0
- package/dist-cjs/rating/Rating.js +140 -0
- package/dist-cjs/rating/Rating.js.map +1 -0
- package/dist-cjs/rating/RatingItem.css.js +6 -0
- package/dist-cjs/rating/RatingItem.css.js.map +1 -0
- package/dist-cjs/rating/RatingItem.js +75 -0
- package/dist-cjs/rating/RatingItem.js.map +1 -0
- package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js +22 -20
- package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
- package/dist-cjs/side-panel/SidePanel.css.js +6 -0
- package/dist-cjs/side-panel/SidePanel.css.js.map +1 -0
- package/dist-cjs/side-panel/SidePanel.js +205 -0
- package/dist-cjs/side-panel/SidePanel.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelCloseButton.js +44 -0
- package/dist-cjs/side-panel/SidePanelCloseButton.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelContent.css.js +6 -0
- package/dist-cjs/side-panel/SidePanelContent.css.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelContent.js +70 -0
- package/dist-cjs/side-panel/SidePanelContent.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelHeader.css.js +6 -0
- package/dist-cjs/side-panel/SidePanelHeader.css.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelHeader.js +30 -0
- package/dist-cjs/side-panel/SidePanelHeader.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelProvider.js +83 -0
- package/dist-cjs/side-panel/SidePanelProvider.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelTitle.css.js +6 -0
- package/dist-cjs/side-panel/SidePanelTitle.css.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelTitle.js +60 -0
- package/dist-cjs/side-panel/SidePanelTitle.js.map +1 -0
- package/dist-cjs/side-panel/SidePanelTrigger.js +43 -0
- package/dist-cjs/side-panel/SidePanelTrigger.js.map +1 -0
- package/dist-cjs/side-panel/internal/SidePanelContext.js +38 -0
- package/dist-cjs/side-panel/internal/SidePanelContext.js.map +1 -0
- package/dist-cjs/side-panel/internal/useIsScrollable.js +50 -0
- package/dist-cjs/side-panel/internal/useIsScrollable.js.map +1 -0
- package/dist-cjs/side-panel/internal/useSidePanelTabOrder.js +214 -0
- package/dist-cjs/side-panel/internal/useSidePanelTabOrder.js.map +1 -0
- package/dist-cjs/side-panel/useSidePanel.js +49 -0
- package/dist-cjs/side-panel/useSidePanel.js.map +1 -0
- package/dist-cjs/tabs/Tab.css.js +6 -0
- package/dist-cjs/tabs/Tab.css.js.map +1 -0
- package/dist-cjs/tabs/Tab.js +211 -0
- package/dist-cjs/tabs/Tab.js.map +1 -0
- package/dist-cjs/tabs/TabAction.js +63 -0
- package/dist-cjs/tabs/TabAction.js.map +1 -0
- package/dist-cjs/tabs/TabBar.css.js +6 -0
- package/dist-cjs/tabs/TabBar.css.js.map +1 -0
- package/dist-cjs/tabs/TabBar.js +45 -0
- package/dist-cjs/tabs/TabBar.js.map +1 -0
- package/dist-cjs/tabs/TabList.css.js +6 -0
- package/dist-cjs/tabs/TabList.css.js.map +1 -0
- package/dist-cjs/tabs/TabList.js +281 -0
- package/dist-cjs/tabs/TabList.js.map +1 -0
- package/dist-cjs/tabs/TabPanel.css.js +6 -0
- package/dist-cjs/tabs/TabPanel.css.js.map +1 -0
- package/dist-cjs/tabs/TabPanel.js +98 -0
- package/dist-cjs/tabs/TabPanel.js.map +1 -0
- package/dist-cjs/tabs/TabTrigger.css.js +6 -0
- package/dist-cjs/tabs/TabTrigger.css.js.map +1 -0
- package/dist-cjs/tabs/TabTrigger.js +188 -0
- package/dist-cjs/tabs/TabTrigger.js.map +1 -0
- package/dist-cjs/tabs/Tabs.css.js +6 -0
- package/dist-cjs/tabs/Tabs.css.js.map +1 -0
- package/dist-cjs/tabs/Tabs.js +200 -0
- package/dist-cjs/tabs/Tabs.js.map +1 -0
- package/dist-cjs/tabs/internal/contexts/TabContext.js +26 -0
- package/dist-cjs/tabs/internal/contexts/TabContext.js.map +1 -0
- package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js +19 -0
- package/dist-cjs/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
- package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js +22 -0
- package/dist-cjs/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
- package/dist-cjs/tabs/internal/contexts/TabsContext.js +50 -0
- package/dist-cjs/tabs/internal/contexts/TabsContext.js.map +1 -0
- package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js +64 -0
- package/dist-cjs/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
- package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js +76 -0
- package/dist-cjs/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
- package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js +165 -0
- package/dist-cjs/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
- package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js +87 -0
- package/dist-cjs/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js +6 -0
- package/dist-cjs/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/TabOverflowList.js +245 -0
- package/dist-cjs/tabs/internal/overflow/TabOverflowList.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/TabSlot.js +30 -0
- package/dist-cjs/tabs/internal/overflow/TabSlot.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/overflowMath.js +86 -0
- package/dist-cjs/tabs/internal/overflow/overflowMath.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/useOverflow.js +273 -0
- package/dist-cjs/tabs/internal/overflow/useOverflow.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js +99 -0
- package/dist-cjs/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js +68 -0
- package/dist-cjs/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js +92 -0
- package/dist-cjs/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
- package/dist-cjs/tabs/internal/overflow/widthMeasurement.js +42 -0
- package/dist-cjs/tabs/internal/overflow/widthMeasurement.js.map +1 -0
- package/dist-cjs/tabs/internal/registry/useCollection.js +197 -0
- package/dist-cjs/tabs/internal/registry/useCollection.js.map +1 -0
- package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js +206 -0
- package/dist-cjs/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
- package/dist-cjs/tabs/internal/utils/domUtils.js +13 -0
- package/dist-cjs/tabs/internal/utils/domUtils.js.map +1 -0
- package/dist-es/index.js +16 -0
- package/dist-es/index.js.map +1 -1
- package/dist-es/navigation-item/NavigationItem.js +2 -0
- package/dist-es/navigation-item/NavigationItem.js.map +1 -1
- package/dist-es/rating/Rating.css.js +4 -0
- package/dist-es/rating/Rating.css.js.map +1 -0
- package/dist-es/rating/Rating.js +138 -0
- package/dist-es/rating/Rating.js.map +1 -0
- package/dist-es/rating/RatingItem.css.js +4 -0
- package/dist-es/rating/RatingItem.css.js.map +1 -0
- package/dist-es/rating/RatingItem.js +73 -0
- package/dist-es/rating/RatingItem.js.map +1 -0
- package/dist-es/semantic-icon-provider/SemanticIconProvider.js +23 -21
- package/dist-es/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
- package/dist-es/side-panel/SidePanel.css.js +4 -0
- package/dist-es/side-panel/SidePanel.css.js.map +1 -0
- package/dist-es/side-panel/SidePanel.js +203 -0
- package/dist-es/side-panel/SidePanel.js.map +1 -0
- package/dist-es/side-panel/SidePanelCloseButton.js +42 -0
- package/dist-es/side-panel/SidePanelCloseButton.js.map +1 -0
- package/dist-es/side-panel/SidePanelContent.css.js +4 -0
- package/dist-es/side-panel/SidePanelContent.css.js.map +1 -0
- package/dist-es/side-panel/SidePanelContent.js +68 -0
- package/dist-es/side-panel/SidePanelContent.js.map +1 -0
- package/dist-es/side-panel/SidePanelHeader.css.js +4 -0
- package/dist-es/side-panel/SidePanelHeader.css.js.map +1 -0
- package/dist-es/side-panel/SidePanelHeader.js +28 -0
- package/dist-es/side-panel/SidePanelHeader.js.map +1 -0
- package/dist-es/side-panel/SidePanelProvider.js +81 -0
- package/dist-es/side-panel/SidePanelProvider.js.map +1 -0
- package/dist-es/side-panel/SidePanelTitle.css.js +4 -0
- package/dist-es/side-panel/SidePanelTitle.css.js.map +1 -0
- package/dist-es/side-panel/SidePanelTitle.js +58 -0
- package/dist-es/side-panel/SidePanelTitle.js.map +1 -0
- package/dist-es/side-panel/SidePanelTrigger.js +41 -0
- package/dist-es/side-panel/SidePanelTrigger.js.map +1 -0
- package/dist-es/side-panel/internal/SidePanelContext.js +35 -0
- package/dist-es/side-panel/internal/SidePanelContext.js.map +1 -0
- package/dist-es/side-panel/internal/useIsScrollable.js +48 -0
- package/dist-es/side-panel/internal/useIsScrollable.js.map +1 -0
- package/dist-es/side-panel/internal/useSidePanelTabOrder.js +212 -0
- package/dist-es/side-panel/internal/useSidePanelTabOrder.js.map +1 -0
- package/dist-es/side-panel/useSidePanel.js +47 -0
- package/dist-es/side-panel/useSidePanel.js.map +1 -0
- package/dist-es/tabs/Tab.css.js +4 -0
- package/dist-es/tabs/Tab.css.js.map +1 -0
- package/dist-es/tabs/Tab.js +209 -0
- package/dist-es/tabs/Tab.js.map +1 -0
- package/dist-es/tabs/TabAction.js +61 -0
- package/dist-es/tabs/TabAction.js.map +1 -0
- package/dist-es/tabs/TabBar.css.js +4 -0
- package/dist-es/tabs/TabBar.css.js.map +1 -0
- package/dist-es/tabs/TabBar.js +43 -0
- package/dist-es/tabs/TabBar.js.map +1 -0
- package/dist-es/tabs/TabList.css.js +4 -0
- package/dist-es/tabs/TabList.css.js.map +1 -0
- package/dist-es/tabs/TabList.js +279 -0
- package/dist-es/tabs/TabList.js.map +1 -0
- package/dist-es/tabs/TabPanel.css.js +4 -0
- package/dist-es/tabs/TabPanel.css.js.map +1 -0
- package/dist-es/tabs/TabPanel.js +96 -0
- package/dist-es/tabs/TabPanel.js.map +1 -0
- package/dist-es/tabs/TabTrigger.css.js +4 -0
- package/dist-es/tabs/TabTrigger.css.js.map +1 -0
- package/dist-es/tabs/TabTrigger.js +186 -0
- package/dist-es/tabs/TabTrigger.js.map +1 -0
- package/dist-es/tabs/Tabs.css.js +4 -0
- package/dist-es/tabs/Tabs.css.js.map +1 -0
- package/dist-es/tabs/Tabs.js +198 -0
- package/dist-es/tabs/Tabs.js.map +1 -0
- package/dist-es/tabs/internal/contexts/TabContext.js +23 -0
- package/dist-es/tabs/internal/contexts/TabContext.js.map +1 -0
- package/dist-es/tabs/internal/contexts/TabListLayoutContext.js +16 -0
- package/dist-es/tabs/internal/contexts/TabListLayoutContext.js.map +1 -0
- package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js +19 -0
- package/dist-es/tabs/internal/contexts/TabSlotRegistryContext.js.map +1 -0
- package/dist-es/tabs/internal/contexts/TabsContext.js +47 -0
- package/dist-es/tabs/internal/contexts/TabsContext.js.map +1 -0
- package/dist-es/tabs/internal/hooks/useFocusWithRetry.js +62 -0
- package/dist-es/tabs/internal/hooks/useFocusWithRetry.js.map +1 -0
- package/dist-es/tabs/internal/hooks/useTabListRecovery.js +74 -0
- package/dist-es/tabs/internal/hooks/useTabListRecovery.js.map +1 -0
- package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js +163 -0
- package/dist-es/tabs/internal/hooks/useTabRemovalHandler.js.map +1 -0
- package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js +85 -0
- package/dist-es/tabs/internal/hooks/useTabSelectionFocus.js.map +1 -0
- package/dist-es/tabs/internal/overflow/TabOverflowList.css.js +4 -0
- package/dist-es/tabs/internal/overflow/TabOverflowList.css.js.map +1 -0
- package/dist-es/tabs/internal/overflow/TabOverflowList.js +243 -0
- package/dist-es/tabs/internal/overflow/TabOverflowList.js.map +1 -0
- package/dist-es/tabs/internal/overflow/TabSlot.js +28 -0
- package/dist-es/tabs/internal/overflow/TabSlot.js.map +1 -0
- package/dist-es/tabs/internal/overflow/overflowMath.js +82 -0
- package/dist-es/tabs/internal/overflow/overflowMath.js.map +1 -0
- package/dist-es/tabs/internal/overflow/useOverflow.js +271 -0
- package/dist-es/tabs/internal/overflow/useOverflow.js.map +1 -0
- package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js +97 -0
- package/dist-es/tabs/internal/overflow/useOverflowLayoutState.js.map +1 -0
- package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js +66 -0
- package/dist-es/tabs/internal/overflow/useOverflowSelectionState.js.map +1 -0
- package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js +90 -0
- package/dist-es/tabs/internal/overflow/useRenderedTabWidth.js.map +1 -0
- package/dist-es/tabs/internal/overflow/widthMeasurement.js +36 -0
- package/dist-es/tabs/internal/overflow/widthMeasurement.js.map +1 -0
- package/dist-es/tabs/internal/registry/useCollection.js +195 -0
- package/dist-es/tabs/internal/registry/useCollection.js.map +1 -0
- package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js +204 -0
- package/dist-es/tabs/internal/registry/useRenderedTabsRegistry.js.map +1 -0
- package/dist-es/tabs/internal/utils/domUtils.js +11 -0
- package/dist-es/tabs/internal/utils/domUtils.js.map +1 -0
- package/dist-types/index.d.ts +3 -0
- package/dist-types/rating/Rating.d.ts +48 -0
- package/dist-types/rating/RatingItem.d.ts +47 -0
- package/dist-types/rating/index.d.ts +1 -0
- package/dist-types/semantic-icon-provider/SemanticIconProvider.d.ts +21 -19
- package/dist-types/side-panel/SidePanel.d.ts +26 -0
- package/dist-types/side-panel/SidePanelCloseButton.d.ts +2 -0
- package/dist-types/side-panel/SidePanelContent.d.ts +5 -0
- package/dist-types/side-panel/SidePanelHeader.d.ts +5 -0
- package/dist-types/side-panel/SidePanelProvider.d.ts +20 -0
- package/dist-types/side-panel/SidePanelTitle.d.ts +3 -0
- package/dist-types/side-panel/SidePanelTrigger.d.ts +3 -0
- package/dist-types/side-panel/index.d.ts +8 -0
- package/dist-types/side-panel/internal/SidePanelContext.d.ts +52 -0
- package/dist-types/side-panel/internal/index.d.ts +3 -0
- package/dist-types/side-panel/internal/useIsScrollable.d.ts +2 -0
- package/dist-types/side-panel/internal/useSidePanelTabOrder.d.ts +7 -0
- package/dist-types/side-panel/useSidePanel.d.ts +58 -0
- package/dist-types/tabs/Tab.d.ts +12 -0
- package/dist-types/tabs/TabAction.d.ts +4 -0
- package/dist-types/tabs/TabBar.d.ts +12 -0
- package/dist-types/tabs/TabList.d.ts +12 -0
- package/dist-types/tabs/TabPanel.d.ts +9 -0
- package/dist-types/tabs/TabTrigger.d.ts +4 -0
- package/dist-types/tabs/Tabs.d.ts +20 -0
- package/dist-types/tabs/index.d.ts +7 -0
- package/dist-types/tabs/internal/contexts/TabContext.d.ts +12 -0
- package/dist-types/tabs/internal/contexts/TabListLayoutContext.d.ts +9 -0
- package/dist-types/tabs/internal/contexts/TabSlotRegistryContext.d.ts +5 -0
- package/dist-types/tabs/internal/contexts/TabsContext.d.ts +43 -0
- package/dist-types/tabs/internal/hooks/useFocusWithRetry.d.ts +9 -0
- package/dist-types/tabs/internal/hooks/useTabListRecovery.d.ts +12 -0
- package/dist-types/tabs/internal/hooks/useTabRemovalHandler.d.ts +32 -0
- package/dist-types/tabs/internal/hooks/useTabSelectionFocus.d.ts +15 -0
- package/dist-types/tabs/internal/overflow/TabOverflowList.d.ts +10 -0
- package/dist-types/tabs/internal/overflow/TabSlot.d.ts +6 -0
- package/dist-types/tabs/internal/overflow/overflowMath.d.ts +18 -0
- package/dist-types/tabs/internal/overflow/useOverflow.d.ts +11 -0
- package/dist-types/tabs/internal/overflow/useOverflowLayoutState.d.ts +13 -0
- package/dist-types/tabs/internal/overflow/useOverflowSelectionState.d.ts +13 -0
- package/dist-types/tabs/internal/overflow/useRenderedTabWidth.d.ts +12 -0
- package/dist-types/tabs/internal/overflow/widthMeasurement.d.ts +5 -0
- package/dist-types/tabs/internal/registry/useCollection.d.ts +30 -0
- package/dist-types/tabs/internal/registry/useRenderedTabsRegistry.d.ts +12 -0
- package/dist-types/tabs/internal/utils/domUtils.d.ts +1 -0
- package/package.json +3 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
3
|
+
import { useWindow } from '@salt-ds/window';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { forwardRef, useState } from 'react';
|
|
6
|
+
import '../form-field-context/FormFieldContext.js';
|
|
7
|
+
import { useFormFieldProps } from '../form-field-context/useFormFieldProps.js';
|
|
8
|
+
import { capitalize } from '../utils/capitalize.js';
|
|
9
|
+
import { makePrefixer } from '../utils/makePrefixer.js';
|
|
10
|
+
import { useControlled } from '../utils/useControlled.js';
|
|
11
|
+
import '../utils/useFloatingUI/useFloatingUI.js';
|
|
12
|
+
import { useId } from '../utils/useId.js';
|
|
13
|
+
import '../salt-provider/SaltProvider.js';
|
|
14
|
+
import '../viewport/ViewportProvider.js';
|
|
15
|
+
import css_248z from './Rating.css.js';
|
|
16
|
+
import { RatingItem } from './RatingItem.js';
|
|
17
|
+
|
|
18
|
+
const withBaseName = makePrefixer("saltRating");
|
|
19
|
+
const defaultGetLabel = (value) => `${value} Star${value > 1 ? "s" : ""}`;
|
|
20
|
+
const Rating = forwardRef(function Rating2({
|
|
21
|
+
value: valueProp,
|
|
22
|
+
defaultValue = 0,
|
|
23
|
+
name: nameProp,
|
|
24
|
+
onChange,
|
|
25
|
+
className,
|
|
26
|
+
readOnly: readOnlyProp,
|
|
27
|
+
disabled: disabledProp,
|
|
28
|
+
max = 5,
|
|
29
|
+
getLabel = defaultGetLabel,
|
|
30
|
+
getVisibleLabel,
|
|
31
|
+
labelPlacement = "right",
|
|
32
|
+
"aria-label": ariaLabel,
|
|
33
|
+
"aria-labelledby": ariaLabelledBy,
|
|
34
|
+
"aria-describedby": ariaDescribedBy,
|
|
35
|
+
...restProps
|
|
36
|
+
}, ref) {
|
|
37
|
+
const targetWindow = useWindow();
|
|
38
|
+
useComponentCssInjection({
|
|
39
|
+
testId: "salt-rating",
|
|
40
|
+
css: css_248z,
|
|
41
|
+
window: targetWindow
|
|
42
|
+
});
|
|
43
|
+
const {
|
|
44
|
+
disabled: formFieldDisabled,
|
|
45
|
+
readOnly: formFieldReadOnly,
|
|
46
|
+
a11yProps: {
|
|
47
|
+
"aria-describedby": formFieldDescribedBy,
|
|
48
|
+
"aria-labelledby": formFieldLabelledBy
|
|
49
|
+
} = {}
|
|
50
|
+
} = useFormFieldProps();
|
|
51
|
+
const disabled = formFieldDisabled || disabledProp;
|
|
52
|
+
const readOnly = formFieldReadOnly || readOnlyProp;
|
|
53
|
+
const [hoveredValue, setHoveredValue] = useState(0);
|
|
54
|
+
const [selected, setSelected] = useControlled({
|
|
55
|
+
controlled: valueProp,
|
|
56
|
+
default: defaultValue,
|
|
57
|
+
name: "Rating",
|
|
58
|
+
state: "value"
|
|
59
|
+
});
|
|
60
|
+
const name = useId(nameProp);
|
|
61
|
+
const handleMouseEnter = (event) => {
|
|
62
|
+
if (readOnly || disabled) return;
|
|
63
|
+
const itemValue = Number.parseInt(event.currentTarget.value, 10);
|
|
64
|
+
setHoveredValue(itemValue);
|
|
65
|
+
};
|
|
66
|
+
const handleChange = (event) => {
|
|
67
|
+
if (readOnly) {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const itemValue = Number.parseInt(event.currentTarget.value, 10);
|
|
72
|
+
setSelected(itemValue);
|
|
73
|
+
onChange == null ? void 0 : onChange(event, itemValue);
|
|
74
|
+
};
|
|
75
|
+
return /* @__PURE__ */ jsxs(
|
|
76
|
+
"div",
|
|
77
|
+
{
|
|
78
|
+
ref,
|
|
79
|
+
className: clsx(
|
|
80
|
+
withBaseName(),
|
|
81
|
+
withBaseName(`label${capitalize(labelPlacement)}`),
|
|
82
|
+
className
|
|
83
|
+
),
|
|
84
|
+
...restProps,
|
|
85
|
+
children: [
|
|
86
|
+
/* @__PURE__ */ jsx(
|
|
87
|
+
"div",
|
|
88
|
+
{
|
|
89
|
+
role: "radiogroup",
|
|
90
|
+
className: withBaseName("container"),
|
|
91
|
+
"aria-readonly": readOnly || void 0,
|
|
92
|
+
"aria-label": ariaLabel,
|
|
93
|
+
"aria-labelledby": clsx(formFieldLabelledBy, ariaLabelledBy) || void 0,
|
|
94
|
+
"aria-describedby": clsx(formFieldDescribedBy, ariaDescribedBy) || void 0,
|
|
95
|
+
onMouseLeave: () => setHoveredValue(0),
|
|
96
|
+
children: Array.from({ length: max }, (_, index) => {
|
|
97
|
+
const itemValue = index + 1;
|
|
98
|
+
const isHovered = hoveredValue > 0 && itemValue <= hoveredValue;
|
|
99
|
+
const isSelected = hoveredValue === 0 && itemValue <= selected;
|
|
100
|
+
const isUnselecting = hoveredValue > 0 && itemValue > hoveredValue && itemValue <= selected;
|
|
101
|
+
return /* @__PURE__ */ jsx(
|
|
102
|
+
RatingItem,
|
|
103
|
+
{
|
|
104
|
+
currentRating: selected,
|
|
105
|
+
isHovered,
|
|
106
|
+
isSelected,
|
|
107
|
+
isUnselecting,
|
|
108
|
+
onMouseEnter: handleMouseEnter,
|
|
109
|
+
onChange: handleChange,
|
|
110
|
+
value: itemValue,
|
|
111
|
+
readOnly,
|
|
112
|
+
disabled,
|
|
113
|
+
name,
|
|
114
|
+
"aria-label": getLabel == null ? void 0 : getLabel(itemValue)
|
|
115
|
+
},
|
|
116
|
+
itemValue
|
|
117
|
+
);
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
getVisibleLabel && /* @__PURE__ */ jsx(
|
|
122
|
+
"div",
|
|
123
|
+
{
|
|
124
|
+
className: clsx(
|
|
125
|
+
withBaseName("label"),
|
|
126
|
+
withBaseName(`label-${labelPlacement}`)
|
|
127
|
+
),
|
|
128
|
+
"aria-hidden": true,
|
|
129
|
+
children: getVisibleLabel(hoveredValue || selected, max)
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
export { Rating };
|
|
138
|
+
//# sourceMappingURL=Rating.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Rating.js","sources":["../src/rating/Rating.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n useState,\n} from \"react\";\nimport { useFormFieldProps } from \"../form-field-context\";\nimport { capitalize, makePrefixer, useControlled, useId } from \"../utils\";\nimport ratingCss from \"./Rating.css\";\nimport { RatingItem } from \"./RatingItem\";\n\nconst withBaseName = makePrefixer(\"saltRating\");\n\nexport interface RatingProps\n extends Omit<ComponentPropsWithoutRef<\"div\">, \"onChange\"> {\n /**\n * When provided, the component is controlled.\n */\n value?: number;\n /**\n * Default rating value for uncontrolled mode.\n * @default 0\n */\n defaultValue?: number;\n /**\n * Callback function for rating change.\n * The first parameter is the event, and the second is the selected rating value.\n */\n onChange?: (event: ChangeEvent<HTMLInputElement>, value: number) => void;\n /**\n * If true, the rating component will be in a read-only state.\n */\n readOnly?: boolean;\n /**\n * If true, the rating component will be in a disabled state.\n */\n disabled?: boolean;\n /**\n * Total number of icons displayed.\n * @default 5\n */\n max?: number;\n /**\n * Function used to provide a user-friendly name for the current value of the rating. Primarily used by screen readers.\n */\n getLabel?: (value: number) => string;\n /**\n * Function used to provide a visible label for the rating.\n */\n getVisibleLabel?: (value: number, max: number) => string;\n /**\n * Position of the label relative to the rating component.\n * @default \"right\"\n */\n labelPlacement?: \"right\" | \"bottom\";\n /**\n * The name to be set on each radio button within the group. If not set, then one will be generated for you.\n */\n name?: string;\n}\n\nconst defaultGetLabel = (value: number) =>\n `${value} Star${value > 1 ? \"s\" : \"\"}`;\n\nexport const Rating = forwardRef<HTMLDivElement, RatingProps>(function Rating(\n {\n value: valueProp,\n defaultValue = 0,\n name: nameProp,\n onChange,\n className,\n readOnly: readOnlyProp,\n disabled: disabledProp,\n max = 5,\n getLabel = defaultGetLabel,\n getVisibleLabel,\n labelPlacement = \"right\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n ...restProps\n },\n ref,\n) {\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-rating\",\n css: ratingCss,\n window: targetWindow,\n });\n const {\n disabled: formFieldDisabled,\n readOnly: formFieldReadOnly,\n a11yProps: {\n \"aria-describedby\": formFieldDescribedBy,\n \"aria-labelledby\": formFieldLabelledBy,\n } = {},\n } = useFormFieldProps();\n\n const disabled = formFieldDisabled || disabledProp;\n const readOnly = formFieldReadOnly || readOnlyProp;\n\n const [hoveredValue, setHoveredValue] = useState(0);\n const [selected, setSelected] = useControlled({\n controlled: valueProp,\n default: defaultValue,\n name: \"Rating\",\n state: \"value\",\n });\n const name = useId(nameProp);\n\n const handleMouseEnter = (event: MouseEvent<HTMLInputElement>) => {\n if (readOnly || disabled) return;\n const itemValue = Number.parseInt(event.currentTarget.value, 10);\n setHoveredValue(itemValue);\n };\n\n const handleChange = (event: ChangeEvent<HTMLInputElement>) => {\n if (readOnly) {\n event.preventDefault();\n return;\n }\n\n const itemValue = Number.parseInt(event.currentTarget.value, 10);\n setSelected(itemValue);\n onChange?.(event, itemValue);\n };\n\n return (\n <div\n ref={ref}\n className={clsx(\n withBaseName(),\n withBaseName(`label${capitalize(labelPlacement)}`),\n className,\n )}\n {...restProps}\n >\n <div\n role=\"radiogroup\"\n className={withBaseName(\"container\")}\n aria-readonly={readOnly || undefined}\n aria-label={ariaLabel}\n aria-labelledby={clsx(formFieldLabelledBy, ariaLabelledBy) || undefined}\n aria-describedby={\n clsx(formFieldDescribedBy, ariaDescribedBy) || undefined\n }\n onMouseLeave={() => setHoveredValue(0)}\n >\n {Array.from({ length: max }, (_, index) => {\n const itemValue = index + 1;\n const isHovered = hoveredValue > 0 && itemValue <= hoveredValue;\n const isSelected = hoveredValue === 0 && itemValue <= selected;\n const isUnselecting =\n hoveredValue > 0 &&\n itemValue > hoveredValue &&\n itemValue <= selected;\n return (\n <RatingItem\n key={itemValue}\n currentRating={selected}\n isHovered={isHovered}\n isSelected={isSelected}\n isUnselecting={isUnselecting}\n onMouseEnter={handleMouseEnter}\n onChange={handleChange}\n value={itemValue}\n readOnly={readOnly}\n disabled={disabled}\n name={name}\n aria-label={getLabel?.(itemValue)}\n />\n );\n })}\n </div>\n {getVisibleLabel && (\n <div\n className={clsx(\n withBaseName(\"label\"),\n withBaseName(`label-${labelPlacement}`),\n )}\n aria-hidden\n >\n {getVisibleLabel(hoveredValue || selected, max)}\n </div>\n )}\n </div>\n );\n});\n"],"names":["Rating","ratingCss"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var css_248z = ".saltRatingItem {\n height: var(--salt-size-icon);\n width: var(--salt-size-icon);\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n cursor: var(--salt-cursor-hover);\n}\n\n.saltRatingItem-disabled,\n.saltRatingItem-readOnly {\n cursor: default;\n}\n\n.saltRatingItem-input {\n position: absolute;\n opacity: 0;\n width: 100%;\n height: 100%;\n margin: 0;\n cursor: inherit;\n z-index: 1;\n}\n\n.saltRatingItem-input::before {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 100%;\n padding: var(--salt-spacing-fixed-600);\n transform: translate(-50%, -50%);\n top: 50%;\n left: 50%;\n box-sizing: content-box;\n}\n\n.saltRatingItem-icon {\n pointer-events: none;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--salt-sentiment-neutral-dataviz);\n}\n\n.saltRatingItem-icon .saltIcon {\n --saltIcon-size: var(--salt-size-icon);\n}\n\n.saltRatingItem-input:focus-visible ~ .saltRatingItem-icon::after {\n content: \"\";\n position: absolute;\n width: 100%;\n height: 100%;\n padding: var(--salt-spacing-fixed-600);\n transform: translate(-50%, -50%);\n top: 50%;\n left: 50%;\n box-sizing: content-box;\n\n border-radius: var(--salt-palette-corner-strongest);\n outline: var(--salt-focused-outline);\n outline-offset: calc(-1 * var(--salt-spacing-fixed-200));\n}\n\n.saltRatingItem-disabled {\n cursor: var(--salt-cursor-disabled);\n opacity: 0.4;\n}\n\n.saltRatingItem-disabled .saltRatingItem-input {\n cursor: var(--salt-cursor-disabled);\n}\n\n.saltRatingItem-selected .saltRatingItem-icon,\n.saltRatingItem-hovered .saltRatingItem-icon,\n.saltRatingItem-unselecting .saltRatingItem-icon {\n color: var(--salt-sentiment-accent-dataviz);\n}\n";
|
|
2
|
+
|
|
3
|
+
export { css_248z as default };
|
|
4
|
+
//# sourceMappingURL=RatingItem.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RatingItem.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
3
|
+
import { useWindow } from '@salt-ds/window';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { forwardRef } from 'react';
|
|
6
|
+
import { useIcon } from '../semantic-icon-provider/SemanticIconProvider.js';
|
|
7
|
+
import { makePrefixer } from '../utils/makePrefixer.js';
|
|
8
|
+
import '../utils/useFloatingUI/useFloatingUI.js';
|
|
9
|
+
import '../utils/useId.js';
|
|
10
|
+
import '../salt-provider/SaltProvider.js';
|
|
11
|
+
import '../viewport/ViewportProvider.js';
|
|
12
|
+
import css_248z from './RatingItem.css.js';
|
|
13
|
+
|
|
14
|
+
const withBaseName = makePrefixer("saltRatingItem");
|
|
15
|
+
const RatingItem = forwardRef(
|
|
16
|
+
function RatingItem2(props, ref) {
|
|
17
|
+
const {
|
|
18
|
+
"aria-label": ariaLabel,
|
|
19
|
+
value,
|
|
20
|
+
currentRating,
|
|
21
|
+
isHovered,
|
|
22
|
+
isSelected,
|
|
23
|
+
isUnselecting,
|
|
24
|
+
onMouseEnter,
|
|
25
|
+
onChange,
|
|
26
|
+
readOnly = false,
|
|
27
|
+
disabled = false,
|
|
28
|
+
name
|
|
29
|
+
} = props;
|
|
30
|
+
const { RatingIcon, RatingSelectedIcon, RatingUnselectingIcon } = useIcon();
|
|
31
|
+
const targetWindow = useWindow();
|
|
32
|
+
useComponentCssInjection({
|
|
33
|
+
testId: "salt-rating-item",
|
|
34
|
+
css: css_248z,
|
|
35
|
+
window: targetWindow
|
|
36
|
+
});
|
|
37
|
+
const icon = isHovered || isSelected ? /* @__PURE__ */ jsx(RatingSelectedIcon, { "aria-hidden": true }) : isUnselecting ? /* @__PURE__ */ jsx(RatingUnselectingIcon, { "aria-hidden": true }) : /* @__PURE__ */ jsx(RatingIcon, { "aria-hidden": true });
|
|
38
|
+
return /* @__PURE__ */ jsxs(
|
|
39
|
+
"div",
|
|
40
|
+
{
|
|
41
|
+
className: clsx(withBaseName(), {
|
|
42
|
+
[withBaseName("hovered")]: isHovered,
|
|
43
|
+
[withBaseName("selected")]: isSelected,
|
|
44
|
+
[withBaseName("unselecting")]: isUnselecting,
|
|
45
|
+
[withBaseName("disabled")]: disabled,
|
|
46
|
+
[withBaseName("readOnly")]: readOnly
|
|
47
|
+
}),
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsx(
|
|
50
|
+
"input",
|
|
51
|
+
{
|
|
52
|
+
ref,
|
|
53
|
+
type: "radio",
|
|
54
|
+
name,
|
|
55
|
+
value,
|
|
56
|
+
checked: currentRating === value,
|
|
57
|
+
onChange,
|
|
58
|
+
onMouseEnter,
|
|
59
|
+
disabled,
|
|
60
|
+
readOnly,
|
|
61
|
+
className: withBaseName("input"),
|
|
62
|
+
"aria-label": ariaLabel
|
|
63
|
+
}
|
|
64
|
+
),
|
|
65
|
+
/* @__PURE__ */ jsx("span", { className: withBaseName("icon"), "aria-hidden": true, children: icon })
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
export { RatingItem };
|
|
73
|
+
//# sourceMappingURL=RatingItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RatingItem.js","sources":["../src/rating/RatingItem.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n} from \"react\";\nimport { useIcon } from \"../semantic-icon-provider\";\nimport { makePrefixer } from \"../utils\";\nimport ratingItemCss from \"./RatingItem.css\";\n\nconst withBaseName = makePrefixer(\"saltRatingItem\");\n\nexport interface RatingItemProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * specifies the value of the feedback item.\n */\n value: number;\n /**\n * To define if the current star is being hovered.\n */\n isHovered?: boolean;\n /**\n * To specify if the item is selected.\n */\n isSelected?: boolean;\n /**\n * defines the current selected rating.\n */\n currentRating?: number;\n /**\n * callback function when feedback item is hovered.\n */\n onMouseEnter: (event: MouseEvent<HTMLInputElement>) => void;\n /**\n * callback function when feedback item is clicked.\n */\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n /**\n * If true, the rating item will be in a read-only state.\n */\n readOnly?: boolean;\n /**\n * If true, the rating item will be in a disabled state.\n */\n disabled?: boolean;\n /**\n * Indicates whether the current rating item is in an active state.\n * An active state typically means that the item is visually highlighted\n * or styled differently to indicate that it is part of the current selection\n * or interaction (e.g., hover or focus).\n */\n isUnselecting?: boolean;\n /**\n * Name of the radio group\n */\n name?: string;\n}\n\nexport const RatingItem = forwardRef<HTMLInputElement, RatingItemProps>(\n function RatingItem(props, ref) {\n const {\n \"aria-label\": ariaLabel,\n value,\n currentRating,\n isHovered,\n isSelected,\n isUnselecting,\n onMouseEnter,\n onChange,\n readOnly = false,\n disabled = false,\n name,\n } = props;\n\n const { RatingIcon, RatingSelectedIcon, RatingUnselectingIcon } = useIcon();\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-rating-item\",\n css: ratingItemCss,\n window: targetWindow,\n });\n\n const icon =\n isHovered || isSelected ? (\n <RatingSelectedIcon aria-hidden />\n ) : isUnselecting ? (\n <RatingUnselectingIcon aria-hidden />\n ) : (\n <RatingIcon aria-hidden />\n );\n\n return (\n <div\n className={clsx(withBaseName(), {\n [withBaseName(\"hovered\")]: isHovered,\n [withBaseName(\"selected\")]: isSelected,\n [withBaseName(\"unselecting\")]: isUnselecting,\n [withBaseName(\"disabled\")]: disabled,\n [withBaseName(\"readOnly\")]: readOnly,\n })}\n >\n <input\n ref={ref}\n type=\"radio\"\n name={name}\n value={value}\n checked={currentRating === value}\n onChange={onChange}\n onMouseEnter={onMouseEnter}\n disabled={disabled}\n readOnly={readOnly}\n className={withBaseName(\"input\")}\n aria-label={ariaLabel}\n />\n <span className={withBaseName(\"icon\")} aria-hidden>\n {icon}\n </span>\n </div>\n );\n },\n);\n"],"names":["RatingItem","ratingItemCss"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,YAAA,GAAe,aAAa,gBAAgB,CAAA;AAgD3C,MAAM,UAAA,GAAa,UAAA;AAAA,EACxB,SAASA,WAAAA,CAAW,KAAA,EAAO,GAAA,EAAK;AAC9B,IAAA,MAAM;AAAA,MACJ,YAAA,EAAc,SAAA;AAAA,MACd,KAAA;AAAA,MACA,aAAA;AAAA,MACA,SAAA;AAAA,MACA,UAAA;AAAA,MACA,aAAA;AAAA,MACA,YAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA,GAAW,KAAA;AAAA,MACX,QAAA,GAAW,KAAA;AAAA,MACX;AAAA,KACF,GAAI,KAAA;AAEJ,IAAA,MAAM,EAAE,UAAA,EAAY,kBAAA,EAAoB,qBAAA,KAA0B,OAAA,EAAQ;AAE1E,IAAA,MAAM,eAAe,SAAA,EAAU;AAC/B,IAAA,wBAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,kBAAA;AAAA,MACR,GAAA,EAAKC,QAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,OACJ,SAAA,IAAa,UAAA,mBACX,GAAA,CAAC,kBAAA,EAAA,EAAmB,eAAW,IAAA,EAAC,CAAA,GAC9B,aAAA,mBACF,GAAA,CAAC,yBAAsB,aAAA,EAAW,IAAA,EAAC,oBAEnC,GAAA,CAAC,UAAA,EAAA,EAAW,eAAW,IAAA,EAAC,CAAA;AAG5B,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAW,IAAA,CAAK,YAAA,EAAa,EAAG;AAAA,UAC9B,CAAC,YAAA,CAAa,SAAS,CAAC,GAAG,SAAA;AAAA,UAC3B,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG,UAAA;AAAA,UAC5B,CAAC,YAAA,CAAa,aAAa,CAAC,GAAG,aAAA;AAAA,UAC/B,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG,QAAA;AAAA,UAC5B,CAAC,YAAA,CAAa,UAAU,CAAC,GAAG;AAAA,SAC7B,CAAA;AAAA,QAED,QAAA,EAAA;AAAA,0BAAA,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,GAAA;AAAA,cACA,IAAA,EAAK,OAAA;AAAA,cACL,IAAA;AAAA,cACA,KAAA;AAAA,cACA,SAAS,aAAA,KAAkB,KAAA;AAAA,cAC3B,QAAA;AAAA,cACA,YAAA;AAAA,cACA,QAAA;AAAA,cACA,QAAA;AAAA,cACA,SAAA,EAAW,aAAa,OAAO,CAAA;AAAA,cAC/B,YAAA,EAAY;AAAA;AAAA,WACd;AAAA,0BACA,GAAA,CAAC,UAAK,SAAA,EAAW,YAAA,CAAa,MAAM,CAAA,EAAG,aAAA,EAAW,MAC/C,QAAA,EAAA,IAAA,EACH;AAAA;AAAA;AAAA,KACF;AAAA,EAEJ;AACF;;;;"}
|
|
@@ -1,40 +1,42 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { WarningSolidIcon, UserSolidIcon, UploadIcon, SuccessCircleSolidIcon, FavoriteStrongIcon, FavoriteSolidIcon, FavoriteIcon, ChevronLeftIcon, StepDefaultIcon, OverflowMenuIcon, ChevronRightIcon, LockedIcon, ProgressInprogressIcon, InfoSolidIcon, TriangleUpIcon, TearOutIcon, ChevronDownIcon, ErrorSolidIcon, TriangleDownIcon, DoubleChevronRightIcon, DoubleChevronLeftIcon, ChevronUpIcon, CloseIcon, CalendarIcon, StepActiveIcon } from '@salt-ds/icons';
|
|
3
3
|
import { createContext, useContext } from 'react';
|
|
4
4
|
import { ErrorAdornmentIcon } from '../status-adornment/ErrorAdornment.js';
|
|
5
5
|
import { SuccessAdornmentIcon } from '../status-adornment/SuccessAdornment.js';
|
|
6
6
|
import { WarningAdornmentIcon } from '../status-adornment/WarningAdornment.js';
|
|
7
7
|
|
|
8
8
|
const defaultIconMap = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
ActiveIcon: StepActiveIcon,
|
|
10
|
+
CalendarIcon,
|
|
11
|
+
CloseIcon,
|
|
12
12
|
CollapseGroupIcon: ChevronDownIcon,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
CollapseIcon: ChevronUpIcon,
|
|
14
|
+
CollapseLeftIcon: DoubleChevronLeftIcon,
|
|
15
|
+
CollapseRightIcon: DoubleChevronRightIcon,
|
|
16
|
+
CompletedIcon: SuccessCircleSolidIcon,
|
|
16
17
|
DecreaseIcon: TriangleDownIcon,
|
|
17
|
-
UploadIcon,
|
|
18
18
|
ErrorIcon: ErrorSolidIcon,
|
|
19
|
-
|
|
19
|
+
ErrorStatusAdornment: ErrorAdornmentIcon,
|
|
20
|
+
ExpandGroupIcon: ChevronRightIcon,
|
|
21
|
+
ExpandIcon: ChevronDownIcon,
|
|
22
|
+
ExternalIcon: TearOutIcon,
|
|
23
|
+
IncreaseIcon: TriangleUpIcon,
|
|
20
24
|
InfoIcon: InfoSolidIcon,
|
|
21
|
-
|
|
25
|
+
InProgressIcon: ProgressInprogressIcon,
|
|
26
|
+
LockedIcon,
|
|
27
|
+
NextIcon: ChevronRightIcon,
|
|
22
28
|
OverflowIcon: OverflowMenuIcon,
|
|
23
|
-
UserIcon: UserSolidIcon,
|
|
24
|
-
CalendarIcon,
|
|
25
|
-
CloseIcon,
|
|
26
|
-
ExternalIcon: TearOutIcon,
|
|
27
29
|
PendingIcon: StepDefaultIcon,
|
|
28
|
-
|
|
29
|
-
CompletedIcon: SuccessCircleSolidIcon,
|
|
30
|
-
LockedIcon,
|
|
31
|
-
InProgressIcon: ProgressInprogressIcon,
|
|
30
|
+
PreviousIcon: ChevronLeftIcon,
|
|
32
31
|
RatingIcon: FavoriteIcon,
|
|
33
32
|
RatingSelectedIcon: FavoriteSolidIcon,
|
|
34
33
|
RatingUnselectingIcon: FavoriteStrongIcon,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
SuccessIcon: SuccessCircleSolidIcon,
|
|
35
|
+
SuccessStatusAdornment: SuccessAdornmentIcon,
|
|
36
|
+
UploadIcon,
|
|
37
|
+
UserIcon: UserSolidIcon,
|
|
38
|
+
WarningIcon: WarningSolidIcon,
|
|
39
|
+
WarningStatusAdornment: WarningAdornmentIcon
|
|
38
40
|
};
|
|
39
41
|
const SemanticIconContext = createContext(defaultIconMap);
|
|
40
42
|
const SemanticIconProvider = ({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SemanticIconProvider.js","sources":["../src/semantic-icon-provider/SemanticIconProvider.tsx"],"sourcesContent":["import {\n CalendarIcon,\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n ChevronUpIcon,\n CloseIcon,\n ErrorSolidIcon,\n FavoriteIcon,\n FavoriteSolidIcon,\n FavoriteStrongIcon,\n InfoSolidIcon,\n LockedIcon,\n OverflowMenuIcon,\n ProgressInprogressIcon,\n StepActiveIcon,\n StepDefaultIcon,\n SuccessCircleSolidIcon,\n TearOutIcon,\n TriangleDownIcon,\n TriangleUpIcon,\n UploadIcon,\n UserSolidIcon,\n WarningSolidIcon,\n} from \"@salt-ds/icons\";\nimport {\n createContext,\n type ElementType,\n type ReactNode,\n useContext,\n} from \"react\";\nimport { ErrorAdornmentIcon } from \"../status-adornment/ErrorAdornment\";\nimport { SuccessAdornmentIcon } from \"../status-adornment/SuccessAdornment\";\nimport { WarningAdornmentIcon } from \"../status-adornment/WarningAdornment\";\n\nexport interface SemanticIconMap {\n
|
|
1
|
+
{"version":3,"file":"SemanticIconProvider.js","sources":["../src/semantic-icon-provider/SemanticIconProvider.tsx"],"sourcesContent":["import {\n CalendarIcon,\n ChevronDownIcon,\n ChevronLeftIcon,\n ChevronRightIcon,\n ChevronUpIcon,\n CloseIcon,\n DoubleChevronLeftIcon,\n DoubleChevronRightIcon,\n ErrorSolidIcon,\n FavoriteIcon,\n FavoriteSolidIcon,\n FavoriteStrongIcon,\n InfoSolidIcon,\n LockedIcon,\n OverflowMenuIcon,\n ProgressInprogressIcon,\n StepActiveIcon,\n StepDefaultIcon,\n SuccessCircleSolidIcon,\n TearOutIcon,\n TriangleDownIcon,\n TriangleUpIcon,\n UploadIcon,\n UserSolidIcon,\n WarningSolidIcon,\n} from \"@salt-ds/icons\";\nimport {\n createContext,\n type ElementType,\n type ReactNode,\n useContext,\n} from \"react\";\nimport { ErrorAdornmentIcon } from \"../status-adornment/ErrorAdornment\";\nimport { SuccessAdornmentIcon } from \"../status-adornment/SuccessAdornment\";\nimport { WarningAdornmentIcon } from \"../status-adornment/WarningAdornment\";\n\nexport interface SemanticIconMap {\n ActiveIcon: ElementType;\n CalendarIcon: ElementType;\n CloseIcon: ElementType;\n CollapseGroupIcon: ElementType;\n CollapseIcon: ElementType;\n CollapseLeftIcon: ElementType;\n CollapseRightIcon: ElementType;\n CompletedIcon: ElementType;\n DecreaseIcon: ElementType;\n ErrorIcon: ElementType;\n ErrorStatusAdornment: ElementType;\n ExpandGroupIcon: ElementType;\n ExpandIcon: ElementType;\n ExternalIcon: ElementType;\n IncreaseIcon: ElementType;\n InfoIcon: ElementType;\n InProgressIcon: ElementType;\n LockedIcon: ElementType;\n NextIcon: ElementType;\n OverflowIcon: ElementType;\n PendingIcon: ElementType;\n PreviousIcon: ElementType;\n RatingIcon: ElementType;\n RatingSelectedIcon: ElementType;\n RatingUnselectingIcon: ElementType;\n SuccessIcon: ElementType;\n SuccessStatusAdornment: ElementType;\n UploadIcon: ElementType;\n UserIcon: ElementType;\n WarningIcon: ElementType;\n WarningStatusAdornment: ElementType;\n}\n\nexport interface SemanticIconProviderProps {\n /**\n * Custom mapping of icon names to components. Overrides default icons if provided.\n */\n iconMap?: Partial<SemanticIconMap>;\n\n /**\n * Child elements that will use the provided icons.\n */\n children: ReactNode;\n}\n\nconst defaultIconMap: SemanticIconMap = {\n ActiveIcon: StepActiveIcon,\n CalendarIcon: CalendarIcon,\n CloseIcon: CloseIcon,\n CollapseGroupIcon: ChevronDownIcon,\n CollapseIcon: ChevronUpIcon,\n CollapseLeftIcon: DoubleChevronLeftIcon,\n CollapseRightIcon: DoubleChevronRightIcon,\n CompletedIcon: SuccessCircleSolidIcon,\n DecreaseIcon: TriangleDownIcon,\n ErrorIcon: ErrorSolidIcon,\n ErrorStatusAdornment: ErrorAdornmentIcon,\n ExpandGroupIcon: ChevronRightIcon,\n ExpandIcon: ChevronDownIcon,\n ExternalIcon: TearOutIcon,\n IncreaseIcon: TriangleUpIcon,\n InfoIcon: InfoSolidIcon,\n InProgressIcon: ProgressInprogressIcon,\n LockedIcon: LockedIcon,\n NextIcon: ChevronRightIcon,\n OverflowIcon: OverflowMenuIcon,\n PendingIcon: StepDefaultIcon,\n PreviousIcon: ChevronLeftIcon,\n RatingIcon: FavoriteIcon,\n RatingSelectedIcon: FavoriteSolidIcon,\n RatingUnselectingIcon: FavoriteStrongIcon,\n SuccessIcon: SuccessCircleSolidIcon,\n SuccessStatusAdornment: SuccessAdornmentIcon,\n UploadIcon,\n UserIcon: UserSolidIcon,\n WarningIcon: WarningSolidIcon,\n WarningStatusAdornment: WarningAdornmentIcon,\n};\n\nconst SemanticIconContext = createContext<SemanticIconMap>(defaultIconMap);\n\nexport const SemanticIconProvider = ({\n iconMap = {},\n children,\n}: SemanticIconProviderProps) => (\n <SemanticIconContext.Provider value={{ ...defaultIconMap, ...iconMap }}>\n {children}\n </SemanticIconContext.Provider>\n);\n\nexport const useIcon = () => {\n const context = useContext(SemanticIconContext);\n return context || defaultIconMap;\n};\n"],"names":[],"mappings":";;;;;;;AAmFA,MAAM,cAAA,GAAkC;AAAA,EACtC,UAAA,EAAY,cAAA;AAAA,EACZ,YAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA,EAAmB,eAAA;AAAA,EACnB,YAAA,EAAc,aAAA;AAAA,EACd,gBAAA,EAAkB,qBAAA;AAAA,EAClB,iBAAA,EAAmB,sBAAA;AAAA,EACnB,aAAA,EAAe,sBAAA;AAAA,EACf,YAAA,EAAc,gBAAA;AAAA,EACd,SAAA,EAAW,cAAA;AAAA,EACX,oBAAA,EAAsB,kBAAA;AAAA,EACtB,eAAA,EAAiB,gBAAA;AAAA,EACjB,UAAA,EAAY,eAAA;AAAA,EACZ,YAAA,EAAc,WAAA;AAAA,EACd,YAAA,EAAc,cAAA;AAAA,EACd,QAAA,EAAU,aAAA;AAAA,EACV,cAAA,EAAgB,sBAAA;AAAA,EAChB,UAAA;AAAA,EACA,QAAA,EAAU,gBAAA;AAAA,EACV,YAAA,EAAc,gBAAA;AAAA,EACd,WAAA,EAAa,eAAA;AAAA,EACb,YAAA,EAAc,eAAA;AAAA,EACd,UAAA,EAAY,YAAA;AAAA,EACZ,kBAAA,EAAoB,iBAAA;AAAA,EACpB,qBAAA,EAAuB,kBAAA;AAAA,EACvB,WAAA,EAAa,sBAAA;AAAA,EACb,sBAAA,EAAwB,oBAAA;AAAA,EACxB,UAAA;AAAA,EACA,QAAA,EAAU,aAAA;AAAA,EACV,WAAA,EAAa,gBAAA;AAAA,EACb,sBAAA,EAAwB;AAC1B,CAAA;AAEA,MAAM,mBAAA,GAAsB,cAA+B,cAAc,CAAA;AAElE,MAAM,uBAAuB,CAAC;AAAA,EACnC,UAAU,EAAC;AAAA,EACX;AACF,CAAA,qBACE,GAAA,CAAC,mBAAA,CAAoB,QAAA,EAApB,EAA6B,KAAA,EAAO,EAAE,GAAG,cAAA,EAAgB,GAAG,OAAA,EAAQ,EAClE,QAAA,EACH;AAGK,MAAM,UAAU,MAAM;AAC3B,EAAA,MAAM,OAAA,GAAU,WAAW,mBAAmB,CAAA;AAC9C,EAAA,OAAO,OAAA,IAAW,cAAA;AACpB;;;;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var css_248z = ".saltSidePanel {\n --saltSidePanel-width: 300px;\n --sidePanel-border: var(--salt-size-fixed-100) var(--salt-borderStyle-solid) var(--sidePanel-borderColor, var(--salt-container-primary-borderColor));\n --saltSidePanel-padding: var(--salt-spacing-300);\n /* Outer wrapper. Idle: a normal flex column whose width comes from\n --saltSidePanel-width (supports any CSS length, including %).\n During enter/exit animation: animates `width` between 0 and the\n panel width and clips the absolutely-positioned inner via\n `contain: paint`. The inner uses a JS-resolved px width during\n animation (--saltSidePanel-animation-width) so percentage widths\n don't compound against the animating outer. */\n position: relative;\n display: flex;\n flex-direction: column;\n flex: none;\n width: var(--saltSidePanel-width);\n height: 100%;\n min-height: 0;\n align-self: stretch;\n}\n\n.saltSidePanel-primary {\n --sidePanel-background: var(--salt-container-primary-background);\n --sidePanel-borderColor: var(--salt-container-primary-borderColor);\n}\n\n.saltSidePanel-secondary {\n --sidePanel-background: var(--salt-container-secondary-background);\n --sidePanel-borderColor: var(--salt-container-secondary-borderColor);\n}\n\n.saltSidePanel-tertiary {\n --sidePanel-background: var(--salt-container-tertiary-background);\n --sidePanel-borderColor: var(--salt-container-tertiary-borderColor);\n}\n\n.saltSidePanel-none {\n --sidePanel-background: none;\n --saltSidePanel-padding: var(--salt-spacing-200);\n}\n\n.saltSidePanel-inner {\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n flex: 1;\n min-height: 0;\n padding: var(--saltSidePanel-padding);\n width: 100%;\n background-color: var(--sidePanel-background, var(--salt-container-primary-background));\n}\n\n.saltSidePanel-left .saltSidePanel-inner {\n border-right: var(--sidePanel-border);\n}\n\n.saltSidePanel-right .saltSidePanel-inner {\n border-left: var(--sidePanel-border);\n}\n\n.saltSidePanel-none .saltSidePanel-inner {\n border: none;\n}\n\n/* Animation: outer becomes the gap + clip; inner is absolutely positioned\n and anchored to the gap's GROWING edge so the leading edge tracks the\n gap's expansion — content visibly pushes the sibling rather than being\n revealed in place. Left grows rightward → anchor inner right; right\n grows leftward → anchor inner left.\n\n During animation the outer's width is interpolating, so the inner can't\n rely on --saltSidePanel-width (which may be a percentage that would\n resolve against the animating outer). Instead the JS layer measures the\n resolved width once and exposes it as --saltSidePanel-animation-width\n (a px value) for the inner to use. */\n.saltSidePanel-enterAnimation,\n.saltSidePanel-exitAnimation {\n contain: paint;\n}\n\n.saltSidePanel-enterAnimation .saltSidePanel-inner,\n.saltSidePanel-exitAnimation .saltSidePanel-inner {\n position: absolute;\n top: 0;\n bottom: 0;\n flex: none;\n width: var(--saltSidePanel-animation-width, var(--saltSidePanel-width));\n}\n\n.saltSidePanel-left.saltSidePanel-enterAnimation .saltSidePanel-inner,\n.saltSidePanel-left.saltSidePanel-exitAnimation .saltSidePanel-inner {\n right: 0;\n}\n\n.saltSidePanel-right.saltSidePanel-enterAnimation .saltSidePanel-inner,\n.saltSidePanel-right.saltSidePanel-exitAnimation .saltSidePanel-inner {\n left: 0;\n}\n\n.saltSidePanel-exitAnimation .saltSidePanel-inner {\n pointer-events: none;\n}\n\n.saltSidePanel-enterAnimation {\n animation: saltSidePanel-open var(--salt-duration-perceptible) var(--salt-animation-timing-function);\n}\n\n.saltSidePanel-exitAnimation {\n animation: saltSidePanel-close var(--salt-duration-perceptible) var(--salt-animation-timing-function) both;\n}\n\n@keyframes saltSidePanel-open {\n from {\n width: 0;\n }\n}\n\n@keyframes saltSidePanel-close {\n to {\n width: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .saltSidePanel-enterAnimation,\n .saltSidePanel-exitAnimation {\n animation: none;\n }\n}\n";
|
|
2
|
+
|
|
3
|
+
export { css_248z as default };
|
|
4
|
+
//# sourceMappingURL=SidePanel.css.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SidePanel.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
3
|
+
import { useWindow } from '@salt-ds/window';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { forwardRef, useMemo, useState, useRef, useEffect } from 'react';
|
|
6
|
+
import { tabbable } from 'tabbable';
|
|
7
|
+
import { makePrefixer } from '../utils/makePrefixer.js';
|
|
8
|
+
import { useEventCallback } from '../utils/useEventCallback.js';
|
|
9
|
+
import '../utils/useFloatingUI/useFloatingUI.js';
|
|
10
|
+
import { useForkRef } from '../utils/useForkRef.js';
|
|
11
|
+
import { useId } from '../utils/useId.js';
|
|
12
|
+
import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect.js';
|
|
13
|
+
import { usePrevious } from '../utils/usePrevious.js';
|
|
14
|
+
import '../salt-provider/SaltProvider.js';
|
|
15
|
+
import '../viewport/ViewportProvider.js';
|
|
16
|
+
import { useSidePanelContext, SidePanelContext } from './internal/SidePanelContext.js';
|
|
17
|
+
import css_248z from './SidePanel.css.js';
|
|
18
|
+
|
|
19
|
+
const withBaseName = makePrefixer("saltSidePanel");
|
|
20
|
+
const SidePanel = forwardRef(
|
|
21
|
+
function SidePanel2(props, ref) {
|
|
22
|
+
const {
|
|
23
|
+
disableAnimation = false,
|
|
24
|
+
position = "right",
|
|
25
|
+
initialFocus,
|
|
26
|
+
variant = "primary",
|
|
27
|
+
children,
|
|
28
|
+
id: idProp,
|
|
29
|
+
className,
|
|
30
|
+
"aria-labelledby": ariaLabelledBy,
|
|
31
|
+
onAnimationEnd,
|
|
32
|
+
...rest
|
|
33
|
+
} = props;
|
|
34
|
+
const sidePanelContext = useSidePanelContext();
|
|
35
|
+
const { openState, setFloating, setPanelId, titleId } = sidePanelContext;
|
|
36
|
+
const positionedContext = useMemo(
|
|
37
|
+
() => ({ ...sidePanelContext, position }),
|
|
38
|
+
[sidePanelContext, position]
|
|
39
|
+
);
|
|
40
|
+
const id = useId(idProp);
|
|
41
|
+
const [showComponent, setShowComponent] = useState(openState);
|
|
42
|
+
const [animating, setAnimating] = useState(false);
|
|
43
|
+
const shouldAnimateOpen = useRef(!openState);
|
|
44
|
+
const initialMountRef = useRef(true);
|
|
45
|
+
const panelRef = useRef(null);
|
|
46
|
+
const targetWindow = useWindow();
|
|
47
|
+
useComponentCssInjection({
|
|
48
|
+
testId: "salt-side-panel",
|
|
49
|
+
css: css_248z,
|
|
50
|
+
window: targetWindow
|
|
51
|
+
});
|
|
52
|
+
const initialFocusDoneRef = useRef(false);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!openState) {
|
|
55
|
+
initialFocusDoneRef.current = false;
|
|
56
|
+
}
|
|
57
|
+
}, [openState]);
|
|
58
|
+
const handleInitialFocus = useEventCallback((el) => {
|
|
59
|
+
var _a, _b;
|
|
60
|
+
if (!el || !openState || initialFocusDoneRef.current) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (initialMountRef.current) {
|
|
64
|
+
const reference2 = sidePanelContext.floatingRootContext.elements.reference;
|
|
65
|
+
const activeElement = reference2 instanceof Element ? (_a = reference2.ownerDocument) == null ? void 0 : _a.activeElement : null;
|
|
66
|
+
const focusCameFromTrigger = reference2 instanceof Element && activeElement instanceof Node && reference2.contains(activeElement);
|
|
67
|
+
if (!focusCameFromTrigger) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
initialMountRef.current = false;
|
|
71
|
+
}
|
|
72
|
+
initialFocusDoneRef.current = true;
|
|
73
|
+
const raf = ((_b = el.ownerDocument.defaultView) == null ? void 0 : _b.requestAnimationFrame) ?? (targetWindow == null ? void 0 : targetWindow.requestAnimationFrame) ?? requestAnimationFrame;
|
|
74
|
+
raf(() => {
|
|
75
|
+
if (!el.isConnected) return;
|
|
76
|
+
const focusTarget = resolveInitialFocusTarget(el, initialFocus);
|
|
77
|
+
focusTarget == null ? void 0 : focusTarget.focus();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
const setPanelEl = useEventCallback((el) => {
|
|
81
|
+
panelRef.current = el;
|
|
82
|
+
setFloating(el);
|
|
83
|
+
handleInitialFocus(el);
|
|
84
|
+
});
|
|
85
|
+
const handleRef = useForkRef(setPanelEl, ref);
|
|
86
|
+
useIsomorphicLayoutEffect(() => {
|
|
87
|
+
if (!animating || disableAnimation) return;
|
|
88
|
+
const panel = panelRef.current;
|
|
89
|
+
if (!panel) return;
|
|
90
|
+
const previousAnimation = panel.style.animation;
|
|
91
|
+
panel.style.animation = "none";
|
|
92
|
+
const widthPx = panel.getBoundingClientRect().width;
|
|
93
|
+
panel.style.animation = previousAnimation;
|
|
94
|
+
panel.style.setProperty(
|
|
95
|
+
"--saltSidePanel-animation-width",
|
|
96
|
+
`${widthPx}px`
|
|
97
|
+
);
|
|
98
|
+
return () => {
|
|
99
|
+
panel.style.removeProperty("--saltSidePanel-animation-width");
|
|
100
|
+
};
|
|
101
|
+
}, [animating, disableAnimation]);
|
|
102
|
+
const handleAnimationEnd = useEventCallback(
|
|
103
|
+
(event) => {
|
|
104
|
+
onAnimationEnd == null ? void 0 : onAnimationEnd(event);
|
|
105
|
+
if (event.currentTarget !== event.target || disableAnimation) return;
|
|
106
|
+
setAnimating(false);
|
|
107
|
+
if (!openState) {
|
|
108
|
+
setShowComponent(false);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
setPanelId(id);
|
|
114
|
+
return () => {
|
|
115
|
+
setPanelId(void 0);
|
|
116
|
+
};
|
|
117
|
+
}, [id, setPanelId]);
|
|
118
|
+
const reference = sidePanelContext.floatingRootContext.elements.reference;
|
|
119
|
+
const previousOpenState = usePrevious(openState, [openState], false);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (!previousOpenState || openState) return;
|
|
122
|
+
const panel = panelRef.current;
|
|
123
|
+
if (!(reference instanceof HTMLElement)) return;
|
|
124
|
+
const doc = reference.ownerDocument;
|
|
125
|
+
const active = doc == null ? void 0 : doc.activeElement;
|
|
126
|
+
const focusInsidePanel = panel && active instanceof Node && panel.contains(active);
|
|
127
|
+
const focusOnBody = active === (doc == null ? void 0 : doc.body) || active == null;
|
|
128
|
+
if (focusInsidePanel || focusOnBody) {
|
|
129
|
+
reference.focus();
|
|
130
|
+
}
|
|
131
|
+
}, [openState, previousOpenState, reference]);
|
|
132
|
+
useIsomorphicLayoutEffect(() => {
|
|
133
|
+
var _a, _b;
|
|
134
|
+
if (disableAnimation) {
|
|
135
|
+
setShowComponent(openState);
|
|
136
|
+
setAnimating(false);
|
|
137
|
+
if (!openState) shouldAnimateOpen.current = true;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (!openState) {
|
|
141
|
+
shouldAnimateOpen.current = true;
|
|
142
|
+
}
|
|
143
|
+
if (openState && !shouldAnimateOpen.current) {
|
|
144
|
+
setShowComponent(true);
|
|
145
|
+
setAnimating(false);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const prefersReducedMotion = (_b = (_a = targetWindow == null ? void 0 : targetWindow.matchMedia) == null ? void 0 : _a.call(
|
|
149
|
+
targetWindow,
|
|
150
|
+
"(prefers-reduced-motion: reduce)"
|
|
151
|
+
)) == null ? void 0 : _b.matches;
|
|
152
|
+
if (openState) {
|
|
153
|
+
setShowComponent(true);
|
|
154
|
+
}
|
|
155
|
+
if (prefersReducedMotion) {
|
|
156
|
+
setAnimating(false);
|
|
157
|
+
if (!openState) {
|
|
158
|
+
setShowComponent(false);
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
setAnimating(true);
|
|
162
|
+
}
|
|
163
|
+
}, [openState, targetWindow, disableAnimation]);
|
|
164
|
+
if (!showComponent) return null;
|
|
165
|
+
return /* @__PURE__ */ jsx(
|
|
166
|
+
"div",
|
|
167
|
+
{
|
|
168
|
+
role: "region",
|
|
169
|
+
"aria-labelledby": clsx(ariaLabelledBy, titleId) || void 0,
|
|
170
|
+
ref: handleRef,
|
|
171
|
+
className: clsx(
|
|
172
|
+
withBaseName(),
|
|
173
|
+
{
|
|
174
|
+
[withBaseName(position)]: position,
|
|
175
|
+
[withBaseName(variant)]: variant,
|
|
176
|
+
[withBaseName("enterAnimation")]: !disableAnimation && openState && animating,
|
|
177
|
+
[withBaseName("exitAnimation")]: !disableAnimation && !openState && animating
|
|
178
|
+
},
|
|
179
|
+
className
|
|
180
|
+
),
|
|
181
|
+
onAnimationEnd: handleAnimationEnd,
|
|
182
|
+
tabIndex: -1,
|
|
183
|
+
...rest,
|
|
184
|
+
id,
|
|
185
|
+
children: /* @__PURE__ */ jsx(SidePanelContext.Provider, { value: positionedContext, children: /* @__PURE__ */ jsx("div", { className: withBaseName("inner"), children }) })
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
function resolveInitialFocusTarget(panel, initialFocus) {
|
|
191
|
+
if (initialFocus && typeof initialFocus === "object") {
|
|
192
|
+
return initialFocus.current ?? null;
|
|
193
|
+
}
|
|
194
|
+
const managed = Array.from(
|
|
195
|
+
panel.querySelectorAll("[data-salt-original-tabindex]")
|
|
196
|
+
);
|
|
197
|
+
const candidates = managed.length ? managed : tabbable(panel, { displayCheck: "none" });
|
|
198
|
+
const index = typeof initialFocus === "number" ? initialFocus : 0;
|
|
199
|
+
return candidates[index] ?? candidates[0] ?? panel;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export { SidePanel };
|
|
203
|
+
//# sourceMappingURL=SidePanel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SidePanel.js","sources":["../src/side-panel/SidePanel.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type AnimationEvent,\n type ComponentPropsWithRef,\n forwardRef,\n type RefObject,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { tabbable } from \"tabbable\";\nimport {\n makePrefixer,\n useEventCallback,\n useForkRef,\n useId,\n useIsomorphicLayoutEffect,\n usePrevious,\n} from \"../utils\";\nimport { SidePanelContext, useSidePanelContext } from \"./internal\";\nimport sidePanelCss from \"./SidePanel.css\";\n\nconst withBaseName = makePrefixer(\"saltSidePanel\");\n\nexport interface SidePanelProps extends ComponentPropsWithRef<\"div\"> {\n /**\n * Disable the panel's own open/close animation.\n * Set to `true` when the parent controls sizing and animation (e.g. inside a splitter).\n * @default false\n */\n disableAnimation?: boolean;\n /**\n * Edge the panel is anchored to; controls animation direction and divider side.\n * @default \"right\"\n */\n position?: \"right\" | \"left\";\n /**\n * Which element receives focus when the panel opens.\n * Pass a number for the tabbable element index (0 = first), or a ref to a specific element.\n * Defaults to the first tabbable element inside the panel (close button if present).\n */\n initialFocus?: number | RefObject<HTMLElement | null>;\n /**\n * The background color palette. Options are 'primary', 'secondary', 'tertiary' and 'none'.\n * @default \"primary\"\n */\n variant?: \"primary\" | \"secondary\" | \"tertiary\" | \"none\";\n}\n\nexport const SidePanel = forwardRef<HTMLDivElement, SidePanelProps>(\n function SidePanel(props, ref) {\n const {\n disableAnimation = false,\n position = \"right\",\n initialFocus,\n variant = \"primary\",\n children,\n id: idProp,\n className,\n \"aria-labelledby\": ariaLabelledBy,\n onAnimationEnd,\n ...rest\n } = props;\n\n const sidePanelContext = useSidePanelContext();\n const { openState, setFloating, setPanelId, titleId } = sidePanelContext;\n const positionedContext = useMemo(\n () => ({ ...sidePanelContext, position }),\n [sidePanelContext, position],\n );\n\n const id = useId(idProp);\n\n const [showComponent, setShowComponent] = useState(openState);\n const [animating, setAnimating] = useState(false);\n const shouldAnimateOpen = useRef(!openState);\n // Stays true until a ref-callback invocation observes focus already\n // inside the trigger (a user-driven open). Flipping this from a mount\n // effect would break under React 18 strict-mode double-mounting.\n const initialMountRef = useRef(true);\n const panelRef = useRef<HTMLDivElement | null>(null);\n const targetWindow = useWindow();\n\n useComponentCssInjection({\n testId: \"salt-side-panel\",\n css: sidePanelCss,\n window: targetWindow,\n });\n\n // Guards against re-focusing the panel multiple times per open session.\n const initialFocusDoneRef = useRef(false);\n useEffect(() => {\n if (!openState) {\n initialFocusDoneRef.current = false;\n }\n }, [openState]);\n\n // useEventCallback keeps a stable identity while always reading the\n // latest closure, so React doesn't tear down and re-invoke the ref\n // callback per render.\n const handleInitialFocus = useEventCallback((el: HTMLDivElement | null) => {\n if (!el || !openState || initialFocusDoneRef.current) {\n return;\n }\n\n // On first mount, only auto-focus if focus is already in the trigger\n // (the common click path). For defaultOpen without user interaction\n // we leave focus alone.\n if (initialMountRef.current) {\n const reference =\n sidePanelContext.floatingRootContext.elements.reference;\n const activeElement =\n reference instanceof Element\n ? reference.ownerDocument?.activeElement\n : null;\n const focusCameFromTrigger =\n reference instanceof Element &&\n activeElement instanceof Node &&\n reference.contains(activeElement);\n if (!focusCameFromTrigger) {\n return;\n }\n initialMountRef.current = false;\n }\n\n initialFocusDoneRef.current = true;\n // Defer one frame so useSidePanelTabOrder has marked descendants\n // with data-salt-original-tabindex and any child layout effects\n // (e.g. SidePanelContent's scrollable-body tabIndex toggle) have\n // settled. Scoped to the panel's owner window for iframe/shadow-root\n // hosts.\n const raf =\n el.ownerDocument.defaultView?.requestAnimationFrame ??\n targetWindow?.requestAnimationFrame ??\n requestAnimationFrame;\n raf(() => {\n if (!el.isConnected) return;\n const focusTarget = resolveInitialFocusTarget(el, initialFocus);\n focusTarget?.focus();\n });\n });\n\n const setPanelEl = useEventCallback((el: HTMLDivElement | null) => {\n panelRef.current = el;\n setFloating(el);\n handleInitialFocus(el);\n });\n\n const handleRef = useForkRef<HTMLDivElement>(setPanelEl, ref);\n\n // Snapshot the panel's natural width (in px) into a CSS variable so the\n // inner can keep its full size while the outer animates between 0 and\n // its target width. This makes percentage values for\n // --saltSidePanel-width work, since the inner no longer resolves a\n // percentage against the outer's animating width.\n useIsomorphicLayoutEffect(() => {\n if (!animating || disableAnimation) return;\n const panel = panelRef.current;\n if (!panel) return;\n\n // Read the natural width with the animation suspended so we see the\n // resting size rather than the in-flight interpolated value.\n // getBoundingClientRect() flushes style/layout, so the inline\n // `animation: none` takes effect for this read.\n const previousAnimation = panel.style.animation;\n panel.style.animation = \"none\";\n const widthPx = panel.getBoundingClientRect().width;\n panel.style.animation = previousAnimation;\n\n panel.style.setProperty(\n \"--saltSidePanel-animation-width\",\n `${widthPx}px`,\n );\n\n return () => {\n panel.style.removeProperty(\"--saltSidePanel-animation-width\");\n };\n }, [animating, disableAnimation]);\n\n const handleAnimationEnd = useEventCallback(\n (event: AnimationEvent<HTMLDivElement>) => {\n onAnimationEnd?.(event);\n\n if (event.currentTarget !== event.target || disableAnimation) return;\n setAnimating(false);\n if (!openState) {\n setShowComponent(false);\n }\n },\n );\n\n useEffect(() => {\n setPanelId(id);\n return () => {\n setPanelId(undefined);\n };\n }, [id, setPanelId]);\n\n // Return focus to the trigger on close (mirrors floating-ui's\n // returnFocus). Initial previousOpenState of `false` ensures we never\n // restore on mount — only on a real true→false transition.\n const reference = sidePanelContext.floatingRootContext.elements.reference;\n const previousOpenState = usePrevious(openState, [openState], false);\n useEffect(() => {\n if (!previousOpenState || openState) return;\n const panel = panelRef.current;\n if (!(reference instanceof HTMLElement)) return;\n const doc = reference.ownerDocument;\n const active = doc?.activeElement;\n const focusInsidePanel =\n panel && active instanceof Node && panel.contains(active);\n const focusOnBody = active === doc?.body || active == null;\n if (focusInsidePanel || focusOnBody) {\n reference.focus();\n }\n }, [openState, previousOpenState, reference]);\n\n useIsomorphicLayoutEffect(() => {\n if (disableAnimation) {\n setShowComponent(openState);\n setAnimating(false);\n if (!openState) shouldAnimateOpen.current = true;\n return;\n }\n\n if (!openState) {\n shouldAnimateOpen.current = true;\n }\n\n // Skip enter animation when the panel was open from the start.\n if (openState && !shouldAnimateOpen.current) {\n setShowComponent(true);\n setAnimating(false);\n return;\n }\n\n const prefersReducedMotion = targetWindow?.matchMedia?.(\n \"(prefers-reduced-motion: reduce)\",\n )?.matches;\n\n if (openState) {\n setShowComponent(true);\n }\n\n if (prefersReducedMotion) {\n setAnimating(false);\n if (!openState) {\n setShowComponent(false);\n }\n } else {\n setAnimating(true);\n }\n }, [openState, targetWindow, disableAnimation]);\n\n if (!showComponent) return null;\n\n return (\n <div\n role=\"region\"\n aria-labelledby={clsx(ariaLabelledBy, titleId) || undefined}\n ref={handleRef}\n className={clsx(\n withBaseName(),\n {\n [withBaseName(position)]: position,\n [withBaseName(variant)]: variant,\n [withBaseName(\"enterAnimation\")]:\n !disableAnimation && openState && animating,\n [withBaseName(\"exitAnimation\")]:\n !disableAnimation && !openState && animating,\n },\n className,\n )}\n onAnimationEnd={handleAnimationEnd}\n tabIndex={-1}\n {...rest}\n id={id}\n >\n <SidePanelContext.Provider value={positionedContext}>\n <div className={withBaseName(\"inner\")}>{children}</div>\n </SidePanelContext.Provider>\n </div>\n );\n },\n);\n\nfunction resolveInitialFocusTarget(\n panel: HTMLElement,\n initialFocus: SidePanelProps[\"initialFocus\"],\n): HTMLElement | null {\n if (initialFocus && typeof initialFocus === \"object\") {\n return initialFocus.current ?? null;\n }\n\n // Prefer the panel's \"managed\" sequence (elements detached from the\n // natural tab order by useSidePanelTabOrder), falling back to a fresh\n // tabbable() scan when detachment hasn't run yet.\n const managed = Array.from(\n panel.querySelectorAll<HTMLElement>(\"[data-salt-original-tabindex]\"),\n );\n\n const candidates = managed.length\n ? managed\n : (tabbable(panel, { displayCheck: \"none\" }) as HTMLElement[]);\n\n const index = typeof initialFocus === \"number\" ? initialFocus : 0;\n return candidates[index] ?? candidates[0] ?? panel;\n}\n"],"names":["SidePanel","sidePanelCss","reference"],"mappings":"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"}
|