@krizaka/ui 2.2.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 +17 -7
- 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/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/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 +148 -8
- 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/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 +191 -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 +3 -3
- 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
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "number-ticker",
|
|
3
|
+
"type": "primitive",
|
|
4
|
+
"title": "Number ticker",
|
|
5
|
+
"summary": "A figure that climbs into view once, or rolls digit by digit to each new value — server-rendered at its final value, its width held from the first paint, read once by assistive technology.",
|
|
6
|
+
"description": "A figure that climbs into view once, or rolls digit by digit to each new value — server-rendered at its final value, its width held from the first paint, read once by assistive technology.",
|
|
7
|
+
"status": "beta",
|
|
8
|
+
"category": "data-display",
|
|
9
|
+
"platforms": "web",
|
|
10
|
+
"whenToUse": [
|
|
11
|
+
"The key figures of a page (90 %, 12,480 creators): they climb once as they come into view.",
|
|
12
|
+
"A live total that changes while it is watched — an auction's highest bid, a tip jar, a credit balance (`trigger=\"change\"`)."
|
|
13
|
+
],
|
|
14
|
+
"whenNotToUse": [
|
|
15
|
+
{
|
|
16
|
+
"when": "For a figure with its trend and comparison in a dashboard tile.",
|
|
17
|
+
"use": "stat"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"when": "For time left until a moment.",
|
|
21
|
+
"use": "countdown"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"when": "Inside running text, or for every number of a table: motion there gets in the way of reading."
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"bestPractices": [
|
|
28
|
+
"Format with the app's `locale` and Intl options (`format`): currency, unit, fraction digits — never by hand.",
|
|
29
|
+
"A few figures per page climb; the rest stay still.",
|
|
30
|
+
"For a live total, `announce` only when the change matters to the reader (an outbid), not for every tick."
|
|
31
|
+
],
|
|
32
|
+
"accessibility": {
|
|
33
|
+
"keyboard": [],
|
|
34
|
+
"notes": [
|
|
35
|
+
"The moving digits are hidden from assistive technology; a visually hidden copy carries the final value — read once, never “0, 312, 1,204…”.",
|
|
36
|
+
"`announce` makes that copy a polite live region: each new value is heard.",
|
|
37
|
+
"Under `prefers-reduced-motion` nothing climbs or rolls: the value is simply there.",
|
|
38
|
+
"Server-rendered at the final value: no layout shift (an invisible copy holds the width), nothing missing without JavaScript."
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"related": [
|
|
42
|
+
"stat",
|
|
43
|
+
"countdown",
|
|
44
|
+
"progress"
|
|
45
|
+
],
|
|
46
|
+
"web": {
|
|
47
|
+
"entry": "@krizaka/ui/number-ticker",
|
|
48
|
+
"import": "import { NumberTicker } from \"@krizaka/ui/number-ticker\";",
|
|
49
|
+
"props": [
|
|
50
|
+
{
|
|
51
|
+
"component": "NumberTicker",
|
|
52
|
+
"description": "A figure that climbs into view, or rolls digit by digit to each new value.",
|
|
53
|
+
"props": [
|
|
54
|
+
{
|
|
55
|
+
"name": "value",
|
|
56
|
+
"type": "number",
|
|
57
|
+
"default": null,
|
|
58
|
+
"description": "The value to show.",
|
|
59
|
+
"required": true
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"name": "align",
|
|
63
|
+
"type": "\"start\" | \"end\"",
|
|
64
|
+
"default": "end",
|
|
65
|
+
"description": "Where the figure sits in the box its final width reserves.",
|
|
66
|
+
"required": false
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "announce",
|
|
70
|
+
"type": "boolean",
|
|
71
|
+
"default": null,
|
|
72
|
+
"description": "Announce each new value politely (`trigger=\"change\"`): a live total the reader should hear.",
|
|
73
|
+
"required": false
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"name": "duration",
|
|
77
|
+
"type": "number",
|
|
78
|
+
"default": "1100",
|
|
79
|
+
"description": "Milliseconds of the climb.",
|
|
80
|
+
"required": false
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"name": "format",
|
|
84
|
+
"type": "NumberFormatOptions",
|
|
85
|
+
"default": null,
|
|
86
|
+
"description": "How to write it (`{ style: \"currency\", currency: \"EUR\" }`, `{ maximumFractionDigits: 1 }`…): Intl.NumberFormat options.",
|
|
87
|
+
"required": false
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "locale",
|
|
91
|
+
"type": "string",
|
|
92
|
+
"default": null,
|
|
93
|
+
"description": "The locale of the digits and separators (`\"fr\"`: 1 204,5) — the app's locale.",
|
|
94
|
+
"required": false
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"name": "trigger",
|
|
98
|
+
"type": "\"view\" | \"change\"",
|
|
99
|
+
"default": "view",
|
|
100
|
+
"description": "`view`: climbs from 0 once, the first time it scrolls into view. `change`: each digit rolls to the new value\nwhenever `value` changes (a live total).",
|
|
101
|
+
"required": false
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
"examples": [
|
|
107
|
+
{
|
|
108
|
+
"name": "stats",
|
|
109
|
+
"title": "Key figures",
|
|
110
|
+
"description": "Three figures that climb once into view — a percentage, a count, a decimal — formatted by Intl.",
|
|
111
|
+
"path": "examples/number-ticker/stats.tsx",
|
|
112
|
+
"module": "@krizaka/ui/registry/examples/number-ticker/stats",
|
|
113
|
+
"code": "import { NumberTicker } from \"@krizaka/ui/number-ticker\";\n\n// Figures that climb once as they scroll into view. The server renders the final values: nothing jumps, and a reader\n// who lands with them already on screen sees them still.\nexport default function NumberTickerStats() {\n const stats = [\n { value: 90, label: \"of every support goes to the creator\", format: { style: \"unit\", unit: \"percent\" } as const },\n { value: 12480, label: \"creators paid this month\" },\n { value: 1.2, label: \"seconds to the first token\", format: { maximumFractionDigits: 1 } },\n ];\n return (\n <dl className=\"grid gap-6 sm:grid-cols-3\">\n {stats.map((s) => (\n <div key={s.label} className=\"flex flex-col gap-1\">\n <dt className=\"text-sm text-fg-secondary\">{s.label}</dt>\n <dd className=\"order-first font-display text-4xl font-semibold text-fg\">\n <NumberTicker value={s.value} locale=\"en\" format={s.format} align=\"start\" />\n </dd>\n </div>\n ))}\n </dl>\n );\n}\n"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"name": "live-total",
|
|
117
|
+
"title": "A live total",
|
|
118
|
+
"description": "`trigger=\"change\"`: the highest bid rolls digit by digit, a rise flashes, the amount is announced.",
|
|
119
|
+
"path": "examples/number-ticker/live-total.tsx",
|
|
120
|
+
"module": "@krizaka/ui/registry/examples/number-ticker/live-total",
|
|
121
|
+
"code": "\"use client\";\n\nimport { Button } from \"@krizaka/ui/button\";\nimport { NumberTicker } from \"@krizaka/ui/number-ticker\";\nimport { useState } from \"react\";\n\n// A live total (an auction's highest bid): each digit rolls to the new value, a rise flashes the success colour, and the\n// new amount is announced politely.\nexport default function NumberTickerLiveTotal() {\n const [bid, setBid] = useState(1250);\n return (\n <div className=\"flex items-center gap-4\">\n <p className=\"font-display text-3xl font-semibold text-fg\">\n <NumberTicker value={bid} trigger=\"change\" announce locale=\"en\" format={{ style: \"currency\", currency: \"EUR\", maximumFractionDigits: 0 }} />\n </p>\n <Button size=\"sm\" variant=\"primary\" onClick={() => setBid((b) => b + 50)}>\n Outbid by €50\n </Button>\n </div>\n );\n}\n"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"name": "gradient",
|
|
125
|
+
"title": "In gradient text",
|
|
126
|
+
"description": "The digits stay painted by the gradient while they climb.",
|
|
127
|
+
"path": "examples/number-ticker/gradient.tsx",
|
|
128
|
+
"module": "@krizaka/ui/registry/examples/number-ticker/gradient",
|
|
129
|
+
"code": "import { NumberTicker } from \"@krizaka/ui/number-ticker\";\n\n// Inside gradient text: every box of the figure carries the gradient, so the climbing digits stay painted.\nexport default function NumberTickerGradient() {\n return (\n <p className=\"bg-linear-to-r from-accent to-accent-2 bg-clip-text font-display text-5xl font-bold text-transparent\">\n <NumberTicker value={4.9} format={{ maximumFractionDigits: 1 }} locale=\"en\" />\n </p>\n );\n}\n"
|
|
130
|
+
}
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
"native": null,
|
|
134
|
+
"files": [
|
|
135
|
+
{
|
|
136
|
+
"path": "cx.ts",
|
|
137
|
+
"content": "/** Joins class names, skipping the falsy ones. */\nexport function cx(...parts: Array<string | false | null | undefined>): string {\n return parts.filter(Boolean).join(\" \");\n}\n"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"path": "meta.ts",
|
|
141
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"glow-card\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"path": "number-ticker/index.ts",
|
|
145
|
+
"content": "/** @krizaka/ui/number-ticker — `NumberTicker`: a figure that climbs into view, or rolls digit by digit to each new value. Client. */\nexport { NumberTicker, type NumberTickerProps } from \"./number-ticker\";\n"
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"path": "number-ticker/meta.ts",
|
|
149
|
+
"content": "import type { ComponentMeta } from \"../meta\";\n\nexport const meta = {\n title: \"Number ticker\",\n summary:\n \"A figure that climbs into view once, or rolls digit by digit to each new value — server-rendered at its final value, its width held from the first paint, read once by assistive technology.\",\n status: \"beta\",\n category: \"data-display\",\n platforms: \"web\",\n whenToUse: [\n \"The key figures of a page (90 %, 12,480 creators): they climb once as they come into view.\",\n \"A live total that changes while it is watched — an auction's highest bid, a tip jar, a credit balance (`trigger=\\\"change\\\"`).\",\n ],\n whenNotToUse: [\n { when: \"For a figure with its trend and comparison in a dashboard tile.\", use: \"stat\" },\n { when: \"For time left until a moment.\", use: \"countdown\" },\n { when: \"Inside running text, or for every number of a table: motion there gets in the way of reading.\" },\n ],\n bestPractices: [\n \"Format with the app's `locale` and Intl options (`format`): currency, unit, fraction digits — never by hand.\",\n \"A few figures per page climb; the rest stay still.\",\n \"For a live total, `announce` only when the change matters to the reader (an outbid), not for every tick.\",\n ],\n accessibility: {\n keyboard: [],\n notes: [\n \"The moving digits are hidden from assistive technology; a visually hidden copy carries the final value — read once, never “0, 312, 1,204…”.\",\n \"`announce` makes that copy a polite live region: each new value is heard.\",\n \"Under `prefers-reduced-motion` nothing climbs or rolls: the value is simply there.\",\n \"Server-rendered at the final value: no layout shift (an invisible copy holds the width), nothing missing without JavaScript.\",\n ],\n },\n related: [\"stat\", \"countdown\", \"progress\"],\n web: {\n imports: [\"NumberTicker\"],\n examples: [\n { name: \"stats\", title: \"Key figures\", description: \"Three figures that climb once into view — a percentage, a count, a decimal — formatted by Intl.\" },\n { name: \"live-total\", title: \"A live total\", description: \"`trigger=\\\"change\\\"`: the highest bid rolls digit by digit, a rise flashes, the amount is announced.\" },\n { name: \"gradient\", title: \"In gradient text\", description: \"The digits stay painted by the gradient while they climb.\" },\n ],\n },\n} satisfies ComponentMeta;\n"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"path": "number-ticker/number-ticker.tsx",
|
|
153
|
+
"content": "// Client (an observer, a short count). A figure that climbs — without the faults of the usual counters: the server\n// renders the final value (crawlers, screen readers, no-JS and reduced-motion readers all read it), an invisible copy\n// holds its width from the first paint (no layout shift), a figure already on screen at load does not drop to 0 in\n// front of the reader, the count is a bounded loop (~1 s) that stops for good, and assistive technology reads only the\n// final value. On `trigger=\"change\"` each digit rolls to its new value (a live total: tips, bids) and the change can be\n// announced.\nimport * as React from \"react\";\n\nimport { cx } from \"../cx\";\n\nexport interface NumberTickerProps extends Omit<React.ComponentProps<\"span\">, \"children\"> {\n /** The value to show. */\n value: number;\n /** The locale of the digits and separators (`\"fr\"`: 1 204,5) — the app's locale. */\n locale?: string;\n /** How to write it (`{ style: \"currency\", currency: \"EUR\" }`, `{ maximumFractionDigits: 1 }`…): Intl.NumberFormat options. */\n format?: Intl.NumberFormatOptions;\n /**\n * `view`: climbs from 0 once, the first time it scrolls into view. `change`: each digit rolls to the new value\n * whenever `value` changes (a live total).\n * @default \"view\"\n */\n trigger?: \"view\" | \"change\";\n /**\n * Milliseconds of the climb.\n * @default 1100\n */\n duration?: number;\n /** Announce each new value politely (`trigger=\"change\"`): a live total the reader should hear. */\n announce?: boolean;\n /**\n * Where the figure sits in the box its final width reserves.\n * @default \"end\"\n */\n align?: \"start\" | \"end\";\n}\n\nconst easeOut = (t: number) => 1 - Math.pow(1 - t, 4);\n\n/** A figure that climbs into view, or rolls digit by digit to each new value. */\nexport function NumberTicker({ value, locale, format, trigger = \"view\", duration = 1100, announce, align = \"end\", className, ...props }: NumberTickerProps) {\n const formatter = React.useMemo(() => new Intl.NumberFormat(locale, format), [locale, format]);\n const text = formatter.format(value);\n const live = React.useRef<HTMLSpanElement>(null);\n // The previous value, kept in state (React's pattern for “adjusting state when a prop changes”): the trend of the last change.\n const [previous, setPrevious] = React.useState(value);\n const [trend, setTrend] = React.useState<\"up\" | \"down\" | undefined>(undefined);\n if (value !== previous) {\n setPrevious(value);\n setTrend(value > previous ? \"up\" : \"down\");\n }\n\n React.useEffect(() => {\n const el = live.current;\n if (trigger !== \"view\" || !el || window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) return;\n let first = true;\n let frame = 0;\n const io = new IntersectionObserver(\n ([entry]) => {\n const wasFirst = first;\n first = false;\n if (!entry?.isIntersecting) return;\n io.disconnect();\n if (wasFirst) return; // already on screen at load: it stays, nothing drops to 0 in front of the reader\n const start = performance.now();\n const tick = (now: number) => {\n const p = Math.min(1, (now - start) / duration);\n el.textContent = formatter.format(value * easeOut(p));\n if (p < 1) frame = requestAnimationFrame(tick);\n };\n el.textContent = formatter.format(0);\n frame = requestAnimationFrame(tick);\n },\n { threshold: 0.6 },\n );\n io.observe(el);\n return () => {\n io.disconnect();\n cancelAnimationFrame(frame);\n el.textContent = formatter.format(value);\n };\n }, [trigger, value, duration, formatter]);\n\n return (\n <span data-align={align} data-trend={trigger === \"change\" ? trend : undefined} className={cx(\"kz-count\", className)} {...props}>\n <span aria-hidden className=\"kz-count-ghost\">\n {text}\n </span>\n {trigger === \"change\" ? (\n <span aria-hidden className=\"kz-count-roll\">\n {/* Keyed from the right: when a digit is added (999 → 1,000), the units stay the units. */}\n {[...text].map((char, i, all) =>\n /\\d/.test(char) ? (\n <span key={all.length - i} className=\"kz-count-digit\" style={{ \"--kz-digit\": char } as React.CSSProperties}>\n <span>\n {\"0123456789\".split(\"\").map((d) => (\n <span key={d}>{d}</span>\n ))}\n </span>\n </span>\n ) : (\n <span key={all.length - i}>{char}</span>\n ),\n )}\n </span>\n ) : (\n <span aria-hidden ref={live}>\n {text}\n </span>\n )}\n <span className=\"sr-only\" aria-live={announce ? \"polite\" : undefined}>\n {text}\n </span>\n </span>\n );\n}\n"
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"dependencies": [],
|
|
157
|
+
"registryDependencies": [],
|
|
158
|
+
"demo": {
|
|
159
|
+
"path": "examples/number-ticker/stats.tsx",
|
|
160
|
+
"content": "import { NumberTicker } from \"@krizaka/ui/number-ticker\";\n\n// Figures that climb once as they scroll into view. The server renders the final values: nothing jumps, and a reader\n// who lands with them already on screen sees them still.\nexport default function NumberTickerStats() {\n const stats = [\n { value: 90, label: \"of every support goes to the creator\", format: { style: \"unit\", unit: \"percent\" } as const },\n { value: 12480, label: \"creators paid this month\" },\n { value: 1.2, label: \"seconds to the first token\", format: { maximumFractionDigits: 1 } },\n ];\n return (\n <dl className=\"grid gap-6 sm:grid-cols-3\">\n {stats.map((s) => (\n <div key={s.label} className=\"flex flex-col gap-1\">\n <dt className=\"text-sm text-fg-secondary\">{s.label}</dt>\n <dd className=\"order-first font-display text-4xl font-semibold text-fg\">\n <NumberTicker value={s.value} locale=\"en\" format={s.format} align=\"start\" />\n </dd>\n </div>\n ))}\n </dl>\n );\n}\n"
|
|
161
|
+
},
|
|
162
|
+
"props": [
|
|
163
|
+
{
|
|
164
|
+
"component": "NumberTicker",
|
|
165
|
+
"description": "A figure that climbs into view, or rolls digit by digit to each new value.",
|
|
166
|
+
"props": [
|
|
167
|
+
{
|
|
168
|
+
"name": "value",
|
|
169
|
+
"type": "number",
|
|
170
|
+
"default": null,
|
|
171
|
+
"description": "The value to show.",
|
|
172
|
+
"required": true
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "align",
|
|
176
|
+
"type": "\"start\" | \"end\"",
|
|
177
|
+
"default": "end",
|
|
178
|
+
"description": "Where the figure sits in the box its final width reserves.",
|
|
179
|
+
"required": false
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "announce",
|
|
183
|
+
"type": "boolean",
|
|
184
|
+
"default": null,
|
|
185
|
+
"description": "Announce each new value politely (`trigger=\"change\"`): a live total the reader should hear.",
|
|
186
|
+
"required": false
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "duration",
|
|
190
|
+
"type": "number",
|
|
191
|
+
"default": "1100",
|
|
192
|
+
"description": "Milliseconds of the climb.",
|
|
193
|
+
"required": false
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "format",
|
|
197
|
+
"type": "NumberFormatOptions",
|
|
198
|
+
"default": null,
|
|
199
|
+
"description": "How to write it (`{ style: \"currency\", currency: \"EUR\" }`, `{ maximumFractionDigits: 1 }`…): Intl.NumberFormat options.",
|
|
200
|
+
"required": false
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"name": "locale",
|
|
204
|
+
"type": "string",
|
|
205
|
+
"default": null,
|
|
206
|
+
"description": "The locale of the digits and separators (`\"fr\"`: 1 204,5) — the app's locale.",
|
|
207
|
+
"required": false
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"name": "trigger",
|
|
211
|
+
"type": "\"view\" | \"change\"",
|
|
212
|
+
"default": "view",
|
|
213
|
+
"description": "`view`: climbs from 0 once, the first time it scrolls into view. `change`: each digit rolls to the new value\nwhenever `value` changes (a live total).",
|
|
214
|
+
"required": false
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
]
|
|
219
|
+
}
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
"files": [
|
|
116
116
|
{
|
|
117
117
|
"path": "meta.ts",
|
|
118
|
-
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"kbd\"\n | \"mascots\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
118
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"glow-card\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"path": "page-header/index.ts",
|
package/registry/popover.json
CHANGED
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
90
|
"path": "meta.ts",
|
|
91
|
-
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"kbd\"\n | \"mascots\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
91
|
+
"content": "// The documentation of a component, carried by its code: each primitive has a `meta.ts` beside its source\n// (`src/<name>/meta.ts`; a component that exists only in React Native: `src/native/meta/<name>.ts`). Never built into\n// the package: `scripts/build-registry.mjs` reads them into `registry/<name>.json`, which krizaka.com renders as\n// /docs/ui/<name>, and `scripts/registry.test.mjs` fails when one is missing or incomplete.\n//\n// Why a typed module and not JSDoc tags: the fields are lists and links (`related`, `whenNotToUse[].use`, examples),\n// which a type checks and a comment does not; the file is plain data (erasable TypeScript), so Node reads it without a\n// compiler, and an editor completes it.\n\n/** Every documented component: the web primitives (one entry of the package each) and the native-only ones. */\nexport type ComponentName =\n | \"alert\"\n | \"avatar\"\n | \"badge\"\n | \"button\"\n | \"card\"\n | \"checkbox\"\n | \"chip\"\n | \"chip-link\"\n | \"cn\"\n | \"command\"\n | \"confirm-button\"\n | \"countdown\"\n | \"dialog\"\n | \"dropdown-menu\"\n | \"empty-state\"\n | \"field\"\n | \"glow-card\"\n | \"iso\"\n | \"kbd\"\n | \"loader\"\n | \"marquee\"\n | \"mascots\"\n | \"meter\"\n | \"nav-bar\"\n | \"number-ticker\"\n | \"page-header\"\n | \"popover\"\n | \"progress\"\n | \"radio-group\"\n | \"section-backdrop\"\n | \"segmented\"\n | \"separator\"\n | \"skeleton\"\n | \"slider\"\n | \"slot\"\n | \"spinner\"\n | \"stat\"\n | \"stepper\"\n | \"switch\"\n | \"tabs\"\n | \"theme\"\n | \"toast\"\n | \"tooltip\"\n | \"txt\";\n\n/** Where a component exists: `@krizaka/ui/<name>` (web), `@krizaka/ui/native` (React Native), or both. */\nexport type Platform = \"web\" | \"native\" | \"both\";\n\n/** `stable`: its API only changes in a major. `beta`: it may still change in a minor. */\nexport type Status = \"stable\" | \"beta\";\n\n/** The group of the catalogue. */\nexport type Category = \"actions\" | \"forms\" | \"navigation\" | \"overlays\" | \"feedback\" | \"data-display\" | \"layout\" | \"foundations\";\n\n/**\n * A named example: the file `registry/examples/<component>/<name>.tsx` (web) or\n * `registry/examples/<component>/native/<name>.tsx` (React Native) — at most 40 lines, imported by the stories and\n * shown (live, with its code) by the documentation.\n */\nexport interface Example {\n /** The file name, kebab-case (`primary`, `icon-button`). */\n readonly name: string;\n /** A short title (`Primary`, `Icon button`). */\n readonly title: string;\n /** One or two sentences: when this variant is the right one. */\n readonly description: string;\n}\n\n/** One platform's side of a component. */\nexport interface PlatformDocs {\n /** The names to import (`[\"Button\", \"IconButton\"]`): from `@krizaka/ui/<name>` on the web, `@krizaka/ui/native` in React Native. */\n readonly imports: readonly string[];\n /** The examples, in reading order; the first one is the component's preview. */\n readonly examples: readonly Example[];\n}\n\n/** The React Native side: the same concept, and what differs from the web API. */\nexport interface NativeDocs extends PlatformDocs {\n /** What differs from the web API (`label` instead of children…); empty for a native-only component. */\n readonly differences: readonly string[];\n}\n\nexport interface KeyboardInteraction {\n /** The keys, as written on a keyboard: `Space`, `Enter`, `Arrow keys`, `Esc`, `Tab`. */\n readonly keys: string;\n /** What they do. */\n readonly action: string;\n}\n\nexport interface ComponentMeta {\n /** The display name: `Button`, `Dropdown menu`. */\n readonly title: string;\n /** One sentence: what it is. */\n readonly summary: string;\n readonly status: Status;\n readonly category: Category;\n /** Must match the sides below: `both` ⇔ `web` and `native`. */\n readonly platforms: Platform;\n /** When to reach for it: concrete situations, one per item. */\n readonly whenToUse: readonly string[];\n /** When not to — and what to use instead (`use`), when another component is the answer. */\n readonly whenNotToUse: readonly { readonly when: string; readonly use?: ComponentName }[];\n /** How to use it well: wording, placement, composition. */\n readonly bestPractices: readonly string[];\n readonly accessibility: {\n /** The keyboard, when it does more than Tab and Enter. */\n readonly keyboard: readonly KeyboardInteraction[];\n /** Roles, names and announcements: what the component does, what the app must provide. */\n readonly notes: readonly string[];\n };\n /** The components a reader of this page should know about. */\n readonly related: readonly ComponentName[];\n readonly web?: PlatformDocs;\n readonly native?: NativeDocs;\n}\n"
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"path": "popover/index.ts",
|