@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.
Files changed (170) hide show
  1. package/.husky/pre-commit +1 -0
  2. package/.storybook/main.ts +25 -0
  3. package/.storybook/preview-head.html +6 -0
  4. package/.storybook/preview.tsx +48 -0
  5. package/.storybook/vitest.setup.ts +8 -0
  6. package/README.md +11 -0
  7. package/eslint.config.mjs +29 -0
  8. package/lint-staged.config.js +15 -0
  9. package/package.json +95 -0
  10. package/pnpm-workspace.yaml +2 -0
  11. package/postcss.config.mjs +7 -0
  12. package/prettier.config.mjs +24 -0
  13. package/scripts/build-icon-types.ts +38 -0
  14. package/src/-types.ts +8 -0
  15. package/src/-utils.tsx +64 -0
  16. package/src/components/accordion/accordion.module.css +44 -0
  17. package/src/components/accordion/accordion.stories.tsx +36 -0
  18. package/src/components/accordion/index.tsx +67 -0
  19. package/src/components/alert-dialog/alert-dialog.module.css +5 -0
  20. package/src/components/alert-dialog/alert-dialog.stories.tsx +53 -0
  21. package/src/components/alert-dialog/index.tsx +138 -0
  22. package/src/components/anchor/anchor.module.css +18 -0
  23. package/src/components/anchor/anchor.stories.tsx +28 -0
  24. package/src/components/anchor/index.tsx +45 -0
  25. package/src/components/avatar/avatar.module.css +56 -0
  26. package/src/components/avatar/avatar.stories.tsx +61 -0
  27. package/src/components/avatar/index.tsx +82 -0
  28. package/src/components/badge/badge.module.css +35 -0
  29. package/src/components/badge/badge.stories.tsx +60 -0
  30. package/src/components/badge/index.tsx +71 -0
  31. package/src/components/button/button.module.css +42 -0
  32. package/src/components/button/button.stories.tsx +108 -0
  33. package/src/components/button/index.tsx +63 -0
  34. package/src/components/checkbox/checkbox.module.css +36 -0
  35. package/src/components/checkbox/checkbox.stories.tsx +21 -0
  36. package/src/components/checkbox/index.tsx +41 -0
  37. package/src/components/code/code.module.css +20 -0
  38. package/src/components/code/code.stories.tsx +42 -0
  39. package/src/components/code/index.tsx +73 -0
  40. package/src/components/collapse/collapse.module.css +27 -0
  41. package/src/components/collapse/collapse.stories.tsx +27 -0
  42. package/src/components/collapse/index.tsx +59 -0
  43. package/src/components/command/command.module.css +95 -0
  44. package/src/components/command/command.stories.tsx +38 -0
  45. package/src/components/command/index.tsx +108 -0
  46. package/src/components/context-menu/context-menu.module.css +36 -0
  47. package/src/components/context-menu/context-menu.stories.tsx +99 -0
  48. package/src/components/context-menu/index.tsx +242 -0
  49. package/src/components/dialog/dialog.module.css +71 -0
  50. package/src/components/dialog/dialog.stories.tsx +29 -0
  51. package/src/components/dialog/index.tsx +148 -0
  52. package/src/components/heading/heading.module.css +3 -0
  53. package/src/components/heading/heading.stories.tsx +52 -0
  54. package/src/components/heading/index.tsx +112 -0
  55. package/src/components/icon/icon-names.ts +3189 -0
  56. package/src/components/icon/icon.module.css +36 -0
  57. package/src/components/icon/icon.stories.tsx +40 -0
  58. package/src/components/icon/index.tsx +60 -0
  59. package/src/components/icon-button/icon-button.module.css +33 -0
  60. package/src/components/icon-button/icon-button.stories.tsx +59 -0
  61. package/src/components/icon-button/index.tsx +48 -0
  62. package/src/components/inline-code/index.tsx +29 -0
  63. package/src/components/inline-code/inline-code.module.css +13 -0
  64. package/src/components/inline-code/inline-code.stories.tsx +31 -0
  65. package/src/components/input/index.tsx +22 -0
  66. package/src/components/input/input.module.css +23 -0
  67. package/src/components/input/input.stories.tsx +52 -0
  68. package/src/components/meter/index.tsx +55 -0
  69. package/src/components/meter/meter.module.css +23 -0
  70. package/src/components/meter/meter.stories.tsx +31 -0
  71. package/src/components/multiline-input/index.tsx +58 -0
  72. package/src/components/multiline-input/multiline-input.stories.tsx +26 -0
  73. package/src/components/number-input/index.tsx +74 -0
  74. package/src/components/number-input/number-input.module.css +41 -0
  75. package/src/components/number-input/number-input.stories.tsx +24 -0
  76. package/src/components/password-input/index.tsx +24 -0
  77. package/src/components/password-input/password-input.module.css +10 -0
  78. package/src/components/password-input/password-input.stories.tsx +24 -0
  79. package/src/components/pill/index.tsx +45 -0
  80. package/src/components/pill/pill.module.css +22 -0
  81. package/src/components/pill/pill.stories.tsx +83 -0
  82. package/src/components/popover/index.tsx +94 -0
  83. package/src/components/popover/popover.module.css +8 -0
  84. package/src/components/popover/popover.stories.tsx +53 -0
  85. package/src/components/preview-card/index.tsx +68 -0
  86. package/src/components/preview-card/preview-card.module.css +5 -0
  87. package/src/components/preview-card/preview-card.stories.tsx +58 -0
  88. package/src/components/radio/index.tsx +67 -0
  89. package/src/components/radio/radio-group.module.css +5 -0
  90. package/src/components/radio/radio.module.css +36 -0
  91. package/src/components/radio/radio.stories.tsx +27 -0
  92. package/src/components/search-bar/index.tsx +60 -0
  93. package/src/components/search-bar/search-bar.module.css +29 -0
  94. package/src/components/search-bar/search-bar.stories.tsx +37 -0
  95. package/src/components/select/index.tsx +132 -0
  96. package/src/components/select/select.module.css +63 -0
  97. package/src/components/select/select.stories.tsx +49 -0
  98. package/src/components/separator/index.tsx +28 -0
  99. package/src/components/separator/separator.module.css +24 -0
  100. package/src/components/separator/separator.stories.tsx +40 -0
  101. package/src/components/slider/index.tsx +28 -0
  102. package/src/components/slider/slider.module.css +52 -0
  103. package/src/components/slider/slider.stories.tsx +53 -0
  104. package/src/components/spinner/index.tsx +14 -0
  105. package/src/components/spinner/spinner.module.css +13 -0
  106. package/src/components/spinner/spinner.stories.tsx +17 -0
  107. package/src/components/stacked-avatars/index.tsx +88 -0
  108. package/src/components/stacked-avatars/stacked-avatars.module.css +79 -0
  109. package/src/components/stacked-avatars/stacked-avatars.stories.tsx +48 -0
  110. package/src/components/status-banner/index.tsx +96 -0
  111. package/src/components/status-banner/status-banner.module.css +52 -0
  112. package/src/components/status-banner/status-banner.stories.tsx +44 -0
  113. package/src/components/surface/index.tsx +83 -0
  114. package/src/components/surface/surface.module.css +35 -0
  115. package/src/components/surface/surface.stories.tsx +84 -0
  116. package/src/components/switch/index.tsx +23 -0
  117. package/src/components/switch/switch.module.css +45 -0
  118. package/src/components/switch/switch.stories.tsx +48 -0
  119. package/src/components/tabs/index.tsx +126 -0
  120. package/src/components/tabs/tabs.module.css +134 -0
  121. package/src/components/tabs/tabs.stories.tsx +88 -0
  122. package/src/components/text/index.tsx +69 -0
  123. package/src/components/text/text.module.css +76 -0
  124. package/src/components/text/text.stories.tsx +107 -0
  125. package/src/components/theme-provider/index.ts +2 -0
  126. package/src/components/theme-provider/theme-context.tsx +18 -0
  127. package/src/components/theme-provider/theme-provider.stories.tsx +47 -0
  128. package/src/components/theme-provider/theme-provider.tsx +77 -0
  129. package/src/components/timestamp/index.tsx +131 -0
  130. package/src/components/timestamp/timestamp.module.css +8 -0
  131. package/src/components/timestamp/timestamp.stories.tsx +37 -0
  132. package/src/components/toast/index.ts +2 -0
  133. package/src/components/toast/toast.module.css +163 -0
  134. package/src/components/toast/toast.stories.tsx +53 -0
  135. package/src/components/toast/toast.tsx +104 -0
  136. package/src/components/toast/use-toast-manager.ts +63 -0
  137. package/src/components/tooltip/index.tsx +61 -0
  138. package/src/components/tooltip/tooltip-arrow.tsx +17 -0
  139. package/src/components/tooltip/tooltip.module.css +44 -0
  140. package/src/components/tooltip/tooltip.stories.tsx +76 -0
  141. package/src/components/view/index.tsx +137 -0
  142. package/src/components/view/view.module.css +11 -0
  143. package/src/components/view/view.stories.tsx +131 -0
  144. package/src/components/view/view_colorway.module.css +280 -0
  145. package/src/components/view/view_interactive.module.css +127 -0
  146. package/src/components/view/view_loading.module.css +58 -0
  147. package/src/components/visually-hidden/index.ts +1 -0
  148. package/src/index.ts +49 -0
  149. package/src/integrations/react-markdown/index.tsx +134 -0
  150. package/src/integrations/react-markdown/react-markdown.module.css +62 -0
  151. package/src/integrations/react-markdown/react-markdown.stories.tsx +31 -0
  152. package/src/integrations/remix.ts +12 -0
  153. package/src/integrations/tailwind.css +173 -0
  154. package/src/integrations/twemoij/index.tsx +13 -0
  155. package/src/integrations/twemoij/twemoji.module.css +7 -0
  156. package/src/integrations/twemoij/twemoji.stories.tsx +40 -0
  157. package/src/stories/components/all-variants.tsx +40 -0
  158. package/src/stories/data.ts +72 -0
  159. package/src/stories/utils.ts +20 -0
  160. package/src/styles/core.css +153 -0
  161. package/src/styles/themes/dark.css +86 -0
  162. package/src/styles/themes/light.css +86 -0
  163. package/src/styles/tokens.ts +282 -0
  164. package/src/styles/transitions.module.css +31 -0
  165. package/stylelint.config.mjs +29 -0
  166. package/tsconfig.app.json +35 -0
  167. package/tsconfig.json +7 -0
  168. package/tsconfig.node.json +26 -0
  169. package/vite.config.ts +103 -0
  170. 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,3 @@
1
+ .heading {
2
+ font-weight: var(--font-weight-medium);
3
+ }
@@ -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
+ }