@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
package/dist/meter.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/meter/meter.tsx
|
|
2
|
+
import { tv } from "tailwind-variants";
|
|
3
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
var meter = tv({
|
|
5
|
+
slots: {
|
|
6
|
+
root: "flex w-full flex-col gap-1.5",
|
|
7
|
+
header: "flex items-baseline gap-2 text-xs",
|
|
8
|
+
caption: "min-w-0 flex-1 truncate font-medium text-fg",
|
|
9
|
+
figure: "shrink-0 tabular-nums text-fg-secondary",
|
|
10
|
+
track: "relative flex h-2 w-full gap-0.5 overflow-hidden rounded-full bg-surface-3",
|
|
11
|
+
fill: "h-full rounded-full transition-[width] duration-700 motion-reduce:transition-none",
|
|
12
|
+
legend: "mt-1 flex flex-wrap gap-x-4 gap-y-1 text-xs text-fg-secondary",
|
|
13
|
+
swatch: "inline-block h-2 w-2 shrink-0 rounded-full",
|
|
14
|
+
ring: "relative inline-flex shrink-0 items-center justify-center",
|
|
15
|
+
center: "absolute inset-0 flex flex-col items-center justify-center text-center"
|
|
16
|
+
},
|
|
17
|
+
variants: {
|
|
18
|
+
size: { sm: { track: "h-1.5", ring: "h-14 w-14" }, md: { ring: "h-24 w-24" }, lg: { track: "h-3", ring: "h-36 w-36" } }
|
|
19
|
+
},
|
|
20
|
+
defaultVariants: { size: "md" }
|
|
21
|
+
});
|
|
22
|
+
var BG = { ok: "bg-accent", success: "bg-success", warning: "bg-warning", danger: "bg-danger" };
|
|
23
|
+
var STROKE = { ok: "stroke-accent", success: "stroke-success", warning: "stroke-warning", danger: "stroke-danger" };
|
|
24
|
+
var PART_BG = ["bg-accent", "bg-fg-secondary", "bg-accent-2", "bg-border-strong"];
|
|
25
|
+
var PART_STROKE = ["stroke-accent", "stroke-fg-secondary", "stroke-accent-2", "stroke-border-strong"];
|
|
26
|
+
function Meter({
|
|
27
|
+
label,
|
|
28
|
+
value = 0,
|
|
29
|
+
min = 0,
|
|
30
|
+
max = 100,
|
|
31
|
+
valueText,
|
|
32
|
+
thresholds,
|
|
33
|
+
optimum = "low",
|
|
34
|
+
parts,
|
|
35
|
+
variant = "bar",
|
|
36
|
+
size = "md",
|
|
37
|
+
showLabel,
|
|
38
|
+
className,
|
|
39
|
+
children,
|
|
40
|
+
...props
|
|
41
|
+
}) {
|
|
42
|
+
const s = meter({ size });
|
|
43
|
+
const span = max - min || 1;
|
|
44
|
+
const ratio = Math.min(1, Math.max(0, (value - min) / span));
|
|
45
|
+
const level = !thresholds ? "ok" : ratio >= thresholds.high ? optimum === "low" ? "danger" : "success" : ratio >= thresholds.low ? "warning" : optimum === "low" ? "success" : "danger";
|
|
46
|
+
const words = valueText ?? `${Math.round(ratio * 100)} %`;
|
|
47
|
+
const shares = (parts ?? []).map((p, i) => ({ ...p, i, ratio: Math.min(1, Math.max(0, p.value / span)), words: p.valueText ?? `${Math.round(p.value / span * 100)} %` }));
|
|
48
|
+
const a11y = parts ? { role: "group", "aria-label": label } : { role: "meter", "aria-label": label, "aria-valuemin": min, "aria-valuemax": max, "aria-valuenow": Math.min(max, Math.max(min, value)), "aria-valuetext": words };
|
|
49
|
+
const legend = parts && /* @__PURE__ */ jsx("ul", { className: s.legend(), children: shares.map((p) => /* @__PURE__ */ jsxs("li", { className: "flex items-center gap-1.5", children: [
|
|
50
|
+
/* @__PURE__ */ jsx("span", { "aria-hidden": true, className: [s.swatch(), PART_BG[p.i % PART_BG.length]].join(" ") }),
|
|
51
|
+
/* @__PURE__ */ jsx("span", { className: "text-fg", children: p.label }),
|
|
52
|
+
/* @__PURE__ */ jsx("span", { className: "tabular-nums", children: p.words })
|
|
53
|
+
] }, p.i)) });
|
|
54
|
+
if (variant === "ring") {
|
|
55
|
+
const r = 44;
|
|
56
|
+
let offset = 0;
|
|
57
|
+
const arcs = parts ? shares.map((p) => {
|
|
58
|
+
const arc = { cls: PART_STROKE[p.i % PART_STROKE.length], len: p.ratio * 100, start: offset };
|
|
59
|
+
offset += arc.len;
|
|
60
|
+
return arc;
|
|
61
|
+
}) : [{ cls: STROKE[level], len: ratio * 100, start: 0 }];
|
|
62
|
+
return /* @__PURE__ */ jsxs("div", { ...a11y, "data-level": parts ? void 0 : level, className: ["inline-flex flex-col items-center gap-2", className].filter(Boolean).join(" "), ...props, children: [
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: s.ring(), children: [
|
|
64
|
+
/* @__PURE__ */ jsxs("svg", { viewBox: "0 0 100 100", className: "h-full w-full -rotate-90", "aria-hidden": true, children: [
|
|
65
|
+
/* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r, fill: "none", strokeWidth: "9", className: "stroke-border-default" }),
|
|
66
|
+
arcs.map((a, i) => /* @__PURE__ */ jsx(
|
|
67
|
+
"circle",
|
|
68
|
+
{
|
|
69
|
+
cx: "50",
|
|
70
|
+
cy: "50",
|
|
71
|
+
r,
|
|
72
|
+
fill: "none",
|
|
73
|
+
strokeWidth: "9",
|
|
74
|
+
pathLength: 100,
|
|
75
|
+
strokeDasharray: `${Math.max(0, a.len - (parts ? 1 : 0))} ${100 - Math.max(0, a.len - (parts ? 1 : 0))}`,
|
|
76
|
+
strokeDashoffset: -a.start,
|
|
77
|
+
className: [a.cls, "transition-[stroke-dasharray] duration-700 motion-reduce:transition-none"].join(" ")
|
|
78
|
+
},
|
|
79
|
+
i
|
|
80
|
+
))
|
|
81
|
+
] }),
|
|
82
|
+
children !== void 0 && /* @__PURE__ */ jsx("div", { className: s.center(), children })
|
|
83
|
+
] }),
|
|
84
|
+
legend
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
return /* @__PURE__ */ jsxs("div", { ...a11y, "data-level": parts ? void 0 : level, className: s.root({ className }), ...props, children: [
|
|
88
|
+
showLabel && /* @__PURE__ */ jsxs("div", { "aria-hidden": true, className: s.header(), children: [
|
|
89
|
+
/* @__PURE__ */ jsx("span", { className: s.caption(), children: label }),
|
|
90
|
+
!parts && /* @__PURE__ */ jsx("span", { className: s.figure(), children: words })
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx("div", { "aria-hidden": true, className: s.track(), children: parts ? shares.map((p) => /* @__PURE__ */ jsx("span", { className: [s.fill(), PART_BG[p.i % PART_BG.length]].join(" "), style: { width: `${p.ratio * 100}%` } }, p.i)) : /* @__PURE__ */ jsx("span", { className: [s.fill(), BG[level]].join(" "), style: { width: `${ratio * 100}%` } }) }),
|
|
93
|
+
legend
|
|
94
|
+
] });
|
|
95
|
+
}
|
|
96
|
+
function MeterValue({ value, caption }) {
|
|
97
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
98
|
+
/* @__PURE__ */ jsx("span", { className: "font-display text-lg font-semibold text-fg tabular-nums", children: value }),
|
|
99
|
+
caption && /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wide text-fg-secondary", children: caption })
|
|
100
|
+
] });
|
|
101
|
+
}
|
|
102
|
+
export {
|
|
103
|
+
Meter,
|
|
104
|
+
MeterValue,
|
|
105
|
+
meter
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=meter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/meter/meter.tsx"],"sourcesContent":["// Server-safe. A measure within a known range — a quota, a balance, a share — as opposed to the progress of a task.\n// `role=\"meter\"`, its value in words; thresholds turn it to warning then danger (or the reverse when high is good);\n// split into parts (90 % to the creator, 10 % to the platform) it becomes a stacked bar or ring with its legend: the\n// text version of what it draws.\nimport type * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nexport const meter = tv({\n slots: {\n root: \"flex w-full flex-col gap-1.5\",\n header: \"flex items-baseline gap-2 text-xs\",\n caption: \"min-w-0 flex-1 truncate font-medium text-fg\",\n figure: \"shrink-0 tabular-nums text-fg-secondary\",\n track: \"relative flex h-2 w-full gap-0.5 overflow-hidden rounded-full bg-surface-3\",\n fill: \"h-full rounded-full transition-[width] duration-700 motion-reduce:transition-none\",\n legend: \"mt-1 flex flex-wrap gap-x-4 gap-y-1 text-xs text-fg-secondary\",\n swatch: \"inline-block h-2 w-2 shrink-0 rounded-full\",\n ring: \"relative inline-flex shrink-0 items-center justify-center\",\n center: \"absolute inset-0 flex flex-col items-center justify-center text-center\",\n },\n variants: {\n size: { sm: { track: \"h-1.5\", ring: \"h-14 w-14\" }, md: { ring: \"h-24 w-24\" }, lg: { track: \"h-3\", ring: \"h-36 w-36\" } },\n },\n defaultVariants: { size: \"md\" },\n});\n\n/** The colour of a fill: by tone (thresholds) or by part (the accent, a neutral, accent-2, a lighter neutral). */\nconst BG = { ok: \"bg-accent\", success: \"bg-success\", warning: \"bg-warning\", danger: \"bg-danger\" } as const;\nconst STROKE = { ok: \"stroke-accent\", success: \"stroke-success\", warning: \"stroke-warning\", danger: \"stroke-danger\" } as const;\nconst PART_BG = [\"bg-accent\", \"bg-fg-secondary\", \"bg-accent-2\", \"bg-border-strong\"];\nconst PART_STROKE = [\"stroke-accent\", \"stroke-fg-secondary\", \"stroke-accent-2\", \"stroke-border-strong\"];\n\nexport interface MeterPart {\n /** Its name (“To the creator”) — passed translated. */\n label: string;\n /** Its value, in the meter's unit. */\n value: number;\n /** Its value in words (“€9.00”), in the legend and for assistive technology; default: its percentage. */\n valueText?: string;\n}\n\nexport type MeterProps = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n /** The accessible name (“Storage”, “Split of a tip”) — passed translated; shown with `showLabel`. */\n label: string;\n /** The value, between `min` and `max` (ignored with `parts`). */\n value?: number;\n /**\n * The bottom of the range.\n * @default 0\n */\n min?: number;\n /**\n * The top of the range.\n * @default 100\n */\n max?: number;\n /** The value in words (“42 GB of 50 GB”) — passed translated; default: the percentage. */\n valueText?: string;\n /**\n * Ratios (0–1) where the tone changes: past `high` it is in danger, past `low` in warning — or the reverse with\n * `optimum=\"high\"` (a balance: the lower, the worse). Without thresholds the fill is the brand accent.\n */\n thresholds?: { readonly low: number; readonly high: number };\n /**\n * Which end is good.\n * @default \"low\"\n */\n optimum?: \"low\" | \"high\";\n /** Split into parts that add up to `max`: a stacked bar or ring, with its legend. */\n parts?: readonly MeterPart[];\n /**\n * bar · ring.\n * @default \"bar\"\n */\n variant?: \"bar\" | \"ring\";\n /**\n * sm · md · lg: the bar's thickness, the ring's diameter.\n * @default \"md\"\n */\n size?: \"sm\" | \"md\" | \"lg\";\n /** Shows the label and the value above the bar. */\n showLabel?: boolean;\n /** A ring's centre: the value, a word. */\n children?: React.ReactNode;\n};\n\n/** A measure within a range — a quota, a balance, a share — toned by thresholds or split into parts. */\nexport function Meter({\n label,\n value = 0,\n min = 0,\n max = 100,\n valueText,\n thresholds,\n optimum = \"low\",\n parts,\n variant = \"bar\",\n size = \"md\",\n showLabel,\n className,\n children,\n ...props\n}: MeterProps) {\n const s = meter({ size });\n const span = max - min || 1;\n const ratio = Math.min(1, Math.max(0, (value - min) / span));\n const level = !thresholds ? \"ok\" : ratio >= thresholds.high ? (optimum === \"low\" ? \"danger\" : \"success\") : ratio >= thresholds.low ? \"warning\" : optimum === \"low\" ? \"success\" : \"danger\";\n const words = valueText ?? `${Math.round(ratio * 100)} %`;\n const shares = (parts ?? []).map((p, i) => ({ ...p, i, ratio: Math.min(1, Math.max(0, p.value / span)), words: p.valueText ?? `${Math.round((p.value / span) * 100)} %` }));\n const a11y = parts\n ? { role: \"group\" as const, \"aria-label\": label }\n : { role: \"meter\" as const, \"aria-label\": label, \"aria-valuemin\": min, \"aria-valuemax\": max, \"aria-valuenow\": Math.min(max, Math.max(min, value)), \"aria-valuetext\": words };\n const legend = parts && (\n <ul className={s.legend()}>\n {shares.map((p) => (\n <li key={p.i} className=\"flex items-center gap-1.5\">\n <span aria-hidden className={[s.swatch(), PART_BG[p.i % PART_BG.length]].join(\" \")} />\n <span className=\"text-fg\">{p.label}</span>\n <span className=\"tabular-nums\">{p.words}</span>\n </li>\n ))}\n </ul>\n );\n\n if (variant === \"ring\") {\n const r = 44;\n let offset = 0;\n const arcs = parts\n ? shares.map((p) => {\n const arc = { cls: PART_STROKE[p.i % PART_STROKE.length]!, len: p.ratio * 100, start: offset };\n offset += arc.len;\n return arc;\n })\n : [{ cls: STROKE[level], len: ratio * 100, start: 0 }];\n return (\n <div {...a11y} data-level={parts ? undefined : level} className={[\"inline-flex flex-col items-center gap-2\", className].filter(Boolean).join(\" \")} {...props}>\n <div className={s.ring()}>\n <svg viewBox=\"0 0 100 100\" className=\"h-full w-full -rotate-90\" aria-hidden>\n <circle cx=\"50\" cy=\"50\" r={r} fill=\"none\" strokeWidth=\"9\" className=\"stroke-border-default\" />\n {arcs.map((a, i) => (\n <circle\n key={i}\n cx=\"50\"\n cy=\"50\"\n r={r}\n fill=\"none\"\n strokeWidth=\"9\"\n pathLength={100}\n strokeDasharray={`${Math.max(0, a.len - (parts ? 1 : 0))} ${100 - Math.max(0, a.len - (parts ? 1 : 0))}`}\n strokeDashoffset={-a.start}\n className={[a.cls, \"transition-[stroke-dasharray] duration-700 motion-reduce:transition-none\"].join(\" \")}\n />\n ))}\n </svg>\n {children !== undefined && <div className={s.center()}>{children}</div>}\n </div>\n {legend}\n </div>\n );\n }\n\n return (\n <div {...a11y} data-level={parts ? undefined : level} className={s.root({ className })} {...props}>\n {showLabel && (\n <div aria-hidden className={s.header()}>\n <span className={s.caption()}>{label}</span>\n {!parts && <span className={s.figure()}>{words}</span>}\n </div>\n )}\n <div aria-hidden className={s.track()}>\n {parts ? (\n shares.map((p) => <span key={p.i} className={[s.fill(), PART_BG[p.i % PART_BG.length]].join(\" \")} style={{ width: `${p.ratio * 100}%` }} />)\n ) : (\n <span className={[s.fill(), BG[level]].join(\" \")} style={{ width: `${ratio * 100}%` }} />\n )}\n </div>\n {legend}\n </div>\n );\n}\n\nexport interface MeterValueProps {\n /** The figure. */\n value: React.ReactNode;\n /** A word under it. */\n caption?: React.ReactNode;\n}\n\n/** For the ring's centre when it shows a figure and a word. */\nexport function MeterValue({ value, caption }: MeterValueProps) {\n return (\n <>\n <span className=\"font-display text-lg font-semibold text-fg tabular-nums\">{value}</span>\n {caption && <span className=\"text-[10px] uppercase tracking-wide text-fg-secondary\">{caption}</span>}\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
package/dist/motion.css
CHANGED
|
@@ -41,17 +41,31 @@
|
|
|
41
41
|
from { opacity: 0; transform: translateY(70%); filter: blur(6px); }
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/* RotatingWord:
|
|
44
|
+
/* RotatingWord: every alternative shares one grid cell from the first paint (the line keeps the width of the longest
|
|
45
|
+
word: no layout shift); the current one is visible and rolls in each time it becomes current. */
|
|
45
46
|
.kz-rotating {
|
|
46
47
|
display: inline-grid;
|
|
47
48
|
overflow: hidden;
|
|
48
49
|
padding-bottom: 0.08em;
|
|
49
50
|
vertical-align: bottom;
|
|
50
51
|
}
|
|
51
|
-
.kz-rotating >
|
|
52
|
+
.kz-rotating > * {
|
|
52
53
|
grid-area: 1 / 1;
|
|
53
54
|
white-space: nowrap;
|
|
54
55
|
}
|
|
56
|
+
.kz-rotating > [data-active="false"] {
|
|
57
|
+
visibility: hidden;
|
|
58
|
+
}
|
|
59
|
+
.kz-rotating > [data-active="true"] {
|
|
60
|
+
animation: kz-word-in 0.6s var(--kz-ease) both;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* A softer reveal for schemas and dense content: shorter travel, no blur. */
|
|
64
|
+
[data-reveal="soft"] {
|
|
65
|
+
transform: translateY(12px);
|
|
66
|
+
filter: none;
|
|
67
|
+
transition-duration: 0.6s;
|
|
68
|
+
}
|
|
55
69
|
|
|
56
70
|
/* Sheen across a primary action on hover. */
|
|
57
71
|
.kz-sheen {
|
|
@@ -140,6 +154,15 @@
|
|
|
140
154
|
@keyframes kz-dialog-in {
|
|
141
155
|
from { opacity: 0; transform: translateY(32px); }
|
|
142
156
|
}
|
|
157
|
+
/* Side panels and drawers slide in from their edge. */
|
|
158
|
+
.kz-dialog[data-placement="right"] { animation-name: kz-drawer-right; }
|
|
159
|
+
.kz-dialog[data-placement="left"] { animation-name: kz-drawer-left; }
|
|
160
|
+
@keyframes kz-drawer-right {
|
|
161
|
+
from { opacity: 0.4; transform: translateX(48px); }
|
|
162
|
+
}
|
|
163
|
+
@keyframes kz-drawer-left {
|
|
164
|
+
from { opacity: 0.4; transform: translateX(-48px); }
|
|
165
|
+
}
|
|
143
166
|
@media (min-width: 640px) {
|
|
144
167
|
@keyframes kz-dialog-in {
|
|
145
168
|
from { opacity: 0; transform: translateY(12px) scale(0.97); }
|
|
@@ -147,6 +170,14 @@
|
|
|
147
170
|
}
|
|
148
171
|
/* An indeterminate progress bar: a segment that crosses the track (Progress, variant bar). */
|
|
149
172
|
.kz-progress[data-state="indeterminate"] { animation: kz-progress-slide 1.4s var(--kz-ease) infinite; }
|
|
173
|
+
/* A segmented bar (Progress `segments`): the steps are cut out of the bar, whatever the surface behind it. */
|
|
174
|
+
.kz-progress-segmented {
|
|
175
|
+
mask-image: repeating-linear-gradient(90deg, #000 0 calc(100% / var(--kz-segments, 1) - 3px), transparent 0 calc(100% / var(--kz-segments, 1)));
|
|
176
|
+
}
|
|
177
|
+
/* A paused fill: diagonal stripes at rest. */
|
|
178
|
+
.kz-progress-paused {
|
|
179
|
+
background-image: repeating-linear-gradient(-45deg, color-mix(in oklab, var(--kz-accent) 85%, transparent) 0 6px, color-mix(in oklab, var(--kz-accent) 45%, transparent) 6px 12px);
|
|
180
|
+
}
|
|
150
181
|
@keyframes kz-progress-slide {
|
|
151
182
|
from { transform: translateX(-100%); }
|
|
152
183
|
to { transform: translateX(250%); }
|
|
@@ -205,9 +236,369 @@
|
|
|
205
236
|
opacity: 0.5;
|
|
206
237
|
}
|
|
207
238
|
|
|
239
|
+
/* ─── The conductor's states (MotionObserver) ───
|
|
240
|
+
- `[data-offscreen]` on a scope (`.kz-backdrop`, `.kz-iso`, `[data-motion-scope]`, a page's sections) while it is out
|
|
241
|
+
of view: every animation inside waits for it to come back — only what can be seen moves.
|
|
242
|
+
- `html[data-motion="settling"]` from the observer's mount until the page has loaded and settled (≈ 1.2 s after
|
|
243
|
+
`load`): the loops (`.kz-loop`, the backdrop's drift) hold their first frame, so nothing repaints the first screen
|
|
244
|
+
while it paints (LCP). Without the observer neither state is ever set: everything simply runs. */
|
|
245
|
+
[data-offscreen] :is(*, *::before, *::after):not(.kz-backdrop-media) {
|
|
246
|
+
animation-play-state: paused !important;
|
|
247
|
+
}
|
|
248
|
+
html[data-motion="settling"] :is(.kz-loop, .kz-backdrop-drift, .kz-loop::before, .kz-loop::after) {
|
|
249
|
+
animation-play-state: paused !important;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* The node of a signature icon (@krizaka/icons, `[data-node]`) lights up when the control that holds it is hovered or
|
|
253
|
+
focused; arrows lean toward where they lead. */
|
|
254
|
+
svg[data-kz-icon] [data-node] {
|
|
255
|
+
transform-box: fill-box;
|
|
256
|
+
transform-origin: center;
|
|
257
|
+
transition: transform 320ms var(--kz-ease), filter 320ms var(--kz-ease);
|
|
258
|
+
}
|
|
259
|
+
:is(a, button, [data-kz-lights]):is(:hover, :focus-visible) svg[data-kz-icon] [data-node] {
|
|
260
|
+
transform: scale(1.5);
|
|
261
|
+
filter: drop-shadow(0 0 3px var(--kz-accent, #196df5));
|
|
262
|
+
}
|
|
263
|
+
svg[data-kz-icon="ForwardIcon"],
|
|
264
|
+
svg[data-kz-icon="ExternalIcon"] {
|
|
265
|
+
transition: transform 220ms var(--kz-ease);
|
|
266
|
+
}
|
|
267
|
+
:is(a, button):is(:hover, :focus-visible) svg[data-kz-icon="ForwardIcon"] {
|
|
268
|
+
transform: translateX(3px);
|
|
269
|
+
}
|
|
270
|
+
:is(a, button):is(:hover, :focus-visible) svg[data-kz-icon="ExternalIcon"] {
|
|
271
|
+
transform: translate(2px, -2px);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Magnetic (`data-kz-magnetic`, driven by MotionObserver): the element leans a few pixels toward a fine pointer. */
|
|
275
|
+
[data-kz-magnetic] {
|
|
276
|
+
translate: var(--kz-mag-x, 0) var(--kz-mag-y, 0);
|
|
277
|
+
transition: translate 420ms var(--kz-ease);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* A figure that climbs (NumberTicker): an invisible copy of the final value shares the grid cell and holds the width. */
|
|
281
|
+
.kz-count {
|
|
282
|
+
display: inline-grid;
|
|
283
|
+
font-variant-numeric: tabular-nums;
|
|
284
|
+
}
|
|
285
|
+
.kz-count > * {
|
|
286
|
+
grid-area: 1 / 1;
|
|
287
|
+
}
|
|
288
|
+
.kz-count[data-align="end"] {
|
|
289
|
+
justify-items: end;
|
|
290
|
+
}
|
|
291
|
+
.kz-count-ghost {
|
|
292
|
+
visibility: hidden;
|
|
293
|
+
}
|
|
294
|
+
/* Inside gradient text every box carries the gradient itself: an inline-grid is not clipped with its parent's text. */
|
|
295
|
+
.kz-count,
|
|
296
|
+
.kz-count > *,
|
|
297
|
+
.kz-count-roll,
|
|
298
|
+
.kz-count-digit {
|
|
299
|
+
background: inherit;
|
|
300
|
+
-webkit-background-clip: inherit;
|
|
301
|
+
background-clip: inherit;
|
|
302
|
+
}
|
|
303
|
+
/* Rolling digits (NumberTicker on change): each digit is a column 0–9 that slides to its value. */
|
|
304
|
+
.kz-count-roll {
|
|
305
|
+
display: inline-flex;
|
|
306
|
+
user-select: none;
|
|
307
|
+
}
|
|
308
|
+
.kz-count-digit {
|
|
309
|
+
display: inline-block;
|
|
310
|
+
height: 1lh;
|
|
311
|
+
overflow: hidden;
|
|
312
|
+
}
|
|
313
|
+
.kz-count-digit > span {
|
|
314
|
+
display: flex;
|
|
315
|
+
flex-direction: column;
|
|
316
|
+
transform: translateY(calc(var(--kz-digit, 0) * -10%));
|
|
317
|
+
transition: transform 0.9s var(--kz-ease);
|
|
318
|
+
}
|
|
319
|
+
.kz-count-digit > span > span {
|
|
320
|
+
height: 1lh;
|
|
321
|
+
}
|
|
322
|
+
.kz-count[data-trend="up"] .kz-count-roll {
|
|
323
|
+
animation: kz-count-flash-up 1.2s var(--kz-ease);
|
|
324
|
+
}
|
|
325
|
+
.kz-count[data-trend="down"] .kz-count-roll {
|
|
326
|
+
animation: kz-count-flash-down 1.2s var(--kz-ease);
|
|
327
|
+
}
|
|
328
|
+
@keyframes kz-count-flash-up {
|
|
329
|
+
from { color: var(--kz-success-text, currentColor); }
|
|
330
|
+
}
|
|
331
|
+
@keyframes kz-count-flash-down {
|
|
332
|
+
from { color: var(--kz-danger-text, currentColor); }
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/* ─── Marquee: a band that slides at a speed, pauses for the reader, and is a still row under reduced motion ─── */
|
|
336
|
+
.kz-band {
|
|
337
|
+
--kz-band-gap: 2.5rem;
|
|
338
|
+
}
|
|
339
|
+
.kz-band[data-fade] > .kz-band-viewport {
|
|
340
|
+
mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
|
|
341
|
+
}
|
|
342
|
+
.kz-band[data-direction="right"] .kz-marquee {
|
|
343
|
+
animation-direction: reverse;
|
|
344
|
+
}
|
|
345
|
+
.kz-band:is([data-paused], :hover, :focus-within) .kz-marquee {
|
|
346
|
+
animation-play-state: paused;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* ─── GlowCard: a bloom that follows the pointer, a ring of the brand gradient that turns ─── */
|
|
350
|
+
@property --kz-glow-angle {
|
|
351
|
+
syntax: "<angle>";
|
|
352
|
+
inherits: false;
|
|
353
|
+
initial-value: 135deg;
|
|
354
|
+
}
|
|
355
|
+
.kz-glow {
|
|
356
|
+
--kz-glow-x: 30%;
|
|
357
|
+
--kz-glow-y: 0%;
|
|
358
|
+
}
|
|
359
|
+
/* The ring: the brand gradient, cut to the border (mask), faint at rest, bright under the pointer or the focus. */
|
|
360
|
+
.kz-glow:is([data-glow="border"], [data-glow="both"])::before {
|
|
361
|
+
content: "";
|
|
362
|
+
position: absolute;
|
|
363
|
+
inset: -1px;
|
|
364
|
+
z-index: -1;
|
|
365
|
+
padding: 1px;
|
|
366
|
+
border-radius: inherit;
|
|
367
|
+
background: conic-gradient(from var(--kz-glow-angle), transparent 0deg, var(--kz-accent) 70deg, var(--kz-accent-2, var(--kz-accent)) 140deg, transparent 210deg, transparent 360deg);
|
|
368
|
+
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
|
369
|
+
-webkit-mask-composite: xor;
|
|
370
|
+
mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
|
|
371
|
+
opacity: 0.35;
|
|
372
|
+
transition: opacity 0.4s var(--kz-ease);
|
|
373
|
+
pointer-events: none;
|
|
374
|
+
}
|
|
375
|
+
.kz-glow[data-alive]::before,
|
|
376
|
+
.kz-glow:is(:hover, :focus-within)::before {
|
|
377
|
+
animation: kz-glow-turn 6s linear infinite;
|
|
378
|
+
}
|
|
379
|
+
.kz-glow:is(:hover, :focus-within)::before {
|
|
380
|
+
opacity: 1;
|
|
381
|
+
}
|
|
382
|
+
/* The bloom: under the pointer, inside the card. */
|
|
383
|
+
.kz-glow:is([data-glow="spotlight"], [data-glow="both"])::after {
|
|
384
|
+
content: "";
|
|
385
|
+
position: absolute;
|
|
386
|
+
inset: 0;
|
|
387
|
+
z-index: -1;
|
|
388
|
+
border-radius: inherit;
|
|
389
|
+
background: radial-gradient(360px circle at var(--kz-glow-x) var(--kz-glow-y), color-mix(in oklab, var(--kz-accent) 16%, transparent), transparent 60%);
|
|
390
|
+
opacity: 0;
|
|
391
|
+
transition: opacity 0.4s var(--kz-ease);
|
|
392
|
+
pointer-events: none;
|
|
393
|
+
}
|
|
394
|
+
.kz-glow:is(:hover, :focus-within)::after {
|
|
395
|
+
opacity: 1;
|
|
396
|
+
}
|
|
397
|
+
@keyframes kz-glow-turn {
|
|
398
|
+
to { --kz-glow-angle: 495deg; }
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/* ─── Toasts: a hairline at the bottom counts the time left, and pauses with the toast ─── */
|
|
402
|
+
.kz-toast::after {
|
|
403
|
+
content: "";
|
|
404
|
+
position: absolute;
|
|
405
|
+
inset: auto 0 0 0;
|
|
406
|
+
height: 2px;
|
|
407
|
+
transform-origin: left;
|
|
408
|
+
background: linear-gradient(90deg, var(--kz-accent), var(--kz-accent-2, var(--kz-accent)));
|
|
409
|
+
opacity: 0.7;
|
|
410
|
+
animation: kz-toast-time var(--kz-toast-duration, 4000ms) linear forwards;
|
|
411
|
+
}
|
|
412
|
+
.kz-toast:is([data-expanded="true"], :hover, :focus-within)::after {
|
|
413
|
+
animation-play-state: paused;
|
|
414
|
+
}
|
|
415
|
+
.kz-toast[data-type="loading"]::after {
|
|
416
|
+
display: none;
|
|
417
|
+
}
|
|
418
|
+
@keyframes kz-toast-time {
|
|
419
|
+
to { transform: scaleX(0); }
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/* ─── Skeletons: one reflection of the brand light crosses every skeleton of the page at once ─── */
|
|
423
|
+
.kz-skeleton,
|
|
424
|
+
.kz-skeleton-shape :is(h1, h2, h3, h4, h5, h6, p, li, dt, dd, label, small, strong, b, em, time, a, button, img, svg, video, picture, canvas, [data-skeleton]) {
|
|
425
|
+
background-image: linear-gradient(100deg, transparent 30%, color-mix(in oklab, var(--kz-accent) 14%, transparent) 46%, color-mix(in oklab, var(--kz-text-primary) 8%, transparent) 50%, transparent 66%);
|
|
426
|
+
background-size: 200vw 100%;
|
|
427
|
+
background-attachment: fixed;
|
|
428
|
+
background-repeat: no-repeat;
|
|
429
|
+
animation: kz-skeleton-sweep 2.2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
430
|
+
}
|
|
431
|
+
@keyframes kz-skeleton-sweep {
|
|
432
|
+
from { background-position: 100vw 0; }
|
|
433
|
+
to { background-position: -100vw 0; }
|
|
434
|
+
}
|
|
435
|
+
/* SkeletonShape: the real component's text, media and icons become shapes in place (its layout untouched). */
|
|
436
|
+
.kz-skeleton-shape { pointer-events: none; user-select: none; }
|
|
437
|
+
.kz-skeleton-shape :is(h1, h2, h3, h4, h5, h6, p, li, dt, dd, label, small, strong, b, em, time, a, button, [data-skeleton]) {
|
|
438
|
+
color: transparent !important;
|
|
439
|
+
}
|
|
440
|
+
/* Text becomes one bar per line, as tall as the letters, as wide as the words. */
|
|
441
|
+
.kz-skeleton-shape :is(h1, h2, h3, h4, h5, h6, p, li, dt, dd, label, small, time) {
|
|
442
|
+
width: fit-content;
|
|
443
|
+
max-width: 100%;
|
|
444
|
+
-webkit-mask-image: repeating-linear-gradient(to bottom, transparent 0 0.18lh, #000 0.18lh 0.82lh, transparent 0.82lh 1lh);
|
|
445
|
+
mask-image: repeating-linear-gradient(to bottom, transparent 0 0.18lh, #000 0.18lh 0.82lh, transparent 0.82lh 1lh);
|
|
446
|
+
background-color: var(--kz-surface-3) !important;
|
|
447
|
+
border-radius: 3px;
|
|
448
|
+
}
|
|
449
|
+
.kz-skeleton-shape :is(a, button, [data-skeleton]) {
|
|
450
|
+
background-color: var(--kz-surface-3) !important;
|
|
451
|
+
}
|
|
452
|
+
.kz-skeleton-shape :is(img, svg, video, picture, canvas) {
|
|
453
|
+
background-color: var(--kz-surface-3);
|
|
454
|
+
opacity: 1;
|
|
455
|
+
}
|
|
456
|
+
.kz-skeleton-shape :is(img, video, picture, canvas) { object-position: -9999px; }
|
|
457
|
+
.kz-skeleton-shape svg * { visibility: hidden; }
|
|
458
|
+
.kz-skeleton-shape :is(p, li) :is(strong, b, em, a, time) { background: none; }
|
|
459
|
+
|
|
460
|
+
/* ─── The loader glyph (Spinner, Loader, Button loading) ───
|
|
461
|
+
A segment of light travels around a hexagon while the node breathes; determinate, the trace grows to its value; done,
|
|
462
|
+
the trace closes and a check or a cross draws itself. */
|
|
463
|
+
.kz-loader-trace {
|
|
464
|
+
stroke-dasharray: 24 76;
|
|
465
|
+
animation: kz-loader-trace 1.4s linear infinite;
|
|
466
|
+
}
|
|
467
|
+
[data-progress] > .kz-loader-trace {
|
|
468
|
+
animation: none;
|
|
469
|
+
transition: stroke-dasharray 0.6s var(--kz-ease);
|
|
470
|
+
}
|
|
471
|
+
.kz-loader-node {
|
|
472
|
+
transform-box: fill-box;
|
|
473
|
+
transform-origin: center;
|
|
474
|
+
animation: kz-loader-node 1.4s var(--kz-ease) infinite;
|
|
475
|
+
}
|
|
476
|
+
.kz-loader-mark {
|
|
477
|
+
stroke-dasharray: 20;
|
|
478
|
+
animation: kz-loader-draw 0.5s var(--kz-ease) 0.12s backwards;
|
|
479
|
+
}
|
|
480
|
+
@keyframes kz-loader-trace { to { stroke-dashoffset: -100; } }
|
|
481
|
+
@keyframes kz-loader-node { 50% { transform: scale(0.62); opacity: 0.55; } }
|
|
482
|
+
@keyframes kz-loader-draw { from { stroke-dashoffset: 20; } }
|
|
483
|
+
/* Once: a ring of the status colour opens around what just succeeded or failed; a failure shakes its head. */
|
|
484
|
+
[data-kz-status="success"] { animation: kz-status-ring 0.9s var(--kz-ease); --kz-status: var(--kz-success); }
|
|
485
|
+
[data-kz-status="error"] { animation: kz-status-ring 0.9s var(--kz-ease), kz-status-shake 0.42s var(--kz-ease); --kz-status: var(--kz-danger); }
|
|
486
|
+
@keyframes kz-status-ring {
|
|
487
|
+
from { box-shadow: 0 0 0 0 color-mix(in oklab, var(--kz-status, currentColor) 55%, transparent); }
|
|
488
|
+
to { box-shadow: 0 0 0 10px transparent; }
|
|
489
|
+
}
|
|
490
|
+
@keyframes kz-status-shake {
|
|
491
|
+
20% { translate: -3px 0; }
|
|
492
|
+
45% { translate: 3px 0; }
|
|
493
|
+
70% { translate: -2px 0; }
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/* ─── The isometric kit (@krizaka/ui/iso) ───
|
|
497
|
+
Objects built from the Krizaka vocabulary — hexagons, cut corners, the node — extruded in isometric projection and lit
|
|
498
|
+
from inside in the brand accent (a `.brand-<id>` ancestor re-points it). Faces read the surfaces, edges the accent
|
|
499
|
+
text: both themes. Motion: stages that stack once at the entrance, a dome that breathes, light that flows along the
|
|
500
|
+
links, satellites that float; the pointer lifts an object and shows its label. */
|
|
501
|
+
/* Unlayered CSS beats Tailwind's layers: the kit sets no size, the app's classes do (`w-full max-w-xl`). */
|
|
502
|
+
.kz-iso {
|
|
503
|
+
overflow: visible;
|
|
504
|
+
}
|
|
505
|
+
/* Light, glass and floor never catch the pointer: the objects under the dome stay reachable. */
|
|
506
|
+
:is(.kz-iso-floor, .kz-iso-rim, .kz-iso-dome, .kz-iso-dome-sheen, .kz-iso-link, .kz-iso-particle, .kz-iso-link-label, .kz-iso-shadow, .kz-iso-tether, .kz-iso-breathe) {
|
|
507
|
+
pointer-events: none;
|
|
508
|
+
}
|
|
509
|
+
.kz-iso-floor { fill: none; stroke: var(--kz-border-strong); stroke-width: 0.8; }
|
|
510
|
+
.kz-iso-face { stroke: color-mix(in oklab, var(--kz-accent-text) 40%, transparent); stroke-width: 0.8; stroke-linejoin: round; }
|
|
511
|
+
.kz-iso-base .kz-iso-top { fill: var(--kz-surface-3); }
|
|
512
|
+
.kz-iso-base .kz-iso-left { fill: var(--kz-surface-2); }
|
|
513
|
+
.kz-iso-base .kz-iso-right { fill: var(--kz-surface-1); }
|
|
514
|
+
.kz-iso-base .kz-iso-face { stroke: color-mix(in oklab, var(--kz-accent-text) 24%, var(--kz-border-default)); }
|
|
515
|
+
.kz-iso-accent .kz-iso-top { fill: color-mix(in oklab, var(--kz-accent) 72%, var(--kz-surface-3)); }
|
|
516
|
+
.kz-iso-accent .kz-iso-left { fill: color-mix(in oklab, var(--kz-accent) 50%, var(--kz-surface-1)); }
|
|
517
|
+
.kz-iso-accent .kz-iso-right { fill: color-mix(in oklab, var(--kz-accent) 32%, var(--kz-surface-0)); }
|
|
518
|
+
.kz-iso-accent2 .kz-iso-top { fill: color-mix(in oklab, var(--kz-accent-2) 70%, var(--kz-surface-3)); }
|
|
519
|
+
.kz-iso-accent2 .kz-iso-left { fill: color-mix(in oklab, var(--kz-accent) 62%, var(--kz-surface-1)); }
|
|
520
|
+
.kz-iso-accent2 .kz-iso-right { fill: color-mix(in oklab, var(--kz-accent-2) 40%, var(--kz-surface-0)); }
|
|
521
|
+
.kz-iso-glass .kz-iso-face { fill: color-mix(in oklab, var(--kz-accent) 14%, var(--kz-surface-1)); fill-opacity: 0.92; }
|
|
522
|
+
.kz-iso-glass .kz-iso-top { fill: color-mix(in oklab, var(--kz-accent) 10%, var(--kz-surface-2)); }
|
|
523
|
+
.kz-iso-strip { fill: none; stroke: var(--kz-accent-text); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 2 7; opacity: 0.85; }
|
|
524
|
+
.kz-iso-strip.kz-loop { animation: kz-iso-blink 2.8s steps(2, jump-none) infinite; animation-delay: calc(var(--kz-iso-i, 0) * -0.7s); }
|
|
525
|
+
.kz-iso-glyph { fill: none; stroke: var(--kz-on-accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; opacity: 0.9; }
|
|
526
|
+
.kz-iso-base .kz-iso-glyph, .kz-iso-glass .kz-iso-glyph { stroke: var(--kz-text-secondary); }
|
|
527
|
+
.kz-iso-glyph-fill { fill: var(--kz-on-accent); opacity: 0.9; }
|
|
528
|
+
.kz-iso-base .kz-iso-glyph-fill, .kz-iso-glass .kz-iso-glyph-fill { fill: var(--kz-text-secondary); }
|
|
529
|
+
.kz-iso-node { fill: var(--kz-accent-text); }
|
|
530
|
+
.kz-iso-shadow { fill: color-mix(in oklab, var(--kz-accent) 9%, transparent); stroke: color-mix(in oklab, var(--kz-accent-text) 22%, transparent); stroke-width: 0.6; }
|
|
531
|
+
.kz-iso-tether { stroke: color-mix(in oklab, var(--kz-accent-text) 45%, transparent); stroke-width: 1; stroke-dasharray: 1 4; stroke-linecap: round; }
|
|
532
|
+
.kz-iso-glow-stop { stop-color: var(--kz-accent); }
|
|
533
|
+
.kz-iso-rim { fill: color-mix(in oklab, var(--kz-accent) 6%, transparent); stroke: color-mix(in oklab, var(--kz-accent-text) 30%, transparent); stroke-width: 1; }
|
|
534
|
+
.kz-iso-dome { fill: color-mix(in oklab, var(--kz-accent) 5%, transparent); stroke: color-mix(in oklab, var(--kz-accent-text) 34%, transparent); stroke-width: 1.2; }
|
|
535
|
+
.kz-iso-dome-sheen { fill: none; stroke: color-mix(in oklab, var(--kz-accent-text) 55%, transparent); stroke-width: 2; stroke-linecap: round; stroke-dasharray: 40 400; }
|
|
536
|
+
.kz-iso-dome-sheen.kz-loop { animation: kz-iso-sheen 9s var(--kz-ease) infinite; }
|
|
537
|
+
.kz-iso-link { fill: none; stroke: var(--kz-accent-text); stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 2 8; opacity: 0.7; }
|
|
538
|
+
.kz-iso-link.kz-loop { animation: kz-iso-flow 2.4s linear infinite; }
|
|
539
|
+
.kz-iso-link[data-direction="in"].kz-loop { animation-direction: reverse; }
|
|
540
|
+
.kz-iso-particle {
|
|
541
|
+
fill: var(--kz-accent-text);
|
|
542
|
+
offset-rotate: 0deg;
|
|
543
|
+
offset-distance: var(--kz-iso-at, 50%);
|
|
544
|
+
}
|
|
545
|
+
.kz-iso-particle.kz-loop {
|
|
546
|
+
animation: kz-iso-travel var(--kz-iso-dur, 3.6s) cubic-bezier(0.45, 0, 0.55, 1) infinite;
|
|
547
|
+
animation-delay: var(--kz-iso-delay, 0s);
|
|
548
|
+
}
|
|
549
|
+
.kz-iso-link-label rect { fill: var(--kz-surface-1); stroke: color-mix(in oklab, var(--kz-accent-text) 45%, var(--kz-border-default)); }
|
|
550
|
+
.kz-iso-link-label text, .kz-iso-tip text {
|
|
551
|
+
fill: var(--kz-text-primary);
|
|
552
|
+
font: 600 12px/1 var(--kz-font-sans, system-ui), system-ui, sans-serif;
|
|
553
|
+
letter-spacing: 0.01em;
|
|
554
|
+
}
|
|
555
|
+
.kz-iso-link-label .kz-iso-strong { fill: var(--kz-accent-text); font-weight: 700; }
|
|
556
|
+
.kz-iso-breathe.kz-loop { animation: kz-iso-breathe 5s ease-in-out infinite alternate; }
|
|
557
|
+
.kz-iso-float.kz-loop { animation: kz-iso-float 8s ease-in-out infinite alternate; animation-delay: calc(var(--kz-iso-i, 0) * -2.3s); }
|
|
558
|
+
/* `animated={false}` on a scene: the still frame, as prefers-reduced-motion shows it. */
|
|
559
|
+
.kz-iso[data-animated="false"] :is(.kz-loop, .kz-iso-rise) { animation: none; }
|
|
560
|
+
/* Entrance: each object rises into place once, in order (--kz-iso-i), when its scene first shows. */
|
|
561
|
+
.kz-iso-rise { animation: kz-iso-rise 0.9s var(--kz-ease) backwards; animation-delay: calc(var(--kz-iso-i, 0) * 110ms + 120ms); }
|
|
562
|
+
/* The pointer (or the focus, in an interactive scene) lifts an object and shows its label. */
|
|
563
|
+
.kz-iso-item { outline: none; }
|
|
564
|
+
.kz-iso-item > .kz-iso-lift { transition: translate 0.45s var(--kz-ease), filter 0.45s var(--kz-ease); }
|
|
565
|
+
.kz-iso-tip { opacity: 0; transition: opacity 0.3s var(--kz-ease), translate 0.45s var(--kz-ease); pointer-events: none; }
|
|
566
|
+
.kz-iso-leader { stroke: var(--kz-accent-text); stroke-width: 1; }
|
|
567
|
+
.kz-iso-tip rect { fill: var(--kz-surface-1); stroke: var(--kz-border-strong); }
|
|
568
|
+
@media (hover: hover) {
|
|
569
|
+
.kz-iso-item:hover > .kz-iso-lift { translate: 0 -8px; filter: drop-shadow(0 10px 14px color-mix(in oklab, var(--kz-accent) 35%, transparent)); }
|
|
570
|
+
.kz-iso-item:hover > .kz-iso-tip { opacity: 1; translate: 0 -8px; }
|
|
571
|
+
}
|
|
572
|
+
.kz-iso-item:focus-visible > .kz-iso-lift { translate: 0 -8px; filter: drop-shadow(0 0 6px var(--kz-ring, currentColor)); }
|
|
573
|
+
.kz-iso-item:focus-visible > .kz-iso-tip { opacity: 1; translate: 0 -8px; }
|
|
574
|
+
@keyframes kz-iso-rise { from { opacity: 0; transform: translateY(-34px); } }
|
|
575
|
+
@keyframes kz-iso-flow { to { stroke-dashoffset: -40; } }
|
|
576
|
+
@keyframes kz-iso-travel {
|
|
577
|
+
0% { offset-distance: 0%; opacity: 0; }
|
|
578
|
+
12% { opacity: 1; }
|
|
579
|
+
88% { opacity: 1; }
|
|
580
|
+
100% { offset-distance: 100%; opacity: 0; }
|
|
581
|
+
}
|
|
582
|
+
@keyframes kz-iso-float { from { transform: translateY(0); } to { transform: translateY(-9px); } }
|
|
583
|
+
@keyframes kz-iso-breathe { from { opacity: 0.6; } to { opacity: 1; } }
|
|
584
|
+
@keyframes kz-iso-blink { 50% { opacity: 0.35; } }
|
|
585
|
+
@keyframes kz-iso-sheen { 0% { stroke-dashoffset: 40; } 60%, 100% { stroke-dashoffset: -400; } }
|
|
586
|
+
|
|
208
587
|
@media (prefers-reduced-motion: reduce) {
|
|
209
|
-
.kz-page, .kz-word, .kz-gradient-text, .kz-marquee, .kz-backdrop-drift, .kz-overlay, .kz-dialog, .kz-pop, .kz-fade, .kz-progress
|
|
588
|
+
.kz-page, .kz-word, .kz-gradient-text, .kz-marquee, .kz-backdrop-drift, .kz-overlay, .kz-dialog, .kz-pop, .kz-fade, .kz-progress,
|
|
589
|
+
.kz-skeleton, .kz-skeleton-shape *, .kz-toast::after, .kz-glow::before,
|
|
590
|
+
.kz-rotating > *, .kz-loop, .kz-iso-rise, .kz-count-roll, .kz-loader-trace, .kz-loader-node, .kz-loader-mark,
|
|
591
|
+
[data-kz-status] { animation: none !important; }
|
|
592
|
+
/* At rest, the trace stands still where a reader expects it: a third of the hexagon from the top. */
|
|
593
|
+
.kz-loader-trace:not([stroke-dasharray]) { stroke-dashoffset: -8; }
|
|
210
594
|
[data-reveal] { opacity: 1; transform: none; filter: none; transition: none; }
|
|
211
595
|
.kz-sheen::after { display: none; }
|
|
596
|
+
/* The band stands still and scrolls by hand; its copy goes. */
|
|
597
|
+
.kz-band > .kz-band-viewport { overflow-x: auto; scrollbar-width: thin; }
|
|
598
|
+
.kz-band-copy { display: none !important; }
|
|
212
599
|
.kz-lift, .kz-lift:hover { transform: none; transition: none; }
|
|
600
|
+
[data-kz-magnetic] { translate: none; }
|
|
601
|
+
.kz-count-digit > span { transition: none; }
|
|
602
|
+
/* The still frame is a composed picture, not a cut animation: particles rest along their link, labels show. */
|
|
603
|
+
.kz-iso-item > .kz-iso-lift, .kz-iso-tip { transition: none; }
|
|
213
604
|
}
|
package/dist/motion.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface MotionObserverProps {
|
|
4
|
+
/**
|
|
5
|
+
* Hold the loops of the page (`.kz-loop`, the backdrop's drift) still until the page has loaded and settled
|
|
6
|
+
* (`html[data-motion="settling"]` → `"ready"`, about 1.2 s after `load`): nothing repaints the first screen while it
|
|
7
|
+
* paints.
|
|
8
|
+
* @default true
|
|
9
|
+
*/
|
|
10
|
+
settle?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Pause every animation of a scope while it is off screen (`data-offscreen` on `.kz-backdrop`, `.kz-iso`,
|
|
13
|
+
* `[data-motion-scope]` and the page's sections).
|
|
14
|
+
* @default true
|
|
15
|
+
*/
|
|
16
|
+
pauseOffscreen?: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The Krizaka motion conductor. Mount it once at the root of the app; it renders nothing and keeps no animation frame
|
|
20
|
+
* running. It reveals every `[data-reveal]` element once as it enters the viewport (including elements added later:
|
|
21
|
+
* client navigation needs nothing more), pauses what is off screen, lets the first screen settle before its loops
|
|
22
|
+
* start, feeds the pointer to `.kz-spotlight` cards (`--spot-x`, `--spot-y`) and to `[data-kz-magnetic]` elements
|
|
23
|
+
* (`Button magnetic`). Under prefers-reduced-motion everything is revealed at once and nothing follows the pointer.
|
|
24
|
+
*/
|
|
25
|
+
declare function MotionObserver({ settle, pauseOffscreen }?: MotionObserverProps): null;
|
|
26
|
+
|
|
27
|
+
interface RotatingWordProps {
|
|
28
|
+
/** The alternatives, passed translated; the first one is what the server renders. */
|
|
29
|
+
words: readonly string[];
|
|
30
|
+
/**
|
|
31
|
+
* Milliseconds each word stays.
|
|
32
|
+
* @default 2600
|
|
33
|
+
*/
|
|
34
|
+
interval?: number;
|
|
35
|
+
/** Classes for every word (a colour, gradient text). */
|
|
36
|
+
className?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A word that rolls through alternatives — the Krizaka headline signature. Every word shares one grid cell from the
|
|
40
|
+
* first paint, so the line keeps the width of the longest one (no layout shift); the current one rolls in. The server
|
|
41
|
+
* render shows the first word; it stays put under prefers-reduced-motion and while the tab is hidden. Decorative
|
|
42
|
+
* (`aria-hidden`): give the heading a stable accessible label.
|
|
43
|
+
*/
|
|
44
|
+
declare function RotatingWord({ words, interval, className }: RotatingWordProps): React.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { MotionObserver, type MotionObserverProps, RotatingWord, type RotatingWordProps };
|
package/dist/motion.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|