@westpac/ui 0.4.0 → 0.5.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 +6 -0
- package/dist/components/alert/alert.component.js +2 -1
- package/dist/components/alert/alert.styles.js +2 -2
- package/dist/components/compacta/compacta.component.js +4 -3
- package/dist/components/flexi-cell/flexi-cell.component.js +2 -2
- package/dist/components/flexi-cell/flexi-cell.styles.js +1 -1
- package/dist/components/flexi-cell/flexi-cell.types.d.ts +4 -0
- package/dist/components/flexi-cell/index.d.ts +1 -0
- package/dist/components/flexi-cell/index.js +1 -0
- package/dist/components/icon/index.d.ts +1 -0
- package/dist/components/icon/index.js +1 -0
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +3 -1
- package/dist/components/list/components/item/item.styles.js +1 -1
- package/dist/components/list/list.styles.js +1 -1
- package/dist/components/repeater/index.d.ts +2 -0
- package/dist/components/repeater/index.js +1 -0
- package/dist/components/repeater/repeater.component.d.ts +3 -0
- package/dist/components/repeater/repeater.component.js +141 -0
- package/dist/components/repeater/repeater.stories.d.ts +13 -0
- package/dist/components/repeater/repeater.stories.js +34 -0
- package/dist/components/repeater/repeater.styles.d.ts +39 -0
- package/dist/components/repeater/repeater.styles.js +31 -0
- package/dist/components/repeater/repeater.types.d.ts +19 -0
- package/dist/components/repeater/repeater.types.js +1 -0
- package/dist/components/repeater/repeater.utils.d.ts +2 -0
- package/dist/components/repeater/repeater.utils.js +2 -0
- package/dist/components/selector/components/index.d.ts +2 -0
- package/dist/components/selector/components/index.js +2 -0
- package/dist/components/selector/components/selector-checkbox-group/components/index.d.ts +1 -0
- package/dist/components/selector/components/selector-checkbox-group/components/index.js +1 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/index.d.ts +2 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/index.js +1 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.d.ts +12 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.js +67 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.d.ts +59 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.js +57 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.types.d.ts +10 -0
- package/dist/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.types.js +1 -0
- package/dist/components/selector/components/selector-checkbox-group/index.d.ts +2 -0
- package/dist/components/selector/components/selector-checkbox-group/index.js +1 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.d.ts +15 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.js +49 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.d.ts +3 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.js +13 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.types.d.ts +20 -0
- package/dist/components/selector/components/selector-checkbox-group/selector-checkbox-group.types.js +1 -0
- package/dist/components/selector/components/selector-radio-group/components/index.d.ts +1 -0
- package/dist/components/selector/components/selector-radio-group/components/index.js +1 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/index.d.ts +2 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/index.js +1 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.d.ts +12 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.js +67 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.d.ts +59 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.js +57 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.types.d.ts +15 -0
- package/dist/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.types.js +1 -0
- package/dist/components/selector/components/selector-radio-group/index.d.ts +2 -0
- package/dist/components/selector/components/selector-radio-group/index.js +1 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.d.ts +15 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.component.js +58 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.styles.d.ts +13 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.styles.js +18 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.types.d.ts +17 -0
- package/dist/components/selector/components/selector-radio-group/selector-radio-group.types.js +1 -0
- package/dist/components/selector/index.d.ts +2 -0
- package/dist/components/selector/index.js +1 -0
- package/dist/components/selector/selector.component.d.ts +30 -0
- package/dist/components/selector/selector.component.js +34 -0
- package/dist/components/selector/selector.stories.d.ts +57 -0
- package/dist/components/selector/selector.stories.js +515 -0
- package/dist/components/selector/selector.types.d.ts +20 -0
- package/dist/components/selector/selector.types.js +1 -0
- package/dist/css/westpac-ui.css +150 -0
- package/dist/css/westpac-ui.min.css +150 -0
- package/dist/utils/generateId.d.ts +1 -0
- package/dist/utils/generateId.js +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/package.json +7 -1
- package/src/components/alert/alert.component.tsx +1 -1
- package/src/components/alert/alert.styles.ts +2 -2
- package/src/components/compacta/compacta.component.tsx +4 -3
- package/src/components/flexi-cell/flexi-cell.component.tsx +2 -1
- package/src/components/flexi-cell/flexi-cell.styles.ts +1 -1
- package/src/components/flexi-cell/flexi-cell.types.ts +4 -0
- package/src/components/flexi-cell/index.ts +1 -0
- package/src/components/icon/index.ts +1 -0
- package/src/components/index.ts +3 -1
- package/src/components/list/components/item/item.styles.ts +1 -1
- package/src/components/list/list.styles.ts +1 -1
- package/src/components/repeater/index.ts +2 -0
- package/src/components/repeater/repeater.component.tsx +121 -0
- package/src/components/repeater/repeater.stories.tsx +49 -0
- package/src/components/repeater/repeater.styles.ts +27 -0
- package/src/components/repeater/repeater.types.ts +20 -0
- package/src/components/repeater/repeater.utils.tsx +3 -0
- package/src/components/selector/components/index.ts +2 -0
- package/src/components/selector/components/selector-checkbox-group/components/index.ts +1 -0
- package/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/index.ts +2 -0
- package/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.component.tsx +96 -0
- package/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.styles.ts +53 -0
- package/src/components/selector/components/selector-checkbox-group/components/selector-checkbox-group-option/selector-checkbox-group-option.types.ts +15 -0
- package/src/components/selector/components/selector-checkbox-group/index.ts +2 -0
- package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.component.tsx +46 -0
- package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.styles.ts +9 -0
- package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.types.ts +25 -0
- package/src/components/selector/components/selector-radio-group/components/index.ts +1 -0
- package/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/index.ts +2 -0
- package/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.component.tsx +90 -0
- package/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.styles.ts +53 -0
- package/src/components/selector/components/selector-radio-group/components/selector-radio-group-option/selector-radio-group-option.types.ts +21 -0
- package/src/components/selector/components/selector-radio-group/index.ts +2 -0
- package/src/components/selector/components/selector-radio-group/selector-radio-group.component.tsx +48 -0
- package/src/components/selector/components/selector-radio-group/selector-radio-group.styles.ts +14 -0
- package/src/components/selector/components/selector-radio-group/selector-radio-group.types.ts +22 -0
- package/src/components/selector/index.ts +2 -0
- package/src/components/selector/selector.component.tsx +34 -0
- package/src/components/selector/selector.stories.tsx +621 -0
- package/src/components/selector/selector.types.ts +24 -0
- package/src/utils/generateId.ts +6 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { AnimatePresence, LazyMotion, m } from 'framer-motion';
|
|
2
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { generateID } from '../../utils/index.js';
|
|
5
|
+
import { Button } from '../button/index.js';
|
|
6
|
+
import { AddCircleIcon, IconProps, RemoveCircleIcon } from '../icon/index.js';
|
|
7
|
+
import { VisuallyHidden } from '../index.js';
|
|
8
|
+
|
|
9
|
+
import { styles as repeaterStyles } from './repeater.styles.js';
|
|
10
|
+
import { type RepeaterProps } from './repeater.types.js';
|
|
11
|
+
|
|
12
|
+
interface Action {
|
|
13
|
+
id?: string;
|
|
14
|
+
index: number;
|
|
15
|
+
type: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const loadAnimations = () => import('./repeater.utils.js').then(res => res.default);
|
|
19
|
+
|
|
20
|
+
export function Repeater({
|
|
21
|
+
addText = 'Add another item',
|
|
22
|
+
indexTag: ItemIndex = 'h3',
|
|
23
|
+
children,
|
|
24
|
+
separator = false,
|
|
25
|
+
className,
|
|
26
|
+
}: RepeaterProps) {
|
|
27
|
+
const [items, setItems] = useState([{ id: generateID() }]);
|
|
28
|
+
const [action, setAction] = useState<Action>({ type: '', index: 0 });
|
|
29
|
+
const [status, setStatus] = useState('');
|
|
30
|
+
const refArr = useRef<HTMLElement[]>([]);
|
|
31
|
+
|
|
32
|
+
const handleAdd = useCallback(() => {
|
|
33
|
+
setItems([...items, { id: generateID() }]);
|
|
34
|
+
setAction({ type: 'add', index: items.length });
|
|
35
|
+
}, [items]);
|
|
36
|
+
|
|
37
|
+
const handleRemove = useCallback(
|
|
38
|
+
(id: string, index: number) => {
|
|
39
|
+
const newItems = items.filter(item => item.id !== id);
|
|
40
|
+
setItems(newItems);
|
|
41
|
+
setAction({ type: 'remove', index, id });
|
|
42
|
+
},
|
|
43
|
+
[items],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (action.type === 'add') {
|
|
48
|
+
refArr.current[items.length - 1]?.focus();
|
|
49
|
+
setStatus(`Item added`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (action.type === 'remove') {
|
|
53
|
+
refArr.current.splice(action.index, 1);
|
|
54
|
+
const focusIndex = action.index === 0 ? 0 : action.index - 1;
|
|
55
|
+
refArr.current[focusIndex]?.focus();
|
|
56
|
+
setStatus(`Item ${action.index + 1} removed`);
|
|
57
|
+
}
|
|
58
|
+
}, [items.length, action]);
|
|
59
|
+
|
|
60
|
+
const Tag = separator ? 'ol' : 'ul';
|
|
61
|
+
const styles = repeaterStyles({ separator });
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={styles.base({ className })}>
|
|
65
|
+
<Tag className={styles.list()}>
|
|
66
|
+
<LazyMotion features={loadAnimations}>
|
|
67
|
+
<AnimatePresence>
|
|
68
|
+
{items.map((item, index) => {
|
|
69
|
+
return (
|
|
70
|
+
<m.li
|
|
71
|
+
initial={{ opacity: 1 }}
|
|
72
|
+
animate={{ opacity: 1 }}
|
|
73
|
+
exit={{ opacity: 0 }}
|
|
74
|
+
transition={{ duration: 0.15 }}
|
|
75
|
+
key={index}
|
|
76
|
+
>
|
|
77
|
+
<div
|
|
78
|
+
ref={(el: HTMLDivElement) => {
|
|
79
|
+
refArr.current[index] = el;
|
|
80
|
+
}}
|
|
81
|
+
tabIndex={-1}
|
|
82
|
+
className={styles.item()}
|
|
83
|
+
>
|
|
84
|
+
{separator && <ItemIndex className={styles.itemIndex()}>{index + 1}.</ItemIndex>}
|
|
85
|
+
<div className={styles.content()}>{children}</div>
|
|
86
|
+
{items.length > 1 && (
|
|
87
|
+
<Button
|
|
88
|
+
className={styles.removeBtn()}
|
|
89
|
+
aria-label={`remove item ${index + 1}`}
|
|
90
|
+
iconBefore={(props: IconProps) => <RemoveCircleIcon {...props} aria-hidden size="xsmall" />}
|
|
91
|
+
look="link"
|
|
92
|
+
size="small"
|
|
93
|
+
soft
|
|
94
|
+
onClick={() => handleRemove(item.id, index)}
|
|
95
|
+
>
|
|
96
|
+
Remove
|
|
97
|
+
</Button>
|
|
98
|
+
)}
|
|
99
|
+
</div>
|
|
100
|
+
</m.li>
|
|
101
|
+
);
|
|
102
|
+
})}
|
|
103
|
+
</AnimatePresence>
|
|
104
|
+
</LazyMotion>
|
|
105
|
+
</Tag>
|
|
106
|
+
<div className={styles.footer()}>
|
|
107
|
+
<Button
|
|
108
|
+
className={styles.addBtn()}
|
|
109
|
+
iconBefore={(props: IconProps) => <AddCircleIcon {...props} aria-hidden look="outlined" />}
|
|
110
|
+
look="link"
|
|
111
|
+
size="small"
|
|
112
|
+
soft
|
|
113
|
+
onClick={() => handleAdd()}
|
|
114
|
+
>
|
|
115
|
+
{addText}
|
|
116
|
+
</Button>
|
|
117
|
+
</div>
|
|
118
|
+
<VisuallyHidden role="status">{status}</VisuallyHidden>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Meta, StoryFn, type StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Form, Input } from '../index.js';
|
|
4
|
+
|
|
5
|
+
import { Repeater } from './repeater.component.js';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Repeater> = {
|
|
8
|
+
title: 'Example/Repeater',
|
|
9
|
+
component: Repeater,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
decorators: [
|
|
12
|
+
(Story: StoryFn) => (
|
|
13
|
+
<div className="p-5">
|
|
14
|
+
<Story />
|
|
15
|
+
</div>
|
|
16
|
+
),
|
|
17
|
+
],
|
|
18
|
+
parameters: {
|
|
19
|
+
layout: 'fullscreen',
|
|
20
|
+
},
|
|
21
|
+
args: {
|
|
22
|
+
children: (
|
|
23
|
+
<Form>
|
|
24
|
+
<Form.Group>
|
|
25
|
+
<Form.Label htmlFor={`test`}>Primary</Form.Label>
|
|
26
|
+
<Form.Hint>Primary title text</Form.Hint>
|
|
27
|
+
<Input name={`test`} onChange={(e: any) => console.log(e)} />
|
|
28
|
+
</Form.Group>
|
|
29
|
+
</Form>
|
|
30
|
+
),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default meta;
|
|
35
|
+
type Story = StoryObj<typeof meta>;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* > Default usage example
|
|
39
|
+
*/
|
|
40
|
+
export const DefaultStory: Story = {
|
|
41
|
+
args: {},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* > Example using the separator prop
|
|
46
|
+
*/
|
|
47
|
+
export const SeparatedRepeater: Story = {
|
|
48
|
+
args: { separator: true },
|
|
49
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
export const styles = tv(
|
|
4
|
+
{
|
|
5
|
+
slots: {
|
|
6
|
+
base: '',
|
|
7
|
+
list: 'm-0 list-none pl-0',
|
|
8
|
+
item: 'relative focus:outline-none',
|
|
9
|
+
itemIndex: 'mb-[1.125rem] font-bold',
|
|
10
|
+
content: '',
|
|
11
|
+
removeBtn: 'absolute right-0 top-0 h-auto p-0 no-underline hover:underline',
|
|
12
|
+
footer: 'flex justify-between',
|
|
13
|
+
addBtn: 'height-auto p-0 no-underline hover:underline',
|
|
14
|
+
},
|
|
15
|
+
variants: {
|
|
16
|
+
separator: {
|
|
17
|
+
true: {
|
|
18
|
+
item: 'border-neutral border-t-2 pt-[0.625rem]',
|
|
19
|
+
content: 'p-[0_1.125rem_2.625rem]',
|
|
20
|
+
removeBtn: 'relative m-[0_0_1.875rem_1.125rem]',
|
|
21
|
+
footer: 'border-neutral border-t-2 pt-[0.875rem]',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{ responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
|
|
27
|
+
);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HTMLAttributes } from 'react';
|
|
2
|
+
|
|
3
|
+
export type RepeaterProps = {
|
|
4
|
+
/**
|
|
5
|
+
* Text for add button
|
|
6
|
+
*/
|
|
7
|
+
addText?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Component to repeat
|
|
10
|
+
*/
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Index heading tag to use for index on separator version
|
|
14
|
+
*/
|
|
15
|
+
indexTag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
|
|
16
|
+
/**
|
|
17
|
+
* Enable separator version
|
|
18
|
+
*/
|
|
19
|
+
separator?: boolean;
|
|
20
|
+
} & HTMLAttributes<Element>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './selector-checkbox-group-option/index.js';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import React, { forwardRef, useContext, useRef } from 'react';
|
|
2
|
+
import { VisuallyHidden, useCheckboxGroupItem, useFocusRing } from 'react-aria';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
FlexiCellAdornment,
|
|
6
|
+
FlexiCellBody,
|
|
7
|
+
FlexiCellButton,
|
|
8
|
+
FlexiCellCircle,
|
|
9
|
+
FlexiCellFooter,
|
|
10
|
+
FlexiCellHint,
|
|
11
|
+
FlexiCellLabel,
|
|
12
|
+
} from '../../../../../../components/flexi-cell/index.js';
|
|
13
|
+
import { ArrowRightIcon, TickIcon } from '../../../../../../components/icon/index.js';
|
|
14
|
+
import { FlexiCell } from '../../../../../../components/index.js';
|
|
15
|
+
import { SelectorCheckboxGroupContext } from '../../selector-checkbox-group.component.js';
|
|
16
|
+
|
|
17
|
+
import { styles as selectorCheckboxGroupOptionStyles } from './selector-checkbox-group-option.styles.js';
|
|
18
|
+
import { type SelectorCheckboxGroupOptionProps } from './selector-checkbox-group-option.types.js';
|
|
19
|
+
|
|
20
|
+
function BaseSelectorCheckboxGroupOption(
|
|
21
|
+
{
|
|
22
|
+
className,
|
|
23
|
+
children,
|
|
24
|
+
value,
|
|
25
|
+
withBorder = true,
|
|
26
|
+
withArrow,
|
|
27
|
+
after,
|
|
28
|
+
badge,
|
|
29
|
+
badgeZIndex,
|
|
30
|
+
before,
|
|
31
|
+
body = true,
|
|
32
|
+
checkIcon = 'checkbox',
|
|
33
|
+
...props
|
|
34
|
+
}: SelectorCheckboxGroupOptionProps,
|
|
35
|
+
ref: any,
|
|
36
|
+
) {
|
|
37
|
+
const state = useContext(SelectorCheckboxGroupContext);
|
|
38
|
+
const localRef = useRef(null);
|
|
39
|
+
const { inputProps, isDisabled, isSelected } = useCheckboxGroupItem({ ...props, value, children }, state, localRef);
|
|
40
|
+
const { isFocusVisible, focusProps } = useFocusRing();
|
|
41
|
+
const styles = selectorCheckboxGroupOptionStyles({
|
|
42
|
+
className,
|
|
43
|
+
isSelected,
|
|
44
|
+
isFocusVisible,
|
|
45
|
+
isDisabled,
|
|
46
|
+
checkIcon,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const FinalIcon = checkIcon === 'checkbox' ? TickIcon : ArrowRightIcon;
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<FlexiCell
|
|
53
|
+
after={
|
|
54
|
+
<div className="flex gap-2">
|
|
55
|
+
{after}
|
|
56
|
+
<FinalIcon aria-hidden="true" className={styles.icon({})} />
|
|
57
|
+
</div>
|
|
58
|
+
}
|
|
59
|
+
badge={badge}
|
|
60
|
+
badgeZIndex={badgeZIndex}
|
|
61
|
+
before={before}
|
|
62
|
+
body={body}
|
|
63
|
+
withBorder={withBorder}
|
|
64
|
+
withArrow={withArrow}
|
|
65
|
+
tag="label"
|
|
66
|
+
ref={ref}
|
|
67
|
+
withHoverEffect
|
|
68
|
+
className={styles.base({})}
|
|
69
|
+
>
|
|
70
|
+
<VisuallyHidden>
|
|
71
|
+
<input {...inputProps} {...focusProps} ref={localRef} />
|
|
72
|
+
</VisuallyHidden>
|
|
73
|
+
{children}
|
|
74
|
+
</FlexiCell>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export const SelectorCheckboxGroupOption = forwardRef(
|
|
79
|
+
BaseSelectorCheckboxGroupOption,
|
|
80
|
+
) as React.ForwardRefExoticComponent<SelectorCheckboxGroupOptionProps & React.RefAttributes<unknown>> & {
|
|
81
|
+
Adornment: typeof FlexiCell.Adornment;
|
|
82
|
+
Body: typeof FlexiCell.Body;
|
|
83
|
+
Button: typeof FlexiCell.Button;
|
|
84
|
+
Circle: typeof FlexiCell.Circle;
|
|
85
|
+
Footer: typeof FlexiCell.Footer;
|
|
86
|
+
Hint: typeof FlexiCell.Hint;
|
|
87
|
+
Label: typeof FlexiCell.Label;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
SelectorCheckboxGroupOption.Body = FlexiCellBody;
|
|
91
|
+
SelectorCheckboxGroupOption.Footer = FlexiCellFooter;
|
|
92
|
+
SelectorCheckboxGroupOption.Adornment = FlexiCellAdornment;
|
|
93
|
+
SelectorCheckboxGroupOption.Hint = FlexiCellHint;
|
|
94
|
+
SelectorCheckboxGroupOption.Label = FlexiCellLabel;
|
|
95
|
+
SelectorCheckboxGroupOption.Button = FlexiCellButton;
|
|
96
|
+
SelectorCheckboxGroupOption.Circle = FlexiCellCircle;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
export const styles = tv(
|
|
4
|
+
{
|
|
5
|
+
slots: {
|
|
6
|
+
base: 'group/checkbox-option cursor-pointer',
|
|
7
|
+
icon: 'transition-transform',
|
|
8
|
+
},
|
|
9
|
+
variants: {
|
|
10
|
+
checkIcon: {
|
|
11
|
+
arrow: {
|
|
12
|
+
icon: 'text-primary group-hover/checkbox-option:translate-x-1',
|
|
13
|
+
},
|
|
14
|
+
checkbox: {},
|
|
15
|
+
},
|
|
16
|
+
isSelected: {
|
|
17
|
+
true: {
|
|
18
|
+
base: 'border-hero shadow-[0_0_0_2px_inset]',
|
|
19
|
+
},
|
|
20
|
+
false: {},
|
|
21
|
+
},
|
|
22
|
+
isFocusVisible: {
|
|
23
|
+
true: {
|
|
24
|
+
base: 'focus-outline',
|
|
25
|
+
},
|
|
26
|
+
false: {},
|
|
27
|
+
},
|
|
28
|
+
isDisabled: {
|
|
29
|
+
true: {
|
|
30
|
+
base: 'opacity-50',
|
|
31
|
+
},
|
|
32
|
+
false: {},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
compoundVariants: [
|
|
36
|
+
{
|
|
37
|
+
checkIcon: 'checkbox',
|
|
38
|
+
isSelected: false,
|
|
39
|
+
className: {
|
|
40
|
+
icon: 'opacity-0',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
checkIcon: 'checkbox',
|
|
45
|
+
isSelected: true,
|
|
46
|
+
className: {
|
|
47
|
+
icon: 'opacity-100',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
|
|
53
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type AriaCheckboxGroupItemProps } from 'react-aria';
|
|
2
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
3
|
+
|
|
4
|
+
import { FlexiCellProps } from '../../../../../index.js';
|
|
5
|
+
|
|
6
|
+
import { styles } from './selector-checkbox-group-option.styles.js';
|
|
7
|
+
|
|
8
|
+
export type SelectorCheckboxGroupOptionProps = {
|
|
9
|
+
/**
|
|
10
|
+
* Check icon to render
|
|
11
|
+
*/
|
|
12
|
+
checkIcon?: 'checkbox' | 'arrow';
|
|
13
|
+
} & FlexiCellProps &
|
|
14
|
+
VariantProps<typeof styles> &
|
|
15
|
+
Omit<AriaCheckboxGroupItemProps, 'isIndeterminate'>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React, { createContext } from 'react';
|
|
2
|
+
import { useCheckboxGroup } from 'react-aria';
|
|
3
|
+
import { useCheckboxGroupState } from 'react-stately';
|
|
4
|
+
|
|
5
|
+
import { SelectorCheckboxGroupOption } from './components/index.js';
|
|
6
|
+
import { styles } from './selector-checkbox-group.styles.js';
|
|
7
|
+
import {
|
|
8
|
+
type SelectorCheckboxGroupContextState,
|
|
9
|
+
type SelectorCheckboxGroupProps,
|
|
10
|
+
} from './selector-checkbox-group.types.js';
|
|
11
|
+
|
|
12
|
+
export const SelectorCheckboxGroupContext = createContext<SelectorCheckboxGroupContextState>({
|
|
13
|
+
value: [],
|
|
14
|
+
isDisabled: false,
|
|
15
|
+
isReadOnly: false,
|
|
16
|
+
isSelected: () => false,
|
|
17
|
+
setValue: () => null,
|
|
18
|
+
addValue: () => null,
|
|
19
|
+
removeValue: () => null,
|
|
20
|
+
toggleValue: () => null,
|
|
21
|
+
validationState: 'valid',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export function SelectorCheckboxGroup(props: SelectorCheckboxGroupProps) {
|
|
25
|
+
const { children, label, description, errorMessage } = props;
|
|
26
|
+
const state = useCheckboxGroupState(props);
|
|
27
|
+
const { groupProps, labelProps, descriptionProps, errorMessageProps } = useCheckboxGroup(props, state);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div {...groupProps} className={styles({ className: groupProps.className })}>
|
|
31
|
+
<span {...labelProps}>{label}</span>
|
|
32
|
+
<SelectorCheckboxGroupContext.Provider value={state}>{children}</SelectorCheckboxGroupContext.Provider>
|
|
33
|
+
{description && (
|
|
34
|
+
<div {...descriptionProps} style={{ fontSize: 12 }}>
|
|
35
|
+
{description}
|
|
36
|
+
</div>
|
|
37
|
+
)}
|
|
38
|
+
{errorMessage && state.validationState === 'invalid' && (
|
|
39
|
+
<div {...errorMessageProps} className="typography-body-10 text-danger">
|
|
40
|
+
{errorMessage}
|
|
41
|
+
</div>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
SelectorCheckboxGroup.Option = SelectorCheckboxGroupOption;
|
package/src/components/selector/components/selector-checkbox-group/selector-checkbox-group.types.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { AriaCheckboxGroupProps } from 'react-aria';
|
|
3
|
+
import { CheckboxGroupState } from 'react-stately';
|
|
4
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
5
|
+
|
|
6
|
+
import { styles } from './selector-checkbox-group.styles.js';
|
|
7
|
+
|
|
8
|
+
export type SelectorCheckboxGroupContextState = CheckboxGroupState;
|
|
9
|
+
|
|
10
|
+
export type SelectorCheckboxGroupProps = {
|
|
11
|
+
/**
|
|
12
|
+
* String to override base style
|
|
13
|
+
*/
|
|
14
|
+
className?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Orientation of checkbox items
|
|
17
|
+
*/
|
|
18
|
+
orientation?: 'horizontal' | 'vertical';
|
|
19
|
+
/**
|
|
20
|
+
* Controls size of `CheckboxItem` components, can't be applied directly to `CheckboxItem`
|
|
21
|
+
*/
|
|
22
|
+
size?: 'medium' | 'large';
|
|
23
|
+
} & AriaCheckboxGroupProps &
|
|
24
|
+
VariantProps<typeof styles> &
|
|
25
|
+
Omit<HTMLAttributes<Element>, 'onChange'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './selector-radio-group-option/index.js';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React, { forwardRef, useContext, useRef } from 'react';
|
|
2
|
+
import { VisuallyHidden, useFocusRing, useRadio } from 'react-aria';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
FlexiCellAdornment,
|
|
6
|
+
FlexiCellBody,
|
|
7
|
+
FlexiCellButton,
|
|
8
|
+
FlexiCellCircle,
|
|
9
|
+
FlexiCellFooter,
|
|
10
|
+
FlexiCellHint,
|
|
11
|
+
FlexiCellLabel,
|
|
12
|
+
} from '../../../../../../components/flexi-cell/index.js';
|
|
13
|
+
import { ArrowRightIcon, TickIcon } from '../../../../../../components/icon/index.js';
|
|
14
|
+
import { FlexiCell } from '../../../../../index.js';
|
|
15
|
+
import { SelectorRadioGroupContext } from '../../selector-radio-group.component.js';
|
|
16
|
+
|
|
17
|
+
import { styles as selectorRadioGroupOptionStyles } from './selector-radio-group-option.styles.js';
|
|
18
|
+
import { type SelectorRadioGroupOptionProps } from './selector-radio-group-option.types.js';
|
|
19
|
+
|
|
20
|
+
function BaseSelectorRadioGroupOption(
|
|
21
|
+
{
|
|
22
|
+
className,
|
|
23
|
+
children,
|
|
24
|
+
value,
|
|
25
|
+
withBorder = true,
|
|
26
|
+
withArrow,
|
|
27
|
+
after,
|
|
28
|
+
badge,
|
|
29
|
+
badgeZIndex,
|
|
30
|
+
before,
|
|
31
|
+
body = true,
|
|
32
|
+
checkIcon = 'checkbox',
|
|
33
|
+
...props
|
|
34
|
+
}: SelectorRadioGroupOptionProps,
|
|
35
|
+
ref: any,
|
|
36
|
+
) {
|
|
37
|
+
const state = useContext(SelectorRadioGroupContext);
|
|
38
|
+
const localRef = useRef(null);
|
|
39
|
+
const { inputProps, isSelected, isDisabled } = useRadio({ ...props, value, children }, state, localRef);
|
|
40
|
+
const { isFocusVisible, focusProps } = useFocusRing();
|
|
41
|
+
const styles = selectorRadioGroupOptionStyles({ className, isSelected, isFocusVisible, isDisabled, checkIcon });
|
|
42
|
+
|
|
43
|
+
const FinalIcon = checkIcon === 'checkbox' ? TickIcon : ArrowRightIcon;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<FlexiCell
|
|
47
|
+
after={
|
|
48
|
+
<div className="flex gap-2">
|
|
49
|
+
{after}
|
|
50
|
+
<FinalIcon aria-hidden="true" className={styles.icon({})} />
|
|
51
|
+
</div>
|
|
52
|
+
}
|
|
53
|
+
badge={badge}
|
|
54
|
+
badgeZIndex={badgeZIndex}
|
|
55
|
+
before={before}
|
|
56
|
+
body={body}
|
|
57
|
+
withBorder={withBorder}
|
|
58
|
+
withArrow={withArrow}
|
|
59
|
+
tag="label"
|
|
60
|
+
ref={ref}
|
|
61
|
+
className={styles.base({})}
|
|
62
|
+
withHoverEffect
|
|
63
|
+
>
|
|
64
|
+
<VisuallyHidden>
|
|
65
|
+
<input {...inputProps} {...focusProps} ref={localRef} />
|
|
66
|
+
</VisuallyHidden>
|
|
67
|
+
{children}
|
|
68
|
+
</FlexiCell>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export const SelectorRadioGroupOption = forwardRef(BaseSelectorRadioGroupOption) as React.ForwardRefExoticComponent<
|
|
73
|
+
SelectorRadioGroupOptionProps & React.RefAttributes<unknown>
|
|
74
|
+
> & {
|
|
75
|
+
Adornment: typeof FlexiCell.Adornment;
|
|
76
|
+
Body: typeof FlexiCell.Body;
|
|
77
|
+
Button: typeof FlexiCell.Button;
|
|
78
|
+
Circle: typeof FlexiCell.Circle;
|
|
79
|
+
Footer: typeof FlexiCell.Footer;
|
|
80
|
+
Hint: typeof FlexiCell.Hint;
|
|
81
|
+
Label: typeof FlexiCell.Label;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
SelectorRadioGroupOption.Body = FlexiCellBody;
|
|
85
|
+
SelectorRadioGroupOption.Footer = FlexiCellFooter;
|
|
86
|
+
SelectorRadioGroupOption.Adornment = FlexiCellAdornment;
|
|
87
|
+
SelectorRadioGroupOption.Hint = FlexiCellHint;
|
|
88
|
+
SelectorRadioGroupOption.Label = FlexiCellLabel;
|
|
89
|
+
SelectorRadioGroupOption.Button = FlexiCellButton;
|
|
90
|
+
SelectorRadioGroupOption.Circle = FlexiCellCircle;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { tv } from 'tailwind-variants';
|
|
2
|
+
|
|
3
|
+
export const styles = tv(
|
|
4
|
+
{
|
|
5
|
+
slots: {
|
|
6
|
+
base: 'group/radio-option cursor-pointer',
|
|
7
|
+
icon: 'transition-transform',
|
|
8
|
+
},
|
|
9
|
+
variants: {
|
|
10
|
+
checkIcon: {
|
|
11
|
+
arrow: {
|
|
12
|
+
icon: 'text-primary group-hover/radio-option:translate-x-1',
|
|
13
|
+
},
|
|
14
|
+
checkbox: {},
|
|
15
|
+
},
|
|
16
|
+
isSelected: {
|
|
17
|
+
true: {
|
|
18
|
+
base: 'border-hero shadow-[0_0_0_2px_inset] shadow-hero',
|
|
19
|
+
},
|
|
20
|
+
false: {},
|
|
21
|
+
},
|
|
22
|
+
isFocusVisible: {
|
|
23
|
+
true: {
|
|
24
|
+
base: 'focus-outline',
|
|
25
|
+
},
|
|
26
|
+
false: {},
|
|
27
|
+
},
|
|
28
|
+
isDisabled: {
|
|
29
|
+
true: {
|
|
30
|
+
base: 'opacity-50',
|
|
31
|
+
},
|
|
32
|
+
false: {},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
compoundVariants: [
|
|
36
|
+
{
|
|
37
|
+
checkIcon: 'checkbox',
|
|
38
|
+
isSelected: false,
|
|
39
|
+
className: {
|
|
40
|
+
icon: 'opacity-0',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
checkIcon: 'checkbox',
|
|
45
|
+
isSelected: true,
|
|
46
|
+
className: {
|
|
47
|
+
icon: 'opacity-100',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
{ responsiveVariants: ['xsl', 'sm', 'md', 'lg', 'xl'] },
|
|
53
|
+
);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { type AriaRadioProps } from 'react-aria';
|
|
3
|
+
import { type VariantProps } from 'tailwind-variants';
|
|
4
|
+
|
|
5
|
+
import { type FlexiCellProps } from '../../../../../../index.js';
|
|
6
|
+
|
|
7
|
+
import { styles } from './selector-radio-group-option.styles.js';
|
|
8
|
+
|
|
9
|
+
export type SelectorRadioGroupOptionProps = {
|
|
10
|
+
/**
|
|
11
|
+
* Check icon to render
|
|
12
|
+
*/
|
|
13
|
+
checkIcon?: 'checkbox' | 'arrow';
|
|
14
|
+
/**
|
|
15
|
+
* Tag to render
|
|
16
|
+
*/
|
|
17
|
+
tag?: keyof JSX.IntrinsicElements;
|
|
18
|
+
} & FlexiCellProps &
|
|
19
|
+
AriaRadioProps &
|
|
20
|
+
VariantProps<typeof styles> &
|
|
21
|
+
HTMLAttributes<Element>;
|