@scality/core-ui 0.147.0 → 0.149.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/.github/workflows/github-pages.yml +4 -4
- package/dist/components/accordion/Accordion.component.d.ts.map +1 -1
- package/dist/components/accordion/Accordion.component.js +15 -9
- package/package.json +1 -1
- package/src/lib/components/accordion/Accordion.component.tsx +23 -11
- package/stories/Accordion/accordion.guideline.mdx +7 -0
- package/stories/Accordion/accordion.stories.tsx +26 -3
- package/stories/form.stories.tsx +179 -0
|
@@ -2,15 +2,15 @@ name: Deploy Storybook
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: development/1.0
|
|
5
|
+
branches: [development/1.0]
|
|
6
6
|
jobs:
|
|
7
7
|
deploy:
|
|
8
8
|
runs-on: ubuntu-latest
|
|
9
9
|
steps:
|
|
10
|
-
- uses: actions/checkout@
|
|
11
|
-
- uses: actions/setup-node@
|
|
10
|
+
- uses: actions/checkout@v4
|
|
11
|
+
- uses: actions/setup-node@v4
|
|
12
12
|
with:
|
|
13
|
-
node-version:
|
|
13
|
+
node-version: 20
|
|
14
14
|
- run: npm ci
|
|
15
15
|
- run: npm run storybook:deploy -- --ci
|
|
16
16
|
env:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Accordion.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/accordion/Accordion.component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAUxC,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;
|
|
1
|
+
{"version":3,"file":"Accordion.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/accordion/Accordion.component.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAUxC,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC7B,CAAC;AAkCF,eAAO,MAAM,SAAS,mCAAoC,cAAc,4CAuDvE,CAAC"}
|
|
@@ -5,37 +5,43 @@ import { Box } from '../box/Box';
|
|
|
5
5
|
import { Icon } from '../icon/Icon.component';
|
|
6
6
|
import styled from 'styled-components';
|
|
7
7
|
import { Text } from '../text/Text.component';
|
|
8
|
+
const AccordionContainer = styled(Box) `
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: auto;
|
|
11
|
+
`;
|
|
8
12
|
const AccordionHeader = styled.button `
|
|
9
13
|
-webkit-appearance: none;
|
|
10
14
|
-moz-appearance: none;
|
|
11
15
|
appearance: none;
|
|
12
16
|
border: none;
|
|
13
|
-
gap: ${spacing.r8};
|
|
14
17
|
width: 100%;
|
|
15
18
|
cursor: pointer;
|
|
16
19
|
background-color: transparent;
|
|
17
20
|
color: ${(props) => props.theme.textPrimary};
|
|
18
|
-
padding:
|
|
19
|
-
|
|
21
|
+
padding: 0;
|
|
22
|
+
font-family: 'Lato';
|
|
20
23
|
`;
|
|
21
|
-
const
|
|
24
|
+
const AccordionContent = styled.div `
|
|
22
25
|
overflow: hidden;
|
|
23
26
|
opacity: ${(props) => (props.isOpen ? 1 : 0)};
|
|
24
|
-
transition:
|
|
27
|
+
transition:
|
|
28
|
+
height 0.3s ease-in,
|
|
29
|
+
opacity 0.3s ease-in,
|
|
30
|
+
visibility 0.3s;
|
|
25
31
|
visibility: ${(props) => (props.isOpen ? 'visible' : 'hidden')};
|
|
26
32
|
`;
|
|
27
33
|
const Wrapper = styled.div `
|
|
28
|
-
padding
|
|
34
|
+
padding: ${spacing.r8} 0 ${spacing.r8} 0;
|
|
29
35
|
`;
|
|
30
36
|
export const Accordion = ({ title, id, style, children }) => {
|
|
31
37
|
const [isOpen, setIsOpen] = useState(false);
|
|
32
|
-
const handleToggleContent = () => {
|
|
38
|
+
const handleToggleContent = (e) => {
|
|
33
39
|
setIsOpen((prev) => !prev);
|
|
34
40
|
};
|
|
35
|
-
return (_jsxs(
|
|
41
|
+
return (_jsxs(AccordionContainer, { children: [_jsx("h3", { style: { margin: 0 }, children: _jsx(AccordionHeader, { type: "button", id: `Accordion-header-${id}`, onClick: handleToggleContent, "aria-controls": id, "aria-expanded": isOpen, onKeyDown: (e) => (e.key === 'Enter' || e.key === ' ') && handleToggleContent, children: _jsxs(Stack, { direction: "horizontal", gap: "r8", children: [_jsx(Icon, { name: "Chevron-up", size: "lg", style: {
|
|
36
42
|
transform: isOpen ? 'rotate(0deg)' : 'rotate(180deg)',
|
|
37
43
|
transition: 'transform 0.3s ease-in',
|
|
38
|
-
} }), _jsx(Text, { isEmphazed: true, children: title })] }) }) }), _jsx(
|
|
44
|
+
} }), _jsx(Text, { isEmphazed: true, children: title })] }) }) }), _jsx(AccordionContent, { ref: (element) => {
|
|
39
45
|
if (isOpen) {
|
|
40
46
|
element === null || element === void 0 ? void 0 : element.style.setProperty('height', element.scrollHeight + 'px');
|
|
41
47
|
}
|
package/package.json
CHANGED
|
@@ -15,42 +15,54 @@ export type AccordionProps = {
|
|
|
15
15
|
style?: React.CSSProperties;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
const AccordionContainer = styled(Box)`
|
|
19
|
+
width: 100%;
|
|
20
|
+
height: auto;
|
|
21
|
+
`;
|
|
22
|
+
|
|
18
23
|
const AccordionHeader = styled.button`
|
|
19
24
|
-webkit-appearance: none;
|
|
20
25
|
-moz-appearance: none;
|
|
21
26
|
appearance: none;
|
|
22
27
|
border: none;
|
|
23
|
-
gap: ${spacing.r8};
|
|
24
28
|
width: 100%;
|
|
25
29
|
cursor: pointer;
|
|
26
30
|
background-color: transparent;
|
|
27
31
|
color: ${(props) => props.theme.textPrimary};
|
|
28
|
-
padding:
|
|
29
|
-
|
|
32
|
+
padding: 0;
|
|
33
|
+
font-family: 'Lato';
|
|
30
34
|
`;
|
|
31
|
-
const
|
|
35
|
+
const AccordionContent = styled.div<{
|
|
32
36
|
isOpen: boolean;
|
|
33
37
|
}>`
|
|
34
38
|
overflow: hidden;
|
|
35
39
|
opacity: ${(props) => (props.isOpen ? 1 : 0)};
|
|
36
|
-
transition:
|
|
40
|
+
transition:
|
|
41
|
+
height 0.3s ease-in,
|
|
42
|
+
opacity 0.3s ease-in,
|
|
43
|
+
visibility 0.3s;
|
|
37
44
|
visibility: ${(props) => (props.isOpen ? 'visible' : 'hidden')};
|
|
38
45
|
`;
|
|
39
46
|
const Wrapper = styled.div`
|
|
40
|
-
padding
|
|
47
|
+
padding: ${spacing.r8} 0 ${spacing.r8} 0;
|
|
41
48
|
`;
|
|
42
49
|
|
|
43
50
|
export const Accordion = ({ title, id, style, children }: AccordionProps) => {
|
|
44
51
|
const [isOpen, setIsOpen] = useState(false);
|
|
45
52
|
|
|
46
|
-
const handleToggleContent = (
|
|
53
|
+
const handleToggleContent = (
|
|
54
|
+
e:
|
|
55
|
+
| React.MouseEvent<HTMLButtonElement>
|
|
56
|
+
| React.KeyboardEvent<HTMLButtonElement>,
|
|
57
|
+
) => {
|
|
47
58
|
setIsOpen((prev) => !prev);
|
|
48
59
|
};
|
|
49
60
|
|
|
50
61
|
return (
|
|
51
|
-
<
|
|
62
|
+
<AccordionContainer>
|
|
52
63
|
<h3 style={{ margin: 0 }}>
|
|
53
64
|
<AccordionHeader
|
|
65
|
+
type="button"
|
|
54
66
|
id={`Accordion-header-${id}`}
|
|
55
67
|
onClick={handleToggleContent}
|
|
56
68
|
aria-controls={id}
|
|
@@ -73,7 +85,7 @@ export const Accordion = ({ title, id, style, children }: AccordionProps) => {
|
|
|
73
85
|
</AccordionHeader>
|
|
74
86
|
</h3>
|
|
75
87
|
|
|
76
|
-
<
|
|
88
|
+
<AccordionContent
|
|
77
89
|
ref={(element) => {
|
|
78
90
|
if (isOpen) {
|
|
79
91
|
element?.style.setProperty('height', element.scrollHeight + 'px');
|
|
@@ -87,7 +99,7 @@ export const Accordion = ({ title, id, style, children }: AccordionProps) => {
|
|
|
87
99
|
role="region"
|
|
88
100
|
>
|
|
89
101
|
<Wrapper style={style}>{children}</Wrapper>
|
|
90
|
-
</
|
|
91
|
-
</
|
|
102
|
+
</AccordionContent>
|
|
103
|
+
</AccordionContainer>
|
|
92
104
|
);
|
|
93
105
|
};
|
|
@@ -19,6 +19,13 @@ import * as Stories from './accordion.stories';
|
|
|
19
19
|
Accordions are used to toggle the visibility of content.
|
|
20
20
|
It is used to hide non essential information or to reduce the amount of information displayed on the screen.
|
|
21
21
|
|
|
22
|
+
## Style
|
|
23
|
+
|
|
24
|
+
Accordion component comes with a style prop that can be used to customize the appearance of the accordion content.
|
|
25
|
+
The default style of the accordion container only includes padding.
|
|
26
|
+
|
|
27
|
+
<Canvas of={Stories.WithCustomStyle} />
|
|
28
|
+
|
|
22
29
|
## Playground
|
|
23
30
|
|
|
24
31
|
<Canvas of={Stories.Playground} layout="fullscreen" />
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
|
|
3
|
+
import { useTheme } from 'styled-components';
|
|
4
4
|
import {
|
|
5
5
|
Accordion,
|
|
6
6
|
AccordionProps,
|
|
7
7
|
} from '../../src/lib/components/accordion/Accordion.component';
|
|
8
|
-
import { Stack } from '../../src/lib/spacing';
|
|
9
8
|
import { Button } from '../../src/lib/components/buttonv2/Buttonv2.component';
|
|
9
|
+
import { spacing, Stack } from '../../src/lib/spacing';
|
|
10
|
+
import { Text } from '../../src/lib';
|
|
10
11
|
|
|
11
12
|
type AccordionStory = StoryObj<AccordionProps>;
|
|
12
13
|
|
|
@@ -59,7 +60,29 @@ export const Stacked: AccordionStory = {
|
|
|
59
60
|
<Stack direction="vertical" gap="r8">
|
|
60
61
|
<Accordion {...args} />
|
|
61
62
|
<Accordion {...args} />
|
|
62
|
-
<Accordion {...args}
|
|
63
|
+
<Accordion {...args} />
|
|
63
64
|
</Stack>
|
|
64
65
|
),
|
|
65
66
|
};
|
|
67
|
+
|
|
68
|
+
export const WithCustomStyle: AccordionStory = {
|
|
69
|
+
render: (args) => {
|
|
70
|
+
const { title } = args;
|
|
71
|
+
const theme = useTheme();
|
|
72
|
+
|
|
73
|
+
const style = {
|
|
74
|
+
backgroundColor: theme.statusHealthy,
|
|
75
|
+
borderRadius: spacing.r4,
|
|
76
|
+
padding: spacing.r16,
|
|
77
|
+
margin: spacing.r8,
|
|
78
|
+
};
|
|
79
|
+
return (
|
|
80
|
+
<Accordion {...args} style={style} title={title}>
|
|
81
|
+
<Text>The container of this accordion has a custom style</Text>
|
|
82
|
+
</Accordion>
|
|
83
|
+
);
|
|
84
|
+
},
|
|
85
|
+
args: {
|
|
86
|
+
title: 'Accordion with custom style',
|
|
87
|
+
},
|
|
88
|
+
};
|
package/stories/form.stories.tsx
CHANGED
|
@@ -13,6 +13,7 @@ import { Text } from '../src/lib/components/text/Text.component';
|
|
|
13
13
|
import { Toggle } from '../src/lib/components/toggle/Toggle.component';
|
|
14
14
|
import { Stack } from '../src/lib/spacing';
|
|
15
15
|
import { iconArgType } from './controls';
|
|
16
|
+
import { Accordion } from '../src/lib/next';
|
|
16
17
|
|
|
17
18
|
export default {
|
|
18
19
|
title: 'Templates/Form',
|
|
@@ -251,3 +252,181 @@ export const PageFormWithIcon = {
|
|
|
251
252
|
},
|
|
252
253
|
},
|
|
253
254
|
};
|
|
255
|
+
|
|
256
|
+
export const FormWithAccordion = {
|
|
257
|
+
render: ({ kind, title, subTitle, icon, requireMode }) => {
|
|
258
|
+
const layout = {
|
|
259
|
+
kind,
|
|
260
|
+
title,
|
|
261
|
+
subTitle,
|
|
262
|
+
icon,
|
|
263
|
+
};
|
|
264
|
+
const [toggle, setToggle] = useState(true);
|
|
265
|
+
return (
|
|
266
|
+
<>
|
|
267
|
+
<Form
|
|
268
|
+
layout={layout}
|
|
269
|
+
requireMode={requireMode}
|
|
270
|
+
rightActions={
|
|
271
|
+
<Stack gap={'r16'}>
|
|
272
|
+
<Button variant="outline" label="Cancel" />
|
|
273
|
+
<Button
|
|
274
|
+
variant="primary"
|
|
275
|
+
label="Save"
|
|
276
|
+
icon={<Icon name="Save" />}
|
|
277
|
+
/>
|
|
278
|
+
</Stack>
|
|
279
|
+
}
|
|
280
|
+
banner={
|
|
281
|
+
<Banner
|
|
282
|
+
variant="danger"
|
|
283
|
+
icon={<Icon name="Exclamation-circle" />}
|
|
284
|
+
title={'Error'}
|
|
285
|
+
>
|
|
286
|
+
There is an error
|
|
287
|
+
</Banner>
|
|
288
|
+
}
|
|
289
|
+
>
|
|
290
|
+
<FormSection
|
|
291
|
+
title={{
|
|
292
|
+
name: 'First part entity data',
|
|
293
|
+
helpTooltip: 'Tooltip of the first entity',
|
|
294
|
+
icon: 'Search',
|
|
295
|
+
}}
|
|
296
|
+
>
|
|
297
|
+
<FormGroup
|
|
298
|
+
direction="vertical"
|
|
299
|
+
label="Name"
|
|
300
|
+
id="name"
|
|
301
|
+
labelHelpTooltip="Name Tooltip"
|
|
302
|
+
content={<Input id="name" />}
|
|
303
|
+
help="Optional helper text"
|
|
304
|
+
required
|
|
305
|
+
disabled
|
|
306
|
+
></FormGroup>
|
|
307
|
+
<FormGroup
|
|
308
|
+
direction="horizontal"
|
|
309
|
+
label="Email"
|
|
310
|
+
id="email"
|
|
311
|
+
labelHelpTooltip="Email Tooltip"
|
|
312
|
+
content={<Input id="email" />}
|
|
313
|
+
error="Invalid email format. Try with a better format."
|
|
314
|
+
helpErrorPosition="right"
|
|
315
|
+
required
|
|
316
|
+
></FormGroup>
|
|
317
|
+
</FormSection>
|
|
318
|
+
<FormSection
|
|
319
|
+
title={{
|
|
320
|
+
name: 'Second part entity data',
|
|
321
|
+
helpTooltip: 'Tooltip of the Second entity',
|
|
322
|
+
icon: 'Search',
|
|
323
|
+
}}
|
|
324
|
+
>
|
|
325
|
+
<FormGroup
|
|
326
|
+
direction="horizontal"
|
|
327
|
+
label="Name"
|
|
328
|
+
id="name1"
|
|
329
|
+
labelHelpTooltip="Name Tooltip"
|
|
330
|
+
content={
|
|
331
|
+
<Toggle
|
|
332
|
+
onChange={() => {
|
|
333
|
+
setToggle(!toggle);
|
|
334
|
+
}}
|
|
335
|
+
toggle={toggle}
|
|
336
|
+
name="toggle"
|
|
337
|
+
/>
|
|
338
|
+
}
|
|
339
|
+
help="Optional helper text"
|
|
340
|
+
required={false}
|
|
341
|
+
></FormGroup>
|
|
342
|
+
<FormGroup
|
|
343
|
+
direction="horizontal"
|
|
344
|
+
label="Email"
|
|
345
|
+
id="email1"
|
|
346
|
+
labelHelpTooltip="Email Tooltip"
|
|
347
|
+
content={<Input id="email1" />}
|
|
348
|
+
error="Invalid email format. Try with a better format."
|
|
349
|
+
helpErrorPosition="right"
|
|
350
|
+
required={false}
|
|
351
|
+
></FormGroup>
|
|
352
|
+
<FormGroup
|
|
353
|
+
direction="horizontal"
|
|
354
|
+
label="Email long long long"
|
|
355
|
+
id="email-long1"
|
|
356
|
+
labelHelpTooltip="Email Tooltip"
|
|
357
|
+
content={<Input id="email-long1" />}
|
|
358
|
+
help="optional helper text"
|
|
359
|
+
helpErrorPosition="bottom"
|
|
360
|
+
required={false}
|
|
361
|
+
></FormGroup>
|
|
362
|
+
</FormSection>
|
|
363
|
+
<FormSection>
|
|
364
|
+
<Accordion title="Advanced Settings" id="advanced-settings">
|
|
365
|
+
<FormGroup
|
|
366
|
+
direction="vertical"
|
|
367
|
+
label="Object Lock Mode"
|
|
368
|
+
id="object_lock_mode"
|
|
369
|
+
labelHelpTooltip="S3 Object Lock Retention"
|
|
370
|
+
content={
|
|
371
|
+
<Stack direction="vertical">
|
|
372
|
+
<Stack direction="vertical">
|
|
373
|
+
<Stack>
|
|
374
|
+
<input
|
|
375
|
+
type="radio"
|
|
376
|
+
name="locktype"
|
|
377
|
+
id="locktype-governance"
|
|
378
|
+
value="governance"
|
|
379
|
+
/>
|
|
380
|
+
<label htmlFor="locktype-governance">Governance</label>
|
|
381
|
+
</Stack>
|
|
382
|
+
<Text isEmphazed color="textSecondary" variant="Smaller">
|
|
383
|
+
An user with a specific IAM permissions can
|
|
384
|
+
overwrite/delete protected object versions during the
|
|
385
|
+
retention period.
|
|
386
|
+
</Text>
|
|
387
|
+
</Stack>
|
|
388
|
+
<Stack>
|
|
389
|
+
<input
|
|
390
|
+
type="radio"
|
|
391
|
+
name="locktype"
|
|
392
|
+
id="locktype-compliance"
|
|
393
|
+
value="compliance"
|
|
394
|
+
/>
|
|
395
|
+
<label htmlFor="locktype-compliance">Compliance</label>
|
|
396
|
+
</Stack>
|
|
397
|
+
<Text isEmphazed color="textSecondary" variant="Smaller">
|
|
398
|
+
No one can overwrite protected object versions during the
|
|
399
|
+
retention period.
|
|
400
|
+
</Text>
|
|
401
|
+
</Stack>
|
|
402
|
+
}
|
|
403
|
+
required={true}
|
|
404
|
+
></FormGroup>
|
|
405
|
+
<FormGroup
|
|
406
|
+
id="value-example"
|
|
407
|
+
label="Choose a value"
|
|
408
|
+
helpErrorPosition="bottom"
|
|
409
|
+
required
|
|
410
|
+
content={
|
|
411
|
+
<Select
|
|
412
|
+
id="value-example"
|
|
413
|
+
placeholder="Select an option..."
|
|
414
|
+
onChange={() => {}}
|
|
415
|
+
value={'value-1'}
|
|
416
|
+
>
|
|
417
|
+
<Select.Option value={'value-1'}>Value 1</Select.Option>
|
|
418
|
+
<Select.Option value={'value-2'}>Value 2</Select.Option>
|
|
419
|
+
<Select.Option value={'value-3'}>Value 3</Select.Option>
|
|
420
|
+
</Select>
|
|
421
|
+
}
|
|
422
|
+
/>
|
|
423
|
+
</Accordion>
|
|
424
|
+
</FormSection>
|
|
425
|
+
</Form>
|
|
426
|
+
</>
|
|
427
|
+
);
|
|
428
|
+
},
|
|
429
|
+
args: {
|
|
430
|
+
requireMode: 'partial',
|
|
431
|
+
},
|
|
432
|
+
};
|