kaleido-ui 0.1.46 → 0.1.49

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.
@@ -170,9 +170,149 @@ import {
170
170
  useTheme
171
171
  } from "@tetherto/wdk-uikit-react-native";
172
172
 
173
+ // src/native/components/qr-code.tsx
174
+ import { useMemo } from "react";
175
+ import { View } from "react-native";
176
+ import Svg, { Rect, Circle, G, Path } from "react-native-svg";
177
+ import encodeQR from "qr";
178
+ import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
179
+ function isFinderPattern(row, col, size) {
180
+ if (row < 7 && col < 7) return true;
181
+ if (row < 7 && col >= size - 7) return true;
182
+ if (row >= size - 7 && col < 7) return true;
183
+ return false;
184
+ }
185
+ function isLogoZone(row, col, size, logoModules) {
186
+ const center = size / 2;
187
+ const half = logoModules / 2;
188
+ return row >= center - half && row < center + half && col >= center - half && col < center + half;
189
+ }
190
+ function renderFinderPattern(originX, originY, moduleSize, fg, bg, key) {
191
+ const r = moduleSize * 0.6;
192
+ return [
193
+ /* @__PURE__ */ jsx2(
194
+ Rect,
195
+ {
196
+ x: originX,
197
+ y: originY,
198
+ width: moduleSize * 7,
199
+ height: moduleSize * 7,
200
+ rx: r * 2.5,
201
+ ry: r * 2.5,
202
+ fill: fg
203
+ },
204
+ `${key}-o`
205
+ ),
206
+ /* @__PURE__ */ jsx2(
207
+ Rect,
208
+ {
209
+ x: originX + moduleSize,
210
+ y: originY + moduleSize,
211
+ width: moduleSize * 5,
212
+ height: moduleSize * 5,
213
+ rx: r * 1.8,
214
+ ry: r * 1.8,
215
+ fill: bg
216
+ },
217
+ `${key}-i`
218
+ ),
219
+ /* @__PURE__ */ jsx2(
220
+ Rect,
221
+ {
222
+ x: originX + moduleSize * 2,
223
+ y: originY + moduleSize * 2,
224
+ width: moduleSize * 3,
225
+ height: moduleSize * 3,
226
+ rx: r * 1.2,
227
+ ry: r * 1.2,
228
+ fill: fg
229
+ },
230
+ `${key}-c`
231
+ )
232
+ ];
233
+ }
234
+ var LOGO_VIEWBOX = 412;
235
+ var LogoPaths = () => /* @__PURE__ */ jsxs(Fragment, { children: [
236
+ /* @__PURE__ */ jsx2(Path, { d: "M137.306 411.865H0.000244141L68.6795 343.29L137.306 411.865Z", fill: "#6F32FF" }),
237
+ /* @__PURE__ */ jsx2(Path, { d: "M0 0H137.306L68.6267 68.574L0 0Z", fill: "#6F32FF" }),
238
+ /* @__PURE__ */ jsx2(Path, { d: "M137.148 274.559H274.455L411.708 411.866H274.401L137.148 274.559Z", fill: "#17B581" }),
239
+ /* @__PURE__ */ jsx2(
240
+ Path,
241
+ {
242
+ d: "M137.149 274.559L68.6274 205.933L137.201 137.306L274.455 137.411L205.776 206.038L274.456 274.559H137.149Z",
243
+ fill: "#15E99A"
244
+ }
245
+ ),
246
+ /* @__PURE__ */ jsx2(Path, { d: "M274.479 0.104797H411.786L274.533 137.411H137.226L274.479 0.104797Z", fill: "#17B581" })
247
+ ] });
248
+ function QrCode({
249
+ value,
250
+ size = 160,
251
+ color = "#040404",
252
+ backgroundColor = "#ffffff"
253
+ }) {
254
+ const { elements, svgSize } = useMemo(() => {
255
+ if (!value) return { elements: [], svgSize: 0 };
256
+ const matrix = encodeQR(value, "raw", { ecc: "medium", border: 0 });
257
+ const n = matrix.length;
258
+ const moduleSize = 10;
259
+ const quietZone = moduleSize * 2;
260
+ const computedSize = n * moduleSize + quietZone * 2;
261
+ const fg = color;
262
+ const bg = backgroundColor;
263
+ const logoModules = Math.ceil(n * 0.2);
264
+ const logoZoneSize = logoModules % 2 === 0 ? logoModules + 1 : logoModules;
265
+ const els = [];
266
+ const dotRadius = moduleSize * 0.42;
267
+ for (let row = 0; row < n; row++) {
268
+ for (let col = 0; col < n; col++) {
269
+ if (isFinderPattern(row, col, n)) continue;
270
+ if (isLogoZone(row, col, n, logoZoneSize)) continue;
271
+ if (!matrix[row][col]) continue;
272
+ const cx = quietZone + col * moduleSize + moduleSize / 2;
273
+ const cy = quietZone + row * moduleSize + moduleSize / 2;
274
+ els.push(/* @__PURE__ */ jsx2(Circle, { cx, cy, r: dotRadius, fill: fg }, `d-${row}-${col}`));
275
+ }
276
+ }
277
+ const finderPositions = [
278
+ [0, 0],
279
+ [0, n - 7],
280
+ [n - 7, 0]
281
+ ];
282
+ for (const [r, c] of finderPositions) {
283
+ els.push(
284
+ ...renderFinderPattern(
285
+ quietZone + c * moduleSize,
286
+ quietZone + r * moduleSize,
287
+ moduleSize,
288
+ fg,
289
+ bg,
290
+ `fp-${r}-${c}`
291
+ )
292
+ );
293
+ }
294
+ const centerX = quietZone + n * moduleSize / 2;
295
+ const centerY = quietZone + n * moduleSize / 2;
296
+ const logoCircleR = logoZoneSize * moduleSize * 0.52;
297
+ els.push(/* @__PURE__ */ jsx2(Circle, { cx: centerX, cy: centerY, r: logoCircleR, fill: bg }, "logo-bg"));
298
+ const logoBox = logoCircleR * 1.35;
299
+ const logoX = centerX - logoBox / 2;
300
+ const logoY = centerY - logoBox / 2;
301
+ const scale = logoBox / LOGO_VIEWBOX;
302
+ els.push(
303
+ /* @__PURE__ */ jsx2(G, { transform: `translate(${logoX}, ${logoY}) scale(${scale})`, children: /* @__PURE__ */ jsx2(LogoPaths, {}) }, "logo")
304
+ );
305
+ return { elements: els, svgSize: computedSize };
306
+ }, [value, color, backgroundColor]);
307
+ if (!value || svgSize === 0) {
308
+ return /* @__PURE__ */ jsx2(View, { style: { width: size, height: size } });
309
+ }
310
+ return /* @__PURE__ */ jsx2(View, { style: { width: size, height: size }, children: /* @__PURE__ */ jsx2(Svg, { width: size, height: size, viewBox: `0 0 ${svgSize} ${svgSize}`, children: elements }) });
311
+ }
312
+
173
313
  // src/native/components/status-badge.tsx
