@crystallize/design-system 1.3.1 → 1.3.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.md +106 -0
- package/dist/index.css +1813 -0
- package/dist/index.d.ts +345 -2
- package/dist/index.js +2631 -5
- package/dist/index.mjs +2574 -0
- package/package.json +90 -78
- package/readme.md +9 -0
- package/src/Tokens.stories.tsx +18 -0
- package/src/action-menu/ActionMenu.stories.tsx +25 -0
- package/src/action-menu/action-item.tsx +16 -0
- package/src/action-menu/action-menu.css +38 -0
- package/src/action-menu/action-menu.tsx +25 -0
- package/src/action-menu/index.tsx +3 -0
- package/src/avatar/Avatar.stories.tsx +20 -0
- package/src/avatar/avatar.css +23 -0
- package/src/avatar/avatar.tsx +34 -0
- package/src/avatar/get-initials.ts +5 -0
- package/src/avatar/index.ts +1 -0
- package/src/button/Button.stories.tsx +105 -0
- package/src/button/button.css +116 -0
- package/src/button/button.tsx +136 -0
- package/src/button/index.ts +3 -0
- package/src/card/card.css +7 -0
- package/src/card/card.stories.tsx +24 -0
- package/src/card/card.tsx +27 -0
- package/src/card/index.ts +3 -0
- package/src/checkbox/checkbox.css +30 -0
- package/src/checkbox/checkbox.stories.tsx +62 -0
- package/src/checkbox/checkbox.test.tsx +16 -0
- package/src/checkbox/checkbox.tsx +28 -0
- package/src/checkbox/index.ts +1 -0
- package/src/colors/Colors.stories.tsx +127 -0
- package/src/colors/color-defaults.json +15 -0
- package/src/colors/color-pairing.json +12 -0
- package/src/colors/colors.json +158 -0
- package/src/colors/index.ts +1 -0
- package/src/colors/old-to-new.txt +19 -0
- package/src/colors/types.ts +29 -0
- package/src/dialog/Dialog.stories.tsx +168 -0
- package/src/dialog/Dialog.test.tsx +25 -0
- package/src/dialog/config.tsx +139 -0
- package/src/dialog/confirm-dialog.tsx +70 -0
- package/src/dialog/destroyFns.ts +1 -0
- package/src/dialog/dialog.css +27 -0
- package/src/dialog/dialog.tsx +94 -0
- package/src/dialog/index.tsx +40 -0
- package/src/dialog/types.ts +70 -0
- package/src/dropdown-menu/DropdownMenu.stories.tsx +38 -0
- package/src/dropdown-menu/dropdown-menu-item.tsx +15 -0
- package/src/dropdown-menu/dropdown-menu-label.tsx +10 -0
- package/src/dropdown-menu/dropdown-menu-root.tsx +33 -0
- package/src/dropdown-menu/dropdown-menu.css +20 -0
- package/src/dropdown-menu/index.ts +11 -0
- package/src/icon-button/IconButton.stories.tsx +45 -0
- package/src/icon-button/icon-button.css +48 -0
- package/src/icon-button/icon-button.tsx +39 -0
- package/src/icon-button/index.ts +3 -0
- package/src/iconography/Icon.stories.tsx +47 -0
- package/src/iconography/add.tsx +30 -0
- package/src/iconography/arrow.tsx +15 -0
- package/src/iconography/atom.tsx +59 -0
- package/src/iconography/cancel.tsx +26 -0
- package/src/iconography/catalogue.tsx +26 -0
- package/src/iconography/copy.tsx +24 -0
- package/src/iconography/crystal.tsx +93 -0
- package/src/iconography/customers.tsx +38 -0
- package/src/iconography/edit.tsx +30 -0
- package/src/iconography/error.tsx +40 -0
- package/src/iconography/fulfilment.tsx +58 -0
- package/src/iconography/glasses.tsx +62 -0
- package/src/iconography/graphQL.tsx +90 -0
- package/src/iconography/grid.tsx +84 -0
- package/src/iconography/hooks.tsx +26 -0
- package/src/iconography/image.tsx +47 -0
- package/src/iconography/index.ts +63 -0
- package/src/iconography/info.tsx +41 -0
- package/src/iconography/key.tsx +19 -0
- package/src/iconography/language.tsx +38 -0
- package/src/iconography/nail-polish.tsx +84 -0
- package/src/iconography/order.tsx +38 -0
- package/src/iconography/particle.tsx +88 -0
- package/src/iconography/percentage.tsx +44 -0
- package/src/iconography/price-tag.tsx +40 -0
- package/src/iconography/shapes.tsx +48 -0
- package/src/iconography/subscription.tsx +34 -0
- package/src/iconography/topics.tsx +58 -0
- package/src/iconography/triangle.tsx +27 -0
- package/src/iconography/usage.tsx +34 -0
- package/src/iconography/users.tsx +44 -0
- package/src/iconography/warning.tsx +51 -0
- package/src/index.css +14 -0
- package/src/index.ts +33 -0
- package/src/inline-radio/index.ts +1 -0
- package/src/inline-radio/inline-radio.css +36 -0
- package/src/inline-radio/inline-radio.stories.tsx +81 -0
- package/src/inline-radio/inline-radio.tsx +41 -0
- package/src/input/Input.stories.tsx +26 -0
- package/src/input/index.ts +1 -0
- package/src/input/input.css +7 -0
- package/src/input/input.tsx +20 -0
- package/src/input-with-label/InputWithLabel.stories.tsx +98 -0
- package/src/input-with-label/index.ts +3 -0
- package/src/input-with-label/input-with-label.css +35 -0
- package/src/input-with-label/input-with-label.tsx +59 -0
- package/src/label/index.ts +1 -0
- package/src/label/label.css +3 -0
- package/src/label/label.stories.tsx +19 -0
- package/src/label/label.tsx +13 -0
- package/src/progress/Progress.stories.tsx +26 -0
- package/src/progress/index.ts +1 -0
- package/src/progress/progress.css +7 -0
- package/src/progress/progress.tsx +17 -0
- package/src/radio/index.ts +1 -0
- package/src/radio/radio.css +20 -0
- package/src/radio/radio.stories.tsx +142 -0
- package/src/radio/radio.tsx +19 -0
- package/src/select/index.ts +1 -0
- package/src/select/select-item.tsx +18 -0
- package/src/select/select-root.tsx +50 -0
- package/src/select/select.css +44 -0
- package/src/select/select.stories.tsx +74 -0
- package/src/select/select.ts +9 -0
- package/src/slider/Slider.stories.tsx +54 -0
- package/src/slider/index.ts +1 -0
- package/src/slider/slider.css +27 -0
- package/src/slider/slider.tsx +20 -0
- package/src/spinner/Spinner.stories.tsx +19 -0
- package/src/spinner/index.tsx +48 -0
- package/src/spinner/spinner.css +11 -0
- package/src/tag/Tag.stories.tsx +32 -0
- package/src/tag/index.ts +1 -0
- package/src/tag/tag.css +7 -0
- package/src/tag/tag.tsx +27 -0
- package/src/vite-env.d.ts +1 -0
- package/tailwind.config.cjs +51 -0
- package/LICENSE +0 -21
- package/README.md +0 -35
- package/dist/components/Button.d.ts +0 -11
- package/dist/components/Typography.d.ts +0 -14
- package/dist/design-system.cjs.development.js +0 -164
- package/dist/design-system.cjs.development.js.map +0 -1
- package/dist/design-system.cjs.production.min.js +0 -2
- package/dist/design-system.cjs.production.min.js.map +0 -1
- package/dist/design-system.esm.js +0 -156
- package/dist/design-system.esm.js.map +0 -1
- package/dist/styles/theme.d.ts +0 -2
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type Color = {
|
|
2
|
+
50: string;
|
|
3
|
+
100: string;
|
|
4
|
+
200: string;
|
|
5
|
+
300: string;
|
|
6
|
+
400: string;
|
|
7
|
+
500: string;
|
|
8
|
+
600: string;
|
|
9
|
+
700: string;
|
|
10
|
+
800: string;
|
|
11
|
+
900: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ColorName =
|
|
15
|
+
| 'cyan'
|
|
16
|
+
| 'pink'
|
|
17
|
+
| 'gray'
|
|
18
|
+
| 'purple'
|
|
19
|
+
| 'green'
|
|
20
|
+
| 'orange'
|
|
21
|
+
| 's-red'
|
|
22
|
+
| 's-orange'
|
|
23
|
+
| 's-yellow'
|
|
24
|
+
| 's-green'
|
|
25
|
+
| 's-blue'
|
|
26
|
+
| 's-purple'
|
|
27
|
+
| 's-pink';
|
|
28
|
+
|
|
29
|
+
export type Colors = Record<ColorName, Color>;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
|
|
3
|
+
import { Dialog, showDialog, showWarning, showConfirm, showInfo, showError } from '.';
|
|
4
|
+
import { ActionMenu } from '../action-menu';
|
|
5
|
+
import { Button } from '../button';
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Dialog> = {
|
|
8
|
+
title: 'Components/Dialog',
|
|
9
|
+
component: Dialog,
|
|
10
|
+
argTypes: {},
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default meta;
|
|
14
|
+
|
|
15
|
+
type Story = StoryObj<typeof Dialog>;
|
|
16
|
+
|
|
17
|
+
const Lorem = () => (
|
|
18
|
+
<p className="leading-6">
|
|
19
|
+
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Reiciendis neque id, blanditiis exercitationem doloremque
|
|
20
|
+
quam ab minima architecto culpa.
|
|
21
|
+
</p>
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
export const Component: Story = {
|
|
25
|
+
render: () => (
|
|
26
|
+
<Dialog>
|
|
27
|
+
<Dialog.Trigger asChild>
|
|
28
|
+
<Button>Open dialog</Button>
|
|
29
|
+
</Dialog.Trigger>
|
|
30
|
+
<Dialog.Content>
|
|
31
|
+
<Dialog.Title>This is a normal Dialog</Dialog.Title>
|
|
32
|
+
<Dialog.Description>That is described in a declarative way</Dialog.Description>
|
|
33
|
+
<div className="flex items-center justify-between">
|
|
34
|
+
Here will go the main content
|
|
35
|
+
<ActionMenu>
|
|
36
|
+
<ActionMenu.Item onSelect={() => console.warn('Download')}>Download</ActionMenu.Item>
|
|
37
|
+
<ActionMenu.Item className="danger" onSelect={() => console.warn('Delete')}>
|
|
38
|
+
Delete
|
|
39
|
+
</ActionMenu.Item>
|
|
40
|
+
</ActionMenu>
|
|
41
|
+
</div>
|
|
42
|
+
</Dialog.Content>
|
|
43
|
+
</Dialog>
|
|
44
|
+
),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const ComponentWithDangerAction: Story = {
|
|
48
|
+
name: 'With danger action',
|
|
49
|
+
render: () => (
|
|
50
|
+
<Dialog>
|
|
51
|
+
<Dialog.Trigger asChild>
|
|
52
|
+
<Button>Open dialog</Button>
|
|
53
|
+
</Dialog.Trigger>
|
|
54
|
+
<Dialog.Content>
|
|
55
|
+
<Dialog.Title>A Dialog</Dialog.Title>
|
|
56
|
+
<div>
|
|
57
|
+
<Dialog.Description>
|
|
58
|
+
<Lorem />
|
|
59
|
+
</Dialog.Description>
|
|
60
|
+
|
|
61
|
+
<div className="mt-8 flex justify-end gap-4">
|
|
62
|
+
<Button>Cancel</Button>
|
|
63
|
+
<Button intent="danger">Delete</Button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</Dialog.Content>
|
|
67
|
+
</Dialog>
|
|
68
|
+
),
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export const ShowConfirm: Story = {
|
|
72
|
+
name: 'Show confirm',
|
|
73
|
+
render: () => {
|
|
74
|
+
const handleClick = () => {
|
|
75
|
+
showConfirm({
|
|
76
|
+
title: 'We need your confirmation',
|
|
77
|
+
description: 'In order to proceed to you account we need your confirmation',
|
|
78
|
+
content: (
|
|
79
|
+
<p className="my-6">
|
|
80
|
+
We really like cookies and our cookies is what allow us to provide you with an awesome user experience. Do
|
|
81
|
+
you allow us to set some cookies for you?
|
|
82
|
+
</p>
|
|
83
|
+
),
|
|
84
|
+
okText: 'Yes sure',
|
|
85
|
+
cancelText: `I don't really like cookies`,
|
|
86
|
+
onCancel() {
|
|
87
|
+
console.warn('you canceled');
|
|
88
|
+
},
|
|
89
|
+
onOk() {
|
|
90
|
+
console.warn('you confirmed');
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return <Button onClick={handleClick}>showConfirm</Button>;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export const ShowWarning: Story = {
|
|
100
|
+
name: 'Show warning',
|
|
101
|
+
render: () => {
|
|
102
|
+
const handleClick = () => {
|
|
103
|
+
showWarning({
|
|
104
|
+
title: 'A warning',
|
|
105
|
+
description: 'This is a warning dialog',
|
|
106
|
+
content: <Lorem />,
|
|
107
|
+
okText: `That's OK`,
|
|
108
|
+
onOk() {
|
|
109
|
+
console.warn('ok');
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
return <Button onClick={handleClick}>showWarning</Button>;
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export const ShowError: Story = {
|
|
119
|
+
name: 'Show error',
|
|
120
|
+
render: () => {
|
|
121
|
+
const handleClick = () => {
|
|
122
|
+
showError({
|
|
123
|
+
title: 'Error',
|
|
124
|
+
description: 'This is an error dialog',
|
|
125
|
+
content: <Lorem />,
|
|
126
|
+
okText: `That's not good`,
|
|
127
|
+
onOk() {
|
|
128
|
+
console.warn('ok');
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
return <Button onClick={handleClick}>showError</Button>;
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export const ShowInfo: Story = {
|
|
138
|
+
name: 'Show info',
|
|
139
|
+
render: () => {
|
|
140
|
+
const handleClick = () => {
|
|
141
|
+
showInfo({
|
|
142
|
+
title: 'Information',
|
|
143
|
+
description: 'This is an informative dialog',
|
|
144
|
+
content: <Lorem />,
|
|
145
|
+
okText: `I'm fine with that`,
|
|
146
|
+
onOk() {
|
|
147
|
+
console.warn('ok');
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
return <Button onClick={handleClick}>showInfo</Button>;
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const ShowDialog: Story = {
|
|
157
|
+
name: 'Show dialog',
|
|
158
|
+
render: () => {
|
|
159
|
+
const handleClick = () => {
|
|
160
|
+
showDialog({
|
|
161
|
+
title: 'Just to let you know',
|
|
162
|
+
content: <Lorem />,
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
return <Button onClick={handleClick}>showDialog</Button>;
|
|
167
|
+
},
|
|
168
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
|
+
|
|
3
|
+
import { Dialog } from '.';
|
|
4
|
+
import { Button } from '../button';
|
|
5
|
+
|
|
6
|
+
describe('testing the dialog', () => {
|
|
7
|
+
it('should open', () => {
|
|
8
|
+
render(
|
|
9
|
+
<Dialog>
|
|
10
|
+
<Dialog.Trigger asChild>
|
|
11
|
+
<Button>Open dialog</Button>
|
|
12
|
+
</Dialog.Trigger>
|
|
13
|
+
<Dialog.Content>
|
|
14
|
+
<Dialog.Title>This is a normal dialog</Dialog.Title>
|
|
15
|
+
<Dialog.Description>That is described in a declarative way</Dialog.Description>
|
|
16
|
+
<div className="flex items-center justify-between">Hello world!</div>
|
|
17
|
+
</Dialog.Content>
|
|
18
|
+
</Dialog>,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
fireEvent.click(screen.getByText('Open dialog'));
|
|
22
|
+
|
|
23
|
+
expect(screen.getByText('This is a normal dialog')).toBeVisible();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { unmountComponentAtNode, render as DOMRender } from 'react-dom';
|
|
2
|
+
import { ConfirmDialog } from './confirm-dialog';
|
|
3
|
+
|
|
4
|
+
import { destroyFns } from './destroyFns';
|
|
5
|
+
import type { ConfigUpdate, DialogFuncProps } from './types';
|
|
6
|
+
|
|
7
|
+
export function confirm(config: DialogFuncProps) {
|
|
8
|
+
const container = document.createDocumentFragment();
|
|
9
|
+
let currentConfig = { ...config, close, open: true };
|
|
10
|
+
let timeoutId: NodeJS.Timeout;
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
+
function close(...args: any[]) {
|
|
14
|
+
currentConfig = {
|
|
15
|
+
...currentConfig,
|
|
16
|
+
open: false,
|
|
17
|
+
afterClose: () => {
|
|
18
|
+
if (typeof config.afterClose === 'function') {
|
|
19
|
+
config.afterClose();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
destroy.apply(this, args);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
render(currentConfig);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
30
|
+
function destroy(...args: any[]) {
|
|
31
|
+
const triggerCancel = args.some(param => param && param.triggerCancel);
|
|
32
|
+
|
|
33
|
+
if (config.onCancel && triggerCancel) {
|
|
34
|
+
config.onCancel(() => {}, ...args.slice(1));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (let i = 0; i < destroyFns.length; i++) {
|
|
38
|
+
const fn = destroyFns[i];
|
|
39
|
+
|
|
40
|
+
if (fn === close) {
|
|
41
|
+
destroyFns.splice(i, 1);
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
unmountComponentAtNode(container);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function render({ okText, cancelText, ...delegated }: any) {
|
|
50
|
+
clearTimeout(timeoutId);
|
|
51
|
+
|
|
52
|
+
timeoutId = setTimeout(() => {
|
|
53
|
+
DOMRender(<ConfirmDialog {...delegated} okText={okText} cancelText={cancelText} />, container);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function update(configUpdate: ConfigUpdate) {
|
|
58
|
+
if (typeof configUpdate === 'function') {
|
|
59
|
+
currentConfig = configUpdate(currentConfig);
|
|
60
|
+
} else {
|
|
61
|
+
currentConfig = {
|
|
62
|
+
...currentConfig,
|
|
63
|
+
...configUpdate,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
render(currentConfig);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
render(currentConfig);
|
|
71
|
+
|
|
72
|
+
destroyFns.push(close);
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
destroy: close,
|
|
76
|
+
update,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const dumbFn = (event: Event) => {
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export function withDialog(delegated: DialogFuncProps): DialogFuncProps {
|
|
85
|
+
return {
|
|
86
|
+
open: true,
|
|
87
|
+
displayCancel: true,
|
|
88
|
+
displayOk: true,
|
|
89
|
+
...delegated,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function withWarning(delegated: DialogFuncProps): DialogFuncProps {
|
|
94
|
+
return {
|
|
95
|
+
open: true,
|
|
96
|
+
displayCancel: false,
|
|
97
|
+
displayOk: true,
|
|
98
|
+
type: 'warning',
|
|
99
|
+
...delegated,
|
|
100
|
+
onInteractOutside: dumbFn,
|
|
101
|
+
onPointerDownOutside: dumbFn,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function withError(delegated: DialogFuncProps): DialogFuncProps {
|
|
106
|
+
return {
|
|
107
|
+
open: true,
|
|
108
|
+
displayOk: true,
|
|
109
|
+
displayCancel: false,
|
|
110
|
+
type: 'error',
|
|
111
|
+
...delegated,
|
|
112
|
+
onInteractOutside: dumbFn,
|
|
113
|
+
onPointerDownOutside: dumbFn,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function withInfo(delegated: DialogFuncProps): DialogFuncProps {
|
|
118
|
+
return {
|
|
119
|
+
open: true,
|
|
120
|
+
displayOk: true,
|
|
121
|
+
displayCancel: false,
|
|
122
|
+
type: 'info',
|
|
123
|
+
...delegated,
|
|
124
|
+
onInteractOutside: dumbFn,
|
|
125
|
+
onPointerDownOutside: dumbFn,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function withConfirm(delegated: DialogFuncProps): DialogFuncProps {
|
|
130
|
+
return {
|
|
131
|
+
open: true,
|
|
132
|
+
displayOk: true,
|
|
133
|
+
displayCancel: true,
|
|
134
|
+
type: 'info',
|
|
135
|
+
...delegated,
|
|
136
|
+
onInteractOutside: dumbFn,
|
|
137
|
+
onPointerDownOutside: dumbFn,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Dialog } from '.';
|
|
2
|
+
import { Button } from '../button';
|
|
3
|
+
import { DialogRoot } from './dialog';
|
|
4
|
+
import type { ConfirmDialogProps } from './types';
|
|
5
|
+
|
|
6
|
+
export function ConfirmDialog({
|
|
7
|
+
open,
|
|
8
|
+
close,
|
|
9
|
+
title,
|
|
10
|
+
description,
|
|
11
|
+
content,
|
|
12
|
+
okCancel,
|
|
13
|
+
displayCancel,
|
|
14
|
+
displayOk,
|
|
15
|
+
okText = 'OK',
|
|
16
|
+
okButtonIntent = 'default',
|
|
17
|
+
onOk,
|
|
18
|
+
onCancel,
|
|
19
|
+
cancelText = 'Cancel',
|
|
20
|
+
onEscapeKeyDown,
|
|
21
|
+
onInteractOutside,
|
|
22
|
+
onPointerDownOutside,
|
|
23
|
+
type,
|
|
24
|
+
closable,
|
|
25
|
+
}: ConfirmDialogProps) {
|
|
26
|
+
const cancelButton = (okCancel || displayCancel) && (
|
|
27
|
+
<Button
|
|
28
|
+
onClick={() => {
|
|
29
|
+
onCancel?.();
|
|
30
|
+
close();
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
33
|
+
{cancelText}
|
|
34
|
+
</Button>
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const okButton = displayOk && (
|
|
38
|
+
<Button
|
|
39
|
+
intent={okButtonIntent}
|
|
40
|
+
onClick={() => {
|
|
41
|
+
onOk?.();
|
|
42
|
+
close();
|
|
43
|
+
}}
|
|
44
|
+
>
|
|
45
|
+
{okText}
|
|
46
|
+
</Button>
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<DialogRoot open={open} onOpenChange={() => close()}>
|
|
51
|
+
<Dialog.Content
|
|
52
|
+
onEscapeKeyDown={onEscapeKeyDown}
|
|
53
|
+
onInteractOutside={onInteractOutside}
|
|
54
|
+
onPointerDownOutside={onPointerDownOutside}
|
|
55
|
+
type={type}
|
|
56
|
+
closable={closable}
|
|
57
|
+
>
|
|
58
|
+
{title && <Dialog.Title>{title}</Dialog.Title>}
|
|
59
|
+
{description && <Dialog.Description>{description}</Dialog.Description>}
|
|
60
|
+
{content}
|
|
61
|
+
{(displayOk || okCancel || displayCancel) && (
|
|
62
|
+
<div className="mt-4 flex items-center justify-end gap-4">
|
|
63
|
+
{cancelButton}
|
|
64
|
+
{okButton}
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
</Dialog.Content>
|
|
68
|
+
</DialogRoot>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const destroyFns: Array<() => void> = [];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
.c-dialog {
|
|
2
|
+
@apply fixed top-1/2 left-1/2 z-20 w-auto min-w-[25%] max-w-[800px] rounded-lg bg-elevate p-14 leading-6 text-gray-500-400 shadow;
|
|
3
|
+
transform: translate(-50%, -50%);
|
|
4
|
+
&-overlay {
|
|
5
|
+
@apply fixed inset-0 z-10 bg-overlay;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
&-icon {
|
|
9
|
+
@apply my-1 shrink-0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
&-title {
|
|
13
|
+
@apply m-0 font-serif text-xl font-bold text-gray;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
&-description {
|
|
17
|
+
@apply mt-1 mb-5 font-medium;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
&-close-button {
|
|
21
|
+
@apply absolute top-0 right-0 inline-flex h-12 w-12 items-center justify-center rounded-none rounded-tr-lg border !bg-transparent !p-0 !drop-shadow-none hover:!bg-gray-50-900 focus:!bg-gray-50-900;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
&-with-icon {
|
|
25
|
+
@apply flex items-start gap-6 pl-6;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode, RefAttributes } from 'react';
|
|
2
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
3
|
+
import { cva, cx, VariantProps } from 'class-variance-authority';
|
|
4
|
+
|
|
5
|
+
import { Button } from '../button';
|
|
6
|
+
import { Icon } from '../iconography';
|
|
7
|
+
import type { DialogFuncProps } from './types';
|
|
8
|
+
|
|
9
|
+
import './dialog.css';
|
|
10
|
+
|
|
11
|
+
const IconMap = {
|
|
12
|
+
error: Icon.Error,
|
|
13
|
+
info: Icon.Info,
|
|
14
|
+
warning: Icon.Warning,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type DialogContentStylesProps = VariantProps<typeof dialogContentStyles>;
|
|
18
|
+
const dialogContentStyles = cva('c-dialog', {
|
|
19
|
+
variants: {
|
|
20
|
+
withIcon: {
|
|
21
|
+
true: 'c-dialog-with-icon',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
type DialogContentProps = DialogContentStylesProps & {
|
|
27
|
+
children: ReactNode;
|
|
28
|
+
} & Pick<
|
|
29
|
+
DialogFuncProps,
|
|
30
|
+
'onEscapeKeyDown' | 'onInteractOutside' | 'onPointerDownOutside' | 'closable' | 'type' | 'className'
|
|
31
|
+
> &
|
|
32
|
+
DialogPrimitive.DialogContentProps &
|
|
33
|
+
Pick<DialogPrimitive.PortalProps, 'container'>;
|
|
34
|
+
|
|
35
|
+
function DialogContent({ children, closable = true, type, className, container, ...delegated }: DialogContentProps) {
|
|
36
|
+
const withIcon = typeof type !== 'undefined';
|
|
37
|
+
|
|
38
|
+
const IconComponent = type && IconMap[type];
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<DialogPrimitive.Portal container={container}>
|
|
42
|
+
<DialogPrimitive.Overlay className="c-dialog-overlay" />
|
|
43
|
+
<DialogPrimitive.Content className={dialogContentStyles({ withIcon, class: className })} {...delegated}>
|
|
44
|
+
{IconComponent && (
|
|
45
|
+
<div className="flex h-[44px] w-[44px] min-w-[44px] items-center justify-center rounded-lg bg-gray-50-900 p-[5px]">
|
|
46
|
+
<IconComponent className="c-dialog-icon" width={34} height={34} />
|
|
47
|
+
</div>
|
|
48
|
+
)}
|
|
49
|
+
{closable && (
|
|
50
|
+
<DialogClose asChild>
|
|
51
|
+
<Button className="c-dialog-close-button">
|
|
52
|
+
<Icon.Cancel color="density" aria-label="Close" height={16} width={16} />
|
|
53
|
+
</Button>
|
|
54
|
+
</DialogClose>
|
|
55
|
+
)}
|
|
56
|
+
<div>{children}</div>
|
|
57
|
+
</DialogPrimitive.Content>
|
|
58
|
+
</DialogPrimitive.Portal>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type DialogTitleProps = JSX.IntrinsicAttributes & DialogPrimitive.DialogTitleProps & RefAttributes<HTMLHeadingElement>;
|
|
63
|
+
|
|
64
|
+
function DialogTitle({ className, ...delegated }: DialogTitleProps) {
|
|
65
|
+
return <DialogPrimitive.Title className={cx('c-dialog-title', className)} {...delegated} />;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
type DialogDescriptionProps = JSX.IntrinsicAttributes &
|
|
69
|
+
DialogPrimitive.DialogDescriptionProps &
|
|
70
|
+
RefAttributes<HTMLParagraphElement>;
|
|
71
|
+
|
|
72
|
+
function DialogDescription(delegated: DialogDescriptionProps) {
|
|
73
|
+
return <DialogPrimitive.Description className="c-dialog-description" {...delegated} />;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
77
|
+
|
|
78
|
+
const DialogClose = DialogPrimitive.Close;
|
|
79
|
+
|
|
80
|
+
export const DialogRoot = DialogPrimitive.Root;
|
|
81
|
+
|
|
82
|
+
type DialogBaseProps = React.ComponentProps<typeof DialogRoot> & {
|
|
83
|
+
children: ReactNode;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export function DialogBase({ children, ...delegated }: DialogBaseProps) {
|
|
87
|
+
return <DialogRoot {...delegated}>{children}</DialogRoot>;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
DialogBase.Title = DialogTitle;
|
|
91
|
+
DialogBase.Trigger = DialogTrigger;
|
|
92
|
+
DialogBase.Description = DialogDescription;
|
|
93
|
+
DialogBase.Content = DialogContent;
|
|
94
|
+
DialogBase.Overlay = DialogPrimitive.Overlay;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { destroyFns } from './destroyFns';
|
|
2
|
+
import { DialogBase } from './dialog';
|
|
3
|
+
import type { DialogFuncProps } from './types';
|
|
4
|
+
import { confirm, withWarning, withConfirm, withDialog, withError, withInfo } from './config';
|
|
5
|
+
|
|
6
|
+
type DialogType = typeof DialogBase & DialogFuncProps;
|
|
7
|
+
|
|
8
|
+
const Dialog = DialogBase as DialogType;
|
|
9
|
+
|
|
10
|
+
function showDialog(delegated: DialogFuncProps) {
|
|
11
|
+
return confirm(withDialog(delegated));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function showWarning(delegated: DialogFuncProps) {
|
|
15
|
+
return confirm(withWarning(delegated));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function showConfirm(delegated: DialogFuncProps) {
|
|
19
|
+
return confirm(withConfirm(delegated));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function showError(delegated: DialogFuncProps) {
|
|
23
|
+
return confirm(withError(delegated));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function showInfo(delegated: DialogFuncProps) {
|
|
27
|
+
return confirm(withInfo(delegated));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function destroyAll() {
|
|
31
|
+
while (destroyFns.length) {
|
|
32
|
+
const close = destroyFns.pop();
|
|
33
|
+
|
|
34
|
+
if (close) {
|
|
35
|
+
close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { Dialog, destroyAll, showWarning, showConfirm, showDialog, showError, showInfo };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { ReactNode, ComponentProps } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Button } from '../button';
|
|
4
|
+
|
|
5
|
+
export type DialogFuncProps = {
|
|
6
|
+
afterClose?: () => void;
|
|
7
|
+
/**
|
|
8
|
+
* Text that should be displayed in the cancel button
|
|
9
|
+
*/
|
|
10
|
+
cancelText?: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
closable?: boolean;
|
|
13
|
+
content?: ReactNode;
|
|
14
|
+
description?: ReactNode;
|
|
15
|
+
/**
|
|
16
|
+
* Flag that controls if the cancel button should be included in the dialog or not
|
|
17
|
+
*/
|
|
18
|
+
displayCancel?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Flag that controls if the ok button should be included in the dialog or not
|
|
21
|
+
*/
|
|
22
|
+
displayOk?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* @deprecated - Use displayCancel instead
|
|
25
|
+
*
|
|
26
|
+
* Flag that controls if the cancel button should be included in the dialog or not
|
|
27
|
+
*/
|
|
28
|
+
okCancel?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Text that should be displayed in the ok button
|
|
31
|
+
*/
|
|
32
|
+
okText?: ReactNode;
|
|
33
|
+
okButtonIntent?: ComponentProps<typeof Button>['intent'];
|
|
34
|
+
/**
|
|
35
|
+
* The callback that will be called once the user click the cancel button
|
|
36
|
+
* @param args
|
|
37
|
+
* @returns void
|
|
38
|
+
*/
|
|
39
|
+
onCancel?: (...args: unknown[]) => void;
|
|
40
|
+
onEscapeKeyDown?: (event: Event) => void;
|
|
41
|
+
onInteractOutside?: (event: Event) => void;
|
|
42
|
+
/**
|
|
43
|
+
* The callback that will be called once the user click the ok button
|
|
44
|
+
* @param args
|
|
45
|
+
* @returns void
|
|
46
|
+
*/
|
|
47
|
+
onOk?: (...args: unknown[]) => void;
|
|
48
|
+
onPointerDownOutside?: (event: Event) => void;
|
|
49
|
+
open?: boolean;
|
|
50
|
+
prefixCls?: string;
|
|
51
|
+
title?: ReactNode;
|
|
52
|
+
type?: 'info' | 'error' | 'warning';
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type ConfigUpdate = DialogFuncProps | ((prevConfig: DialogFuncProps) => DialogFuncProps);
|
|
56
|
+
|
|
57
|
+
export type DialogFunc = (props: DialogFuncProps) => {
|
|
58
|
+
destroy: () => void;
|
|
59
|
+
update: (configUpdate: ConfigUpdate) => void;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export type ModalStaticFunctions = Record<NonNullable<DialogFuncProps['type']>, DialogFunc>;
|
|
63
|
+
|
|
64
|
+
export interface ConfirmDialogProps extends DialogFuncProps {
|
|
65
|
+
afterClose?: () => void;
|
|
66
|
+
close: (...args: unknown[]) => void;
|
|
67
|
+
autoFocusButton?: null | 'ok' | 'cancel';
|
|
68
|
+
rootPrefixCls: string;
|
|
69
|
+
iconPrefixCls?: string;
|
|
70
|
+
}
|