@krizaka/ui 2.0.0-beta.3 → 2.0.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +70 -6
  2. package/dist/{button-8La7l0V4.d.ts → button-D5aSsmxX.d.ts} +3 -3
  3. package/dist/button.d.ts +3 -3
  4. package/dist/button.js +1 -1
  5. package/dist/button.js.map +1 -1
  6. package/dist/card.js +1 -1
  7. package/dist/card.js.map +1 -1
  8. package/dist/{chunk-ZUD4U22H.js → chunk-6DJ6SQY3.js} +2 -2
  9. package/dist/chunk-6DJ6SQY3.js.map +1 -0
  10. package/dist/{chunk-3X5MVH54.js → chunk-IUGBKMJC.js} +2 -2
  11. package/dist/command.js +2 -2
  12. package/dist/confirm-button.d.ts +1 -1
  13. package/dist/confirm-button.js +1 -1
  14. package/dist/dialog.js +2 -2
  15. package/dist/dropdown-menu.js +1 -1
  16. package/dist/dropdown-menu.js.map +1 -1
  17. package/dist/index.d.ts +9 -2
  18. package/dist/index.js +90 -65
  19. package/dist/index.js.map +1 -1
  20. package/dist/motion.css +52 -2
  21. package/dist/native.d.ts +498 -5
  22. package/dist/native.js +1274 -38
  23. package/dist/native.js.map +1 -1
  24. package/dist/section-backdrop.d.ts +75 -0
  25. package/dist/section-backdrop.js +27 -0
  26. package/dist/section-backdrop.js.map +1 -0
  27. package/dist/theme.d.ts +1 -1
  28. package/dist/theme.js +1 -1
  29. package/package.json +33 -7
  30. package/registry/button.json +1 -1
  31. package/registry/card.json +1 -1
  32. package/registry/demos/section-backdrop.d.ts +5 -0
  33. package/registry/demos/section-backdrop.js +14 -0
  34. package/registry/demos/section-backdrop.tsx +10 -0
  35. package/registry/dropdown-menu.json +1 -1
  36. package/registry/index.json +10 -1
  37. package/registry/section-backdrop.json +73 -0
  38. package/dist/chunk-ZUD4U22H.js.map +0 -1
  39. /package/dist/{chunk-3X5MVH54.js.map → chunk-IUGBKMJC.js.map} +0 -0
