@luxfi/ui 5.6.0 → 6.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 (125) hide show
  1. package/README.md +109 -0
  2. package/package.json +81 -278
  3. package/dist/accordion.cjs +0 -213
  4. package/dist/accordion.js +0 -186
  5. package/dist/alert.cjs +0 -553
  6. package/dist/alert.js +0 -531
  7. package/dist/avatar.cjs +0 -149
  8. package/dist/avatar.js +0 -125
  9. package/dist/badge.cjs +0 -611
  10. package/dist/badge.js +0 -589
  11. package/dist/button.cjs +0 -689
  12. package/dist/button.js +0 -664
  13. package/dist/checkbox.cjs +0 -265
  14. package/dist/checkbox.js +0 -241
  15. package/dist/close-button.cjs +0 -73
  16. package/dist/close-button.js +0 -51
  17. package/dist/collapsible.cjs +0 -702
  18. package/dist/collapsible.js +0 -679
  19. package/dist/color-mode.cjs +0 -96
  20. package/dist/color-mode.js +0 -72
  21. package/dist/dialog.cjs +0 -279
  22. package/dist/dialog.js +0 -246
  23. package/dist/drawer.cjs +0 -207
  24. package/dist/drawer.js +0 -175
  25. package/dist/empty-state.cjs +0 -93
  26. package/dist/empty-state.js +0 -71
  27. package/dist/field.cjs +0 -183
  28. package/dist/field.js +0 -160
  29. package/dist/heading.cjs +0 -46
  30. package/dist/heading.js +0 -40
  31. package/dist/icon-button.cjs +0 -491
  32. package/dist/icon-button.js +0 -470
  33. package/dist/image.cjs +0 -572
  34. package/dist/image.js +0 -551
  35. package/dist/index.cjs +0 -5779
  36. package/dist/index.js +0 -5619
  37. package/dist/input-group.cjs +0 -155
  38. package/dist/input-group.js +0 -133
  39. package/dist/input.cjs +0 -65
  40. package/dist/input.js +0 -59
  41. package/dist/link.cjs +0 -630
  42. package/dist/link.js +0 -606
  43. package/dist/menu.cjs +0 -305
  44. package/dist/menu.js +0 -269
  45. package/dist/pin-input.cjs +0 -182
  46. package/dist/pin-input.js +0 -160
  47. package/dist/popover.cjs +0 -327
  48. package/dist/popover.js +0 -294
  49. package/dist/progress-circle.cjs +0 -152
  50. package/dist/progress-circle.js +0 -128
  51. package/dist/progress.cjs +0 -117
  52. package/dist/progress.js +0 -94
  53. package/dist/provider.cjs +0 -62
  54. package/dist/provider.js +0 -40
  55. package/dist/radio.cjs +0 -177
  56. package/dist/radio.js +0 -153
  57. package/dist/rating.cjs +0 -80
  58. package/dist/rating.js +0 -58
  59. package/dist/select.cjs +0 -791
  60. package/dist/select.js +0 -757
  61. package/dist/separator.cjs +0 -57
  62. package/dist/separator.js +0 -51
  63. package/dist/skeleton.cjs +0 -370
  64. package/dist/skeleton.js +0 -346
  65. package/dist/slider.cjs +0 -138
  66. package/dist/slider.js +0 -115
  67. package/dist/switch.cjs +0 -163
  68. package/dist/switch.js +0 -140
  69. package/dist/table.cjs +0 -1044
  70. package/dist/table.js +0 -1013
  71. package/dist/tabs.cjs +0 -240
  72. package/dist/tabs.js +0 -213
  73. package/dist/tag.cjs +0 -651
  74. package/dist/tag.js +0 -628
  75. package/dist/textarea.cjs +0 -65
  76. package/dist/textarea.js +0 -59
  77. package/dist/toaster.cjs +0 -99
  78. package/dist/toaster.js +0 -96
  79. package/dist/tooltip.cjs +0 -171
  80. package/dist/tooltip.js +0 -148
  81. package/dist/utils.cjs +0 -11
  82. package/dist/utils.js +0 -9
  83. package/src/accordion.tsx +0 -285
  84. package/src/alert.tsx +0 -221
  85. package/src/avatar.tsx +0 -174
  86. package/src/badge.tsx +0 -158
  87. package/src/button.tsx +0 -411
  88. package/src/checkbox.tsx +0 -307
  89. package/src/close-button.tsx +0 -51
  90. package/src/collapsible.tsx +0 -126
  91. package/src/color-mode.tsx +0 -125
  92. package/src/dialog.tsx +0 -356
  93. package/src/drawer.tsx +0 -186
  94. package/src/empty-state.tsx +0 -97
  95. package/src/field.tsx +0 -202
  96. package/src/heading.tsx +0 -55
  97. package/src/icon-button.tsx +0 -192
  98. package/src/image.tsx +0 -280
  99. package/src/index.ts +0 -192
  100. package/src/input-group.tsx +0 -159
  101. package/src/input.tsx +0 -60
  102. package/src/link.tsx +0 -326
  103. package/src/menu.tsx +0 -471
  104. package/src/pin-input.tsx +0 -187
  105. package/src/popover.tsx +0 -400
  106. package/src/progress-circle.tsx +0 -180
  107. package/src/progress.tsx +0 -109
  108. package/src/provider.tsx +0 -12
  109. package/src/radio.tsx +0 -175
  110. package/src/rating.tsx +0 -79
  111. package/src/select.tsx +0 -696
  112. package/src/separator.tsx +0 -59
  113. package/src/skeleton.tsx +0 -302
  114. package/src/slider.tsx +0 -152
  115. package/src/switch.tsx +0 -158
  116. package/src/table.tsx +0 -621
  117. package/src/tabs.tsx +0 -354
  118. package/src/tag.tsx +0 -159
  119. package/src/textarea.tsx +0 -60
  120. package/src/toaster.tsx +0 -117
  121. package/src/tokens.css +0 -438
  122. package/src/tooltip.tsx +0 -184
  123. package/src/utils/cn.ts +0 -7
  124. package/src/utils.ts +0 -6
  125. package/tokens.css +0 -438
