reshaped 3.5.1-canary.1 → 3.5.2
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-old.md +14 -0
- package/CHANGELOG.md +23 -3
- package/dist/bundle.css +1 -1
- package/dist/bundle.js +10 -10
- package/dist/components/Autocomplete/tests/Autocomplete.stories.js +1 -0
- package/dist/components/Card/Card.js +2 -2
- package/dist/components/Card/Card.module.css +1 -1
- package/dist/components/Checkbox/Checkbox.module.css +1 -1
- package/dist/components/Radio/Radio.module.css +1 -1
- package/dist/components/ScrollArea/ScrollArea.js +3 -6
- package/dist/components/ScrollArea/tests/ScrollArea.stories.d.ts +13 -4
- package/dist/components/ScrollArea/tests/ScrollArea.stories.js +129 -30
- package/dist/components/Slider/Slider.types.d.ts +1 -1
- package/dist/components/Slider/SliderControlled.js +4 -2
- package/dist/components/Slider/tests/Slider.stories.d.ts +1 -0
- package/dist/components/Slider/tests/Slider.stories.js +8 -0
- package/dist/utilities/a11y/focus.d.ts +3 -6
- package/dist/utilities/a11y/focus.js +11 -8
- package/dist/utilities/a11y/types.d.ts +4 -0
- package/package.json +8 -9
- package/dist/components/ScrollArea/tests/ScrollArea.test.stories.d.ts +0 -23
- package/dist/components/ScrollArea/tests/ScrollArea.test.stories.js +0 -66
@@ -56,6 +56,7 @@ export const active = {
|
|
56
56
|
expect(args.handleClose).toHaveBeenCalledTimes(1);
|
57
57
|
expect(args.handleClose).toHaveBeenLastCalledWith();
|
58
58
|
});
|
59
|
+
await sleep(500);
|
59
60
|
await userEvent.click(input);
|
60
61
|
await waitFor(() => {
|
61
62
|
expect(args.handleOpen).toHaveBeenCalledTimes(1);
|
@@ -28,9 +28,9 @@ const Card = forwardRef((props, ref) => {
|
|
28
28
|
if (isActionable) {
|
29
29
|
return (_jsx(Actionable, { className: rootClassNames, attributes: { ...attributes, style }, href: href, as: TagName, onClick: onClick,
|
30
30
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
31
|
-
ref: ref, children:
|
31
|
+
ref: ref, children: children }));
|
32
32
|
}
|
33
|
-
return (_jsx(TagName, { ...attributes, onClick: onClick, href: href, ref: ref, className: rootClassNames, style: style, children:
|
33
|
+
return (_jsx(TagName, { ...attributes, onClick: onClick, href: href, ref: ref, className: rootClassNames, style: style, children: children }));
|
34
34
|
});
|
35
35
|
Card.displayName = "Card";
|
36
36
|
export default Card;
|
@@ -1 +1 @@
|
|
1
|
-
.root{--rs-border-width:1px;background:var(--rs-color-background-elevation-base);border:var(--rs-border-width) solid var(--rs-color-border-neutral-faded);color:var(--rs-color-foreground-neutral);display:block;overflow:hidden;text-align:initial;transition:var(--rs-duration-fast) var(--rs-easing-accelerate);transition-property:box-shadow,border-color}
|
1
|
+
.root{--rs-border-width:1px;background:var(--rs-color-background-elevation-base);border:var(--rs-border-width) solid var(--rs-color-border-neutral-faded);color:var(--rs-color-foreground-neutral);display:block;overflow:hidden;position:relative;text-align:initial;transition:var(--rs-duration-fast) var(--rs-easing-accelerate);transition-property:box-shadow,border-color}.--selected{border-color:transparent;box-shadow:0 0 0 2px var(--rs-color-border-primary);transition-timing-function:var(--rs-easing-decelerate)}.--elevated{background:var(--rs-color-background-elevation-raised);box-shadow:var(--rs-shadow-raised)}.--actionable:not(.--selected){color:inherit;cursor:pointer;outline:none;text-decoration:none}[data-rs-keyboard] .--actionable:not(.--selected):focus{box-shadow:var(--rs-focus-shadow)}.--actionable:not(.--selected):before{background:rgba(var(--rs-color-rgb-background-neutral-faded),32%);content:"";inset:0;opacity:0;pointer-events:none;position:absolute;transition:opacity var(--rs-duration-fast) var(--rs-easing-standard)}.--actionable:not(.--selected):hover:before{opacity:1}
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
.root{align-items:center;cursor:pointer;display:inline-flex;gap:var(--rs-checkbox-gap);user-select:none;vertical-align:top;-webkit-tap-highlight-color:transparent}.root:hover .decorator{background:var(--rs-color-background-neutral-faded)}.field{position:relative}.decorator{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:var(--rs-radius-small);color:var(--rs-color-on-background-primary);height:var(--rs-checkbox-line-height);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,border-color;width:var(--rs-checkbox-line-height)}.decorator:before{background:var(--rs-color-on-background-primary);border-radius:999px;content:"";height:1.5px;left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:opacity,transform;width:calc(var(--rs-checkbox-line-height) * .5)}.--size-small{--rs-checkbox-line-height:var(--rs-line-height-caption-1);--rs-checkbox-gap:var(--rs-unit-x1)}.--size-medium{--rs-checkbox-line-height:var(--rs-line-height-body-3);--rs-checkbox-gap:var(--rs-unit-x2)}.--size-large{--rs-checkbox-line-height:var(--rs-line-height-body-2);--rs-checkbox-gap:var(--rs-unit-x2)}.icon{left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:opacity,transform}[data-rs-keyboard] .input:focus-visible+.decorator{box-shadow:var(--rs-focus-shadow)}.root.--error .decorator{border-color:var(--rs-color-border-critical)}.input:checked+.decorator,.input:indeterminate+.decorator{background:var(--rs-color-background-primary);border-color:var(--rs-color-background-primary)}.input:checked+.decorator .icon,.input:indeterminate+.decorator:before{opacity:1;transform:translate(-50%,-50%) scale(1)}.root.--disabled{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.root.--disabled .decorator{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled);color:var(--rs-color-foreground-disabled)}.root.--disabled .input:checked+.decorator,.root.--disabled .input:indeterminate+.decorator{background:var(--rs-color-background-disabled);border-color:transparent}.root.--disabled .input:checked+.decorator:before,.root.--disabled .input:indeterminate+.decorator:before{background-color:var(--rs-color-foreground-disabled)}@media (--rs-viewport-m ){.--size-small--m{--rs-checkbox-line-height:var(--rs-line-height-caption-1);--rs-checkbox-gap:var(--rs-unit-x1)}.--size-medium--m{--rs-checkbox-line-height:var(--rs-line-height-body-3);--rs-checkbox-gap:var(--rs-unit-x2)}.--size-large--m{--rs-checkbox-line-height:var(--rs-line-height-body-2);--rs-checkbox-gap:var(--rs-unit-x2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-checkbox-line-height:var(--rs-line-height-caption-1);--rs-checkbox-gap:var(--rs-unit-x1)}.--size-medium--l{--rs-checkbox-line-height:var(--rs-line-height-body-3);--rs-checkbox-gap:var(--rs-unit-x2)}.--size-large--l{--rs-checkbox-line-height:var(--rs-line-height-body-2);--rs-checkbox-gap:var(--rs-unit-x2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-checkbox-line-height:var(--rs-line-height-caption-1);--rs-checkbox-gap:var(--rs-unit-x1)}.--size-medium--xl{--rs-checkbox-line-height:var(--rs-line-height-body-3);--rs-checkbox-gap:var(--rs-unit-x2)}.--size-large--xl{--rs-checkbox-line-height:var(--rs-line-height-body-2);--rs-checkbox-gap:var(--rs-unit-x2)}}
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
.root{align-items:center;cursor:pointer;display:inline-flex;gap:var(--rs-radio-gap);user-select:none;vertical-align:top;-webkit-tap-highlight-color:transparent}.root:hover .decorator{background:var(--rs-color-background-neutral-faded)}.field{position:relative}.decorator{background:var(--rs-color-background-elevation-base);border:1px solid var(--rs-color-border-neutral);border-radius:50%;height:var(--rs-radio-line-height);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:background-color,border-color;width:var(--rs-radio-line-height)}.decorator:after{background:var(--rs-color-on-background-primary);border-radius:50%;content:"";height:calc(var(--rs-radio-line-height) * .4);left:50%;opacity:0;position:absolute;top:50%;transform:translate(-50%,-50%) scale(0);transition:var(--rs-duration-fast) var(--rs-easing-standard);transition-property:opacity,transform;width:calc(var(--rs-radio-line-height) * .4)}.--size-small{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}[data-rs-keyboard] .input:focus+.decorator{box-shadow:var(--rs-focus-shadow)}.root.--error .decorator{border-color:var(--rs-color-border-critical)}.input:checked+.decorator{background:var(--rs-color-background-primary);border-color:var(--rs-color-background-primary)}.input:checked+.decorator:after{opacity:1;transform:translate(-50%,-50%) scale(1)}.root.--disabled{color:var(--rs-color-foreground-disabled);cursor:not-allowed}.root.--disabled .decorator{background:var(--rs-color-background-disabled-faded);border-color:var(--rs-color-border-disabled)}.root.--disabled .decorator:after{background-color:var(--rs-color-foreground-disabled)}.root.--disabled .input:checked+.decorator{background:var(--rs-color-background-disabled);border-color:transparent}@media (--rs-viewport-m ){.--size-small--m{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--m{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--m{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-l ){.--size-small--l{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--l{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--l{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}@media (--rs-viewport-xl ){.--size-small--xl{--rs-radio-line-height:var(--rs-line-height-caption-1);--rs-radio-gap:var(--rs-unit-x1)}.--size-medium--xl{--rs-radio-line-height:var(--rs-line-height-body-3);--rs-radio-gap:var(--rs-unit-x2)}.--size-large--xl{--rs-radio-line-height:var(--rs-line-height-body-2);--rs-radio-gap:var(--rs-unit-x2)}}
|
@@ -73,11 +73,8 @@ const ScrollArea = forwardRef((props, ref) => {
|
|
73
73
|
const contentRef = React.useRef(null);
|
74
74
|
const heightStyles = getHeightStyles(height);
|
75
75
|
const maxHeightStyles = getMaxHeightStyles(maxHeight);
|
76
|
-
const rootClassNames = classNames(s.root, scrollbarDisplay && s[`--display-${scrollbarDisplay}`], heightStyles?.classNames,
|
77
|
-
const
|
78
|
-
...heightStyles?.variables,
|
79
|
-
...maxHeightStyles?.variables,
|
80
|
-
};
|
76
|
+
const rootClassNames = classNames(s.root, scrollbarDisplay && s[`--display-${scrollbarDisplay}`], heightStyles?.classNames, className);
|
77
|
+
const contentClassNames = classNames(s.content, maxHeightStyles?.classNames);
|
81
78
|
const updateScroll = React.useCallback(() => {
|
82
79
|
const scrollableEl = scrollableRef.current;
|
83
80
|
if (!scrollableEl)
|
@@ -134,7 +131,7 @@ const ScrollArea = forwardRef((props, ref) => {
|
|
134
131
|
observer.observe(contentEl);
|
135
132
|
return () => observer.disconnect();
|
136
133
|
}, [updateScroll]);
|
137
|
-
return (_jsxs("div", { ...attributes, className: rootClassNames, style:
|
134
|
+
return (_jsxs("div", { ...attributes, className: rootClassNames, style: { ...heightStyles?.variables }, children: [_jsx("div", { className: s.scrollable, ref: scrollableRef, onScroll: handleScroll, tabIndex: 0, children: _jsx("div", { className: contentClassNames, ref: contentRef, style: { ...maxHeightStyles?.variables }, children: children }) }), scrollRatio.y < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { vertical: true, onThumbMove: handleThumbYMove, ratio: scrollRatio.y, position: scrollPosition.y })), scrollRatio.x < 1 && scrollbarDisplay !== "hidden" && (_jsx(ScrollAreaBar, { onThumbMove: handleThumbXMove, ratio: scrollRatio.x, position: scrollPosition.x }))] }));
|
138
135
|
});
|
139
136
|
ScrollArea.displayName = "ScrollArea";
|
140
137
|
export default ScrollArea;
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import React from "react";
|
2
2
|
import { StoryObj } from "@storybook/react";
|
3
|
+
import { Mock } from "@storybook/test";
|
3
4
|
declare const _default: {
|
4
5
|
title: string;
|
5
6
|
component: React.ForwardRefExoticComponent<import("./..").ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
|
@@ -13,16 +14,24 @@ declare const _default: {
|
|
13
14
|
};
|
14
15
|
};
|
15
16
|
export default _default;
|
16
|
-
export declare const
|
17
|
+
export declare const base: {
|
17
18
|
name: string;
|
18
19
|
render: () => React.JSX.Element;
|
19
20
|
};
|
20
|
-
export declare const
|
21
|
+
export declare const scrollbarDisplay: {
|
21
22
|
name: string;
|
22
23
|
render: () => React.JSX.Element;
|
23
24
|
};
|
24
|
-
export declare const
|
25
|
+
export declare const height: {
|
25
26
|
name: string;
|
26
27
|
render: () => React.JSX.Element;
|
27
28
|
};
|
28
|
-
export declare const
|
29
|
+
export declare const onScroll: StoryObj<{
|
30
|
+
handleScroll: Mock;
|
31
|
+
}>;
|
32
|
+
export declare const className: StoryObj;
|
33
|
+
export declare const testNested: {
|
34
|
+
name: string;
|
35
|
+
render: () => React.JSX.Element;
|
36
|
+
};
|
37
|
+
export declare const testDynamicHeight: StoryObj;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import React from "react";
|
2
|
+
import { userEvent, expect, waitFor, fn } from "@storybook/test";
|
2
3
|
import { Example } from "../../../utilities/storybook/index.js";
|
3
4
|
import ScrollArea from "../index.js";
|
4
5
|
import View from "../../View/index.js";
|
@@ -16,10 +17,10 @@ export default {
|
|
16
17
|
},
|
17
18
|
},
|
18
19
|
};
|
19
|
-
export const
|
20
|
-
name: "
|
20
|
+
export const base = {
|
21
|
+
name: "base",
|
21
22
|
render: () => (<Example>
|
22
|
-
<Example.Item title="vertical">
|
23
|
+
<Example.Item title="vertical scroll">
|
23
24
|
<ScrollArea height="100px" scrollbarDisplay="visible">
|
24
25
|
<View backgroundColor="elevation-base" padding={4}>
|
25
26
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
@@ -33,7 +34,7 @@ export const direction = {
|
|
33
34
|
</ScrollArea>
|
34
35
|
</Example.Item>
|
35
36
|
|
36
|
-
<Example.Item title="horizontal">
|
37
|
+
<Example.Item title="horizontal scroll">
|
37
38
|
<ScrollArea height="100px" scrollbarDisplay="visible">
|
38
39
|
<View backgroundColor="elevation-base" padding={4} width="150%" height="100px">
|
39
40
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
@@ -42,7 +43,7 @@ export const direction = {
|
|
42
43
|
</ScrollArea>
|
43
44
|
</Example.Item>
|
44
45
|
|
45
|
-
<Example.Item title="horizontal
|
46
|
+
<Example.Item title="horizontal and vertical scroll">
|
46
47
|
<ScrollArea height="100px" scrollbarDisplay="visible">
|
47
48
|
<View backgroundColor="elevation-base" padding={4} width="150%">
|
48
49
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
@@ -57,12 +58,12 @@ export const direction = {
|
|
57
58
|
</Example.Item>
|
58
59
|
</Example>),
|
59
60
|
};
|
60
|
-
export const
|
61
|
+
export const scrollbarDisplay = {
|
61
62
|
name: "scrollbarDisplay",
|
62
63
|
render: () => (<Example>
|
63
|
-
<Example.Item title="
|
64
|
+
<Example.Item title="scrollbarDisplay: hover">
|
64
65
|
<ScrollArea height="100px">
|
65
|
-
<View backgroundColor="elevation-base" padding={4}>
|
66
|
+
<View backgroundColor="elevation-base" padding={4} width="150%">
|
66
67
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
67
68
|
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
68
69
|
printer took a galley of type and scrambled it to make a type specimen book. It has
|
@@ -74,9 +75,9 @@ export const visibility = {
|
|
74
75
|
</ScrollArea>
|
75
76
|
</Example.Item>
|
76
77
|
|
77
|
-
<Example.Item title="
|
78
|
+
<Example.Item title="scrollbarDisplay: hidden">
|
78
79
|
<ScrollArea height="100px" scrollbarDisplay="hidden">
|
79
|
-
<View backgroundColor="elevation-base" padding={4}>
|
80
|
+
<View backgroundColor="elevation-base" padding={4} width="150%">
|
80
81
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
81
82
|
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
82
83
|
printer took a galley of type and scrambled it to make a type specimen book. It has
|
@@ -88,9 +89,9 @@ export const visibility = {
|
|
88
89
|
</ScrollArea>
|
89
90
|
</Example.Item>
|
90
91
|
|
91
|
-
<Example.Item title="
|
92
|
+
<Example.Item title="scrollbarDisplay: visible">
|
92
93
|
<ScrollArea height="100px" scrollbarDisplay="visible">
|
93
|
-
<View backgroundColor="elevation-base" padding={4}>
|
94
|
+
<View backgroundColor="elevation-base" padding={4} width="150%">
|
94
95
|
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
95
96
|
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
96
97
|
printer took a galley of type and scrambled it to make a type specimen book. It has
|
@@ -103,26 +104,129 @@ export const visibility = {
|
|
103
104
|
</Example.Item>
|
104
105
|
</Example>),
|
105
106
|
};
|
106
|
-
export const
|
107
|
-
name: "
|
107
|
+
export const height = {
|
108
|
+
name: "height, maxHeight",
|
108
109
|
render: () => (<Example>
|
109
|
-
<Example.Item title="
|
110
|
-
<ScrollArea height="
|
111
|
-
<View padding={4}
|
112
|
-
|
113
|
-
|
110
|
+
<Example.Item title="height: 80px">
|
111
|
+
<ScrollArea height="80px">
|
112
|
+
<View backgroundColor="elevation-base" padding={4}>
|
113
|
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
114
|
+
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
115
|
+
printer took a galley of type and scrambled it to make a type specimen book. It has
|
116
|
+
survived not only five centuries, but also the leap into electronic typesetting,
|
117
|
+
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
118
|
+
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
119
|
+
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
120
|
+
</View>
|
121
|
+
</ScrollArea>
|
122
|
+
</Example.Item>
|
123
|
+
|
124
|
+
<Example.Item title="responsive height: s 80px, m: 120px">
|
125
|
+
<ScrollArea height={{ s: "80px", m: "120px" }}>
|
126
|
+
<View backgroundColor="elevation-base" padding={4}>
|
127
|
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
128
|
+
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
129
|
+
printer took a galley of type and scrambled it to make a type specimen book. It has
|
130
|
+
survived not only five centuries, but also the leap into electronic typesetting,
|
131
|
+
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
132
|
+
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
133
|
+
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
134
|
+
</View>
|
135
|
+
</ScrollArea>
|
136
|
+
</Example.Item>
|
137
|
+
|
138
|
+
<Example.Item title="maxHeight: 80px">
|
139
|
+
<ScrollArea maxHeight="80px">
|
140
|
+
<View backgroundColor="elevation-base" padding={4}>
|
141
|
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
142
|
+
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
143
|
+
printer took a galley of type and scrambled it to make a type specimen book. It has
|
144
|
+
survived not only five centuries, but also the leap into electronic typesetting,
|
145
|
+
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
146
|
+
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
147
|
+
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
148
|
+
</View>
|
149
|
+
</ScrollArea>
|
150
|
+
</Example.Item>
|
151
|
+
|
152
|
+
<Example.Item title="responsive max height: s 80px, m: 200px">
|
153
|
+
<ScrollArea maxHeight={{ s: "80px", m: "200px" }}>
|
154
|
+
<View backgroundColor="elevation-base" padding={4}>
|
155
|
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
156
|
+
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
157
|
+
printer took a galley of type and scrambled it to make a type specimen book. It has
|
158
|
+
survived not only five centuries, but also the leap into electronic typesetting,
|
159
|
+
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
160
|
+
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
161
|
+
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
162
|
+
</View>
|
163
|
+
</ScrollArea>
|
164
|
+
</Example.Item>
|
165
|
+
</Example>),
|
166
|
+
};
|
167
|
+
export const onScroll = {
|
168
|
+
name: "ref, onScroll",
|
169
|
+
args: {
|
170
|
+
handleScroll: fn(),
|
171
|
+
},
|
172
|
+
render: (args) => {
|
173
|
+
const ref = React.useRef(null);
|
174
|
+
return (<View gap={4}>
|
175
|
+
<View.Item>
|
176
|
+
<Button onClick={() => ref.current?.scrollBy({ top: 50, left: 50 })}>Scroll</Button>
|
177
|
+
</View.Item>
|
178
|
+
<ScrollArea height="100px" ref={ref} scrollbarDisplay="visible" onScroll={args.handleScroll}>
|
179
|
+
<View backgroundColor="neutral-faded" padding={4} width="1000px" height="200px">
|
180
|
+
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
181
|
+
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
182
|
+
printer took a galley of type and scrambled it to make a type specimen book. It has
|
183
|
+
survived not only five centuries, but also the leap into electronic typesetting,
|
184
|
+
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
185
|
+
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
186
|
+
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
187
|
+
</View>
|
188
|
+
</ScrollArea>
|
189
|
+
</View>);
|
190
|
+
},
|
191
|
+
play: async ({ canvas, args }) => {
|
192
|
+
const trigger = canvas.getAllByRole("button")[0];
|
193
|
+
await userEvent.click(trigger);
|
194
|
+
await waitFor(() => {
|
195
|
+
expect(args.handleScroll).toHaveBeenCalledTimes(1);
|
196
|
+
// x value is flaky, so only testing y here
|
197
|
+
expect(args.handleScroll).toHaveBeenCalledWith(expect.objectContaining({ y: 0.5 }));
|
198
|
+
});
|
199
|
+
},
|
200
|
+
};
|
201
|
+
export const className = {
|
202
|
+
name: "className, attributes",
|
203
|
+
render: () => (<div data-testid="root">
|
204
|
+
<ScrollArea className="test-classname" attributes={{ id: "test-id" }}>
|
205
|
+
Content
|
206
|
+
</ScrollArea>
|
207
|
+
</div>),
|
208
|
+
play: async ({ canvas }) => {
|
209
|
+
const root = canvas.getByTestId("root").firstChild;
|
210
|
+
expect(root).toHaveClass("test-classname");
|
211
|
+
expect(root).toHaveAttribute("id", "test-id");
|
212
|
+
},
|
213
|
+
};
|
214
|
+
export const testNested = {
|
215
|
+
name: "test: nested",
|
216
|
+
render: () => (<ScrollArea height="100px" scrollbarDisplay="visible">
|
217
|
+
<View padding={4} paddingInline={16}>
|
218
|
+
<ScrollArea height="200px" scrollbarDisplay="visible">
|
219
|
+
{Array(20)
|
114
220
|
.fill("")
|
115
221
|
.map((_, index) => {
|
116
222
|
return <div key={index}>Item {index + 1}</div>;
|
117
223
|
})}
|
118
|
-
</ScrollArea>
|
119
|
-
</View>
|
120
224
|
</ScrollArea>
|
121
|
-
</
|
122
|
-
</
|
225
|
+
</View>
|
226
|
+
</ScrollArea>),
|
123
227
|
};
|
124
|
-
export const
|
125
|
-
name: "
|
228
|
+
export const testDynamicHeight = {
|
229
|
+
name: "test: dynamic height change",
|
126
230
|
render: () => {
|
127
231
|
const [count, setCount] = React.useState(10);
|
128
232
|
return (<View gap={4}>
|
@@ -137,9 +241,4 @@ export const dynamicHeight = {
|
|
137
241
|
</ScrollArea>
|
138
242
|
</View>);
|
139
243
|
},
|
140
|
-
// TODO: After Using play(), Storybook makes the scroll lag, but not when triggered manually in the browser
|
141
|
-
// play: async ({ canvas }) => {
|
142
|
-
// const trigger = canvas.getAllByRole("button")[0];
|
143
|
-
// await userEvent.click(trigger);
|
144
|
-
// },
|
145
244
|
};
|
@@ -71,7 +71,7 @@ export type ThumbProps = {
|
|
71
71
|
onChange: (value: number, options?: {
|
72
72
|
commit?: boolean;
|
73
73
|
}) => void;
|
74
|
-
onDragStart: () => void;
|
74
|
+
onDragStart: (e: React.TouchEvent | React.MouseEvent) => void;
|
75
75
|
max: number;
|
76
76
|
min: number;
|
77
77
|
step: NonNullable<BaseProps["step"]>;
|
@@ -136,14 +136,16 @@ const SliderControlled = (props) => {
|
|
136
136
|
disableScroll();
|
137
137
|
setDraggingId(closestId);
|
138
138
|
};
|
139
|
-
const handleMinDragStart = () => {
|
139
|
+
const handleMinDragStart = (e) => {
|
140
140
|
if (disabled)
|
141
141
|
return;
|
142
|
+
e.stopPropagation();
|
142
143
|
setDraggingId(minId);
|
143
144
|
};
|
144
|
-
const handleMaxDragStart = () => {
|
145
|
+
const handleMaxDragStart = (e) => {
|
145
146
|
if (disabled)
|
146
147
|
return;
|
148
|
+
e.stopPropagation();
|
147
149
|
setDraggingId(maxId);
|
148
150
|
};
|
149
151
|
const handleDragStop = React.useCallback(() => {
|
@@ -14,3 +14,4 @@ export declare const step: () => import("react").JSX.Element;
|
|
14
14
|
export declare const boundaries: () => import("react").JSX.Element;
|
15
15
|
export declare const status: () => import("react").JSX.Element;
|
16
16
|
export declare const customRender: () => import("react").JSX.Element;
|
17
|
+
export declare const testModal: () => import("react").JSX.Element;
|
@@ -2,6 +2,8 @@ import { Example } from "../../../utilities/storybook/index.js";
|
|
2
2
|
import Slider from "../index.js";
|
3
3
|
import View from "../../View/index.js";
|
4
4
|
import FormControl from "../../FormControl/index.js";
|
5
|
+
import Modal from "../../Modal/index.js";
|
6
|
+
import useToggle from "../../../hooks/useToggle.js";
|
5
7
|
export default {
|
6
8
|
title: "Components/Slider",
|
7
9
|
component: Slider,
|
@@ -61,3 +63,9 @@ export const customRender = () => (<Example>
|
|
61
63
|
</FormControl>
|
62
64
|
</Example.Item>
|
63
65
|
</Example>);
|
66
|
+
export const testModal = () => {
|
67
|
+
const toggle = useToggle(true);
|
68
|
+
return (<Modal active={toggle.active} onClose={toggle.deactivate} position="end">
|
69
|
+
<Slider name="slider" defaultValue={30} renderValue={false}/>
|
70
|
+
</Modal>);
|
71
|
+
};
|
@@ -1,18 +1,15 @@
|
|
1
|
-
import type { FocusableElement } from "./types";
|
1
|
+
import type { FocusableElement, FocusableOptions } from "./types";
|
2
2
|
export declare const focusableSelector = "a,button,input:not([type=\"hidden\"]),textarea,select,details,[tabindex],[contenteditable]";
|
3
3
|
export declare const getActiveElement: (originEl?: HTMLElement | null) => HTMLButtonElement;
|
4
4
|
export declare const focusElement: (el: FocusableElement, options?: {
|
5
5
|
pseudoFocus?: boolean;
|
6
6
|
}) => void;
|
7
|
-
export declare const getFocusableElements: (rootEl: HTMLElement, options?:
|
8
|
-
additionalElement?: FocusableElement | null;
|
9
|
-
}) => FocusableElement[];
|
7
|
+
export declare const getFocusableElements: (rootEl: HTMLElement, options?: FocusableOptions) => FocusableElement[];
|
10
8
|
export declare const getFocusData: (args: {
|
11
9
|
root: HTMLElement;
|
12
10
|
target: "next" | "prev" | "first" | "last";
|
13
|
-
options?: {
|
11
|
+
options?: FocusableOptions & {
|
14
12
|
circular?: boolean;
|
15
|
-
additionalElement?: FocusableElement | null;
|
16
13
|
};
|
17
14
|
}) => {
|
18
15
|
overflow: boolean;
|
@@ -26,7 +26,7 @@ export const getFocusableElements = (rootEl, options) => {
|
|
26
26
|
if (el.clientHeight === 0)
|
27
27
|
return false;
|
28
28
|
// Using getAttribute here since browser sets el.tabIndex to -1 by default
|
29
|
-
if (el.getAttribute("tabindex") === "-1")
|
29
|
+
if (!options?.includeNegativeTabIndex && el.getAttribute("tabindex") === "-1")
|
30
30
|
return false;
|
31
31
|
if (el.type === "radio") {
|
32
32
|
let sameNameRadioEls;
|
@@ -65,7 +65,10 @@ export const getFocusableElements = (rootEl, options) => {
|
|
65
65
|
};
|
66
66
|
export const getFocusData = (args) => {
|
67
67
|
const { root, target, options } = args;
|
68
|
-
const focusable = getFocusableElements(root, {
|
68
|
+
const focusable = getFocusableElements(root, {
|
69
|
+
additionalElement: options?.additionalElement,
|
70
|
+
includeNegativeTabIndex: options?.includeNegativeTabIndex,
|
71
|
+
});
|
69
72
|
const focusableLimit = focusable.length - 1;
|
70
73
|
const currentElement = getActiveElement(root);
|
71
74
|
const currentIndex = focusable.indexOf(currentElement);
|
@@ -87,11 +90,11 @@ export const getFocusData = (args) => {
|
|
87
90
|
}
|
88
91
|
return { overflow: isOverflow, el: focusable[nextIndex] };
|
89
92
|
};
|
90
|
-
const focusTargetElement = (root, target) => {
|
91
|
-
const data = getFocusData({ root, target });
|
93
|
+
const focusTargetElement = (root, target, options) => {
|
94
|
+
const data = getFocusData({ root, target, options });
|
92
95
|
focusElement(data.el);
|
93
96
|
};
|
94
|
-
export const focusNextElement = (root) => focusTargetElement(root, "next");
|
95
|
-
export const focusPreviousElement = (root) => focusTargetElement(root, "prev");
|
96
|
-
export const focusFirstElement = (root) => focusTargetElement(root, "first");
|
97
|
-
export const focusLastElement = (root) => focusTargetElement(root, "last");
|
97
|
+
export const focusNextElement = (root) => focusTargetElement(root, "next", { includeNegativeTabIndex: true });
|
98
|
+
export const focusPreviousElement = (root) => focusTargetElement(root, "prev", { includeNegativeTabIndex: true });
|
99
|
+
export const focusFirstElement = (root) => focusTargetElement(root, "first", { includeNegativeTabIndex: true });
|
100
|
+
export const focusLastElement = (root) => focusTargetElement(root, "last", { includeNegativeTabIndex: true });
|
@@ -18,3 +18,7 @@
|
|
18
18
|
*/
|
19
19
|
export type TrapMode = "dialog" | "action-menu" | "action-bar" | "content-menu" | "selection-menu";
|
20
20
|
export type FocusableElement = HTMLButtonElement | HTMLInputElement;
|
21
|
+
export type FocusableOptions = {
|
22
|
+
additionalElement?: FocusableElement | null;
|
23
|
+
includeNegativeTabIndex?: boolean;
|
24
|
+
};
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "reshaped",
|
3
3
|
"description": "Professionally crafted design system in React & Figma for building products of any scale and complexity",
|
4
|
-
"version": "3.5.
|
4
|
+
"version": "3.5.2",
|
5
5
|
"license": "MIT",
|
6
6
|
"email": "hello@reshaped.so",
|
7
7
|
"homepage": "https://reshaped.so",
|
@@ -21,10 +21,9 @@
|
|
21
21
|
"bugs": {
|
22
22
|
"url": "https://github.com/formaat-design/reshaped/issues"
|
23
23
|
},
|
24
|
-
"
|
25
|
-
"
|
26
|
-
|
27
|
-
},
|
24
|
+
"sideEffects": [
|
25
|
+
"*.css"
|
26
|
+
],
|
28
27
|
"files": [
|
29
28
|
"bin/cli.js",
|
30
29
|
"dist/**/*"
|
@@ -58,7 +57,6 @@
|
|
58
57
|
"./themes/fragments/twitter/*": "./dist/themes/fragments/twitter/*",
|
59
58
|
"./package.json": "./package.json"
|
60
59
|
},
|
61
|
-
"sideEffects": false,
|
62
60
|
"bin": {
|
63
61
|
"reshaped": "./bin/cli.js"
|
64
62
|
},
|
@@ -76,8 +74,8 @@
|
|
76
74
|
"build:storybook": "storybook build -o dist/app --disable-telemetry",
|
77
75
|
"build:chromatic": "STORYBOOK_ENV=chromatic storybook build",
|
78
76
|
"release": "read -p 'Have you updated chromatic tests?' && yarn release:lib && yarn release:source && yarn build:storybook && yarn release:copy",
|
79
|
-
"release:lib": "yarn build && yarn publish",
|
80
|
-
"release:canary": "yarn build && yarn publish --tag canary",
|
77
|
+
"release:lib": "yarn build && yarn publish && sh ./bin/update-changelog.sh",
|
78
|
+
"release:canary": "yarn build && yarn publish --tag canary && sh ./bin/update-changelog.sh",
|
81
79
|
"release:test": "yarn build && yarn pack --filename reshaped-test.tgz",
|
82
80
|
"release:source": "sh ./bin/release-source.sh",
|
83
81
|
"release:copy": "sh ./bin/release-copy.sh",
|
@@ -89,7 +87,7 @@
|
|
89
87
|
"lint": "yarn lint:js && yarn lint:css",
|
90
88
|
"lint:js": "eslint './src/**/*.{ts,tsx}' --fix",
|
91
89
|
"lint:css": "stylelint 'src/**/*.css'",
|
92
|
-
"commit": "
|
90
|
+
"commit": "sh ./bin/commit.sh"
|
93
91
|
},
|
94
92
|
"browserslist": [
|
95
93
|
"defaults and not IE 11"
|
@@ -118,6 +116,7 @@
|
|
118
116
|
"@vitest/coverage-istanbul": "3.1.2",
|
119
117
|
"@vitest/coverage-v8": "3.1.2",
|
120
118
|
"chromatic": "11.28.2",
|
119
|
+
"conventional-changelog-cli": "^5.0.0",
|
121
120
|
"cz-conventional-changelog": "3.3.0",
|
122
121
|
"eslint": "9.25.1",
|
123
122
|
"eslint-config-prettier": "10.1.2",
|
@@ -1,23 +0,0 @@
|
|
1
|
-
import React from "react";
|
2
|
-
import { StoryObj } from "@storybook/react";
|
3
|
-
import { fn } from "@storybook/test";
|
4
|
-
declare const _default: {
|
5
|
-
title: string;
|
6
|
-
component: React.ForwardRefExoticComponent<import("./..").ScrollAreaProps & React.RefAttributes<HTMLDivElement>>;
|
7
|
-
parameters: {
|
8
|
-
iframe: {
|
9
|
-
url: string;
|
10
|
-
};
|
11
|
-
a11y: {
|
12
|
-
disable: boolean;
|
13
|
-
};
|
14
|
-
chromatic: {
|
15
|
-
disableSnapshot: boolean;
|
16
|
-
};
|
17
|
-
};
|
18
|
-
};
|
19
|
-
export default _default;
|
20
|
-
export declare const onScroll: StoryObj<{
|
21
|
-
handleScroll: ReturnType<typeof fn>;
|
22
|
-
}>;
|
23
|
-
export declare const className: StoryObj;
|
@@ -1,66 +0,0 @@
|
|
1
|
-
import React from "react";
|
2
|
-
import { expect, fn, userEvent, waitFor } from "@storybook/test";
|
3
|
-
import Button from "../../Button/index.js";
|
4
|
-
import ScrollArea from "../index.js";
|
5
|
-
import View from "../../View/index.js";
|
6
|
-
export default {
|
7
|
-
title: "Utility components/ScrollArea/tests",
|
8
|
-
component: ScrollArea,
|
9
|
-
parameters: {
|
10
|
-
iframe: {
|
11
|
-
url: "https://reshaped.so/docs/utilities/text",
|
12
|
-
},
|
13
|
-
// Skip because axe core incorrectly reports contrast issues
|
14
|
-
a11y: {
|
15
|
-
disable: true,
|
16
|
-
},
|
17
|
-
chromatic: { disableSnapshot: true },
|
18
|
-
},
|
19
|
-
};
|
20
|
-
export const onScroll = {
|
21
|
-
name: "ref, onScroll",
|
22
|
-
args: {
|
23
|
-
handleScroll: fn(),
|
24
|
-
},
|
25
|
-
render: (args) => {
|
26
|
-
const ref = React.useRef(null);
|
27
|
-
return (<View gap={4}>
|
28
|
-
<View.Item>
|
29
|
-
<Button onClick={() => ref.current?.scrollBy({ top: 50, left: 50 })}>Scroll</Button>
|
30
|
-
</View.Item>
|
31
|
-
<ScrollArea height="100px" ref={ref} scrollbarDisplay="visible" onScroll={args.handleScroll}>
|
32
|
-
<View backgroundColor="neutral-faded" padding={4} width="1000px" height="200px">
|
33
|
-
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum
|
34
|
-
has been the industry's standard dummy text ever since the 1500s, when an unknown
|
35
|
-
printer took a galley of type and scrambled it to make a type specimen book. It has
|
36
|
-
survived not only five centuries, but also the leap into electronic typesetting,
|
37
|
-
remaining essentially unchanged. It was popularised in the 1960s with the release of
|
38
|
-
Letraset sheets containing Lorem Ipsum passages, and more recently with desktop
|
39
|
-
publishing software like Aldus PageMaker including versions of Lorem Ipsum.
|
40
|
-
</View>
|
41
|
-
</ScrollArea>
|
42
|
-
</View>);
|
43
|
-
},
|
44
|
-
play: async ({ canvas, args }) => {
|
45
|
-
const trigger = canvas.getAllByRole("button")[0];
|
46
|
-
await userEvent.click(trigger);
|
47
|
-
await waitFor(() => {
|
48
|
-
expect(args.handleScroll).toHaveBeenCalledTimes(1);
|
49
|
-
// x value is flaky, so only testing y here
|
50
|
-
expect(args.handleScroll).toHaveBeenCalledWith(expect.objectContaining({ y: 0.5 }));
|
51
|
-
});
|
52
|
-
},
|
53
|
-
};
|
54
|
-
export const className = {
|
55
|
-
name: "className, attributes",
|
56
|
-
render: () => (<div data-testid="root">
|
57
|
-
<ScrollArea className="test-classname" attributes={{ id: "test-id" }}>
|
58
|
-
Content
|
59
|
-
</ScrollArea>
|
60
|
-
</div>),
|
61
|
-
play: async ({ canvas }) => {
|
62
|
-
const root = canvas.getByTestId("root").firstChild;
|
63
|
-
expect(root).toHaveClass("test-classname");
|
64
|
-
expect(root).toHaveAttribute("id", "test-id");
|
65
|
-
},
|
66
|
-
};
|