package/dist/native.js CHANGED
@@ -1,7 +1,871 @@
1
+ // src/countdown/core.ts
2
+ import { useSyncExternalStore } from "react";
3
+ var listeners = /* @__PURE__ */ new Set();
4
+ var timer = null;
5
+ function subscribe(listener) {
6
+ listeners.add(listener);
7
+ timer ??= setInterval(() => listeners.forEach((l) => l()), 1e3);
8
+ return () => {
9
+ listeners.delete(listener);
10
+ if (listeners.size === 0 && timer) {
11
+ clearInterval(timer);
12
+ timer = null;
13
+ }
14
+ };
15
+ }
16
+ var nowSecond = () => Math.floor(Date.now() / 1e3) * 1e3;
17
+ function useCountdown(target, skewMs = 0) {
18
+ const now = useSyncExternalStore(subscribe, nowSecond, nowSecond);
19
+ return Math.max(0, new Date(target).getTime() - (now + skewMs));
20
+ }
21
+ function splitDuration(ms) {
22
+ const total = Math.max(0, Math.floor(ms / 1e3));
23
+ return { d: Math.floor(total / 86400), h: Math.floor(total % 86400 / 3600), m: Math.floor(total % 3600 / 60), s: total % 60 };
24
+ }
25
+ function countdownParts(ms, units) {
26
+ const { d, h, m, s } = splitDuration(ms);
27
+ return d > 0 ? [[d, units.d], [h, units.h], [m, units.m]] : [[h, units.h], [m, units.m], [s, units.s]];
28
+ }
29
+
30
+ // src/native/avatar.tsx
31
+ import * as React2 from "react";
32
+ import { Image, StyleSheet, Text, View } from "react-native";
33
+
34
+ // ../tokens/dist/native.js
35
+ var themes = Object.freeze({ dark: Object.freeze({
36
+ "surface0": "#0c0c0e",
37
+ "surface1": "#161618",
38
+ "surface2": "#1f1f23",
39
+ "surface3": "#2a2a2d",
40
+ "media": "#1b1b1d",
41
+ "borderSubtle": "rgba(255,255,255,0.06)",
42
+ "borderDefault": "rgba(255,255,255,0.1)",
43
+ "borderStrong": "rgba(255,255,255,0.16)",
44
+ "textPrimary": "#f5f5f5",
45
+ "textSecondary": "#a0a0a7",
46
+ "textMuted": "#73737d",
47
+ "textOnMedia": "#ffffff",
48
+ "accent": "#196df5",
49
+ "accentHover": "#0e5bd8",
50
+ "accentSoft": "rgba(25,109,245,0.1)",
51
+ "accentText": "#629cf8",
52
+ "accent2": "#196df5",
53
+ "onAccent": "#ffffff",
54
+ "ring": "#196df5",
55
+ "brandGradientFrom": "#0e1525",
56
+ "brandGradientVia": "#0e0f16",
57
+ "brandGradientTo": "#0c0c0e",
58
+ "success": "#10b77f",
59
+ "warning": "#f59f0a",
60
+ "danger": "#ef4343",
61
+ "info": "#196df5",
62
+ "scrim": "rgba(0,0,0,0.6)",
63
+ "scrimStrong": "rgba(0,0,0,0.8)",
64
+ "overlay": "rgba(0,0,0,0.7)"
65
+ }), light: Object.freeze({
66
+ "surface0": "#fafafa",
67
+ "surface1": "#ffffff",
68
+ "surface2": "#f1f1f3",
69
+ "surface3": "#e4e4e7",
70
+ "media": "#e9e9ec",
71
+ "borderSubtle": "rgba(0,0,0,0.06)",
72
+ "borderDefault": "rgba(0,0,0,0.1)",
73
+ "borderStrong": "rgba(0,0,0,0.16)",
74
+ "textPrimary": "#18181b",
75
+ "textSecondary": "#64646d",
76
+ "textMuted": "#808089",
77
+ "textOnMedia": "#ffffff",
78
+ "accent": "#0a64f5",
79
+ "accentHover": "#0d55c9",
80
+ "accentSoft": "rgba(10,100,245,0.08)",
81
+ "accentText": "#0954ce",
82
+ "accent2": "#0a64f5",
83
+ "onAccent": "#ffffff",
84
+ "ring": "#0a64f5",
85
+ "brandGradientFrom": "#dcebfe",
86
+ "brandGradientVia": "#f3f6fc",
87
+ "brandGradientTo": "#fafafa",
88
+ "success": "#10b77f",
89
+ "warning": "#f59f0a",
90
+ "danger": "#ef4343",
91
+ "info": "#0a64f5",
92
+ "scrim": "rgba(0,0,0,0.6)",
93
+ "scrimStrong": "rgba(0,0,0,0.8)",
94
+ "overlay": "rgba(0,0,0,0.7)"
95
+ }) });
96
+ var radius = Object.freeze({
97
+ "sm": 8,
98
+ "md": 12,
99
+ "lg": 16,
100
+ "xl": 20,
101
+ "full": 9999
102
+ });
103
+ var typography = Object.freeze({
104
+ "sans": "Inter",
105
+ "display": "Inter",
106
+ "mono": "JetBrains Mono"
107
+ });
108
+ var motion = Object.freeze({ ease: Object.freeze([0.16, 1, 0.3, 1]) });
109
+ var brands = Object.freeze({
110
+ "krizaka": {
111
+ "dark": {
112
+ "accent": "#196df5",
113
+ "accentHover": "#0e5bd8",
114
+ "accentSoft": "rgba(25,109,245,0.1)",
115
+ "accentText": "#629cf8",
116
+ "accent2": "#196df5",
117
+ "onAccent": "#ffffff",
118
+ "ring": "#196df5",
119
+ "info": "#196df5",
120
+ "brandGradientFrom": "#0e1525",
121
+ "brandGradientVia": "#0e0f16",
122
+ "brandGradientTo": "#0c0c0e"
123
+ },
124
+ "light": {
125
+ "accent": "#0a64f5",
126
+ "accentHover": "#0d55c9",
127
+ "accentSoft": "rgba(10,100,245,0.08)",
128
+ "accentText": "#0954ce",
129
+ "accent2": "#0a64f5",
130
+ "onAccent": "#ffffff",
131
+ "ring": "#0a64f5",
132
+ "info": "#0a64f5",
133
+ "brandGradientFrom": "#dcebfe",
134
+ "brandGradientVia": "#f3f6fc",
135
+ "brandGradientTo": "#fafafa"
136
+ }
137
+ },
138
+ "orazaka": {
139
+ "dark": {
140
+ "accent": "#f67e23",
141
+ "accentHover": "#f79245",
142
+ "accentSoft": "rgba(246,126,35,0.12)",
143
+ "accentText": "#f78c3b",
144
+ "accent2": "#f59e0b",
145
+ "onAccent": "#0c0c0e",
146
+ "ring": "#f67e23",
147
+ "info": "#3b83f7",
148
+ "brandGradientFrom": "#28170b",
149
+ "brandGradientVia": "#17130c",
150
+ "brandGradientTo": "#0c0c0e"
151
+ },
152
+ "light": {
153
+ "accent": "#b45309",
154
+ "accentHover": "#964608",
155
+ "accentSoft": "rgba(180,83,9,0.08)",
156
+ "accentText": "#9b4808",
157
+ "accent2": "#a45904",
158
+ "onAccent": "#ffffff",
159
+ "ring": "#b45309",
160
+ "info": "#0a64f5",
161
+ "brandGradientFrom": "#ffebd6",
162
+ "brandGradientVia": "#fdf7ed",
163
+ "brandGradientTo": "#fafafa"
164
+ }
165
+ },
166
+ "orochia": {
167
+ "dark": {
168
+ "accent": "#7c3aed",
169
+ "accentHover": "#6d28d9",
170
+ "accentSoft": "rgba(139,92,246,0.12)",
171
+ "accentText": "#a78bfa",
172
+ "accent2": "#db2777",
173
+ "onAccent": "#ffffff",
174
+ "ring": "#a78bfa",
175
+ "info": "#7c3aed",
176
+ "brandGradientFrom": "#1a0e2a",
177
+ "brandGradientVia": "#1c0d17",
178
+ "brandGradientTo": "#0c0c0e"
179
+ },
180
+ "light": {
181
+ "accent": "#7c3aed",
182
+ "accentHover": "#6d28d9",
183
+ "accentSoft": "rgba(124,58,237,0.08)",
184
+ "accentText": "#6d28d9",
185
+ "accent2": "#db2777",
186
+ "onAccent": "#ffffff",
187
+ "ring": "#7c3aed",
188
+ "info": "#7c3aed",
189
+ "brandGradientFrom": "#efe7fe",
190
+ "brandGradientVia": "#fdedf5",
191
+ "brandGradientTo": "#fafafa"
192
+ }
193
+ }
194
+ });
195
+
196
+ // src/native/theme.tsx
197
+ import * as React from "react";
198
+ import { AccessibilityInfo, useColorScheme } from "react-native";
199
+ import { jsx } from "react/jsx-runtime";
200
+ var themes2 = themes;
201
+ var radius2 = radius;
202
+ var motion2 = motion;
203
+ var ThemeContext = React.createContext(null);
204
+ function resolve(mode, system) {
205
+ if (mode === "system") return system === "light" ? "light" : "dark";
206
+ return mode;
207
+ }
208
+ function ThemeProvider({ children, mode: controlled, defaultMode = "system", onModeChange, overrides, fonts }) {
209
+ const system = useColorScheme();
210
+ const [own, setOwn] = React.useState(defaultMode);
211
+ const mode = controlled ?? own;
212
+ const setMode = React.useCallback(
213
+ (next) => {
214
+ if (controlled === void 0) setOwn(next);
215
+ onModeChange?.(next);
216
+ },
217
+ [controlled, onModeChange]
218
+ );
219
+ const scheme = resolve(mode, system);
220
+ const override = overrides?.[scheme];
221
+ const theme = React.useMemo(() => override ? { ...themes2[scheme], ...override } : themes2[scheme], [scheme, override]);
222
+ const value = React.useMemo(
223
+ () => ({ mode, setMode, scheme, theme, radius: radius2, motion: motion2, fonts: fonts ?? {} }),
224
+ [mode, setMode, scheme, theme, fonts]
225
+ );
226
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value, children });
227
+ }
228
+ var noop = () => void 0;
229
+ function useTheme() {
230
+ const context = React.useContext(ThemeContext);
231
+ const system = useColorScheme();
232
+ if (context) return context;
233
+ const scheme = resolve("system", system);
234
+ return { mode: "system", setMode: noop, scheme, theme: themes2[scheme], radius: radius2, motion: motion2, fonts: {} };
235
+ }
236
+ function useReducedMotion() {
237
+ const [reduce, setReduce] = React.useState(false);
238
+ React.useEffect(() => {
239
+ let alive = true;
240
+ void AccessibilityInfo.isReduceMotionEnabled().then((value) => {
241
+ if (alive) setReduce(value);
242
+ });
243
+ const subscription = AccessibilityInfo.addEventListener("reduceMotionChanged", setReduce);
244
+ return () => {
245
+ alive = false;
246
+ subscription.remove();
247
+ };
248
+ }, []);
249
+ return reduce;
250
+ }
251
+ function alpha(color, opacity) {
252
+ const hex = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(color);
253
+ if (!hex) return color;
254
+ const [r, g, b] = hex.slice(1).map((part) => parseInt(part, 16));
255
+ return `rgba(${r},${g},${b},${opacity})`;
256
+ }
257
+ function useSvgId(prefix) {
258
+ return `${prefix}${React.useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
259
+ }
260
+
261
+ // src/native/avatar.tsx
262
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
263
+ var SIDE = { xs: 20, sm: 32, md: 40, lg: 56, xl: 80 };
264
+ function AvatarRoot({ src, alt = "", fallback, size = "md", style, ...props }) {
265
+ const { theme } = useTheme();
266
+ const [failedSrc, setFailedSrc] = React2.useState(null);
267
+ const failed = Boolean(src) && failedSrc === src;
268
+ const side = typeof size === "number" ? size : SIDE[size];
269
+ const initial = alt.trim().charAt(0).toUpperCase();
270
+ const content = fallback ?? initial;
271
+ return /* @__PURE__ */ jsx2(
272
+ View,
273
+ {
274
+ accessible: Boolean(alt),
275
+ role: alt ? "img" : void 0,
276
+ "aria-label": alt || void 0,
277
+ ...props,
278
+ style: [styles.root, { width: side, height: side, borderRadius: side / 2, backgroundColor: theme.surface3 }, style],
279
+ children: src && !failed ? /* @__PURE__ */ jsx2(Image, { testID: props.testID ? `${props.testID}.image` : void 0, source: { uri: src }, onError: () => setFailedSrc(src), resizeMode: "cover", style: StyleSheet.absoluteFill }) : typeof content === "string" ? /* @__PURE__ */ jsx2(Text, { style: [styles.initial, { color: theme.textSecondary, fontSize: Math.max(9, Math.round(side * 0.4)) }], children: content }) : content
280
+ }
281
+ );
282
+ }
283
+ function AvatarGroup({ max, size = "md", style, children, ...props }) {
284
+ const { theme } = useTheme();
285
+ const items2 = React2.Children.toArray(children);
286
+ const shown = max === void 0 ? items2 : items2.slice(0, max);
287
+ const rest = items2.length - shown.length;
288
+ const side = typeof size === "number" ? size : SIDE[size];
289
+ const ring = { borderWidth: 2, borderColor: theme.surface0, marginLeft: -side / 5 };
290
+ return /* @__PURE__ */ jsxs(View, { ...props, style: [styles.group, { paddingLeft: side / 5 }, style], children: [
291
+ shown.map((child, i) => /* @__PURE__ */ jsx2(View, { style: [ring, { borderRadius: side }], children: React2.isValidElement(child) ? React2.cloneElement(child, { size }) : child }, i)),
292
+ rest > 0 ? /* @__PURE__ */ jsx2(View, { style: [ring, { borderRadius: side }], children: /* @__PURE__ */ jsx2(AvatarRoot, { size, fallback: `+${rest}` }) }) : null
293
+ ] });
294
+ }
295
+ var Avatar = Object.assign(AvatarRoot, { Group: AvatarGroup });
296
+ var styles = StyleSheet.create({
297
+ root: { overflow: "hidden", alignItems: "center", justifyContent: "center" },
298
+ initial: { fontWeight: "700" },
299
+ group: { flexDirection: "row", alignItems: "center" }
300
+ });
301
+
302
+ // src/native/badge.tsx
303
+ import * as React3 from "react";
304
+ import { Animated, StyleSheet as StyleSheet2, Text as Text2 } from "react-native";
305
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
306
+ function look(tone2, t) {
307
+ switch (tone2) {
308
+ case "accent":
309
+ return { bg: t.accentSoft, fg: t.textPrimary, border: alpha(t.accent, 0.4), dot: t.accent };
310
+ case "success":
311
+ case "warning":
312
+ case "danger":
313
+ return { bg: alpha(t[tone2], 0.15), fg: t.textPrimary, border: alpha(t[tone2], 0.4), dot: t[tone2] };
314
+ case "scrim":
315
+ return { bg: t.scrim, fg: t.textOnMedia, border: "transparent", dot: t.textOnMedia };
316
+ default:
317
+ return { bg: t.surface3, fg: t.textSecondary, border: "transparent", dot: t.textSecondary };
318
+ }
319
+ }
320
+ function Badge({ tone: tone2 = "neutral", size = "sm", dot, pulse, style, children, ...props }) {
321
+ const { theme } = useTheme();
322
+ const colors = look(tone2, theme);
323
+ const reduce = useReducedMotion();
324
+ const [opacity] = React3.useState(() => new Animated.Value(1));
325
+ React3.useEffect(() => {
326
+ if (!dot || !pulse || reduce) return;
327
+ const loop = Animated.loop(
328
+ Animated.sequence([
329
+ Animated.timing(opacity, { toValue: 0.35, duration: 800, useNativeDriver: true }),
330
+ Animated.timing(opacity, { toValue: 1, duration: 800, useNativeDriver: true })
331
+ ])
332
+ );
333
+ loop.start();
334
+ return () => {
335
+ loop.stop();
336
+ opacity.setValue(1);
337
+ };
338
+ }, [dot, pulse, reduce, opacity]);
339
+ return /* @__PURE__ */ jsxs2(
340
+ Animated.View,
341
+ {
342
+ ...props,
343
+ style: [styles2.root, size === "md" ? styles2.md : styles2.sm, { backgroundColor: colors.bg, borderColor: colors.border }, style],
344
+ children: [
345
+ dot ? /* @__PURE__ */ jsx3(Animated.View, { "aria-hidden": true, style: [styles2.dot, { backgroundColor: colors.dot, opacity }] }) : null,
346
+ typeof children === "string" || typeof children === "number" ? /* @__PURE__ */ jsx3(Text2, { style: [styles2.text, { color: colors.fg, fontSize: size === "md" ? 11 : 10 }], children }) : children
347
+ ]
348
+ }
349
+ );
350
+ }
351
+ var styles2 = StyleSheet2.create({
352
+ root: { flexDirection: "row", alignItems: "center", alignSelf: "flex-start", gap: 4, borderRadius: 9999, borderWidth: 1 },
353
+ sm: { paddingHorizontal: 8, paddingVertical: 2 },
354
+ md: { paddingHorizontal: 10, paddingVertical: 4 },
355
+ dot: { width: 6, height: 6, borderRadius: 3 },
356
+ text: { fontWeight: "700", textTransform: "uppercase", letterSpacing: 0.8 }
357
+ });
358
+
359
+ // src/native/button.tsx
360
+ import { ActivityIndicator, Pressable, StyleSheet as StyleSheet4, View as View2 } from "react-native";
361
+
362
+ // src/native/txt.tsx
363
+ import { StyleSheet as StyleSheet3, Text as Text3 } from "react-native";
364
+ import { jsx as jsx4 } from "react/jsx-runtime";
365
+ var TONE = {
366
+ text: "textPrimary",
367
+ secondary: "textSecondary",
368
+ muted: "textMuted",
369
+ accent: "accentText",
370
+ success: "success",
371
+ warning: "warning",
372
+ danger: "danger",
373
+ onAccent: "onAccent",
374
+ onMedia: "textOnMedia"
375
+ };
376
+ function Txt({ variant = "body", tone: tone2 = "text", style, ...props }) {
377
+ const { theme, fonts } = useTheme();
378
+ const family = variant === "display" || variant === "title" ? fonts.display : variant === "mono" ? fonts.mono : fonts.sans;
379
+ return /* @__PURE__ */ jsx4(
380
+ Text3,
381
+ {
382
+ role: variant === "display" || variant === "title" ? "heading" : void 0,
383
+ ...props,
384
+ style: [styles3[variant], { color: theme[TONE[tone2]] }, family ? { fontFamily: family } : null, style]
385
+ }
386
+ );
387
+ }
388
+ var textStyles = StyleSheet3.create({
389
+ display: { fontSize: 30, lineHeight: 36, fontWeight: "900", letterSpacing: -0.5 },
390
+ title: { fontSize: 18, lineHeight: 24, fontWeight: "800" },
391
+ body: { fontSize: 15, lineHeight: 21 },
392
+ caption: { fontSize: 12, lineHeight: 16 },
393
+ label: { fontSize: 14, lineHeight: 18, fontWeight: "700" },
394
+ mono: { fontSize: 14, lineHeight: 18, fontWeight: "700", fontVariant: ["tabular-nums"] }
395
+ });
396
+ var styles3 = textStyles;
397
+
398
+ // src/native/button.tsx
399
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
400
+ function look2(variant, t) {
401
+ switch (variant) {
402
+ case "primary":
403
+ return { bg: t.accent, fg: t.onAccent, border: t.accent };
404
+ case "outline":
405
+ return { bg: "transparent", fg: t.textPrimary, border: t.borderDefault };
406
+ case "ghost":
407
+ return { bg: "transparent", fg: t.textSecondary, border: "transparent" };
408
+ case "danger":
409
+ return { bg: alpha(t.danger, 0.1), fg: t.textPrimary, border: alpha(t.danger, 0.5) };
410
+ default:
411
+ return { bg: t.surface2, fg: t.textPrimary, border: t.borderDefault };
412
+ }
413
+ }
414
+ var HEIGHT = { sm: 32, md: 40, lg: 48 };
415
+ var PADDING = { sm: 12, md: 16, lg: 24 };
416
+ function useButton({ variant = "secondary", size = "md", shape = "rounded", loading, disabled }) {
417
+ const { theme, radius: radius3 } = useTheme();
418
+ const colors = look2(variant, theme);
419
+ const inactive = Boolean(disabled || loading);
420
+ const frame = (pressed) => ({
421
+ height: HEIGHT[size],
422
+ borderRadius: shape === "pill" ? radius3.full : radius3.sm,
423
+ backgroundColor: colors.bg,
424
+ borderColor: colors.border,
425
+ opacity: inactive ? 0.4 : pressed ? 0.85 : 1,
426
+ transform: [{ scale: pressed ? 0.98 : 1 }]
427
+ });
428
+ return { colors, inactive, frame };
429
+ }
430
+ function Button({ label, icon, variant, size = "md", shape, loading = false, disabled, style, ...props }) {
431
+ const { colors, inactive, frame } = useButton({ variant, size, shape, loading, disabled });
432
+ return /* @__PURE__ */ jsx5(
433
+ Pressable,
434
+ {
435
+ role: "button",
436
+ "aria-label": label,
437
+ "aria-disabled": inactive,
438
+ "aria-busy": loading,
439
+ ...props,
440
+ disabled: inactive,
441
+ style: ({ pressed }) => [styles4.base, { paddingHorizontal: PADDING[size] }, frame(pressed), style],
442
+ children: /* @__PURE__ */ jsxs3(View2, { style: styles4.row, children: [
443
+ loading ? /* @__PURE__ */ jsx5(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon,
444
+ /* @__PURE__ */ jsx5(Txt, { variant: "label", numberOfLines: 1, style: { color: colors.fg, fontSize: size === "sm" ? 12 : 14 }, children: label })
445
+ ] })
446
+ }
447
+ );
448
+ }
449
+ function IconButton({ label, icon, variant, size = "md", shape, loading = false, disabled, style, ...props }) {
450
+ const { colors, inactive, frame } = useButton({ variant, size, shape, loading, disabled });
451
+ const side = HEIGHT[size];
452
+ return /* @__PURE__ */ jsx5(
453
+ Pressable,
454
+ {
455
+ role: "button",
456
+ "aria-label": label,
457
+ "aria-disabled": inactive,
458
+ "aria-busy": loading,
459
+ hitSlop: side < 44 ? (44 - side) / 2 : void 0,
460
+ ...props,
461
+ disabled: inactive,
462
+ style: ({ pressed }) => [styles4.base, frame(pressed), { width: side }, style],
463
+ children: loading ? /* @__PURE__ */ jsx5(ActivityIndicator, { "aria-hidden": true, size: "small", color: colors.fg }) : icon
464
+ }
465
+ );
466
+ }
467
+ var styles4 = StyleSheet4.create({
468
+ base: { alignItems: "center", justifyContent: "center", borderWidth: 1 },
469
+ row: { flexDirection: "row", alignItems: "center", gap: 8 }
470
+ });
471
+
472
+ // src/native/card.tsx
473
+ import { Image as Image2, Pressable as Pressable2, StyleSheet as StyleSheet5, View as View3 } from "react-native";
474
+ import { jsx as jsx6 } from "react/jsx-runtime";
475
+ function CardRoot({ tone: tone2 = "default", radius: radius3 = "xl", onPress, style, ...props }) {
476
+ const { theme, radius: r } = useTheme();
477
+ const frame = [
478
+ styles5.root,
479
+ {
480
+ backgroundColor: tone2 === "elevated" ? theme.surface2 : theme.surface1,
481
+ borderColor: theme.borderDefault,
482
+ borderRadius: r[radius3]
483
+ },
484
+ tone2 === "elevated" ? [styles5.shadow, { shadowColor: theme.scrimStrong }] : null
485
+ ];
486
+ if (!onPress) return /* @__PURE__ */ jsx6(View3, { ...props, style: [frame, style] });
487
+ return /* @__PURE__ */ jsx6(
488
+ Pressable2,
489
+ {
490
+ role: "button",
491
+ onPress,
492
+ ...props,
493
+ style: ({ pressed }) => [frame, { opacity: pressed ? 0.92 : 1, transform: [{ scale: pressed ? 0.99 : 1 }] }, style]
494
+ }
495
+ );
496
+ }
497
+ var ASPECT = { video: 16 / 9, square: 1, portrait: 3 / 4 };
498
+ function CardMedia({ aspect = "video", style, ...props }) {
499
+ const { theme } = useTheme();
500
+ return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.media, { backgroundColor: theme.media }, aspect === "auto" ? null : { aspectRatio: ASPECT[aspect] }, style] });
501
+ }
502
+ function CardImage({ src, fallback, alt, style, ...props }) {
503
+ const { theme } = useTheme();
504
+ if (!src) {
505
+ return /* @__PURE__ */ jsx6(View3, { "aria-hidden": true, style: [StyleSheet5.absoluteFill, styles5.center, { backgroundColor: theme.accentSoft }], children: fallback });
506
+ }
507
+ return /* @__PURE__ */ jsx6(Image2, { accessible: Boolean(alt), alt, "aria-label": alt, resizeMode: "cover", ...props, source: { uri: src }, style: [StyleSheet5.absoluteFill, style] });
508
+ }
509
+ var CORNER = {
510
+ "top-left": { top: 10, left: 10 },
511
+ "top-right": { top: 10, right: 10 },
512
+ "bottom-left": { bottom: 10, left: 10 },
513
+ "bottom-right": { bottom: 10, right: 10 }
514
+ };
515
+ function CardOverlay({ corner = "top-left", style, ...props }) {
516
+ return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.overlay, CORNER[corner], style] });
517
+ }
518
+ var PADDING2 = { none: 0, sm: 12, md: 16, lg: 24 };
519
+ function CardBody({ padding = "md", style, ...props }) {
520
+ return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.body, { padding: PADDING2[padding] }, style] });
521
+ }
522
+ function CardTitle({ numberOfLines = 1, ...props }) {
523
+ return /* @__PURE__ */ jsx6(Txt, { variant: "label", role: "heading", numberOfLines, ...props });
524
+ }
525
+ function CardDescription({ numberOfLines = 2, ...props }) {
526
+ return /* @__PURE__ */ jsx6(Txt, { variant: "caption", tone: "secondary", numberOfLines, ...props });
527
+ }
528
+ function CardFooter({ style, ...props }) {
529
+ const { theme } = useTheme();
530
+ return /* @__PURE__ */ jsx6(View3, { ...props, style: [styles5.footer, { borderTopColor: theme.borderSubtle }, style] });
531
+ }
532
+ var Card = {
533
+ Root: CardRoot,
534
+ Media: CardMedia,
535
+ Image: CardImage,
536
+ Overlay: CardOverlay,
537
+ Body: CardBody,
538
+ Title: CardTitle,
539
+ Description: CardDescription,
540
+ Footer: CardFooter
541
+ };
542
+ var styles5 = StyleSheet5.create({
543
+ root: { overflow: "hidden", borderWidth: StyleSheet5.hairlineWidth },
544
+ shadow: { shadowOpacity: 0.25, shadowRadius: 12, shadowOffset: { width: 0, height: 6 }, elevation: 4 },
545
+ media: { position: "relative", overflow: "hidden", width: "100%" },
546
+ center: { alignItems: "center", justifyContent: "center" },
547
+ overlay: { position: "absolute", zIndex: 1, flexDirection: "row", alignItems: "center", gap: 6 },
548
+ body: { gap: 12 },
549
+ footer: { flexDirection: "row", alignItems: "center", gap: 8, borderTopWidth: StyleSheet5.hairlineWidth, paddingTop: 12, marginTop: "auto" }
550
+ });
551
+
552
+ // src/native/chip.tsx
553
+ import * as React4 from "react";
554
+ import { Pressable as Pressable3, ScrollView, StyleSheet as StyleSheet6, Text as Text4, View as View4 } from "react-native";
555
+ import { Fragment, jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
556
+ var ChipGroupContext = React4.createContext(null);
557
+ function Label({ children, color, size }) {
558
+ if (typeof children !== "string" && typeof children !== "number") return /* @__PURE__ */ jsx7(Fragment, { children });
559
+ return /* @__PURE__ */ jsx7(Text4, { style: [styles6.label, { color, fontSize: size === "sm" ? 12 : 13 }], children });
560
+ }
561
+ function ChipBase(props) {
562
+ const group = React4.useContext(ChipGroupContext);
563
+ const { theme, radius: radius3 } = useTheme();
564
+ const [own, setOwn] = React4.useState(props.removable ? false : props.defaultSelected ?? false);
565
+ const size = props.size ?? group?.size ?? "md";
566
+ const frame = (on2, pressed) => ({
567
+ height: size === "sm" ? 28 : 36,
568
+ borderRadius: radius3.full,
569
+ borderColor: on2 ? theme.accent : theme.borderDefault,
570
+ backgroundColor: on2 ? theme.accentSoft : theme.surface1,
571
+ opacity: pressed ? 0.85 : 1
572
+ });
573
+ if (props.removable) {
574
+ const { removable: _r2, removeLabel, onRemove, disabled: disabled2, size: _s2, style: style2, children: children2, ...rest2 } = props;
575
+ return /* @__PURE__ */ jsxs4(View4, { ...rest2, style: [styles6.base, frame(false, false), disabled2 ? styles6.disabled : null, style2], children: [
576
+ /* @__PURE__ */ jsx7(Label, { color: theme.textSecondary, size, children: children2 }),
577
+ /* @__PURE__ */ jsx7(Pressable3, { role: "button", "aria-label": removeLabel, disabled: disabled2 ?? void 0, hitSlop: 10, onPress: onRemove, style: styles6.remove, children: /* @__PURE__ */ jsx7(Text4, { style: [styles6.cross, { color: theme.textSecondary }], children: "\xD7" }) })
578
+ ] });
579
+ }
580
+ const { removable: _r, value, selected, defaultSelected: _d, onSelectedChange, disabled: ownDisabled, size: _s, style, children, ...rest } = props;
581
+ if (group && value === void 0) throw new Error("Chip: a chip inside Chip.Group needs a `value`.");
582
+ const on = group ? group.isSelected(value) : selected ?? own;
583
+ const disabled = Boolean(ownDisabled || group?.disabled);
584
+ const press = () => {
585
+ if (group) return group.toggle(value);
586
+ if (selected === void 0) setOwn(!on);
587
+ onSelectedChange?.(!on);
588
+ };
589
+ const single = group?.type === "single";
590
+ return /* @__PURE__ */ jsx7(
591
+ Pressable3,
592
+ {
593
+ role: single ? "radio" : "checkbox",
594
+ "aria-checked": on,
595
+ "aria-disabled": disabled,
596
+ ...rest,
597
+ disabled,
598
+ onPress: press,
599
+ style: ({ pressed }) => [styles6.base, frame(on, pressed), disabled ? styles6.disabled : null, style],
600
+ children: /* @__PURE__ */ jsx7(Label, { color: on ? theme.textPrimary : theme.textSecondary, size, children })
601
+ }
602
+ );
603
+ }
604
+ function ChipGroup(props) {
605
+ const { size, disabled, scrollable, "aria-label": label, style, children } = props;
606
+ const initial = props.type === "single" ? props.defaultValue ?? "" : props.defaultValue ?? [];
607
+ const [own, setOwn] = React4.useState(initial);
608
+ const current = props.value ?? own;
609
+ const context = React4.useMemo(() => {
610
+ const list = Array.isArray(current) ? current : [current];
611
+ return {
612
+ type: props.type,
613
+ size,
614
+ disabled,
615
+ isSelected: (v) => list.includes(v),
616
+ toggle: (v) => {
617
+ const next = props.type === "single" ? v : list.includes(v) ? list.filter((x) => x !== v) : [...list, v];
618
+ if (props.value === void 0) setOwn(next);
619
+ props.onValueChange?.(next);
620
+ }
621
+ };
622
+ }, [current, props.type, props.value, props.onValueChange, size, disabled]);
623
+ const a11y = { role: props.type === "single" ? "radiogroup" : "group", "aria-label": label };
624
+ return /* @__PURE__ */ jsx7(ChipGroupContext.Provider, { value: context, children: scrollable ? /* @__PURE__ */ jsx7(ScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, ...a11y, style, contentContainerStyle: styles6.row, children }) : /* @__PURE__ */ jsx7(View4, { ...a11y, style: [styles6.row, styles6.wrap, style], children }) });
625
+ }
626
+ var Chip = Object.assign(ChipBase, { Group: ChipGroup });
627
+ var styles6 = StyleSheet6.create({
628
+ base: { flexDirection: "row", alignItems: "center", justifyContent: "center", gap: 6, paddingHorizontal: 14, borderWidth: 1, alignSelf: "flex-start" },
629
+ label: { fontWeight: "600" },
630
+ remove: { marginRight: -6, width: 24, height: 24, alignItems: "center", justifyContent: "center" },
631
+ cross: { fontSize: 16, lineHeight: 18, fontWeight: "700" },
632
+ disabled: { opacity: 0.4 },
633
+ row: { flexDirection: "row", alignItems: "center", gap: 8 },
634
+ wrap: { flexWrap: "wrap" }
635
+ });
636
+
637
+ // src/native/countdown.tsx
638
+ import * as React5 from "react";
639
+ import { Animated as Animated2, StyleSheet as StyleSheet7, Text as Text5 } from "react-native";
640
+ import { jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
641
+ var FONT = { sm: 14, md: 20, lg: 32 };
642
+ function Countdown({ target, skewMs = 0, units, urgentBelowMs = 6e4, size = "md", label, style }) {
643
+ const { theme, fonts } = useTheme();
644
+ const reduce = useReducedMotion();
645
+ const ms = useCountdown(target, skewMs);
646
+ const urgent = ms > 0 && ms < urgentBelowMs;
647
+ const parts = countdownParts(ms, units);
648
+ const [opacity] = React5.useState(() => new Animated2.Value(1));
649
+ React5.useEffect(() => {
650
+ if (!urgent || reduce) return;
651
+ const loop = Animated2.loop(
652
+ Animated2.sequence([
653
+ Animated2.timing(opacity, { toValue: 0.4, duration: 500, useNativeDriver: true }),
654
+ Animated2.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true })
655
+ ])
656
+ );
657
+ loop.start();
658
+ return () => {
659
+ loop.stop();
660
+ opacity.setValue(1);
661
+ };
662
+ }, [urgent, reduce, opacity]);
663
+ const color = urgent ? theme.danger : theme.textPrimary;
664
+ const text = parts.map(([value, unit]) => `${String(value).padStart(2, "0")}${unit}`).join(" ");
665
+ return /* @__PURE__ */ jsx8(
666
+ Animated2.View,
667
+ {
668
+ accessible: true,
669
+ role: "timer",
670
+ "aria-label": `${label} ${text}`,
671
+ style: [styles7.root, style],
672
+ children: parts.map(([value, unit], i) => /* @__PURE__ */ jsxs5(Animated2.View, { style: [styles7.segment, urgent && i === parts.length - 1 ? { opacity } : null], children: [
673
+ /* @__PURE__ */ jsx8(Text5, { style: [styles7.value, { color, fontSize: FONT[size] }, fonts.display ? { fontFamily: fonts.display } : null], children: String(value).padStart(2, "0") }),
674
+ /* @__PURE__ */ jsx8(Text5, { style: [styles7.unit, { color: theme.textSecondary, fontSize: Math.round(FONT[size] / 2) }], children: unit })
675
+ ] }, unit))
676
+ }
677
+ );
678
+ }
679
+ var styles7 = StyleSheet7.create({
680
+ root: { flexDirection: "row", alignItems: "baseline", gap: 6 },
681
+ segment: { flexDirection: "row", alignItems: "baseline" },
682
+ value: { fontWeight: "900", fontVariant: ["tabular-nums"], letterSpacing: -0.3 },
683
+ unit: { marginLeft: 2, fontWeight: "700", textTransform: "uppercase" }
684
+ });
685
+
686
+ // src/native/empty-state.tsx
687
+ import { StyleSheet as StyleSheet8, View as View5 } from "react-native";
688
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
689
+ function EmptyState({ icon, title, description, action, style, ...props }) {
690
+ const { theme } = useTheme();
691
+ return /* @__PURE__ */ jsxs6(View5, { ...props, style: [styles8.root, style], children: [
692
+ icon ? /* @__PURE__ */ jsx9(View5, { "aria-hidden": true, style: [styles8.icon, { backgroundColor: theme.surface2 }], children: icon }) : null,
693
+ /* @__PURE__ */ jsx9(Txt, { variant: "label", role: "heading", style: styles8.center, children: title }),
694
+ description ? /* @__PURE__ */ jsx9(Txt, { tone: "secondary", style: styles8.center, children: description }) : null,
695
+ action ? /* @__PURE__ */ jsx9(View5, { style: styles8.action, children: action }) : null
696
+ ] });
697
+ }
698
+ var styles8 = StyleSheet8.create({
699
+ root: { alignItems: "center", justifyContent: "center", gap: 8, paddingVertical: 40, paddingHorizontal: 24 },
700
+ icon: { width: 48, height: 48, borderRadius: 24, alignItems: "center", justifyContent: "center", marginBottom: 4 },
701
+ center: { textAlign: "center", maxWidth: 360 },
702
+ action: { marginTop: 8, flexDirection: "row", flexWrap: "wrap", justifyContent: "center", gap: 8 }
703
+ });
704
+
705
+ // src/native/KrizakaMark.tsx
706
+ import { View as View6 } from "react-native";
707
+ import Svg, { Circle, Defs, G as Group, LinearGradient, Path, RadialGradient, Stop } from "react-native-svg";
708
+
709
+ // src/marks/krizaka-geometry.ts
710
+ var KRIZAKA = {
711
+ viewBox: "0 0 400 400",
712
+ croppedViewBox: "86 82 228 228",
713
+ offset: 20,
714
+ /** The shield: a pointy-top hexagon (r 92 around 180,180), open at its upper-right edge. */
715
+ shield: "M259.7,134 L259.7,226 L180,272 L100.3,226 L100.3,134 L180,88 L212,106.5",
716
+ stroke: 22,
717
+ ink: { x1: 70, y1: 290, x2: 290, y2: 70 },
718
+ blue: { x1: 180, y1: 180, x2: 300, y2: 60, stops: [["0%", "#196df5"], ["100%", "#629cf8"]] },
719
+ /** The vertex where the shield opens: a node (the serpent's head in Orochia's grammar). */
720
+ node: { cx: 259.7, cy: 134, r: 19, inner: 6 },
721
+ core: { cx: 180, cy: 180, r: 24, inner: 8 },
722
+ highlight: "#dbeafe",
723
+ glow: { color: "#196df5", opacity: 0.16 },
724
+ orbit: { r: 160, dash: "8 8", width: 1.5 },
725
+ ring: { r: 134, width: 1 }
726
+ };
727
+
728
+ // src/native/mark-motion.ts
729
+ import { useEffect as useEffect4, useState as useState6 } from "react";
730
+ import { AccessibilityInfo as AccessibilityInfo2, Animated as Animated3, Easing } from "react-native";
731
+ var markA11y = (title) => title ? { accessible: true, accessibilityRole: "image", accessibilityLabel: title } : { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants" };
732
+ function useMarkMotion(size, animated, spinMs = 3e4) {
733
+ const [spin] = useState6(() => new Animated3.Value(0));
734
+ const [pulse] = useState6(() => new Animated3.Value(0));
735
+ useEffect4(() => {
736
+ if (!animated) return;
737
+ let loops = [];
738
+ let cancelled = false;
739
+ void AccessibilityInfo2.isReduceMotionEnabled().then((reduce) => {
740
+ if (reduce || cancelled) return;
741
+ loops = [
742
+ Animated3.loop(Animated3.timing(spin, { toValue: 1, duration: spinMs, easing: Easing.linear, useNativeDriver: true })),
743
+ Animated3.loop(
744
+ Animated3.sequence([
745
+ Animated3.timing(pulse, { toValue: 1, duration: 1600, easing: Easing.inOut(Easing.ease), useNativeDriver: true }),
746
+ Animated3.timing(pulse, { toValue: 0, duration: 1600, easing: Easing.inOut(Easing.ease), useNativeDriver: true })
747
+ ])
748
+ )
749
+ ];
750
+ loops.forEach((l) => l.start());
751
+ });
752
+ return () => {
753
+ cancelled = true;
754
+ loops.forEach((l) => l.stop());
755
+ };
756
+ }, [animated, spin, pulse, spinMs]);
757
+ return {
758
+ Animated: Animated3,
759
+ layer: { position: "absolute", width: size, height: size },
760
+ spinStyle: { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] },
761
+ pulseStyle: { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }
762
+ };
763
+ }
764
+
765
+ // src/native/KrizakaMark.tsx
766
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
767
+ function KrizakaMark({ size = 48, animated = true, title, neutral }) {
768
+ const { theme } = useTheme();
769
+ const { Animated: Animated8, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
770
+ const id = useSvgId("kzm");
771
+ const viewBox = size < 48 ? KRIZAKA.croppedViewBox : KRIZAKA.viewBox;
772
+ const stroke = neutral ?? theme.textMuted;
773
+ const blue = /* @__PURE__ */ jsx10(LinearGradient, { id: `${id}b`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.blue.x1 + KRIZAKA.offset, y1: KRIZAKA.blue.y1 + KRIZAKA.offset, x2: KRIZAKA.blue.x2 + KRIZAKA.offset, y2: KRIZAKA.blue.y2 + KRIZAKA.offset, children: KRIZAKA.blue.stops.map(([offset, color]) => /* @__PURE__ */ jsx10(Stop, { offset, stopColor: color }, offset)) });
774
+ const dot = (c) => /* @__PURE__ */ jsxs7(Fragment2, { children: [
775
+ /* @__PURE__ */ jsx10(Circle, { cx: c.cx, cy: c.cy, r: c.r, fill: `url(#${id}b)` }),
776
+ /* @__PURE__ */ jsx10(Circle, { cx: c.cx, cy: c.cy, r: c.inner, fill: KRIZAKA.highlight })
777
+ ] });
778
+ return /* @__PURE__ */ jsxs7(View6, { style: { width: size, height: size }, ...markA11y(title), children: [
779
+ /* @__PURE__ */ jsxs7(Svg, { viewBox, style: layer, children: [
780
+ /* @__PURE__ */ jsxs7(Defs, { children: [
781
+ /* @__PURE__ */ jsxs7(RadialGradient, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
782
+ /* @__PURE__ */ jsx10(Stop, { offset: "0%", stopColor: KRIZAKA.glow.color, stopOpacity: KRIZAKA.glow.opacity }),
783
+ /* @__PURE__ */ jsx10(Stop, { offset: "100%", stopColor: KRIZAKA.glow.color, stopOpacity: 0 })
784
+ ] }),
785
+ /* @__PURE__ */ jsxs7(LinearGradient, { id: `${id}i`, gradientUnits: "userSpaceOnUse", x1: KRIZAKA.ink.x1 + KRIZAKA.offset, y1: KRIZAKA.ink.y1 + KRIZAKA.offset, x2: KRIZAKA.ink.x2 + KRIZAKA.offset, y2: KRIZAKA.ink.y2 + KRIZAKA.offset, children: [
786
+ /* @__PURE__ */ jsx10(Stop, { offset: "0%", stopColor: theme.textSecondary }),
787
+ /* @__PURE__ */ jsx10(Stop, { offset: "100%", stopColor: theme.textPrimary })
788
+ ] }),
789
+ blue
790
+ ] }),
791
+ size >= 48 ? /* @__PURE__ */ jsx10(Circle, { cx: 200, cy: 200, r: 190, fill: `url(#${id}g)` }) : null,
792
+ /* @__PURE__ */ jsx10(Circle, { cx: 200, cy: 200, r: KRIZAKA.ring.r, stroke, strokeWidth: KRIZAKA.ring.width, opacity: 0.35, fill: "none" }),
793
+ /* @__PURE__ */ jsx10(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: /* @__PURE__ */ jsx10(Path, { d: KRIZAKA.shield, stroke: `url(#${id}i)`, strokeWidth: KRIZAKA.stroke, strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }) })
794
+ ] }),
795
+ /* @__PURE__ */ jsx10(Animated8.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsx10(Svg, { viewBox, style: layer, children: /* @__PURE__ */ jsx10(Circle, { cx: 200, cy: 200, r: KRIZAKA.orbit.r, stroke, strokeWidth: KRIZAKA.orbit.width, strokeDasharray: KRIZAKA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
796
+ /* @__PURE__ */ jsx10(Animated8.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs7(Svg, { viewBox, style: layer, children: [
797
+ /* @__PURE__ */ jsx10(Defs, { children: blue }),
798
+ /* @__PURE__ */ jsxs7(Group, { transform: `translate(${KRIZAKA.offset} ${KRIZAKA.offset})`, children: [
799
+ dot(KRIZAKA.node),
800
+ dot(KRIZAKA.core)
801
+ ] })
802
+ ] }) })
803
+ ] });
804
+ }
805
+
806
+ // src/native/OrazakaMark.tsx
807
+ import { View as View7 } from "react-native";
808
+ import Svg2, { Circle as Circle2, Defs as Defs2, LinearGradient as LinearGradient2, Path as Path2, RadialGradient as RadialGradient2, Stop as Stop2 } from "react-native-svg";
809
+
810
+ // src/marks/orazaka-geometry.ts
811
+ var ORAZAKA = {
812
+ viewBox: "0 0 400 400",
813
+ croppedViewBox: "76 76 248 248",
814
+ center: 200,
815
+ /**
816
+ * The three shards — a hexagon's cap (from the original 132-unit drawing), scaled ×1.9 around the centre and turned
817
+ * 0°, 120°, 240° — in view-box coordinates, so that one gradient runs across all three.
818
+ */
819
+ shards: [
820
+ "M154.4,121.2 L200,94.7 L245.6,121.2 L245.6,154.4 L226.6,165.4 L226.6,132.2 L200,116.8 L173.4,132.2 L173.4,165.4 L154.4,154.4 Z",
821
+ "M291.1,199.9 L291.2,252.6 L245.5,278.9 L216.7,262.3 L216.6,240.3 L245.4,257 L272.1,241.6 L272,210.9 L243.2,194.3 L262.3,183.3 Z",
822
+ "M154.5,278.9 L108.8,252.6 L108.9,199.9 L137.7,183.3 L156.8,194.3 L128,210.9 L127.9,241.6 L154.6,257 L183.4,240.3 L183.3,262.3 Z"
823
+ ],
824
+ shardStroke: 5.7,
825
+ amber: { x1: 90, y1: 310, x2: 310, y2: 90, stops: [["0%", "#b45309"], ["100%", "#f59e0b"]] },
826
+ core: { r: 21, inner: 7.6 },
827
+ highlight: "#fffbeb",
828
+ glow: { color: "#f59e0b", opacity: 0.16 },
829
+ orbit: { r: 160, dash: "8 8", width: 1.5 },
830
+ ring: { r: 134, width: 1 }
831
+ };
832
+
833
+ // src/native/OrazakaMark.tsx
834
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
835
+ function OrazakaMark({ size = 48, animated = true, title, neutral }) {
836
+ const { theme } = useTheme();
837
+ const { Animated: Animated8, layer, spinStyle, pulseStyle } = useMarkMotion(size, animated);
838
+ const id = useSvgId("ozm");
839
+ const viewBox = size < 48 ? ORAZAKA.croppedViewBox : ORAZAKA.viewBox;
840
+ const stroke = neutral ?? theme.textMuted;
841
+ const amber = /* @__PURE__ */ jsx11(LinearGradient2, { id: `${id}a`, gradientUnits: "userSpaceOnUse", x1: ORAZAKA.amber.x1, y1: ORAZAKA.amber.y1, x2: ORAZAKA.amber.x2, y2: ORAZAKA.amber.y2, children: ORAZAKA.amber.stops.map(([offset, color]) => /* @__PURE__ */ jsx11(Stop2, { offset, stopColor: color }, offset)) });
842
+ const fill = `url(#${id}a)`;
843
+ return /* @__PURE__ */ jsxs8(View7, { style: { width: size, height: size }, ...markA11y(title), children: [
844
+ /* @__PURE__ */ jsxs8(Svg2, { viewBox, style: layer, children: [
845
+ /* @__PURE__ */ jsx11(Defs2, { children: /* @__PURE__ */ jsxs8(RadialGradient2, { id: `${id}g`, cx: "50%", cy: "50%", r: "50%", children: [
846
+ /* @__PURE__ */ jsx11(Stop2, { offset: "0%", stopColor: ORAZAKA.glow.color, stopOpacity: ORAZAKA.glow.opacity }),
847
+ /* @__PURE__ */ jsx11(Stop2, { offset: "100%", stopColor: ORAZAKA.glow.color, stopOpacity: 0 })
848
+ ] }) }),
849
+ size >= 48 ? /* @__PURE__ */ jsx11(Circle2, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: 190, fill: `url(#${id}g)` }) : null,
850
+ /* @__PURE__ */ jsx11(Circle2, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.orbit.r, stroke, strokeWidth: ORAZAKA.orbit.width, strokeDasharray: ORAZAKA.orbit.dash, opacity: 0.6, fill: "none" }),
851
+ /* @__PURE__ */ jsx11(Circle2, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.ring.r, stroke, strokeWidth: ORAZAKA.ring.width, opacity: 0.35, fill: "none" })
852
+ ] }),
853
+ /* @__PURE__ */ jsx11(Animated8.View, { style: [layer, spinStyle], children: /* @__PURE__ */ jsxs8(Svg2, { viewBox, style: layer, children: [
854
+ /* @__PURE__ */ jsx11(Defs2, { children: amber }),
855
+ ORAZAKA.shards.map((d) => /* @__PURE__ */ jsx11(Path2, { d, fill, stroke: fill, strokeWidth: ORAZAKA.shardStroke, strokeLinejoin: "round" }, d))
856
+ ] }) }),
857
+ /* @__PURE__ */ jsx11(Animated8.View, { style: [layer, pulseStyle], children: /* @__PURE__ */ jsxs8(Svg2, { viewBox, style: layer, children: [
858
+ /* @__PURE__ */ jsx11(Defs2, { children: amber }),
859
+ /* @__PURE__ */ jsx11(Circle2, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.r, fill }),
860
+ /* @__PURE__ */ jsx11(Circle2, { cx: ORAZAKA.center, cy: ORAZAKA.center, r: ORAZAKA.core.inner, fill: ORAZAKA.highlight })
861
+ ] }) })
862
+ ] });
863
+ }
864
+
1
865
  // src/native/OrochiaMark.tsx
