@a-type/ui 2.6.1 → 2.7.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/dist/cjs/components/button/Button.d.ts +14 -1
- package/dist/cjs/components/button/Button.js +84 -8
- package/dist/cjs/components/button/Button.js.map +1 -1
- package/dist/cjs/components/button/Button.stories.d.ts +14 -1
- package/dist/cjs/components/button/Button.stories.js +27 -6
- package/dist/cjs/components/button/Button.stories.js.map +1 -1
- package/dist/cjs/components/button/classes.d.ts +2 -2
- package/dist/cjs/components/button/classes.js +12 -7
- package/dist/cjs/components/button/classes.js.map +1 -1
- package/dist/cjs/components/camera/Camera.js +3 -3
- package/dist/cjs/components/camera/Camera.js.map +1 -1
- package/dist/cjs/components/card/Card.d.ts +2 -2
- package/dist/cjs/components/card/Card.stories.js +7 -7
- package/dist/cjs/components/card/Card.stories.js.map +1 -1
- package/dist/cjs/components/contextMenu/contextMenu.js +2 -2
- package/dist/cjs/components/contextMenu/contextMenu.js.map +1 -1
- package/dist/cjs/components/datePicker/DatePicker.js +4 -4
- package/dist/cjs/components/datePicker/DatePicker.js.map +1 -1
- package/dist/cjs/components/dropdownMenu/DropdownMenu.js +5 -5
- package/dist/cjs/components/dropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/cjs/components/emojiPicker/EmojiPicker.js +2 -2
- package/dist/cjs/components/emojiPicker/EmojiPicker.js.map +1 -1
- package/dist/cjs/components/horizontalList/HorizontalList.js +1 -1
- package/dist/cjs/components/horizontalList/HorizontalList.js.map +1 -1
- package/dist/cjs/components/horizontalList/HorizontalList.stories.js +2 -2
- package/dist/cjs/components/horizontalList/HorizontalList.stories.js.map +1 -1
- package/dist/cjs/components/icon/Icon.js +7 -1
- package/dist/cjs/components/icon/Icon.js.map +1 -1
- package/dist/cjs/components/icon/IconLoadingContext.d.ts +2 -0
- package/dist/cjs/components/icon/IconLoadingContext.js +12 -0
- package/dist/cjs/components/icon/IconLoadingContext.js.map +1 -0
- package/dist/cjs/components/imageUploader/ImageUploader.js +1 -1
- package/dist/cjs/components/imageUploader/ImageUploader.js.map +1 -1
- package/dist/cjs/components/particles/ParticleLayer.stories.js +1 -1
- package/dist/cjs/components/particles/ParticleLayer.stories.js.map +1 -1
- package/dist/cjs/components/select/Select.js +8 -4
- package/dist/cjs/components/select/Select.js.map +1 -1
- package/dist/cjs/components/spinner/Spinner.js +1 -1
- package/dist/cjs/components/spinner/Spinner.js.map +1 -1
- package/dist/cjs/themes.stories.d.ts +1 -0
- package/dist/cjs/themes.stories.js +3 -2
- package/dist/cjs/themes.stories.js.map +1 -1
- package/dist/cjs/uno/colors.d.ts +1 -0
- package/dist/cjs/uno/colors.js +1 -0
- package/dist/cjs/uno/colors.js.map +1 -1
- package/dist/cjs/uno/shadows.js +11 -8
- package/dist/cjs/uno/shadows.js.map +1 -1
- package/dist/css/main.css +12 -12
- package/dist/esm/components/button/Button.d.ts +14 -1
- package/dist/esm/components/button/Button.js +82 -7
- package/dist/esm/components/button/Button.js.map +1 -1
- package/dist/esm/components/button/Button.stories.d.ts +14 -1
- package/dist/esm/components/button/Button.stories.js +27 -6
- package/dist/esm/components/button/Button.stories.js.map +1 -1
- package/dist/esm/components/button/classes.d.ts +2 -2
- package/dist/esm/components/button/classes.js +13 -8
- package/dist/esm/components/button/classes.js.map +1 -1
- package/dist/esm/components/camera/Camera.js +3 -3
- package/dist/esm/components/camera/Camera.js.map +1 -1
- package/dist/esm/components/card/Card.d.ts +2 -2
- package/dist/esm/components/card/Card.stories.js +7 -7
- package/dist/esm/components/card/Card.stories.js.map +1 -1
- package/dist/esm/components/contextMenu/contextMenu.js +2 -2
- package/dist/esm/components/contextMenu/contextMenu.js.map +1 -1
- package/dist/esm/components/datePicker/DatePicker.js +4 -4
- package/dist/esm/components/datePicker/DatePicker.js.map +1 -1
- package/dist/esm/components/dropdownMenu/DropdownMenu.js +5 -5
- package/dist/esm/components/dropdownMenu/DropdownMenu.js.map +1 -1
- package/dist/esm/components/emojiPicker/EmojiPicker.js +2 -2
- package/dist/esm/components/emojiPicker/EmojiPicker.js.map +1 -1
- package/dist/esm/components/horizontalList/HorizontalList.js +1 -1
- package/dist/esm/components/horizontalList/HorizontalList.js.map +1 -1
- package/dist/esm/components/horizontalList/HorizontalList.stories.js +2 -2
- package/dist/esm/components/horizontalList/HorizontalList.stories.js.map +1 -1
- package/dist/esm/components/icon/Icon.js +7 -1
- package/dist/esm/components/icon/Icon.js.map +1 -1
- package/dist/esm/components/icon/IconLoadingContext.d.ts +2 -0
- package/dist/esm/components/icon/IconLoadingContext.js +8 -0
- package/dist/esm/components/icon/IconLoadingContext.js.map +1 -0
- package/dist/esm/components/imageUploader/ImageUploader.js +1 -1
- package/dist/esm/components/imageUploader/ImageUploader.js.map +1 -1
- package/dist/esm/components/particles/ParticleLayer.stories.js +1 -1
- package/dist/esm/components/particles/ParticleLayer.stories.js.map +1 -1
- package/dist/esm/components/select/Select.js +8 -4
- package/dist/esm/components/select/Select.js.map +1 -1
- package/dist/esm/components/spinner/Spinner.js +1 -1
- package/dist/esm/components/spinner/Spinner.js.map +1 -1
- package/dist/esm/themes.stories.d.ts +1 -0
- package/dist/esm/themes.stories.js +3 -2
- package/dist/esm/themes.stories.js.map +1 -1
- package/dist/esm/uno/colors.d.ts +1 -0
- package/dist/esm/uno/colors.js +1 -0
- package/dist/esm/uno/colors.js.map +1 -1
- package/dist/esm/uno/shadows.js +11 -8
- package/dist/esm/uno/shadows.js.map +1 -1
- package/package.json +2 -1
- package/src/components/button/Button.stories.tsx +47 -7
- package/src/components/button/Button.tsx +137 -14
- package/src/components/button/classes.tsx +19 -11
- package/src/components/camera/Camera.tsx +1 -7
- package/src/components/card/Card.stories.tsx +10 -10
- package/src/components/contextMenu/contextMenu.tsx +3 -5
- package/src/components/datePicker/DatePicker.tsx +0 -4
- package/src/components/dropdownMenu/DropdownMenu.tsx +7 -6
- package/src/components/emojiPicker/EmojiPicker.tsx +4 -4
- package/src/components/horizontalList/HorizontalList.stories.tsx +0 -2
- package/src/components/horizontalList/HorizontalList.tsx +0 -1
- package/src/components/icon/Icon.tsx +9 -0
- package/src/components/icon/IconLoadingContext.tsx +7 -0
- package/src/components/imageUploader/ImageUploader.tsx +0 -1
- package/src/components/particles/ParticleLayer.stories.tsx +2 -2
- package/src/components/select/Select.tsx +11 -9
- package/src/components/spinner/Spinner.tsx +1 -1
- package/src/themes.stories.tsx +39 -12
- package/src/uno/colors.ts +1 -0
- package/src/uno/shadows.ts +11 -8
package/dist/esm/uno/shadows.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// @unocss-include
|
|
2
2
|
export function getShadows(hard = false) {
|
|
3
|
+
const opacity1 = `calc(var(--un-shadow-opacity,0.1)*(1 + var(--global-shadow-spread,1) * 0.5)*2)`;
|
|
4
|
+
const opacity2 = `calc(var(--un-shadow-opacity,0.1)*(1 + var(--global-shadow-spread,1) * 0.5))`;
|
|
5
|
+
const opacity3 = `calc(var(--un-shadow-opacity,0.1)*(1 + var(--global-shadow-spread,1) * 0.5)/2)`;
|
|
3
6
|
return {
|
|
4
|
-
sm: `var(--un-shadow-inset) 0 calc(0px * var(--v-shadow-y-mult,1)) calc(1px * var(--global-shadow-spread,1)) 0 rgb(from var(--un-shadow-color) r g b /
|
|
5
|
-
var(--un-shadow-inset) 0 calc(1px * var(--v-shadow-y-mult,1)) calc(2px * var(--global-shadow-spread,1)) 0 rgb(from var(--un-shadow-color) r g b /
|
|
6
|
-
md: `var(--un-shadow-inset) 0 calc(4px * var(--v-shadow-y-mult,1)) calc(8px * var(--global-shadow-spread,1)) -1px rgb(from var(--un-shadow-color) r g b /
|
|
7
|
-
var(--un-shadow-inset) 0 calc(2px * var(--v-shadow-y-mult,1)) calc(4px * var(--global-shadow-spread,1)) -1px rgb(from var(--un-shadow-color) r g b /
|
|
8
|
-
lg: `var(--un-shadow-inset) 0 calc(8px * var(--v-shadow-y-mult,1)) calc(16px * var(--global-shadow-spread,1)) 0px rgb(from var(--un-shadow-color) r g b /
|
|
9
|
-
var(--un-shadow-inset) 0 calc(5px * var(--v-shadow-y-mult,1)) calc(10px * var(--global-shadow-spread,1)) 0px rgb(from var(--un-shadow-color) r g b /
|
|
10
|
-
xl: `var(--un-shadow-inset) 0 calc(20px * var(--v-shadow-y-mult,1)) calc(40px * (0.1 + var(--global-shadow-spread,1))) -0px rgb(from var(--un-shadow-color) r g b /
|
|
11
|
-
var(--un-shadow-inset) 0 calc(15px * var(--v-shadow-y-mult,1)) calc(30px * (0.05 + var(--global-shadow-spread,1))) -6px rgb(from var(--un-shadow-color) r g b /
|
|
7
|
+
sm: `var(--un-shadow-inset) 0 calc(0px * var(--v-shadow-y-mult,1)) calc(1px * var(--global-shadow-spread,1)) 0 rgb(from var(--un-shadow-color) r g b / ${opacity1}),
|
|
8
|
+
var(--un-shadow-inset) 0 calc(1px * var(--v-shadow-y-mult,1)) calc(2px * var(--global-shadow-spread,1)) 0 rgb(from var(--un-shadow-color) r g b / ${opacity1})`,
|
|
9
|
+
md: `var(--un-shadow-inset) 0 calc(4px * var(--v-shadow-y-mult,1)) calc(8px * var(--global-shadow-spread,1)) -1px rgb(from var(--un-shadow-color) r g b / ${opacity2}),
|
|
10
|
+
var(--un-shadow-inset) 0 calc(2px * var(--v-shadow-y-mult,1)) calc(4px * var(--global-shadow-spread,1)) -1px rgb(from var(--un-shadow-color) r g b / ${opacity1})`,
|
|
11
|
+
lg: `var(--un-shadow-inset) 0 calc(8px * var(--v-shadow-y-mult,1)) calc(16px * var(--global-shadow-spread,1)) 0px rgb(from var(--un-shadow-color) r g b / ${opacity2}),
|
|
12
|
+
var(--un-shadow-inset) 0 calc(5px * var(--v-shadow-y-mult,1)) calc(10px * var(--global-shadow-spread,1)) 0px rgb(from var(--un-shadow-color) r g b / ${opacity2})`,
|
|
13
|
+
xl: `var(--un-shadow-inset) 0 calc(20px * var(--v-shadow-y-mult,1)) calc(40px * (0.1 + var(--global-shadow-spread,1))) -0px rgb(from var(--un-shadow-color) r g b / ${opacity2}),
|
|
14
|
+
var(--un-shadow-inset) 0 calc(15px * var(--v-shadow-y-mult,1)) calc(30px * (0.05 + var(--global-shadow-spread,1))) -6px rgb(from var(--un-shadow-color) r g b / ${opacity3})`,
|
|
12
15
|
};
|
|
13
16
|
}
|
|
14
17
|
//# sourceMappingURL=shadows.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadows.js","sourceRoot":"","sources":["../../../src/uno/shadows.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,KAAK;IACtC,OAAO;QACN,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"shadows.js","sourceRoot":"","sources":["../../../src/uno/shadows.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,UAAU,CAAC,IAAI,GAAG,KAAK;IACtC,MAAM,QAAQ,GAAG,gFAAgF,CAAC;IAClG,MAAM,QAAQ,GAAG,8EAA8E,CAAC;IAChG,MAAM,QAAQ,GAAG,gFAAgF,CAAC;IAClG,OAAO;QACN,EAAE,EAAE,qJAAqJ,QAAQ;uJACZ,QAAQ,GAAG;QAChK,EAAE,EAAE,wJAAwJ,QAAQ;0JACZ,QAAQ,GAAG;QACnK,EAAE,EAAE,wJAAwJ,QAAQ;0JACZ,QAAQ,GAAG;QACnK,EAAE,EAAE,kKAAkK,QAAQ;qKACX,QAAQ,GAAG;KAC9K,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@a-type/ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"/dist",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"date-fns": "^4.1.0",
|
|
69
69
|
"formik": "^2.4.6",
|
|
70
70
|
"frimousse": "^0.2.0",
|
|
71
|
+
"motion": "^12.23.6",
|
|
71
72
|
"pluralize": "^8.0.0",
|
|
72
73
|
"react-hot-toast": "^2.4.1",
|
|
73
74
|
"valtio": "^2.1.4"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
2
|
import { useState } from 'react';
|
|
3
|
+
import { Box } from '../box/Box.js';
|
|
3
4
|
import { Icon } from '../icon/index.js';
|
|
4
5
|
import { Button } from './Button.js';
|
|
5
6
|
import { ConfirmedButton } from './ConfirmedButton.js';
|
|
@@ -13,6 +14,12 @@ const meta = {
|
|
|
13
14
|
},
|
|
14
15
|
args: {
|
|
15
16
|
children: 'Button',
|
|
17
|
+
loading: false,
|
|
18
|
+
color: 'default',
|
|
19
|
+
size: 'default',
|
|
20
|
+
visuallyDisabled: false,
|
|
21
|
+
disabled: false,
|
|
22
|
+
visuallyFocused: false,
|
|
16
23
|
},
|
|
17
24
|
} satisfies Meta<typeof Button>;
|
|
18
25
|
|
|
@@ -20,7 +27,37 @@ export default meta;
|
|
|
20
27
|
|
|
21
28
|
type Story = StoryObj<typeof Button>;
|
|
22
29
|
|
|
23
|
-
export const Default: Story = {
|
|
30
|
+
export const Default: Story = {
|
|
31
|
+
render: (args) => {
|
|
32
|
+
return (
|
|
33
|
+
<Box gap items="center">
|
|
34
|
+
<Button {...args} />
|
|
35
|
+
<Button {...args} color="primary">
|
|
36
|
+
<Icon name="placeholder" />
|
|
37
|
+
{args.children}
|
|
38
|
+
</Button>
|
|
39
|
+
<Button {...args} size="small" />
|
|
40
|
+
</Box>
|
|
41
|
+
);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const WithIcon: Story = {
|
|
46
|
+
args: {
|
|
47
|
+
children: (
|
|
48
|
+
<>
|
|
49
|
+
<Icon name="placeholder" />
|
|
50
|
+
Iconic
|
|
51
|
+
</>
|
|
52
|
+
),
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const IconOnly: Story = {
|
|
57
|
+
args: {
|
|
58
|
+
children: <Icon name="placeholder" />,
|
|
59
|
+
},
|
|
60
|
+
};
|
|
24
61
|
|
|
25
62
|
export const Toggled: Story = {
|
|
26
63
|
render: (args) => {
|
|
@@ -31,18 +68,20 @@ export const Toggled: Story = {
|
|
|
31
68
|
};
|
|
32
69
|
|
|
33
70
|
export const Alignment: Story = {
|
|
34
|
-
render() {
|
|
71
|
+
render(args) {
|
|
35
72
|
return (
|
|
36
73
|
<div className="col">
|
|
37
74
|
<div className="row border-default">
|
|
38
|
-
<Button size="small">
|
|
39
|
-
|
|
75
|
+
<Button size="small" {...args}>
|
|
76
|
+
Button
|
|
77
|
+
</Button>
|
|
78
|
+
<Button size="small" {...args}>
|
|
40
79
|
<Icon name="placeholder" />
|
|
41
80
|
</Button>
|
|
42
81
|
</div>
|
|
43
82
|
<div className="row border-default">
|
|
44
|
-
<Button>Button</Button>
|
|
45
|
-
<Button
|
|
83
|
+
<Button {...args}>Button</Button>
|
|
84
|
+
<Button {...args}>
|
|
46
85
|
<Icon name="placeholder" />
|
|
47
86
|
</Button>
|
|
48
87
|
</div>
|
|
@@ -52,12 +91,13 @@ export const Alignment: Story = {
|
|
|
52
91
|
};
|
|
53
92
|
|
|
54
93
|
export const ConfirmedButtonDemo: Story = {
|
|
55
|
-
render() {
|
|
94
|
+
render(args) {
|
|
56
95
|
return (
|
|
57
96
|
<ConfirmedButton
|
|
58
97
|
confirmText="Are you sure?"
|
|
59
98
|
confirmTitle="Confirm"
|
|
60
99
|
onConfirm={() => console.log('confirmed')}
|
|
100
|
+
{...args}
|
|
61
101
|
>
|
|
62
102
|
Confirm
|
|
63
103
|
</ConfirmedButton>
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import { Slot } from '@radix-ui/react-slot';
|
|
2
2
|
import classNames from 'clsx';
|
|
3
|
-
import {
|
|
3
|
+
import { AnimatePresence, motion } from 'motion/react';
|
|
4
|
+
import {
|
|
5
|
+
ButtonHTMLAttributes,
|
|
6
|
+
Children,
|
|
7
|
+
memo,
|
|
8
|
+
Ref,
|
|
9
|
+
useCallback,
|
|
10
|
+
useState,
|
|
11
|
+
} from 'react';
|
|
12
|
+
import { withClassName } from '../../hooks.js';
|
|
13
|
+
import useMergedRef from '../../hooks/useMergedRef.js';
|
|
14
|
+
import { IconLoadingProvider } from '../icon/IconLoadingContext.js';
|
|
4
15
|
import { Icon } from '../icon/index.js';
|
|
5
16
|
import { Spinner } from '../spinner/index.js';
|
|
6
17
|
import { getButtonClassName } from './classes.js';
|
|
@@ -16,6 +27,9 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
16
27
|
| 'accent'
|
|
17
28
|
| 'contrast'
|
|
18
29
|
| 'unstyled';
|
|
30
|
+
/**
|
|
31
|
+
* icon and icon-small are deprecated.
|
|
32
|
+
*/
|
|
19
33
|
size?: 'default' | 'small' | 'icon' | 'icon-small';
|
|
20
34
|
toggled?: boolean;
|
|
21
35
|
toggleMode?: 'color-and-indicator' | 'color' | 'indicator' | 'state-only';
|
|
@@ -27,7 +41,7 @@ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
|
27
41
|
ref?: Ref<HTMLButtonElement>;
|
|
28
42
|
}
|
|
29
43
|
|
|
30
|
-
export function
|
|
44
|
+
export function ButtonRoot({
|
|
31
45
|
className,
|
|
32
46
|
color,
|
|
33
47
|
size,
|
|
@@ -44,13 +58,21 @@ export function Button({
|
|
|
44
58
|
...props
|
|
45
59
|
}: ButtonProps) {
|
|
46
60
|
const Comp = asChild ? Slot : 'button';
|
|
61
|
+
|
|
62
|
+
const isFormSubmitting = false;
|
|
63
|
+
const isSubmitLoading = props.type === 'submit' && isFormSubmitting;
|
|
64
|
+
const isLoading = loading || isSubmitLoading;
|
|
65
|
+
|
|
66
|
+
const finalRef = useMergedRef(useAnnotateWithChildParts(), ref);
|
|
67
|
+
|
|
47
68
|
const buttonProps = {
|
|
48
|
-
ref:
|
|
69
|
+
ref: finalRef,
|
|
49
70
|
...props,
|
|
50
|
-
disabled: disabled ||
|
|
71
|
+
disabled: disabled || isLoading,
|
|
51
72
|
'data-disabled': visuallyDisabled,
|
|
52
73
|
'data-focus': visuallyFocused,
|
|
53
74
|
'data-size': size,
|
|
75
|
+
'data-loading': isLoading,
|
|
54
76
|
tabIndex: visuallyDisabled ? -1 : undefined,
|
|
55
77
|
className: classNames(
|
|
56
78
|
getButtonClassName({
|
|
@@ -69,25 +91,68 @@ export function Button({
|
|
|
69
91
|
buttonProps['aria-pressed'] = !!toggled;
|
|
70
92
|
}
|
|
71
93
|
|
|
94
|
+
// for asChild, no need to do the rest of this stuff.
|
|
72
95
|
if (asChild) {
|
|
73
96
|
// avoid rendering loading spinner with asChild
|
|
74
97
|
return <Comp {...buttonProps}>{children}</Comp>;
|
|
75
98
|
}
|
|
76
99
|
|
|
100
|
+
// wrap and inspect children
|
|
101
|
+
let hasLabel = false;
|
|
102
|
+
let hasIcon = false;
|
|
103
|
+
const wrappedChildren = Children.toArray(children).map((child, index) => {
|
|
104
|
+
if (child && typeof child === 'object' && 'type' in child) {
|
|
105
|
+
const isIcon = child.type === Icon || child.type;
|
|
106
|
+
if (isIcon) {
|
|
107
|
+
hasIcon = true;
|
|
108
|
+
return child; // return icon as is
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
hasLabel = true; // mark that we have a label
|
|
113
|
+
|
|
114
|
+
if ((!!child && typeof child === 'string') || typeof child === 'number') {
|
|
115
|
+
return (
|
|
116
|
+
<span key={`text-${index}`} data-auto-wrapped-label className="flex">
|
|
117
|
+
{child}
|
|
118
|
+
</span>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
return child;
|
|
122
|
+
});
|
|
123
|
+
|
|
77
124
|
return (
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
125
|
+
<IconLoadingProvider value={isLoading}>
|
|
126
|
+
<Comp
|
|
127
|
+
{...buttonProps}
|
|
128
|
+
data-has-icon={String(hasIcon || isLoading)}
|
|
129
|
+
data-has-label={String(hasLabel)}
|
|
130
|
+
>
|
|
131
|
+
<AnimatePresence>
|
|
132
|
+
{isLoading && !hasIcon && (
|
|
133
|
+
<motion.div
|
|
134
|
+
key="spinner"
|
|
135
|
+
initial={{ width: 0, marginLeft: '-0.5rem' }}
|
|
136
|
+
animate={{ width: 'auto', marginLeft: 0 }}
|
|
137
|
+
exit={{ width: 0, marginLeft: '-0.5rem' }}
|
|
138
|
+
className="flex-shrink-0 inline-block overflow-hidden my-auto flex"
|
|
139
|
+
>
|
|
140
|
+
<Spinner size={15} className="inline-block w-1em h-1em" />
|
|
141
|
+
</motion.div>
|
|
142
|
+
)}
|
|
143
|
+
</AnimatePresence>
|
|
144
|
+
{toggled !== undefined &&
|
|
145
|
+
(toggleMode === 'indicator' ||
|
|
146
|
+
toggleMode === 'color-and-indicator') && (
|
|
147
|
+
<ButtonToggleIndicator value={toggled} />
|
|
148
|
+
)}
|
|
149
|
+
{wrappedChildren}
|
|
150
|
+
</Comp>
|
|
151
|
+
</IconLoadingProvider>
|
|
87
152
|
);
|
|
88
153
|
}
|
|
89
154
|
|
|
90
|
-
const
|
|
155
|
+
export const ButtonToggleIndicator = memo(function ToggleIndicator({
|
|
91
156
|
value,
|
|
92
157
|
}: {
|
|
93
158
|
value: boolean;
|
|
@@ -103,3 +168,61 @@ const ToggleIndicator = memo(function ToggleIndicator({
|
|
|
103
168
|
/>
|
|
104
169
|
);
|
|
105
170
|
});
|
|
171
|
+
|
|
172
|
+
// allows custom icons to trigger icon button behavior
|
|
173
|
+
export const ButtonIcon = withClassName(
|
|
174
|
+
'div',
|
|
175
|
+
'icon flex-shrink-0 inline-block',
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
export const Button = Object.assign(ButtonRoot, {
|
|
179
|
+
ToggleIndicator: ButtonToggleIndicator,
|
|
180
|
+
Icon: ButtonIcon,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
function useAnnotateWithChildParts() {
|
|
184
|
+
const mutationObserver = useState(() => {
|
|
185
|
+
if (typeof window === 'undefined') return null!;
|
|
186
|
+
return new MutationObserver((entries) => {
|
|
187
|
+
applyPartAttributes(entries[0].target as HTMLButtonElement);
|
|
188
|
+
});
|
|
189
|
+
})[0];
|
|
190
|
+
|
|
191
|
+
const ref = useCallback(
|
|
192
|
+
(node: HTMLButtonElement | null) => {
|
|
193
|
+
if (node && mutationObserver) {
|
|
194
|
+
mutationObserver.disconnect();
|
|
195
|
+
mutationObserver.observe(node, { childList: true, subtree: true });
|
|
196
|
+
applyPartAttributes(node);
|
|
197
|
+
} else if (mutationObserver) {
|
|
198
|
+
mutationObserver.disconnect();
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
[mutationObserver],
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
return ref;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function applyPartAttributes(button: HTMLButtonElement) {
|
|
208
|
+
// each child node that's not an icon counts as a label
|
|
209
|
+
const registry = {
|
|
210
|
+
icon: 0,
|
|
211
|
+
label: 0,
|
|
212
|
+
};
|
|
213
|
+
button.childNodes.forEach((child) => {
|
|
214
|
+
if (!(child instanceof HTMLElement || child instanceof SVGElement)) return;
|
|
215
|
+
if (child.style.display === 'none' || child.style.width === '0') return; // skip hidden elements
|
|
216
|
+
if (
|
|
217
|
+
(child instanceof HTMLElement || child instanceof SVGElement) &&
|
|
218
|
+
child.classList.contains('icon')
|
|
219
|
+
) {
|
|
220
|
+
registry.icon++;
|
|
221
|
+
} else {
|
|
222
|
+
registry.label++;
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
button.setAttribute('data-has-icon', String(registry.icon > 0));
|
|
226
|
+
button.setAttribute('data-has-label', String(registry.label > 0));
|
|
227
|
+
button.setAttribute('data-icon-count', String(registry.icon));
|
|
228
|
+
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import { type ButtonProps } from './Button.jsx';
|
|
3
|
+
|
|
4
|
+
const sizeMap = {
|
|
5
|
+
default: 'default',
|
|
6
|
+
small: 'small',
|
|
7
|
+
icon: 'default',
|
|
8
|
+
'icon-small': 'small',
|
|
9
|
+
} satisfies Record<string, 'default' | 'small'>;
|
|
3
10
|
|
|
4
11
|
export function getButtonClassName({
|
|
5
12
|
color,
|
|
6
|
-
size,
|
|
13
|
+
size: rawSize,
|
|
7
14
|
toggleable,
|
|
8
15
|
align,
|
|
9
16
|
}: {
|
|
@@ -12,8 +19,10 @@ export function getButtonClassName({
|
|
|
12
19
|
toggleable?: boolean;
|
|
13
20
|
align?: ButtonProps['align'];
|
|
14
21
|
}) {
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
const size = sizeMap[rawSize ?? 'default'];
|
|
23
|
+
|
|
24
|
+
return clsx(
|
|
25
|
+
'layer-components:(px-4 py-2 bg-[var(--bg-neutral,var(--bg))] [--webkit-tap-highlight-color:transparent] [line-height:1] text-size-md font-inherit border-solid border-thin border-transparent rounded-lg cursor-pointer font-bold flex flex-row gap-sm items-center relative overflow-visible select-none all:transition duration-200 whitespace-nowrap ring-bg)',
|
|
17
26
|
'layer-components:hover:(bg-[var(--bg)] bg-darken-1 ring-4)',
|
|
18
27
|
'layer-components:focus:outline-off',
|
|
19
28
|
'layer-components:focus-visible:(bg-[var(--bg)] outline-off bg-darken-1 ring-6)',
|
|
@@ -37,7 +46,7 @@ export function getButtonClassName({
|
|
|
37
46
|
const colors = {
|
|
38
47
|
primary: `layer-variants:[&.btn-color-primary]:([--bg:var(--color-primary)] shadow-sm color-black border-primary-dark)`,
|
|
39
48
|
accent: `layer-variants:[&.btn-color-accent]:([--bg-neutral:var(--color-accent-wash)] [--bg:var(--color-accent-light)] shadow-sm color-black border-accent-dark)`,
|
|
40
|
-
default: `layer-variants:[&.btn-color-default]:([--bg-neutral:var(--color-white)] [--bg:var(--color-gray
|
|
49
|
+
default: `layer-variants:[&.btn-color-default]:([--bg-neutral:var(--color-white)] [--bg:var(--color-gray)] shadow-sm color-black border-gray-dark focus-visible:bg-lighten-1 hover:bg-lighten-1)`,
|
|
41
50
|
ghost: `layer-variants:[&.btn-color-ghost]:([--bg-neutral:transparent] [--bg:oklch(from_var(--color-gray)_l_c_h/50%)] color-dark-blend)`,
|
|
42
51
|
destructive: `layer-variants:[&.btn-color-destructive]:([--bg:var(--color-attention)] shadow-sm border-attention-dark color-black)`,
|
|
43
52
|
ghostDestructive: `layer-variants:[&.btn-color-ghostDestructive]:([--bg-neutral:transparent] [--bg:var(--color-attention-light)] color-attention-dark hover:(color-black) focus-visible:(color-black))`,
|
|
@@ -48,11 +57,10 @@ const colors = {
|
|
|
48
57
|
export const buttonColorClasses = colors;
|
|
49
58
|
|
|
50
59
|
const sizes = {
|
|
51
|
-
default:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
'layer-variants:[&.size-icon-small]:(p-2 text-xs rounded-lg -m-y-0.5)',
|
|
60
|
+
default:
|
|
61
|
+
'layer-variants:[&[data-has-icon=true][data-has-label=false]]:(p-2.35 text-sm rounded-lg)',
|
|
62
|
+
small:
|
|
63
|
+
'layer-variants:[&.size-small]:(px-4 py-1 text-sm rounded-md) layer-variants:[&.size-small[data-has-icon=true][data-has-label=false]]:(p-2 text-xs rounded-lg -m-y-0.5)',
|
|
56
64
|
};
|
|
57
65
|
|
|
58
66
|
const toggledClass =
|
|
@@ -244,7 +244,6 @@ export const CameraDeviceSelector = (props: CameraDeviceSelectorProps) => {
|
|
|
244
244
|
if (devices.length === 2) {
|
|
245
245
|
return (
|
|
246
246
|
<Button
|
|
247
|
-
size="icon"
|
|
248
247
|
color="ghost"
|
|
249
248
|
className="absolute bottom-2 left-2 color-white"
|
|
250
249
|
onClick={swapCamera}
|
|
@@ -260,11 +259,7 @@ export const CameraDeviceSelector = (props: CameraDeviceSelectorProps) => {
|
|
|
260
259
|
onValueChange={selectDeviceId}
|
|
261
260
|
>
|
|
262
261
|
<Select.Trigger asChild>
|
|
263
|
-
<Button
|
|
264
|
-
size="icon"
|
|
265
|
-
color="ghost"
|
|
266
|
-
className="absolute bottom-2 left-2 color-white"
|
|
267
|
-
>
|
|
262
|
+
<Button color="ghost" className="absolute bottom-2 left-2 color-white">
|
|
268
263
|
<Icon name="refresh" />
|
|
269
264
|
</Button>
|
|
270
265
|
</Select.Trigger>
|
|
@@ -284,7 +279,6 @@ export const CameraFullscreenButton = (props: ButtonProps) => {
|
|
|
284
279
|
return (
|
|
285
280
|
<Button
|
|
286
281
|
{...props}
|
|
287
|
-
size="icon"
|
|
288
282
|
color="ghost"
|
|
289
283
|
className="absolute top-2 right-2 color-white"
|
|
290
284
|
onClick={() => setFullscreen(!fullscreen)}
|
|
@@ -46,12 +46,12 @@ export const Default: Story = {
|
|
|
46
46
|
<CardFooter>
|
|
47
47
|
<CardActions>
|
|
48
48
|
<Button size="small">Button</Button>
|
|
49
|
-
<Button size="
|
|
49
|
+
<Button size="small" color="primary">
|
|
50
50
|
<Icon name="placeholder" />
|
|
51
51
|
</Button>
|
|
52
52
|
</CardActions>
|
|
53
53
|
<CardMenu>
|
|
54
|
-
<Button size="
|
|
54
|
+
<Button size="small" color="ghost">
|
|
55
55
|
<Icon name="dots" />
|
|
56
56
|
</Button>
|
|
57
57
|
</CardMenu>
|
|
@@ -68,7 +68,7 @@ export const Default: Story = {
|
|
|
68
68
|
<CardFooter>
|
|
69
69
|
<CardActions>
|
|
70
70
|
<Button size="small">Button</Button>
|
|
71
|
-
<Button size="
|
|
71
|
+
<Button size="small" color="ghost">
|
|
72
72
|
<Icon name="placeholder" />
|
|
73
73
|
</Button>
|
|
74
74
|
</CardActions>
|
|
@@ -89,7 +89,7 @@ export const Compact: Story = {
|
|
|
89
89
|
<CardFooter>
|
|
90
90
|
<CardActions>
|
|
91
91
|
<Button size="small">Button</Button>
|
|
92
|
-
<Button size="
|
|
92
|
+
<Button size="small" color="ghost">
|
|
93
93
|
<Icon name="placeholder" />
|
|
94
94
|
</Button>
|
|
95
95
|
</CardActions>
|
|
@@ -108,7 +108,7 @@ export const NonInteractive: Story = {
|
|
|
108
108
|
<CardFooter>
|
|
109
109
|
<CardActions>
|
|
110
110
|
<Button size="small">Button</Button>
|
|
111
|
-
<Button
|
|
111
|
+
<Button color="ghost">
|
|
112
112
|
<Icon name="placeholder" />
|
|
113
113
|
</Button>
|
|
114
114
|
</CardActions>
|
|
@@ -129,7 +129,7 @@ export const AsChild: Story = {
|
|
|
129
129
|
<CardFooter>
|
|
130
130
|
<CardActions>
|
|
131
131
|
<Button size="small">Button</Button>
|
|
132
|
-
<Button
|
|
132
|
+
<Button color="ghost">
|
|
133
133
|
<Icon name="placeholder" />
|
|
134
134
|
</Button>
|
|
135
135
|
</CardActions>
|
|
@@ -150,7 +150,7 @@ export const AsChildNonInteractive: Story = {
|
|
|
150
150
|
<CardFooter>
|
|
151
151
|
<CardActions>
|
|
152
152
|
<Button size="small">Button</Button>
|
|
153
|
-
<Button
|
|
153
|
+
<Button color="ghost">
|
|
154
154
|
<Icon name="placeholder" />
|
|
155
155
|
</Button>
|
|
156
156
|
</CardActions>
|
|
@@ -249,7 +249,7 @@ export const VisuallyFocused: Story = {
|
|
|
249
249
|
<CardFooter>
|
|
250
250
|
<CardActions>
|
|
251
251
|
<Button size="small">Button</Button>
|
|
252
|
-
<Button
|
|
252
|
+
<Button color="ghost">
|
|
253
253
|
<Icon name="placeholder" />
|
|
254
254
|
</Button>
|
|
255
255
|
</CardActions>
|
|
@@ -270,7 +270,7 @@ export const CardsInBox: Story = {
|
|
|
270
270
|
<CardFooter>
|
|
271
271
|
<CardActions>
|
|
272
272
|
<Button size="small">Button</Button>
|
|
273
|
-
<Button
|
|
273
|
+
<Button color="ghost">
|
|
274
274
|
<Icon name="placeholder" />
|
|
275
275
|
</Button>
|
|
276
276
|
</CardActions>
|
|
@@ -284,7 +284,7 @@ export const CardsInBox: Story = {
|
|
|
284
284
|
<CardFooter>
|
|
285
285
|
<CardActions>
|
|
286
286
|
<Button size="small">Button</Button>
|
|
287
|
-
<Button
|
|
287
|
+
<Button color="ghost">
|
|
288
288
|
<Icon name="placeholder" />
|
|
289
289
|
</Button>
|
|
290
290
|
</CardActions>
|
|
@@ -19,7 +19,7 @@ export const ContextMenuContent = function Content({
|
|
|
19
19
|
<BoxContext.Provider value={{ spacingScale: 1 }}>
|
|
20
20
|
<ContextMenuPrimitive.Content
|
|
21
21
|
className={classNames(
|
|
22
|
-
'layer-components:(min-w-120px bg-white rounded-
|
|
22
|
+
'layer-components:(min-w-120px bg-white rounded-md overflow-hidden border-gray-dark border shadow-md z-menu)',
|
|
23
23
|
'layer-components:transform-origin-[var(--radix-context-menu-transform-origin)]',
|
|
24
24
|
'layer-components:[&[data-state=open]]:animate-popover-in',
|
|
25
25
|
'layer-components:[&[data-state=closed]]:animate-popover-out',
|
|
@@ -47,10 +47,8 @@ export const ContextMenuArrow = withClassName(
|
|
|
47
47
|
|
|
48
48
|
export const ContextMenuItem = withClassName(
|
|
49
49
|
ContextMenuPrimitive.Item,
|
|
50
|
-
'layer-components:(flex items-center py-1 px-2 relative pl-25px select-none outline-none cursor-pointer
|
|
51
|
-
'layer-components:[
|
|
52
|
-
'layer-components:[&:last-of-type]:rounded-b-md',
|
|
53
|
-
'layer-components:(hover:bg-gray-light [&[data-highlighted=true]]:bg-gray-light [&[data-disabled=true]]:(opacity-50 cursor-default) disabled:(opacity-50 cursor-default))',
|
|
50
|
+
'layer-components:(flex items-center py-1 px-2 relative pl-25px select-none outline-none cursor-pointer)',
|
|
51
|
+
'layer-components:(hover:(bg-gray bg-lighten-3) [&[data-highlighted=true]]:(bg-gray bg-lighten-3) [&[data-disabled=true]]:(opacity-50 cursor-default) disabled:(opacity-50 cursor-default))',
|
|
54
52
|
);
|
|
55
53
|
|
|
56
54
|
export const ContextMenuTrigger = withClassName(
|
|
@@ -40,7 +40,6 @@ export function DatePicker({
|
|
|
40
40
|
>
|
|
41
41
|
<MonthRow>
|
|
42
42
|
<MonthButton
|
|
43
|
-
size="icon"
|
|
44
43
|
color="ghost"
|
|
45
44
|
onClick={() =>
|
|
46
45
|
setDisplay((cur) => ({
|
|
@@ -53,7 +52,6 @@ export function DatePicker({
|
|
|
53
52
|
</MonthButton>
|
|
54
53
|
<MonthLabel>{monthLabel}</MonthLabel>
|
|
55
54
|
<MonthButton
|
|
56
|
-
size="icon"
|
|
57
55
|
color="ghost"
|
|
58
56
|
onClick={() =>
|
|
59
57
|
setDisplay((cur) => ({
|
|
@@ -143,7 +141,6 @@ export function DateRangePicker({
|
|
|
143
141
|
>
|
|
144
142
|
<RangeLayout>
|
|
145
143
|
<MonthButton
|
|
146
|
-
size="icon"
|
|
147
144
|
color="ghost"
|
|
148
145
|
className="[grid-area:prevMonth]"
|
|
149
146
|
onClick={() =>
|
|
@@ -160,7 +157,6 @@ export function DateRangePicker({
|
|
|
160
157
|
{nextMonthLabel}
|
|
161
158
|
</MonthLabel>
|
|
162
159
|
<MonthButton
|
|
163
|
-
size="icon"
|
|
164
160
|
color="ghost"
|
|
165
161
|
className="[grid-area:nextMonth]"
|
|
166
162
|
onClick={() =>
|
|
@@ -15,7 +15,7 @@ const StyledContent = withClassName(
|
|
|
15
15
|
</BoxContext.Provider>
|
|
16
16
|
);
|
|
17
17
|
},
|
|
18
|
-
'layer-components:(min-w-220px bg-white z-menu shadow-lg rounded-
|
|
18
|
+
'layer-components:(min-w-220px bg-white z-menu shadow-lg rounded-md border border-gray-dark)',
|
|
19
19
|
'layer-components:transform-origin-[var(--radix-dropdown-menu-transform-origin)]',
|
|
20
20
|
'layer-components:[&[data-state=open]]:animate-popover-in',
|
|
21
21
|
'layer-components:[&[data-state=closed]]:animate-popover-out',
|
|
@@ -25,8 +25,9 @@ const StyledContent = withClassName(
|
|
|
25
25
|
);
|
|
26
26
|
const itemClassName = classNames(
|
|
27
27
|
'layer-components:(text-md leading-4 color-black flex items-center pr-4 pl-8 py-2 relative text-left select-none cursor-pointer)',
|
|
28
|
-
'layer-components:[&[data-disabled]]:(color-
|
|
29
|
-
'layer-components:focus-visible:(bg-gray
|
|
28
|
+
'layer-components:[&[data-disabled]]:(color-gray-dark pointer-events-none)',
|
|
29
|
+
'layer-components:focus-visible:(bg-gray bg-lighten-3 color-black)',
|
|
30
|
+
'layer-components:hover:(bg-gray bg-lighten-3 color-black)',
|
|
30
31
|
'layer-components:focus:outline-none',
|
|
31
32
|
);
|
|
32
33
|
const StyledItemBase = withClassName(DropdownMenuPrimitive.Item, itemClassName);
|
|
@@ -46,7 +47,7 @@ const StyledItem = ({
|
|
|
46
47
|
{...props}
|
|
47
48
|
className={clsx(
|
|
48
49
|
color === 'destructive' &&
|
|
49
|
-
'layer-variants:(color-attention-dark hover:bg-attention-
|
|
50
|
+
'layer-variants:(color-attention-dark hover:bg-attention-light focus-visible:bg-attention-light)',
|
|
50
51
|
className,
|
|
51
52
|
)}
|
|
52
53
|
ref={forwardedRef}
|
|
@@ -111,14 +112,14 @@ export const DropdownMenuContent = ({
|
|
|
111
112
|
return (
|
|
112
113
|
<StyledPortal forceMount={forceMount}>
|
|
113
114
|
<StyledContent {...props}>
|
|
114
|
-
<div className="overflow-hidden rounded-
|
|
115
|
+
<div className="overflow-hidden rounded-md">{children}</div>
|
|
115
116
|
<StyledArrow />
|
|
116
117
|
</StyledContent>
|
|
117
118
|
</StyledPortal>
|
|
118
119
|
);
|
|
119
120
|
};
|
|
120
121
|
|
|
121
|
-
export const DropdownMenuItemRightSlot = withClassName('div', 'ml-auto');
|
|
122
|
+
export const DropdownMenuItemRightSlot = withClassName('div', 'ml-auto pl-md');
|
|
122
123
|
|
|
123
124
|
export const DropdownMenu = Object.assign(DropdownMenuRoot, {
|
|
124
125
|
Content: DropdownMenuContent,
|
|
@@ -71,11 +71,11 @@ export const EmojiPickerEmoji = withClassName(
|
|
|
71
71
|
color="ghost"
|
|
72
72
|
toggled={p.emoji.isActive}
|
|
73
73
|
toggleMode="color"
|
|
74
|
-
size="
|
|
74
|
+
size="small"
|
|
75
75
|
aria-label={p.emoji.label}
|
|
76
76
|
className="text-lg p-xs"
|
|
77
77
|
>
|
|
78
|
-
{p.emoji.emoji}
|
|
78
|
+
<Button.Icon>{p.emoji.emoji}</Button.Icon>
|
|
79
79
|
</Button>
|
|
80
80
|
),
|
|
81
81
|
'',
|
|
@@ -122,12 +122,12 @@ export const EmojiPickerSkinToneSelector = (props: BoxProps) => {
|
|
|
122
122
|
color="ghost"
|
|
123
123
|
toggled={option.skinTone === skinTone}
|
|
124
124
|
toggleMode="color"
|
|
125
|
-
size="
|
|
125
|
+
size="small"
|
|
126
126
|
aria-label={`Skin tone ${option}`}
|
|
127
127
|
className="text-md p-xs"
|
|
128
128
|
onClick={() => setSkinTone(option.skinTone)}
|
|
129
129
|
>
|
|
130
|
-
{option.emoji}
|
|
130
|
+
<Button.Icon>{option.emoji}</Button.Icon>
|
|
131
131
|
</Button>
|
|
132
132
|
))}
|
|
133
133
|
</Box>
|
|
@@ -36,7 +36,6 @@ const meta = {
|
|
|
36
36
|
<Button size="small">Twenty three</Button>
|
|
37
37
|
<Button size="small">Twenty four</Button>
|
|
38
38
|
<Button
|
|
39
|
-
size="icon"
|
|
40
39
|
color="primary"
|
|
41
40
|
className="sticky right-2 bottom-2 flex-shrink-0 shadow-sm ml-auto"
|
|
42
41
|
>
|
|
@@ -113,7 +112,6 @@ export const CantOpen: Story = {
|
|
|
113
112
|
</>
|
|
114
113
|
)}
|
|
115
114
|
<Button
|
|
116
|
-
size="icon"
|
|
117
115
|
color="primary"
|
|
118
116
|
className="sticky right-2 bottom-2 flex-shrink-0 shadow-sm ml-auto"
|
|
119
117
|
>
|