package/src/popover.tsx DELETED
@@ -1,400 +0,0 @@
1
- import * as RadixPopover from '@radix-ui/react-popover';
2
- import * as React from 'react';
3
-
4
- import { cn } from './utils';
5
-
6
- import { CloseButton } from './close-button';
7
-
8
- // --- Utility: map Chakra-style placement string to Radix side + align ---
9
-
10
- type Side = 'top' | 'right' | 'bottom' | 'left';
11
- type Align = 'start' | 'center' | 'end';
12
-
13
- interface PlacementMapping {
14
- readonly side: Side;
15
- readonly align: Align;
16
- }
17
-
18
- function parsePlacement(placement: string | undefined): PlacementMapping {
19
- if (!placement) {
20
- return { side: 'bottom', align: 'start' };
21
- }
22
-
23
- const parts = placement.split('-');
24
- const side = (parts[0] as Side) ?? 'bottom';
25
- const alignPart = parts[1];
26
-
27
- let align: Align = 'center';
28
- if (alignPart === 'start') {
29
- align = 'start';
30
- } else if (alignPart === 'end') {
31
- align = 'end';
32
- }
33
-
34
- return { side, align };
35
- }
36
-
37
- // --- PopoverRoot ---
38
-
39
- interface Positioning {
40
- readonly placement?: string;
41
- readonly offset?: {
42
- readonly mainAxis?: number;
43
- readonly crossAxis?: number;
44
- };
45
- readonly overflowPadding?: number;
46
- }
47
-
48
- export interface PopoverRootProps {
49
- readonly children?: React.ReactNode;
50
- readonly open?: boolean;
51
- readonly defaultOpen?: boolean;
52
-
53
- /** Chakra-style callback: receives `{ open: boolean }` */
54
- readonly onOpenChange?: (details: { open: boolean }) => void;
55
- readonly positioning?: Positioning;
56
- readonly lazyMount?: boolean;
57
- readonly unmountOnExit?: boolean;
58
- readonly autoFocus?: boolean;
59
- readonly closeOnInteractOutside?: boolean;
60
- readonly modal?: boolean;
61
- }
62
-
63
- // Stash positioning info in context so PopoverContent can read it.
64
- interface PopoverPositioning {
65
- readonly side: Side;
66
- readonly align: Align;
67
- readonly sideOffset: number;
68
- readonly alignOffset: number;
69
- readonly collisionPadding: number;
70
- readonly autoFocus: boolean;
71
- readonly closeOnInteractOutside: boolean;
72
- }
73
-
74
- const PositioningContext = React.createContext<PopoverPositioning>({
75
- side: 'bottom',
76
- align: 'start',
77
- sideOffset: 4,
78
- alignOffset: 0,
79
- collisionPadding: 4,
80
- autoFocus: false,
81
- closeOnInteractOutside: true,
82
- });
83
-
84
- export const PopoverRoot = (props: PopoverRootProps): React.ReactElement => {
85
- const {
86
- children,
87
- open,
88
- defaultOpen,
89
- onOpenChange,
90
- positioning,
91
- autoFocus = false,
92
- closeOnInteractOutside = true,
93
- modal = false,
94
- // lazyMount and unmountOnExit are handled via forceMount on Portal/Content
95
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
96
- lazyMount: _lazyMount,
97
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
- unmountOnExit: _unmountOnExit,
99
- } = props;
100
-
101
- // Merge default positioning with user positioning
102
- const mergedPositioning: Positioning = {
103
- placement: 'bottom-start',
104
- overflowPadding: 4,
105
- ...positioning,
106
- offset: {
107
- mainAxis: 4,
108
- ...positioning?.offset,
109
- },
110
- };
111
-
112
- const { side, align } = parsePlacement(mergedPositioning.placement);
113
-
114
- const positioningValue = React.useMemo<PopoverPositioning>(() => ({
115
- side,
116
- align,
117
- sideOffset: mergedPositioning.offset?.mainAxis ?? 4,
118
- alignOffset: mergedPositioning.offset?.crossAxis ?? 0,
119
- collisionPadding: mergedPositioning.overflowPadding ?? 4,
120
- autoFocus,
121
- closeOnInteractOutside,
122
- }), [
123
- side, align,
124
- mergedPositioning.offset?.mainAxis, mergedPositioning.offset?.crossAxis,
125
- mergedPositioning.overflowPadding, autoFocus, closeOnInteractOutside,
126
- ]);
127
-
128
- // Bridge Chakra-style onOpenChange ({ open }) to Radix (open)
129
- const handleOpenChange = React.useCallback((isOpen: boolean) => {
130
- onOpenChange?.({ open: isOpen });
131
- }, [ onOpenChange ]);
132
-
133
- return (
134
- <PositioningContext.Provider value={ positioningValue }>
135
- <RadixPopover.Root
136
- open={ open }
137
- defaultOpen={ defaultOpen }
138
- onOpenChange={ handleOpenChange }
139
- modal={ modal }
140
- >
141
- { children }
142
- </RadixPopover.Root>
143
- </PositioningContext.Provider>
144
- );
145
- };
146
-
147
- // --- PopoverTrigger ---
148
-
149
- export interface PopoverTriggerProps extends React.ComponentPropsWithoutRef<'button'> {
150
- readonly asChild?: boolean;
151
- }
152
-
153
- export const PopoverTrigger = React.forwardRef<
154
- HTMLButtonElement,
155
- PopoverTriggerProps
156
- >(function PopoverTrigger(props, ref) {
157
- const { asChild = true, ...rest } = props;
158
- return <RadixPopover.Trigger asChild={ asChild } ref={ ref } { ...rest }/>;
159
- });
160
-
161
- // --- PopoverContent ---
162
-
163
- export interface PopoverContentProps extends React.ComponentPropsWithoutRef<'div'> {
164
- readonly portalled?: boolean;
165
- readonly portalRef?: React.RefObject<HTMLElement>;
166
- // Legacy Chakra style-prop shims
167
- readonly w?: string | Record<string, string>;
168
- readonly minW?: string;
169
- readonly maxW?: string;
170
- readonly paddingTop?: number | string;
171
- }
172
-
173
- export const PopoverContent = React.forwardRef<
174
- HTMLDivElement,
175
- PopoverContentProps
176
- >(function PopoverContent(props, ref) {
177
- const { portalled = true, portalRef, className, w, minW, maxW, paddingTop, style: styleProp, ...rest } = props;
178
- const resolvedW = typeof w === 'object' ? (w as Record<string, string>).base ?? (w as Record<string, string>).lg : w;
179
- const contentStyle: React.CSSProperties = {
180
- ...styleProp,
181
- ...(resolvedW ? { width: resolvedW } : {}),
182
- ...(minW ? { minWidth: minW } : {}),
183
- ...(maxW ? { maxWidth: maxW } : {}),
184
- ...(paddingTop !== undefined ? { paddingTop: typeof paddingTop === 'number' ? `${ paddingTop * 4 }px` : paddingTop } : {}),
185
- };
186
- const positioning = React.useContext(PositioningContext);
187
-
188
- const preventFocus = React.useCallback((e: Event) => e.preventDefault(), []);
189
- const preventInteract = React.useCallback((e: Event) => e.preventDefault(), []);
190
-
191
- const content = (
192
- <RadixPopover.Content
193
- ref={ ref }
194
- side={ positioning.side }
195
- align={ positioning.align }
196
- sideOffset={ positioning.sideOffset }
197
- alignOffset={ positioning.alignOffset }
198
- collisionPadding={ positioning.collisionPadding }
199
- onOpenAutoFocus={ positioning.autoFocus ? undefined : preventFocus }
200
- onInteractOutside={ positioning.closeOnInteractOutside ? undefined : preventInteract }
201
- className={ cn(
202
- 'z-50 rounded-lg border border-[var(--color-popover-border,var(--color-border-divider))]',
203
- 'bg-[var(--color-popover-bg,var(--color-dialog-bg))]',
204
- 'shadow-[var(--shadow-popover,var(--shadow-lg))]',
205
- 'outline-none',
206
- 'data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95',
207
- 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',
208
- 'data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',
209
- 'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
210
- className,
211
- ) }
212
- style={ Object.keys(contentStyle).length > 0 ? contentStyle : undefined }
213
- { ...rest }
214
- />
215
- );
216
-
217
- if (!portalled) {
218
- return content;
219
- }
220
-
221
- return (
222
- <RadixPopover.Portal container={ portalRef?.current ?? undefined }>
223
- { content }
224
- </RadixPopover.Portal>
225
- );
226
- });
227
-
228
- // --- PopoverArrow ---
229
-
230
- export interface PopoverArrowProps extends React.ComponentPropsWithoutRef<'svg'> {}
231
-
232
- export const PopoverArrow = React.forwardRef<
233
- SVGSVGElement,
234
- PopoverArrowProps
235
- >(function PopoverArrow(props, ref) {
236
- const { className, ...rest } = props;
237
- return (
238
- <RadixPopover.Arrow
239
- ref={ ref }
240
- className={ cn('fill-[var(--color-popover-bg,var(--color-dialog-bg))]', className) }
241
- { ...rest }
242
- />
243
- );
244
- });
245
-
246
- // --- PopoverCloseTrigger ---
247
-
248
- export interface PopoverCloseTriggerProps extends React.ComponentPropsWithoutRef<'button'> {}
249
-
250
- export const PopoverCloseTrigger = React.forwardRef<
251
- HTMLButtonElement,
252
- PopoverCloseTriggerProps
253
- >(function PopoverCloseTrigger(props, ref) {
254
- const { className, ...rest } = props;
255
- return (
256
- <RadixPopover.Close
257
- className={ cn('absolute top-1 right-1', className) }
258
- { ...rest }
259
- asChild
260
- ref={ ref }
261
- >
262
- <CloseButton/>
263
- </RadixPopover.Close>
264
- );
265
- });
266
-
267
- // --- PopoverCloseTriggerWrapper ---
268
-
269
- export interface PopoverCloseTriggerWrapperProps extends React.ComponentPropsWithoutRef<'button'> {
270
- readonly disabled?: boolean;
271
- }
272
-
273
- export const PopoverCloseTriggerWrapper = React.forwardRef<
274
- HTMLButtonElement,
275
- PopoverCloseTriggerWrapperProps
276
- >(function PopoverCloseTriggerWrapper(props, ref) {
277
- const { disabled, children, ...rest } = props;
278
-
279
- if (disabled) {
280
- return children as React.ReactElement;
281
- }
282
-
283
- return (
284
- <RadixPopover.Close ref={ ref } { ...rest } asChild>
285
- { children }
286
- </RadixPopover.Close>
287
- );
288
- });
289
-
290
- // --- Simple wrapper components ---
291
-
292
- export interface PopoverBodyProps extends React.ComponentPropsWithoutRef<'div'> {
293
- // Legacy Chakra style-prop shims
294
- readonly display?: string;
295
- readonly flexDir?: string;
296
- readonly rowGap?: number | string;
297
- readonly px?: number | string;
298
- readonly py?: number | string;
299
- readonly textStyle?: string;
300
- readonly alignItems?: string;
301
- }
302
-
303
- export const PopoverBody = React.forwardRef<
304
- HTMLDivElement,
305
- PopoverBodyProps
306
- >(function PopoverBody(props, ref) {
307
- const {
308
- className, style: styleProp,
309
- display: _display, flexDir: _flexDir, rowGap: _rowGap, px: _px, py: _py,
310
- textStyle: _textStyle, alignItems: _alignItems,
311
- ...rest
312
- } = props;
313
- const bodyStyle: React.CSSProperties = {
314
- ...styleProp,
315
- ...(_display ? { display: _display } : {}),
316
- ...(_flexDir ? { flexDirection: _flexDir as React.CSSProperties['flexDirection'] } : {}),
317
- ...(_rowGap !== undefined ? { rowGap: typeof _rowGap === 'number' ? `${ _rowGap * 4 }px` : _rowGap } : {}),
318
- ...(_px !== undefined ? {
319
- paddingLeft: typeof _px === 'number' ? `${ _px * 4 }px` : _px,
320
- paddingRight: typeof _px === 'number' ? `${ _px * 4 }px` : _px,
321
- } : {}),
322
- ...(_py !== undefined ? {
323
- paddingTop: typeof _py === 'number' ? `${ _py * 4 }px` : _py,
324
- paddingBottom: typeof _py === 'number' ? `${ _py * 4 }px` : _py,
325
- } : {}),
326
- ...(_alignItems ? { alignItems: _alignItems } : {}),
327
- };
328
- return (
329
- <div
330
- ref={ ref }
331
- className={ cn('p-4', className) }
332
- style={ Object.keys(bodyStyle).length > 0 ? bodyStyle : undefined }
333
- { ...rest }
334
- />
335
- );
336
- });
337
-
338
- export interface PopoverHeaderProps extends React.ComponentPropsWithoutRef<'div'> {}
339
-
340
- export const PopoverHeader = React.forwardRef<
341
- HTMLDivElement,
342
- PopoverHeaderProps
343
- >(function PopoverHeader(props, ref) {
344
- const { className, ...rest } = props;
345
- return (
346
- <div
347
- ref={ ref }
348
- className={ cn('px-4 pt-4 pb-0 font-semibold', className) }
349
- { ...rest }
350
- />
351
- );
352
- });
353
-
354
- export interface PopoverFooterProps extends React.ComponentPropsWithoutRef<'div'> {}
355
-
356
- export const PopoverFooter = React.forwardRef<
357
- HTMLDivElement,
358
- PopoverFooterProps
359
- >(function PopoverFooter(props, ref) {
360
- const { className, ...rest } = props;
361
- return (
362
- <div
363
- ref={ ref }
364
- className={ cn('px-4 pb-4 pt-0', className) }
365
- { ...rest }
366
- />
367
- );
368
- });
369
-
370
- export interface PopoverTitleProps extends React.ComponentPropsWithoutRef<'h3'> {}
371
-
372
- export const PopoverTitle = React.forwardRef<
373
- HTMLHeadingElement,
374
- PopoverTitleProps
375
- >(function PopoverTitle(props, ref) {
376
- const { className, ...rest } = props;
377
- return (
378
- <h3
379
- ref={ ref }
380
- className={ cn('text-base font-semibold', className) }
381
- { ...rest }
382
- />
383
- );
384
- });
385
-
386
- export interface PopoverDescriptionProps extends React.ComponentPropsWithoutRef<'p'> {}
387
-
388
- export const PopoverDescription = React.forwardRef<
389
- HTMLParagraphElement,
390
- PopoverDescriptionProps
391
- >(function PopoverDescription(props, ref) {
392
- const { className, ...rest } = props;
393
- return (
394
- <p
395
- ref={ ref }
396
- className={ cn('text-sm', className) }
397
- { ...rest }
398
- />
399
- );
400
- });
@@ -1,180 +0,0 @@
1
- import * as React from 'react';
2
-
3
- import { cn } from './utils';
4
-
5
- // ---------------------------------------------------------------------------
6
- // Size presets matching the original Chakra progressCircle recipe
7
- // ---------------------------------------------------------------------------
8
-
9
- const SIZE_MAP = {
10
- xs: { size: 24, thickness: 4, textClass: 'text-[10px]' },
11
- sm: { size: 32, thickness: 5, textClass: 'text-[10px]' },
12
- md: { size: 40, thickness: 6, textClass: 'text-xs' },
13
- lg: { size: 48, thickness: 7, textClass: 'text-sm' },
14
- xl: { size: 64, thickness: 8, textClass: 'text-sm' },
15
- } as const;
16
-
17
- type Size = keyof typeof SIZE_MAP;
18
-
19
- // ---------------------------------------------------------------------------
20
- // Context
21
- // ---------------------------------------------------------------------------
22
-
23
- interface ProgressCircleCtx {
24
- readonly value: number | null;
25
- readonly size: Size;
26
- readonly colorPalette: string;
27
- }
28
-
29
- const Ctx = React.createContext<ProgressCircleCtx>({
30
- value: 0,
31
- size: 'md',
32
- colorPalette: 'blue',
33
- });
34
-
35
- // ---------------------------------------------------------------------------
36
- // Root
37
- // ---------------------------------------------------------------------------
38
-
39
- export interface ProgressCircleRootProps
40
- extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {
41
- readonly value?: number | null;
42
- readonly size?: Size;
43
- readonly colorPalette?: string;
44
- }
45
-
46
- export const ProgressCircleRoot = React.forwardRef<
47
- HTMLDivElement,
48
- ProgressCircleRootProps
49
- >(function ProgressCircleRoot(props, ref) {
50
- const {
51
- value = 0,
52
- size = 'md',
53
- colorPalette = 'blue',
54
- className,
55
- children,
56
- ...rest
57
- } = props;
58
-
59
- const ctx = React.useMemo<ProgressCircleCtx>(
60
- () => ({ value: value ?? null, size, colorPalette }),
61
- [ value, size, colorPalette ],
62
- );
63
-
64
- return (
65
- <Ctx.Provider value={ ctx }>
66
- <div
67
- ref={ ref }
68
- role="progressbar"
69
- aria-valuenow={ value ?? undefined }
70
- aria-valuemin={ 0 }
71
- aria-valuemax={ 100 }
72
- className={ cn('relative inline-flex text-sm', className) }
73
- { ...rest }
74
- >
75
- { children }
76
- </div>
77
- </Ctx.Provider>
78
- );
79
- });
80
-
81
- // ---------------------------------------------------------------------------
82
- // Ring (SVG track + range arc)
83
- // ---------------------------------------------------------------------------
84
-
85
- export interface ProgressCircleRingProps
86
- extends Omit<React.SVGAttributes<SVGSVGElement>, 'color'> {
87
- readonly trackColor?: string;
88
- readonly cap?: React.SVGAttributes<SVGCircleElement>['strokeLinecap'];
89
- readonly color?: string;
90
- }
91
-
92
- export const ProgressCircleRing = React.forwardRef<
93
- SVGSVGElement,
94
- ProgressCircleRingProps
95
- >(function ProgressCircleRing(props, ref) {
96
- const { trackColor, cap, color, className, ...rest } = props;
97
- const { value, size: sizeKey } = React.useContext(Ctx);
98
-
99
- const { size, thickness } = SIZE_MAP[sizeKey];
100
- const radius = size / 2 - thickness / 2;
101
- const circumference = 2 * Math.PI * radius;
102
- const percent = value ?? 0;
103
- const offset = circumference * ((100 - percent) / 100);
104
-
105
- return (
106
- <svg
107
- ref={ ref }
108
- width={ size }
109
- height={ size }
110
- viewBox={ `0 0 ${ size } ${ size }` }
111
- className={ cn(
112
- value === null && 'animate-spin',
113
- className,
114
- ) }
115
- { ...rest }
116
- >
117
- { /* Track */ }
118
- <circle
119
- cx={ size / 2 }
120
- cy={ size / 2 }
121
- r={ radius }
122
- fill="transparent"
123
- strokeWidth={ thickness }
124
- stroke={ trackColor ?? 'currentColor' }
125
- className={ !trackColor ? 'opacity-20' : undefined }
126
- />
127
- { /* Range */ }
128
- <circle
129
- cx={ size / 2 }
130
- cy={ size / 2 }
131
- r={ radius }
132
- fill="transparent"
133
- strokeWidth={ thickness }
134
- stroke={ color ?? 'currentColor' }
135
- strokeLinecap={ cap }
136
- strokeDasharray={ circumference }
137
- strokeDashoffset={ offset }
138
- style={{
139
- transformOrigin: 'center',
140
- transform: 'rotate(-90deg)',
141
- transition: 'stroke-dashoffset 0.6s, stroke-dasharray 0.6s',
142
- opacity: percent === 0 ? 0 : undefined,
143
- }}
144
- />
145
- </svg>
146
- );
147
- });
148
-
149
- // ---------------------------------------------------------------------------
150
- // Value text (centered number)
151
- // ---------------------------------------------------------------------------
152
-
153
- export interface ProgressCircleValueTextProps
154
- extends React.HTMLAttributes<HTMLDivElement> {}
155
-
156
- export const ProgressCircleValueText = React.forwardRef<
157
- HTMLDivElement,
158
- ProgressCircleValueTextProps
159
- >(function ProgressCircleValueText(props, ref) {
160
- const { className, children, ...rest } = props;
161
- const { value, size: sizeKey } = React.useContext(Ctx);
162
-
163
- const { textClass } = SIZE_MAP[sizeKey];
164
-
165
- return (
166
- <div
167
- ref={ ref }
168
- aria-live="polite"
169
- className={ cn(
170
- 'absolute inset-0 flex items-center justify-center',
171
- 'font-medium tracking-tight tabular-nums leading-none',
172
- textClass,
173
- className,
174
- ) }
175
- { ...rest }
176
- >
177
- { children ?? `${ Math.round(value ?? 0) }%` }
178
- </div>
179
- );
180
- });
package/src/progress.tsx DELETED
@@ -1,109 +0,0 @@
1
- import * as RadixProgress from '@radix-ui/react-progress';
2
- import * as React from 'react';
3
-
4
- import { cn } from './utils';
5
-
6
- const SIZE_CLASSES = {
7
- sm: 'h-1',
8
- md: 'h-2',
9
- lg: 'h-3',
10
- xl: 'h-4',
11
- } as const;
12
-
13
- type Size = keyof typeof SIZE_CLASSES;
14
-
15
- interface TrackProps {
16
- readonly borderStartRadius?: number | string;
17
- readonly borderEndRadius?: number | string;
18
- readonly className?: string;
19
- readonly style?: React.CSSProperties;
20
- }
21
-
22
- interface ProgressProps extends React.ComponentPropsWithoutRef<'div'> {
23
- readonly value?: number | null;
24
- readonly min?: number;
25
- readonly max?: number;
26
- readonly size?: Size;
27
- readonly color?: string;
28
- readonly trackProps?: TrackProps;
29
-
30
- // Common Chakra layout shorthands that consumers currently pass.
31
- readonly w?: string;
32
- readonly flex?: string | number;
33
- }
34
-
35
- function normalizeValue(value: number | null | undefined, min: number, max: number): number {
36
- if (value == null) return 0;
37
- if (max <= min) return 0;
38
- return Math.round(((value - min) / (max - min)) * 100);
39
- }
40
-
41
- export const Progress = React.forwardRef<HTMLDivElement, ProgressProps>(
42
- function Progress(props, ref) {
43
- const {
44
- value,
45
- min = 0,
46
- max = 100,
47
- size = 'md',
48
- color,
49
- trackProps,
50
- className,
51
- style,
52
- w,
53
- flex,
54
- ...rest
55
- } = props;
56
-
57
- const percent = normalizeValue(value, min, max);
58
-
59
- const trackStyle: React.CSSProperties = {
60
- ...trackProps?.style,
61
- ...(trackProps?.borderStartRadius !== undefined && {
62
- borderStartStartRadius: trackProps.borderStartRadius,
63
- borderEndStartRadius: trackProps.borderStartRadius,
64
- }),
65
- ...(trackProps?.borderEndRadius !== undefined && {
66
- borderStartEndRadius: trackProps.borderEndRadius,
67
- borderEndEndRadius: trackProps.borderEndRadius,
68
- }),
69
- };
70
-
71
- const rootStyle: React.CSSProperties = {
72
- ...style,
73
- ...(w !== undefined && { width: w === 'full' ? '100%' : w }),
74
- ...(flex !== undefined && { flex }),
75
- };
76
-
77
- return (
78
- <div
79
- ref={ ref }
80
- className={ cn('relative', className) }
81
- style={ rootStyle }
82
- { ...rest }
83
- >
84
- <RadixProgress.Root
85
- value={ percent }
86
- max={ 100 }
87
- className={ cn(
88
- 'w-full overflow-hidden rounded-full',
89
- 'bg-[var(--color-progress-track)]',
90
- SIZE_CLASSES[size],
91
- trackProps?.className,
92
- ) }
93
- style={ trackStyle }
94
- >
95
- <RadixProgress.Indicator
96
- className={ cn(
97
- 'h-full rounded-full transition-transform duration-500 ease-out',
98
- !color && 'bg-[var(--color-progress-indicator)]',
99
- ) }
100
- style={{
101
- width: `${ percent }%`,
102
- ...(color && { backgroundColor: `var(--color-${ color.replace('.', '-') }, ${ color })` }),
103
- }}
104
- />
105
- </RadixProgress.Root>
106
- </div>
107
- );
108
- },
109
- );
package/src/provider.tsx DELETED
@@ -1,12 +0,0 @@
1
- 'use client';
2
-
3
- import React from 'react';
4
-
5
- import {
6
- ColorModeProvider,
7
- type ColorModeProviderProps,
8
- } from './color-mode';
9
-
10
- export function Provider(props: ColorModeProviderProps) {
11
- return <ColorModeProvider { ...props }/>;
12
- }