@a-type/ui 0.3.1 → 0.3.3
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.js +6 -1
- package/dist/cjs/components/button/Button.js.map +1 -1
- package/dist/cjs/components/camera/Camera.d.ts +1 -0
- package/dist/cjs/components/camera/Camera.js +24 -18
- package/dist/cjs/components/camera/Camera.js.map +1 -1
- package/dist/cjs/components/icon/generated/IconSpritesheet.js +1 -1
- package/dist/cjs/components/icon/generated/IconSpritesheet.js.map +1 -1
- package/dist/cjs/components/icon/generated/iconNames.d.ts +1 -1
- package/dist/cjs/components/icon/generated/iconNames.js +10 -0
- package/dist/cjs/components/icon/generated/iconNames.js.map +1 -1
- package/dist/cjs/components/imageUploader/ImageUploader.js +28 -2
- package/dist/cjs/components/imageUploader/ImageUploader.js.map +1 -1
- package/dist/cjs/components/imageUploader/ImageUploader.stories.d.ts +22 -0
- package/dist/cjs/components/imageUploader/ImageUploader.stories.js +28 -0
- package/dist/cjs/components/imageUploader/ImageUploader.stories.js.map +1 -0
- package/dist/esm/components/button/Button.js +6 -1
- package/dist/esm/components/button/Button.js.map +1 -1
- package/dist/esm/components/camera/Camera.d.ts +1 -0
- package/dist/esm/components/camera/Camera.js +24 -18
- package/dist/esm/components/camera/Camera.js.map +1 -1
- package/dist/esm/components/icon/generated/IconSpritesheet.js +1 -1
- package/dist/esm/components/icon/generated/IconSpritesheet.js.map +1 -1
- package/dist/esm/components/icon/generated/iconNames.d.ts +1 -1
- package/dist/esm/components/icon/generated/iconNames.js +10 -0
- package/dist/esm/components/icon/generated/iconNames.js.map +1 -1
- package/dist/esm/components/imageUploader/ImageUploader.js +29 -3
- package/dist/esm/components/imageUploader/ImageUploader.js.map +1 -1
- package/dist/esm/components/imageUploader/ImageUploader.stories.d.ts +22 -0
- package/dist/esm/components/imageUploader/ImageUploader.stories.js +25 -0
- package/dist/esm/components/imageUploader/ImageUploader.stories.js.map +1 -0
- package/package.json +3 -2
- package/src/components/actions/ActionBar.tsx +38 -0
- package/src/components/actions/ActionButton.tsx +59 -0
- package/src/components/actions/index.ts +2 -0
- package/src/components/actions.ts +1 -0
- package/src/components/avatar/Avatar.tsx +62 -0
- package/src/components/avatar/AvatarList.tsx +71 -0
- package/src/components/avatar/index.ts +2 -0
- package/src/components/avatar.ts +1 -0
- package/src/components/button/Button.stories.tsx +20 -0
- package/src/components/button/Button.tsx +66 -0
- package/src/components/button/ConfirmedButton.tsx +66 -0
- package/src/components/button/classes.tsx +56 -0
- package/src/components/button/index.ts +3 -0
- package/src/components/button.ts +1 -0
- package/src/components/camera/Camera.stories.tsx +40 -0
- package/src/components/camera/Camera.tsx +215 -0
- package/src/components/camera/index.ts +1 -0
- package/src/components/camera.ts +1 -0
- package/src/components/card/Card.stories.tsx +41 -0
- package/src/components/card/Card.tsx +68 -0
- package/src/components/card/index.ts +1 -0
- package/src/components/card.ts +1 -0
- package/src/components/checkbox/Checkbox.tsx +46 -0
- package/src/components/checkbox/index.ts +1 -0
- package/src/components/checkbox.ts +1 -0
- package/src/components/chip/Chip.tsx +29 -0
- package/src/components/chip/index.ts +1 -0
- package/src/components/chip.ts +1 -0
- package/src/components/collapsible/Collapsible.tsx +48 -0
- package/src/components/collapsible/index.ts +1 -0
- package/src/components/collapsible.ts +1 -0
- package/src/components/colorPicker/ColorPicker.tsx +82 -0
- package/src/components/colorPicker/index.ts +1 -0
- package/src/components/colorPicker.ts +1 -0
- package/src/components/contextMenu/contextMenu.tsx +43 -0
- package/src/components/contextMenu.ts +1 -0
- package/src/components/dialog/Dialog.stories.tsx +38 -0
- package/src/components/dialog/Dialog.tsx +267 -0
- package/src/components/dialog/index.ts +1 -0
- package/src/components/dialog.ts +1 -0
- package/src/components/divider/Divider.tsx +26 -0
- package/src/components/divider/index.ts +1 -0
- package/src/components/divider.ts +1 -0
- package/src/components/dropdownMenu/DropdownMenu.stories.tsx +47 -0
- package/src/components/dropdownMenu/DropdownMenu.tsx +89 -0
- package/src/components/dropdownMenu/index.ts +1 -0
- package/src/components/dropdownMenu.ts +1 -0
- package/src/components/errorBoundary/ErrorBoundary.tsx +23 -0
- package/src/components/errorBoundary/index.ts +1 -0
- package/src/components/errorBoundary.ts +1 -0
- package/src/components/forms/Form.tsx +9 -0
- package/src/components/forms/FormikForm.tsx +41 -0
- package/src/components/forms/SubmitButton.tsx +15 -0
- package/src/components/forms/TextField.tsx +112 -0
- package/src/components/forms/index.tsx +4 -0
- package/src/components/forms.ts +1 -0
- package/src/components/icon/Icon.tsx +28 -0
- package/src/components/icon/generated/IconSpritesheet.tsx +442 -0
- package/src/components/icon/generated/iconNames.ts +44 -0
- package/src/components/icon/index.ts +3 -0
- package/src/components/icon.ts +1 -0
- package/src/components/imageUploader/ImageUploader.stories.tsx +39 -0
- package/src/components/imageUploader/ImageUploader.tsx +203 -0
- package/src/components/imageUploader/UploadIcon.tsx +23 -0
- package/src/components/imageUploader/index.ts +1 -0
- package/src/components/imageUploader.ts +1 -0
- package/src/components/infiniteLoadTrigger/InfiniteLoadTrigger.tsx +38 -0
- package/src/components/infiniteLoadTrigger.ts +1 -0
- package/src/components/input/Input.stories.tsx +17 -0
- package/src/components/input/Input.tsx +32 -0
- package/src/components/input/index.ts +1 -0
- package/src/components/input.ts +1 -0
- package/src/components/layouts/PageContent.tsx +51 -0
- package/src/components/layouts/PageFixedArea.tsx +17 -0
- package/src/components/layouts/PageNav.tsx +23 -0
- package/src/components/layouts/PageNowPlaying.tsx +24 -0
- package/src/components/layouts/PageRoot.tsx +29 -0
- package/src/components/layouts/PageSection.tsx +23 -0
- package/src/components/layouts/index.tsx +6 -0
- package/src/components/layouts.ts +1 -0
- package/src/components/liveUpdateTextField/LiveUpdateTextField.tsx +132 -0
- package/src/components/liveUpdateTextField/index.ts +1 -0
- package/src/components/liveUpdateTextField.ts +1 -0
- package/src/components/navBar/NavBar.tsx +59 -0
- package/src/components/navBar/index.ts +1 -0
- package/src/components/navBar.ts +1 -0
- package/src/components/note/Note.tsx +21 -0
- package/src/components/note/index.ts +1 -0
- package/src/components/note.ts +1 -0
- package/src/components/numberStepper/NumberStepper.stories.tsx +21 -0
- package/src/components/numberStepper/NumberStepper.tsx +74 -0
- package/src/components/numberStepper/index.ts +1 -0
- package/src/components/numberStepper.ts +1 -0
- package/src/components/particles/ParticleContext.tsx +11 -0
- package/src/components/particles/ParticleLayer.stories.tsx +46 -0
- package/src/components/particles/ParticleLayer.tsx +28 -0
- package/src/components/particles/index.ts +7 -0
- package/src/components/particles/particlesState.ts +502 -0
- package/src/components/particles.ts +1 -0
- package/src/components/peek/Peek.tsx +74 -0
- package/src/components/peek/index.ts +1 -0
- package/src/components/peek.ts +1 -0
- package/src/components/popover/Popover.tsx +84 -0
- package/src/components/popover/index.ts +1 -0
- package/src/components/popover.ts +1 -0
- package/src/components/relativeTime/RelativeTime.tsx +43 -0
- package/src/components/relativeTime/index.ts +1 -0
- package/src/components/relativeTime.ts +1 -0
- package/src/components/richEditor/EditorContent.tsx +4 -0
- package/src/components/richEditor/RichEditor.tsx +38 -0
- package/src/components/richEditor/index.ts +1 -0
- package/src/components/richEditor.ts +1 -0
- package/src/components/select/Select.tsx +247 -0
- package/src/components/select/index.ts +1 -0
- package/src/components/select.ts +1 -0
- package/src/components/skeletons/skeletons.tsx +27 -0
- package/src/components/skeletons.ts +1 -0
- package/src/components/spinner/Spinner.tsx +59 -0
- package/src/components/spinner/index.ts +1 -0
- package/src/components/spinner.ts +1 -0
- package/src/components/switch/Switch.tsx +23 -0
- package/src/components/switch/index.ts +1 -0
- package/src/components/switch.ts +1 -0
- package/src/components/tabs/tabs.tsx +18 -0
- package/src/components/tabs.ts +1 -0
- package/src/components/textArea/TextArea.stories.tsx +21 -0
- package/src/components/textArea/TextArea.tsx +58 -0
- package/src/components/textArea/index.ts +1 -0
- package/src/components/textArea.ts +1 -0
- package/src/components/toggleGroup/toggleGroup.tsx +11 -0
- package/src/components/toggleGroup.ts +1 -0
- package/src/components/tooltip/Tooltip.tsx +56 -0
- package/src/components/tooltip/index.ts +1 -0
- package/src/components/tooltip.ts +1 -0
- package/src/components/typography/index.ts +1 -0
- package/src/components/typography/typography.tsx +18 -0
- package/src/components/typography.ts +1 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useMergedRef.ts +14 -0
- package/src/hooks/useOnUnmount.ts +20 -0
- package/src/hooks/useSize.ts +164 -0
- package/src/hooks/useStableCallback.ts +11 -0
- package/src/hooks/useToggle.tsx +9 -0
- package/src/hooks/useVisualViewportOffset.ts +35 -0
- package/src/hooks/withClassName.tsx +21 -0
- package/src/hooks.ts +1 -0
- package/src/uno.preset.ts +767 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { forwardRef } from 'react';
|
|
4
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
5
|
+
import * as CollapsiblePrimitive from '@radix-ui/react-collapsible';
|
|
6
|
+
|
|
7
|
+
export const CollapsibleRoot = CollapsiblePrimitive.Root;
|
|
8
|
+
const CollapsibleContentBase = withClassName(
|
|
9
|
+
CollapsiblePrimitive.Content,
|
|
10
|
+
'overflow-hidden animate-forwards',
|
|
11
|
+
'layer-components:[&[data-state=open]]:(animate-radix-collapsible-open-vertical animate-duration-300 animate-ease-springy) layer-components:[&[data-state=closed]]:(animate-radix-collapsible-close-vertical animate-duration-300 animate-ease-springy)',
|
|
12
|
+
'layer-variants:[&[data-horizontal][data-state=open]]:(animate-radix-collapsible-open-horizontal animate-duration-300 animate-ease-springy) layer-variants:[&[data-horizontal][data-state=closed]]:(animate-radix-collapsible-close-horizontal animate-duration-300 animate-ease-springy)',
|
|
13
|
+
'layer-variants:[&[data-both][data-state=open]]:(animate-radix-collapsible-open-both animate-duration-300 animate-ease-springy) layer-variants:[&[data-both][data-state=closed]]:(animate-radix-collapsible-close-both animate-duration-300 animate-ease-springy)',
|
|
14
|
+
);
|
|
15
|
+
// specifically removing className... it's causing problems?
|
|
16
|
+
export const CollapsibleContent = forwardRef<
|
|
17
|
+
HTMLDivElement,
|
|
18
|
+
CollapsiblePrimitive.CollapsibleContentProps & {
|
|
19
|
+
horizontal?: boolean;
|
|
20
|
+
both?: boolean;
|
|
21
|
+
}
|
|
22
|
+
>(function CollapsibleContent({ horizontal, both, ...props }, ref) {
|
|
23
|
+
return (
|
|
24
|
+
<CollapsibleContentBase
|
|
25
|
+
data-horizontal={horizontal}
|
|
26
|
+
data-both={both}
|
|
27
|
+
{...props}
|
|
28
|
+
ref={ref}
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
});
|
|
32
|
+
export const CollapsibleTrigger = CollapsiblePrimitive.Trigger;
|
|
33
|
+
|
|
34
|
+
export const CollapsibleSimple = ({
|
|
35
|
+
horizontal,
|
|
36
|
+
both,
|
|
37
|
+
children,
|
|
38
|
+
...props
|
|
39
|
+
}: CollapsiblePrimitive.CollapsibleProps & {
|
|
40
|
+
horizontal?: boolean;
|
|
41
|
+
both?: boolean;
|
|
42
|
+
}) => (
|
|
43
|
+
<CollapsibleRoot {...props}>
|
|
44
|
+
<CollapsibleContent horizontal={horizontal} both={both}>
|
|
45
|
+
{children}
|
|
46
|
+
</CollapsibleContent>
|
|
47
|
+
</CollapsibleRoot>
|
|
48
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Collapsible.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './collapsible/index.js';
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Select,
|
|
5
|
+
SelectContent,
|
|
6
|
+
SelectItem,
|
|
7
|
+
SelectTrigger,
|
|
8
|
+
SelectValue,
|
|
9
|
+
} from '../select/Select.js';
|
|
10
|
+
import classNames from 'classnames';
|
|
11
|
+
import { ReactNode } from 'react';
|
|
12
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
13
|
+
|
|
14
|
+
export type ThemeName = 'lemon' | 'tomato' | 'leek' | 'blueberry' | 'eggplant';
|
|
15
|
+
|
|
16
|
+
export interface ColorPickerProps {
|
|
17
|
+
value: ThemeName | null;
|
|
18
|
+
onChange: (value: ThemeName) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function ColorPicker({ value, onChange }: ColorPickerProps) {
|
|
22
|
+
const resolvedValue = [
|
|
23
|
+
'lemon',
|
|
24
|
+
'tomato',
|
|
25
|
+
'leek',
|
|
26
|
+
'blueberry',
|
|
27
|
+
'eggplant',
|
|
28
|
+
].includes(value || '')
|
|
29
|
+
? (value as ThemeName)
|
|
30
|
+
: 'lemon';
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<Select value={resolvedValue} onValueChange={onChange}>
|
|
34
|
+
<SelectTrigger>
|
|
35
|
+
<SelectValue />
|
|
36
|
+
</SelectTrigger>
|
|
37
|
+
<SelectContent className="z-[calc(var(--z-dialog)+1)]">
|
|
38
|
+
<SelectItem value="lemon">
|
|
39
|
+
<ColorSwatch value="lemon" />
|
|
40
|
+
<ItemLabel>Lemon</ItemLabel>
|
|
41
|
+
</SelectItem>
|
|
42
|
+
<SelectItem value="tomato">
|
|
43
|
+
<ColorSwatch value="tomato" />
|
|
44
|
+
<ItemLabel>Tomato</ItemLabel>
|
|
45
|
+
</SelectItem>
|
|
46
|
+
<SelectItem value="leek">
|
|
47
|
+
<ColorSwatch value="leek" />
|
|
48
|
+
<ItemLabel>Leek</ItemLabel>
|
|
49
|
+
</SelectItem>
|
|
50
|
+
<SelectItem value="blueberry">
|
|
51
|
+
<ColorSwatch value="blueberry" />
|
|
52
|
+
<ItemLabel>Blueberry</ItemLabel>
|
|
53
|
+
</SelectItem>
|
|
54
|
+
<SelectItem value="eggplant">
|
|
55
|
+
<ColorSwatch value="eggplant" />
|
|
56
|
+
<ItemLabel>Eggplant</ItemLabel>
|
|
57
|
+
</SelectItem>
|
|
58
|
+
</SelectContent>
|
|
59
|
+
</Select>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const ItemLabel = withClassName('span', 'display-none');
|
|
64
|
+
|
|
65
|
+
export function ColorSwatch({
|
|
66
|
+
value,
|
|
67
|
+
children,
|
|
68
|
+
}: {
|
|
69
|
+
value: ThemeName;
|
|
70
|
+
children?: ReactNode;
|
|
71
|
+
}) {
|
|
72
|
+
return (
|
|
73
|
+
<div
|
|
74
|
+
className={classNames(
|
|
75
|
+
'bg-primary w-16px h-16px rounded-sm',
|
|
76
|
+
`theme-${value ?? 'lemon'}`,
|
|
77
|
+
)}
|
|
78
|
+
>
|
|
79
|
+
{children}
|
|
80
|
+
</div>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ColorPicker.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './colorPicker/index.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import * as ContextMenu from '@radix-ui/react-context-menu';
|
|
2
|
+
import { ComponentPropsWithoutRef, forwardRef } from 'react';
|
|
3
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
4
|
+
import classNames from 'classnames';
|
|
5
|
+
|
|
6
|
+
export const ContextMenuRoot = ContextMenu.Root;
|
|
7
|
+
|
|
8
|
+
export const ContextMenuContent = forwardRef<
|
|
9
|
+
HTMLDivElement,
|
|
10
|
+
ComponentPropsWithoutRef<typeof ContextMenu.Content>
|
|
11
|
+
>(function Content({ className, onClick, ...props }, ref) {
|
|
12
|
+
return (
|
|
13
|
+
<ContextMenu.Portal>
|
|
14
|
+
<ContextMenu.Content
|
|
15
|
+
className={classNames(
|
|
16
|
+
'layer-components:(min-w-120px bg-white rounded-md border-default overflow-hidden p-2 shadow-md z-menu)',
|
|
17
|
+
'layer-components:transform-origin-[var(--radix-context-menu-transform-origin)]',
|
|
18
|
+
'layer-components:[&[data-state=open]]:animate-popover-in',
|
|
19
|
+
'layer-components:[&[data-state=closed]]:animate-popover-out',
|
|
20
|
+
'layer-components:(max-h-[var(--radix-context-menu-content-available-height)] overflow-y-auto)',
|
|
21
|
+
'important:motion-reduce:animate-none',
|
|
22
|
+
className,
|
|
23
|
+
)}
|
|
24
|
+
onClick={(ev) => {
|
|
25
|
+
ev.stopPropagation();
|
|
26
|
+
onClick?.(ev);
|
|
27
|
+
}}
|
|
28
|
+
ref={ref}
|
|
29
|
+
{...props}
|
|
30
|
+
/>
|
|
31
|
+
</ContextMenu.Portal>
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const ContextMenuArrow = withClassName(ContextMenu.Arrow, 'fill-white');
|
|
36
|
+
|
|
37
|
+
export const ContextMenuItem = withClassName(
|
|
38
|
+
ContextMenu.Item,
|
|
39
|
+
'flex items-center py-1 px-2 relative pl-25px select-none outline-none cursor-pointer',
|
|
40
|
+
'hover:bg-gray2 [&[data-highlighted=true]]:bg-gray2 [&[data-disabled=true]]:(opacity-50 cursor-default) disabled:(opacity-50 cursor-default)',
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
export const ContextMenuTrigger = withClassName(ContextMenu.Trigger, '');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './contextMenu/contextMenu.js';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import {
|
|
3
|
+
Dialog,
|
|
4
|
+
DialogContent,
|
|
5
|
+
DialogTrigger,
|
|
6
|
+
DialogActions,
|
|
7
|
+
DialogClose,
|
|
8
|
+
DialogTitle,
|
|
9
|
+
} from './Dialog.js';
|
|
10
|
+
|
|
11
|
+
const meta = {
|
|
12
|
+
title: 'Dialog',
|
|
13
|
+
component: Dialog,
|
|
14
|
+
argTypes: {},
|
|
15
|
+
parameters: {
|
|
16
|
+
controls: { expanded: true },
|
|
17
|
+
},
|
|
18
|
+
} satisfies Meta<typeof Dialog>;
|
|
19
|
+
|
|
20
|
+
export default meta;
|
|
21
|
+
|
|
22
|
+
type Story = StoryObj<typeof Dialog>;
|
|
23
|
+
|
|
24
|
+
export const Default: Story = {
|
|
25
|
+
args: {
|
|
26
|
+
children: (
|
|
27
|
+
<>
|
|
28
|
+
<DialogTrigger>Open</DialogTrigger>
|
|
29
|
+
<DialogContent>
|
|
30
|
+
<DialogTitle>Hello world</DialogTitle>
|
|
31
|
+
<DialogActions>
|
|
32
|
+
<DialogClose>Close</DialogClose>
|
|
33
|
+
</DialogActions>
|
|
34
|
+
</DialogContent>
|
|
35
|
+
</>
|
|
36
|
+
),
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
4
|
+
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
5
|
+
import {
|
|
6
|
+
ComponentPropsWithoutRef,
|
|
7
|
+
createContext,
|
|
8
|
+
forwardRef,
|
|
9
|
+
useCallback,
|
|
10
|
+
useContext,
|
|
11
|
+
useRef,
|
|
12
|
+
useState,
|
|
13
|
+
} from 'react';
|
|
14
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
15
|
+
import useMergedRef from '../../hooks/useMergedRef.js';
|
|
16
|
+
import { useParticles } from '../particles.js';
|
|
17
|
+
import classNames from 'classnames';
|
|
18
|
+
import { CheckIcon, ChevronDownIcon } from '@radix-ui/react-icons';
|
|
19
|
+
import { selectTriggerClassName } from '../select.js';
|
|
20
|
+
import { useDrag } from '@use-gesture/react';
|
|
21
|
+
|
|
22
|
+
const StyledOverlay = withClassName(
|
|
23
|
+
DialogPrimitive.Overlay,
|
|
24
|
+
'layer-components(bg-overlay fixed inset-0 z-dialog-backdrop animate-fade-in animate-duration-200)',
|
|
25
|
+
'layer-components:[&[data-state=closed]]:animate-fade-out',
|
|
26
|
+
'motion-reduce:animate-none',
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const StyledContent = withClassName(
|
|
30
|
+
DialogPrimitive.Content,
|
|
31
|
+
'layer-components:(translate-0 z-dialog fixed bottom-[calc(var(--viewport-bottom-offset,0px)+var(--gesture-y,0px))] left-0 right-0 h-min-content max-h-[calc(0.85*var(--viewport-height,100vh))])',
|
|
32
|
+
'transform-gpu',
|
|
33
|
+
'animate-ease-out',
|
|
34
|
+
'layer-components:(shadow-xl bg-white rounded-tl-xl rounded-tr-xl p-6 pt-8 border-default border-b-0 overflow-y-auto flex flex-col pb-[calc(3rem+env(safe-area-inset-bottom,0px))])',
|
|
35
|
+
'animate-fade-in-up-big animate-duration-200 [&[data-state=closed]]:animate-fade-out-down-big animate-ease-in motion-reduce:animate-none',
|
|
36
|
+
'layer-components:sm:(left-50% top-50% translate-[-50%] w-90vw max-w-450px max-h-85vh pb-6 rounded-lg border-b-1 pt-6)',
|
|
37
|
+
'sm:(animate-dialog-in [&[data-state=closed]]:animate-dialog-out motion-reduce:animate-none)',
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
export const Content = forwardRef<
|
|
41
|
+
HTMLDivElement,
|
|
42
|
+
ComponentPropsWithoutRef<typeof StyledContent> & {
|
|
43
|
+
outerClassName?: string;
|
|
44
|
+
width?: 'lg' | 'md' | 'sm';
|
|
45
|
+
}
|
|
46
|
+
>(function Content(
|
|
47
|
+
{ children, width, outerClassName, className, ...props },
|
|
48
|
+
ref,
|
|
49
|
+
) {
|
|
50
|
+
const particles = useParticles();
|
|
51
|
+
const wasOpenRef = useRef(false);
|
|
52
|
+
const openRef = useCallback(
|
|
53
|
+
(element: HTMLDivElement | null) => {
|
|
54
|
+
if (
|
|
55
|
+
!wasOpenRef.current &&
|
|
56
|
+
element?.getAttribute('data-state') === 'open'
|
|
57
|
+
) {
|
|
58
|
+
wasOpenRef.current = true;
|
|
59
|
+
|
|
60
|
+
const matchesSmall = !window.matchMedia('(min-width:600px)').matches;
|
|
61
|
+
if (!matchesSmall) return;
|
|
62
|
+
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
particles?.addParticles(
|
|
65
|
+
particles.elementExplosion({
|
|
66
|
+
count: 20,
|
|
67
|
+
borders: ['top'],
|
|
68
|
+
color: [
|
|
69
|
+
{
|
|
70
|
+
space: 'rgb',
|
|
71
|
+
values: [0, 0, 0],
|
|
72
|
+
opacity: 0.02,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
space: 'rgb',
|
|
76
|
+
values: [0, 0, 0],
|
|
77
|
+
opacity: 0,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
element,
|
|
81
|
+
startRadius: 15,
|
|
82
|
+
endRadius: 0,
|
|
83
|
+
lifespan: 1000,
|
|
84
|
+
force: 0.5,
|
|
85
|
+
drag: 0.01,
|
|
86
|
+
forceFuzz: 0.5,
|
|
87
|
+
angleFuzz: 0.1,
|
|
88
|
+
}),
|
|
89
|
+
);
|
|
90
|
+
}, 180);
|
|
91
|
+
} else if (element?.getAttribute('data-state') === 'closed') {
|
|
92
|
+
wasOpenRef.current = false;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
[particles],
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const gestureRef = useRef<HTMLDivElement>(null);
|
|
99
|
+
|
|
100
|
+
const finalRef = useMergedRef(ref, openRef, gestureRef);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<DialogPrimitive.Portal>
|
|
104
|
+
<StyledOverlay />
|
|
105
|
+
<StyledContent
|
|
106
|
+
data-dialog-content
|
|
107
|
+
ref={finalRef}
|
|
108
|
+
{...props}
|
|
109
|
+
className={classNames(
|
|
110
|
+
{
|
|
111
|
+
'md:max-w-800px': width === 'lg',
|
|
112
|
+
'max-w-600px': width === 'md',
|
|
113
|
+
'max-w-300px': width === 'sm',
|
|
114
|
+
},
|
|
115
|
+
outerClassName || className,
|
|
116
|
+
)}
|
|
117
|
+
>
|
|
118
|
+
<DialogSwipeHandle />
|
|
119
|
+
{children}
|
|
120
|
+
</StyledContent>
|
|
121
|
+
</DialogPrimitive.Portal>
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
export const DialogSwipeHandle = forwardRef<
|
|
126
|
+
HTMLDivElement,
|
|
127
|
+
ComponentPropsWithoutRef<'div'>
|
|
128
|
+
>(function DialogSwipeHandle({ className, ...props }, ref) {
|
|
129
|
+
const close = useContext(DialogCloseContext);
|
|
130
|
+
const innerRef = useRef<HTMLDivElement>(null);
|
|
131
|
+
useDrag(
|
|
132
|
+
({ swipe: [, swipeY], movement: [, dy], velocity: [, vy], last }) => {
|
|
133
|
+
const content = findParentDialogContent(innerRef.current);
|
|
134
|
+
if (!content) return;
|
|
135
|
+
|
|
136
|
+
const contentHeight = content.clientHeight;
|
|
137
|
+
|
|
138
|
+
if (last) console.log(swipeY, dy, contentHeight);
|
|
139
|
+
|
|
140
|
+
if (last && (swipeY === 1 || dy > contentHeight / 2)) {
|
|
141
|
+
console.log('close');
|
|
142
|
+
close();
|
|
143
|
+
}
|
|
144
|
+
const gestureY = last ? 0 : -Math.max(0, dy);
|
|
145
|
+
content.style.setProperty('--gesture-y', `${gestureY}px`);
|
|
146
|
+
content.style.setProperty('transition', last ? 'bottom 0.2s' : '');
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
target: innerRef,
|
|
150
|
+
axis: 'y',
|
|
151
|
+
},
|
|
152
|
+
);
|
|
153
|
+
const finalRef = useMergedRef(ref, innerRef);
|
|
154
|
+
return (
|
|
155
|
+
<div
|
|
156
|
+
ref={finalRef}
|
|
157
|
+
{...props}
|
|
158
|
+
className={classNames(
|
|
159
|
+
'absolute top-0 left-50% transform-gpu -translate-x-1/2 w-20% py-2 rounded-full cursor-grab sm:display-none touch-none',
|
|
160
|
+
className,
|
|
161
|
+
)}
|
|
162
|
+
>
|
|
163
|
+
<div className="w-full h-[4px] bg-gray-4 rounded-full" />
|
|
164
|
+
</div>
|
|
165
|
+
);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
function findParentDialogContent(
|
|
169
|
+
element: HTMLElement | null,
|
|
170
|
+
): HTMLElement | null {
|
|
171
|
+
if (!element) return null;
|
|
172
|
+
if (element.getAttribute('data-dialog-content')) return element;
|
|
173
|
+
return findParentDialogContent(element.parentElement);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const DialogCloseContext = createContext<() => void>(() => {});
|
|
177
|
+
|
|
178
|
+
const StyledTitle = withClassName(
|
|
179
|
+
DialogPrimitive.Title,
|
|
180
|
+
'font-title color-black text-3xl mb-4 mt-0',
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
const StyledDescription = withClassName(
|
|
184
|
+
DialogPrimitive.Description,
|
|
185
|
+
'mt-3 mb-6 color-gray8 text-md leading-6',
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
// Exports
|
|
189
|
+
export const Dialog = (props: DialogPrimitive.DialogProps) => {
|
|
190
|
+
const [innerOpen, innerOnOpenChange] = useState(props.defaultOpen);
|
|
191
|
+
const open = props.open ?? innerOpen;
|
|
192
|
+
const onOpenChange = useCallback(
|
|
193
|
+
(open: boolean) => {
|
|
194
|
+
innerOnOpenChange(open);
|
|
195
|
+
props.onOpenChange?.(open);
|
|
196
|
+
},
|
|
197
|
+
[props.onOpenChange],
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
const close = useCallback(() => {
|
|
201
|
+
onOpenChange(false);
|
|
202
|
+
}, [onOpenChange]);
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<DialogCloseContext.Provider value={close}>
|
|
206
|
+
<DialogPrimitive.Root
|
|
207
|
+
{...props}
|
|
208
|
+
open={open}
|
|
209
|
+
onOpenChange={onOpenChange}
|
|
210
|
+
/>
|
|
211
|
+
</DialogCloseContext.Provider>
|
|
212
|
+
);
|
|
213
|
+
};
|
|
214
|
+
export const DialogTrigger = DialogPrimitive.Trigger;
|
|
215
|
+
export const DialogContent = Content;
|
|
216
|
+
export const DialogTitle = StyledTitle;
|
|
217
|
+
export const DialogDescription = StyledDescription;
|
|
218
|
+
export const DialogClose = DialogPrimitive.Close;
|
|
219
|
+
|
|
220
|
+
export type { DialogProps } from '@radix-ui/react-dialog';
|
|
221
|
+
|
|
222
|
+
export const DialogActions = withClassName(
|
|
223
|
+
'div',
|
|
224
|
+
'flex justify-end sticky w-full gap-3 items-center bg-white py-3 translate-y-6 flex-wrap',
|
|
225
|
+
'bottom--6',
|
|
226
|
+
'sm:(bottom-0)',
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
export const DialogSelectTrigger = forwardRef<
|
|
230
|
+
HTMLButtonElement,
|
|
231
|
+
DialogPrimitive.DialogTriggerProps
|
|
232
|
+
>(function DialogSelectTrigger({ children, className, ...props }, ref) {
|
|
233
|
+
return (
|
|
234
|
+
<DialogPrimitive.Trigger
|
|
235
|
+
className={classNames(selectTriggerClassName, className)}
|
|
236
|
+
{...props}
|
|
237
|
+
>
|
|
238
|
+
<span>{children}</span>
|
|
239
|
+
<ChevronDownIcon />
|
|
240
|
+
</DialogPrimitive.Trigger>
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
export const DialogSelectList = withClassName(
|
|
245
|
+
RadioGroupPrimitive.Root,
|
|
246
|
+
'flex flex-col gap-2 overflow-y-auto p-2',
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
export const DialogSelectItemRoot = withClassName(
|
|
250
|
+
RadioGroupPrimitive.Item,
|
|
251
|
+
'flex items-center gap-3 w-full py-3 px-4 text-left border-none rounded-lg font-normal bg-transparent [&:nth-child(2n+1)]:bg-gray-blend cursor-pointer transition-all',
|
|
252
|
+
'[&[data-state=checked]]:(bg-primary-wash text-primary-dark)',
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
export const DialogSelectItem = forwardRef<
|
|
256
|
+
HTMLButtonElement,
|
|
257
|
+
ComponentPropsWithoutRef<typeof DialogSelectItemRoot>
|
|
258
|
+
>(function DialogSelectItem({ children, ...props }, ref) {
|
|
259
|
+
return (
|
|
260
|
+
<DialogSelectItemRoot {...props}>
|
|
261
|
+
<span className="flex-1">{children}</span>
|
|
262
|
+
<RadioGroupPrimitive.Indicator className="flex-0-0-auto">
|
|
263
|
+
<CheckIcon />
|
|
264
|
+
</RadioGroupPrimitive.Indicator>
|
|
265
|
+
</DialogSelectItemRoot>
|
|
266
|
+
);
|
|
267
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Dialog.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dialog/index.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { HTMLAttributes, forwardRef } from 'react';
|
|
2
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
3
|
+
import classNames from 'classnames';
|
|
4
|
+
|
|
5
|
+
const DividerBase = withClassName('div', 'w-full h-1px bg-black relative');
|
|
6
|
+
|
|
7
|
+
export interface DividerProps extends HTMLAttributes<HTMLDivElement> {
|
|
8
|
+
compensate?: 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
9
|
+
padded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Divider = forwardRef<HTMLDivElement, DividerProps>(
|
|
13
|
+
function Divider({ compensate, padded, className, ...props }, ref) {
|
|
14
|
+
return (
|
|
15
|
+
<DividerBase
|
|
16
|
+
ref={ref}
|
|
17
|
+
style={{
|
|
18
|
+
left: compensate ? `calc(${compensate} * 0.25rem)` : undefined,
|
|
19
|
+
width: compensate ? `calc(100% - ${compensate} * 0.5rem)` : undefined,
|
|
20
|
+
}}
|
|
21
|
+
{...props}
|
|
22
|
+
className={classNames(padded && 'my-4', className)}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
},
|
|
26
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Divider.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './divider/index.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import {
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuItemRightSlot,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
} from './DropdownMenu.js';
|
|
9
|
+
import { Icon } from '../icon.js';
|
|
10
|
+
import { DropdownMenuLabel } from '@radix-ui/react-dropdown-menu';
|
|
11
|
+
|
|
12
|
+
const meta = {
|
|
13
|
+
title: 'DropdownMenu',
|
|
14
|
+
component: DropdownMenu,
|
|
15
|
+
argTypes: {},
|
|
16
|
+
parameters: {
|
|
17
|
+
controls: { expanded: true },
|
|
18
|
+
},
|
|
19
|
+
} satisfies Meta<typeof DropdownMenu>;
|
|
20
|
+
|
|
21
|
+
export default meta;
|
|
22
|
+
|
|
23
|
+
type Story = StoryObj<typeof DropdownMenu>;
|
|
24
|
+
|
|
25
|
+
export const Default: Story = {
|
|
26
|
+
args: {
|
|
27
|
+
children: (
|
|
28
|
+
<>
|
|
29
|
+
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
|
|
30
|
+
<DropdownMenuContent>
|
|
31
|
+
<DropdownMenuItem>
|
|
32
|
+
<DropdownMenuLabel>Item 1</DropdownMenuLabel>
|
|
33
|
+
<DropdownMenuItemRightSlot>
|
|
34
|
+
<Icon name="flag" />
|
|
35
|
+
</DropdownMenuItemRightSlot>
|
|
36
|
+
</DropdownMenuItem>
|
|
37
|
+
<DropdownMenuItem>
|
|
38
|
+
<DropdownMenuLabel>Item 2</DropdownMenuLabel>
|
|
39
|
+
<DropdownMenuItemRightSlot>
|
|
40
|
+
<Icon name="add_person" />
|
|
41
|
+
</DropdownMenuItemRightSlot>
|
|
42
|
+
</DropdownMenuItem>
|
|
43
|
+
</DropdownMenuContent>
|
|
44
|
+
</>
|
|
45
|
+
),
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
|
4
|
+
import { withClassName } from '../../hooks/withClassName.js';
|
|
5
|
+
import classNames from 'classnames';
|
|
6
|
+
|
|
7
|
+
const StyledContent = withClassName(
|
|
8
|
+
DropdownMenuPrimitive.Content,
|
|
9
|
+
'min-w-220px bg-white z-menu shadow-lg rounded-xl border-default',
|
|
10
|
+
'layer-components:transform-origin-[var(--radix-dropdown-menu-transform-origin)]',
|
|
11
|
+
'layer-components:[&[data-state=open]]:animate-popover-in',
|
|
12
|
+
'layer-components:[&[data-state=closed]]:animate-popover-out',
|
|
13
|
+
'layer-components:(max-h-[var(--radix-dropdown-menu-content-available-height)])',
|
|
14
|
+
'important:motion-reduce:animate-none',
|
|
15
|
+
'will-change-transform',
|
|
16
|
+
);
|
|
17
|
+
const itemClassName = classNames(
|
|
18
|
+
'text-md leading-4 color-black rounded-sm flex items-center pr-4 pl-8 py-3 relative text-left select-none cursor-pointer',
|
|
19
|
+
'[&[data-disabled]]:(color-gray9 pointer-events-none)',
|
|
20
|
+
'focus-visible:(bg-gray2 color-gray9)',
|
|
21
|
+
'focus:outline-none',
|
|
22
|
+
);
|
|
23
|
+
const StyledItem = withClassName(DropdownMenuPrimitive.Item, itemClassName);
|
|
24
|
+
const StyledCheckboxItem = withClassName(
|
|
25
|
+
DropdownMenuPrimitive.CheckboxItem,
|
|
26
|
+
itemClassName,
|
|
27
|
+
);
|
|
28
|
+
const StyledRadioItem = withClassName(
|
|
29
|
+
DropdownMenuPrimitive.RadioItem,
|
|
30
|
+
itemClassName,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const StyledLabel = withClassName(
|
|
34
|
+
DropdownMenuPrimitive.Label,
|
|
35
|
+
'pl-25px text-12px leading-6 color-gray7',
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const StyledSeparator = withClassName(
|
|
39
|
+
DropdownMenuPrimitive.Separator,
|
|
40
|
+
'h-1px bg-gray5 m-5px',
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const StyledItemIndicator = withClassName(
|
|
44
|
+
DropdownMenuPrimitive.ItemIndicator,
|
|
45
|
+
'absolute left-0 w-25px inline-flex items-center justify-center',
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const StyledArrow = withClassName(
|
|
49
|
+
DropdownMenuPrimitive.Arrow,
|
|
50
|
+
'fill-white stroke-black stroke-1',
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const StyledTrigger = withClassName(
|
|
54
|
+
DropdownMenuPrimitive.Trigger,
|
|
55
|
+
'select-none',
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const StyledPortal = DropdownMenuPrimitive.Portal;
|
|
59
|
+
|
|
60
|
+
// Exports
|
|
61
|
+
export const DropdownMenu = DropdownMenuPrimitive.Root;
|
|
62
|
+
export const DropdownMenuTrigger = StyledTrigger;
|
|
63
|
+
export const DropdownMenuItem = StyledItem;
|
|
64
|
+
export const DropdownMenuCheckboxItem = StyledCheckboxItem;
|
|
65
|
+
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
|
66
|
+
export const DropdownMenuRadioItem = StyledRadioItem;
|
|
67
|
+
export const DropdownMenuItemIndicator = StyledItemIndicator;
|
|
68
|
+
export const DropdownMenuLabel = StyledLabel;
|
|
69
|
+
export const DropdownMenuSeparator = StyledSeparator;
|
|
70
|
+
export const DropdownMenuArrow = StyledArrow;
|
|
71
|
+
|
|
72
|
+
export const DropdownMenuContent = ({
|
|
73
|
+
children,
|
|
74
|
+
forceMount,
|
|
75
|
+
...props
|
|
76
|
+
}: DropdownMenuPrimitive.DropdownMenuContentProps & {
|
|
77
|
+
forceMount?: boolean;
|
|
78
|
+
}) => {
|
|
79
|
+
return (
|
|
80
|
+
<StyledPortal forceMount={forceMount}>
|
|
81
|
+
<StyledContent {...props}>
|
|
82
|
+
<div className="overflow-hidden rounded-xl">{children}</div>
|
|
83
|
+
<StyledArrow />
|
|
84
|
+
</StyledContent>
|
|
85
|
+
</StyledPortal>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export const DropdownMenuItemRightSlot = withClassName('div', 'ml-auto');
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './DropdownMenu.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './dropdownMenu/index.js';
|