@repraze/kernelkit 0.1.0-alpha.4 → 0.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/alert-dialog.d.ts.map +1 -1
- package/dist/components/alert-dialog.js +4 -1
- package/dist/components/alert-dialog.js.map +1 -1
- package/dist/components/alert.js +3 -3
- package/dist/components/alert.js.map +1 -1
- package/dist/components/badge.js +1 -1
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.js +1 -1
- package/dist/components/button.js.map +1 -1
- package/dist/components/calendar.d.ts +8 -1
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +33 -11
- package/dist/components/calendar.js.map +1 -1
- package/dist/components/callout.js +2 -2
- package/dist/components/callout.js.map +1 -1
- package/dist/components/combobox.js +1 -1
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/date-picker.d.ts +11 -5
- package/dist/components/date-picker.d.ts.map +1 -1
- package/dist/components/date-picker.js +29 -7
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +26 -0
- package/dist/components/description-list.d.ts.map +1 -0
- package/dist/components/description-list.js +59 -0
- package/dist/components/description-list.js.map +1 -0
- package/dist/components/locale.d.ts +19 -0
- package/dist/components/locale.d.ts.map +1 -0
- package/dist/components/locale.js +54 -0
- package/dist/components/locale.js.map +1 -0
- package/dist/components/popover.d.ts +1 -1
- package/dist/components/popover.d.ts.map +1 -1
- package/dist/components/popover.js +2 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/progress.d.ts +19 -6
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +18 -3
- package/dist/components/progress.js.map +1 -1
- package/dist/components/search-trigger.d.ts +4 -1
- package/dist/components/search-trigger.d.ts.map +1 -1
- package/dist/components/search-trigger.js +5 -2
- package/dist/components/search-trigger.js.map +1 -1
- package/dist/components/shimmer.d.ts +13 -0
- package/dist/components/shimmer.d.ts.map +1 -0
- package/dist/components/shimmer.js +21 -0
- package/dist/components/shimmer.js.map +1 -0
- package/dist/components/spinner.d.ts +28 -6
- package/dist/components/spinner.d.ts.map +1 -1
- package/dist/components/spinner.js +66 -14
- package/dist/components/spinner.js.map +1 -1
- package/dist/components/stepper.d.ts +64 -0
- package/dist/components/stepper.d.ts.map +1 -0
- package/dist/components/stepper.js +167 -0
- package/dist/components/stepper.js.map +1 -0
- package/dist/components/tag-input.d.ts +47 -0
- package/dist/components/tag-input.d.ts.map +1 -0
- package/dist/components/tag-input.js +211 -0
- package/dist/components/tag-input.js.map +1 -0
- package/dist/components/time-input.d.ts +75 -0
- package/dist/components/time-input.d.ts.map +1 -0
- package/dist/components/time-input.js +341 -0
- package/dist/components/time-input.js.map +1 -0
- package/dist/components/time-select.d.ts +49 -0
- package/dist/components/time-select.d.ts.map +1 -0
- package/dist/components/time-select.js +178 -0
- package/dist/components/time-select.js.map +1 -0
- package/dist/components/timeline.d.ts +41 -0
- package/dist/components/timeline.d.ts.map +1 -0
- package/dist/components/timeline.js +83 -0
- package/dist/components/timeline.js.map +1 -0
- package/dist/components/toast.d.ts.map +1 -1
- package/dist/components/toast.js +4 -2
- package/dist/components/toast.js.map +1 -1
- package/dist/components/tree.d.ts +87 -0
- package/dist/components/tree.d.ts.map +1 -0
- package/dist/components/tree.js +516 -0
- package/dist/components/tree.js.map +1 -0
- package/dist/hooks/use-time-format.d.ts +23 -0
- package/dist/hooks/use-time-format.d.ts.map +1 -0
- package/dist/hooks/use-time-format.js +52 -0
- package/dist/hooks/use-time-format.js.map +1 -0
- package/dist/lib/color.d.ts +5 -1
- package/dist/lib/color.d.ts.map +1 -1
- package/dist/lib/color.js +14 -2
- package/dist/lib/color.js.map +1 -1
- package/dist/lib/recipes.d.ts +5 -4
- package/dist/lib/recipes.d.ts.map +1 -1
- package/dist/lib/recipes.js +7 -5
- package/dist/lib/recipes.js.map +1 -1
- package/package.json +1 -1
- package/src/components/alert-dialog.tsx +4 -1
- package/src/components/alert.tsx +3 -3
- package/src/components/badge.tsx +1 -1
- package/src/components/button.tsx +1 -1
- package/src/components/calendar.tsx +48 -4
- package/src/components/callout.tsx +2 -2
- package/src/components/combobox.tsx +1 -1
- package/src/components/date-picker.tsx +43 -9
- package/src/components/description-list.tsx +107 -0
- package/src/components/locale.tsx +67 -0
- package/src/components/popover.tsx +3 -1
- package/src/components/progress.tsx +70 -4
- package/src/components/search-trigger.tsx +8 -2
- package/src/components/shimmer.tsx +36 -0
- package/src/components/spinner.tsx +126 -23
- package/src/components/stepper.tsx +346 -0
- package/src/components/tag-input.tsx +345 -0
- package/src/components/time-input.tsx +578 -0
- package/src/components/time-select.tsx +291 -0
- package/src/components/timeline.tsx +190 -0
- package/src/components/toast.tsx +4 -4
- package/src/components/tree.tsx +832 -0
- package/src/hooks/use-time-format.ts +72 -0
- package/src/lib/color.ts +19 -2
- package/src/lib/recipes.ts +7 -5
- package/src/styles/kernelkit.css +56 -0
|
@@ -20,9 +20,10 @@ function PopoverContent({
|
|
|
20
20
|
alignOffset = 0,
|
|
21
21
|
side = "bottom",
|
|
22
22
|
sideOffset = 4,
|
|
23
|
+
anchor,
|
|
23
24
|
...props
|
|
24
25
|
}: PopoverPrimitive.Popup.Props &
|
|
25
|
-
Pick<PopoverPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset">) {
|
|
26
|
+
Pick<PopoverPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" | "anchor">) {
|
|
26
27
|
return (
|
|
27
28
|
<PopoverPrimitive.Portal container={usePortalContainer()}>
|
|
28
29
|
<PopoverPrimitive.Positioner
|
|
@@ -30,6 +31,7 @@ function PopoverContent({
|
|
|
30
31
|
alignOffset={alignOffset}
|
|
31
32
|
side={side}
|
|
32
33
|
sideOffset={sideOffset}
|
|
34
|
+
anchor={anchor}
|
|
33
35
|
className="isolate z-50"
|
|
34
36
|
>
|
|
35
37
|
<PopoverPrimitive.Popup
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import {Progress as ProgressPrimitive} from "@base-ui/react/progress";
|
|
4
4
|
import {type Color, colorVariants} from "@repraze/kernelkit/lib/color";
|
|
5
|
+
import {placeholderFill} from "@repraze/kernelkit/lib/recipes";
|
|
5
6
|
import {cva} from "class-variance-authority";
|
|
6
7
|
import {cn} from "cn";
|
|
8
|
+
import type * as React from "react";
|
|
7
9
|
|
|
8
10
|
/** Root of a progress or meter: label + value on one row, track below. Sets the color vars. */
|
|
9
11
|
const progressVariants = cva("group/progress flex w-full flex-wrap items-center gap-x-3 gap-y-1.5", {
|
|
@@ -29,24 +31,44 @@ interface ProgressProps extends Omit<ProgressPrimitive.Root.Props, "color"> {
|
|
|
29
31
|
color?: Color | null;
|
|
30
32
|
/** Track height: sm `h-1`, default `h-1.5`, lg `h-2`. */
|
|
31
33
|
size?: ProgressSize | null;
|
|
34
|
+
/** `bar`: one pill track. `segmented`: a row of cells, lit in order; a wave runs through them while indeterminate. */
|
|
35
|
+
variant?: "bar" | "segmented";
|
|
36
|
+
/** `segmented` only: number of cells. */
|
|
37
|
+
segments?: number;
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
function Progress({
|
|
40
|
+
function Progress({
|
|
41
|
+
className,
|
|
42
|
+
children,
|
|
43
|
+
value,
|
|
44
|
+
color,
|
|
45
|
+
size,
|
|
46
|
+
variant = "bar",
|
|
47
|
+
segments = 12,
|
|
48
|
+
max = 100,
|
|
49
|
+
...props
|
|
50
|
+
}: ProgressProps) {
|
|
35
51
|
const resolvedColor = color ?? "primary";
|
|
36
52
|
const resolvedSize = size ?? "default";
|
|
37
53
|
return (
|
|
38
54
|
<ProgressPrimitive.Root
|
|
39
55
|
value={value}
|
|
56
|
+
max={max}
|
|
40
57
|
data-slot="progress"
|
|
58
|
+
data-variant={variant}
|
|
41
59
|
data-color={resolvedColor}
|
|
42
60
|
data-size={resolvedSize}
|
|
43
61
|
className={cn(progressVariants({color: resolvedColor, size: resolvedSize}), className)}
|
|
44
62
|
{...props}
|
|
45
63
|
>
|
|
46
64
|
{children}
|
|
47
|
-
|
|
48
|
-
<
|
|
49
|
-
|
|
65
|
+
{variant === "segmented" ? (
|
|
66
|
+
<ProgressSegments segments={segments} lit={value == null ? null : (value / max) * segments} />
|
|
67
|
+
) : (
|
|
68
|
+
<ProgressTrack>
|
|
69
|
+
<ProgressIndicator />
|
|
70
|
+
</ProgressTrack>
|
|
71
|
+
)}
|
|
50
72
|
</ProgressPrimitive.Root>
|
|
51
73
|
);
|
|
52
74
|
}
|
|
@@ -72,6 +94,49 @@ function ProgressIndicator({className, ...props}: ProgressPrimitive.Indicator.Pr
|
|
|
72
94
|
);
|
|
73
95
|
}
|
|
74
96
|
|
|
97
|
+
/** Negative delays so every cell is mid-cycle on the first frame (no dead start). */
|
|
98
|
+
const cellDelay = (i: number, n: number) => ({animationDelay: `${-((n - i) * 1.2) / n}s`});
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The `segmented` track: cells in the fill tier, unlit ones on the placeholder fill (§4). `lit` is how many
|
|
102
|
+
* cells are on (fractional rounds), `null` runs the indeterminate wave. Reduced motion slows the wave down.
|
|
103
|
+
*/
|
|
104
|
+
function ProgressSegments({
|
|
105
|
+
segments,
|
|
106
|
+
lit,
|
|
107
|
+
className,
|
|
108
|
+
...props
|
|
109
|
+
}: React.ComponentProps<"div"> & {segments: number; lit: number | null}) {
|
|
110
|
+
const on = lit === null ? -1 : Math.round(Math.min(segments, Math.max(0, lit)));
|
|
111
|
+
return (
|
|
112
|
+
<div
|
|
113
|
+
data-slot="progress-segments"
|
|
114
|
+
aria-hidden
|
|
115
|
+
className={cn(
|
|
116
|
+
"flex h-1.5 w-full gap-0.5 group-data-[size=lg]/progress:h-2 group-data-[size=sm]/progress:h-1",
|
|
117
|
+
className,
|
|
118
|
+
)}
|
|
119
|
+
{...props}
|
|
120
|
+
>
|
|
121
|
+
{Array.from({length: segments}, (_, i) => (
|
|
122
|
+
<span
|
|
123
|
+
key={i}
|
|
124
|
+
data-lit={on < 0 || i < on ? "" : undefined}
|
|
125
|
+
className={cn(
|
|
126
|
+
"h-full flex-1 rounded-xs transition-colors duration-300 motion-reduce:transition-none",
|
|
127
|
+
on < 0
|
|
128
|
+
? "animate-loader-cell bg-(--c-fill) motion-reduce:[animation-duration:3s]"
|
|
129
|
+
: i < on
|
|
130
|
+
? "bg-(--c-fill)"
|
|
131
|
+
: placeholderFill,
|
|
132
|
+
)}
|
|
133
|
+
style={on < 0 ? cellDelay(i, segments) : undefined}
|
|
134
|
+
/>
|
|
135
|
+
))}
|
|
136
|
+
</div>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
75
140
|
function ProgressLabel({className, ...props}: ProgressPrimitive.Label.Props) {
|
|
76
141
|
return (
|
|
77
142
|
<ProgressPrimitive.Label
|
|
@@ -97,6 +162,7 @@ export {
|
|
|
97
162
|
ProgressIndicator,
|
|
98
163
|
progressIndicatorClass,
|
|
99
164
|
ProgressLabel,
|
|
165
|
+
ProgressSegments,
|
|
100
166
|
ProgressTrack,
|
|
101
167
|
progressTrackClass,
|
|
102
168
|
ProgressValue,
|
|
@@ -51,7 +51,10 @@ interface SearchTriggerProps extends React.ComponentProps<typeof Button> {
|
|
|
51
51
|
children?: React.ReactNode;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Header search button: icon, placeholder, OS-aware shortcut. Same 32px height as the header's icon buttons. Open your dialog in `onClick`.
|
|
56
|
+
* The keycap gets the same inset on the right as top/bottom (32 - 20 = 6px each side, border included).
|
|
57
|
+
*/
|
|
55
58
|
function SearchTrigger({children = "Search…", className, ...props}: SearchTriggerProps) {
|
|
56
59
|
const mod = useModKey();
|
|
57
60
|
return (
|
|
@@ -59,7 +62,10 @@ function SearchTrigger({children = "Search…", className, ...props}: SearchTrig
|
|
|
59
62
|
variant="outline"
|
|
60
63
|
aria-label="Search"
|
|
61
64
|
data-slot="search-trigger"
|
|
62
|
-
className={cn(
|
|
65
|
+
className={cn(
|
|
66
|
+
"w-8 justify-start px-0 text-muted-foreground sm:w-48 sm:pr-1.25 sm:pl-2.5 md:w-56",
|
|
67
|
+
className,
|
|
68
|
+
)}
|
|
63
69
|
{...props}
|
|
64
70
|
>
|
|
65
71
|
<SearchIcon data-icon="inline-start" className="mx-auto sm:mx-0" />
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {mergeProps} from "@base-ui/react/merge-props";
|
|
4
|
+
import {useRender} from "@base-ui/react/use-render";
|
|
5
|
+
import {cn} from "cn";
|
|
6
|
+
|
|
7
|
+
interface ShimmerProps extends useRender.ComponentProps<"span"> {
|
|
8
|
+
/** Seconds per sweep. */
|
|
9
|
+
duration?: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Text with a highlight band sweeping across it ("Thinking…", "Indexing files…"). Muted text, foreground
|
|
14
|
+
* band. Reduced motion: plain muted text.
|
|
15
|
+
*/
|
|
16
|
+
function Shimmer({render, duration, className, style, ...props}: ShimmerProps) {
|
|
17
|
+
return useRender({
|
|
18
|
+
defaultTagName: "span",
|
|
19
|
+
props: mergeProps<"span">(
|
|
20
|
+
{
|
|
21
|
+
className: cn(
|
|
22
|
+
"inline-block animate-shimmer bg-linear-to-r from-muted-foreground from-40% via-foreground via-50% to-muted-foreground to-60% bg-size-[250%_100%] bg-clip-text text-transparent",
|
|
23
|
+
"motion-reduce:animate-none motion-reduce:bg-none motion-reduce:text-muted-foreground",
|
|
24
|
+
className,
|
|
25
|
+
),
|
|
26
|
+
style: duration ? {animationDuration: `${duration}s`, ...style} : style,
|
|
27
|
+
},
|
|
28
|
+
props,
|
|
29
|
+
),
|
|
30
|
+
render,
|
|
31
|
+
state: {slot: "shimmer"},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export {Shimmer};
|
|
36
|
+
export type {ShimmerProps};
|
|
@@ -1,42 +1,145 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import {type Color, colorVariants} from "@repraze/kernelkit/lib/color";
|
|
4
|
+
import {placeholderFill} from "@repraze/kernelkit/lib/recipes";
|
|
3
5
|
import {cva, type VariantProps} from "class-variance-authority";
|
|
4
6
|
import {cn} from "cn";
|
|
5
7
|
import {Loader2Icon} from "lucide-react";
|
|
8
|
+
import * as React from "react";
|
|
6
9
|
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Sizes follow the icon column of §4 so a spinner can replace an icon in place. Each size also sets the
|
|
12
|
+
* vars the techy variants draw with: `--ls` (box), `--lc`/`--lg` (dot cell and gap, whole pixels so cells
|
|
13
|
+
* stay crisp) and `--lb` (bar width).
|
|
14
|
+
*/
|
|
15
|
+
const spinnerVariants = cva("relative inline-flex shrink-0 items-center justify-center align-middle text-current", {
|
|
16
|
+
variants: {
|
|
17
|
+
variant: {
|
|
18
|
+
// reduced motion: slow the spin down rather than freeze it, a frozen spinner reads as a glyph
|
|
19
|
+
ring: "size-(--ls) animate-spin motion-reduce:[animation-duration:2.5s]",
|
|
20
|
+
dots: "size-(--ls)",
|
|
21
|
+
braille: "h-(--ls) w-(--ls) items-start overflow-hidden font-mono text-(length:--ls) leading-none",
|
|
22
|
+
// hc: the placeholder fill is the dark border colour there, so the box becomes an outline instead
|
|
23
|
+
scan: `size-(--ls) overflow-hidden rounded-box ${placeholderFill} hc:bg-transparent hc:shadow-[inset_0_0_0_1px_var(--border)]`,
|
|
24
|
+
blink: "h-(--ls) w-[calc(var(--ls)/2)]",
|
|
25
|
+
bars: "size-(--ls) justify-between",
|
|
26
|
+
},
|
|
27
|
+
size: {
|
|
28
|
+
xs: "[--lb:2px] [--lc:3px] [--lg:1px] [--ls:0.75rem]",
|
|
29
|
+
sm: "[--lb:2px] [--lc:4px] [--lg:1px] [--ls:0.875rem]",
|
|
30
|
+
default: "[--lb:3px] [--lc:4px] [--lg:2px] [--ls:1rem]",
|
|
31
|
+
lg: "[--lb:3px] [--lc:6px] [--lg:1px] [--ls:1.25rem]",
|
|
32
|
+
xl: "[--lb:4px] [--lc:6px] [--lg:3px] [--ls:1.5rem]",
|
|
20
33
|
},
|
|
21
|
-
defaultVariants: {size: "default"},
|
|
22
34
|
},
|
|
23
|
-
|
|
35
|
+
defaultVariants: {variant: "ring", size: "default"},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
type SpinnerVariant = NonNullable<VariantProps<typeof spinnerVariants>["variant"]>;
|
|
39
|
+
|
|
40
|
+
/** Every animated part: slower, not frozen, under reduced motion. */
|
|
41
|
+
const slow = "motion-reduce:[animation-duration:3s]";
|
|
24
42
|
|
|
25
|
-
|
|
43
|
+
const BRAILLE = "⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏";
|
|
44
|
+
|
|
45
|
+
/** Negative delays so every cell is mid-cycle on the first frame (no dead start). */
|
|
46
|
+
const delay = (i: number, n: number, duration: number) => ({animationDelay: `${-((n - i) * duration) / n}s`});
|
|
47
|
+
|
|
48
|
+
function SpinnerParts({variant}: {variant: SpinnerVariant}) {
|
|
49
|
+
switch (variant) {
|
|
50
|
+
case "ring":
|
|
51
|
+
return <Loader2Icon aria-hidden className="size-full" />;
|
|
52
|
+
case "dots":
|
|
53
|
+
return (
|
|
54
|
+
<span
|
|
55
|
+
data-slot="spinner-grid"
|
|
56
|
+
className="grid grid-cols-[repeat(3,var(--lc))] grid-rows-[repeat(3,var(--lc))] gap-(--lg)"
|
|
57
|
+
>
|
|
58
|
+
{Array.from({length: 9}, (_, i) => (
|
|
59
|
+
<span
|
|
60
|
+
key={i}
|
|
61
|
+
className={cn("animate-loader-cell rounded-pill bg-current", slow)}
|
|
62
|
+
// diagonal wave from the top-left corner
|
|
63
|
+
style={delay(4 - (Math.floor(i / 3) + (i % 3)), 5, 1.2)}
|
|
64
|
+
/>
|
|
65
|
+
))}
|
|
66
|
+
</span>
|
|
67
|
+
);
|
|
68
|
+
case "braille":
|
|
69
|
+
return (
|
|
70
|
+
<span aria-hidden className={cn("flex animate-loader-braille flex-col", slow)}>
|
|
71
|
+
{[...BRAILLE].map((g) => (
|
|
72
|
+
<span key={g} className="h-(--ls) leading-(--ls)">
|
|
73
|
+
{g}
|
|
74
|
+
</span>
|
|
75
|
+
))}
|
|
76
|
+
</span>
|
|
77
|
+
);
|
|
78
|
+
case "scan":
|
|
79
|
+
return (
|
|
80
|
+
<span
|
|
81
|
+
className={cn(
|
|
82
|
+
"absolute inset-0 animate-loader-scan border-e-2 border-current bg-linear-to-r from-transparent to-current/40",
|
|
83
|
+
slow,
|
|
84
|
+
)}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
87
|
+
case "blink":
|
|
88
|
+
return <span className={cn("size-full animate-loader-blink bg-current", slow)} />;
|
|
89
|
+
case "bars":
|
|
90
|
+
return Array.from({length: 4}, (_, i) => (
|
|
91
|
+
<span
|
|
92
|
+
key={i}
|
|
93
|
+
className={cn("h-full w-(--lb) origin-bottom animate-loader-bars rounded-box bg-current", slow)}
|
|
94
|
+
style={delay((i * 2 + Math.floor(i / 2)) % 4, 4, 0.9)}
|
|
95
|
+
/>
|
|
96
|
+
));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const SpinnerContext = React.createContext<SpinnerVariant>("ring");
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Sets the default `variant` of every Spinner below it, including the ones the kit renders itself
|
|
104
|
+
* (tree lazy rows, stepper, file upload, toasts): one switch for the whole app's loading look.
|
|
105
|
+
*/
|
|
106
|
+
function SpinnerProvider({variant, children}: {variant: SpinnerVariant; children: React.ReactNode}) {
|
|
107
|
+
return <SpinnerContext.Provider value={variant}>{children}</SpinnerContext.Provider>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface SpinnerProps
|
|
111
|
+
extends Omit<React.ComponentProps<"span">, "color" | "children">, VariantProps<typeof spinnerVariants> {
|
|
112
|
+
/** Color from the §2 axis; defaults to `currentColor`. */
|
|
113
|
+
color?: Color;
|
|
114
|
+
}
|
|
26
115
|
|
|
27
|
-
/**
|
|
28
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Indeterminate loading indicator at icon size: a spinning ring, or a techy variant (dot matrix, braille,
|
|
118
|
+
* scan line, block cursor, equalizer bars). Inherits `currentColor`; announces itself as a status. The
|
|
119
|
+
* default variant comes from the nearest `SpinnerProvider`.
|
|
120
|
+
*/
|
|
121
|
+
function Spinner({variant, size, color, className, ...props}: SpinnerProps) {
|
|
122
|
+
const fallback = React.useContext(SpinnerContext);
|
|
123
|
+
const resolved = variant ?? fallback;
|
|
29
124
|
return (
|
|
30
|
-
<
|
|
125
|
+
<span
|
|
31
126
|
data-slot="spinner"
|
|
127
|
+
data-variant={resolved}
|
|
32
128
|
data-size={size ?? "default"}
|
|
129
|
+
data-color={color}
|
|
33
130
|
role="status"
|
|
34
131
|
aria-label="Loading"
|
|
35
|
-
className={cn(
|
|
132
|
+
className={cn(
|
|
133
|
+
spinnerVariants({variant: resolved, size}),
|
|
134
|
+
color && cn(colorVariants[color], "text-(--c)"),
|
|
135
|
+
className,
|
|
136
|
+
)}
|
|
36
137
|
{...props}
|
|
37
|
-
|
|
138
|
+
>
|
|
139
|
+
<SpinnerParts variant={resolved} />
|
|
140
|
+
</span>
|
|
38
141
|
);
|
|
39
142
|
}
|
|
40
143
|
|
|
41
|
-
export {Spinner, spinnerVariants};
|
|
42
|
-
export type {SpinnerProps};
|
|
144
|
+
export {Spinner, SpinnerProvider, spinnerVariants};
|
|
145
|
+
export type {SpinnerProps, SpinnerVariant};
|