@kjun-ui/native 0.14.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1738,6 +1738,18 @@ function KjunFormLayout({
1738
1738
  ) });
1739
1739
  }
1740
1740
 
1741
+ // shared/package-runtime/use-after-close.ts
1742
+ import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef6 } from "react";
1743
+ function useAfterClose(present, onAfterClose, enabled = true) {
1744
+ const was = useRef6(present), callback = useRef6(onAfterClose);
1745
+ callback.current = onAfterClose;
1746
+ useEffect4(() => {
1747
+ var _a;
1748
+ if (was.current && !present && enabled) (_a = callback.current) == null ? void 0 : _a.call(callback);
1749
+ was.current = present;
1750
+ }, [present, enabled]);
1751
+ }
1752
+
1741
1753
  // shared/package-runtime/content-presence.ts
1742
1754
  import { Fragment as Fragment2, isValidElement as isValidElement2 } from "react";
1743
1755
  function hasContent(node) {
@@ -1779,8 +1791,9 @@ import {
1779
1791
  import {
1780
1792
  createContext as createContext14,
1781
1793
  useContext as useContext9,
1782
- useEffect as useEffect4,
1783
- useId as useId3
1794
+ useEffect as useEffect5,
1795
+ useId as useId3,
1796
+ useRef as useRef7
1784
1797
  } from "react";
1785
1798
  import { Platform as Platform9, View as View6 } from "react-native";
1786
1799
 
@@ -1797,13 +1810,14 @@ var FeedbackOverlayContext = createContext14(
1797
1810
  null
1798
1811
  );
1799
1812
  function ScopedNativeModal({ children, visible, ...props }) {
1800
- var _a;
1801
1813
  const layers = useLayerState(), scope = useContext9(LayerScope);
1802
1814
  const entry = scope ? layers.entries.get(scope) : void 0;
1803
- const generation = (_a = entry == null ? void 0 : entry.order) != null ? _a : 0;
1815
+ const last = useRef7(0);
1816
+ if (entry) last.current = entry.order;
1817
+ const generation = last.current;
1804
1818
  const inactive = !!scope && !layers.isActive(scope);
1805
1819
  const host = useContext9(FeedbackOverlayContext), id = "kjun-" + useId3(), register = host == null ? void 0 : host.register;
1806
- useEffect4(
1820
+ useEffect5(
1807
1821
  () => visible && register ? register(id) : void 0,
1808
1822
  [visible, register, id, generation]
1809
1823
  );
@@ -1928,6 +1942,7 @@ function KjunModal({
1928
1942
  open,
1929
1943
  onOpenChange,
1930
1944
  onClose,
1945
+ onAfterClose,
1931
1946
  onCancel,
1932
1947
  onConfirm,
1933
1948
  title = "",
@@ -1975,10 +1990,15 @@ function KjunModal({
1975
1990
  const layer = useLayer(open, motion.present, "window", () => {
1976
1991
  if (closeOnEsc) close();
1977
1992
  });
1993
+ const iosDismiss = Platform10.OS === "ios";
1994
+ useAfterClose(motion.present, onAfterClose, !iosDismiss);
1978
1995
  return /* @__PURE__ */ jsx13(LayerScope.Provider, { value: layer.id, children: /* @__PURE__ */ jsx13(
1979
1996
  ScopedNativeModal,
1980
1997
  {
1981
1998
  visible: motion.present,
1999
+ onDismiss: iosDismiss ? () => {
2000
+ if (!open) onAfterClose == null ? void 0 : onAfterClose();
2001
+ } : void 0,
1982
2002
  transparent: true,
1983
2003
  animationType: "none",
1984
2004
  onRequestClose: () => {
@@ -2246,7 +2266,7 @@ function alertRole(tone, live) {
2246
2266
 
2247
2267
  // packages/native/src/display-primitives.tsx
2248
2268
  import { tokens as tokens12 } from "@kjun-ui/tokens";
2249
- import { useContext as useContext10, useEffect as useEffect5, useRef as useRef6, useState as useState9 } from "react";
2269
+ import { useContext as useContext10, useEffect as useEffect6, useRef as useRef8, useState as useState9 } from "react";
2250
2270
  import {
2251
2271
  Animated as Animated5,
2252
2272
  Easing as Easing3,
@@ -2410,8 +2430,8 @@ function KjunEmpty({
2410
2430
  }
2411
2431
  function KjunSpinner({ size = "md", text }) {
2412
2432
  const m = useKjunMessages();
2413
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), rotation = useRef6(new Animated5.Value(0)).current;
2414
- useEffect5(() => {
2433
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), rotation = useRef8(new Animated5.Value(0)).current;
2434
+ useEffect6(() => {
2415
2435
  if (reduced) return;
2416
2436
  const loop = Animated5.loop(
2417
2437
  Animated5.timing(rotation, {
@@ -2704,7 +2724,7 @@ function KjunProgress({
2704
2724
 
2705
2725
  // packages/native/src/skeleton-base.tsx
2706
2726
  import { tokens as tokens13 } from "@kjun-ui/tokens";
2707
- import { useEffect as useEffect6, useRef as useRef7 } from "react";
2727
+ import { useEffect as useEffect7, useRef as useRef9 } from "react";
2708
2728
  import {
2709
2729
  Animated as Animated6,
2710
2730
  View as View10
@@ -2719,8 +2739,8 @@ function KjunSkeleton({
2719
2739
  animated = true,
2720
2740
  rounded = true
2721
2741
  }) {
2722
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef7(new Animated6.Value(1)).current;
2723
- useEffect6(() => {
2742
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef9(new Animated6.Value(1)).current;
2743
+ useEffect7(() => {
2724
2744
  if (!animated || reduced) return;
2725
2745
  const loop = Animated6.loop(
2726
2746
  Animated6.sequence([
@@ -2898,13 +2918,15 @@ var toneRole = {
2898
2918
  inverse: "onBrand"
2899
2919
  };
2900
2920
  var textAlign = { start: "left", center: "center", end: "right" };
2901
- function KjunText({ variant = "body", tone = "default", align, maxLines, style, children }) {
2921
+ function KjunText({ variant = "body", tone = "default", align, maxLines, style, children, ...rest }) {
2922
+ var _a;
2902
2923
  const { colors, fontFamily, numericFontFamily } = useKjunStyles();
2903
2924
  const lines = maxLines && maxLines > 0 ? Math.floor(maxLines) : void 0;
2904
2925
  return /* @__PURE__ */ jsx17(
2905
2926
  KText,
2906
2927
  {
2907
- accessibilityRole: titleVariants.includes(variant) ? "header" : void 0,
2928
+ ...rest,
2929
+ accessibilityRole: (_a = rest.accessibilityRole) != null ? _a : titleVariants.includes(variant) ? "header" : void 0,
2908
2930
  numberOfLines: lines,
2909
2931
  ellipsizeMode: lines ? "tail" : void 0,
2910
2932
  style: [
@@ -2972,13 +2994,13 @@ function KjunInline({ gap = "sm", align, justify = "start", wrap = true, style,
2972
2994
  }
2973
2995
 
2974
2996
  // shared/package-runtime/feedback-dialog.ts
2975
- import { useRef as useRef8, useState as useState10 } from "react";
2997
+ import { useRef as useRef10, useState as useState10 } from "react";
2976
2998
  function useFeedbackDialog(controller, request, messages = kjunMessagesKo) {
2977
2999
  const options = request.options;
2978
3000
  const [value, setValue] = useState10(options.initialValue || "");
2979
3001
  const [error, setError] = useState10("");
2980
3002
  const [busy, setBusy] = useState10(false);
2981
- const working = useRef8(false);
3003
+ const working = useRef10(false);
2982
3004
  const active = () => {
2983
3005
  var _a;
2984
3006
  return ((_a = controller.getSnapshot().current) == null ? void 0 : _a.id) === request.id;
@@ -3021,10 +3043,10 @@ function useFeedbackDialog(controller, request, messages = kjunMessagesKo) {
3021
3043
 
3022
3044
  // shared/package-runtime/feedback-motion.ts
3023
3045
  import { tokens as tokens15 } from "@kjun-ui/tokens";
3024
- import { useLayoutEffect as useLayoutEffect4, useRef as useRef9, useState as useState11 } from "react";
3046
+ import { useLayoutEffect as useLayoutEffect4, useRef as useRef11, useState as useState11 } from "react";
3025
3047
  function usePresentedToasts(toasts, reduced) {
3026
3048
  const [items2, setItems] = useState11([]);
3027
- const removals = useRef9(/* @__PURE__ */ new Map());
3049
+ const removals = useRef11(/* @__PURE__ */ new Map());
3028
3050
  useLayoutEffect4(() => {
3029
3051
  const ids = new Set(toasts.map((toast) => toast.id));
3030
3052
  setItems((previous) => {
@@ -3074,7 +3096,7 @@ function useOptionalKjunFeedback() {
3074
3096
  }
3075
3097
 
3076
3098
  // packages/native/src/toast-stack.tsx
3077
- import { useLayoutEffect as useLayoutEffect5, useRef as useRef11 } from "react";
3099
+ import { useLayoutEffect as useLayoutEffect5, useRef as useRef13 } from "react";
3078
3100
  import { Animated as Animated8, Platform as Platform13, View as View13 } from "react-native";
3079
3101
  import { tokens as tokens17 } from "@kjun-ui/tokens";
3080
3102
 
@@ -3092,7 +3114,7 @@ function shadowLayers(layers, colors) {
3092
3114
 
3093
3115
  // packages/native/src/toast.tsx
3094
3116
  import { tokens as tokens16 } from "@kjun-ui/tokens";
3095
- import { useEffect as useEffect7, useRef as useRef10 } from "react";
3117
+ import { useEffect as useEffect8, useRef as useRef12 } from "react";
3096
3118
  import { Animated as Animated7, View as View12 } from "react-native";
3097
3119
  import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
3098
3120
  function ToastView({
@@ -3100,14 +3122,14 @@ function ToastView({
3100
3122
  controller
3101
3123
  }) {
3102
3124
  const m = useKjunMessages();
3103
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), progress = useRef10(new Animated7.Value(1)).current;
3104
- const reasons = useRef10({
3125
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), progress = useRef12(new Animated7.Value(1)).current;
3126
+ const reasons = useRef12({
3105
3127
  hover: /* @__PURE__ */ Symbol("hover"),
3106
3128
  actionHover: /* @__PURE__ */ Symbol("actionHover"),
3107
3129
  closeHover: /* @__PURE__ */ Symbol("closeHover"),
3108
3130
  focus: /* @__PURE__ */ Symbol("focus")
3109
3131
  }).current;
3110
- useEffect7(() => () => {
3132
+ useEffect8(() => () => {
3111
3133
  for (const reason of Object.values(reasons)) controller.resumeToast(toast.id, reason);
3112
3134
  }, [controller, toast.id, reasons]);
3113
3135
  const tone = toast.type === "error" ? "danger" : toast.type || "info", icon = {
@@ -3116,7 +3138,7 @@ function ToastView({
3116
3138
  warning: "alert-triangle",
3117
3139
  info: "info-circle"
3118
3140
  }[tone];
3119
- useEffect7(() => {
3141
+ useEffect8(() => {
3120
3142
  progress.stopAnimation();
3121
3143
  progress.setValue(toast.duration ? toast.remaining / toast.duration : 1);
3122
3144
  if (!toast.paused && !reduced) {
@@ -3236,9 +3258,9 @@ function useToastReflow(_root, _reduced) {
3236
3258
  // packages/native/src/toast-stack.tsx
3237
3259
  import { jsx as jsx19 } from "react/jsx-runtime";
3238
3260
  function ToastSlot({ item, controller, boxes }) {
3239
- const born = useRef11(Math.min(tokens17.motion.toastEnter, Date.now() - item.born)).current;
3261
+ const born = useRef13(Math.min(tokens17.motion.toastEnter, Date.now() - item.born)).current;
3240
3262
  const motion = useNativePresence(!item.exiting, tokens17.motion.toastEnter - born, tokens17.motion.toastExit, true, born / tokens17.motion.toastEnter);
3241
- const offset = useRef11(new Animated8.Value(0)).current;
3263
+ const offset = useRef13(new Animated8.Value(0)).current;
3242
3264
  const box = boxes.get(item.toast.id);
3243
3265
  useLayoutEffect5(() => {
3244
3266
  if (motion.reduced) {
@@ -3285,9 +3307,9 @@ function ToastSlot({ item, controller, boxes }) {
3285
3307
  function ToastStack({ items: items2, controller }) {
3286
3308
  var _a;
3287
3309
  const layers = useLayerState();
3288
- const root = useRef11(null), reduced = useReducedMotion();
3310
+ const root = useRef13(null), reduced = useReducedMotion();
3289
3311
  useToastReflow(root, reduced);
3290
- const boxes = useRef11(/* @__PURE__ */ new Map()).current;
3312
+ const boxes = useRef13(/* @__PURE__ */ new Map()).current;
3291
3313
  for (const id of boxes.keys()) if (!items2.some((item) => item.toast.id === id)) boxes.delete(id);
3292
3314
  return /* @__PURE__ */ jsx19(View13, { ref: root, pointerEvents: "box-none", style: {
3293
3315
  position: "absolute",
@@ -3307,9 +3329,9 @@ import {
3307
3329
  feedbackControllerOf
3308
3330
  } from "@kjun-ui/tokens";
3309
3331
  import {
3310
- useCallback as useCallback3,
3311
- useEffect as useEffect8,
3312
- useRef as useRef12,
3332
+ useCallback as useCallback4,
3333
+ useEffect as useEffect9,
3334
+ useRef as useRef14,
3313
3335
  useState as useState12,
3314
3336
  useSyncExternalStore as useSyncExternalStore2
3315
3337
  } from "react";
@@ -3366,8 +3388,8 @@ function FeedbackDialog({
3366
3388
  function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3367
3389
  const [owned] = useState12(() => controllerProp ? void 0 : createFeedbackController());
3368
3390
  const controller = controllerProp ? feedbackControllerOf(controllerProp) : owned;
3369
- useEffect8(() => controller.attach(), [controller]);
3370
- const life = useRef12(0);
3391
+ useEffect9(() => controller.attach(), [controller]);
3392
+ const life = useRef14(0);
3371
3393
  const snapshot = useSyncExternalStore2(
3372
3394
  controller.subscribe,
3373
3395
  controller.getSnapshot,
@@ -3376,7 +3398,7 @@ function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3376
3398
  const reduced = useReducedMotion();
3377
3399
  const toasts = usePresentedToasts(snapshot.toasts, reduced);
3378
3400
  const dialog = usePresentedRequest(snapshot.current, reduced);
3379
- useEffect8(() => {
3401
+ useEffect9(() => {
3380
3402
  const version = ++life.current;
3381
3403
  return () => {
3382
3404
  queueMicrotask(() => {
@@ -3385,7 +3407,7 @@ function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3385
3407
  };
3386
3408
  }, [controller]);
3387
3409
  const [layers, setLayers] = useState12([]);
3388
- const register = useCallback3((id) => {
3410
+ const register = useCallback4((id) => {
3389
3411
  setLayers((previous) => [...previous, id]);
3390
3412
  return () => setLayers((previous) => previous.filter((item) => item !== id));
3391
3413
  }, []);
@@ -3420,8 +3442,8 @@ import {
3420
3442
  createContext as createContext16,
3421
3443
  useContext as useContext12,
3422
3444
  useState as useState13,
3423
- useEffect as useEffect9,
3424
- useRef as useRef13
3445
+ useEffect as useEffect10,
3446
+ useRef as useRef15
3425
3447
  } from "react";
3426
3448
  import {
3427
3449
  View as View15
@@ -3623,7 +3645,7 @@ function KjunRadio({
3623
3645
  const group = useContext12(RadioContext), { colors } = useKjunStyles(), selected = (group ? group.value : value) === val;
3624
3646
  const geometry2 = tokens19.extensions.radio;
3625
3647
  const [hovered, setHovered] = useState13(false);
3626
- useEffect9(() => {
3648
+ useEffect10(() => {
3627
3649
  if (disabled) setHovered(false);
3628
3650
  }, [disabled]);
3629
3651
  return /* @__PURE__ */ jsx21(
@@ -3695,7 +3717,7 @@ function KjunRadioGroup({
3695
3717
  onValueChange,
3696
3718
  onChange
3697
3719
  }) {
3698
- const root = useRef13(null);
3720
+ const root = useRef15(null);
3699
3721
  useRadioKeyboard(root);
3700
3722
  return /* @__PURE__ */ jsx21(
3701
3723
  RadioContext.Provider,
@@ -3735,7 +3757,7 @@ function KjunRadioGroup({
3735
3757
 
3736
3758
  // packages/native/src/selection-groups.tsx
3737
3759
  import { tokens as tokens21 } from "@kjun-ui/tokens";
3738
- import { useLayoutEffect as useLayoutEffect7, useRef as useRef15 } from "react";
3760
+ import { useLayoutEffect as useLayoutEffect7, useRef as useRef17 } from "react";
3739
3761
  import {
3740
3762
  Animated as Animated11,
3741
3763
  ScrollView as ScrollView2,
@@ -3744,7 +3766,7 @@ import {
3744
3766
  } from "react-native";
3745
3767
 
3746
3768
  // packages/native/src/button-group-motion.tsx
3747
- import { useCallback as useCallback4, useEffect as useEffect10, useLayoutEffect as useLayoutEffect6, useRef as useRef14, useState as useState14 } from "react";
3769
+ import { useCallback as useCallback5, useEffect as useEffect11, useLayoutEffect as useLayoutEffect6, useRef as useRef16, useState as useState14 } from "react";
3748
3770
  import { Animated as Animated10, Easing as Easing4, StyleSheet as StyleSheet5, View as View16 } from "react-native";
3749
3771
  import { tokens as tokens20 } from "@kjun-ui/tokens";
3750
3772
  import { jsx as jsx22, jsxs as jsxs11 } from "react/jsx-runtime";
@@ -3754,14 +3776,14 @@ var sameBox = (a, b) => a.x === b.x && a.y === b.y && a.width === b.width && a.h
3754
3776
  function useButtonGroupMotion(selected) {
3755
3777
  const reduced = useReducedMotion();
3756
3778
  const [layouts, setLayouts] = useState14(/* @__PURE__ */ new Map());
3757
- const x = useRef14(new Animated10.Value(0)).current;
3758
- const width = useRef14(new Animated10.Value(0)).current;
3759
- const previous = useRef14(null);
3779
+ const x = useRef16(new Animated10.Value(0)).current;
3780
+ const width = useRef16(new Animated10.Value(0)).current;
3781
+ const previous = useRef16(null);
3760
3782
  const layout = selected && layouts.get(selected.value);
3761
- const updateLayout = useCallback4((value, box) => {
3783
+ const updateLayout = useCallback5((value, box) => {
3762
3784
  setLayouts((old) => old.has(value) && sameBox(old.get(value), box) ? old : new Map(old).set(value, box));
3763
3785
  }, []);
3764
- const measure = useCallback4((value, event) => updateLayout(value, event.nativeEvent.layout), [updateLayout]);
3786
+ const measure = useCallback5((value, event) => updateLayout(value, event.nativeEvent.layout), [updateLayout]);
3765
3787
  useLayoutEffect6(() => {
3766
3788
  const old = previous.current;
3767
3789
  if (!selected || !layout) {
@@ -3784,7 +3806,7 @@ function useButtonGroupMotion(selected) {
3784
3806
  }
3785
3807
  previous.current = { value: selected.value, box: layout, reduced };
3786
3808
  }, [selected == null ? void 0 : selected.value, layout, reduced, x, width]);
3787
- useEffect10(() => () => {
3809
+ useEffect11(() => () => {
3788
3810
  x.stopAnimation();
3789
3811
  width.stopAnimation();
3790
3812
  }, [x, width]);
@@ -3792,9 +3814,9 @@ function useButtonGroupMotion(selected) {
3792
3814
  }
3793
3815
  function ButtonGroupLabel({ label, active, size, reduced }) {
3794
3816
  const { colors, fontFamily } = useKjunStyles();
3795
- const progress = useRef14(new Animated10.Value(active ? 1 : 0)).current;
3817
+ const progress = useRef16(new Animated10.Value(active ? 1 : 0)).current;
3796
3818
  const interpolate = typeof colors.textSecondary === "string" && typeof colors.text === "string";
3797
- useEffect10(() => {
3819
+ useEffect11(() => {
3798
3820
  progress.stopAnimation();
3799
3821
  if (reduced || !interpolate) progress.setValue(active ? 1 : 0);
3800
3822
  else Animated10.timing(progress, { toValue: active ? 1 : 0, duration: tokens20.motion.indicator, easing, useNativeDriver: false }).start();
@@ -3841,7 +3863,7 @@ function KjunButtonGroup({
3841
3863
  const motion = useButtonGroupMotion(selected);
3842
3864
  const padding = tokens21.buttonGroup.padding[size];
3843
3865
  const itemRadius = tokens21.buttonGroup.itemRadii[size];
3844
- const itemRefs = useRef15(/* @__PURE__ */ new Map());
3866
+ const itemRefs = useRef17(/* @__PURE__ */ new Map());
3845
3867
  const { updateLayout } = motion;
3846
3868
  useLayoutEffect7(() => {
3847
3869
  for (const [value2, node] of itemRefs.current) {
@@ -4012,7 +4034,7 @@ function KjunFilterGroup({
4012
4034
  paddingHorizontal: { xs: tokens21.dimension.value8, sm: tokens21.dimension.value12, md: tokens21.dimension.value12, lg: tokens21.dimension.value14, xl: tokens21.dimension.value16 }[size],
4013
4035
  // Corners follow the button scale with the height, so every size keeps the same shape.
4014
4036
  borderRadius: tokens21.button.radii[size],
4015
- backgroundColor: active ? colors.text : colors.secondary
4037
+ backgroundColor: active ? colors.filterSelectedBg : colors.secondary
4016
4038
  },
4017
4039
  children: [
4018
4040
  option.dot && /* @__PURE__ */ jsx23(
@@ -4031,7 +4053,7 @@ function KjunFilterGroup({
4031
4053
  {
4032
4054
  name: option.icon,
4033
4055
  size: tokens21.extensions.selection.iconSize,
4034
- color: active ? colors.inverse : colors.textSecondary
4056
+ color: active ? colors.filterSelectedText : colors.textSecondary
4035
4057
  }
4036
4058
  ),
4037
4059
  /* @__PURE__ */ jsxs12(View17, { children: [
@@ -4054,7 +4076,7 @@ function KjunFilterGroup({
4054
4076
  right: 0,
4055
4077
  top: 0,
4056
4078
  ...selectionTypeStyle(size, active),
4057
- color: active ? colors.inverse : colors.textSecondary
4079
+ color: active ? colors.filterSelectedText : colors.textSecondary
4058
4080
  },
4059
4081
  children: option.label
4060
4082
  }
@@ -4159,7 +4181,7 @@ var KjunTextarea = forwardRef4(
4159
4181
 
4160
4182
  // packages/native/src/drawer.tsx
4161
4183
  import { tokens as tokens23 } from "@kjun-ui/tokens";
4162
- import { useEffect as useEffect11, useState as useState15 } from "react";
4184
+ import { useEffect as useEffect12, useState as useState15 } from "react";
4163
4185
  import { Animated as Animated12, Keyboard } from "react-native";
4164
4186
 
4165
4187
  // shared/package-runtime/drawer-geometry.ts
@@ -4194,7 +4216,7 @@ import {
4194
4216
  import { jsx as jsx25, jsxs as jsxs13 } from "react/jsx-runtime";
4195
4217
  function useKeyboardOverlap(enabled, windowHeight) {
4196
4218
  const [overlap, setOverlap] = useState15(0);
4197
- useEffect11(() => {
4219
+ useEffect12(() => {
4198
4220
  var _a, _b;
4199
4221
  setOverlap(0);
4200
4222
  const events = keyboardEvents(Platform15.OS);
@@ -4224,6 +4246,7 @@ function KjunDrawer({
4224
4246
  footer,
4225
4247
  children,
4226
4248
  onClose,
4249
+ onAfterClose,
4227
4250
  ariaLabel,
4228
4251
  safeAreaTop = 0,
4229
4252
  safeAreaBottom = 0,
@@ -4254,10 +4277,15 @@ function KjunDrawer({
4254
4277
  const layer = useLayer(open, motion.present, "window", () => {
4255
4278
  if (closeOnEsc) close();
4256
4279
  });
4280
+ const iosDismiss = Platform15.OS === "ios";
4281
+ useAfterClose(motion.present, onAfterClose, !iosDismiss);
4257
4282
  return /* @__PURE__ */ jsx25(LayerScope.Provider, { value: layer.id, children: /* @__PURE__ */ jsx25(
4258
4283
  ScopedNativeModal,
4259
4284
  {
4260
4285
  visible: motion.present,
4286
+ onDismiss: iosDismiss ? () => {
4287
+ if (!open) onAfterClose == null ? void 0 : onAfterClose();
4288
+ } : void 0,
4261
4289
  transparent: true,
4262
4290
  onRequestClose: () => {
4263
4291
  if (closeOnEsc) close();
@@ -4390,8 +4418,8 @@ import {
4390
4418
  createContext as createContext17,
4391
4419
  isValidElement as isValidElement6,
4392
4420
  useContext as useContext13,
4393
- useEffect as useEffect14,
4394
- useRef as useRef18,
4421
+ useEffect as useEffect15,
4422
+ useRef as useRef20,
4395
4423
  useState as useState18
4396
4424
  } from "react";
4397
4425
  import {
@@ -4404,9 +4432,9 @@ import { tokens as tokens24 } from "@kjun-ui/tokens";
4404
4432
  import {
4405
4433
  cloneElement as cloneElement3,
4406
4434
  isValidElement as isValidElement4,
4407
- useEffect as useEffect12,
4435
+ useEffect as useEffect13,
4408
4436
  useLayoutEffect as useLayoutEffect8,
4409
- useRef as useRef16,
4437
+ useRef as useRef18,
4410
4438
  useState as useState16
4411
4439
  } from "react";
4412
4440
  import {
@@ -4463,10 +4491,10 @@ function FloatingPanel({
4463
4491
  const m = useKjunMessages();
4464
4492
  ariaLabel != null ? ariaLabel : ariaLabel = m.select;
4465
4493
  const [headerHeight, setHeaderHeight] = useState16(0);
4466
- const panelRef = useRef16(null);
4467
- const scroll = useRef16(null), viewport = useRef16(0);
4494
+ const panelRef = useRef18(null);
4495
+ const scroll = useRef18(null), viewport = useRef18(0);
4468
4496
  const { colors } = useKjunStyles(), window2 = useWindowDimensions4(), [anchored, setAnchored] = useState16(false), [sized, setSized] = useState16(false), [anchor, setAnchor] = useState16({ x: 0, y: 0, width: 0, height: 0 }), [panel, setPanel] = useState16({ width: 0, height: 0 });
4469
- const measurement = useRef16(0);
4497
+ const measurement = useRef18(0);
4470
4498
  const motion = useNativePresence(open, tooltip ? tokens24.motion.tooltipEnter : tokens24.motion.popupEnter, tooltip ? tokens24.motion.tooltipExit : tokens24.motion.popupExit, anchored && sized);
4471
4499
  const layer = useLayer(open, motion.present, tooltip ? "tooltip" : "popup", () => onOpenChange(false), triggerRef);
4472
4500
  useLayoutEffect8(() => {
@@ -4488,14 +4516,14 @@ function FloatingPanel({
4488
4516
  setAnchored(false);
4489
4517
  }
4490
4518
  }, [motion.present]);
4491
- useEffect12(() => {
4519
+ useEffect13(() => {
4492
4520
  var _a;
4493
4521
  const row = reveal == null ? void 0 : reveal.current;
4494
4522
  if (!open || !anchored || !sized || !row || !viewport.current) return;
4495
4523
  const offset = row.y + row.height + (menu || field ? tokens24.extensions.menu.padding : 0) - viewport.current;
4496
4524
  if (offset > 0) (_a = scroll.current) == null ? void 0 : _a.scrollTo({ y: offset, animated: false });
4497
4525
  }, [open, anchored, sized, reveal, menu, field]);
4498
- useEffect12(() => {
4526
+ useEffect13(() => {
4499
4527
  if (!open || !anchored || !sized || !focusOnOpen || !panelRef.current) return;
4500
4528
  if (Platform16.OS === "web") {
4501
4529
  const node = panelRef.current;
@@ -4683,8 +4711,8 @@ function FloatingPanel({
4683
4711
  import {
4684
4712
  cloneElement as cloneElement4,
4685
4713
  isValidElement as isValidElement5,
4686
- useEffect as useEffect13,
4687
- useRef as useRef17,
4714
+ useEffect as useEffect14,
4715
+ useRef as useRef19,
4688
4716
  useState as useState17
4689
4717
  } from "react";
4690
4718
  import {
@@ -4710,7 +4738,7 @@ function KjunPopover({
4710
4738
  children
4711
4739
  }) {
4712
4740
  const { colors } = useKjunStyles();
4713
- const [internal, setInternal] = useState17(false), open = controlled != null ? controlled : internal, ref = useRef17(null);
4741
+ const [internal, setInternal] = useState17(false), open = controlled != null ? controlled : internal, ref = useRef19(null);
4714
4742
  const change = (v) => {
4715
4743
  setInternal(v);
4716
4744
  onOpenChange == null ? void 0 : onOpenChange(v);
@@ -4749,7 +4777,10 @@ function KjunPopover({
4749
4777
  ] });
4750
4778
  }
4751
4779
  function KjunTooltip({
4752
- content: message = "",
4780
+ content: body = "",
4781
+ title,
4782
+ align,
4783
+ width,
4753
4784
  placement = "top",
4754
4785
  delay = 0,
4755
4786
  children,
@@ -4758,13 +4789,14 @@ function KjunTooltip({
4758
4789
  open: controlled,
4759
4790
  onOpenChange
4760
4791
  }) {
4761
- const { colors } = useKjunStyles(), [internal, setInternal] = useState17(false), open = controlled != null ? controlled : internal, latest = useRef17({ open, onOpenChange }), setOpen = (value) => {
4792
+ const message = [title, body].filter(Boolean).join(", ");
4793
+ const { colors } = useKjunStyles(), [internal, setInternal] = useState17(false), open = controlled != null ? controlled : internal, latest = useRef19({ open, onOpenChange }), setOpen = (value) => {
4762
4794
  var _a, _b;
4763
4795
  if (latest.current.open === value) return;
4764
4796
  latest.current.open = value;
4765
4797
  setInternal(value);
4766
4798
  (_b = (_a = latest.current).onOpenChange) == null ? void 0 : _b.call(_a, value);
4767
- }, ref = useRef17(null), timer = useRef17(void 0);
4799
+ }, ref = useRef19(null), timer = useRef19(void 0);
4768
4800
  latest.current = { open, onOpenChange };
4769
4801
  const scopeActive = useActiveLayerScope();
4770
4802
  const hide = () => {
@@ -4776,11 +4808,11 @@ function KjunTooltip({
4776
4808
  clearTimeout(timer.current);
4777
4809
  timer.current = setTimeout(() => setOpen(true), delay);
4778
4810
  };
4779
- useEffect13(() => {
4811
+ useEffect14(() => {
4780
4812
  if (!scopeActive) hide();
4781
4813
  }, [scopeActive]);
4782
- useEffect13(() => () => clearTimeout(timer.current), []);
4783
- useEffect13(() => {
4814
+ useEffect14(() => () => clearTimeout(timer.current), []);
4815
+ useEffect14(() => {
4784
4816
  if (Platform17.OS !== "web" || !open) return;
4785
4817
  const escape = (event) => {
4786
4818
  if (event.key === "Escape") hide();
@@ -4843,25 +4875,29 @@ function KjunTooltip({
4843
4875
  triggerRef: ref,
4844
4876
  placement,
4845
4877
  ariaLabel: message,
4846
- children: /* @__PURE__ */ jsx27(
4878
+ children: /* @__PURE__ */ jsxs15(
4847
4879
  View20,
4848
4880
  {
4849
4881
  style: {
4850
4882
  paddingVertical: tokens25.extensions.tooltip.paddingY,
4851
4883
  paddingHorizontal: tokens25.extensions.tooltip.paddingX,
4852
- maxWidth: tokens25.extensions.tooltip.maxWidth,
4884
+ maxWidth: width ? tokens25.extensions.tooltip.maxWidths[width] : tokens25.extensions.tooltip.maxWidth,
4853
4885
  backgroundColor: colors.chartTooltipBg
4854
4886
  },
4855
- children: /* @__PURE__ */ jsx27(
4856
- KText,
4857
- {
4858
- style: {
4859
- ...typeStyle("caption"),
4860
- color: colors.chartTooltipText
4861
- },
4862
- children: message
4863
- }
4864
- )
4887
+ children: [
4888
+ !!title && /* @__PURE__ */ jsx27(KText, { style: { ...typeStyle("controlSmall"), color: colors.chartTooltipText, ...align ? { textAlign: align === "center" ? "center" : "left" } : {} }, children: title }),
4889
+ !!body && /* @__PURE__ */ jsx27(
4890
+ KText,
4891
+ {
4892
+ style: {
4893
+ ...typeStyle("caption"),
4894
+ color: colors.chartTooltipText,
4895
+ ...align ? { textAlign: align === "center" ? "center" : "left" } : {}
4896
+ },
4897
+ children: body
4898
+ }
4899
+ )
4900
+ ]
4865
4901
  }
4866
4902
  )
4867
4903
  }
@@ -4885,7 +4921,7 @@ function KjunDropdown({
4885
4921
  onClose
4886
4922
  }) {
4887
4923
  const m = useKjunMessages();
4888
- const [open, setOpen] = useState18(false), currentOpen = useRef18(false), ref = useRef18(null);
4924
+ const [open, setOpen] = useState18(false), currentOpen = useRef20(false), ref = useRef20(null);
4889
4925
  let control = trigger;
4890
4926
  while (isValidElement6(control) && control.type === KjunTooltip)
4891
4927
  control = control.props.children;
@@ -4897,7 +4933,7 @@ function KjunDropdown({
4897
4933
  if (v) onOpen == null ? void 0 : onOpen();
4898
4934
  else onClose == null ? void 0 : onClose();
4899
4935
  };
4900
- useEffect14(() => {
4936
+ useEffect15(() => {
4901
4937
  if (unavailable) change(false);
4902
4938
  }, [unavailable]);
4903
4939
  return /* @__PURE__ */ jsxs16(DropdownContext.Provider, { value: () => change(false), children: [
@@ -5033,7 +5069,7 @@ function KjunMenuButton({
5033
5069
  }
5034
5070
 
5035
5071
  // shared/package-runtime/combobox.ts
5036
- import { useEffect as useEffect15, useState as useState19 } from "react";
5072
+ import { useEffect as useEffect16, useState as useState19 } from "react";
5037
5073
 
5038
5074
  // shared/package-runtime/options.ts
5039
5075
  var optionValue = (option, key = "value") => typeof option === "object" ? option[key] : option;
@@ -5113,8 +5149,8 @@ function useComboboxModel({
5113
5149
  const selectedLabel = selected !== void 0 ? optionLabel(selected, labelKey) : "";
5114
5150
  const [query, setQuery] = useState19(selectedLabel);
5115
5151
  const [open, setOpen] = useState19(false);
5116
- useEffect15(() => setQuery(selectedLabel), [value, selectedLabel]);
5117
- useEffect15(() => {
5152
+ useEffect16(() => setQuery(selectedLabel), [value, selectedLabel]);
5153
+ useEffect16(() => {
5118
5154
  if (disabled) setOpen(false);
5119
5155
  }, [disabled]);
5120
5156
  const change = (next) => {
@@ -5148,7 +5184,7 @@ function useComboboxModel({
5148
5184
 
5149
5185
  // packages/native/src/combobox.tsx
5150
5186
  import { tokens as tokens28 } from "@kjun-ui/tokens";
5151
- import { useId as useId5, useRef as useRef19 } from "react";
5187
+ import { useId as useId5, useRef as useRef21 } from "react";
5152
5188
  import { Platform as Platform18, View as View23 } from "react-native";
5153
5189
 
5154
5190
  // packages/native/src/select-options.tsx
@@ -5278,8 +5314,8 @@ function SearchField({
5278
5314
  }) {
5279
5315
  const m = useKjunMessages();
5280
5316
  const searchId = "kjun-popup-search-" + useId5().replace(/:/g, "");
5281
- const clearing = useRef19(false);
5282
- const ref = useRef19(null), { colors } = useKjunStyles();
5317
+ const clearing = useRef21(false);
5318
+ const ref = useRef21(null), { colors } = useKjunStyles();
5283
5319
  const focusGuard = usePopupFocusGuard(ref);
5284
5320
  const openFromPress = () => {
5285
5321
  if (!disabled) {
@@ -5379,7 +5415,7 @@ function SearchField({
5379
5415
 
5380
5416
  // packages/native/src/date-picker.tsx
5381
5417
  import { tokens as tokens29 } from "@kjun-ui/tokens";
5382
- import { useRef as useRef20, useState as useState20 } from "react";
5418
+ import { useRef as useRef22, useState as useState20 } from "react";
5383
5419
  import { Platform as Platform19, View as View24 } from "react-native";
5384
5420
  import { Fragment as Fragment9, jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
5385
5421
  function displayMonth(value) {
@@ -5402,7 +5438,7 @@ function KjunDatePicker({
5402
5438
  const scope = useKjunMessageScope();
5403
5439
  placeholder != null ? placeholder : placeholder = scope.messages.datePlaceholder;
5404
5440
  const clear = clearable && !!value && !disabled;
5405
- const { colors } = useKjunStyles(), field = useKjunField(), [open, setOpen] = useState20(false), [month, setMonth] = useState20(() => displayMonth(value)), ref = useRef20(null), spec = tokens29.input[size];
5441
+ const { colors } = useKjunStyles(), field = useKjunField(), [open, setOpen] = useState20(false), [month, setMonth] = useState20(() => displayMonth(value)), ref = useRef22(null), spec = tokens29.input[size];
5406
5442
  const surface = useFieldSurface(size, { disabled, invalid: error || !!(field == null ? void 0 : field.error), open });
5407
5443
  const year = month.getFullYear(), m = month.getMonth(), first = new Date(year, m, 1).getDay(), count = new Date(year, m + 1, 0).getDate();
5408
5444
  const date = (day) => `${year}-${String(m + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
@@ -5580,7 +5616,7 @@ function KjunDatePicker({
5580
5616
  import { useState as useState22 } from "react";
5581
5617
 
5582
5618
  // shared/package-runtime/search-input.ts
5583
- import { useEffect as useEffect16, useLayoutEffect as useLayoutEffect9, useRef as useRef21, useState as useState21 } from "react";
5619
+ import { useEffect as useEffect17, useLayoutEffect as useLayoutEffect9, useRef as useRef23, useState as useState21 } from "react";
5584
5620
  function useSearchInputModel({
5585
5621
  value,
5586
5622
  disabled = false,
@@ -5590,10 +5626,10 @@ function useSearchInputModel({
5590
5626
  onValueChange,
5591
5627
  onSearchError
5592
5628
  }, open) {
5593
- const [query, setQuery] = useState21(value), [options, setOptions] = useState21([]), [loading, setLoading] = useState21(false), [failed, setFailed] = useState21(false), version = useRef21(0), notify = useRef21(onSearchError);
5629
+ const [query, setQuery] = useState21(value), [options, setOptions] = useState21([]), [loading, setLoading] = useState21(false), [failed, setFailed] = useState21(false), version = useRef23(0), notify = useRef23(onSearchError);
5594
5630
  notify.current = onSearchError;
5595
- const timer = useRef21(void 0);
5596
- const notifyValue = useRef21(onValueChange);
5631
+ const timer = useRef23(void 0);
5632
+ const notifyValue = useRef23(onValueChange);
5597
5633
  notifyValue.current = onValueChange;
5598
5634
  useLayoutEffect9(() => {
5599
5635
  clearTimeout(timer.current);
@@ -5603,7 +5639,7 @@ function useSearchInputModel({
5603
5639
  clearTimeout(timer.current);
5604
5640
  return () => clearTimeout(timer.current);
5605
5641
  }, [disabled, debounce, !!loadOptions]);
5606
- useEffect16(() => {
5642
+ useEffect17(() => {
5607
5643
  const current = ++version.current, abort = new AbortController();
5608
5644
  setFailed(false);
5609
5645
  if (!loadOptions || !open || disabled || query.length < minChars) {
@@ -5756,7 +5792,7 @@ function KjunSearchInput({
5756
5792
 
5757
5793
  // packages/native/src/select-control.tsx
5758
5794
  import { tokens as tokens31 } from "@kjun-ui/tokens";
5759
- import { useContext as useContext14, useEffect as useEffect18, useRef as useRef23 } from "react";
5795
+ import { useContext as useContext14, useEffect as useEffect19, useRef as useRef25 } from "react";
5760
5796
 
5761
5797
  // packages/native/src/compound-control.tsx
5762
5798
  import { createContext as createContext18 } from "react";
@@ -5770,7 +5806,7 @@ function CompoundTarget({ children, square = false }) {
5770
5806
  }
5771
5807
 
5772
5808
  // shared/package-runtime/select.ts
5773
- import { useEffect as useEffect17, useRef as useRef22, useState as useState23 } from "react";
5809
+ import { useEffect as useEffect18, useRef as useRef24, useState as useState23 } from "react";
5774
5810
  function useSelectState(controlled, disabled, pageSize, onOpenChange) {
5775
5811
  const [internal, setInternal] = useState23(false);
5776
5812
  const [query, setQuery] = useState23("");
@@ -5778,8 +5814,8 @@ function useSelectState(controlled, disabled, pageSize, onOpenChange) {
5778
5814
  const [session, setSession] = useState23(0);
5779
5815
  const isControlled = typeof controlled === "boolean";
5780
5816
  const open = !disabled && (isControlled ? controlled : internal);
5781
- const previousOpen = useRef22(open);
5782
- useEffect17(() => {
5817
+ const previousOpen = useRef24(open);
5818
+ useEffect18(() => {
5783
5819
  if (disabled && !isControlled) setInternal(false);
5784
5820
  if (previousOpen.current && !open) {
5785
5821
  setQuery("");
@@ -5788,7 +5824,7 @@ function useSelectState(controlled, disabled, pageSize, onOpenChange) {
5788
5824
  }
5789
5825
  previousOpen.current = open;
5790
5826
  }, [open, disabled, isControlled, pageSize]);
5791
- useEffect17(() => {
5827
+ useEffect18(() => {
5792
5828
  setLimit(pageSize);
5793
5829
  }, [pageSize]);
5794
5830
  const changeOpen = (next) => {
@@ -5838,14 +5874,14 @@ function KjunSelect({
5838
5874
  placeholder != null ? placeholder : placeholder = m.select;
5839
5875
  searchPlaceholder != null ? searchPlaceholder : searchPlaceholder = m.search;
5840
5876
  const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
5841
- const { colors } = useKjunStyles(), field = useKjunField(), ref = useRef23(null), spec = tokens31.input[size];
5842
- const trigger = useRef23(null);
5877
+ const { colors } = useKjunStyles(), field = useKjunField(), ref = useRef25(null), spec = tokens31.input[size];
5878
+ const trigger = useRef25(null);
5843
5879
  const compound = useContext14(CompoundControlContext);
5844
- useEffect18(() => {
5880
+ useEffect19(() => {
5845
5881
  if (compound == null ? void 0 : compound.focusRef) compound.focusRef.current = trigger.current;
5846
5882
  }, [compound == null ? void 0 : compound.focusRef]);
5847
5883
  const expanded = usePopupExpanded(open, ref);
5848
- const selectedRow = useRef23(null);
5884
+ const selectedRow = useRef25(null);
5849
5885
  const surface = useFieldSurface(size, { disabled, invalid: error || !!(field == null ? void 0 : field.error), open: expanded });
5850
5886
  const change = (v) => {
5851
5887
  onValueChange == null ? void 0 : onValueChange(v);
@@ -6043,15 +6079,16 @@ import { tokens as tokens34 } from "@kjun-ui/tokens";
6043
6079
 
6044
6080
  // packages/native/src/collapse.tsx
6045
6081
  import { tokens as tokens32 } from "@kjun-ui/tokens";
6046
- import { useLayoutEffect as useLayoutEffect10, useRef as useRef24, useState as useState24 } from "react";
6082
+ import { useLayoutEffect as useLayoutEffect10, useRef as useRef26, useState as useState24 } from "react";
6047
6083
  import { Animated as Animated14, View as View27 } from "react-native";
6048
6084
  import { jsx as jsx35 } from "react/jsx-runtime";
6049
- function Collapse({ open, children }) {
6085
+ function Collapse({ open, keepMounted = false, children }) {
6050
6086
  const reduced = useReducedMotion();
6051
6087
  const [retained, setRetained] = useState24(open), [height, setHeight] = useState24(null);
6052
- const value = useRef24(new Animated14.Value(0)).current;
6088
+ const value = useRef26(new Animated14.Value(0)).current;
6053
6089
  const [settled, setSettled] = useState24(open);
6054
- const version = useRef24(0), first = useRef24(open);
6090
+ const version = useRef26(0), first = useRef26(open), opened = useRef26(open);
6091
+ if (open) opened.current = true;
6055
6092
  useLayoutEffect10(() => {
6056
6093
  const revision = ++version.current;
6057
6094
  if (open) setRetained(true);
@@ -6079,13 +6116,13 @@ function Collapse({ open, children }) {
6079
6116
  value.stopAnimation();
6080
6117
  };
6081
6118
  }, [open, height, reduced, value]);
6082
- return open || retained ? /* @__PURE__ */ jsx35(
6119
+ return open || retained || keepMounted && opened.current ? /* @__PURE__ */ jsx35(
6083
6120
  Animated14.View,
6084
6121
  {
6085
6122
  pointerEvents: open ? "auto" : "none",
6086
6123
  accessibilityElementsHidden: !open,
6087
6124
  importantForAccessibility: open ? "auto" : "no-hide-descendants",
6088
- ...!open ? { inert: true } : {},
6125
+ ...!open ? { inert: true, "aria-hidden": true } : {},
6089
6126
  style: { height: settled && open ? void 0 : value, overflow: "hidden" },
6090
6127
  children: /* @__PURE__ */ jsx35(View27, { onLayout: (event) => setHeight(event.nativeEvent.layout.height), children })
6091
6128
  }
@@ -6093,10 +6130,10 @@ function Collapse({ open, children }) {
6093
6130
  }
6094
6131
 
6095
6132
  // shared/package-runtime/navigation.ts
6096
- import { useEffect as useEffect19, useRef as useRef25, useState as useState25 } from "react";
6133
+ import { useEffect as useEffect20, useRef as useRef27, useState as useState25 } from "react";
6097
6134
  function useInitialTab(value, candidate, change) {
6098
- const requested = useRef25(/* @__PURE__ */ new Set());
6099
- useEffect19(() => {
6135
+ const requested = useRef27(/* @__PURE__ */ new Set());
6136
+ useEffect20(() => {
6100
6137
  if (value !== "") {
6101
6138
  requested.current.clear();
6102
6139
  return;
@@ -6108,7 +6145,7 @@ function useInitialTab(value, candidate, change) {
6108
6145
  }
6109
6146
  function useAccordionState(multiple) {
6110
6147
  const [opened, setOpened] = useState25(/* @__PURE__ */ new Set());
6111
- useEffect19(() => {
6148
+ useEffect20(() => {
6112
6149
  if (!multiple) setOpened((previous) => previous.size > 1 ? new Set([...previous].slice(-1)) : previous);
6113
6150
  }, [multiple]);
6114
6151
  return {
@@ -6136,15 +6173,16 @@ import {
6136
6173
  Fragment as Fragment11,
6137
6174
  createContext as createContext20,
6138
6175
  useContext as useContext16,
6139
- useEffect as useEffect20,
6176
+ useEffect as useEffect21,
6140
6177
  useId as useId7,
6178
+ useRef as useRef29,
6141
6179
  useState as useState27
6142
6180
  } from "react";
6143
6181
  import { Animated as Animated16, View as View29, useWindowDimensions as useWindowDimensions5, Platform as Platform22 } from "react-native";
6144
6182
 
6145
6183
  // packages/native/src/tabs.tsx
6146
6184
  import { tokens as tokens33 } from "@kjun-ui/tokens";
6147
- import { Children as Children4, createContext as createContext19, isValidElement as isValidElement7, useContext as useContext15, useCallback as useCallback5, useLayoutEffect as useLayoutEffect11, useRef as useRef26, useId as useId6, useState as useState26 } from "react";
6185
+ import { Children as Children4, createContext as createContext19, isValidElement as isValidElement7, useContext as useContext15, useCallback as useCallback6, useLayoutEffect as useLayoutEffect11, useRef as useRef28, useId as useId6, useState as useState26 } from "react";
6148
6186
  import { Animated as Animated15, Platform as Platform21, ScrollView as ScrollView5, View as View28 } from "react-native";
6149
6187
 
6150
6188
  // packages/native/src/tabs-accessibility.ts
@@ -6175,10 +6213,10 @@ function KjunTabs({
6175
6213
  isValidElement7
6176
6214
  );
6177
6215
  const tabs = items2.length ? items2 : panes.filter((child) => child.type === KjunTabPane).map((child) => child.props);
6178
- const id = "kjun-" + useId6(), root = useRef26(null);
6179
- const menuState = useRef26({ tabs, onTabMenu });
6216
+ const id = "kjun-" + useId6(), root = useRef28(null);
6217
+ const menuState = useRef28({ tabs, onTabMenu });
6180
6218
  menuState.current = { tabs, onTabMenu };
6181
- const pressedMenu = useRef26(null);
6219
+ const pressedMenu = useRef28(null);
6182
6220
  useLayoutEffect11(() => {
6183
6221
  if (!onTabMenu || !tabs.some((tab) => tab.name === pressedMenu.current && !tab.disabled)) pressedMenu.current = null;
6184
6222
  }, [tabs, onTabMenu]);
@@ -6194,10 +6232,10 @@ function KjunTabs({
6194
6232
  const roomX = underline ? ringRoom : 0, roomY = Math.max(underline ? ringRoom : 0, slop);
6195
6233
  const selectedTab = tabs.find((tab) => tab.name === value);
6196
6234
  const selection = useButtonGroupMotion(selectedTab ? { ...selectedTab, value: selectedTab.name } : void 0);
6197
- const tabRefs = useRef26(/* @__PURE__ */ new Map());
6235
+ const tabRefs = useRef28(/* @__PURE__ */ new Map());
6198
6236
  const { updateLayout } = selection;
6199
6237
  const firstName = (_a = tabs[0]) == null ? void 0 : _a.name;
6200
- const measureIndicator = useCallback5((name, box) => {
6238
+ const measureIndicator = useCallback6((name, box) => {
6201
6239
  const left = underline && name === firstName ? 0 : paddingX;
6202
6240
  updateLayout(name, underline ? {
6203
6241
  x: box.x + left,
@@ -6366,7 +6404,7 @@ function KjunTabs({
6366
6404
  }
6367
6405
  function KjunTabPane({ name, children }) {
6368
6406
  const { value, id, names } = useContext15(TabContext);
6369
- const root = useRef26(null);
6407
+ const root = useRef28(null);
6370
6408
  usePanelFocus(root);
6371
6409
  const hidden = value !== name;
6372
6410
  return /* @__PURE__ */ jsx36(
@@ -6419,14 +6457,32 @@ function KjunAccordionItem({
6419
6457
  defaultOpen = false,
6420
6458
  disabled = false,
6421
6459
  header,
6460
+ open: openProp,
6461
+ onOpenChange,
6462
+ keepMounted = false,
6422
6463
  children
6423
6464
  }) {
6424
- const { colors } = useKjunStyles(), group = useContext16(AccordionContext), id = "kjun-" + useId7(), [own, setOwn] = useState27(defaultOpen), open = group ? group.opened.has(id) : own;
6465
+ const controlled = openProp !== void 0, context = useContext16(AccordionContext), { colors } = useKjunStyles(), group = controlled ? null : context, id = "kjun-" + useId7(), [own, setOwn] = useState27(defaultOpen), open = controlled ? openProp : group ? group.opened.has(id) : own;
6466
+ const reported = useRef29(open), notify = useRef29(onOpenChange), registering = useRef29(!!group && defaultOpen);
6467
+ notify.current = onOpenChange;
6468
+ useEffect21(() => {
6469
+ var _a;
6470
+ if (registering.current) {
6471
+ if (open) {
6472
+ registering.current = false;
6473
+ reported.current = open;
6474
+ }
6475
+ return;
6476
+ }
6477
+ if (controlled || reported.current === open) return;
6478
+ reported.current = open;
6479
+ (_a = notify.current) == null ? void 0 : _a.call(notify, open);
6480
+ }, [open, controlled]);
6425
6481
  const rotation = useMotionValue(open ? 1 : 0, tokens34.motion.collapse, void 0, void 0, true);
6426
6482
  const geometry2 = tokens34.extensions.accordion;
6427
6483
  const [hovered, setHovered] = useState27(false);
6428
6484
  const wrapping = Platform22.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
6429
- useEffect20(() => {
6485
+ useEffect21(() => {
6430
6486
  return group == null ? void 0 : group.register(id, defaultOpen);
6431
6487
  }, []);
6432
6488
  return /* @__PURE__ */ jsxs22(View29, { children: [
@@ -6440,7 +6496,10 @@ function KjunAccordionItem({
6440
6496
  accessibilityLabel: title,
6441
6497
  accessibilityState: { expanded: open, disabled },
6442
6498
  disabled,
6443
- onPress: () => group ? group.toggle(id) : setOwn(!own),
6499
+ onPress: () => {
6500
+ registering.current = false;
6501
+ controlled ? onOpenChange == null ? void 0 : onOpenChange(!open) : group ? group.toggle(id) : setOwn(!own);
6502
+ },
6444
6503
  onHoverIn: () => setHovered(true),
6445
6504
  onHoverOut: () => setHovered(false),
6446
6505
  style: ({ pressed }) => ({
@@ -6460,7 +6519,7 @@ function KjunAccordionItem({
6460
6519
  ]
6461
6520
  }
6462
6521
  ),
6463
- /* @__PURE__ */ jsx37(Collapse, { open, children: /* @__PURE__ */ jsx37(
6522
+ /* @__PURE__ */ jsx37(Collapse, { open, keepMounted, children: /* @__PURE__ */ jsx37(
6464
6523
  View29,
6465
6524
  {
6466
6525
  nativeID: id + "-panel",
@@ -6657,7 +6716,7 @@ function KjunPagination({
6657
6716
 
6658
6717
  // packages/native/src/actions.tsx
6659
6718
  import { tokens as tokens35 } from "@kjun-ui/tokens";
6660
- import { useContext as useContext17, useEffect as useEffect21, useRef as useRef27, useState as useState28 } from "react";
6719
+ import { useContext as useContext17, useEffect as useEffect22, useRef as useRef30, useState as useState28 } from "react";
6661
6720
  import { Platform as Platform23, ScrollView as ScrollView7, View as View30 } from "react-native";
6662
6721
  import { jsx as jsx38, jsxs as jsxs23 } from "react/jsx-runtime";
6663
6722
  function KjunIconToggle({
@@ -6742,8 +6801,8 @@ function KjunCopyButton({
6742
6801
  }) {
6743
6802
  const m = useKjunMessages();
6744
6803
  successText != null ? successText : successText = m.copied;
6745
- const feedback = useOptionalKjunFeedback(), { colors } = useKjunStyles(), [copied, setCopied] = useState28(false), [failed, setFailed] = useState28(false), busy = useRef27(false), timer = useRef27(void 0), mounted = useRef27(true);
6746
- useEffect21(() => {
6804
+ const feedback = useOptionalKjunFeedback(), { colors } = useKjunStyles(), [copied, setCopied] = useState28(false), [failed, setFailed] = useState28(false), busy = useRef30(false), timer = useRef30(void 0), mounted = useRef30(true);
6805
+ useEffect22(() => {
6747
6806
  mounted.current = true;
6748
6807
  return () => {
6749
6808
  mounted.current = false;
@@ -6907,10 +6966,10 @@ import { Component, useState as useState30 } from "react";
6907
6966
  import { Platform as Platform24, View as View31 } from "react-native";
6908
6967
 
6909
6968
  // shared/package-runtime/use-loading-reveal.ts
6910
- import { useEffect as useEffect22, useState as useState29 } from "react";
6969
+ import { useEffect as useEffect23, useState as useState29 } from "react";
6911
6970
  function useLoadingReveal(active, delay = 0) {
6912
6971
  const [revealed, setRevealed] = useState29(false);
6913
- useEffect22(() => {
6972
+ useEffect23(() => {
6914
6973
  setRevealed(false);
6915
6974
  if (!active || delay <= 0) return;
6916
6975
  const timer = setTimeout(() => setRevealed(true), delay);
@@ -7080,7 +7139,7 @@ KjunErrorBoundary.contextType = KjunMessageContext;
7080
7139
 
7081
7140
  // packages/native/src/skeletons.tsx
7082
7141
  import { tokens as tokens40 } from "@kjun-ui/tokens";
7083
- import { useEffect as useEffect23, useRef as useRef28, useState as useState32 } from "react";
7142
+ import { useEffect as useEffect24, useRef as useRef31, useState as useState32 } from "react";
7084
7143
  import { Animated as Animated17, Platform as Platform25, View as View33, useWindowDimensions as useWindowDimensions6 } from "react-native";
7085
7144
  import Svg5, { Path as Path4 } from "react-native-svg";
7086
7145
 
@@ -7271,8 +7330,8 @@ function KjunChartSkeleton({
7271
7330
  }) {
7272
7331
  const m = useKjunMessages();
7273
7332
  loadingText != null ? loadingText : loadingText = m.chartLoading;
7274
- const kind = chartSkeletonKind(requestedKind), { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef28(new Animated17.Value(1)).current, revealed = useLoadingReveal(true, loadingDelay), [measured, setMeasured] = useState32(0), thickness = tokens40.extensions.chartSkeleton.donutThickness, boxHeight = typeof height === "number" ? height : measured, hole = boxHeight > 0 ? chartDonutHole(boxHeight, thickness) : void 0, rowCount = chartSkeletonCount(rows), columnCount = chartSkeletonCount(columns), status = revealed && loadingText ? "status" : void 0, hidden = { "aria-hidden": true, importantForAccessibility: "no-hide-descendants" };
7275
- useEffect23(() => {
7333
+ const kind = chartSkeletonKind(requestedKind), { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef31(new Animated17.Value(1)).current, revealed = useLoadingReveal(true, loadingDelay), [measured, setMeasured] = useState32(0), thickness = tokens40.extensions.chartSkeleton.donutThickness, boxHeight = typeof height === "number" ? height : measured, hole = boxHeight > 0 ? chartDonutHole(boxHeight, thickness) : void 0, rowCount = chartSkeletonCount(rows), columnCount = chartSkeletonCount(columns), status = revealed && loadingText ? "status" : void 0, hidden = { "aria-hidden": true, importantForAccessibility: "no-hide-descendants" };
7334
+ useEffect24(() => {
7276
7335
  if (reduced || !skeleton) return;
7277
7336
  const loop = Animated17.loop(
7278
7337
  Animated17.sequence([
@@ -7370,7 +7429,7 @@ import Svg6, {
7370
7429
  import { tokens as tokens42 } from "@kjun-ui/tokens";
7371
7430
 
7372
7431
  // shared/package-runtime/use-number-motion.ts
7373
- import { useLayoutEffect as useLayoutEffect12, useRef as useRef29, useState as useState33 } from "react";
7432
+ import { useLayoutEffect as useLayoutEffect12, useRef as useRef32, useState as useState33 } from "react";
7374
7433
 
7375
7434
  // shared/package-runtime/number-motion.ts
7376
7435
  import { tokens as tokens41 } from "@kjun-ui/tokens";
@@ -7417,7 +7476,7 @@ function createNumberMotion(apply) {
7417
7476
  // shared/package-runtime/use-number-motion.ts
7418
7477
  function useNumberMotion(value, animated, fromPrevious, reduced) {
7419
7478
  const [display, setDisplay] = useState33(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
7420
- const motion = useRef29(null);
7479
+ const motion = useRef32(null);
7421
7480
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
7422
7481
  useLayoutEffect12(() => {
7423
7482
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
@@ -7882,7 +7941,7 @@ function KjunSparkline({
7882
7941
 
7883
7942
  // shared/package-runtime/table.ts
7884
7943
  import { nextTableSort } from "@kjun-ui/tokens";
7885
- import { useEffect as useEffect25, useRef as useRef31, useState as useState35 } from "react";
7944
+ import { useEffect as useEffect26, useRef as useRef34, useState as useState35 } from "react";
7886
7945
 
7887
7946
  // shared/package-runtime/table-model.ts
7888
7947
  function getValue(row, key) {
@@ -7929,8 +7988,8 @@ function useTableModel(props) {
7929
7988
  const [internalSort, setSort] = useState35({
7930
7989
  key: "",
7931
7990
  order: "asc"
7932
- }), [internalExpanded, setExpanded] = useState35([]), [search, setSearch] = useState35(""), timer = useRef31(void 0);
7933
- useEffect25(() => () => clearTimeout(timer.current), []);
7991
+ }), [internalExpanded, setExpanded] = useState35([]), [search, setSearch] = useState35(""), timer = useRef34(void 0);
7992
+ useEffect26(() => () => clearTimeout(timer.current), []);
7934
7993
  const sort = props.sort === void 0 ? internalSort : (_a = props.sort) != null ? _a : { key: "", order: "asc" };
7935
7994
  const rows = sortTableRows(data, sort, { sortable, sortMode });
7936
7995
  const key = (row, index = 0) => tableRowKey(row, rowKey, index);
@@ -9087,7 +9146,7 @@ import { tokens as tokens51 } from "@kjun-ui/tokens";
9087
9146
  import { ScrollView as ScrollView10, View as View44 } from "react-native";
9088
9147
 
9089
9148
  // shared/package-runtime/market-cards.ts
9090
- import { useEffect as useEffect26, useRef as useRef32, useState as useState38 } from "react";
9149
+ import { useEffect as useEffect27, useRef as useRef35, useState as useState38 } from "react";
9091
9150
  function useMarketCardsModel(props, persistence) {
9092
9151
  const {
9093
9152
  columns,
@@ -9104,7 +9163,7 @@ function useMarketCardsModel(props, persistence) {
9104
9163
  isDefaultSort: c.defaultSort
9105
9164
  }));
9106
9165
  const [key, setKey] = useState38(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
9107
- const mounted = useRef32("");
9166
+ const mounted = useRef35("");
9108
9167
  const save = (key2) => {
9109
9168
  var _a;
9110
9169
  try {
@@ -9112,7 +9171,7 @@ function useMarketCardsModel(props, persistence) {
9112
9171
  } catch (e) {
9113
9172
  }
9114
9173
  };
9115
- useEffect26(() => {
9174
+ useEffect27(() => {
9116
9175
  var _a, _b;
9117
9176
  if (mounted.current === restoreSignature) return;
9118
9177
  mounted.current = restoreSignature;
@@ -9897,26 +9956,31 @@ import { Children as Children5, createContext as createContext22, useContext as
9897
9956
  import { View as View48, Platform as Platform26 } from "react-native";
9898
9957
  import { Fragment as Fragment19, jsx as jsx56, jsxs as jsxs41 } from "react/jsx-runtime";
9899
9958
  var ListRowContext = createContext22({ divider: true, compact: false });
9900
- function KjunListRow({ title, description, leading, trailing, actions, href, disabled = false, destructive = false, chevron = false, onPress }) {
9959
+ function KjunListRow({ title, description, leading, trailing, actions, href, disabled = false, destructive = false, chevron = false, onPress, ariaLabel, children }) {
9901
9960
  const { colors } = useKjunStyles(), { divider, compact } = useContext19(ListRowContext);
9902
9961
  const parts = /* @__PURE__ */ jsxs41(Fragment19, { children: [
9903
9962
  hasContent(leading) && /* @__PURE__ */ jsx56(View48, { children: content(leading) }),
9904
9963
  /* @__PURE__ */ jsxs41(View48, { style: { flex: 1, minWidth: 0 }, children: [
9905
9964
  /* @__PURE__ */ jsx56(KText, { style: { ...typeStyle("label"), ...destructive ? { color: colors.danger } : {} }, children: title }),
9906
- !!description && /* @__PURE__ */ jsx56(KText, { style: { marginTop: tokens55.extensions.list.descriptionGap, color: colors.textSecondary, ...typeStyle("caption") }, children: description })
9965
+ !!description && /* @__PURE__ */ jsx56(KText, { style: { marginTop: tokens55.extensions.list.descriptionGap, color: colors.textSecondary, ...typeStyle("caption") }, children: description }),
9966
+ hasContent(children) && /* @__PURE__ */ jsx56(View48, { style: { marginTop: tokens55.extensions.list.descriptionGap }, children: content(children) })
9907
9967
  ] }),
9908
9968
  hasContent(trailing) && /* @__PURE__ */ jsx56(View48, { style: { maxWidth: "35%" }, children: content(trailing) }),
9909
9969
  chevron && /* @__PURE__ */ jsx56(View48, { accessible: false, importantForAccessibility: "no-hide-descendants", accessibilityElementsHidden: true, children: /* @__PURE__ */ jsx56(KjunIcon, { name: "chevron-right", size: tokens55.iconSizes.default, color: colors.textTertiary }) })
9910
9970
  ] });
9911
9971
  const style = { flex: 1, minWidth: 0, minHeight: compact ? tokens55.extensions.list.compactMinimumHeight : tokens55.extensions.list.minimumHeight, flexDirection: "row", alignItems: "center", gap: tokens55.extensions.list.gap, padding: tokens55.extensions.list.padding, ...compact ? { paddingVertical: tokens55.extensions.list.compactPaddingY } : {} };
9912
9972
  return /* @__PURE__ */ jsxs41(View48, { role: "listitem", style: { flexDirection: "row", alignItems: "center", gap: tokens55.extensions.list.gap, borderBottomWidth: divider ? tokens55.border.defaultWidth : 0, borderBottomColor: colors.divider }, children: [
9913
- onPress || href ? /* @__PURE__ */ jsx56(AccessiblePressable, { ...Platform26.OS === "web" && href && !disabled ? { href } : {}, accessibilityRole: href ? "link" : "button", accessibilityLabel: title + (description ? ", " + description : ""), disabled, accessibilityState: { disabled }, onPress, style: ({ pressed }) => ({ ...style, opacity: disabled ? tokens55.states.opacity.disabled : 1, backgroundColor: pressed ? colors.hover : "transparent" }), children: parts }) : /* @__PURE__ */ jsx56(View48, { style, children: parts }),
9973
+ onPress || href ? /* @__PURE__ */ jsx56(AccessiblePressable, { ...Platform26.OS === "web" && href && !disabled ? { href } : {}, accessibilityRole: href ? "link" : "button", accessibilityLabel: ariaLabel != null ? ariaLabel : title + (description ? ", " + description : ""), disabled, accessibilityState: { disabled }, onPress, style: ({ pressed }) => ({ ...style, opacity: disabled ? tokens55.states.opacity.disabled : 1, backgroundColor: pressed ? colors.hover : "transparent" }), children: parts }) : /* @__PURE__ */ jsx56(View48, { style, children: parts }),
9914
9974
  hasContent(actions) && /* @__PURE__ */ jsx56(View48, { pointerEvents: disabled ? "none" : "auto", ...disabled && Platform26.OS === "web" ? { inert: true } : {}, style: { maxWidth: "45%", flexDirection: "row", flexWrap: "wrap", gap: tokens55.extensions.list.actionsGap, paddingRight: tokens55.extensions.list.actionsPadding, opacity: disabled ? tokens55.states.opacity.disabled : 1 }, children: content(actions) })
9915
9975
  ] });
9916
9976
  }
9917
- function KjunListSection({ title, description, actions, children, ariaLabel, surface = true, divider = true, density = "default" }) {
9977
+ function KjunListSection({ title, description, actions, children, ariaLabel, surface = true, divider = true, density = "default", radius = "none" }) {
9918
9978
  const { colors } = useKjunStyles();
9919
- return /* @__PURE__ */ jsxs41(View48, { style: { minWidth: 0, backgroundColor: surface ? colors.surface : "transparent" }, children: [
9979
+ return /* @__PURE__ */ jsxs41(View48, { style: {
9980
+ minWidth: 0,
9981
+ backgroundColor: surface ? colors.surface : "transparent",
9982
+ ...radius === "none" ? {} : { borderRadius: tokens55.card.radii[radius], overflow: "hidden" }
9983
+ }, children: [
9920
9984
  !!(title || description || actions) && /* @__PURE__ */ jsxs41(View48, { style: { flexDirection: "row", alignItems: "center", gap: tokens55.extensions.list.gap, padding: tokens55.extensions.list.padding }, children: [
9921
9985
  /* @__PURE__ */ jsxs41(View48, { style: { flex: 1 }, children: [
9922
9986
  !!title && /* @__PURE__ */ jsx56(KText, { accessibilityRole: "header", style: { ...typeStyle("cardTitle") }, children: title }),
@@ -10053,14 +10117,14 @@ function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboa
10053
10117
  }
10054
10118
 
10055
10119
  // packages/native/src/media.tsx
10056
- import { createContext as createContext23, useContext as useContext20, useRef as useRef33, useState as useState41 } from "react";
10120
+ import { createContext as createContext23, useContext as useContext20, useRef as useRef36, useState as useState41 } from "react";
10057
10121
  import { Image, View as View50 } from "react-native";
10058
10122
  import { tokens as tokens57 } from "@kjun-ui/tokens";
10059
10123
  import { jsx as jsx58 } from "react/jsx-runtime";
10060
10124
  var ImageBackgroundContext = createContext23(void 0);
10061
10125
  function KjunImage({ src, source, alt, decorative = false, aspectRatio = 1, fit = "cover", fallback: fallback2, onLoad, onError }) {
10062
10126
  const { colors } = useKjunStyles(), background = useContext20(ImageBackgroundContext);
10063
- const request = JSON.stringify(source != null ? source : src), current = useRef33({ request, version: 0 });
10127
+ const request = JSON.stringify(source != null ? source : src), current = useRef36({ request, version: 0 });
10064
10128
  if (current.current.request !== request) current.current = { request, version: current.current.version + 1 };
10065
10129
  const version = current.current.version;
10066
10130
  const [failed, setFailed] = useState41(null);
@@ -10128,7 +10192,7 @@ function KjunFab({ icon, ariaLabel, disabled = false, safeAreaBottom = 0, offset
10128
10192
  }
10129
10193
 
10130
10194
  // packages/native/src/range-input.tsx
10131
- import { useEffect as useEffect27, useMemo as useMemo3, useRef as useRef34, useState as useState42 } from "react";
10195
+ import { useEffect as useEffect28, useMemo as useMemo3, useRef as useRef37, useState as useState42 } from "react";
10132
10196
  import { PanResponder, Platform as Platform28, Pressable as Pressable3, View as View52 } from "react-native";
10133
10197
  import { tokens as tokens60, createSliderDomain, sliderKey } from "@kjun-ui/tokens";
10134
10198
  import { jsx as jsx61, jsxs as jsxs44 } from "react/jsx-runtime";
@@ -10156,15 +10220,15 @@ function RangeInput({
10156
10220
  const [hovered, setHovered] = useState42(null);
10157
10221
  const [dragging, setDragging] = useState42(null);
10158
10222
  const [focused, setFocused] = useState42(null);
10159
- const track = useRef34(null), measured = useRef34({ x: 0, width: 1 }), selected = useRef34(0), dirty = useRef34(false);
10160
- const latest = useRef34(values);
10223
+ const track = useRef37(null), measured = useRef37({ x: 0, width: 1 }), selected = useRef37(0), dirty = useRef37(false);
10224
+ const latest = useRef37(values);
10161
10225
  latest.current = values;
10162
- const callbacks = useRef34({ onValueChange, onChangeCommit });
10226
+ const callbacks = useRef37({ onValueChange, onChangeCommit });
10163
10227
  callbacks.current = { onValueChange, onChangeCommit };
10164
- useEffect27(() => {
10228
+ useEffect28(() => {
10165
10229
  if (!valid) console.warn("KJUN Slider: \uBC94\uC704\xB7step\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10166
10230
  }, [valid]);
10167
- useEffect27(() => {
10231
+ useEffect28(() => {
10168
10232
  if (blocked) {
10169
10233
  setDragging(null);
10170
10234
  setHovered(null);
@@ -10429,7 +10493,7 @@ function KjunRangeSlider(props) {
10429
10493
  }
10430
10494
 
10431
10495
  // packages/native/src/quantity-stepper.tsx
10432
- import { useEffect as useEffect28, useRef as useRef35, useState as useState43 } from "react";
10496
+ import { useEffect as useEffect29, useRef as useRef38, useState as useState43 } from "react";
10433
10497
  import { Platform as Platform29, View as View53 } from "react-native";
10434
10498
  import { createNumberDomain, quantityKeyAction, tokens as tokens61 } from "@kjun-ui/tokens";
10435
10499
 
@@ -10453,15 +10517,15 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10453
10517
  const domain = createNumberDomain({ min, max, step, precision }), valid = domain.valid && domain.accepts(value), blocked = disabled || !valid;
10454
10518
  const surface = useFieldSurface(size, { disabled: blocked, invalid });
10455
10519
  const [draft, setDraft] = useState43(String(value));
10456
- const inputRef = useRef35(null);
10457
- const composing = useRef35(false), dirty = useRef35(false), accepted = useRef35(value);
10458
- const cancelledEscape = useRef35(false);
10459
- useEffect28(() => {
10520
+ const inputRef = useRef38(null);
10521
+ const composing = useRef38(false), dirty = useRef38(false), accepted = useRef38(value);
10522
+ const cancelledEscape = useRef38(false);
10523
+ useEffect29(() => {
10460
10524
  setDraft(String(value));
10461
10525
  accepted.current = value;
10462
10526
  dirty.current = false;
10463
10527
  }, [value, precision, min, max, step]);
10464
- useEffect28(() => {
10528
+ useEffect29(() => {
10465
10529
  if (!valid) console.warn("KJUN QuantityStepper: \uBC94\uC704\xB7step\xB7\uC815\uBC00\uB3C4\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10466
10530
  }, [valid]);
10467
10531
  const emit = (next) => {
@@ -10498,7 +10562,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10498
10562
  } else if (action === "commit") commit();
10499
10563
  else move(action === "increment" ? 1 : -1);
10500
10564
  };
10501
- const handlers = useRef35({ key, edit: (text) => {
10565
+ const handlers = useRef38({ key, edit: (text) => {
10502
10566
  dirty.current = true;
10503
10567
  setDraft(text);
10504
10568
  } });
@@ -10506,7 +10570,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10506
10570
  dirty.current = true;
10507
10571
  setDraft(text);
10508
10572
  } };
10509
- useEffect28(() => {
10573
+ useEffect29(() => {
10510
10574
  if (Platform29.OS !== "web") return;
10511
10575
  const input = inputRef.current;
10512
10576
  const keydown = (event) => handlers.current.key(event);
@@ -10578,7 +10642,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10578
10642
  }
10579
10643
 
10580
10644
  // packages/native/src/time-picker.tsx
10581
- import { Fragment as Fragment21, useEffect as useEffect29, useId as useId11, useMemo as useMemo4, useRef as useRef36, useState as useState44 } from "react";
10645
+ import { Fragment as Fragment21, useEffect as useEffect30, useId as useId11, useMemo as useMemo4, useRef as useRef39, useState as useState44 } from "react";
10582
10646
  import { View as View54 } from "react-native";
10583
10647
  import { createTimeDomain, tokens as tokens62 } from "@kjun-ui/tokens";
10584
10648
  import { jsx as jsx63, jsxs as jsxs46 } from "react/jsx-runtime";
@@ -10587,12 +10651,12 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
10587
10651
  ariaLabel != null ? ariaLabel : ariaLabel = m.time;
10588
10652
  const geometry2 = tokens62.extensions.timePicker, spec = tokens62.input[size];
10589
10653
  const { colors } = useKjunStyles();
10590
- const first = useRef36(null);
10654
+ const first = useRef39(null);
10591
10655
  const [focused, setFocused] = useState44(false), [opened, setOpened] = useState44(null);
10592
10656
  const field = useKjunField(), uid = useId11();
10593
10657
  const fieldId = (field == null ? void 0 : field.id) || `kjun-time-${uid}`;
10594
10658
  const domain = useMemo4(() => createTimeDomain({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
10595
- useEffect29(() => {
10659
+ useEffect30(() => {
10596
10660
  if (!valid) console.warn("KJUN TimePicker: \uC2DC\uAC01 \uBC94\uC704\xB7\uAC04\uACA9\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10597
10661
  }, [valid]);
10598
10662
  const change = (next) => {