@krizaka/ui 2.1.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -9
- package/dist/{button-Cgfkg_3y.d.ts → button-BMAO7dKF.d.ts} +29 -2
- package/dist/button.d.ts +32 -5
- package/dist/button.js +62 -9
- package/dist/button.js.map +1 -1
- package/dist/chip-link.d.ts +53 -0
- package/dist/chip-link.js +32 -0
- package/dist/chip-link.js.map +1 -0
- package/dist/chunk-43PTCDTL.js +31 -0
- package/dist/chunk-43PTCDTL.js.map +1 -0
- package/dist/chunk-6ISW63JI.js +11 -0
- package/dist/chunk-6ISW63JI.js.map +1 -0
- package/dist/chunk-HAQWKORZ.js +117 -0
- package/dist/chunk-HAQWKORZ.js.map +1 -0
- package/dist/{chunk-FHYZSO2S.js → chunk-R6SDS7JM.js} +5 -3
- package/dist/chunk-R6SDS7JM.js.map +1 -0
- package/dist/chunk-RUPNPMP3.js +103 -0
- package/dist/chunk-RUPNPMP3.js.map +1 -0
- package/dist/chunk-VDR2EP6K.js +49 -0
- package/dist/chunk-VDR2EP6K.js.map +1 -0
- package/dist/chunk-WEVYKZIF.js +33 -0
- package/dist/chunk-WEVYKZIF.js.map +1 -0
- package/dist/command.d.ts +7 -7
- package/dist/command.js +3 -2
- package/dist/command.js.map +1 -1
- package/dist/confirm-button.d.ts +1 -1
- package/dist/confirm-button.js +2 -1
- package/dist/confirm-button.js.map +1 -1
- package/dist/{dialog-GQ4Nvuyf.d.ts → dialog-D42QwYb_.d.ts} +11 -1
- package/dist/dialog.d.ts +1 -1
- package/dist/dialog.js +3 -2
- package/dist/dialog.js.map +1 -1
- package/dist/glow-card.d.ts +20 -0
- package/dist/glow-card.js +30 -0
- package/dist/glow-card.js.map +1 -0
- package/dist/index.d.ts +2 -20
- package/dist/index.js +7 -64
- package/dist/index.js.map +1 -1
- package/dist/iso.d.ts +400 -0
- package/dist/iso.js +363 -0
- package/dist/iso.js.map +1 -0
- package/dist/loader.d.ts +206 -0
- package/dist/loader.js +138 -0
- package/dist/loader.js.map +1 -0
- package/dist/marquee.d.ts +33 -0
- package/dist/marquee.js +52 -0
- package/dist/marquee.js.map +1 -0
- package/dist/mascots.d.ts +40 -0
- package/dist/mascots.js +253 -0
- package/dist/mascots.js.map +1 -0
- package/dist/meter.d.ts +146 -0
- package/dist/meter.js +107 -0
- package/dist/meter.js.map +1 -0
- package/dist/motion.css +394 -3
- package/dist/motion.d.ts +46 -0
- package/dist/motion.js +10 -0
- package/dist/motion.js.map +1 -0
- package/dist/native.d.ts +40 -1
- package/dist/native.js +326 -128
- package/dist/native.js.map +1 -1
- package/dist/nav-bar.d.ts +178 -0
- package/dist/nav-bar.js +157 -0
- package/dist/nav-bar.js.map +1 -0
- package/dist/number-ticker.d.ts +32 -0
- package/dist/number-ticker.js +61 -0
- package/dist/number-ticker.js.map +1 -0
- package/dist/progress.d.ts +56 -1
- package/dist/progress.js +72 -25
- package/dist/progress.js.map +1 -1
- package/dist/skeleton.d.ts +18 -3
- package/dist/skeleton.js +9 -1
- package/dist/skeleton.js.map +1 -1
- package/dist/spinner.d.ts +21 -5
- package/dist/spinner.js +13 -12
- package/dist/spinner.js.map +1 -1
- package/dist/stepper.d.ts +112 -0
- package/dist/stepper.js +67 -0
- package/dist/stepper.js.map +1 -0
- package/dist/tabs.d.ts +1 -1
- package/dist/tabs.js +14 -8
- package/dist/tabs.js.map +1 -1
- package/dist/theme.d.ts +1 -1
- package/dist/theme.js +2 -1
- package/dist/theme.js.map +1 -1
- package/dist/toast.d.ts +39 -4
- package/dist/toast.js +81 -7
- package/dist/toast.js.map +1 -1
- package/package.json +159 -9
- package/registry/alert.json +1 -1
- package/registry/avatar.json +1 -1
- package/registry/badge.json +1 -1
- package/registry/button.json +232 -26
- package/registry/card.json +1 -1
- package/registry/checkbox.json +1 -1
- package/registry/chip-link.json +158 -0
- package/registry/chip.json +1 -1
- package/registry/command.json +1 -1
- package/registry/confirm-button.json +91 -7
- package/registry/countdown.json +1 -1
- package/registry/dialog.json +15 -7
- package/registry/dropdown-menu.json +1 -1
- package/registry/empty-state.json +1 -1
- package/registry/examples/button/error.js +11 -0
- package/registry/examples/button/error.tsx +10 -0
- package/registry/examples/button/loading.tsx +1 -1
- package/registry/examples/button/save-flow.d.ts +4 -0
- package/registry/examples/button/save-flow.js +28 -0
- package/registry/examples/button/save-flow.tsx +24 -0
- package/registry/examples/button/signature.d.ts +4 -0
- package/registry/examples/button/signature.js +17 -0
- package/registry/examples/button/signature.tsx +19 -0
- package/registry/examples/button/upload-progress.d.ts +4 -0
- package/registry/examples/button/upload-progress.js +23 -0
- package/registry/examples/button/upload-progress.tsx +26 -0
- package/registry/examples/chip-link/filters.d.ts +4 -0
- package/registry/examples/chip-link/filters.js +12 -0
- package/registry/examples/chip-link/filters.tsx +17 -0
- package/registry/examples/dialog/left.d.ts +4 -0
- package/registry/examples/dialog/left.js +22 -0
- package/registry/examples/dialog/left.tsx +32 -0
- package/registry/examples/glow-card/link-card.d.ts +4 -0
- package/registry/examples/glow-card/link-card.js +14 -0
- package/registry/examples/glow-card/link-card.tsx +13 -0
- package/registry/examples/glow-card/plans.d.ts +4 -0
- package/registry/examples/glow-card/plans.js +25 -0
- package/registry/examples/glow-card/plans.tsx +26 -0
- package/registry/examples/glow-card/spotlight.d.ts +4 -0
- package/registry/examples/glow-card/spotlight.js +14 -0
- package/registry/examples/glow-card/spotlight.tsx +15 -0
- package/registry/examples/iso/compose.d.ts +4 -0
- package/registry/examples/iso/compose.js +22 -0
- package/registry/examples/iso/compose.tsx +19 -0
- package/registry/examples/iso/orazaka-hero.d.ts +4 -0
- package/registry/examples/iso/orazaka-hero.js +26 -0
- package/registry/examples/iso/orazaka-hero.tsx +21 -0
- package/registry/examples/iso/orochia-hero.d.ts +4 -0
- package/registry/examples/iso/orochia-hero.js +29 -0
- package/registry/examples/iso/orochia-hero.tsx +23 -0
- package/registry/examples/iso/still.d.ts +4 -0
- package/registry/examples/iso/still.js +21 -0
- package/registry/examples/iso/still.tsx +15 -0
- package/registry/examples/loader/endings.d.ts +4 -0
- package/registry/examples/loader/endings.js +14 -0
- package/registry/examples/loader/endings.tsx +11 -0
- package/registry/examples/loader/fetch-flow.d.ts +4 -0
- package/registry/examples/loader/fetch-flow.js +24 -0
- package/registry/examples/loader/fetch-flow.tsx +24 -0
- package/registry/examples/loader/minimal.d.ts +4 -0
- package/registry/examples/loader/minimal.js +11 -0
- package/registry/examples/loader/minimal.tsx +6 -0
- package/registry/examples/loader/overlay.d.ts +4 -0
- package/registry/examples/loader/overlay.js +16 -0
- package/registry/examples/loader/overlay.tsx +13 -0
- package/registry/examples/loader/region-handover.d.ts +4 -0
- package/registry/examples/loader/region-handover.js +42 -0
- package/registry/examples/loader/region-handover.tsx +29 -0
- package/registry/examples/loader/upload-eta.d.ts +4 -0
- package/registry/examples/loader/upload-eta.js +11 -0
- package/registry/examples/loader/upload-eta.tsx +10 -0
- package/registry/examples/marquee/cards.d.ts +4 -0
- package/registry/examples/marquee/cards.js +23 -0
- package/registry/examples/marquee/cards.tsx +21 -0
- package/registry/examples/marquee/logos.d.ts +4 -0
- package/registry/examples/marquee/logos.js +12 -0
- package/registry/examples/marquee/logos.tsx +17 -0
- package/registry/examples/mascots/empty-state.d.ts +4 -0
- package/registry/examples/mascots/empty-state.js +24 -0
- package/registry/examples/mascots/empty-state.tsx +18 -0
- package/registry/examples/mascots/flock.d.ts +4 -0
- package/registry/examples/mascots/flock.js +14 -0
- package/registry/examples/mascots/flock.tsx +15 -0
- package/registry/examples/mascots/long-task.d.ts +4 -0
- package/registry/examples/mascots/long-task.js +18 -0
- package/registry/examples/mascots/long-task.tsx +15 -0
- package/registry/examples/mascots/moods.d.ts +4 -0
- package/registry/examples/mascots/moods.js +14 -0
- package/registry/examples/mascots/moods.tsx +15 -0
- package/registry/examples/mascots/native/default.d.ts +4 -0
- package/registry/examples/mascots/native/default.dark.png +0 -0
- package/registry/examples/mascots/native/default.js +25 -0
- package/registry/examples/mascots/native/default.light.png +0 -0
- package/registry/examples/mascots/native/default.tsx +22 -0
- package/registry/examples/mascots/own-tone.d.ts +4 -0
- package/registry/examples/mascots/own-tone.js +11 -0
- package/registry/examples/mascots/own-tone.tsx +12 -0
- package/registry/examples/meter/balance.d.ts +4 -0
- package/registry/examples/meter/balance.js +14 -0
- package/registry/examples/meter/balance.tsx +15 -0
- package/registry/examples/meter/quota.d.ts +4 -0
- package/registry/examples/meter/quota.js +15 -0
- package/registry/examples/meter/quota.tsx +12 -0
- package/registry/examples/meter/split.d.ts +4 -0
- package/registry/examples/meter/split.js +18 -0
- package/registry/examples/meter/split.tsx +18 -0
- package/registry/examples/nav-bar/app-bar.d.ts +4 -0
- package/registry/examples/nav-bar/app-bar.js +22 -0
- package/registry/examples/nav-bar/app-bar.tsx +21 -0
- package/registry/examples/nav-bar/menu-open.d.ts +4 -0
- package/registry/examples/nav-bar/menu-open.js +26 -0
- package/registry/examples/nav-bar/menu-open.tsx +26 -0
- package/registry/examples/nav-bar/site.d.ts +4 -0
- package/registry/examples/nav-bar/site.js +31 -0
- package/registry/examples/nav-bar/site.tsx +36 -0
- package/registry/examples/number-ticker/gradient.d.ts +4 -0
- package/registry/examples/number-ticker/gradient.js +11 -0
- package/registry/examples/number-ticker/gradient.tsx +10 -0
- package/registry/examples/number-ticker/live-total.d.ts +4 -0
- package/registry/examples/number-ticker/live-total.js +17 -0
- package/registry/examples/number-ticker/live-total.tsx +21 -0
- package/registry/examples/number-ticker/stats.d.ts +4 -0
- package/registry/examples/number-ticker/stats.js +19 -0
- package/registry/examples/number-ticker/stats.tsx +23 -0
- package/registry/examples/progress/buffer.d.ts +4 -0
- package/registry/examples/progress/buffer.js +11 -0
- package/registry/examples/progress/buffer.tsx +10 -0
- package/registry/examples/progress/statuses.d.ts +4 -0
- package/registry/examples/progress/statuses.js +14 -0
- package/registry/examples/progress/statuses.tsx +11 -0
- package/registry/examples/progress/steps.d.ts +4 -0
- package/registry/examples/progress/steps.js +14 -0
- package/registry/examples/progress/steps.tsx +13 -0
- package/registry/examples/progress/upload.d.ts +4 -0
- package/registry/examples/progress/upload.js +11 -0
- package/registry/examples/progress/upload.tsx +10 -0
- package/registry/examples/skeleton/paragraph.d.ts +4 -0
- package/registry/examples/skeleton/paragraph.js +14 -0
- package/registry/examples/skeleton/paragraph.tsx +12 -0
- package/registry/examples/skeleton/shape-of-content.d.ts +4 -0
- package/registry/examples/skeleton/shape-of-content.js +23 -0
- package/registry/examples/skeleton/shape-of-content.tsx +26 -0
- package/registry/examples/spinner/default.js +5 -2
- package/registry/examples/spinner/default.tsx +7 -1
- package/registry/examples/spinner/sizes.js +2 -1
- package/registry/examples/spinner/sizes.tsx +2 -0
- package/registry/examples/spinner/value.d.ts +4 -0
- package/registry/examples/spinner/value.js +11 -0
- package/registry/examples/spinner/value.tsx +12 -0
- package/registry/examples/stepper/checkout.d.ts +4 -0
- package/registry/examples/stepper/checkout.js +22 -0
- package/registry/examples/stepper/checkout.tsx +17 -0
- package/registry/examples/stepper/failed.d.ts +4 -0
- package/registry/examples/stepper/failed.js +26 -0
- package/registry/examples/stepper/failed.tsx +21 -0
- package/registry/examples/stepper/job.d.ts +4 -0
- package/registry/examples/stepper/job.js +32 -0
- package/registry/examples/stepper/job.tsx +28 -0
- package/registry/examples/toast/grouped.d.ts +4 -0
- package/registry/examples/toast/grouped.js +21 -0
- package/registry/examples/toast/grouped.tsx +23 -0
- package/registry/examples/toast/undo.d.ts +4 -0
- package/registry/examples/toast/undo.js +29 -0
- package/registry/examples/toast/undo.tsx +30 -0
- package/registry/examples/toast/upload-progress.d.ts +4 -0
- package/registry/examples/toast/upload-progress.js +29 -0
- package/registry/examples/toast/upload-progress.tsx +31 -0
- package/registry/field.json +1 -1
- package/registry/glow-card.json +162 -0
- package/registry/index.json +207 -20
- package/registry/iso.json +1355 -0
- package/registry/kbd.json +1 -1
- package/registry/loader.json +399 -0
- package/registry/marquee.json +225 -0
- package/registry/mascots.json +314 -0
- package/registry/meter.json +324 -0
- package/registry/nav-bar.json +480 -0
- package/registry/number-ticker.json +219 -0
- package/registry/page-header.json +1 -1
- package/registry/popover.json +1 -1
- package/registry/progress.json +116 -11
- package/registry/radio-group.json +1 -1
- package/registry/section-backdrop.json +1 -1
- package/registry/separator.json +1 -1
- package/registry/skeleton.json +69 -13
- package/registry/slider.json +1 -1
- package/registry/slot.json +1 -1
- package/registry/spinner.json +91 -27
- package/registry/stat.json +1 -1
- package/registry/stepper.json +174 -0
- package/registry/switch.json +1 -1
- package/registry/tabs.json +11 -7
- package/registry/theme.json +3 -3
- package/registry/toast.json +41 -13
- package/registry/tooltip.json +1 -1
- package/dist/chunk-FHYZSO2S.js.map +0 -1
- package/dist/chunk-PESA2R4U.js +0 -51
- package/dist/chunk-PESA2R4U.js.map +0 -1
- package/registry/examples/spinner/muted.js +0 -11
- package/registry/examples/spinner/muted.tsx +0 -6
- /package/registry/examples/{spinner/muted.d.ts → button/error.d.ts} +0 -0
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as tailwind_variants from 'tailwind-variants';
|
|
2
|
+
import { VariantProps } from 'tailwind-variants';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
declare const loader: tailwind_variants.TVReturnType<{
|
|
6
|
+
variant: {
|
|
7
|
+
inline: {
|
|
8
|
+
box: string;
|
|
9
|
+
glyph: string;
|
|
10
|
+
};
|
|
11
|
+
block: {
|
|
12
|
+
box: string;
|
|
13
|
+
glyph: string;
|
|
14
|
+
text: string;
|
|
15
|
+
};
|
|
16
|
+
overlay: {
|
|
17
|
+
root: string;
|
|
18
|
+
box: string;
|
|
19
|
+
glyph: string;
|
|
20
|
+
text: string;
|
|
21
|
+
};
|
|
22
|
+
page: {
|
|
23
|
+
root: string;
|
|
24
|
+
box: string;
|
|
25
|
+
glyph: string;
|
|
26
|
+
text: string;
|
|
27
|
+
label: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
ended: {
|
|
31
|
+
success: {
|
|
32
|
+
glyph: string;
|
|
33
|
+
};
|
|
34
|
+
error: {
|
|
35
|
+
glyph: string;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
}, {
|
|
39
|
+
root: string;
|
|
40
|
+
box: string;
|
|
41
|
+
glyph: string;
|
|
42
|
+
text: string;
|
|
43
|
+
label: string;
|
|
44
|
+
detail: string;
|
|
45
|
+
}, undefined, {
|
|
46
|
+
variant: {
|
|
47
|
+
inline: {
|
|
48
|
+
box: string;
|
|
49
|
+
glyph: string;
|
|
50
|
+
};
|
|
51
|
+
block: {
|
|
52
|
+
box: string;
|
|
53
|
+
glyph: string;
|
|
54
|
+
text: string;
|
|
55
|
+
};
|
|
56
|
+
overlay: {
|
|
57
|
+
root: string;
|
|
58
|
+
box: string;
|
|
59
|
+
glyph: string;
|
|
60
|
+
text: string;
|
|
61
|
+
};
|
|
62
|
+
page: {
|
|
63
|
+
root: string;
|
|
64
|
+
box: string;
|
|
65
|
+
glyph: string;
|
|
66
|
+
text: string;
|
|
67
|
+
label: string;
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
ended: {
|
|
71
|
+
success: {
|
|
72
|
+
glyph: string;
|
|
73
|
+
};
|
|
74
|
+
error: {
|
|
75
|
+
glyph: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
}, {
|
|
79
|
+
root: string;
|
|
80
|
+
box: string;
|
|
81
|
+
glyph: string;
|
|
82
|
+
text: string;
|
|
83
|
+
label: string;
|
|
84
|
+
detail: string;
|
|
85
|
+
}, tailwind_variants.TVReturnTypeLike<{
|
|
86
|
+
variant: {
|
|
87
|
+
inline: {
|
|
88
|
+
box: string;
|
|
89
|
+
glyph: string;
|
|
90
|
+
};
|
|
91
|
+
block: {
|
|
92
|
+
box: string;
|
|
93
|
+
glyph: string;
|
|
94
|
+
text: string;
|
|
95
|
+
};
|
|
96
|
+
overlay: {
|
|
97
|
+
root: string;
|
|
98
|
+
box: string;
|
|
99
|
+
glyph: string;
|
|
100
|
+
text: string;
|
|
101
|
+
};
|
|
102
|
+
page: {
|
|
103
|
+
root: string;
|
|
104
|
+
box: string;
|
|
105
|
+
glyph: string;
|
|
106
|
+
text: string;
|
|
107
|
+
label: string;
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
ended: {
|
|
111
|
+
success: {
|
|
112
|
+
glyph: string;
|
|
113
|
+
};
|
|
114
|
+
error: {
|
|
115
|
+
glyph: string;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
}, {
|
|
119
|
+
root: string;
|
|
120
|
+
box: string;
|
|
121
|
+
glyph: string;
|
|
122
|
+
text: string;
|
|
123
|
+
label: string;
|
|
124
|
+
detail: string;
|
|
125
|
+
}>>;
|
|
126
|
+
type LoaderVariants = VariantProps<typeof loader>;
|
|
127
|
+
/**
|
|
128
|
+
* `true` once `active` has lasted `delay` ms; then stays `true` at least `minDuration` ms — a wait that ends early never
|
|
129
|
+
* shows, one that shows never blinks.
|
|
130
|
+
*/
|
|
131
|
+
declare function useDelayedWait(active: boolean, delay?: number, minDuration?: number): boolean;
|
|
132
|
+
interface LoaderProps extends Omit<React.ComponentProps<"div">, "children"> {
|
|
133
|
+
/** What is loading, in words (“Loading your invoices”) — passed translated; shown and announced. */
|
|
134
|
+
label: string;
|
|
135
|
+
/**
|
|
136
|
+
* loading · success · error. When the wait ends, the loader shows how it ended for `endDuration` ms, then disappears.
|
|
137
|
+
* @default "loading"
|
|
138
|
+
*/
|
|
139
|
+
status?: "loading" | "success" | "error";
|
|
140
|
+
/** The words of a success (“Invoices loaded”) — passed translated. Default: nothing more than the check. */
|
|
141
|
+
successLabel?: string;
|
|
142
|
+
/** The words of a failure (“Could not load the invoices”) — passed translated. */
|
|
143
|
+
errorLabel?: string;
|
|
144
|
+
/** Between 0 and 1: a determinate wait — the trace grows to it and the percentage shows. */
|
|
145
|
+
value?: number | null;
|
|
146
|
+
/** The time left, in words (“About 20 s left”) — passed translated (`@krizaka/intl` formats durations). */
|
|
147
|
+
eta?: string;
|
|
148
|
+
/**
|
|
149
|
+
* Milliseconds before anything shows: a wait shorter than this never flashes.
|
|
150
|
+
* @default 250
|
|
151
|
+
*/
|
|
152
|
+
delay?: number;
|
|
153
|
+
/**
|
|
154
|
+
* Once shown, the least milliseconds it stays: it never blinks.
|
|
155
|
+
* @default 600
|
|
156
|
+
*/
|
|
157
|
+
minDuration?: number;
|
|
158
|
+
/**
|
|
159
|
+
* Milliseconds the ending (check or cross) stays before the loader disappears; `0` never shows it, `Infinity` keeps it.
|
|
160
|
+
* @default 1600
|
|
161
|
+
*/
|
|
162
|
+
endDuration?: number;
|
|
163
|
+
/**
|
|
164
|
+
* inline (beside the content) · block (a region's centre) · overlay (over a `relative` parent, frosted) · page (the
|
|
165
|
+
* whole screen).
|
|
166
|
+
* @default "inline"
|
|
167
|
+
*/
|
|
168
|
+
variant?: LoaderVariants["variant"];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* A wait, from start to end. `role="status"` (polite): its words are announced when it shows and when it ends. Under
|
|
172
|
+
* prefers-reduced-motion the glyph rests on a still frame; the delay and the ending stay.
|
|
173
|
+
*/
|
|
174
|
+
declare function Loader({ label, status, successLabel, errorLabel, value, eta, delay, minDuration, endDuration, variant, className, ...props }: LoaderProps): React.JSX.Element;
|
|
175
|
+
interface LoadingRegionProps extends React.ComponentProps<"div"> {
|
|
176
|
+
/** Whether the content is on its way. */
|
|
177
|
+
loading: boolean;
|
|
178
|
+
/** What stands in while it loads: skeletons the shape of the content (no layout shift when it arrives). */
|
|
179
|
+
skeleton: React.ReactNode;
|
|
180
|
+
/** What is loading, in words — passed translated; announced when the wait shows. */
|
|
181
|
+
label: string;
|
|
182
|
+
/** The words when the wait grows long (“Still loading — the server is busy”) — passed translated. */
|
|
183
|
+
slowLabel?: string;
|
|
184
|
+
/**
|
|
185
|
+
* Milliseconds of skeleton before the words of a long wait appear over it.
|
|
186
|
+
* @default 4000
|
|
187
|
+
*/
|
|
188
|
+
slowAfter?: number;
|
|
189
|
+
/**
|
|
190
|
+
* Milliseconds before the skeleton shows: a fast answer goes straight to the content.
|
|
191
|
+
* @default 200
|
|
192
|
+
*/
|
|
193
|
+
delay?: number;
|
|
194
|
+
/**
|
|
195
|
+
* Once shown, the least milliseconds the skeleton stays.
|
|
196
|
+
* @default 500
|
|
197
|
+
*/
|
|
198
|
+
minDuration?: number;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* A region that hands over: its content → (after `delay`) a skeleton of the same shape → (after `slowAfter`) words over
|
|
202
|
+
* the skeleton → its content again, fading in. `aria-busy` while it waits; the wait is announced once.
|
|
203
|
+
*/
|
|
204
|
+
declare function LoadingRegion({ loading, skeleton, label, slowLabel, slowAfter, delay, minDuration, className, children, ...props }: LoadingRegionProps): React.JSX.Element;
|
|
205
|
+
|
|
206
|
+
export { Loader, type LoaderProps, type LoaderVariants, LoadingRegion, type LoadingRegionProps, loader, useDelayedWait };
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
LoaderGlyph
|
|
4
|
+
} from "./chunk-WEVYKZIF.js";
|
|
5
|
+
|
|
6
|
+
// src/loader/loader.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { tv } from "tailwind-variants";
|
|
9
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
var loader = tv({
|
|
11
|
+
slots: {
|
|
12
|
+
root: "text-fg-secondary",
|
|
13
|
+
box: "kz-fade flex items-center gap-3",
|
|
14
|
+
glyph: "shrink-0 text-accent",
|
|
15
|
+
text: "flex min-w-0 flex-col",
|
|
16
|
+
label: "font-medium text-fg",
|
|
17
|
+
detail: "text-xs text-fg-secondary tabular-nums"
|
|
18
|
+
},
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
inline: { box: "text-sm", glyph: "h-5 w-5" },
|
|
22
|
+
block: { box: "flex-col justify-center py-10 text-center text-sm", glyph: "h-9 w-9", text: "items-center" },
|
|
23
|
+
overlay: {
|
|
24
|
+
root: "absolute inset-0 z-10 flex items-center justify-center rounded-[inherit] empty:hidden",
|
|
25
|
+
box: "flex-col rounded-xl border border-border-default bg-surface-1/90 px-6 py-5 text-center text-sm shadow-lg backdrop-blur-sm",
|
|
26
|
+
glyph: "h-9 w-9",
|
|
27
|
+
text: "items-center"
|
|
28
|
+
},
|
|
29
|
+
page: {
|
|
30
|
+
root: "fixed inset-0 z-50 flex items-center justify-center bg-surface-0/80 backdrop-blur-sm empty:hidden",
|
|
31
|
+
box: "flex-col text-center",
|
|
32
|
+
glyph: "h-14 w-14",
|
|
33
|
+
text: "items-center",
|
|
34
|
+
label: "font-display text-lg"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
ended: {
|
|
38
|
+
success: { glyph: "text-fg-success" },
|
|
39
|
+
error: { glyph: "text-fg-danger" }
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
defaultVariants: { variant: "inline" }
|
|
43
|
+
});
|
|
44
|
+
function useDelayedWait(active, delay = 250, minDuration = 600) {
|
|
45
|
+
const [shown, setShown] = React.useState(false);
|
|
46
|
+
const since = React.useRef(0);
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
if (active === shown) return;
|
|
49
|
+
const wait = active ? delay : Math.max(0, minDuration - (Date.now() - since.current));
|
|
50
|
+
const timer = setTimeout(() => {
|
|
51
|
+
since.current = Date.now();
|
|
52
|
+
setShown(active);
|
|
53
|
+
}, wait);
|
|
54
|
+
return () => clearTimeout(timer);
|
|
55
|
+
}, [active, shown, delay, minDuration]);
|
|
56
|
+
return shown;
|
|
57
|
+
}
|
|
58
|
+
function Loader({
|
|
59
|
+
label,
|
|
60
|
+
status = "loading",
|
|
61
|
+
successLabel,
|
|
62
|
+
errorLabel,
|
|
63
|
+
value,
|
|
64
|
+
eta,
|
|
65
|
+
delay = 250,
|
|
66
|
+
minDuration = 600,
|
|
67
|
+
endDuration = 1600,
|
|
68
|
+
variant,
|
|
69
|
+
className,
|
|
70
|
+
...props
|
|
71
|
+
}) {
|
|
72
|
+
const waiting = useDelayedWait(status === "loading", delay, minDuration);
|
|
73
|
+
const [ending, setEnding] = React.useState(() => status !== "loading" && endDuration > 0 ? status : null);
|
|
74
|
+
const wasWaiting = React.useRef(false);
|
|
75
|
+
React.useEffect(() => {
|
|
76
|
+
if (!Number.isFinite(endDuration)) return;
|
|
77
|
+
const hide = setTimeout(() => setEnding((e) => wasWaiting.current ? e : null), endDuration);
|
|
78
|
+
return () => clearTimeout(hide);
|
|
79
|
+
}, []);
|
|
80
|
+
React.useEffect(() => {
|
|
81
|
+
if (waiting) {
|
|
82
|
+
wasWaiting.current = true;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (!wasWaiting.current || status === "loading") return;
|
|
86
|
+
wasWaiting.current = false;
|
|
87
|
+
const end = status;
|
|
88
|
+
const show = setTimeout(() => setEnding(endDuration > 0 ? end : null), 0);
|
|
89
|
+
const hide = Number.isFinite(endDuration) ? setTimeout(() => setEnding(null), endDuration) : void 0;
|
|
90
|
+
return () => {
|
|
91
|
+
clearTimeout(show);
|
|
92
|
+
clearTimeout(hide);
|
|
93
|
+
};
|
|
94
|
+
}, [waiting, status, endDuration]);
|
|
95
|
+
const phase = waiting ? "loading" : ending;
|
|
96
|
+
const s = loader({ variant, ended: phase === "success" || phase === "error" ? phase : void 0 });
|
|
97
|
+
const known = phase === "loading" && typeof value === "number" && Number.isFinite(value);
|
|
98
|
+
const words = phase === "success" ? successLabel ?? label : phase === "error" ? errorLabel ?? label : label;
|
|
99
|
+
const detail = phase === "loading" ? [known ? `${Math.round(Math.min(1, Math.max(0, value)) * 100)} %` : null, eta].filter(Boolean).join(" \xB7 ") : "";
|
|
100
|
+
return /* @__PURE__ */ jsx("div", { role: "status", "aria-live": "polite", "data-phase": phase ?? "idle", className: s.root({ className }), ...props, children: phase && /* @__PURE__ */ jsxs("div", { className: s.box(), children: [
|
|
101
|
+
/* @__PURE__ */ jsx(LoaderGlyph, { state: phase, value: known ? value : null, className: s.glyph() }),
|
|
102
|
+
/* @__PURE__ */ jsxs("span", { className: s.text(), children: [
|
|
103
|
+
/* @__PURE__ */ jsx("span", { className: s.label(), children: words }),
|
|
104
|
+
detail && /* @__PURE__ */ jsx("span", { className: s.detail(), children: detail })
|
|
105
|
+
] })
|
|
106
|
+
] }) });
|
|
107
|
+
}
|
|
108
|
+
function LoadingRegion({
|
|
109
|
+
loading,
|
|
110
|
+
skeleton,
|
|
111
|
+
label,
|
|
112
|
+
slowLabel,
|
|
113
|
+
slowAfter = 4e3,
|
|
114
|
+
delay = 200,
|
|
115
|
+
minDuration = 500,
|
|
116
|
+
className,
|
|
117
|
+
children,
|
|
118
|
+
...props
|
|
119
|
+
}) {
|
|
120
|
+
const waiting = useDelayedWait(loading, delay, minDuration);
|
|
121
|
+
const slow = useDelayedWait(waiting && loading, slowAfter, 0);
|
|
122
|
+
const busy = loading || waiting;
|
|
123
|
+
return /* @__PURE__ */ jsxs("div", { "aria-busy": busy, "data-phase": waiting ? slow ? "slow" : "skeleton" : busy ? "pending" : "ready", className: ["relative", className].filter(Boolean).join(" "), ...props, children: [
|
|
124
|
+
/* @__PURE__ */ jsx("span", { role: "status", className: "sr-only", children: waiting ? slow ? slowLabel ?? label : label : "" }),
|
|
125
|
+
waiting ? /* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "kz-fade", children: skeleton }) : busy ? (
|
|
126
|
+
// Within the delay: the skeleton holds the place, invisible — nothing flashes, nothing jumps.
|
|
127
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, className: "invisible", children: skeleton })
|
|
128
|
+
) : /* @__PURE__ */ jsx("div", { className: "kz-fade", children }),
|
|
129
|
+
waiting && slow && /* @__PURE__ */ jsx(Loader, { label: slowLabel ?? label, variant: "overlay", delay: 0, minDuration: 0, endDuration: 0, "aria-live": "off", role: "presentation" })
|
|
130
|
+
] });
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
Loader,
|
|
134
|
+
LoadingRegion,
|
|
135
|
+
loader,
|
|
136
|
+
useDelayedWait
|
|
137
|
+
};
|
|
138
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/loader/loader.tsx"],"sourcesContent":["// Client (timers). The whole life of a wait, done right once: nothing for the first instants (a fast answer never\n// flashes a spinner), then the Krizaka glyph with its words and an ETA, held long enough to be read, ending on a\n// check or a cross that is drawn and announced. `LoadingRegion` hands a region over from its content to a skeleton of\n// the same shape, then to words when the wait grows long, then back to the content.\nimport * as React from \"react\";\nimport { tv, type VariantProps } from \"tailwind-variants\";\n\nimport { LoaderGlyph } from \"../spinner/glyph\";\n\nexport const loader = tv({\n slots: {\n root: \"text-fg-secondary\",\n box: \"kz-fade flex items-center gap-3\",\n glyph: \"shrink-0 text-accent\",\n text: \"flex min-w-0 flex-col\",\n label: \"font-medium text-fg\",\n detail: \"text-xs text-fg-secondary tabular-nums\",\n },\n variants: {\n variant: {\n inline: { box: \"text-sm\", glyph: \"h-5 w-5\" },\n block: { box: \"flex-col justify-center py-10 text-center text-sm\", glyph: \"h-9 w-9\", text: \"items-center\" },\n overlay: {\n root: \"absolute inset-0 z-10 flex items-center justify-center rounded-[inherit] empty:hidden\",\n box: \"flex-col rounded-xl border border-border-default bg-surface-1/90 px-6 py-5 text-center text-sm shadow-lg backdrop-blur-sm\",\n glyph: \"h-9 w-9\",\n text: \"items-center\",\n },\n page: {\n root: \"fixed inset-0 z-50 flex items-center justify-center bg-surface-0/80 backdrop-blur-sm empty:hidden\",\n box: \"flex-col text-center\",\n glyph: \"h-14 w-14\",\n text: \"items-center\",\n label: \"font-display text-lg\",\n },\n },\n ended: {\n success: { glyph: \"text-fg-success\" },\n error: { glyph: \"text-fg-danger\" },\n },\n },\n defaultVariants: { variant: \"inline\" },\n});\n\nexport type LoaderVariants = VariantProps<typeof loader>;\n\n/**\n * `true` once `active` has lasted `delay` ms; then stays `true` at least `minDuration` ms — a wait that ends early never\n * shows, one that shows never blinks.\n */\nexport function useDelayedWait(active: boolean, delay = 250, minDuration = 600): boolean {\n const [shown, setShown] = React.useState(false);\n const since = React.useRef(0);\n React.useEffect(() => {\n if (active === shown) return;\n const wait = active ? delay : Math.max(0, minDuration - (Date.now() - since.current));\n const timer = setTimeout(() => {\n since.current = Date.now();\n setShown(active);\n }, wait);\n return () => clearTimeout(timer);\n }, [active, shown, delay, minDuration]);\n return shown;\n}\n\nexport interface LoaderProps extends Omit<React.ComponentProps<\"div\">, \"children\"> {\n /** What is loading, in words (“Loading your invoices”) — passed translated; shown and announced. */\n label: string;\n /**\n * loading · success · error. When the wait ends, the loader shows how it ended for `endDuration` ms, then disappears.\n * @default \"loading\"\n */\n status?: \"loading\" | \"success\" | \"error\";\n /** The words of a success (“Invoices loaded”) — passed translated. Default: nothing more than the check. */\n successLabel?: string;\n /** The words of a failure (“Could not load the invoices”) — passed translated. */\n errorLabel?: string;\n /** Between 0 and 1: a determinate wait — the trace grows to it and the percentage shows. */\n value?: number | null;\n /** The time left, in words (“About 20 s left”) — passed translated (`@krizaka/intl` formats durations). */\n eta?: string;\n /**\n * Milliseconds before anything shows: a wait shorter than this never flashes.\n * @default 250\n */\n delay?: number;\n /**\n * Once shown, the least milliseconds it stays: it never blinks.\n * @default 600\n */\n minDuration?: number;\n /**\n * Milliseconds the ending (check or cross) stays before the loader disappears; `0` never shows it, `Infinity` keeps it.\n * @default 1600\n */\n endDuration?: number;\n /**\n * inline (beside the content) · block (a region's centre) · overlay (over a `relative` parent, frosted) · page (the\n * whole screen).\n * @default \"inline\"\n */\n variant?: LoaderVariants[\"variant\"];\n}\n\n/**\n * A wait, from start to end. `role=\"status\"` (polite): its words are announced when it shows and when it ends. Under\n * prefers-reduced-motion the glyph rests on a still frame; the delay and the ending stay.\n */\nexport function Loader({\n label,\n status = \"loading\",\n successLabel,\n errorLabel,\n value,\n eta,\n delay = 250,\n minDuration = 600,\n endDuration = 1600,\n variant,\n className,\n ...props\n}: LoaderProps) {\n const waiting = useDelayedWait(status === \"loading\", delay, minDuration);\n // Rendered already ended (a result to show), it shows its ending; otherwise only a wait that was seen ends visibly.\n const [ending, setEnding] = React.useState<\"success\" | \"error\" | null>(() => (status !== \"loading\" && endDuration > 0 ? status : null));\n const wasWaiting = React.useRef(false);\n React.useEffect(() => {\n if (!Number.isFinite(endDuration)) return;\n const hide = setTimeout(() => setEnding((e) => (wasWaiting.current ? e : null)), endDuration);\n return () => clearTimeout(hide);\n // Only the ending a loader was mounted with: later endings have their own timer below.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n React.useEffect(() => {\n if (waiting) {\n wasWaiting.current = true;\n return;\n }\n if (!wasWaiting.current || status === \"loading\") return;\n wasWaiting.current = false;\n const end = status;\n const show = setTimeout(() => setEnding(endDuration > 0 ? end : null), 0);\n const hide = Number.isFinite(endDuration) ? setTimeout(() => setEnding(null), endDuration) : undefined;\n return () => {\n clearTimeout(show);\n clearTimeout(hide);\n };\n }, [waiting, status, endDuration]);\n\n const phase = waiting ? \"loading\" : ending;\n const s = loader({ variant, ended: phase === \"success\" || phase === \"error\" ? phase : undefined });\n const known = phase === \"loading\" && typeof value === \"number\" && Number.isFinite(value);\n const words = phase === \"success\" ? (successLabel ?? label) : phase === \"error\" ? (errorLabel ?? label) : label;\n const detail = phase === \"loading\" ? [known ? `${Math.round(Math.min(1, Math.max(0, value)) * 100)} %` : null, eta].filter(Boolean).join(\" · \") : \"\";\n return (\n <div role=\"status\" aria-live=\"polite\" data-phase={phase ?? \"idle\"} className={s.root({ className })} {...props}>\n {phase && (\n <div className={s.box()}>\n <LoaderGlyph state={phase} value={known ? value : null} className={s.glyph()} />\n <span className={s.text()}>\n <span className={s.label()}>{words}</span>\n {detail && <span className={s.detail()}>{detail}</span>}\n </span>\n </div>\n )}\n </div>\n );\n}\n\nexport interface LoadingRegionProps extends React.ComponentProps<\"div\"> {\n /** Whether the content is on its way. */\n loading: boolean;\n /** What stands in while it loads: skeletons the shape of the content (no layout shift when it arrives). */\n skeleton: React.ReactNode;\n /** What is loading, in words — passed translated; announced when the wait shows. */\n label: string;\n /** The words when the wait grows long (“Still loading — the server is busy”) — passed translated. */\n slowLabel?: string;\n /**\n * Milliseconds of skeleton before the words of a long wait appear over it.\n * @default 4000\n */\n slowAfter?: number;\n /**\n * Milliseconds before the skeleton shows: a fast answer goes straight to the content.\n * @default 200\n */\n delay?: number;\n /**\n * Once shown, the least milliseconds the skeleton stays.\n * @default 500\n */\n minDuration?: number;\n}\n\n/**\n * A region that hands over: its content → (after `delay`) a skeleton of the same shape → (after `slowAfter`) words over\n * the skeleton → its content again, fading in. `aria-busy` while it waits; the wait is announced once.\n */\nexport function LoadingRegion({\n loading,\n skeleton,\n label,\n slowLabel,\n slowAfter = 4000,\n delay = 200,\n minDuration = 500,\n className,\n children,\n ...props\n}: LoadingRegionProps) {\n const waiting = useDelayedWait(loading, delay, minDuration);\n const slow = useDelayedWait(waiting && loading, slowAfter, 0);\n const busy = loading || waiting;\n return (\n <div aria-busy={busy} data-phase={waiting ? (slow ? \"slow\" : \"skeleton\") : busy ? \"pending\" : \"ready\"} className={[\"relative\", className].filter(Boolean).join(\" \")} {...props}>\n <span role=\"status\" className=\"sr-only\">\n {waiting ? (slow ? (slowLabel ?? label) : label) : \"\"}\n </span>\n {waiting ? (\n <div aria-hidden className=\"kz-fade\">\n {skeleton}\n </div>\n ) : busy ? (\n // Within the delay: the skeleton holds the place, invisible — nothing flashes, nothing jumps.\n <div aria-hidden className=\"invisible\">\n {skeleton}\n </div>\n ) : (\n <div className=\"kz-fade\">{children}</div>\n )}\n {waiting && slow && <Loader label={slowLabel ?? label} variant=\"overlay\" delay={0} minDuration={0} endDuration={0} aria-live=\"off\" role=\"presentation\" />}\n </div>\n );\n}\n"],"mappings":";;;;;;AAIA,YAAY,WAAW;AACvB,SAAS,UAA6B;AAyJ5B,cACA,YADA;AArJH,IAAM,SAAS,GAAG;AAAA,EACvB,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,MACP,QAAQ,EAAE,KAAK,WAAW,OAAO,UAAU;AAAA,MAC3C,OAAO,EAAE,KAAK,qDAAqD,OAAO,WAAW,MAAM,eAAe;AAAA,MAC1G,SAAS;AAAA,QACP,MAAM;AAAA,QACN,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,SAAS,EAAE,OAAO,kBAAkB;AAAA,MACpC,OAAO,EAAE,OAAO,iBAAiB;AAAA,IACnC;AAAA,EACF;AAAA,EACA,iBAAiB,EAAE,SAAS,SAAS;AACvC,CAAC;AAQM,SAAS,eAAe,QAAiB,QAAQ,KAAK,cAAc,KAAc;AACvF,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAS,KAAK;AAC9C,QAAM,QAAc,aAAO,CAAC;AAC5B,EAAM,gBAAU,MAAM;AACpB,QAAI,WAAW,MAAO;AACtB,UAAM,OAAO,SAAS,QAAQ,KAAK,IAAI,GAAG,eAAe,KAAK,IAAI,IAAI,MAAM,QAAQ;AACpF,UAAM,QAAQ,WAAW,MAAM;AAC7B,YAAM,UAAU,KAAK,IAAI;AACzB,eAAS,MAAM;AAAA,IACjB,GAAG,IAAI;AACP,WAAO,MAAM,aAAa,KAAK;AAAA,EACjC,GAAG,CAAC,QAAQ,OAAO,OAAO,WAAW,CAAC;AACtC,SAAO;AACT;AA6CO,SAAS,OAAO;AAAA,EACrB;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAgB;AACd,QAAM,UAAU,eAAe,WAAW,WAAW,OAAO,WAAW;AAEvE,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAqC,MAAO,WAAW,aAAa,cAAc,IAAI,SAAS,IAAK;AACtI,QAAM,aAAmB,aAAO,KAAK;AACrC,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,OAAO,SAAS,WAAW,EAAG;AACnC,UAAM,OAAO,WAAW,MAAM,UAAU,CAAC,MAAO,WAAW,UAAU,IAAI,IAAK,GAAG,WAAW;AAC5F,WAAO,MAAM,aAAa,IAAI;AAAA,EAGhC,GAAG,CAAC,CAAC;AACL,EAAM,gBAAU,MAAM;AACpB,QAAI,SAAS;AACX,iBAAW,UAAU;AACrB;AAAA,IACF;AACA,QAAI,CAAC,WAAW,WAAW,WAAW,UAAW;AACjD,eAAW,UAAU;AACrB,UAAM,MAAM;AACZ,UAAM,OAAO,WAAW,MAAM,UAAU,cAAc,IAAI,MAAM,IAAI,GAAG,CAAC;AACxE,UAAM,OAAO,OAAO,SAAS,WAAW,IAAI,WAAW,MAAM,UAAU,IAAI,GAAG,WAAW,IAAI;AAC7F,WAAO,MAAM;AACX,mBAAa,IAAI;AACjB,mBAAa,IAAI;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,WAAW,CAAC;AAEjC,QAAM,QAAQ,UAAU,YAAY;AACpC,QAAM,IAAI,OAAO,EAAE,SAAS,OAAO,UAAU,aAAa,UAAU,UAAU,QAAQ,OAAU,CAAC;AACjG,QAAM,QAAQ,UAAU,aAAa,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK;AACvF,QAAM,QAAQ,UAAU,YAAa,gBAAgB,QAAS,UAAU,UAAW,cAAc,QAAS;AAC1G,QAAM,SAAS,UAAU,YAAY,CAAC,QAAQ,GAAG,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,KAAK,QAAK,IAAI;AAClJ,SACE,oBAAC,SAAI,MAAK,UAAS,aAAU,UAAS,cAAY,SAAS,QAAQ,WAAW,EAAE,KAAK,EAAE,UAAU,CAAC,GAAI,GAAG,OACtG,mBACC,qBAAC,SAAI,WAAW,EAAE,IAAI,GACpB;AAAA,wBAAC,eAAY,OAAO,OAAO,OAAO,QAAQ,QAAQ,MAAM,WAAW,EAAE,MAAM,GAAG;AAAA,IAC9E,qBAAC,UAAK,WAAW,EAAE,KAAK,GACtB;AAAA,0BAAC,UAAK,WAAW,EAAE,MAAM,GAAI,iBAAM;AAAA,MAClC,UAAU,oBAAC,UAAK,WAAW,EAAE,OAAO,GAAI,kBAAO;AAAA,OAClD;AAAA,KACF,GAEJ;AAEJ;AAgCO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAuB;AACrB,QAAM,UAAU,eAAe,SAAS,OAAO,WAAW;AAC1D,QAAM,OAAO,eAAe,WAAW,SAAS,WAAW,CAAC;AAC5D,QAAM,OAAO,WAAW;AACxB,SACE,qBAAC,SAAI,aAAW,MAAM,cAAY,UAAW,OAAO,SAAS,aAAc,OAAO,YAAY,SAAS,WAAW,CAAC,YAAY,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAAI,GAAG,OACvK;AAAA,wBAAC,UAAK,MAAK,UAAS,WAAU,WAC3B,oBAAW,OAAQ,aAAa,QAAS,QAAS,IACrD;AAAA,IACC,UACC,oBAAC,SAAI,eAAW,MAAC,WAAU,WACxB,oBACH,IACE;AAAA;AAAA,MAEF,oBAAC,SAAI,eAAW,MAAC,WAAU,aACxB,oBACH;AAAA,QAEA,oBAAC,SAAI,WAAU,WAAW,UAAS;AAAA,IAEpC,WAAW,QAAQ,oBAAC,UAAO,OAAO,aAAa,OAAO,SAAQ,WAAU,OAAO,GAAG,aAAa,GAAG,aAAa,GAAG,aAAU,OAAM,MAAK,gBAAe;AAAA,KACzJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type MarqueeProps = Omit<React.ComponentProps<"section">, "children"> & {
|
|
4
|
+
/** The accessible name of the band (“Our partners”) — passed translated. */
|
|
5
|
+
label: string;
|
|
6
|
+
/** The pause button's name (“Pause the band”) — passed translated. */
|
|
7
|
+
pauseLabel: string;
|
|
8
|
+
/** The same button's name once paused (“Play the band”) — passed translated. */
|
|
9
|
+
playLabel: string;
|
|
10
|
+
/** The items: logos, words, cards. */
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
/**
|
|
13
|
+
* Pixels per second.
|
|
14
|
+
* @default 40
|
|
15
|
+
*/
|
|
16
|
+
speed?: number;
|
|
17
|
+
/**
|
|
18
|
+
* Which way it slides.
|
|
19
|
+
* @default "left"
|
|
20
|
+
*/
|
|
21
|
+
direction?: "left" | "right";
|
|
22
|
+
/**
|
|
23
|
+
* The edges fade into the page.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
fade?: boolean;
|
|
27
|
+
/** Starts paused. */
|
|
28
|
+
defaultPaused?: boolean;
|
|
29
|
+
};
|
|
30
|
+
/** A band of items sliding forever — pausable, accessible, still under reduced motion. */
|
|
31
|
+
declare function Marquee({ label, pauseLabel, playLabel, children, speed, direction, fade, defaultPaused, className, ...props }: MarqueeProps): React.JSX.Element;
|
|
32
|
+
|
|
33
|
+
export { Marquee, type MarqueeProps };
|
package/dist/marquee.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-5AXLA4LK.js";
|
|
5
|
+
|
|
6
|
+
// src/marquee/marquee.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
function Marquee({ label, pauseLabel, playLabel, children, speed = 40, direction = "left", fade = true, defaultPaused = false, className, ...props }) {
|
|
10
|
+
const [paused, setPaused] = React.useState(defaultPaused);
|
|
11
|
+
const track = React.useRef(null);
|
|
12
|
+
React.useEffect(() => {
|
|
13
|
+
const el = track.current;
|
|
14
|
+
if (!el) return;
|
|
15
|
+
const measure = () => el.style.setProperty("--kz-marquee-duration", `${Math.max(4, el.scrollWidth / 2 / Math.max(1, speed))}s`);
|
|
16
|
+
measure();
|
|
17
|
+
const ro = new ResizeObserver(measure);
|
|
18
|
+
ro.observe(el);
|
|
19
|
+
return () => ro.disconnect();
|
|
20
|
+
}, [speed]);
|
|
21
|
+
return /* @__PURE__ */ jsxs("section", { "aria-label": label, "data-paused": paused ? "" : void 0, "data-direction": direction, "data-fade": fade ? "" : void 0, className: cn("kz-band group/marquee relative", className), ...props, children: [
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
"div",
|
|
24
|
+
{
|
|
25
|
+
tabIndex: 0,
|
|
26
|
+
className: "kz-band-viewport overflow-hidden rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring",
|
|
27
|
+
children: /* @__PURE__ */ jsxs("div", { ref: track, className: "kz-marquee kz-loop", children: [
|
|
28
|
+
/* @__PURE__ */ jsx("ul", { className: "flex shrink-0 items-center gap-(--kz-band-gap) pr-(--kz-band-gap)", children: wrap(children) }),
|
|
29
|
+
/* @__PURE__ */ jsx("ul", { "aria-hidden": true, className: "kz-band-copy flex shrink-0 items-center gap-(--kz-band-gap) pr-(--kz-band-gap)", children: wrap(children) })
|
|
30
|
+
] })
|
|
31
|
+
}
|
|
32
|
+
),
|
|
33
|
+
/* @__PURE__ */ jsx(
|
|
34
|
+
"button",
|
|
35
|
+
{
|
|
36
|
+
type: "button",
|
|
37
|
+
"aria-pressed": paused,
|
|
38
|
+
"aria-label": paused ? playLabel : pauseLabel,
|
|
39
|
+
onClick: () => setPaused(!paused),
|
|
40
|
+
className: "absolute right-1 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full border border-border-default bg-surface-1/90 text-fg-secondary opacity-0 shadow-sm transition-opacity hover:text-fg focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring group-hover/marquee:opacity-100 aria-pressed:opacity-100 motion-reduce:hidden",
|
|
41
|
+
children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", className: "h-3.5 w-3.5", fill: "currentColor", "aria-hidden": true, children: paused ? /* @__PURE__ */ jsx("path", { d: "M8 5.5v13l10-6.5Z" }) : /* @__PURE__ */ jsx("path", { d: "M7 5h3.5v14H7zM13.5 5H17v14h-3.5z" }) })
|
|
42
|
+
}
|
|
43
|
+
)
|
|
44
|
+
] });
|
|
45
|
+
}
|
|
46
|
+
function wrap(children) {
|
|
47
|
+
return React.Children.map(children, (child) => /* @__PURE__ */ jsx("li", { className: "shrink-0", children: child }));
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
Marquee
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=marquee.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/marquee/marquee.tsx"],"sourcesContent":["// Client (a pause button, a measure). A band that slides — and that anyone can stop: it pauses under the pointer and\n// while something inside has the focus, it carries a visible pause button (WCAG 2.2.2: motion longer than 5 s can be\n// paused), its speed is in pixels per second whatever its width (a long band does not race), its copy is hidden from\n// assistive technology (each item is read once), and under reduced motion it is a still row you scroll by hand.\nimport * as React from \"react\";\n\nimport { cn } from \"../cn\";\n\nexport type MarqueeProps = Omit<React.ComponentProps<\"section\">, \"children\"> & {\n /** The accessible name of the band (“Our partners”) — passed translated. */\n label: string;\n /** The pause button's name (“Pause the band”) — passed translated. */\n pauseLabel: string;\n /** The same button's name once paused (“Play the band”) — passed translated. */\n playLabel: string;\n /** The items: logos, words, cards. */\n children: React.ReactNode;\n /**\n * Pixels per second.\n * @default 40\n */\n speed?: number;\n /**\n * Which way it slides.\n * @default \"left\"\n */\n direction?: \"left\" | \"right\";\n /**\n * The edges fade into the page.\n * @default true\n */\n fade?: boolean;\n /** Starts paused. */\n defaultPaused?: boolean;\n};\n\n/** A band of items sliding forever — pausable, accessible, still under reduced motion. */\nexport function Marquee({ label, pauseLabel, playLabel, children, speed = 40, direction = \"left\", fade = true, defaultPaused = false, className, ...props }: MarqueeProps) {\n const [paused, setPaused] = React.useState(defaultPaused);\n const track = React.useRef<HTMLDivElement>(null);\n React.useEffect(() => {\n const el = track.current;\n if (!el) return;\n const measure = () => el.style.setProperty(\"--kz-marquee-duration\", `${Math.max(4, el.scrollWidth / 2 / Math.max(1, speed))}s`);\n measure();\n const ro = new ResizeObserver(measure);\n ro.observe(el);\n return () => ro.disconnect();\n }, [speed]);\n return (\n <section aria-label={label} data-paused={paused ? \"\" : undefined} data-direction={direction} data-fade={fade ? \"\" : undefined} className={cn(\"kz-band group/marquee relative\", className)} {...props}>\n {/* Focusable: the keyboard stops the band (focus-within) and, still under reduced motion, scrolls the row. */}\n <div\n tabIndex={0}\n className=\"kz-band-viewport overflow-hidden rounded-lg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring\"\n >\n {/* Each copy ends with the gap: two copies are exactly twice one, so the loop never jumps. */}\n <div ref={track} className=\"kz-marquee kz-loop\">\n <ul className=\"flex shrink-0 items-center gap-(--kz-band-gap) pr-(--kz-band-gap)\">{wrap(children)}</ul>\n <ul aria-hidden className=\"kz-band-copy flex shrink-0 items-center gap-(--kz-band-gap) pr-(--kz-band-gap)\">\n {wrap(children)}\n </ul>\n </div>\n </div>\n <button\n type=\"button\"\n aria-pressed={paused}\n aria-label={paused ? playLabel : pauseLabel}\n onClick={() => setPaused(!paused)}\n className=\"absolute right-1 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full border border-border-default bg-surface-1/90 text-fg-secondary opacity-0 shadow-sm transition-opacity hover:text-fg focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring group-hover/marquee:opacity-100 aria-pressed:opacity-100 motion-reduce:hidden\"\n >\n <svg viewBox=\"0 0 24 24\" className=\"h-3.5 w-3.5\" fill=\"currentColor\" aria-hidden>\n {paused ? <path d=\"M8 5.5v13l10-6.5Z\" /> : <path d=\"M7 5h3.5v14H7zM13.5 5H17v14h-3.5z\" />}\n </svg>\n </button>\n </section>\n );\n}\n\nfunction wrap(children: React.ReactNode) {\n return React.Children.map(children, (child) => <li className=\"shrink-0\">{child}</li>);\n}\n"],"mappings":";;;;;;AAIA,YAAY,WAAW;AAqDf,SACE,KADF;AApBD,SAAS,QAAQ,EAAE,OAAO,YAAY,WAAW,UAAU,QAAQ,IAAI,YAAY,QAAQ,OAAO,MAAM,gBAAgB,OAAO,WAAW,GAAG,MAAM,GAAiB;AACzK,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAS,aAAa;AACxD,QAAM,QAAc,aAAuB,IAAI;AAC/C,EAAM,gBAAU,MAAM;AACpB,UAAM,KAAK,MAAM;AACjB,QAAI,CAAC,GAAI;AACT,UAAM,UAAU,MAAM,GAAG,MAAM,YAAY,yBAAyB,GAAG,KAAK,IAAI,GAAG,GAAG,cAAc,IAAI,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC,GAAG;AAC9H,YAAQ;AACR,UAAM,KAAK,IAAI,eAAe,OAAO;AACrC,OAAG,QAAQ,EAAE;AACb,WAAO,MAAM,GAAG,WAAW;AAAA,EAC7B,GAAG,CAAC,KAAK,CAAC;AACV,SACE,qBAAC,aAAQ,cAAY,OAAO,eAAa,SAAS,KAAK,QAAW,kBAAgB,WAAW,aAAW,OAAO,KAAK,QAAW,WAAW,GAAG,kCAAkC,SAAS,GAAI,GAAG,OAE7L;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,WAAU;AAAA,QAGV,+BAAC,SAAI,KAAK,OAAO,WAAU,sBACzB;AAAA,8BAAC,QAAG,WAAU,qEAAqE,eAAK,QAAQ,GAAE;AAAA,UAClG,oBAAC,QAAG,eAAW,MAAC,WAAU,kFACvB,eAAK,QAAQ,GAChB;AAAA,WACF;AAAA;AAAA,IACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,gBAAc;AAAA,QACd,cAAY,SAAS,YAAY;AAAA,QACjC,SAAS,MAAM,UAAU,CAAC,MAAM;AAAA,QAChC,WAAU;AAAA,QAEV,8BAAC,SAAI,SAAQ,aAAY,WAAU,eAAc,MAAK,gBAAe,eAAW,MAC7E,mBAAS,oBAAC,UAAK,GAAE,qBAAoB,IAAK,oBAAC,UAAK,GAAE,qCAAoC,GACzF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAEA,SAAS,KAAK,UAA2B;AACvC,SAAa,eAAS,IAAI,UAAU,CAAC,UAAU,oBAAC,QAAG,WAAU,YAAY,iBAAM,CAAK;AACtF;","names":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The Krizaka flock — the geometry of the mascots, drawn by the web `Mascot` (`./mascot.tsx`) and the native one
|
|
5
|
+
* (`../native/mascots.tsx`). Five birds that have carried the Krizaka story since the first site (the sentry falcon,
|
|
6
|
+
* the owl that reads, the developer duck, the flamingo that answers, the carrier pigeon), redrawn on one 120 × 120
|
|
7
|
+
* grid so that any bird can wear any mood.
|
|
8
|
+
*
|
|
9
|
+
* Colours are roles, never fixed: `brand` (the default) paints a bird in the host's accent (`--kz-accent`,
|
|
10
|
+
* `--kz-accent-2`), so the same falcon is blue on krizaka.com, orange in Orazaka and violet in Orochia; `own` gives
|
|
11
|
+
* each bird the signature palette it has in the Krizaka story (the brand layer's exception, like the marks). Shades
|
|
12
|
+
* and highlights are black and white at a low opacity over the role, so they hold in both themes.
|
|
13
|
+
*/
|
|
14
|
+
declare const MASCOT_BIRDS: readonly ["falcon", "owl", "duck", "flamingo", "pigeon"];
|
|
15
|
+
type MascotBird = (typeof MASCOT_BIRDS)[number];
|
|
16
|
+
declare const MASCOT_MOODS: readonly ["welcome", "thinking", "success", "empty", "error"];
|
|
17
|
+
type MascotMood = (typeof MASCOT_MOODS)[number];
|
|
18
|
+
type MascotTone = "brand" | "own";
|
|
19
|
+
|
|
20
|
+
type MascotProps = Omit<React.ComponentProps<"svg">, "children"> & {
|
|
21
|
+
/** Which bird of the flock: `falcon` (watch, security), `owl` (reading, documents), `duck` (building, code), `flamingo` (answers, support), `pigeon` (delivery, notifications). */
|
|
22
|
+
bird?: MascotBird;
|
|
23
|
+
/** What the moment is: `welcome` (onboarding), `thinking` (a long task running), `success` (it is done), `empty` (nothing here yet), `error` (it failed). */
|
|
24
|
+
mood?: MascotMood;
|
|
25
|
+
/** `brand` (default): the host's accent, so the bird wears the product it is in. `own`: the bird's signature colours of the Krizaka story. */
|
|
26
|
+
tone?: MascotTone;
|
|
27
|
+
/** Width and height in pixels. */
|
|
28
|
+
size?: number;
|
|
29
|
+
/** A light idle motion and the mood's gesture. Off with `false`; always off under `prefers-reduced-motion`. */
|
|
30
|
+
animated?: boolean;
|
|
31
|
+
/** An accessible name (the bird becomes an image); without it the mascot is decorative. */
|
|
32
|
+
title?: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* One of the five Krizaka birds in one mood — for the moments a product speaks to a person: a welcome, a long wait,
|
|
36
|
+
* a success, an empty list, an error. Drawn in the host's brand colours by default (`tone="own"` for the story's).
|
|
37
|
+
*/
|
|
38
|
+
declare function Mascot({ bird, mood, tone, size, animated, title, className, ...props }: MascotProps): React.JSX.Element;
|
|
39
|
+
|
|
40
|
+
export { MASCOT_BIRDS, MASCOT_MOODS, Mascot, type MascotBird, type MascotMood, type MascotProps, type MascotTone };
|