@koide-labs/ui 0.0.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/.husky/pre-commit +1 -0
- package/.storybook/main.ts +25 -0
- package/.storybook/preview-head.html +6 -0
- package/.storybook/preview.tsx +48 -0
- package/.storybook/vitest.setup.ts +8 -0
- package/README.md +11 -0
- package/eslint.config.mjs +29 -0
- package/lint-staged.config.js +15 -0
- package/package.json +95 -0
- package/pnpm-workspace.yaml +2 -0
- package/postcss.config.mjs +7 -0
- package/prettier.config.mjs +24 -0
- package/scripts/build-icon-types.ts +38 -0
- package/src/-types.ts +8 -0
- package/src/-utils.tsx +64 -0
- package/src/components/accordion/accordion.module.css +44 -0
- package/src/components/accordion/accordion.stories.tsx +36 -0
- package/src/components/accordion/index.tsx +67 -0
- package/src/components/alert-dialog/alert-dialog.module.css +5 -0
- package/src/components/alert-dialog/alert-dialog.stories.tsx +53 -0
- package/src/components/alert-dialog/index.tsx +138 -0
- package/src/components/anchor/anchor.module.css +18 -0
- package/src/components/anchor/anchor.stories.tsx +28 -0
- package/src/components/anchor/index.tsx +45 -0
- package/src/components/avatar/avatar.module.css +56 -0
- package/src/components/avatar/avatar.stories.tsx +61 -0
- package/src/components/avatar/index.tsx +82 -0
- package/src/components/badge/badge.module.css +35 -0
- package/src/components/badge/badge.stories.tsx +60 -0
- package/src/components/badge/index.tsx +71 -0
- package/src/components/button/button.module.css +42 -0
- package/src/components/button/button.stories.tsx +108 -0
- package/src/components/button/index.tsx +63 -0
- package/src/components/checkbox/checkbox.module.css +36 -0
- package/src/components/checkbox/checkbox.stories.tsx +21 -0
- package/src/components/checkbox/index.tsx +41 -0
- package/src/components/code/code.module.css +20 -0
- package/src/components/code/code.stories.tsx +42 -0
- package/src/components/code/index.tsx +73 -0
- package/src/components/collapse/collapse.module.css +27 -0
- package/src/components/collapse/collapse.stories.tsx +27 -0
- package/src/components/collapse/index.tsx +59 -0
- package/src/components/command/command.module.css +95 -0
- package/src/components/command/command.stories.tsx +38 -0
- package/src/components/command/index.tsx +108 -0
- package/src/components/context-menu/context-menu.module.css +36 -0
- package/src/components/context-menu/context-menu.stories.tsx +99 -0
- package/src/components/context-menu/index.tsx +242 -0
- package/src/components/dialog/dialog.module.css +71 -0
- package/src/components/dialog/dialog.stories.tsx +29 -0
- package/src/components/dialog/index.tsx +148 -0
- package/src/components/heading/heading.module.css +3 -0
- package/src/components/heading/heading.stories.tsx +52 -0
- package/src/components/heading/index.tsx +112 -0
- package/src/components/icon/icon-names.ts +3189 -0
- package/src/components/icon/icon.module.css +36 -0
- package/src/components/icon/icon.stories.tsx +40 -0
- package/src/components/icon/index.tsx +60 -0
- package/src/components/icon-button/icon-button.module.css +33 -0
- package/src/components/icon-button/icon-button.stories.tsx +59 -0
- package/src/components/icon-button/index.tsx +48 -0
- package/src/components/inline-code/index.tsx +29 -0
- package/src/components/inline-code/inline-code.module.css +13 -0
- package/src/components/inline-code/inline-code.stories.tsx +31 -0
- package/src/components/input/index.tsx +22 -0
- package/src/components/input/input.module.css +23 -0
- package/src/components/input/input.stories.tsx +52 -0
- package/src/components/meter/index.tsx +55 -0
- package/src/components/meter/meter.module.css +23 -0
- package/src/components/meter/meter.stories.tsx +31 -0
- package/src/components/multiline-input/index.tsx +58 -0
- package/src/components/multiline-input/multiline-input.stories.tsx +26 -0
- package/src/components/number-input/index.tsx +74 -0
- package/src/components/number-input/number-input.module.css +41 -0
- package/src/components/number-input/number-input.stories.tsx +24 -0
- package/src/components/password-input/index.tsx +24 -0
- package/src/components/password-input/password-input.module.css +10 -0
- package/src/components/password-input/password-input.stories.tsx +24 -0
- package/src/components/pill/index.tsx +45 -0
- package/src/components/pill/pill.module.css +22 -0
- package/src/components/pill/pill.stories.tsx +83 -0
- package/src/components/popover/index.tsx +94 -0
- package/src/components/popover/popover.module.css +8 -0
- package/src/components/popover/popover.stories.tsx +53 -0
- package/src/components/preview-card/index.tsx +68 -0
- package/src/components/preview-card/preview-card.module.css +5 -0
- package/src/components/preview-card/preview-card.stories.tsx +58 -0
- package/src/components/radio/index.tsx +67 -0
- package/src/components/radio/radio-group.module.css +5 -0
- package/src/components/radio/radio.module.css +36 -0
- package/src/components/radio/radio.stories.tsx +27 -0
- package/src/components/search-bar/index.tsx +60 -0
- package/src/components/search-bar/search-bar.module.css +29 -0
- package/src/components/search-bar/search-bar.stories.tsx +37 -0
- package/src/components/select/index.tsx +132 -0
- package/src/components/select/select.module.css +63 -0
- package/src/components/select/select.stories.tsx +49 -0
- package/src/components/separator/index.tsx +28 -0
- package/src/components/separator/separator.module.css +24 -0
- package/src/components/separator/separator.stories.tsx +40 -0
- package/src/components/slider/index.tsx +28 -0
- package/src/components/slider/slider.module.css +52 -0
- package/src/components/slider/slider.stories.tsx +53 -0
- package/src/components/spinner/index.tsx +14 -0
- package/src/components/spinner/spinner.module.css +13 -0
- package/src/components/spinner/spinner.stories.tsx +17 -0
- package/src/components/stacked-avatars/index.tsx +88 -0
- package/src/components/stacked-avatars/stacked-avatars.module.css +79 -0
- package/src/components/stacked-avatars/stacked-avatars.stories.tsx +48 -0
- package/src/components/status-banner/index.tsx +96 -0
- package/src/components/status-banner/status-banner.module.css +52 -0
- package/src/components/status-banner/status-banner.stories.tsx +44 -0
- package/src/components/surface/index.tsx +83 -0
- package/src/components/surface/surface.module.css +35 -0
- package/src/components/surface/surface.stories.tsx +84 -0
- package/src/components/switch/index.tsx +23 -0
- package/src/components/switch/switch.module.css +45 -0
- package/src/components/switch/switch.stories.tsx +48 -0
- package/src/components/tabs/index.tsx +126 -0
- package/src/components/tabs/tabs.module.css +134 -0
- package/src/components/tabs/tabs.stories.tsx +88 -0
- package/src/components/text/index.tsx +69 -0
- package/src/components/text/text.module.css +76 -0
- package/src/components/text/text.stories.tsx +107 -0
- package/src/components/theme-provider/index.ts +2 -0
- package/src/components/theme-provider/theme-context.tsx +18 -0
- package/src/components/theme-provider/theme-provider.stories.tsx +47 -0
- package/src/components/theme-provider/theme-provider.tsx +77 -0
- package/src/components/timestamp/index.tsx +131 -0
- package/src/components/timestamp/timestamp.module.css +8 -0
- package/src/components/timestamp/timestamp.stories.tsx +37 -0
- package/src/components/toast/index.ts +2 -0
- package/src/components/toast/toast.module.css +163 -0
- package/src/components/toast/toast.stories.tsx +53 -0
- package/src/components/toast/toast.tsx +104 -0
- package/src/components/toast/use-toast-manager.ts +63 -0
- package/src/components/tooltip/index.tsx +61 -0
- package/src/components/tooltip/tooltip-arrow.tsx +17 -0
- package/src/components/tooltip/tooltip.module.css +44 -0
- package/src/components/tooltip/tooltip.stories.tsx +76 -0
- package/src/components/view/index.tsx +137 -0
- package/src/components/view/view.module.css +11 -0
- package/src/components/view/view.stories.tsx +131 -0
- package/src/components/view/view_colorway.module.css +280 -0
- package/src/components/view/view_interactive.module.css +127 -0
- package/src/components/view/view_loading.module.css +58 -0
- package/src/components/visually-hidden/index.ts +1 -0
- package/src/index.ts +49 -0
- package/src/integrations/react-markdown/index.tsx +134 -0
- package/src/integrations/react-markdown/react-markdown.module.css +62 -0
- package/src/integrations/react-markdown/react-markdown.stories.tsx +31 -0
- package/src/integrations/remix.ts +12 -0
- package/src/integrations/tailwind.css +173 -0
- package/src/integrations/twemoij/index.tsx +13 -0
- package/src/integrations/twemoij/twemoji.module.css +7 -0
- package/src/integrations/twemoij/twemoji.stories.tsx +40 -0
- package/src/stories/components/all-variants.tsx +40 -0
- package/src/stories/data.ts +72 -0
- package/src/stories/utils.ts +20 -0
- package/src/styles/core.css +153 -0
- package/src/styles/themes/dark.css +86 -0
- package/src/styles/themes/light.css +86 -0
- package/src/styles/tokens.ts +282 -0
- package/src/styles/transitions.module.css +31 -0
- package/stylelint.config.mjs +29 -0
- package/tsconfig.app.json +35 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +26 -0
- package/vite.config.ts +103 -0
- package/vitest.shims.d.ts +1 -0
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
|
|
2
|
+
import clsx from "clsx";
|
|
3
|
+
import type { ComponentProps, ReactElement, ReactNode } from "react";
|
|
4
|
+
|
|
5
|
+
import type { Size } from "~/styles/tokens";
|
|
6
|
+
|
|
7
|
+
import { Button, type ButtonProps } from "../button";
|
|
8
|
+
import { IconButton } from "../icon-button";
|
|
9
|
+
import { Surface, type Background } from "../surface";
|
|
10
|
+
import { Text } from "../text";
|
|
11
|
+
import { View } from "../view";
|
|
12
|
+
|
|
13
|
+
import transitionStyles from "../../styles/transitions.module.css";
|
|
14
|
+
import styles from "./dialog.module.css";
|
|
15
|
+
|
|
16
|
+
export type BaseDialogProps = {
|
|
17
|
+
/**
|
|
18
|
+
* The title of the dialog.
|
|
19
|
+
* Renders DialogPrimitive.Title at "2xl" size.
|
|
20
|
+
*/
|
|
21
|
+
title?: string;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The description of the dialog.
|
|
25
|
+
* Renders DialogPrimitive.Description at default size & dimmer color.
|
|
26
|
+
*/
|
|
27
|
+
description?: string;
|
|
28
|
+
|
|
29
|
+
/** Dialog content */
|
|
30
|
+
children?: ReactNode;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Specify trigger to open alert. You can still used a {@link https://base-ui.com/react/components/dialog#detached-triggers detached trigger}
|
|
34
|
+
*/
|
|
35
|
+
trigger?: ReactElement;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Maximum width of the dialog. Defaults to "md".
|
|
39
|
+
*/
|
|
40
|
+
width?: Extract<Size, "sm" | "md" | "lg">;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Override popup background. Defaults to "root"
|
|
44
|
+
*/
|
|
45
|
+
background?: Background;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Vertically center dialog (or not). You probably shouldn't if you suspect
|
|
49
|
+
* content will overflow.
|
|
50
|
+
*/
|
|
51
|
+
centered?: boolean;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Apply className to the dialog content
|
|
55
|
+
*/
|
|
56
|
+
className?: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type DialogProps = ComponentProps<typeof DialogPrimitive.Root> &
|
|
60
|
+
BaseDialogProps & {
|
|
61
|
+
/**
|
|
62
|
+
* Show close icon
|
|
63
|
+
*/
|
|
64
|
+
closable?: boolean;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export function Dialog({
|
|
68
|
+
title,
|
|
69
|
+
description,
|
|
70
|
+
trigger,
|
|
71
|
+
width = "md",
|
|
72
|
+
background = "root",
|
|
73
|
+
centered,
|
|
74
|
+
closable,
|
|
75
|
+
children,
|
|
76
|
+
className,
|
|
77
|
+
...props
|
|
78
|
+
}: DialogProps) {
|
|
79
|
+
return (
|
|
80
|
+
<DialogPrimitive.Root {...props}>
|
|
81
|
+
{trigger ? <DialogPrimitive.Trigger render={trigger} /> : null}
|
|
82
|
+
<DialogPrimitive.Portal>
|
|
83
|
+
<DialogPrimitive.Backdrop
|
|
84
|
+
className={clsx(
|
|
85
|
+
styles["dialog__backdrop"],
|
|
86
|
+
transitionStyles["transition_opacity"],
|
|
87
|
+
)}
|
|
88
|
+
/>
|
|
89
|
+
<DialogPrimitive.Popup
|
|
90
|
+
className={clsx(
|
|
91
|
+
styles["dialog__popup"],
|
|
92
|
+
centered && styles["dialog__popup_centered"],
|
|
93
|
+
transitionStyles["transition_scale"],
|
|
94
|
+
)}
|
|
95
|
+
>
|
|
96
|
+
<Surface
|
|
97
|
+
background={background}
|
|
98
|
+
className={clsx(
|
|
99
|
+
styles["dialog__content"],
|
|
100
|
+
styles[`dialog__content_width_${width}`],
|
|
101
|
+
className,
|
|
102
|
+
)}
|
|
103
|
+
>
|
|
104
|
+
{title || description ? (
|
|
105
|
+
<View className={styles["dialog__header"]}>
|
|
106
|
+
{title ? (
|
|
107
|
+
<Text render={<DialogPrimitive.Title />} size="2xl">
|
|
108
|
+
{title}
|
|
109
|
+
</Text>
|
|
110
|
+
) : null}
|
|
111
|
+
{description ? (
|
|
112
|
+
<Text
|
|
113
|
+
multiline
|
|
114
|
+
color="dimmer"
|
|
115
|
+
render={<DialogPrimitive.Description />}
|
|
116
|
+
>
|
|
117
|
+
{description}
|
|
118
|
+
</Text>
|
|
119
|
+
) : null}
|
|
120
|
+
</View>
|
|
121
|
+
) : null}
|
|
122
|
+
|
|
123
|
+
{children}
|
|
124
|
+
|
|
125
|
+
{closable ? (
|
|
126
|
+
<DialogPrimitive.Close
|
|
127
|
+
data-framework-close
|
|
128
|
+
className={styles["dialog__close"]}
|
|
129
|
+
render={
|
|
130
|
+
<IconButton
|
|
131
|
+
size="sm"
|
|
132
|
+
icon="close-line"
|
|
133
|
+
alt="Close"
|
|
134
|
+
interactive="no-fill"
|
|
135
|
+
/>
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
) : null}
|
|
139
|
+
</Surface>
|
|
140
|
+
</DialogPrimitive.Popup>
|
|
141
|
+
</DialogPrimitive.Portal>
|
|
142
|
+
</DialogPrimitive.Root>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function DialogClose(props: ButtonProps) {
|
|
147
|
+
return <DialogPrimitive.Close render={<Button {...props} />} />;
|
|
148
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Heading, Section, type HeadingProps } from ".";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Typography/Heading",
|
|
7
|
+
component: Heading,
|
|
8
|
+
parameters: { layout: "centered" },
|
|
9
|
+
argTypes: {
|
|
10
|
+
level: {
|
|
11
|
+
control: "select",
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
} satisfies Meta<HeadingProps>;
|
|
15
|
+
|
|
16
|
+
export default meta;
|
|
17
|
+
|
|
18
|
+
type Story = StoryObj<typeof meta>;
|
|
19
|
+
|
|
20
|
+
export const Default: Story = {
|
|
21
|
+
args: {
|
|
22
|
+
level: 1,
|
|
23
|
+
},
|
|
24
|
+
render: ({ level }) => (
|
|
25
|
+
<Heading level={level}>Hello World (h{level})</Heading>
|
|
26
|
+
),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const AutoLevel: Story = {
|
|
30
|
+
args: {
|
|
31
|
+
level: 1,
|
|
32
|
+
},
|
|
33
|
+
parameters: {
|
|
34
|
+
docs: {
|
|
35
|
+
description: {
|
|
36
|
+
story:
|
|
37
|
+
"When nested within `Section` components, `Heading` will automatically determine its level based on the current section depth.",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
render: (props) => (
|
|
42
|
+
<Section {...props}>
|
|
43
|
+
<Heading>Hello World</Heading>
|
|
44
|
+
<Section>
|
|
45
|
+
<Heading>Hello World</Heading>
|
|
46
|
+
<Section>
|
|
47
|
+
<Heading>Hello World</Heading>
|
|
48
|
+
</Section>
|
|
49
|
+
</Section>
|
|
50
|
+
</Section>
|
|
51
|
+
),
|
|
52
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { mergeProps, useRender } from "@base-ui/react";
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
|
|
4
|
+
import type { Size } from "~/styles/tokens";
|
|
5
|
+
|
|
6
|
+
import { Text, type TextProps } from "../text";
|
|
7
|
+
|
|
8
|
+
import styles from "./heading.module.css";
|
|
9
|
+
|
|
10
|
+
type Level = 1 | 2 | 3 | 4 | 5 | 6;
|
|
11
|
+
|
|
12
|
+
const levelToClassName: Record<Level, Size> = {
|
|
13
|
+
1: "3xl",
|
|
14
|
+
2: "2xl",
|
|
15
|
+
3: "xl",
|
|
16
|
+
4: "lg",
|
|
17
|
+
5: "md",
|
|
18
|
+
6: "md",
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
const LevelContext = createContext<number>(0);
|
|
22
|
+
|
|
23
|
+
export interface HeadingProps extends useRender.ComponentProps<"h1"> {
|
|
24
|
+
/**
|
|
25
|
+
* Explicitly set heading level, which determines size.
|
|
26
|
+
* Defaults to level provided by section.
|
|
27
|
+
*/
|
|
28
|
+
level?: Level;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Override text size.
|
|
32
|
+
* For example, you may want an h2 but render it as "sm".
|
|
33
|
+
*/
|
|
34
|
+
size?: Size;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Override text color.
|
|
38
|
+
*/
|
|
39
|
+
color?: TextProps["color"];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function Heading({
|
|
43
|
+
level,
|
|
44
|
+
size,
|
|
45
|
+
color,
|
|
46
|
+
render,
|
|
47
|
+
...props
|
|
48
|
+
}: HeadingProps) {
|
|
49
|
+
const levelContext = useContext(LevelContext);
|
|
50
|
+
const normalizedLevel = normalizeLevel(level || levelContext);
|
|
51
|
+
|
|
52
|
+
const element = useRender({
|
|
53
|
+
defaultTagName: `h${normalizedLevel}`,
|
|
54
|
+
render,
|
|
55
|
+
props: mergeProps(
|
|
56
|
+
{
|
|
57
|
+
className: styles["heading"],
|
|
58
|
+
},
|
|
59
|
+
props,
|
|
60
|
+
),
|
|
61
|
+
});
|
|
62
|
+
return (
|
|
63
|
+
<Text
|
|
64
|
+
render={element}
|
|
65
|
+
size={size || levelToClassName[normalizedLevel]}
|
|
66
|
+
color={color}
|
|
67
|
+
/>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Sections inspired by Carbon Design
|
|
72
|
+
// https://react.carbondesignsystem.com/?path=%2Fdocs%2Fcomponents-heading--overview
|
|
73
|
+
export interface SectionProps extends useRender.ComponentProps<"section"> {
|
|
74
|
+
/**
|
|
75
|
+
* Explicitly set section level, but does not override heading level
|
|
76
|
+
* Automatically increases by one level from the current section
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* <Section level={1}>
|
|
80
|
+
* <Heading>1</Heading>
|
|
81
|
+
* </Section>
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* <Section>
|
|
85
|
+
* <Heading>1</Heading>
|
|
86
|
+
* <Section>
|
|
87
|
+
* <Heading>2</Heading>
|
|
88
|
+
* <Heading level={6}>6</Heading>
|
|
89
|
+
* </Section>
|
|
90
|
+
* </Section>
|
|
91
|
+
*/
|
|
92
|
+
level?: Level;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function Section({ level, render, ...props }: SectionProps) {
|
|
96
|
+
const levelContext = useContext(LevelContext) ?? 0;
|
|
97
|
+
const normalizedLevel = normalizeLevel(level || levelContext + 1);
|
|
98
|
+
const element = useRender({
|
|
99
|
+
defaultTagName: "section",
|
|
100
|
+
render,
|
|
101
|
+
props,
|
|
102
|
+
});
|
|
103
|
+
return (
|
|
104
|
+
<LevelContext.Provider value={normalizedLevel}>
|
|
105
|
+
{element}
|
|
106
|
+
</LevelContext.Provider>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function normalizeLevel(level: number = 1) {
|
|
111
|
+
return Math.max(Math.min(level, 6), 1) as Level;
|
|
112
|
+
}
|