reshaped 3.7.0-canary.17 → 3.7.0-canary.19
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 +7 -1
- package/dist/bundle.css +1 -1
- package/dist/bundle.js +8 -8
- package/dist/components/ActionBar/ActionBar.js +11 -4
- package/dist/components/ActionBar/ActionBar.module.css +1 -1
- package/dist/components/ActionBar/ActionBar.types.d.ts +5 -1
- package/dist/components/ActionBar/tests/ActionBar.stories.d.ts +23 -1
- package/dist/components/ActionBar/tests/ActionBar.stories.js +175 -3
- package/dist/components/Card/Card.d.ts +1 -1
- package/dist/components/FileUpload/FileUpload.js +5 -3
- package/dist/components/FileUpload/FileUpload.module.css +1 -1
- package/dist/components/FileUpload/FileUpload.types.d.ts +5 -1
- package/dist/components/FileUpload/tests/FileUpload.stories.d.ts +18 -2
- package/dist/components/FileUpload/tests/FileUpload.stories.js +102 -23
- package/dist/components/Popover/tests/Popover.stories.js +4 -3
- package/package.json +1 -1
- package/dist/components/ActionBar/tests/ActionBar.test.stories.d.ts +0 -15
- package/dist/components/ActionBar/tests/ActionBar.test.stories.js +0 -26
- package/dist/components/FileUpload/tests/FileUpload.test.stories.d.ts +0 -21
- package/dist/components/FileUpload/tests/FileUpload.test.stories.js +0 -52
@@ -1,11 +1,18 @@
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import { classNames } from "../../utilities/props.js";
|
2
|
+
import { classNames, responsiveVariables } from "../../utilities/props.js";
|
3
3
|
import View from "../View/index.js";
|
4
4
|
import s from "./ActionBar.module.css";
|
5
|
+
const fullWidthPositions = ["top", "bottom"];
|
5
6
|
const ActionBar = (props) => {
|
6
|
-
const { position = "bottom", padding, paddingBlock = 3, paddingInline = 4, children, elevated, className, attributes, } = props;
|
7
|
-
const
|
8
|
-
|
7
|
+
const { position = "bottom", positionType: passedPositionType, offset: passedOffset, padding, paddingBlock = 3, paddingInline = 4, children, blurred, elevated, active = true, className, attributes, } = props;
|
8
|
+
const positionType = passedPositionType ?? (fullWidthPositions.includes(position) ? "relative" : "absolute");
|
9
|
+
const offset = passedOffset ?? (positionType === "relative" ? undefined : 4);
|
10
|
+
const offsetVariables = offset && responsiveVariables("--rs-action-bar-offset", offset);
|
11
|
+
const rootClassNames = classNames(s.root, (elevated || !!offsetVariables) && s["--elevated"], position && s[`--position-${position}`], blurred && s["--blurred"], active && s["--active"], className);
|
12
|
+
return (_jsx(View, { className: rootClassNames, attributes: {
|
13
|
+
...attributes,
|
14
|
+
style: { ...attributes?.style, ...offsetVariables },
|
15
|
+
}, position: positionType, paddingBlock: padding || paddingBlock, paddingInline: padding || paddingInline, children: children }));
|
9
16
|
};
|
10
17
|
ActionBar.displayName = "ActionBar";
|
11
18
|
export default ActionBar;
|
@@ -1 +1 @@
|
|
1
|
-
.root{background:var(--rs-color-background-elevation-base);position:
|
1
|
+
.root{--rs-action-bar-background-rgb:var(--rs-color-rgb-background-elevation-base);--rs-action-bar-background-opacity:1;--rs-action-bar-translate-x:0;--rs-action-bar-translate-y:0;--rs-action-bar-radius:0;background:rgba(var(--rs-action-bar-background-rgb),var(--rs-action-bar-background-opacity));border:1px solid var(--rs-color-border-neutral-faded);border-radius:var(--rs-action-bar-radius);max-width:calc(100% - var(--rs-action-bar-offset) * 2);transform:translate(var(--rs-action-bar-translate-x),var(--rs-action-bar-translate-y));transition:transform var(--rs-duration-fast) var(--rs-easing-accelerate)}.root[style*="--rs-action-bar-offset-"]{--rs-action-bar-radius:var(--rs-radius-medium);margin:calc(var(--rs-action-bar-offset) * var(--rs-unit-x1));--rs-action-bar-offset-s:0;--rs-action-bar-offset-m:var(--rs-action-bar-offset-s);--rs-action-bar-offset-l:var(--rs-action-bar-offset-m);--rs-action-bar-offset-xl:var(--rs-action-bar-offset-l);--rs-action-bar-offset:var(--rs-action-bar-offset-s)}.--position-top,.--position-top-end,.--position-top-start{--rs-action-bar-translate-y:calc(-100% - var(--rs-action-bar-offset) * var(--rs-unit-x1) * 2);inset-block-start:0}.--position-bottom,.--position-bottom-end,.--position-bottom-start{--rs-action-bar-translate-y:calc(100% + var(--rs-action-bar-offset) * var(--rs-unit-x1) * 2);inset-block-end:0}.--position-bottom,.--position-top{--rs-action-bar-translate-x:-50%;inset-inline-start:50%}.--position-bottom-start,.--position-top-start{inset-inline-start:0}.--position-bottom-end,.--position-top-end{inset-inline-end:0}.--position-bottom:not([style*="--rs-action-bar-offset-"]),.--position-top:not([style*="--rs-action-bar-offset-"]){--rs-action-bar-border-radius:0px;border:0;overflow-x:clip;width:100%}.--position-bottom:not([style*="--rs-action-bar-offset-"]).--elevated,.--position-top:not([style*="--rs-action-bar-offset-"]).--elevated{border:0!important}.--position-top:not([style*="--rs-action-bar-offset-"]){border-bottom:1px solid var(--rs-color-border-neutral-faded)}.--position-bottom:not([style*="--rs-action-bar-offset-"]){border-top:1px solid var(--rs-color-border-neutral-faded)}.--active{--rs-action-bar-translate-y:0px;transition-timing-function:var(--rs-easing-decelerate)}.--blurred{--rs-action-bar-background-opacity:0.84;backdrop-filter:blur(10px)}.--elevated{--rs-action-bar-background-rgb:var(--rs-color-rgb-background-elevation-raised)}.--elevated:after{border-radius:var(--rs-action-bar-radius);bottom:0;box-shadow:var(--rs-shadow-raised);content:"";display:block;height:100%;left:0;pointer-events:none;position:absolute;right:0}.--position-bottom.--elevated:after{transform:rotateX(180deg)}@media (--rs-viewport-m ){.root[style*="--rs-action-bar-offset-"]{--rs-action-bar-offset:var(--rs-action-bar-offset-m)}}@media (--rs-viewport-l ){.root[style*="--rs-action-bar-offset-"]{--rs-action-bar-offset:var(--rs-action-bar-offset-l)}}@media (--rs-viewport-xl ){.root[style*="--rs-action-bar-offset-"]{--rs-action-bar-offset:var(--rs-action-bar-offset-xl)}}
|
@@ -2,7 +2,11 @@ import type React from "react";
|
|
2
2
|
import type { ViewProps } from "../View";
|
3
3
|
import type * as G from "../../types/global";
|
4
4
|
export type Props = Pick<ViewProps, "paddingBlock" | "paddingInline" | "padding"> & {
|
5
|
-
|
5
|
+
active?: boolean;
|
6
|
+
offset?: G.Responsive<number>;
|
7
|
+
position?: "top" | "top-end" | "top-start" | "bottom" | "bottom-start" | "bottom-end";
|
8
|
+
positionType?: G.Responsive<"relative" | "absolute" | "fixed">;
|
9
|
+
blurred?: boolean;
|
6
10
|
elevated?: boolean;
|
7
11
|
children?: React.ReactNode;
|
8
12
|
className?: G.ClassName;
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { StoryObj } from "@storybook/react-vite";
|
1
2
|
declare const _default: {
|
2
3
|
title: string;
|
3
4
|
component: import("react").FC<import("./..").ActionBarProps>;
|
@@ -8,7 +9,15 @@ declare const _default: {
|
|
8
9
|
};
|
9
10
|
};
|
10
11
|
export default _default;
|
11
|
-
export declare const
|
12
|
+
export declare const positionRelative: {
|
13
|
+
name: string;
|
14
|
+
render: () => import("react").JSX.Element;
|
15
|
+
};
|
16
|
+
export declare const positionAbsolute: {
|
17
|
+
name: string;
|
18
|
+
render: () => import("react").JSX.Element;
|
19
|
+
};
|
20
|
+
export declare const positionFixed: {
|
12
21
|
name: string;
|
13
22
|
render: () => import("react").JSX.Element;
|
14
23
|
};
|
@@ -16,7 +25,20 @@ export declare const elevated: {
|
|
16
25
|
name: string;
|
17
26
|
render: () => import("react").JSX.Element;
|
18
27
|
};
|
28
|
+
export declare const offset: {
|
29
|
+
name: string;
|
30
|
+
render: () => import("react").JSX.Element;
|
31
|
+
};
|
32
|
+
export declare const active: {
|
33
|
+
name: string;
|
34
|
+
render: () => import("react").JSX.Element;
|
35
|
+
};
|
36
|
+
export declare const blurred: {
|
37
|
+
name: string;
|
38
|
+
render: () => import("react").JSX.Element;
|
39
|
+
};
|
19
40
|
export declare const padding: {
|
20
41
|
name: string;
|
21
42
|
render: () => import("react").JSX.Element;
|
22
43
|
};
|
44
|
+
export declare const className: StoryObj;
|
@@ -1,5 +1,9 @@
|
|
1
|
+
import { expect } from "storybook/test";
|
1
2
|
import { Placeholder, Example } from "../../../utilities/storybook/index.js";
|
2
3
|
import ActionBar from "../index.js";
|
4
|
+
import View from "../../View/index.js";
|
5
|
+
import Button from "../../Button/index.js";
|
6
|
+
import useToggle from "../../../hooks/useToggle.js";
|
3
7
|
export default {
|
4
8
|
title: "Components/ActionBar",
|
5
9
|
component: ActionBar,
|
@@ -9,8 +13,19 @@ export default {
|
|
9
13
|
},
|
10
14
|
},
|
11
15
|
};
|
12
|
-
|
13
|
-
|
16
|
+
const Fixtures = {
|
17
|
+
Container: (props) => (<View backgroundColor="neutral-faded" height="160px" overflow="hidden" borderRadius="medium">
|
18
|
+
{props.children}
|
19
|
+
</View>),
|
20
|
+
Actions: () => (<View direction="row" gap={2}>
|
21
|
+
<Button onClick={() => { }}>Action</Button>
|
22
|
+
<Button onClick={() => { }} variant="outline">
|
23
|
+
Action
|
24
|
+
</Button>
|
25
|
+
</View>),
|
26
|
+
};
|
27
|
+
export const positionRelative = {
|
28
|
+
name: "position, positionType: relative",
|
14
29
|
render: () => (<Example>
|
15
30
|
<Example.Item title="position: top">
|
16
31
|
<ActionBar position="top">
|
@@ -19,12 +34,94 @@ export const position = {
|
|
19
34
|
</Example.Item>
|
20
35
|
|
21
36
|
<Example.Item title="position: bottom">
|
22
|
-
<ActionBar>
|
37
|
+
<ActionBar position="bottom">
|
23
38
|
<Placeholder />
|
24
39
|
</ActionBar>
|
25
40
|
</Example.Item>
|
26
41
|
</Example>),
|
27
42
|
};
|
43
|
+
export const positionAbsolute = {
|
44
|
+
name: "position, positionType: absolute",
|
45
|
+
render: () => (<Example>
|
46
|
+
<Example.Item title="position: top-start">
|
47
|
+
<Fixtures.Container>
|
48
|
+
<ActionBar padding={2} position="top-start" positionType="absolute">
|
49
|
+
<Fixtures.Actions />
|
50
|
+
</ActionBar>
|
51
|
+
</Fixtures.Container>
|
52
|
+
</Example.Item>
|
53
|
+
|
54
|
+
<Example.Item title="position: top">
|
55
|
+
<Fixtures.Container>
|
56
|
+
<ActionBar padding={2} position="top" positionType="absolute">
|
57
|
+
<Fixtures.Actions />
|
58
|
+
</ActionBar>
|
59
|
+
</Fixtures.Container>
|
60
|
+
</Example.Item>
|
61
|
+
|
62
|
+
<Example.Item title="position: top-end">
|
63
|
+
<Fixtures.Container>
|
64
|
+
<ActionBar padding={2} position="top-end" positionType="absolute">
|
65
|
+
<Fixtures.Actions />
|
66
|
+
</ActionBar>
|
67
|
+
</Fixtures.Container>
|
68
|
+
</Example.Item>
|
69
|
+
|
70
|
+
<Example.Item title="position: bottom-start">
|
71
|
+
<Fixtures.Container>
|
72
|
+
<ActionBar padding={2} position="bottom-start" positionType="absolute">
|
73
|
+
<Fixtures.Actions />
|
74
|
+
</ActionBar>
|
75
|
+
</Fixtures.Container>
|
76
|
+
</Example.Item>
|
77
|
+
|
78
|
+
<Example.Item title="position: bottom">
|
79
|
+
<Fixtures.Container>
|
80
|
+
<ActionBar padding={2} position="bottom" positionType="absolute">
|
81
|
+
<Fixtures.Actions />
|
82
|
+
</ActionBar>
|
83
|
+
</Fixtures.Container>
|
84
|
+
</Example.Item>
|
85
|
+
|
86
|
+
<Example.Item title="position: bottom-end">
|
87
|
+
<Fixtures.Container>
|
88
|
+
<ActionBar padding={2} position="bottom-end" positionType="absolute">
|
89
|
+
<Fixtures.Actions />
|
90
|
+
</ActionBar>
|
91
|
+
</Fixtures.Container>
|
92
|
+
</Example.Item>
|
93
|
+
</Example>),
|
94
|
+
};
|
95
|
+
export const positionFixed = {
|
96
|
+
name: "position, positionType: fixed",
|
97
|
+
render: () => (<>
|
98
|
+
<ActionBar padding={2} position="top-start" positionType="fixed">
|
99
|
+
<Fixtures.Actions />
|
100
|
+
</ActionBar>
|
101
|
+
|
102
|
+
<ActionBar padding={2} position="top" positionType="fixed">
|
103
|
+
<Fixtures.Actions />
|
104
|
+
</ActionBar>
|
105
|
+
|
106
|
+
<ActionBar padding={2} position="top-end" positionType="fixed">
|
107
|
+
<Fixtures.Actions />
|
108
|
+
</ActionBar>
|
109
|
+
|
110
|
+
<ActionBar padding={2} position="bottom-start" positionType="fixed">
|
111
|
+
<Fixtures.Actions />
|
112
|
+
</ActionBar>
|
113
|
+
|
114
|
+
<ActionBar padding={2} position="bottom" positionType="fixed">
|
115
|
+
<Fixtures.Actions />
|
116
|
+
</ActionBar>
|
117
|
+
|
118
|
+
<ActionBar padding={2} position="bottom-end" positionType="fixed">
|
119
|
+
<Fixtures.Actions />
|
120
|
+
</ActionBar>
|
121
|
+
|
122
|
+
<div style={{ height: 2000 }}/>
|
123
|
+
</>),
|
124
|
+
};
|
28
125
|
export const elevated = {
|
29
126
|
name: "elevated",
|
30
127
|
render: () => (<Example>
|
@@ -39,6 +136,68 @@ export const elevated = {
|
|
39
136
|
<Placeholder />
|
40
137
|
</ActionBar>
|
41
138
|
</Example.Item>
|
139
|
+
|
140
|
+
<Example.Item title="auto elevated, position: bottom">
|
141
|
+
<Fixtures.Container>
|
142
|
+
<ActionBar position="bottom-end">
|
143
|
+
<Fixtures.Actions />
|
144
|
+
</ActionBar>
|
145
|
+
</Fixtures.Container>
|
146
|
+
</Example.Item>
|
147
|
+
</Example>),
|
148
|
+
};
|
149
|
+
export const offset = {
|
150
|
+
name: "offset",
|
151
|
+
render: () => (<Example>
|
152
|
+
<Example.Item title="offset 2, position: top">
|
153
|
+
<Fixtures.Container>
|
154
|
+
<ActionBar position="top" positionType="absolute" offset={2}>
|
155
|
+
<Fixtures.Actions />
|
156
|
+
</ActionBar>
|
157
|
+
</Fixtures.Container>
|
158
|
+
</Example.Item>
|
159
|
+
|
160
|
+
<Example.Item title="offset 2, position: bottom-end">
|
161
|
+
<Fixtures.Container>
|
162
|
+
<ActionBar position="bottom-end" offset={2}>
|
163
|
+
<Fixtures.Actions />
|
164
|
+
</ActionBar>
|
165
|
+
</Fixtures.Container>
|
166
|
+
</Example.Item>
|
167
|
+
|
168
|
+
<Example.Item title="offset s: 2, m: 4, position: bottom-end">
|
169
|
+
<Fixtures.Container>
|
170
|
+
<ActionBar position="bottom-end" offset={{ s: 2, m: 4 }}>
|
171
|
+
<Fixtures.Actions />
|
172
|
+
</ActionBar>
|
173
|
+
</Fixtures.Container>
|
174
|
+
</Example.Item>
|
175
|
+
</Example>),
|
176
|
+
};
|
177
|
+
export const active = {
|
178
|
+
name: "active",
|
179
|
+
render: () => {
|
180
|
+
const barToggle = useToggle();
|
181
|
+
return (<>
|
182
|
+
<Button onClick={() => barToggle.toggle()}>Toggle</Button>
|
183
|
+
<ActionBar active={barToggle.active} positionType="fixed" position="top-end">
|
184
|
+
<Fixtures.Actions />
|
185
|
+
</ActionBar>
|
186
|
+
</>);
|
187
|
+
},
|
188
|
+
};
|
189
|
+
export const blurred = {
|
190
|
+
name: "blurred",
|
191
|
+
render: () => (<Example>
|
192
|
+
<Example.Item title="blurred">
|
193
|
+
<View backgroundColor="neutral-faded" height="200px" align="end" justify="end" padding={8}>
|
194
|
+
<Button color="primary">Action</Button>
|
195
|
+
|
196
|
+
<ActionBar position="bottom-end" blurred>
|
197
|
+
<View width={20} height={20}/>
|
198
|
+
</ActionBar>
|
199
|
+
</View>
|
200
|
+
</Example.Item>
|
42
201
|
</Example>),
|
43
202
|
};
|
44
203
|
export const padding = {
|
@@ -63,3 +222,16 @@ export const padding = {
|
|
63
222
|
</Example.Item>
|
64
223
|
</Example>),
|
65
224
|
};
|
225
|
+
export const className = {
|
226
|
+
name: "className, attributes",
|
227
|
+
render: () => (<div data-testid="root">
|
228
|
+
<ActionBar className="test-classname" attributes={{ id: "test-id" }}>
|
229
|
+
<Placeholder />
|
230
|
+
</ActionBar>
|
231
|
+
</div>),
|
232
|
+
play: async ({ canvas }) => {
|
233
|
+
const root = canvas.getByTestId("root").firstChild;
|
234
|
+
expect(root).toHaveClass("test-classname");
|
235
|
+
expect(root).toHaveAttribute("id", "test-id");
|
236
|
+
},
|
237
|
+
};
|
@@ -9,7 +9,7 @@ declare const Card: React.ForwardRefExoticComponent<{
|
|
9
9
|
href?: string;
|
10
10
|
as?: keyof React.JSX.IntrinsicElements | undefined;
|
11
11
|
className?: import("../../types/global").ClassName;
|
12
|
-
attributes?: (import("../..").Attributes<keyof React.JSX.IntrinsicElements> & ((import("../..").Attributes<"button"> & Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "form" | "slot" | "style" | "title" | "disabled" | "color" | "children" | "className" | "hidden" | "content" | "ref" | "aria-orientation" | "role" | "suppressHydrationWarning" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "value" | "dir" | "name" | "key" | "type" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "enterKeyHint" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "
|
12
|
+
attributes?: (import("../..").Attributes<keyof React.JSX.IntrinsicElements> & ((import("../..").Attributes<"button"> & Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "form" | "slot" | "style" | "title" | "disabled" | "color" | "children" | "className" | "hidden" | "content" | "ref" | "aria-orientation" | "role" | "suppressHydrationWarning" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "formAction" | "formEncType" | "formMethod" | "formNoValidate" | "formTarget" | "value" | "dir" | "name" | "key" | "type" | "translate" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "draggable" | "enterKeyHint" | "id" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "radioGroup" | "about" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "popover" | "popoverTargetAction" | "popoverTarget" | "inert" | "inputMode" | "is" | "exportparts" | "part" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onScrollEnd" | "onScrollEndCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onToggle" | "onBeforeToggle" | "onTransitionCancel" | "onTransitionCancelCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "onTransitionRun" | "onTransitionRunCapture" | "onTransitionStart" | "onTransitionStartCapture"> & {
|
13
13
|
ref?: React.RefObject<HTMLButtonElement | HTMLAnchorElement | null>;
|
14
14
|
}) | undefined)) | undefined;
|
15
15
|
} & Pick<import("../View").ViewProps, "height"> & React.RefAttributes<HTMLElement>>;
|
@@ -10,9 +10,9 @@ const FileUploadTrigger = (props) => {
|
|
10
10
|
return _jsx("span", { className: s.trigger, children: children });
|
11
11
|
};
|
12
12
|
const FileUpload = (props) => {
|
13
|
-
const { name, children, height, className, attributes, inputAttributes, onChange } = props;
|
13
|
+
const { name, children, height, variant = "outline", inline, className, attributes, inputAttributes, onChange, } = props;
|
14
14
|
const highlightToggle = useToggle();
|
15
|
-
const rootClassNames = classNames(s.root, highlightToggle.active && s["--highlighted"], className);
|
15
|
+
const rootClassNames = classNames(s.root, variant && s[`--variant-${variant}`], inline && s[`--inline`], highlightToggle.active && s["--highlighted"], className);
|
16
16
|
const handleDragOver = (event) => {
|
17
17
|
event.preventDefault();
|
18
18
|
attributes?.onDragOver?.(event);
|
@@ -41,13 +41,15 @@ const FileUpload = (props) => {
|
|
41
41
|
onChange?.({ name, event, value: Array.from(nextValue) });
|
42
42
|
inputAttributes?.onChange?.(event);
|
43
43
|
};
|
44
|
+
const inputNode = (_jsx(HiddenVisually, { children: _jsx("input", { ...inputAttributes, type: "file", className: s.field, name: name, onChange: handleChange }) }));
|
45
|
+
const childrenNode = typeof children === "function" ? children({ highlighted: highlightToggle.active }) : children;
|
44
46
|
return (_jsx(View, { className: rootClassNames, height: height, attributes: {
|
45
47
|
...attributes,
|
46
48
|
onDragOver: handleDragOver,
|
47
49
|
onDragEnter: handleDragEnter,
|
48
50
|
onDragLeave: handleDragLeave,
|
49
51
|
onDrop: handleDrop,
|
50
|
-
}, children: _jsxs(View, { as: "label", className: s.triggerLayer, padding: 6, borderRadius: "medium", gap: 2, align: "center", justify: "center", textAlign: "center", animated: true, height: "100%", children: [_jsx(View.Item, { children:
|
52
|
+
}, children: variant === "outline" && !inline ? (_jsxs(View, { as: "label", className: s.triggerLayer, padding: 6, borderRadius: "medium", gap: 2, align: "center", justify: "center", textAlign: "center", animated: true, height: "100%", children: [inputNode, _jsx(View.Item, { children: childrenNode })] })) : (_jsxs("label", { className: s.triggerLayer, children: [inputNode, childrenNode] })) }));
|
51
53
|
};
|
52
54
|
FileUpload.Trigger = FileUploadTrigger;
|
53
55
|
FileUpload.displayName = "FileUpload";
|
@@ -1 +1 @@
|
|
1
|
-
.root
|
1
|
+
.root{--rs-file-upload-radius:var(--rs-radius-medium);display:block}[data-rs-keyboard] .root:focus-within{box-shadow:var(--rs-focus-shadow)}.--inline{--rs-file-upload-radius:var(--rs-radius-small)}.--inline,.--inline .triggerLayer{display:inline-block;vertical-align:top}[data-rs-keyboard] .--inline:focus-within{box-shadow:none}[data-rs-keyboard] .--inline:focus-within .triggerLayer>*{box-shadow:var(--rs-focus-shadow)}.--variant-outline .triggerLayer{border:1px dashed var(--rs-color-border-neutral);border-radius:var(--rs-file-upload-radius)}.--highlighted.--variant-outline .triggerLayer{background:rgba(var(--rs-color-rgb-background-primary),.08);border-color:var(--rs-color-border-primary)}@media (hover:hover) and (pointer:fine){.--variant-outline .triggerLayer:hover:not(:has(.trigger)){background:rgba(var(--rs-color-rgb-background-neutral),.16)}}.triggerLayer:has(.trigger){pointer-events:none}.triggerLayer:has(.trigger) .trigger{pointer-events:all}.trigger{display:contents}
|
@@ -3,9 +3,13 @@ import type { ViewProps } from "../View";
|
|
3
3
|
import type * as G from "../../types/global";
|
4
4
|
export type Props = {
|
5
5
|
name: string;
|
6
|
-
children?: React.ReactNode
|
6
|
+
children?: React.ReactNode | ((props: {
|
7
|
+
highlighted?: boolean;
|
8
|
+
}) => React.ReactNode);
|
7
9
|
onChange?: G.ChangeHandler<File[], React.DragEvent<HTMLDivElement> | React.ChangeEvent<HTMLInputElement>>;
|
8
10
|
height?: ViewProps["height"];
|
11
|
+
variant?: "outline" | "headless";
|
12
|
+
inline?: boolean;
|
9
13
|
className?: G.ClassName;
|
10
14
|
attributes?: G.Attributes<"div">;
|
11
15
|
inputAttributes?: G.Attributes<"input">;
|
@@ -1,4 +1,6 @@
|
|
1
1
|
import React from "react";
|
2
|
+
import { StoryObj } from "@storybook/react-vite";
|
3
|
+
import { fn } from "storybook/test";
|
2
4
|
declare const _default: {
|
3
5
|
title: string;
|
4
6
|
component: React.FC<import("./..").FileUploadProps> & {
|
@@ -11,5 +13,19 @@ declare const _default: {
|
|
11
13
|
};
|
12
14
|
};
|
13
15
|
export default _default;
|
14
|
-
export declare const base:
|
15
|
-
|
16
|
+
export declare const base: {
|
17
|
+
name: string;
|
18
|
+
render: () => React.JSX.Element;
|
19
|
+
};
|
20
|
+
export declare const inline: {
|
21
|
+
name: string;
|
22
|
+
render: () => React.JSX.Element;
|
23
|
+
};
|
24
|
+
export declare const height: {
|
25
|
+
name: string;
|
26
|
+
render: () => React.JSX.Element;
|
27
|
+
};
|
28
|
+
export declare const onChange: StoryObj<{
|
29
|
+
handleChange: ReturnType<typeof fn>;
|
30
|
+
}>;
|
31
|
+
export declare const className: StoryObj;
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import React from "react";
|
2
|
+
import { expect, userEvent, fn } from "storybook/test";
|
2
3
|
import { Example } from "../../../utilities/storybook/index.js";
|
3
4
|
import FileUpload from "../index.js";
|
4
5
|
import View from "../../View/index.js";
|
@@ -6,6 +7,7 @@ import Image from "../../Image/index.js";
|
|
6
7
|
import Link from "../../Link/index.js";
|
7
8
|
import Icon from "../../Icon/index.js";
|
8
9
|
import IconMic from "../../../icons/Mic.js";
|
10
|
+
import Button from "../../Button/index.js";
|
9
11
|
export default {
|
10
12
|
title: "Components/FileUpload",
|
11
13
|
component: FileUpload,
|
@@ -34,28 +36,105 @@ const Demo = () => {
|
|
34
36
|
</View>
|
35
37
|
</View>);
|
36
38
|
};
|
37
|
-
export const base =
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
<
|
46
|
-
|
47
|
-
|
48
|
-
|
39
|
+
export const base = {
|
40
|
+
name: "base",
|
41
|
+
render: () => (<Example>
|
42
|
+
<Example.Item title="Base upload with previews">
|
43
|
+
<Demo />
|
44
|
+
</Example.Item>
|
45
|
+
<Example.Item title="With trigger">
|
46
|
+
<FileUpload name="file">
|
47
|
+
<div>
|
48
|
+
Drop files to attach, or{" "}
|
49
|
+
<FileUpload.Trigger>
|
50
|
+
<Link variant="plain">browse</Link>
|
51
|
+
</FileUpload.Trigger>
|
52
|
+
</div>
|
53
|
+
</FileUpload>
|
54
|
+
</Example.Item>
|
55
|
+
</Example>),
|
56
|
+
};
|
57
|
+
export const inline = {
|
58
|
+
name: "inline, variant, render props",
|
59
|
+
render: () => {
|
60
|
+
return (<Example>
|
61
|
+
<Example.Item title="inline">
|
62
|
+
<FileUpload name="file" inline onChange={console.log}>
|
63
|
+
<View padding={2} paddingInline={3}>
|
64
|
+
Upload
|
65
|
+
</View>
|
66
|
+
</FileUpload>
|
67
|
+
</Example.Item>
|
68
|
+
<Example.Item title="variant headless">
|
69
|
+
<FileUpload name="file2" variant="headless" onChange={console.log}>
|
70
|
+
<Button variant="outline" fullWidth>
|
71
|
+
Upload
|
72
|
+
</Button>
|
73
|
+
</FileUpload>
|
74
|
+
</Example.Item>
|
75
|
+
<Example.Item title="variant headless, inline">
|
76
|
+
<FileUpload name="file2" variant="headless" inline onChange={console.log}>
|
77
|
+
<Button>Upload</Button>
|
78
|
+
</FileUpload>
|
79
|
+
</Example.Item>
|
80
|
+
<Example.Item title="inline, render props">
|
81
|
+
<FileUpload name="file3" variant="headless" inline onChange={console.log}>
|
82
|
+
{(props) => <Button highlighted={props.highlighted}>Upload</Button>}
|
83
|
+
</FileUpload>
|
84
|
+
</Example.Item>
|
85
|
+
</Example>);
|
86
|
+
},
|
87
|
+
};
|
88
|
+
export const height = {
|
89
|
+
name: "height",
|
90
|
+
render: () => (<Example>
|
91
|
+
<Example.Item title="Custom height">
|
92
|
+
<FileUpload name="file" height="300px">
|
93
|
+
<View gap={3}>
|
94
|
+
<Icon svg={IconMic} size={8}/>
|
95
|
+
Drop files to attach
|
96
|
+
</View>
|
97
|
+
</FileUpload>
|
98
|
+
</Example.Item>
|
99
|
+
</Example>),
|
100
|
+
};
|
101
|
+
export const onChange = {
|
102
|
+
name: "name, onChange",
|
103
|
+
args: {
|
104
|
+
handleChange: fn(),
|
105
|
+
},
|
106
|
+
render: (args) => (<div data-testid="root">
|
107
|
+
<FileUpload name="test-name" onChange={args.handleChange}>
|
108
|
+
Content
|
49
109
|
</FileUpload>
|
50
|
-
</
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
110
|
+
</div>),
|
111
|
+
play: async ({ canvas, args }) => {
|
112
|
+
const file = new File(["hello"], "hello.png", { type: "image/png" });
|
113
|
+
const input = canvas.getByTestId("root").querySelector("input");
|
114
|
+
await userEvent.upload(input, file);
|
115
|
+
expect(input).toHaveAttribute("name", "test-name");
|
116
|
+
expect(input.files?.[0]).toBe(file);
|
117
|
+
expect(input.files).toHaveLength(1);
|
118
|
+
expect(args.handleChange).toHaveBeenCalledTimes(1);
|
119
|
+
expect(args.handleChange).toHaveBeenCalledWith({
|
120
|
+
name: "test-name",
|
121
|
+
value: [file],
|
122
|
+
event: expect.objectContaining({ target: input }),
|
123
|
+
});
|
124
|
+
},
|
125
|
+
};
|
126
|
+
export const className = {
|
127
|
+
name: "className, attributes",
|
128
|
+
render: () => (<div data-testid="root">
|
129
|
+
<FileUpload name="name" className="test-classname" attributes={{ id: "test-id" }} inputAttributes={{ id: "test-input-id" }}>
|
130
|
+
Content
|
59
131
|
</FileUpload>
|
60
|
-
</
|
61
|
-
|
132
|
+
</div>),
|
133
|
+
play: async ({ canvas }) => {
|
134
|
+
const root = canvas.getByTestId("root").firstChild;
|
135
|
+
const input = canvas.getByTestId("root").querySelector("input");
|
136
|
+
expect(root).toHaveClass("test-classname");
|
137
|
+
expect(root).toHaveAttribute("id", "test-id");
|
138
|
+
expect(input).toHaveAttribute("id", "test-input-id");
|
139
|
+
},
|
140
|
+
};
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { useState } from "react";
|
1
|
+
import { useState, useId } from "react";
|
2
2
|
import { expect, fn, userEvent, within, waitFor } from "storybook/test";
|
3
3
|
import { Example } from "../../../utilities/storybook/index.js";
|
4
4
|
import { sleep } from "../../../utilities/helpers.js";
|
@@ -19,13 +19,14 @@ export default {
|
|
19
19
|
};
|
20
20
|
const Demo = (props) => {
|
21
21
|
const { position, ...rest } = props;
|
22
|
+
const id = useId();
|
22
23
|
return (<Popover position={position} {...rest}>
|
23
24
|
<Popover.Trigger>
|
24
25
|
{(attributes) => <Button attributes={attributes}>{position || "Open"}</Button>}
|
25
26
|
</Popover.Trigger>
|
26
|
-
<Popover.Content>
|
27
|
+
<Popover.Content attributes={{ "aria-labelledby": id }}>
|
27
28
|
<View gap={2} align="start">
|
28
|
-
Popover content
|
29
|
+
<span id={id}>Popover content</span>
|
29
30
|
<View direction="row" gap={2}>
|
30
31
|
<Button onClick={() => { }}>Action 1</Button>
|
31
32
|
<Button onClick={() => { }}>Action 2</Button>
|
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.7.0-canary.
|
4
|
+
"version": "3.7.0-canary.19",
|
5
5
|
"license": "MIT",
|
6
6
|
"email": "hello@reshaped.so",
|
7
7
|
"homepage": "https://reshaped.so",
|
@@ -1,15 +0,0 @@
|
|
1
|
-
import { StoryObj } from "@storybook/react-vite";
|
2
|
-
declare const _default: {
|
3
|
-
title: string;
|
4
|
-
component: import("react").FC<import("./..").ActionBarProps>;
|
5
|
-
parameters: {
|
6
|
-
iframe: {
|
7
|
-
url: string;
|
8
|
-
};
|
9
|
-
chromatic: {
|
10
|
-
disableSnapshot: boolean;
|
11
|
-
};
|
12
|
-
};
|
13
|
-
};
|
14
|
-
export default _default;
|
15
|
-
export declare const className: StoryObj;
|
@@ -1,26 +0,0 @@
|
|
1
|
-
import { expect } from "storybook/test";
|
2
|
-
import ActionBar from "../index.js";
|
3
|
-
import { Placeholder } from "../../../utilities/storybook/index.js";
|
4
|
-
export default {
|
5
|
-
title: "Components/ActionBar/tests",
|
6
|
-
component: ActionBar,
|
7
|
-
parameters: {
|
8
|
-
iframe: {
|
9
|
-
url: "https://reshaped.so/docs/components/action-bar",
|
10
|
-
},
|
11
|
-
chromatic: { disableSnapshot: true },
|
12
|
-
},
|
13
|
-
};
|
14
|
-
export const className = {
|
15
|
-
name: "className, attributes",
|
16
|
-
render: () => (<div data-testid="root">
|
17
|
-
<ActionBar className="test-classname" attributes={{ id: "test-id" }}>
|
18
|
-
<Placeholder />
|
19
|
-
</ActionBar>
|
20
|
-
</div>),
|
21
|
-
play: async ({ canvas }) => {
|
22
|
-
const root = canvas.getByTestId("root").firstChild;
|
23
|
-
expect(root).toHaveClass("test-classname");
|
24
|
-
expect(root).toHaveAttribute("id", "test-id");
|
25
|
-
},
|
26
|
-
};
|