174
- import { View, Text, StyleSheet } from "react-native";
175
- import { jsx as jsx2 } from "react/jsx-runtime";
314
+ import { View as View2, Text, StyleSheet } from "react-native";
315
+ import { jsx as jsx3 } from "react/jsx-runtime";
176
316
  var statusConfig = {
177
317
  success: { color: colors.primary, bg: `${colors.primary}1A`, borderColor: `${colors.primary}33`, label: "Success" },
178
318
  completed: { color: colors.primary, bg: `${colors.primary}1A`, borderColor: `${colors.primary}33`, label: "Completed" },
@@ -182,7 +322,7 @@ var statusConfig = {
182
322
  };
183
323
  function StatusBadge({ status, style }) {
184
324
  const config = statusConfig[status];
185
- return /* @__PURE__ */ jsx2(View, { style: [styles.container, { backgroundColor: config.bg, borderColor: config.borderColor }, style], children: /* @__PURE__ */ jsx2(Text, { style: [styles.label, { color: config.color }], children: config.label }) });
325
+ return /* @__PURE__ */ jsx3(View2, { style: [styles.container, { backgroundColor: config.bg, borderColor: config.borderColor }, style], children: /* @__PURE__ */ jsx3(Text, { style: [styles.label, { color: config.color }], children: config.label }) });
186
326
  }
187
327
  var styles = StyleSheet.create({
188
328
  container: {
@@ -200,8 +340,8 @@ var styles = StyleSheet.create({
200
340
  });
201
341
 
202
342
  // src/native/components/network-badge.tsx
203
- import { View as View2, Text as Text2, StyleSheet as StyleSheet2 } from "react-native";
204
- import { jsx as jsx3 } from "react/jsx-runtime";
343
+ import { View as View3, Text as Text2, StyleSheet as StyleSheet2 } from "react-native";
344
+ import { jsx as jsx4 } from "react/jsx-runtime";
205
345
  var networkConfig = {
206
346
  L1: { color: colors.network.bitcoin, label: "L1" },
207
347
  LN: { color: colors.network.lightning, label: "LN" },
@@ -214,7 +354,7 @@ var networkConfig = {
214
354
  };
215
355
  function NetworkBadge({ network, style }) {
216
356
  const config = networkConfig[network];
217
- return /* @__PURE__ */ jsx3(View2, { style: [styles2.container, { backgroundColor: `${config.color}1A`, borderColor: `${config.color}33` }, style], children: /* @__PURE__ */ jsx3(Text2, { style: [styles2.label, { color: config.color }], children: config.label }) });
357
+ return /* @__PURE__ */ jsx4(View3, { style: [styles2.container, { backgroundColor: `${config.color}1A`, borderColor: `${config.color}33` }, style], children: /* @__PURE__ */ jsx4(Text2, { style: [styles2.label, { color: config.color }], children: config.label }) });
218
358
  }
219
359
  var styles2 = StyleSheet2.create({
220
360
  container: {
@@ -233,8 +373,8 @@ var styles2 = StyleSheet2.create({
233
373
  });
234
374
 
235
375
  // src/native/components/alert-banner.tsx
236
- import { View as View3, Text as Text3, StyleSheet as StyleSheet3 } from "react-native";
237
- import { jsx as jsx4 } from "react/jsx-runtime";
376
+ import { View as View4, Text as Text3, StyleSheet as StyleSheet3 } from "react-native";
377
+ import { jsx as jsx5 } from "react/jsx-runtime";
238
378
  var variantConfig = {
239
379
  error: { bg: `${colors.danger}1A`, borderColor: `${colors.danger}33`, iconColor: colors.danger },
240
380
  warning: { bg: `${colors.warning}1A`, borderColor: `${colors.warning}33`, iconColor: colors.warning },
@@ -243,7 +383,7 @@ var variantConfig = {
243
383
  };
244
384
  function AlertBanner({ variant = "info", children, style }) {
245
385
  const config = variantConfig[variant];
246
- return /* @__PURE__ */ jsx4(View3, { style: [styles3.container, { backgroundColor: config.bg, borderColor: config.borderColor }, style], children: typeof children === "string" ? /* @__PURE__ */ jsx4(Text3, { style: styles3.text, children }) : children });
386
+ return /* @__PURE__ */ jsx5(View4, { style: [styles3.container, { backgroundColor: config.bg, borderColor: config.borderColor }, style], children: typeof children === "string" ? /* @__PURE__ */ jsx5(Text3, { style: styles3.text, children }) : children });
247
387
  }
248
388
  var styles3 = StyleSheet3.create({
249
389
  container: {
@@ -263,9 +403,9 @@ var styles3 = StyleSheet3.create({
263
403
 
264
404
  // src/native/components/section-label.tsx
265
405
  import { Text as Text4, StyleSheet as StyleSheet4 } from "react-native";
266
- import { jsx as jsx5 } from "react/jsx-runtime";
406
+ import { jsx as jsx6 } from "react/jsx-runtime";
267
407
  function SectionLabel({ children, style }) {
268
- return /* @__PURE__ */ jsx5(Text4, { style: [styles4.label, style], children: typeof children === "string" ? children.toUpperCase() : children });
408
+ return /* @__PURE__ */ jsx6(Text4, { style: [styles4.label, style], children: typeof children === "string" ? children.toUpperCase() : children });
269
409
  }
270
410
  var styles4 = StyleSheet4.create({
271
411
  label: {
@@ -276,6 +416,551 @@ var styles4 = StyleSheet4.create({
276
416
  }
277
417
  });
278
418
 
419
+ // src/native/theme-context.tsx
420
+ import { createContext, useContext, useMemo as useMemo2, useState } from "react";
421
+
422
+ // src/tokens/theme.ts
423
+ var nativeType = {
424
+ mini: { size: 9, line: 12 },
425
+ xxs: { size: 10, line: 14 },
426
+ tiny: { size: 11, line: 16 },
427
+ caption: { size: 13, line: 18 },
428
+ body: { size: 15, line: 22 },
429
+ subhead: { size: 17, line: 24 },
430
+ title: { size: 20, line: 28 },
431
+ headline: { size: 28, line: 34 },
432
+ display: { size: 36, line: 40 },
433
+ hero: { size: 44, line: 48 }
434
+ };
435
+ var NETWORK_GLYPH = {
436
+ bitcoin: "#F7931A",
437
+ lightning: "#F6C343",
438
+ spark: "#FF6D00",
439
+ rgb: "#DD352E",
440
+ arkade: "#7C3AED",
441
+ liquid: "#22E1C9"
442
+ };
443
+ var dark = {
444
+ mode: "dark",
445
+ background: "#0D1813",
446
+ card: "#121C16",
447
+ cardElevated: "#17231C",
448
+ primary: "#15E99A",
449
+ primaryFg: "#062318",
450
+ violet: "#8B5CFF",
451
+ violetSurface: "rgba(111, 50, 255, 0.18)",
452
+ success: "#2BEE79",
453
+ warning: "#FACC15",
454
+ danger: "#F94040",
455
+ info: "#4290FF",
456
+ successSurface: "rgba(43, 238, 121, 0.14)",
457
+ warningSurface: "rgba(250, 204, 21, 0.14)",
458
+ dangerSurface: "rgba(249, 64, 64, 0.14)",
459
+ infoSurface: "rgba(66, 144, 255, 0.14)",
460
+ text: {
461
+ primary: "#FFFFFF",
462
+ secondary: "rgba(255, 255, 255, 0.64)",
463
+ muted: "rgba(255, 255, 255, 0.42)",
464
+ disabled: "rgba(255, 255, 255, 0.26)",
465
+ onAccent: "#062318",
466
+ onFill: "#FFFFFF"
467
+ },
468
+ border: {
469
+ subtle: "rgba(255, 255, 255, 0.06)",
470
+ default: "rgba(255, 255, 255, 0.10)",
471
+ strong: "rgba(255, 255, 255, 0.16)"
472
+ },
473
+ surface: {
474
+ base: "rgba(255, 255, 255, 0.03)",
475
+ raised: "rgba(255, 255, 255, 0.06)",
476
+ sunken: "rgba(0, 0, 0, 0.22)",
477
+ overlay: "rgba(0, 0, 0, 0.55)",
478
+ scrim: "rgba(0, 0, 0, 0.70)"
479
+ },
480
+ network: NETWORK_GLYPH,
481
+ networkSurface: {
482
+ bitcoin: "#3A2D18",
483
+ lightning: "#39351A",
484
+ spark: "#3A2A1C",
485
+ rgb: "#3C2422",
486
+ arkade: "#2E2548",
487
+ liquid: "#0E2A2C"
488
+ },
489
+ tx: { sent: "#F94040", receive: "#2BEE79", swap: "#4290FF" },
490
+ gradientBrand: ["#15E99A", "#6F32FF"]
491
+ };
492
+ var light = {
493
+ mode: "light",
494
+ background: "#F4F5F2",
495
+ card: "#FFFFFF",
496
+ cardElevated: "#FFFFFF",
497
+ primary: "#13D88E",
498
+ primaryFg: "#04231A",
499
+ violet: "#6F32FF",
500
+ violetSurface: "rgba(111, 50, 255, 0.12)",
501
+ success: "#0FB67C",
502
+ warning: "#C8881A",
503
+ danger: "#E2403B",
504
+ info: "#2F73E0",
505
+ successSurface: "rgba(15, 182, 124, 0.12)",
506
+ warningSurface: "rgba(200, 136, 26, 0.12)",
507
+ dangerSurface: "rgba(226, 64, 59, 0.12)",
508
+ infoSurface: "rgba(47, 115, 224, 0.12)",
509
+ text: {
510
+ primary: "#0D1813",
511
+ secondary: "rgba(13, 24, 19, 0.62)",
512
+ muted: "rgba(13, 24, 19, 0.44)",
513
+ disabled: "rgba(13, 24, 19, 0.26)",
514
+ onAccent: "#04231A",
515
+ onFill: "#FFFFFF"
516
+ },
517
+ border: {
518
+ subtle: "rgba(13, 24, 19, 0.06)",
519
+ default: "rgba(13, 24, 19, 0.10)",
520
+ strong: "rgba(13, 24, 19, 0.16)"
521
+ },
522
+ surface: {
523
+ base: "rgba(13, 24, 19, 0.02)",
524
+ raised: "rgba(13, 24, 19, 0.04)",
525
+ sunken: "rgba(13, 24, 19, 0.04)",
526
+ overlay: "rgba(13, 24, 19, 0.40)",
527
+ scrim: "rgba(13, 24, 19, 0.55)"
528
+ },
529
+ network: NETWORK_GLYPH,
530
+ networkSurface: {
531
+ bitcoin: "#FBEFD9",
532
+ lightning: "#FCF6D6",
533
+ spark: "#FFE7D6",
534
+ rgb: "#FBE3E1",
535
+ arkade: "#ECE4FF",
536
+ liquid: "#D8F5F1"
537
+ },
538
+ tx: { sent: "#E2403B", receive: "#0FB67C", swap: "#2F73E0" },
539
+ gradientBrand: ["#15E99A", "#6F32FF"]
540
+ };
541
+ var themes = { light, dark };
542
+ function makeTheme(mode) {
543
+ return themes[mode];
544
+ }
545
+
546
+ // src/native/theme-context.tsx
547
+ import { jsx as jsx7 } from "react/jsx-runtime";
548
+ var KaleidoThemeContext = createContext(null);
549
+ function KaleidoUIProvider({
550
+ children,
551
+ mode: controlledMode,
552
+ defaultMode = "dark",
553
+ onModeChange,
554
+ fontFamily: fontFamily2
555
+ }) {
556
+ const [internalMode, setInternalMode] = useState(defaultMode);
557
+ const activeMode = controlledMode ?? internalMode;
558
+ const setMode = (next) => {
559
+ if (controlledMode === void 0) setInternalMode(next);
560
+ onModeChange?.(next);
561
+ };
562
+ const toggleMode = () => setMode(activeMode === "dark" ? "light" : "dark");
563
+ const value = useMemo2(
564
+ () => ({ theme: makeTheme(activeMode), mode: activeMode, fontFamily: fontFamily2, setMode, toggleMode }),
565
+ // setMode/toggleMode are stable enough for this context's purpose
566
+ [activeMode, fontFamily2]
567
+ );
568
+ return /* @__PURE__ */ jsx7(KaleidoThemeContext.Provider, { value, children });
569
+ }
570
+ function useKaleidoTheme() {
571
+ const ctx = useContext(KaleidoThemeContext);
572
+ if (ctx) return ctx;
573
+ return {
574
+ theme: makeTheme("dark"),
575
+ mode: "dark",
576
+ fontFamily: void 0,
577
+ setMode: () => {
578
+ },
579
+ toggleMode: () => {
580
+ }
581
+ };
582
+ }
583
+
584
+ // src/native/components/k-text.tsx
585
+ import { Text as Text5 } from "react-native";
586
+ import { jsx as jsx8 } from "react/jsx-runtime";
587
+ var WEIGHT_MAP = {
588
+ normal: "400",
589
+ medium: "500",
590
+ semibold: "600",
591
+ bold: "700"
592
+ };
593
+ function KText({
594
+ variant = "body",
595
+ weight = "normal",
596
+ tone = "primary",
597
+ color,
598
+ eyebrow = false,
599
+ center = false,
600
+ style,
601
+ children,
602
+ ...rest
603
+ }) {
604
+ const { theme, fontFamily: fontFamily2 } = useKaleidoTheme();
605
+ const scale = nativeType[variant];
606
+ const toneColor = color ?? (tone === "accent" ? theme.primary : tone === "violet" ? theme.violet : tone === "success" ? theme.success : tone === "warning" ? theme.warning : tone === "danger" ? theme.danger : theme.text[tone]);
607
+ const tracking = eyebrow ? 1.2 : scale.size >= 28 ? -0.5 : 0;
608
+ return /* @__PURE__ */ jsx8(
609
+ Text5,
610
+ {
611
+ ...rest,
612
+ style: [
613
+ {
614
+ fontFamily: fontFamily2,
615
+ fontSize: scale.size,
616
+ lineHeight: scale.line,
617
+ fontWeight: WEIGHT_MAP[weight],
618
+ color: toneColor,
619
+ letterSpacing: tracking,
620
+ textAlign: center ? "center" : void 0,
621
+ textTransform: eyebrow ? "uppercase" : void 0
622
+ },
623
+ style
624
+ ],
625
+ children
626
+ }
627
+ );
628
+ }
629
+
630
+ // src/native/components/k-screen.tsx
631
+ import { StatusBar, View as View5 } from "react-native";
632
+ import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
633
+ function KScreen({ elevated = false, style, children, ...rest }) {
634
+ const { theme, mode } = useKaleidoTheme();
635
+ return /* @__PURE__ */ jsxs2(
636
+ View5,
637
+ {
638
+ ...rest,
639
+ style: [{ flex: 1, backgroundColor: elevated ? theme.card : theme.background }, style],
640
+ children: [
641
+ /* @__PURE__ */ jsx9(
642
+ StatusBar,
643
+ {
644
+ barStyle: mode === "dark" ? "light-content" : "dark-content",
645
+ backgroundColor: "transparent",
646
+ translucent: true
647
+ }
648
+ ),
649
+ children
650
+ ]
651
+ }
652
+ );
653
+ }
654
+
655
+ // src/native/components/k-card.tsx
656
+ import { View as View6 } from "react-native";
657
+ import { jsx as jsx10 } from "react/jsx-runtime";
658
+ function KCard({
659
+ variant = "default",
660
+ padding = 16,
661
+ radius: radius2 = 16,
662
+ bordered = true,
663
+ style,
664
+ children,
665
+ ...rest
666
+ }) {
667
+ const { theme } = useKaleidoTheme();
668
+ const backgroundColor = variant === "elevated" ? theme.cardElevated : variant === "inset" ? theme.surface.base : variant === "outline" ? "transparent" : theme.card;
669
+ return /* @__PURE__ */ jsx10(
670
+ View6,
671
+ {
672
+ ...rest,
673
+ style: [
674
+ {
675
+ backgroundColor,
676
+ borderRadius: radius2,
677
+ padding,
678
+ borderWidth: bordered ? 1 : 0,
679
+ borderColor: theme.border.subtle
680
+ },
681
+ style
682
+ ],
683
+ children
684
+ }
685
+ );
686
+ }
687
+
688
+ // src/native/components/k-button.tsx
689
+ import {
690
+ ActivityIndicator,
691
+ Pressable,
692
+ View as View7
693
+ } from "react-native";
694
+ import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
695
+ var SIZE = {
696
+ sm: { h: 40, px: 16, type: "caption" },
697
+ md: { h: 52, px: 20, type: "body" },
698
+ lg: { h: 58, px: 24, type: "subhead" }
699
+ };
700
+ function KButton({
701
+ label,
702
+ variant = "primary",
703
+ size = "md",
704
+ loading = false,
705
+ fullWidth = false,
706
+ leading,
707
+ disabled,
708
+ style,
709
+ ...rest
710
+ }) {
711
+ const { theme } = useKaleidoTheme();
712
+ const s = SIZE[size];
713
+ const isDisabled = disabled || loading;
714
+ const palette = (pressed) => {
715
+ switch (variant) {
716
+ case "secondary":
717
+ return { bg: pressed ? theme.surface.raised : "transparent", border: theme.border.strong, fg: theme.text.primary };
718
+ case "violet":
719
+ return { bg: theme.violet, border: theme.violet, fg: theme.text.onFill };
720
+ case "ghost":
721
+ return { bg: pressed ? theme.surface.base : "transparent", border: "transparent", fg: theme.primary };
722
+ case "danger":
723
+ return { bg: theme.danger, border: theme.danger, fg: theme.text.onFill };
724
+ case "primary":
725
+ default:
726
+ return { bg: theme.primary, border: theme.primary, fg: theme.primaryFg };
727
+ }
728
+ };
729
+ return /* @__PURE__ */ jsx11(
730
+ Pressable,
731
+ {
732
+ accessibilityRole: "button",
733
+ accessibilityState: { disabled: !!isDisabled, busy: loading },
734
+ disabled: isDisabled,
735
+ style: ({ pressed }) => {
736
+ const p = palette(pressed);
737
+ return {
738
+ height: s.h,
739
+ paddingHorizontal: s.px,
740
+ borderRadius: 14,
741
+ borderWidth: 1,
742
+ borderColor: p.border,
743
+ backgroundColor: p.bg,
744
+ alignItems: "center",
745
+ justifyContent: "center",
746
+ flexDirection: "row",
747
+ alignSelf: fullWidth ? "stretch" : "flex-start",
748
+ opacity: isDisabled ? 0.45 : pressed ? 0.92 : 1,
749
+ ...style
750
+ };
751
+ },
752
+ ...rest,
753
+ children: loading ? /* @__PURE__ */ jsx11(ActivityIndicator, { color: palette(false).fg }) : /* @__PURE__ */ jsxs3(View7, { style: { flexDirection: "row", alignItems: "center", gap: 8 }, children: [
754
+ leading,
755
+ /* @__PURE__ */ jsx11(KText, { variant: s.type, weight: "bold", color: palette(false).fg, children: label })
756
+ ] })
757
+ }
758
+ );
759
+ }
760
+
761
+ // src/native/components/action-button.tsx
762
+ import { Pressable as Pressable2, View as View8 } from "react-native";
763
+ import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
764
+ function ActionButton({
765
+ label,
766
+ icon,
767
+ onPress,
768
+ tone = "neutral",
769
+ filled = false,
770
+ disabled = false,
771
+ size = 56
772
+ }) {
773
+ const { theme } = useKaleidoTheme();
774
+ const accent = tone === "violet" ? theme.violet : tone === "primary" ? theme.primary : theme.text.primary;
775
+ const tileBg = filled ? accent : theme.surface.raised;
776
+ const glyphColor = filled ? tone === "violet" ? theme.text.onFill : theme.primaryFg : accent;
777
+ return /* @__PURE__ */ jsxs4(
778
+ Pressable2,
779
+ {
780
+ onPress,
781
+ disabled,
782
+ accessibilityRole: "button",
783
+ accessibilityLabel: label,
784
+ style: ({ pressed }) => ({
785
+ alignItems: "center",
786
+ gap: 8,
787
+ opacity: disabled ? 0.4 : pressed ? 0.85 : 1
788
+ }),
789
+ children: [
790
+ /* @__PURE__ */ jsx12(
791
+ View8,
792
+ {
793
+ style: {
794
+ width: size,
795
+ height: size,
796
+ borderRadius: size / 2,
797
+ backgroundColor: tileBg,
798
+ borderWidth: filled ? 0 : 1,
799
+ borderColor: theme.border.subtle,
800
+ alignItems: "center",
801
+ justifyContent: "center"
802
+ },
803
+ children: icon(glyphColor, Math.round(size * 0.42))
804
+ }
805
+ ),
806
+ /* @__PURE__ */ jsx12(KText, { variant: "caption", weight: "medium", tone: "secondary", children: label })
807
+ ]
808
+ }
809
+ );
810
+ }
811
+
812
+ // src/native/components/balance-card.tsx
813
+ import { View as View9 } from "react-native";
814
+ import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
815
+ function BalanceCard({
816
+ label = "Total Balance",
817
+ amount,
818
+ unit,
819
+ fiat,
820
+ footer,
821
+ style,
822
+ ...rest
823
+ }) {
824
+ const { theme } = useKaleidoTheme();
825
+ return /* @__PURE__ */ jsxs5(View9, { ...rest, style: [{ alignItems: "center", gap: 6 }, style], children: [
826
+ !!label && /* @__PURE__ */ jsx13(KText, { variant: "caption", weight: "medium", tone: "muted", eyebrow: true, children: label }),
827
+ /* @__PURE__ */ jsxs5(View9, { style: { flexDirection: "row", alignItems: "baseline", gap: 8 }, children: [
828
+ /* @__PURE__ */ jsx13(KText, { variant: "hero", weight: "bold", tone: "primary", children: amount }),
829
+ !!unit && /* @__PURE__ */ jsx13(KText, { variant: "title", weight: "medium", tone: "secondary", children: unit })
830
+ ] }),
831
+ !!fiat && /* @__PURE__ */ jsx13(KText, { variant: "body", weight: "medium", color: theme.text.muted, children: fiat }),
832
+ footer
833
+ ] });
834
+ }
835
+
836
+ // src/native/components/network-chip.tsx
837
+ import { Pressable as Pressable3, View as View10 } from "react-native";
838
+ import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
839
+ function NetworkChip({
840
+ network,
841
+ title,
842
+ subtitle,
843
+ selected = false,
844
+ onPress,
845
+ icon,
846
+ dot = false
847
+ }) {
848
+ const { theme } = useKaleidoTheme();
849
+ const glyph = network ? theme.network[network] : theme.text.secondary;
850
+ const glyphBg = network ? theme.networkSurface[network] : theme.surface.raised;
851
+ return /* @__PURE__ */ jsxs6(
852
+ Pressable3,
853
+ {
854
+ onPress,
855
+ accessibilityRole: "button",
856
+ accessibilityState: { selected },
857
+ style: ({ pressed }) => ({
858
+ flexDirection: "row",
859
+ alignItems: "center",
860
+ gap: 10,
861
+ paddingVertical: 10,
862
+ paddingHorizontal: 12,
863
+ borderRadius: 14,
864
+ backgroundColor: selected ? theme.violetSurface : theme.surface.base,
865
+ borderWidth: 1.5,
866
+ borderColor: selected ? theme.violet : theme.border.subtle,
867
+ opacity: pressed ? 0.9 : 1
868
+ }),
869
+ children: [
870
+ icon && /* @__PURE__ */ jsx14(
871
+ View10,
872
+ {
873
+ style: {
874
+ width: 30,
875
+ height: 30,
876
+ borderRadius: 15,
877
+ backgroundColor: glyphBg,
878
+ alignItems: "center",
879
+ justifyContent: "center"
880
+ },
881
+ children: icon(glyph, 16)
882
+ }
883
+ ),
884
+ /* @__PURE__ */ jsxs6(View10, { style: { gap: 1 }, children: [
885
+ /* @__PURE__ */ jsx14(KText, { variant: "caption", weight: "bold", color: selected ? theme.violet : theme.text.primary, children: title }),
886
+ !!subtitle && /* @__PURE__ */ jsx14(KText, { variant: "mini", weight: "medium", tone: "muted", children: subtitle })
887
+ ] }),
888
+ dot && /* @__PURE__ */ jsx14(
889
+ View10,
890
+ {
891
+ style: {
892
+ width: 7,
893
+ height: 7,
894
+ borderRadius: 4,
895
+ backgroundColor: theme.primary,
896
+ marginLeft: 2
897
+ }
898
+ }
899
+ )
900
+ ]
901
+ }
902
+ );
903
+ }
904
+
905
+ // src/native/components/empty-state.tsx
906
+ import { View as View11 } from "react-native";
907
+ import { jsx as jsx15, jsxs as jsxs7 } from "react/jsx-runtime";
908
+ function EmptyState({ title, description, icon, action, style, ...rest }) {
909
+ const { theme } = useKaleidoTheme();
910
+ return /* @__PURE__ */ jsxs7(View11, { ...rest, style: [{ alignItems: "center", paddingVertical: 36, gap: 12 }, style], children: [
911
+ icon && /* @__PURE__ */ jsx15(
912
+ View11,
913
+ {
914
+ style: {
915
+ width: 64,
916
+ height: 64,
917
+ borderRadius: 32,
918
+ backgroundColor: theme.surface.raised,
919
+ alignItems: "center",
920
+ justifyContent: "center"
921
+ },
922
+ children: icon(theme.text.muted, 28)
923
+ }
924
+ ),
925
+ /* @__PURE__ */ jsxs7(View11, { style: { alignItems: "center", gap: 4 }, children: [
926
+ /* @__PURE__ */ jsx15(KText, { variant: "subhead", weight: "bold", tone: "primary", center: true, children: title }),
927
+ !!description && /* @__PURE__ */ jsx15(KText, { variant: "caption", tone: "muted", center: true, children: description })
928
+ ] }),
929
+ action
930
+ ] });
931
+ }
932
+
933
+ // src/native/components/mode-toggle.tsx
934
+ import { Pressable as Pressable4, View as View12 } from "react-native";
935
+ import { jsx as jsx16 } from "react/jsx-runtime";
936
+ function ModeToggle({ icon, size = 40, onToggle }) {
937
+ const { theme, mode, toggleMode } = useKaleidoTheme();
938
+ return /* @__PURE__ */ jsx16(
939
+ Pressable4,
940
+ {
941
+ accessibilityRole: "switch",
942
+ accessibilityState: { checked: mode === "dark" },
943
+ accessibilityLabel: mode === "dark" ? "Switch to light mode" : "Switch to dark mode",
944
+ onPress: () => {
945
+ toggleMode();
946
+ onToggle?.(mode === "dark" ? "light" : "dark");
947
+ },
948
+ style: ({ pressed }) => ({
949
+ width: size,
950
+ height: size,
951
+ borderRadius: size / 2,
952
+ backgroundColor: theme.surface.raised,
953
+ borderWidth: 1,
954
+ borderColor: theme.border.subtle,
955
+ alignItems: "center",
956
+ justifyContent: "center",
957
+ opacity: pressed ? 0.85 : 1
958
+ }),
959
+ children: /* @__PURE__ */ jsx16(View12, { children: icon(mode, theme.text.primary, Math.round(size * 0.5)) })
960
+ }
961
+ );
962
+ }
963
+
279
964
  // src/tokens/typography.ts
280
965
  var fontFamily = {
281
966
  display: "'Satoshi', system-ui, -apple-system, sans-serif",
@@ -343,15 +1028,26 @@ var transition = {
343
1028
  slow: "300ms ease-out"
344
1029
  };
345
1030
  export {
1031
+ ActionButton,
346
1032
  AlertBanner,
347
1033
  AmountInput,
348
1034
  AssetSelector,
349
1035
  Balance,
1036
+ BalanceCard,
350
1037
  CryptoAddressInput,
1038
+ EmptyState,
1039
+ KButton,
1040
+ KCard,
1041
+ KScreen,
1042
+ KText,
351
1043
  KaleidoThemeProvider,
1044
+ KaleidoUIProvider,
1045
+ ModeToggle,
352
1046
  NetworkBadge,
1047
+ NetworkChip,
353
1048
  NetworkSelector,
354
1049
  QRCode,
1050
+ QrCode,
355
1051
  SectionLabel,
356
1052
  SeedPhrase,
357
1053
  StatusBadge,
@@ -363,9 +1059,13 @@ export {
363
1059
  fontWeight,
364
1060
  kaleidoswapBrandConfig,
365
1061
  kaleidoswapTokens,
1062
+ makeTheme,
1063
+ nativeType,
366
1064
  radius,
367
1065
  shadow,
1066
+ themes,
368
1067
  transition,
369
1068
  typeScale,
1069
+ useKaleidoTheme,
370
1070
  useTheme
371
1071
  };