@a-type/ui 0.3.2 → 0.4.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 (169) hide show
  1. package/dist/cjs/components/datePicker/DatePicker.d.ts +19 -0
  2. package/dist/cjs/components/datePicker/DatePicker.js +97 -0
  3. package/dist/cjs/components/datePicker/DatePicker.js.map +1 -0
  4. package/dist/cjs/components/datePicker/DatePicker.stories.d.ts +16 -0
  5. package/dist/cjs/components/datePicker/DatePicker.stories.js +28 -0
  6. package/dist/cjs/components/datePicker/DatePicker.stories.js.map +1 -0
  7. package/dist/cjs/components/datePicker/index.d.ts +1 -0
  8. package/dist/cjs/components/datePicker/index.js +3 -0
  9. package/dist/cjs/components/datePicker/index.js.map +1 -0
  10. package/dist/esm/components/datePicker/DatePicker.d.ts +19 -0
  11. package/dist/esm/components/datePicker/DatePicker.js +89 -0
  12. package/dist/esm/components/datePicker/DatePicker.js.map +1 -0
  13. package/dist/esm/components/datePicker/DatePicker.stories.d.ts +16 -0
  14. package/dist/esm/components/datePicker/DatePicker.stories.js +25 -0
  15. package/dist/esm/components/datePicker/DatePicker.stories.js.map +1 -0
  16. package/dist/esm/components/datePicker/index.d.ts +1 -0
  17. package/dist/esm/components/datePicker/index.js +2 -0
  18. package/dist/esm/components/datePicker/index.js.map +1 -0
  19. package/package.json +4 -2
  20. package/src/components/actions/ActionBar.tsx +38 -0
  21. package/src/components/actions/ActionButton.tsx +59 -0
  22. package/src/components/actions/index.ts +2 -0
  23. package/src/components/actions.ts +1 -0
  24. package/src/components/avatar/Avatar.tsx +62 -0
  25. package/src/components/avatar/AvatarList.tsx +71 -0
  26. package/src/components/avatar/index.ts +2 -0
  27. package/src/components/avatar.ts +1 -0
  28. package/src/components/button/Button.stories.tsx +20 -0
  29. package/src/components/button/Button.tsx +66 -0
  30. package/src/components/button/ConfirmedButton.tsx +66 -0
  31. package/src/components/button/classes.tsx +56 -0
  32. package/src/components/button/index.ts +3 -0
  33. package/src/components/button.ts +1 -0
  34. package/src/components/camera/Camera.stories.tsx +40 -0
  35. package/src/components/camera/Camera.tsx +215 -0
  36. package/src/components/camera/index.ts +1 -0
  37. package/src/components/camera.ts +1 -0
  38. package/src/components/card/Card.stories.tsx +41 -0
  39. package/src/components/card/Card.tsx +68 -0
  40. package/src/components/card/index.ts +1 -0
  41. package/src/components/card.ts +1 -0
  42. package/src/components/checkbox/Checkbox.tsx +46 -0
  43. package/src/components/checkbox/index.ts +1 -0
  44. package/src/components/checkbox.ts +1 -0
  45. package/src/components/chip/Chip.tsx +29 -0
  46. package/src/components/chip/index.ts +1 -0
  47. package/src/components/chip.ts +1 -0
  48. package/src/components/collapsible/Collapsible.tsx +48 -0
  49. package/src/components/collapsible/index.ts +1 -0
  50. package/src/components/collapsible.ts +1 -0
  51. package/src/components/colorPicker/ColorPicker.tsx +82 -0
  52. package/src/components/colorPicker/index.ts +1 -0
  53. package/src/components/colorPicker.ts +1 -0
  54. package/src/components/contextMenu/contextMenu.tsx +43 -0
  55. package/src/components/contextMenu.ts +1 -0
  56. package/src/components/datePicker/DatePicker.stories.tsx +33 -0
  57. package/src/components/datePicker/DatePicker.tsx +258 -0
  58. package/src/components/datePicker/index.ts +0 -0
  59. package/src/components/dialog/Dialog.stories.tsx +38 -0
  60. package/src/components/dialog/Dialog.tsx +267 -0
  61. package/src/components/dialog/index.ts +1 -0
  62. package/src/components/dialog.ts +1 -0
  63. package/src/components/divider/Divider.tsx +26 -0
  64. package/src/components/divider/index.ts +1 -0
  65. package/src/components/divider.ts +1 -0
  66. package/src/components/dropdownMenu/DropdownMenu.stories.tsx +47 -0
  67. package/src/components/dropdownMenu/DropdownMenu.tsx +89 -0
  68. package/src/components/dropdownMenu/index.ts +1 -0
  69. package/src/components/dropdownMenu.ts +1 -0
  70. package/src/components/errorBoundary/ErrorBoundary.tsx +23 -0
  71. package/src/components/errorBoundary/index.ts +1 -0
  72. package/src/components/errorBoundary.ts +1 -0
  73. package/src/components/forms/Form.tsx +9 -0
  74. package/src/components/forms/FormikForm.tsx +41 -0
  75. package/src/components/forms/SubmitButton.tsx +15 -0
  76. package/src/components/forms/TextField.tsx +112 -0
  77. package/src/components/forms/index.tsx +4 -0
  78. package/src/components/forms.ts +1 -0
  79. package/src/components/icon/Icon.tsx +28 -0
  80. package/src/components/icon/generated/IconSpritesheet.tsx +442 -0
  81. package/src/components/icon/generated/iconNames.ts +44 -0
  82. package/src/components/icon/index.ts +3 -0
  83. package/src/components/icon.ts +1 -0
  84. package/src/components/imageUploader/ImageUploader.stories.tsx +39 -0
  85. package/src/components/imageUploader/ImageUploader.tsx +203 -0
  86. package/src/components/imageUploader/UploadIcon.tsx +23 -0
  87. package/src/components/imageUploader/index.ts +1 -0
  88. package/src/components/imageUploader.ts +1 -0
  89. package/src/components/infiniteLoadTrigger/InfiniteLoadTrigger.tsx +38 -0
  90. package/src/components/infiniteLoadTrigger.ts +1 -0
  91. package/src/components/input/Input.stories.tsx +17 -0
  92. package/src/components/input/Input.tsx +32 -0
  93. package/src/components/input/index.ts +1 -0
  94. package/src/components/input.ts +1 -0
  95. package/src/components/layouts/PageContent.tsx +51 -0
  96. package/src/components/layouts/PageFixedArea.tsx +17 -0
  97. package/src/components/layouts/PageNav.tsx +23 -0
  98. package/src/components/layouts/PageNowPlaying.tsx +24 -0
  99. package/src/components/layouts/PageRoot.tsx +29 -0
  100. package/src/components/layouts/PageSection.tsx +23 -0
  101. package/src/components/layouts/index.tsx +6 -0
  102. package/src/components/layouts.ts +1 -0
  103. package/src/components/liveUpdateTextField/LiveUpdateTextField.tsx +132 -0
  104. package/src/components/liveUpdateTextField/index.ts +1 -0
  105. package/src/components/liveUpdateTextField.ts +1 -0
  106. package/src/components/navBar/NavBar.tsx +59 -0
  107. package/src/components/navBar/index.ts +1 -0
  108. package/src/components/navBar.ts +1 -0
  109. package/src/components/note/Note.tsx +21 -0
  110. package/src/components/note/index.ts +1 -0
  111. package/src/components/note.ts +1 -0
  112. package/src/components/numberStepper/NumberStepper.stories.tsx +21 -0
  113. package/src/components/numberStepper/NumberStepper.tsx +74 -0
  114. package/src/components/numberStepper/index.ts +1 -0
  115. package/src/components/numberStepper.ts +1 -0
  116. package/src/components/particles/ParticleContext.tsx +11 -0
  117. package/src/components/particles/ParticleLayer.stories.tsx +46 -0
  118. package/src/components/particles/ParticleLayer.tsx +28 -0
  119. package/src/components/particles/index.ts +7 -0
  120. package/src/components/particles/particlesState.ts +502 -0
  121. package/src/components/particles.ts +1 -0
  122. package/src/components/peek/Peek.tsx +74 -0
  123. package/src/components/peek/index.ts +1 -0
  124. package/src/components/peek.ts +1 -0
  125. package/src/components/popover/Popover.tsx +84 -0
  126. package/src/components/popover/index.ts +1 -0
  127. package/src/components/popover.ts +1 -0
  128. package/src/components/relativeTime/RelativeTime.tsx +43 -0
  129. package/src/components/relativeTime/index.ts +1 -0
  130. package/src/components/relativeTime.ts +1 -0
  131. package/src/components/richEditor/EditorContent.tsx +4 -0
  132. package/src/components/richEditor/RichEditor.tsx +38 -0
  133. package/src/components/richEditor/index.ts +1 -0
  134. package/src/components/richEditor.ts +1 -0
  135. package/src/components/select/Select.tsx +247 -0
  136. package/src/components/select/index.ts +1 -0
  137. package/src/components/select.ts +1 -0
  138. package/src/components/skeletons/skeletons.tsx +27 -0
  139. package/src/components/skeletons.ts +1 -0
  140. package/src/components/spinner/Spinner.tsx +59 -0
  141. package/src/components/spinner/index.ts +1 -0
  142. package/src/components/spinner.ts +1 -0
  143. package/src/components/switch/Switch.tsx +23 -0
  144. package/src/components/switch/index.ts +1 -0
  145. package/src/components/switch.ts +1 -0
  146. package/src/components/tabs/tabs.tsx +18 -0
  147. package/src/components/tabs.ts +1 -0
  148. package/src/components/textArea/TextArea.stories.tsx +21 -0
  149. package/src/components/textArea/TextArea.tsx +58 -0
  150. package/src/components/textArea/index.ts +1 -0
  151. package/src/components/textArea.ts +1 -0
  152. package/src/components/toggleGroup/toggleGroup.tsx +11 -0
  153. package/src/components/toggleGroup.ts +1 -0
  154. package/src/components/tooltip/Tooltip.tsx +56 -0
  155. package/src/components/tooltip/index.ts +1 -0
  156. package/src/components/tooltip.ts +1 -0
  157. package/src/components/typography/index.ts +1 -0
  158. package/src/components/typography/typography.tsx +18 -0
  159. package/src/components/typography.ts +1 -0
  160. package/src/hooks/index.ts +7 -0
  161. package/src/hooks/useMergedRef.ts +14 -0
  162. package/src/hooks/useOnUnmount.ts +20 -0
  163. package/src/hooks/useSize.ts +164 -0
  164. package/src/hooks/useStableCallback.ts +11 -0
  165. package/src/hooks/useToggle.tsx +9 -0
  166. package/src/hooks/useVisualViewportOffset.ts +35 -0
  167. package/src/hooks/withClassName.tsx +21 -0
  168. package/src/hooks.ts +1 -0
  169. package/src/uno.preset.ts +767 -0