2
- import { useEffect, useState } from "react";
3
- import { AccessibilityInfo, Animated, Easing, View } from "react-native";
4
- import Svg, { Circle, Defs, Ellipse, G as Group, LinearGradient, Path, RadialGradient, Stop } from "react-native-svg";
866
+ import { useEffect as useEffect5, useState as useState7 } from "react";
867
+ import { AccessibilityInfo as AccessibilityInfo3, Animated as Animated4, Easing as Easing2, View as View8 } from "react-native";
868
+ import Svg3, { Circle as Circle3, Defs as Defs3, Ellipse, G as Group2, LinearGradient as LinearGradient3, Path as Path3, RadialGradient as RadialGradient3, Stop as Stop3 } from "react-native-svg";
5
869
 
6
870
  // src/marks/orochia-geometry.ts
7
871
  var OROCHIA = {
@@ -28,23 +892,25 @@ var OROCHIA = {
28
892
  };
29
893
 
30
894
  // src/native/OrochiaMark.tsx
31
- import { jsx, jsxs } from "react/jsx-runtime";
895
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
32
896
  var CENTER = OROCHIA.offset + 180;
33
- function OrochiaMark({ size = 48, animated = true, title, neutral = "rgba(255,255,255,0.35)" }) {
34
- const [spin] = useState(() => new Animated.Value(0));
35
- const [pulse] = useState(() => new Animated.Value(0));
36
- useEffect(() => {
897
+ function OrochiaMark({ size = 48, animated = true, title, neutral: neutralProp }) {
898
+ const { theme } = useTheme();
899
+ const neutral = neutralProp ?? theme.textMuted;
900
+ const [spin] = useState7(() => new Animated4.Value(0));
901
+ const [pulse] = useState7(() => new Animated4.Value(0));
902
+ useEffect5(() => {
37
903
  if (!animated) return;
38
904
  let loops = [];
39
905
  let cancelled = false;
40
- void AccessibilityInfo.isReduceMotionEnabled().then((reduce) => {
906
+ void AccessibilityInfo3.isReduceMotionEnabled().then((reduce) => {
41
907
  if (reduce || cancelled) return;
42
908
  loops = [
43
- Animated.loop(Animated.timing(spin, { toValue: 1, duration: 3e4, easing: Easing.linear, useNativeDriver: true })),
44
- Animated.loop(
45
- Animated.sequence([
46
- Animated.timing(pulse, { toValue: 1, duration: 1600, easing: Easing.inOut(Easing.ease), useNativeDriver: true }),
47
- Animated.timing(pulse, { toValue: 0, duration: 1600, easing: Easing.inOut(Easing.ease), useNativeDriver: true })
909
+ Animated4.loop(Animated4.timing(spin, { toValue: 1, duration: 3e4, easing: Easing2.linear, useNativeDriver: true })),
910
+ Animated4.loop(
911
+ Animated4.sequence([
912
+ Animated4.timing(pulse, { toValue: 1, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true }),
913
+ Animated4.timing(pulse, { toValue: 0, duration: 1600, easing: Easing2.inOut(Easing2.ease), useNativeDriver: true })
48
914
  ])
49
915
  )
50
916
  ];
@@ -58,38 +924,408 @@ function OrochiaMark({ size = 48, animated = true, title, neutral = "rgba(255,25
58
924
  const viewBox = size < 48 ? OROCHIA.croppedViewBox : OROCHIA.viewBox;
59
925
  const layer = { position: "absolute", width: size, height: size };
60
926
  const a11y = title ? { accessible: true, accessibilityRole: "image", accessibilityLabel: title } : { accessibilityElementsHidden: true, importantForAccessibility: "no-hide-descendants" };
61
- const bodyGradient = /* @__PURE__ */ jsx(LinearGradient, { id: "body", gradientUnits: "userSpaceOnUse", x1: OROCHIA.body.x1 + OROCHIA.offset, y1: OROCHIA.body.y1 + OROCHIA.offset, x2: OROCHIA.body.x2 + OROCHIA.offset, y2: OROCHIA.body.y2 + OROCHIA.offset, children: OROCHIA.body.stops.map(([offset, color]) => /* @__PURE__ */ jsx(Stop, { offset, stopColor: color }, offset)) });
62
- return /* @__PURE__ */ jsxs(View, { style: { width: size, height: size }, ...a11y, children: [
63
- /* @__PURE__ */ jsxs(Svg, { viewBox, style: layer, children: [
64
- /* @__PURE__ */ jsx(Defs, { children: /* @__PURE__ */ jsxs(RadialGradient, { id: "glow", cx: "50%", cy: "50%", r: "50%", children: [
65
- /* @__PURE__ */ jsx(Stop, { offset: "0%", stopColor: OROCHIA.glow.color, stopOpacity: OROCHIA.glow.opacity }),
66
- /* @__PURE__ */ jsx(Stop, { offset: "100%", stopColor: OROCHIA.glow.color, stopOpacity: 0 })
927
+ const bodyGradient = /* @__PURE__ */ jsx12(LinearGradient3, { id: "body", gradientUnits: "userSpaceOnUse", x1: OROCHIA.body.x1 + OROCHIA.offset, y1: OROCHIA.body.y1 + OROCHIA.offset, x2: OROCHIA.body.x2 + OROCHIA.offset, y2: OROCHIA.body.y2 + OROCHIA.offset, children: OROCHIA.body.stops.map(([offset, color]) => /* @__PURE__ */ jsx12(Stop3, { offset, stopColor: color }, offset)) });
928
+ return /* @__PURE__ */ jsxs9(View8, { style: { width: size, height: size }, ...a11y, children: [
929
+ /* @__PURE__ */ jsxs9(Svg3, { viewBox, style: layer, children: [
930
+ /* @__PURE__ */ jsx12(Defs3, { children: /* @__PURE__ */ jsxs9(RadialGradient3, { id: "glow", cx: "50%", cy: "50%", r: "50%", children: [
931
+ /* @__PURE__ */ jsx12(Stop3, { offset: "0%", stopColor: OROCHIA.glow.color, stopOpacity: OROCHIA.glow.opacity }),
932
+ /* @__PURE__ */ jsx12(Stop3, { offset: "100%", stopColor: OROCHIA.glow.color, stopOpacity: 0 })
67
933
  ] }) }),
68
- /* @__PURE__ */ jsx(Circle, { cx: CENTER, cy: CENTER, r: 170, fill: "url(#glow)" }),
69
- /* @__PURE__ */ jsx(Circle, { cx: CENTER, cy: CENTER, r: OROCHIA.ring.r, stroke: neutral, strokeWidth: OROCHIA.ring.width, opacity: 0.35, fill: "none" })
934
+ /* @__PURE__ */ jsx12(Circle3, { cx: CENTER, cy: CENTER, r: 170, fill: "url(#glow)" }),
935
+ /* @__PURE__ */ jsx12(Circle3, { cx: CENTER, cy: CENTER, r: OROCHIA.ring.r, stroke: neutral, strokeWidth: OROCHIA.ring.width, opacity: 0.35, fill: "none" })
70
936
  ] }),
71
- /* @__PURE__ */ jsx(Animated.View, { style: [layer, { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] }], children: /* @__PURE__ */ jsx(Svg, { viewBox, style: layer, children: /* @__PURE__ */ jsx(Circle, { cx: CENTER, cy: CENTER, r: OROCHIA.orbit.r, stroke: neutral, strokeWidth: OROCHIA.orbit.width, strokeDasharray: OROCHIA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
72
- /* @__PURE__ */ jsxs(Svg, { viewBox, style: layer, children: [
73
- /* @__PURE__ */ jsx(Defs, { children: bodyGradient }),
74
- /* @__PURE__ */ jsxs(Group, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
75
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.arc, stroke: "url(#body)", strokeWidth: 22, strokeLinecap: "round", fill: "none" }),
76
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.arc, stroke: OROCHIA.scales.color, strokeOpacity: OROCHIA.scales.opacity, strokeWidth: OROCHIA.scales.width, strokeLinecap: "round", strokeDasharray: OROCHIA.scales.dash, fill: "none" }),
77
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.neck, stroke: "url(#body)", strokeWidth: 14, strokeLinecap: "round", fill: "none" }),
78
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.tail, stroke: "url(#body)", strokeWidth: 6, strokeLinecap: "round", fill: "none" }),
79
- /* @__PURE__ */ jsx(Ellipse, { cx: OROCHIA.head.cx, cy: OROCHIA.head.cy, rx: OROCHIA.head.rx, ry: OROCHIA.head.ry, rotation: OROCHIA.head.rotate, origin: `${OROCHIA.head.cx}, ${OROCHIA.head.cy}`, fill: "url(#body)" }),
80
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.tongue.d, stroke: OROCHIA.tongue.color, strokeWidth: 3, strokeLinecap: "round", fill: "none" })
937
+ /* @__PURE__ */ jsx12(Animated4.View, { style: [layer, { transform: [{ rotate: spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] }) }] }], children: /* @__PURE__ */ jsx12(Svg3, { viewBox, style: layer, children: /* @__PURE__ */ jsx12(Circle3, { cx: CENTER, cy: CENTER, r: OROCHIA.orbit.r, stroke: neutral, strokeWidth: OROCHIA.orbit.width, strokeDasharray: OROCHIA.orbit.dash, opacity: 0.6, fill: "none" }) }) }),
938
+ /* @__PURE__ */ jsxs9(Svg3, { viewBox, style: layer, children: [
939
+ /* @__PURE__ */ jsx12(Defs3, { children: bodyGradient }),
940
+ /* @__PURE__ */ jsxs9(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
941
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.arc, stroke: "url(#body)", strokeWidth: 22, strokeLinecap: "round", fill: "none" }),
942
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.arc, stroke: OROCHIA.scales.color, strokeOpacity: OROCHIA.scales.opacity, strokeWidth: OROCHIA.scales.width, strokeLinecap: "round", strokeDasharray: OROCHIA.scales.dash, fill: "none" }),
943
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.neck, stroke: "url(#body)", strokeWidth: 14, strokeLinecap: "round", fill: "none" }),
944
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.tail, stroke: "url(#body)", strokeWidth: 6, strokeLinecap: "round", fill: "none" }),
945
+ /* @__PURE__ */ jsx12(Ellipse, { cx: OROCHIA.head.cx, cy: OROCHIA.head.cy, rx: OROCHIA.head.rx, ry: OROCHIA.head.ry, rotation: OROCHIA.head.rotate, origin: `${OROCHIA.head.cx}, ${OROCHIA.head.cy}`, fill: "url(#body)" }),
946
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.tongue.d, stroke: OROCHIA.tongue.color, strokeWidth: 3, strokeLinecap: "round", fill: "none" })
81
947
  ] })
82
948
  ] }),
83
- /* @__PURE__ */ jsx(Animated.View, { style: [layer, { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }], children: /* @__PURE__ */ jsxs(Svg, { viewBox, style: layer, children: [
84
- /* @__PURE__ */ jsx(Defs, { children: /* @__PURE__ */ jsx(LinearGradient, { id: "flame", x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: OROCHIA.flameGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx(Stop, { offset, stopColor: color }, offset)) }) }),
85
- /* @__PURE__ */ jsxs(Group, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
86
- /* @__PURE__ */ jsx(Circle, { cx: OROCHIA.eye.cx, cy: OROCHIA.eye.cy, r: OROCHIA.eye.r, fill: OROCHIA.eye.color }),
87
- /* @__PURE__ */ jsx(Path, { d: OROCHIA.flame.d, transform: `translate(${OROCHIA.flame.translate[0]} ${OROCHIA.flame.translate[1]}) scale(${OROCHIA.flame.scale})`, fill: "url(#flame)" })
949
+ /* @__PURE__ */ jsx12(Animated4.View, { style: [layer, { opacity: pulse.interpolate({ inputRange: [0, 1], outputRange: [0.85, 1] }) }], children: /* @__PURE__ */ jsxs9(Svg3, { viewBox, style: layer, children: [
950
+ /* @__PURE__ */ jsx12(Defs3, { children: /* @__PURE__ */ jsx12(LinearGradient3, { id: "flame", x1: "50%", y1: "100%", x2: "50%", y2: "0%", children: OROCHIA.flameGradient.stops.map(([offset, color]) => /* @__PURE__ */ jsx12(Stop3, { offset, stopColor: color }, offset)) }) }),
951
+ /* @__PURE__ */ jsxs9(Group2, { transform: `translate(${OROCHIA.offset} ${OROCHIA.offset})`, children: [
952
+ /* @__PURE__ */ jsx12(Circle3, { cx: OROCHIA.eye.cx, cy: OROCHIA.eye.cy, r: OROCHIA.eye.r, fill: OROCHIA.eye.color }),
953
+ /* @__PURE__ */ jsx12(Path3, { d: OROCHIA.flame.d, transform: `translate(${OROCHIA.flame.translate[0]} ${OROCHIA.flame.translate[1]}) scale(${OROCHIA.flame.scale})`, fill: "url(#flame)" })
88
954
  ] })
89
955
  ] }) })
90
956
  ] });
91
957
  }
958
+
959
+ // src/native/ProductMark.tsx
960
+ import { jsx as jsx13 } from "react/jsx-runtime";
961
+ function ProductMark({ id, ...props }) {
962
+ if (id === "krizaka") return /* @__PURE__ */ jsx13(KrizakaMark, { ...props });
963
+ if (id === "orazaka") return /* @__PURE__ */ jsx13(OrazakaMark, { ...props });
964
+ return /* @__PURE__ */ jsx13(OrochiaMark, { ...props });
965
+ }
966
+
967
+ // src/native/progress.tsx
968
+ import * as React7 from "react";
969
+ import { Animated as Animated5, Easing as Easing3, StyleSheet as StyleSheet9, View as View9 } from "react-native";
970
+ import Svg4, { Circle as Circle4, Defs as Defs4, LinearGradient as LinearGradient4, Rect, Stop as Stop4 } from "react-native-svg";
971
+ import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
972
+ var AnimatedCircle = Animated5.createAnimatedComponent(Circle4);
973
+ var BAR = { sm: 4, md: 8, lg: 12 };
974
+ var RING = { sm: 40, md: 80, lg: 144 };
975
+ var STROKE = { sm: 12, md: 9, lg: 7 };
976
+ function Progress({ variant = "bar", size = "md", value, max = 100, label, valueText, children, style }) {
977
+ const { theme } = useTheme();
978
+ const reduce = useReducedMotion();
979
+ const id = useSvgId("kz-progress-");
980
+ const known = typeof value === "number" && Number.isFinite(value);
981
+ const ratio = known ? Math.min(1, Math.max(0, value / (max || 1))) : 0;
982
+ const percent = Math.round(ratio * 100);
983
+ const [progress] = React7.useState(() => new Animated5.Value(ratio));
984
+ const [spin] = React7.useState(() => new Animated5.Value(0));
985
+ const [track, setTrack] = React7.useState(0);
986
+ React7.useEffect(() => {
987
+ if (reduce) {
988
+ progress.setValue(ratio);
989
+ return;
990
+ }
991
+ const animation = Animated5.timing(progress, { toValue: ratio, duration: 700, easing: Easing3.out(Easing3.cubic), useNativeDriver: false });
992
+ animation.start();
993
+ return () => animation.stop();
994
+ }, [ratio, reduce, progress]);
995
+ React7.useEffect(() => {
996
+ if (known || reduce) return;
997
+ const loop = Animated5.loop(Animated5.timing(spin, { toValue: 1, duration: 1200, easing: Easing3.linear, useNativeDriver: true }));
998
+ loop.start();
999
+ return () => {
1000
+ loop.stop();
1001
+ spin.setValue(0);
1002
+ };
1003
+ }, [known, reduce, spin]);
1004
+ const a11y = {
1005
+ accessible: true,
1006
+ role: "progressbar",
1007
+ "aria-label": label,
1008
+ "aria-valuemin": known ? 0 : void 0,
1009
+ "aria-valuemax": known ? max : void 0,
1010
+ "aria-valuenow": known ? Math.min(max, Math.max(0, value)) : void 0,
1011
+ "aria-valuetext": known ? valueText ?? `${percent}%` : valueText
1012
+ };
1013
+ const gradient = /* @__PURE__ */ jsx14(Defs4, { children: /* @__PURE__ */ jsxs10(LinearGradient4, { id, x1: "0", y1: "0", x2: "1", y2: variant === "ring" ? "1" : "0", children: [
1014
+ /* @__PURE__ */ jsx14(Stop4, { offset: "0", stopColor: theme.accent }),
1015
+ /* @__PURE__ */ jsx14(Stop4, { offset: "1", stopColor: theme.accent2 })
1016
+ ] }) });
1017
+ if (variant === "ring") {
1018
+ const side = RING[size];
1019
+ const stroke = STROKE[size];
1020
+ const r = 50 - stroke / 2;
1021
+ const circumference = 2 * Math.PI * r;
1022
+ const offset = known ? progress.interpolate({ inputRange: [0, 1], outputRange: [circumference, 0] }) : circumference * 0.75;
1023
+ const rotate = spin.interpolate({ inputRange: [0, 1], outputRange: ["0deg", "360deg"] });
1024
+ return /* @__PURE__ */ jsxs10(View9, { ...a11y, style: [styles9.ring, { width: side, height: side }, style], children: [
1025
+ /* @__PURE__ */ jsx14(Animated5.View, { style: [StyleSheet9.absoluteFill, { transform: [{ rotate: known ? "-90deg" : rotate }] }], children: /* @__PURE__ */ jsxs10(Svg4, { width: side, height: side, viewBox: "0 0 100 100", children: [
1026
+ gradient,
1027
+ /* @__PURE__ */ jsx14(Circle4, { cx: 50, cy: 50, r, fill: "none", stroke: theme.borderDefault, strokeWidth: stroke }),
1028
+ /* @__PURE__ */ jsx14(
1029
+ AnimatedCircle,
1030
+ {
1031
+ cx: 50,
1032
+ cy: 50,
1033
+ r,
1034
+ fill: "none",
1035
+ stroke: `url(#${id})`,
1036
+ strokeWidth: stroke,
1037
+ strokeLinecap: "round",
1038
+ strokeDasharray: `${circumference} ${circumference}`,
1039
+ strokeDashoffset: offset
1040
+ }
1041
+ )
1042
+ ] }) }),
1043
+ children
1044
+ ] });
1045
+ }
1046
+ const width = known ? progress.interpolate({ inputRange: [0, 1], outputRange: ["0%", "100%"] }) : "40%";
1047
+ const translate = spin.interpolate({ inputRange: [0, 1], outputRange: [-0.4 * track, track] });
1048
+ return /* @__PURE__ */ jsx14(
1049
+ View9,
1050
+ {
1051
+ ...a11y,
1052
+ onLayout: known ? void 0 : (event) => setTrack(event.nativeEvent.layout.width),
1053
+ style: [styles9.bar, { height: BAR[size], backgroundColor: theme.surface3 }, style],
1054
+ children: /* @__PURE__ */ jsx14(Animated5.View, { style: [styles9.fill, { width }, known || reduce ? null : { transform: [{ translateX: translate }] }], children: /* @__PURE__ */ jsxs10(Svg4, { width: "100%", height: "100%", preserveAspectRatio: "none", children: [
1055
+ gradient,
1056
+ /* @__PURE__ */ jsx14(Rect, { x: 0, y: 0, width: "100%", height: "100%", fill: `url(#${id})` })
1057
+ ] }) })
1058
+ }
1059
+ );
1060
+ }
1061
+ var styles9 = StyleSheet9.create({
1062
+ ring: { alignItems: "center", justifyContent: "center" },
1063
+ bar: { width: "100%", overflow: "hidden", borderRadius: 9999 },
1064
+ fill: { height: "100%", overflow: "hidden", borderRadius: 9999 }
1065
+ });
1066
+
1067
+ // src/native/segmented.tsx
1068
+ import { Pressable as Pressable4, StyleSheet as StyleSheet10, Text as Text6, View as View10 } from "react-native";
1069
+ import { jsx as jsx15 } from "react/jsx-runtime";
1070
+ function Segmented({ options, value, onValueChange, size = "md", "aria-label": label, style }) {
1071
+ const { theme, radius: radius3 } = useTheme();
1072
+ return /* @__PURE__ */ jsx15(
1073
+ View10,
1074
+ {
1075
+ role: "tablist",
1076
+ "aria-label": label,
1077
+ style: [styles10.track, { backgroundColor: theme.surface2, borderColor: theme.borderSubtle, borderRadius: radius3.md, height: size === "sm" ? 32 : 40 }, style],
1078
+ children: options.map((option) => {
1079
+ const selected = option.value === value;
1080
+ return /* @__PURE__ */ jsx15(
1081
+ Pressable4,
1082
+ {
1083
+ role: "tab",
1084
+ "aria-selected": selected,
1085
+ "aria-disabled": option.disabled,
1086
+ disabled: option.disabled,
1087
+ onPress: () => {
1088
+ if (!selected) onValueChange(option.value);
1089
+ },
1090
+ style: [
1091
+ styles10.segment,
1092
+ { borderRadius: radius3.sm },
1093
+ selected ? { backgroundColor: theme.surface0, borderColor: theme.borderDefault } : null,
1094
+ option.disabled ? styles10.disabled : null
1095
+ ],
1096
+ children: /* @__PURE__ */ jsx15(Text6, { numberOfLines: 1, style: [styles10.label, { color: selected ? theme.textPrimary : theme.textSecondary, fontSize: size === "sm" ? 12 : 13 }], children: option.label })
1097
+ },
1098
+ option.value
1099
+ );
1100
+ })
1101
+ }
1102
+ );
1103
+ }
1104
+ var styles10 = StyleSheet10.create({
1105
+ track: { flexDirection: "row", padding: 3, gap: 3, borderWidth: StyleSheet10.hairlineWidth },
1106
+ segment: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 8, borderWidth: StyleSheet10.hairlineWidth, borderColor: "transparent" },
1107
+ label: { fontWeight: "600" },
1108
+ disabled: { opacity: 0.4 }
1109
+ });
1110
+
1111
+ // src/native/skeleton.tsx
1112
+ import * as React8 from "react";
1113
+ import { Animated as Animated6 } from "react-native";
1114
+ import { jsx as jsx16 } from "react/jsx-runtime";
1115
+ var SHAPE = {
1116
+ text: { width: "100%", height: 12, radius: 4 },
1117
+ circle: { width: 40, height: 40, radius: 9999 },
1118
+ rect: { width: "100%", height: 96, radius: 12 }
1119
+ };
1120
+ function Skeleton({ shape = "text", width, height, style, testID }) {
1121
+ const { theme } = useTheme();
1122
+ const reduce = useReducedMotion();
1123
+ const [opacity] = React8.useState(() => new Animated6.Value(1));
1124
+ React8.useEffect(() => {
1125
+ if (reduce) return;
1126
+ const loop = Animated6.loop(
1127
+ Animated6.sequence([
1128
+ Animated6.timing(opacity, { toValue: 0.5, duration: 900, useNativeDriver: true }),
1129
+ Animated6.timing(opacity, { toValue: 1, duration: 900, useNativeDriver: true })
1130
+ ])
1131
+ );
1132
+ loop.start();
1133
+ return () => {
1134
+ loop.stop();
1135
+ opacity.setValue(1);
1136
+ };
1137
+ }, [reduce, opacity]);
1138
+ const s = SHAPE[shape];
1139
+ const side = shape === "circle" ? width ?? height ?? s.width : void 0;
1140
+ return /* @__PURE__ */ jsx16(
1141
+ Animated6.View,
1142
+ {
1143
+ testID,
1144
+ "aria-hidden": true,
1145
+ style: [
1146
+ { width: side ?? width ?? s.width, height: side ?? height ?? s.height, borderRadius: s.radius, backgroundColor: theme.surface3, opacity },
1147
+ style
1148
+ ]
1149
+ }
1150
+ );
1151
+ }
1152
+
1153
+ // src/native/spinner.tsx
1154
+ import { ActivityIndicator as ActivityIndicator2 } from "react-native";
1155
+ import { jsx as jsx17 } from "react/jsx-runtime";
1156
+ function Spinner({ label, size = "md", ...props }) {
1157
+ const { theme } = useTheme();
1158
+ return /* @__PURE__ */ jsx17(
1159
+ ActivityIndicator2,
1160
+ {
1161
+ accessible: true,
1162
+ role: "progressbar",
1163
+ "aria-label": label,
1164
+ ...props,
1165
+ size: size === "lg" ? "large" : "small",
1166
+ color: theme.accent,
1167
+ style: [size === "sm" ? { transform: [{ scale: 0.75 }] } : null, props.style]
1168
+ }
1169
+ );
1170
+ }
1171
+
1172
+ // src/native/toast.tsx
1173
+ import * as React9 from "react";
1174
+ import { AccessibilityInfo as AccessibilityInfo4, Animated as Animated7, Pressable as Pressable5, StyleSheet as StyleSheet11, Text as Text7, View as View11 } from "react-native";
1175
+ import { Fragment as Fragment3, jsx as jsx18, jsxs as jsxs11 } from "react/jsx-runtime";
1176
+ var items = [];
1177
+ var listeners2 = /* @__PURE__ */ new Set();
1178
+ var counter = 0;
1179
+ var emit = () => listeners2.forEach((listener) => listener());
1180
+ var subscribe2 = (listener) => {
1181
+ listeners2.add(listener);
1182
+ return () => listeners2.delete(listener);
1183
+ };
1184
+ var snapshot = () => items;
1185
+ function show(title, options = {}) {
1186
+ const id = options.id ?? `kz-toast-${++counter}`;
1187
+ const item = { ...options, id, title };
1188
+ items = items.some((t) => t.id === id) ? items.map((t) => t.id === id ? item : t) : [...items, item];
1189
+ emit();
1190
+ return id;
1191
+ }
1192
+ function dismiss(id) {
1193
+ const gone = items.filter((t) => id === void 0 || t.id === id);
1194
+ if (gone.length === 0) return;
1195
+ items = id === void 0 ? [] : items.filter((t) => t.id !== id);
1196
+ emit();
1197
+ gone.forEach((t) => t.onDismiss?.());
1198
+ }
1199
+ var tone = (name) => (title, options) => show(title, { ...options, tone: name });
1200
+ var toast = Object.assign(show, {
1201
+ success: tone("success"),
1202
+ warning: tone("warning"),
1203
+ error: tone("error"),
1204
+ info: tone("info"),
1205
+ dismiss
1206
+ });
1207
+ function ToastView({ item, closeLabel, duration }) {
1208
+ const { theme, radius: radius3 } = useTheme();
1209
+ const reduce = useReducedMotion();
1210
+ const [enter] = React9.useState(() => new Animated7.Value(reduce ? 1 : 0));
1211
+ React9.useEffect(() => {
1212
+ if (reduce) enter.setValue(1);
1213
+ else Animated7.timing(enter, { toValue: 1, duration: 220, useNativeDriver: true }).start();
1214
+ }, [enter, reduce]);
1215
+ React9.useEffect(() => {
1216
+ AccessibilityInfo4.announceForAccessibility(item.description ? `${item.title}. ${item.description}` : item.title);
1217
+ }, [item.title, item.description]);
1218
+ const ms = item.duration ?? duration;
1219
+ React9.useEffect(() => {
1220
+ if (!Number.isFinite(ms)) return;
1221
+ const timer2 = setTimeout(() => dismiss(item.id), ms);
1222
+ return () => clearTimeout(timer2);
1223
+ }, [item.id, ms]);
1224
+ const edge = { success: theme.success, warning: theme.warning, error: theme.danger, info: theme.info, default: theme.borderDefault }[item.tone ?? "default"];
1225
+ const text = /* @__PURE__ */ jsxs11(Fragment3, { children: [
1226
+ item.icon ? /* @__PURE__ */ jsx18(View11, { "aria-hidden": true, children: item.icon }) : null,
1227
+ /* @__PURE__ */ jsxs11(View11, { style: styles11.content, children: [
1228
+ /* @__PURE__ */ jsx18(Txt, { variant: "label", numberOfLines: 2, children: item.title }),
1229
+ item.description ? /* @__PURE__ */ jsx18(Txt, { variant: "caption", tone: "secondary", numberOfLines: 3, children: item.description }) : null
1230
+ ] })
1231
+ ] });
1232
+ const body = /* @__PURE__ */ jsxs11(Fragment3, { children: [
1233
+ item.onPress ? /* @__PURE__ */ jsx18(
1234
+ Pressable5,
1235
+ {
1236
+ role: "button",
1237
+ onPress: () => {
1238
+ item.onPress?.();
1239
+ dismiss(item.id);
1240
+ },
1241
+ style: ({ pressed }) => [styles11.main, { opacity: pressed ? 0.8 : 1 }],
1242
+ children: text
1243
+ }
1244
+ ) : /* @__PURE__ */ jsx18(View11, { style: styles11.main, children: text }),
1245
+ item.action ? /* @__PURE__ */ jsx18(
1246
+ Pressable5,
1247
+ {
1248
+ role: "button",
1249
+ onPress: () => {
1250
+ item.action?.onPress();
1251
+ dismiss(item.id);
1252
+ },
1253
+ style: [styles11.action, { backgroundColor: theme.accent, borderRadius: radius3.sm }],
1254
+ children: /* @__PURE__ */ jsx18(Text7, { style: [styles11.actionLabel, { color: theme.onAccent }], children: item.action.label })
1255
+ }
1256
+ ) : null,
1257
+ /* @__PURE__ */ jsx18(Pressable5, { role: "button", "aria-label": closeLabel, hitSlop: 10, onPress: () => dismiss(item.id), style: styles11.close, children: /* @__PURE__ */ jsx18(Text7, { style: [styles11.cross, { color: theme.textSecondary }], children: "\xD7" }) })
1258
+ ] });
1259
+ const frame = [
1260
+ styles11.toast,
1261
+ { backgroundColor: theme.surface2, borderColor: theme.borderDefault, borderLeftColor: edge, borderRadius: radius3.lg, shadowColor: theme.scrimStrong }
1262
+ ];
1263
+ const motion3 = { transform: [{ translateY: enter.interpolate({ inputRange: [0, 1], outputRange: [-8, 0] }) }] };
1264
+ return /* @__PURE__ */ jsx18(Animated7.View, { "aria-live": "polite", style: motion3, children: /* @__PURE__ */ jsx18(View11, { style: frame, children: body }) });
1265
+ }
1266
+ function Toaster({ closeLabel, position = "top", offset = 12, duration = 6e3, max = 3 }) {
1267
+ const all = React9.useSyncExternalStore(subscribe2, snapshot, snapshot);
1268
+ const shown = all.slice(-max);
1269
+ if (shown.length === 0) return null;
1270
+ return /* @__PURE__ */ jsx18(View11, { pointerEvents: "box-none", style: [styles11.stack, position === "top" ? { top: offset } : { bottom: offset }], children: (position === "top" ? shown : [...shown].reverse()).map((item) => /* @__PURE__ */ jsx18(ToastView, { item, closeLabel, duration }, item.id)) });
1271
+ }
1272
+ var styles11 = StyleSheet11.create({
1273
+ stack: { position: "absolute", left: 12, right: 12, gap: 8, zIndex: 100 },
1274
+ toast: {
1275
+ flexDirection: "row",
1276
+ alignItems: "center",
1277
+ gap: 10,
1278
+ padding: 12,
1279
+ borderWidth: StyleSheet11.hairlineWidth,
1280
+ borderLeftWidth: 4,
1281
+ shadowOpacity: 0.3,
1282
+ shadowRadius: 16,
1283
+ shadowOffset: { width: 0, height: 8 },
1284
+ elevation: 8
1285
+ },
1286
+ main: { flex: 1, flexDirection: "row", alignItems: "center", gap: 10 },
1287
+ content: { flex: 1, gap: 2 },
1288
+ action: { paddingHorizontal: 12, paddingVertical: 6 },
1289
+ actionLabel: { fontSize: 12, fontWeight: "700" },
1290
+ close: { width: 28, height: 28, alignItems: "center", justifyContent: "center" },
1291
+ cross: { fontSize: 18, lineHeight: 20, fontWeight: "700" }
1292
+ });
92
1293
  export {
93
- OrochiaMark
1294
+ Avatar,
1295
+ AvatarGroup,
1296
+ AvatarRoot,
1297
+ Badge,
1298
+ Button,
1299
+ Card,
1300
+ CardBody,
1301
+ CardDescription,
1302
+ CardFooter,
1303
+ CardImage,
1304
+ CardMedia,
1305
+ CardOverlay,
1306
+ CardRoot,
1307
+ CardTitle,
1308
+ Chip,
1309
+ Countdown,
1310
+ EmptyState,
1311
+ IconButton,
1312
+ KrizakaMark,
1313
+ OrazakaMark,
1314
+ OrochiaMark,
1315
+ ProductMark,
1316
+ Progress,
1317
+ Segmented,
1318
+ Skeleton,
1319
+ Spinner,
1320
+ ThemeProvider,
1321
+ Toaster,
1322
+ Txt,
1323
+ alpha,
1324
+ splitDuration,
1325
+ textStyles,
1326
+ toast,
1327
+ useCountdown,
1328
+ useReducedMotion,
1329
+ useTheme
94
1330
  };
95
1331
  //# sourceMappingURL=native.js.map