@@ -0,0 +1 @@
1
+ export * from './RelativeTime.js';
@@ -0,0 +1 @@
1
+ export * from './relativeTime/index.js';
@@ -0,0 +1,4 @@
1
+ // @ts-nocheck
2
+ import { EditorContent } from '@tiptap/react';
3
+
4
+ export default EditorContent;
@@ -0,0 +1,38 @@
1
+ 'use client';
2
+
3
+ import classNames from 'classnames';
4
+ import { forwardRef, lazy } from 'react';
5
+
6
+ const EditorContent = lazy(() => import('./EditorContent.js'));
7
+
8
+ export interface RichEditorProps {
9
+ editor: any;
10
+ className?: string;
11
+ readOnly?: boolean;
12
+ }
13
+
14
+ export const RichEditor = forwardRef<any, RichEditorProps>(function RichEditor(
15
+ { className, ...rest },
16
+ ref,
17
+ ) {
18
+ if (typeof ref === 'string') {
19
+ throw new Error('String ref not supported!');
20
+ }
21
+ return (
22
+ <EditorContent
23
+ ref={ref as any}
24
+ className={classNames(
25
+ 'layer-components:(w-full rounded-lg)',
26
+ !rest.readOnly &&
27
+ 'bg-gray-blend [&_.ProseMirror:focus]:(outline-none bg-gray-1 shadow-focus)',
28
+ '[&_.ProseMirror_h1,h2,h3,p]:mt-0',
29
+ '[&_.ProseMirror_h1]:(text-xl font-medium)',
30
+ '[&_.ProseMirror_h2]:(text-lg font-medium mt-4 mb-2)',
31
+ '[&_.ProseMirror_h3]:(text-md font-extrabold)',
32
+ '[&_.ProseMirror_a]:underline',
33
+ className,
34
+ )}
35
+ {...rest}
36
+ />
37
+ );
38
+ });
@@ -0,0 +1 @@
1
+ export * from './RichEditor.js';
@@ -0,0 +1 @@
1
+ export * from './richEditor/index.js';
@@ -0,0 +1,247 @@
1
+ 'use client';
2
+
3
+ import {
4
+ CheckIcon,
5
+ ChevronDownIcon,
6
+ ChevronUpIcon,
7
+ } from '@radix-ui/react-icons';
8
+ import * as SelectPrimitive from '@radix-ui/react-select';
9
+ import {
10
+ ComponentPropsWithRef,
11
+ ComponentType,
12
+ ElementType,
13
+ FunctionComponent,
14
+ ReactNode,
15
+ createContext,
16
+ forwardRef,
17
+ useContext,
18
+ } from 'react';
19
+ import classNames from 'classnames';
20
+ import { withClassName } from '../../hooks/withClassName.js';
21
+
22
+ export const SelectItem = forwardRef<
23
+ HTMLDivElement,
24
+ SelectPrimitive.SelectItemProps
25
+ >(({ children, className, ...props }, forwardedRef) => {
26
+ const isNative = useContext(IsNativeContext);
27
+
28
+ if (isNative) {
29
+ return <option value={props.value}>{children}</option>;
30
+ }
31
+
32
+ return (
33
+ <SelectItemRoot className={className} {...props} ref={forwardedRef}>
34
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
35
+ <SelectItemIndicator />
36
+ </SelectItemRoot>
37
+ );
38
+ });
39
+
40
+ export const SelectItemRoot = withClassName(
41
+ SelectPrimitive.Item,
42
+ 'text-md leading-4 color-black rounded-sm flex items-center flex-row h-36px pr-4 pl-35px relative select-none',
43
+ '[&[data-disabled]]:(color-gray5 pointer-events-none) [&[data-highlighted]]:(outline-none bg-primary-wash color-black)',
44
+ );
45
+ export const SelectItemIndicatorRoot = withClassName(
46
+ SelectPrimitive.ItemIndicator,
47
+ 'absolute left-0 w-25px inline-flex items-center justify-center',
48
+ );
49
+ export const SelectItemIndicator = withNoNativeRender(
50
+ (props: SelectPrimitive.SelectItemIndicatorProps) => (
51
+ <SelectItemIndicatorRoot {...props}>
52
+ <CheckIcon />
53
+ </SelectItemIndicatorRoot>
54
+ ),
55
+ );
56
+ export const SelectItemText = withClassName(SelectPrimitive.ItemText, '');
57
+ export const SelectGroup = (props: SelectPrimitive.SelectGroupProps) => {
58
+ const isNative = useContext(IsNativeContext);
59
+
60
+ if (isNative) {
61
+ return (
62
+ <optgroup id={props.id} className={props.className}>
63
+ {props.children}
64
+ </optgroup>
65
+ );
66
+ }
67
+
68
+ return <SelectPrimitive.Group {...props} />;
69
+ };
70
+
71
+ export const SelectRoot = SelectPrimitive.Root;
72
+ export const selectTriggerClassName =
73
+ 'layer-components:([all:unset] inline-flex items-center justify-center rounded-full px-3 py-1 text-sm gap-2 color-black border-solid border border-gray5 hover:border-gray7 focus:shadow-focus [&[data-placeholder]]:color-gray8) select-none';
74
+ export const SelectTrigger = withNoNativeRender(
75
+ withClassName(SelectPrimitive.Trigger, selectTriggerClassName),
76
+ );
77
+ export const UnstyledSelectTrigger = withNoNativeRender(
78
+ SelectPrimitive.Trigger,
79
+ );
80
+
81
+ export const SelectValue = withNoNativeRender(
82
+ withClassName(SelectPrimitive.Value, 'flex flex-row'),
83
+ );
84
+ export const SelectLabel = withNoNativeRender(
85
+ withClassName(
86
+ SelectPrimitive.Label,
87
+ 'px-25px text-xs leading-6 color-black select-none',
88
+ ),
89
+ );
90
+ export const SelectSeparator = withNoNativeRender(
91
+ withClassName(SelectPrimitive.Separator, 'h-1px bg-gray50 m-1'),
92
+ );
93
+ export const SelectIcon = withNoNativeRender(
94
+ forwardRef<HTMLDivElement, SelectPrimitive.SelectIconProps>(
95
+ ({ className, ...props }, forwardedRef) => {
96
+ return (
97
+ <SelectPrimitive.Icon
98
+ className={classNames('color-inherit', className)}
99
+ {...props}
100
+ ref={forwardedRef}
101
+ >
102
+ <ChevronDownIcon />
103
+ </SelectPrimitive.Icon>
104
+ );
105
+ },
106
+ ),
107
+ );
108
+
109
+ const zIndex = { zIndex: 1001 };
110
+ export const SelectContent = withPassthroughNativeRender(
111
+ forwardRef<
112
+ HTMLDivElement,
113
+ SelectPrimitive.SelectContentProps & { inDialog?: boolean }
114
+ >(({ children, inDialog, className, ...props }, forwardedRef) => {
115
+ return (
116
+ <SelectPrimitive.Portal className={className} style={zIndex}>
117
+ <SelectPrimitive.Content
118
+ className={classNames(
119
+ 'layer-components:(overflow-hidden bg-white rounded-lg border border-solid border-1 border-black z-menu shadow-lg)',
120
+ 'layer-components:transform-origin-[var(--radix-select-content-transform-origin)]',
121
+ 'layer-components:[&[data-state=open]]:animate-popover-in',
122
+ 'layer-components:[&[data-state=closed]]:animate-popover-out',
123
+ 'layer-components:(min-w-[var(--radix-select-trigger-width)] max-h-[var(--radix-select-content-available-height)])',
124
+ inDialog && 'z-[calc(var(--z-dialog)+1)]',
125
+ )}
126
+ {...props}
127
+ ref={forwardedRef}
128
+ >
129
+ <SelectPrimitive.ScrollUpButton className="flex items-center justify-center h-25px bg-white color-primary-dark cursor-default">
130
+ <ChevronUpIcon />
131
+ </SelectPrimitive.ScrollUpButton>
132
+ <SelectPrimitive.Viewport className="p-1">
133
+ {children}
134
+ </SelectPrimitive.Viewport>
135
+ <SelectPrimitive.ScrollDownButton className="flex items-center justify-center h-25px bg-white color-primary-dark cursor-default">
136
+ <ChevronDownIcon />
137
+ </SelectPrimitive.ScrollDownButton>
138
+ </SelectPrimitive.Content>
139
+ </SelectPrimitive.Portal>
140
+ );
141
+ }),
142
+ );
143
+
144
+ export const NativeSelect = forwardRef<
145
+ HTMLSelectElement,
146
+ React.SelectHTMLAttributes<HTMLSelectElement>
147
+ >(({ className, ...props }, forwardedRef) => {
148
+ return (
149
+ <div className={classNames('relative', className)}>
150
+ <select
151
+ className={classNames(
152
+ 'appearance-none font-inherit bg-white inline-flex items-center justify-center rounded-full px-3 py-1 pr-8 text-sm gap-2 color-black border-solid border border-gray5 hover:border-gray7 focus:outline-none focus-visible:shadow-focus [&[data-placeholder]]:color-gray8',
153
+ )}
154
+ {...props}
155
+ ref={forwardedRef}
156
+ />
157
+ <div className="absolute right-1 top-50% translate-y-[-50%] pointer-events-none">
158
+ <ChevronDownIcon className="w-4 h-4 m-2" />
159
+ </div>
160
+ </div>
161
+ );
162
+ });
163
+
164
+ export type SelectProps<T extends string = string> = {
165
+ children?: ReactNode;
166
+ value: T;
167
+ onValueChange?: (value: T) => void;
168
+ className?: string;
169
+ id?: string;
170
+ /** Native on mobile; otherwise use custom select impl */
171
+ mobileNative?: boolean;
172
+ /** won't work on mobile and mobileNative=true */
173
+ open?: boolean;
174
+ /** won't work on mobile and mobileNative=true */
175
+ onOpenChange?: (open: boolean) => void;
176
+ };
177
+ /**
178
+ * A high-level Select which converts to native on mobile. Use with SelectItem.
179
+ */
180
+ export const Select = <T extends string = string>({
181
+ children,
182
+ value,
183
+ onValueChange,
184
+ mobileNative,
185
+ ...rest
186
+ }: SelectProps<T>) => {
187
+ const mobile = isMobile();
188
+
189
+ if (mobile && mobileNative) {
190
+ return (
191
+ <IsNativeContext.Provider value={true}>
192
+ <NativeSelect
193
+ onChange={(ev) => {
194
+ onValueChange?.(ev.target.value as any);
195
+ }}
196
+ value={value}
197
+ {...rest}
198
+ >
199
+ {children}
200
+ </NativeSelect>
201
+ </IsNativeContext.Provider>
202
+ );
203
+ }
204
+
205
+ return (
206
+ <SelectRoot value={value} onValueChange={onValueChange}>
207
+ {children}
208
+ </SelectRoot>
209
+ );
210
+ };
211
+
212
+ function isMobile() {
213
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
214
+ navigator.userAgent,
215
+ );
216
+ }
217
+
218
+ // facilitate the auto native switching
219
+ const IsNativeContext = createContext(false);
220
+
221
+ function withNoNativeRender<T extends ComponentType<any> | ElementType<any>>(
222
+ Component: T,
223
+ ): FunctionComponent<ComponentPropsWithRef<T>> {
224
+ const WithNoNativeRender = forwardRef<any, any>((props, ref) => {
225
+ const isNative = useContext(IsNativeContext);
226
+
227
+ if (isNative) return null;
228
+
229
+ return <Component ref={ref} {...props} />;
230
+ });
231
+ return WithNoNativeRender as any;
232
+ }
233
+
234
+ function withPassthroughNativeRender<
235
+ T extends ComponentType<any> | ElementType<any>,
236
+ >(Component: T): FunctionComponent<ComponentPropsWithRef<T>> {
237
+ const WithPassthroughNativeRender = forwardRef<any, any>((props, ref) => {
238
+ const isNative = useContext(IsNativeContext);
239
+
240
+ if (isNative) {
241
+ return <>{props.children}</>;
242
+ }
243
+
244
+ return <Component ref={ref} {...props} />;
245
+ });
246
+ return WithPassthroughNativeRender as any;
247
+ }
@@ -0,0 +1 @@
1
+ export * from './Select.js';
@@ -0,0 +1 @@
1
+ export * from './select/index.js';
@@ -0,0 +1,27 @@
1
+ import { useState } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ export const TextSkeleton = ({
5
+ maxLength,
6
+ className,
7
+ }: {
8
+ maxLength: number;
9
+ className?: string;
10
+ }) => {
11
+ const [length] = useState(() =>
12
+ Math.round(Math.random() * (maxLength - 5) + 5),
13
+ );
14
+
15
+ return (
16
+ <span
17
+ className={classNames(
18
+ 'w-full h-full rounded-2 bg-gradient-to-r from-gray1 via-gray2 to-gray1 [background-size:400%_400%] max-w-full animate-skeleton animate-duration-1200 animate-ease-in-out animate-iteration-infinite animate-alternate',
19
+ className,
20
+ )}
21
+ style={{
22
+ width: `${length}ch`,
23
+ height: '1.2em',
24
+ }}
25
+ />
26
+ );
27
+ };
@@ -0,0 +1 @@
1
+ export * from './skeletons/skeletons.js';
@@ -0,0 +1,59 @@
1
+ import { HTMLAttributes, forwardRef } from 'react';
2
+ import classNames from 'classnames';
3
+
4
+ const CIRCLE_SIZE = 44;
5
+
6
+ export interface SpinnerProps
7
+ extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
8
+ size?: number;
9
+ thickness?: number;
10
+ }
11
+
12
+ export const Spinner = forwardRef<HTMLDivElement, SpinnerProps>(
13
+ function Spinner(
14
+ { size = 40, thickness = 7.2, className, style, ...props },
15
+ ref,
16
+ ) {
17
+ return (
18
+ <div
19
+ ref={ref}
20
+ role="progressbar"
21
+ {...props}
22
+ className={classNames(
23
+ 'inline-block animate-spin animate-ease-linear animate-iteration-infinite color-inherit animate-duration-1400 transform-origin-[50%_50%]',
24
+ className,
25
+ )}
26
+ style={{ width: size, height: size, ...style }}
27
+ >
28
+ <svg
29
+ className="block"
30
+ viewBox={`${CIRCLE_SIZE / 2} ${
31
+ CIRCLE_SIZE / 2
32
+ } ${CIRCLE_SIZE} ${CIRCLE_SIZE}`}
33
+ >
34
+ <circle
35
+ className="stroke-current animate-spinner-stroke animate-ease-in-out animate-iteration-infinite animate-duration-1400 [stroke-dasharray:80_200] [stroke-dashoffset:0]"
36
+ cx={CIRCLE_SIZE}
37
+ cy={CIRCLE_SIZE}
38
+ r={(CIRCLE_SIZE - thickness) / 2}
39
+ fill="none"
40
+ strokeWidth={thickness}
41
+ />
42
+ </svg>
43
+ </div>
44
+ );
45
+ },
46
+ );
47
+
48
+ export const FullScreenSpinner = forwardRef<HTMLDivElement, SpinnerProps>(
49
+ function FullScreenSpinner(props, ref) {
50
+ return (
51
+ <div
52
+ ref={ref}
53
+ className="flex flex-row gap-4 w-full flex-1 justify-center items-center self-stretch"
54
+ >
55
+ <Spinner {...props} />
56
+ </div>
57
+ );
58
+ },
59
+ );
@@ -0,0 +1 @@
1
+ export * from './Spinner.js';
@@ -0,0 +1 @@
1
+ export * from './spinner/index.js';
@@ -0,0 +1,23 @@
1
+ import { withClassName } from '../../hooks/withClassName.js';
2
+ import { Root, SwitchProps, Thumb } from '@radix-ui/react-switch';
3
+ import { forwardRef } from 'react';
4
+
5
+ const SwitchRoot = withClassName(
6
+ Root,
7
+ 'unset w-42px h-25px bg-white rounded-full relative transition-color border-default flex-shrink-0 focus-visible:shadow-focus [&[data-state=checked]]:bg-accent',
8
+ );
9
+
10
+ const SwitchThumb = withClassName(
11
+ Thumb,
12
+ 'block w-21px h-21px bg-white rounded-full border-default transition-transform will-change-transform [&[data-state=checked]]:translate-x-19px',
13
+ );
14
+
15
+ export const Switch = forwardRef<HTMLButtonElement, SwitchProps>(
16
+ function Switch(props, ref) {
17
+ return (
18
+ <SwitchRoot {...props} ref={ref}>
19
+ <SwitchThumb />
20
+ </SwitchRoot>
21
+ );
22
+ },
23
+ );
@@ -0,0 +1 @@
1
+ export * from './Switch.js';
@@ -0,0 +1 @@
1
+ export * from './switch/index.js';
@@ -0,0 +1,18 @@
1
+ import * as Tabs from '@radix-ui/react-tabs';
2
+ import { withClassName } from '../../hooks/withClassName.js';
3
+
4
+ export const TabsRoot = withClassName(Tabs.Root, '');
5
+
6
+ export const TabsList = withClassName(
7
+ Tabs.List,
8
+ 'flex flex-row py-2 px-2 justify-center',
9
+ );
10
+
11
+ export const TabsTrigger = withClassName(
12
+ Tabs.Trigger,
13
+ 'flex flex-row items-center justify-center gap-2 color-black py-1 px-4 bg-wash text-md font-bold min-w-100px border border-solid border-gray-4',
14
+ 'hover:bg-gray-3 focus-visible:(shadow-focus outline-off) [&[data-state=active]]:(bg-primary-wash border-primary hover:bg-primary-wash relative z-1)',
15
+ 'first:rounded-l-full last:rounded-r-full',
16
+ );
17
+
18
+ export const TabsContent = withClassName(Tabs.Content, '');
@@ -0,0 +1 @@
1
+ export * from './tabs/tabs.js';
@@ -0,0 +1,21 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { TextArea } from './TextArea.js';
3
+
4
+ const meta = {
5
+ title: 'TextArea',
6
+ component: TextArea,
7
+ argTypes: {},
8
+ parameters: {
9
+ controls: { expanded: true },
10
+ },
11
+ } satisfies Meta<typeof TextArea>;
12
+
13
+ export default meta;
14
+
15
+ type Story = StoryObj<typeof TextArea>;
16
+
17
+ export const Default: Story = {
18
+ args: {
19
+ autoSize: true,
20
+ },
21
+ };
@@ -0,0 +1,58 @@
1
+ 'use client';
2
+
3
+ import classNames from 'classnames';
4
+ import useMergedRef from '../../hooks/useMergedRef.js';
5
+ import { forwardRef, HTMLProps, useLayoutEffect, useRef } from 'react';
6
+ import { inputClassName } from '../input.js';
7
+
8
+ export interface TextAreaProps
9
+ extends Omit<HTMLProps<HTMLTextAreaElement>, 'ref'> {
10
+ className?: string;
11
+ autoSize?: boolean;
12
+ // if auto-size, pad the height by this many px
13
+ padBottomPixels?: number;
14
+ }
15
+
16
+ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
17
+ function TextArea(
18
+ { autoSize, className, rows, padBottomPixels = 0, ...rest },
19
+ ref,
20
+ ) {
21
+ const innerRef = useRef<HTMLTextAreaElement>(null);
22
+ const finalRef = useMergedRef(innerRef, ref);
23
+
24
+ useLayoutEffect(() => {
25
+ if (!autoSize) return;
26
+ const element = innerRef.current;
27
+ let valueWasEmpty = false;
28
+ if (element) {
29
+ if (
30
+ element!.value !== '' ||
31
+ (!valueWasEmpty && element!.value === '') ||
32
+ padBottomPixels
33
+ ) {
34
+ element!.style.height = 'auto';
35
+ const baseHeight = element!.scrollHeight;
36
+ element!.style.height = baseHeight + padBottomPixels + 'px';
37
+ }
38
+ valueWasEmpty = element!.value === '';
39
+ }
40
+ }, [autoSize, padBottomPixels, rest.value]);
41
+
42
+ return (
43
+ <textarea
44
+ ref={finalRef}
45
+ className={classNames(
46
+ inputClassName,
47
+ 'layer-components:([font-family:inherit] text-inherit overflow-hidden)',
48
+ {
49
+ 'layer-components:[resize:vertical]': !autoSize,
50
+ },
51
+ className,
52
+ )}
53
+ rows={autoSize ? 1 : rows}
54
+ {...rest}
55
+ />
56
+ );
57
+ },
58
+ );
@@ -0,0 +1 @@
1
+ export * from './TextArea.js';
@@ -0,0 +1 @@
1
+ export * from './textArea/index.js';
@@ -0,0 +1,11 @@
1
+ import * as ToggleGroup from '@radix-ui/react-toggle-group';
2
+ import { withClassName } from '../../hooks/withClassName.js';
3
+
4
+ export const ToggleGroupRoot = withClassName(
5
+ ToggleGroup.Root,
6
+ 'inline-flex bg-gray1 rounded-lg gap-1',
7
+ );
8
+ export const ToggleGroupItem = withClassName(
9
+ ToggleGroup.Item,
10
+ 'rounded-xl bg-gray2 py-1 px-2 flex items-center justify-center cursor-pointer hover:bg-gray3 active:bg-gray4 focus-visible:(shadow-focus outline-off) [&[data-state=on]]:(bg-primary-light border-black)',
11
+ );
@@ -0,0 +1 @@
1
+ export * from './toggleGroup/toggleGroup.js';
@@ -0,0 +1,56 @@
1
+ 'use client';
2
+
3
+ import React, { ComponentPropsWithoutRef } from 'react';
4
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
5
+ import classNames from 'classnames';
6
+
7
+ function Content({
8
+ children,
9
+ className,
10
+ ...props
11
+ }: TooltipPrimitive.TooltipContentProps) {
12
+ return (
13
+ <TooltipPrimitive.Portal>
14
+ <TooltipPrimitive.Content
15
+ className={classNames(
16
+ 'layer-components:(relative rounded-lg py-2 px-3 border-default text-sm leading-tight color-inherit bg-white shadow-sm select-none display-none z-tooltip sm:display-initial)',
17
+ '[&[data-state=delayed-open]]:display-initial',
18
+ '[&[data-state=instant-open]]:display-initial',
19
+ 'layer-components:transform-origin-[var(--radix-tooltip-content-transform-origin)]',
20
+ 'layer-components:[&[data-state=delayed-open]]:animate-popover-in',
21
+ className,
22
+ )}
23
+ {...props}
24
+ >
25
+ {children}
26
+ <TooltipPrimitive.Arrow className="fill-white stroke-black stroke-1" />
27
+ </TooltipPrimitive.Content>
28
+ </TooltipPrimitive.Portal>
29
+ );
30
+ }
31
+
32
+ // Exports
33
+ export const TooltipProvider = TooltipPrimitive.Provider;
34
+
35
+ export function Tooltip({
36
+ content,
37
+ children,
38
+ open,
39
+ disabled,
40
+ ...rest
41
+ }: { content: React.ReactNode; open?: boolean } & ComponentPropsWithoutRef<
42
+ typeof TooltipPrimitive.TooltipTrigger
43
+ >) {
44
+ return (
45
+ <TooltipPrimitive.Root open={open}>
46
+ {disabled ? (
47
+ children
48
+ ) : (
49
+ <TooltipPrimitive.TooltipTrigger asChild {...rest}>
50
+ {children}
51
+ </TooltipPrimitive.TooltipTrigger>
52
+ )}
53
+ <Content sideOffset={12}>{content}</Content>
54
+ </TooltipPrimitive.Root>
55
+ );
56
+ }
@@ -0,0 +1 @@
1
+ export * from './Tooltip.js';
@@ -0,0 +1 @@
1
+ export * from './tooltip/index.js';
@@ -0,0 +1 @@
1
+ export * from './typography.js';
@@ -0,0 +1,18 @@
1
+ import { withClassName } from '../../hooks/withClassName.js';
2
+
3
+ const baseHeadingClass = 'my-0';
4
+ export const H1 = withClassName(
5
+ 'h1',
6
+ baseHeadingClass,
7
+ 'font-title text-2xl font-bold',
8
+ );
9
+ export const H2 = withClassName(
10
+ 'h2',
11
+ baseHeadingClass,
12
+ 'text-lg font-title font-bold color-gray9',
13
+ );
14
+ export const H3 = withClassName('h3', baseHeadingClass, 'font-title text-md');
15
+ export const H4 = withClassName('h4', baseHeadingClass);
16
+ export const H5 = withClassName('h5', baseHeadingClass);
17
+
18
+ export const P = withClassName('p', 'my-0 leading-normal');
@@ -0,0 +1 @@
1
+ export * from './typography/index.js';
@@ -0,0 +1,7 @@
1
+ export * from './useMergedRef.js';
2
+ export * from './useSize.js';
3
+ export * from './useStableCallback.js';
4
+ export * from './useToggle.js';
5
+ export * from './useVisualViewportOffset.js';
6
+ export * from './useOnUnmount.js';
7
+ export * from './withClassName.js';
@@ -0,0 +1,14 @@
1
+ import * as React from 'react';
2
+
3
+ function useMergedRef<T>(...refs: React.Ref<T>[]): React.RefCallback<T> {
4
+ return React.useCallback((element: T) => {
5
+ for (let i = 0; i < refs.length; i++) {
6
+ const ref = refs[i];
7
+ if (typeof ref === 'function') ref(element);
8
+ else if (ref && typeof ref === 'object')
9
+ (ref as React.MutableRefObject<T>).current = element;
10
+ }
11
+ }, refs);
12
+ }
13
+
14
+ export default useMergedRef;