@kjun-ui/native 0.14.0 → 0.15.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.cjs CHANGED
@@ -1818,13 +1818,25 @@ function KjunFormLayout({
1818
1818
  ) });
1819
1819
  }
1820
1820
 
1821
- // shared/package-runtime/content-presence.ts
1821
+ // shared/package-runtime/use-after-close.ts
1822
1822
  var import_react18 = require("react");
1823
+ function useAfterClose(present, onAfterClose, enabled = true) {
1824
+ const was = (0, import_react18.useRef)(present), callback = (0, import_react18.useRef)(onAfterClose);
1825
+ callback.current = onAfterClose;
1826
+ (0, import_react18.useEffect)(() => {
1827
+ var _a;
1828
+ if (was.current && !present && enabled) (_a = callback.current) == null ? void 0 : _a.call(callback);
1829
+ was.current = present;
1830
+ }, [present, enabled]);
1831
+ }
1832
+
1833
+ // shared/package-runtime/content-presence.ts
1834
+ var import_react19 = require("react");
1823
1835
  function hasContent(node) {
1824
1836
  if (node == null || typeof node === "boolean") return false;
1825
1837
  if (typeof node === "string") return node.trim().length > 0;
1826
1838
  if (Array.isArray(node)) return node.some(hasContent);
1827
- if ((0, import_react18.isValidElement)(node) && node.type === import_react18.Fragment)
1839
+ if ((0, import_react19.isValidElement)(node) && node.type === import_react19.Fragment)
1828
1840
  return hasContent(node.props.children);
1829
1841
  return true;
1830
1842
  }
@@ -1837,7 +1849,7 @@ function LayerBackdrop({ onPress, style }) {
1837
1849
  }
1838
1850
 
1839
1851
  // packages/native/src/modal.tsx
1840
- var import_react20 = require("react");
1852
+ var import_react21 = require("react");
1841
1853
 
1842
1854
  // shared/package-runtime/form-actions.ts
1843
1855
  function formActionsNeedStack(width, widths, gap) {
@@ -1850,7 +1862,7 @@ var import_tokens11 = require("@kjun-ui/tokens");
1850
1862
  var import_react_native14 = require("react-native");
1851
1863
 
1852
1864
  // packages/native/src/overlay-host.tsx
1853
- var import_react19 = require("react");
1865
+ var import_react20 = require("react");
1854
1866
  var import_react_native12 = require("react-native");
1855
1867
 
1856
1868
  // packages/native/src/modal-window.tsx
@@ -1866,17 +1878,18 @@ var import_jsx_runtime12 = (
1866
1878
  // a new window even when an interrupted exit retained the old surface.
1867
1879
  require("react/jsx-runtime")
1868
1880
  );
1869
- var FeedbackOverlayContext = (0, import_react19.createContext)(
1881
+ var FeedbackOverlayContext = (0, import_react20.createContext)(
1870
1882
  null
1871
1883
  );
1872
1884
  function ScopedNativeModal({ children, visible, ...props }) {
1873
- var _a;
1874
- const layers = useLayerState(), scope = (0, import_react19.useContext)(LayerScope);
1885
+ const layers = useLayerState(), scope = (0, import_react20.useContext)(LayerScope);
1875
1886
  const entry = scope ? layers.entries.get(scope) : void 0;
1876
- const generation = (_a = entry == null ? void 0 : entry.order) != null ? _a : 0;
1887
+ const last = (0, import_react20.useRef)(0);
1888
+ if (entry) last.current = entry.order;
1889
+ const generation = last.current;
1877
1890
  const inactive = !!scope && !layers.isActive(scope);
1878
- const host = (0, import_react19.useContext)(FeedbackOverlayContext), id = "kjun-" + (0, import_react19.useId)(), register = host == null ? void 0 : host.register;
1879
- (0, import_react19.useEffect)(
1891
+ const host = (0, import_react20.useContext)(FeedbackOverlayContext), id = "kjun-" + (0, import_react20.useId)(), register = host == null ? void 0 : host.register;
1892
+ (0, import_react20.useEffect)(
1880
1893
  () => visible && register ? register(id) : void 0,
1881
1894
  [visible, register, id, generation]
1882
1895
  );
@@ -1925,7 +1938,7 @@ function KjunFormActions({
1925
1938
  cancelText != null ? cancelText : cancelText = m.cancel;
1926
1939
  confirmText != null ? confirmText : confirmText = m.save;
1927
1940
  const { fontFamily } = useKjunStyles();
1928
- const [width, setWidth] = (0, import_react20.useState)(0), [measurements, setMeasurements] = (0, import_react20.useState)({});
1941
+ const [width, setWidth] = (0, import_react21.useState)(0), [measurements, setMeasurements] = (0, import_react21.useState)({});
1929
1942
  const labels = [showCancel && { text: cancelText }, showConfirm && { text: confirmText }].filter(Boolean);
1930
1943
  const keyFor = (text) => `${fontFamily}:${size}:${text}`;
1931
1944
  const widths = labels.map((label) => measurements[keyFor(label.text)] === void 0 ? 0 : Math.max(import_tokens11.tokens.button.minWidths[size], measurements[keyFor(label.text)] + import_tokens11.tokens.button.paddingX[size] * 2));
@@ -1997,6 +2010,7 @@ function KjunModal({
1997
2010
  open,
1998
2011
  onOpenChange,
1999
2012
  onClose,
2013
+ onAfterClose,
2000
2014
  onCancel,
2001
2015
  onConfirm,
2002
2016
  title = "",
@@ -2029,7 +2043,7 @@ function KjunModal({
2029
2043
  const motion = useNativePresence(open, import_tokens11.tokens.motion.layerEnter, import_tokens11.tokens.motion.layerExit, true, 0, { fade: import_tokens11.tokens.motion.backdropExit });
2030
2044
  const offset = useMotionValue(open ? 0 : import_tokens11.tokens.motionDistance.modalExit, open ? import_tokens11.tokens.motion.layerEnter : import_tokens11.tokens.motion.layerExit, import_tokens11.tokens.motionDistance.modalEnter, open ? motionOut : motionIn, true);
2031
2045
  const backdrop = useNativePresence(open, import_tokens11.tokens.motion.backdrop, import_tokens11.tokens.motion.backdropExit, true, 0, { fade: import_tokens11.tokens.motion.backdropExit });
2032
- (0, import_react20.useLayoutEffect)(() => {
2046
+ (0, import_react21.useLayoutEffect)(() => {
2033
2047
  if (!motion.present) {
2034
2048
  offset.stopAnimation();
2035
2049
  offset.setValue(import_tokens11.tokens.motionDistance.modalEnter);
@@ -2044,10 +2058,15 @@ function KjunModal({
2044
2058
  const layer = useLayer(open, motion.present, "window", () => {
2045
2059
  if (closeOnEsc) close();
2046
2060
  });
2061
+ const iosDismiss = import_react_native14.Platform.OS === "ios";
2062
+ useAfterClose(motion.present, onAfterClose, !iosDismiss);
2047
2063
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(LayerScope.Provider, { value: layer.id, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
2048
2064
  ScopedNativeModal,
2049
2065
  {
2050
2066
  visible: motion.present,
2067
+ onDismiss: iosDismiss ? () => {
2068
+ if (!open) onAfterClose == null ? void 0 : onAfterClose();
2069
+ } : void 0,
2051
2070
  transparent: true,
2052
2071
  animationType: "none",
2053
2072
  onRequestClose: () => {
@@ -2205,7 +2224,7 @@ function KjunModal({
2205
2224
 
2206
2225
  // packages/native/src/card.tsx
2207
2226
  var import_tokens12 = require("@kjun-ui/tokens");
2208
- var import_react21 = require("react");
2227
+ var import_react22 = require("react");
2209
2228
  var import_react_native15 = require("react-native");
2210
2229
  var import_react_native_svg2 = __toESM(require("react-native-svg"), 1);
2211
2230
  var import_jsx_runtime14 = require("react/jsx-runtime");
@@ -2231,7 +2250,7 @@ function KjunCard({
2231
2250
  onPress
2232
2251
  }) {
2233
2252
  const { colors } = useKjunStyles();
2234
- const id = "kjun-" + (0, import_react21.useId)().replace(/[^a-z0-9]/gi, "");
2253
+ const id = "kjun-" + (0, import_react22.useId)().replace(/[^a-z0-9]/gi, "");
2235
2254
  const inset = import_tokens12.tokens.card.padding[padding], bodyInset = import_tokens12.tokens.card.padding[bodyPadding];
2236
2255
  const corner = import_tokens12.tokens.card.radii[radius];
2237
2256
  const paint = import_tokens12.tokens.cardSurfaces[surface];
@@ -2315,7 +2334,7 @@ function alertRole(tone, live) {
2315
2334
 
2316
2335
  // packages/native/src/display-primitives.tsx
2317
2336
  var import_tokens14 = require("@kjun-ui/tokens");
2318
- var import_react22 = require("react");
2337
+ var import_react23 = require("react");
2319
2338
  var import_react_native16 = require("react-native");
2320
2339
  var import_react_native_svg3 = __toESM(require("react-native-svg"), 1);
2321
2340
 
@@ -2439,7 +2458,7 @@ function KjunEmpty({
2439
2458
  text != null ? text : text = m.noData;
2440
2459
  const { colors } = useKjunStyles();
2441
2460
  const spec = import_tokens14.tokens.extensions.empty;
2442
- const stateContent = (0, import_react22.useContext)(DataStateContentContext);
2461
+ const stateContent = (0, import_react23.useContext)(DataStateContentContext);
2443
2462
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
2444
2463
  import_react_native16.View,
2445
2464
  {
@@ -2473,8 +2492,8 @@ function KjunEmpty({
2473
2492
  }
2474
2493
  function KjunSpinner({ size = "md", text }) {
2475
2494
  const m = useKjunMessages();
2476
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), rotation = (0, import_react22.useRef)(new import_react_native16.Animated.Value(0)).current;
2477
- (0, import_react22.useEffect)(() => {
2495
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), rotation = (0, import_react23.useRef)(new import_react_native16.Animated.Value(0)).current;
2496
+ (0, import_react23.useEffect)(() => {
2478
2497
  if (reduced) return;
2479
2498
  const loop = import_react_native16.Animated.loop(
2480
2499
  import_react_native16.Animated.timing(rotation, {
@@ -2563,7 +2582,7 @@ function KjunAlert({
2563
2582
  }) {
2564
2583
  const m = useKjunMessages();
2565
2584
  const { colors } = useKjunStyles();
2566
- const [visible, setVisible] = (0, import_react22.useState)(true);
2585
+ const [visible, setVisible] = (0, import_react23.useState)(true);
2567
2586
  if (!visible) return null;
2568
2587
  const tone = variant || (type === "error" ? "danger" : type), small = size === "sm";
2569
2588
  const geometry2 = import_tokens14.tokens.extensions.alert;
@@ -2767,7 +2786,7 @@ function KjunProgress({
2767
2786
 
2768
2787
  // packages/native/src/skeleton-base.tsx
2769
2788
  var import_tokens15 = require("@kjun-ui/tokens");
2770
- var import_react23 = require("react");
2789
+ var import_react24 = require("react");
2771
2790
  var import_react_native17 = require("react-native");
2772
2791
  var import_jsx_runtime16 = require("react/jsx-runtime");
2773
2792
  function KjunSkeleton({
@@ -2779,8 +2798,8 @@ function KjunSkeleton({
2779
2798
  animated = true,
2780
2799
  rounded = true
2781
2800
  }) {
2782
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react23.useRef)(new import_react_native17.Animated.Value(1)).current;
2783
- (0, import_react23.useEffect)(() => {
2801
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react24.useRef)(new import_react_native17.Animated.Value(1)).current;
2802
+ (0, import_react24.useEffect)(() => {
2784
2803
  if (!animated || reduced) return;
2785
2804
  const loop = import_react_native17.Animated.loop(
2786
2805
  import_react_native17.Animated.sequence([
@@ -2935,7 +2954,7 @@ function KjunSkeleton({
2935
2954
  }
2936
2955
 
2937
2956
  // packages/native/src/layout-primitives.tsx
2938
- var import_react24 = require("react");
2957
+ var import_react25 = require("react");
2939
2958
  var import_react_native18 = require("react-native");
2940
2959
  var import_tokens16 = require("@kjun-ui/tokens");
2941
2960
 
@@ -2958,13 +2977,15 @@ var toneRole = {
2958
2977
  inverse: "onBrand"
2959
2978
  };
2960
2979
  var textAlign = { start: "left", center: "center", end: "right" };
2961
- function KjunText({ variant = "body", tone = "default", align, maxLines, style, children }) {
2980
+ function KjunText({ variant = "body", tone = "default", align, maxLines, style, children, ...rest }) {
2981
+ var _a;
2962
2982
  const { colors, fontFamily, numericFontFamily } = useKjunStyles();
2963
2983
  const lines = maxLines && maxLines > 0 ? Math.floor(maxLines) : void 0;
2964
2984
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
2965
2985
  KText,
2966
2986
  {
2967
- accessibilityRole: titleVariants.includes(variant) ? "header" : void 0,
2987
+ ...rest,
2988
+ accessibilityRole: (_a = rest.accessibilityRole) != null ? _a : titleVariants.includes(variant) ? "header" : void 0,
2968
2989
  numberOfLines: lines,
2969
2990
  ellipsizeMode: lines ? "tail" : void 0,
2970
2991
  style: [
@@ -2979,23 +3000,23 @@ function KjunText({ variant = "body", tone = "default", align, maxLines, style,
2979
3000
  );
2980
3001
  }
2981
3002
  function flatten(children, path = "") {
2982
- return import_react24.Children.toArray(children).flatMap((child, i) => {
3003
+ return import_react25.Children.toArray(children).flatMap((child, i) => {
2983
3004
  const key = `${path}${i}`;
2984
- return (0, import_react24.isValidElement)(child) && child.type === import_react24.Fragment ? flatten(child.props.children, `${key}.`) : [[key, child]];
3005
+ return (0, import_react25.isValidElement)(child) && child.type === import_react25.Fragment ? flatten(child.props.children, `${key}.`) : [[key, child]];
2985
3006
  });
2986
3007
  }
2987
3008
  function items(children, childAlign) {
2988
3009
  return flatten(children).map(([key, child]) => {
2989
3010
  if (typeof child === "string" || typeof child === "number") return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(KText, { children: child }, key);
2990
- if ((0, import_react24.isValidElement)(child) && child.type === KjunFormGroup) {
3011
+ if ((0, import_react25.isValidElement)(child) && child.type === KjunFormGroup) {
2991
3012
  const group = child;
2992
- return (0, import_react24.cloneElement)(group, { key, style: [{ marginBottom: 0 }, group.props.style] });
3013
+ return (0, import_react25.cloneElement)(group, { key, style: [{ marginBottom: 0 }, group.props.style] });
2993
3014
  }
2994
- if (childAlign && (0, import_react24.isValidElement)(child) && (child.type === KjunButton || child.type === KjunBadge)) {
3015
+ if (childAlign && (0, import_react25.isValidElement)(child) && (child.type === KjunButton || child.type === KjunBadge)) {
2995
3016
  const control = child;
2996
- return (0, import_react24.cloneElement)(control, { key, style: [{ alignSelf: childAlign }, control.props.style] });
3017
+ return (0, import_react25.cloneElement)(control, { key, style: [{ alignSelf: childAlign }, control.props.style] });
2997
3018
  }
2998
- return (0, import_react24.isValidElement)(child) ? (0, import_react24.cloneElement)(child, { key }) : child;
3019
+ return (0, import_react25.isValidElement)(child) ? (0, import_react25.cloneElement)(child, { key }) : child;
2999
3020
  });
3000
3021
  }
3001
3022
  var followed = (align) => align && align !== "stretch" ? crossAxis[align] : void 0;
@@ -3032,13 +3053,13 @@ function KjunInline({ gap = "sm", align, justify = "start", wrap = true, style,
3032
3053
  }
3033
3054
 
3034
3055
  // shared/package-runtime/feedback-dialog.ts
3035
- var import_react25 = require("react");
3056
+ var import_react26 = require("react");
3036
3057
  function useFeedbackDialog(controller, request, messages = kjunMessagesKo) {
3037
3058
  const options = request.options;
3038
- const [value, setValue] = (0, import_react25.useState)(options.initialValue || "");
3039
- const [error, setError] = (0, import_react25.useState)("");
3040
- const [busy, setBusy] = (0, import_react25.useState)(false);
3041
- const working = (0, import_react25.useRef)(false);
3059
+ const [value, setValue] = (0, import_react26.useState)(options.initialValue || "");
3060
+ const [error, setError] = (0, import_react26.useState)("");
3061
+ const [busy, setBusy] = (0, import_react26.useState)(false);
3062
+ const working = (0, import_react26.useRef)(false);
3042
3063
  const active = () => {
3043
3064
  var _a;
3044
3065
  return ((_a = controller.getSnapshot().current) == null ? void 0 : _a.id) === request.id;
@@ -3081,11 +3102,11 @@ function useFeedbackDialog(controller, request, messages = kjunMessagesKo) {
3081
3102
 
3082
3103
  // shared/package-runtime/feedback-motion.ts
3083
3104
  var import_tokens17 = require("@kjun-ui/tokens");
3084
- var import_react26 = require("react");
3105
+ var import_react27 = require("react");
3085
3106
  function usePresentedToasts(toasts, reduced) {
3086
- const [items2, setItems] = (0, import_react26.useState)([]);
3087
- const removals = (0, import_react26.useRef)(/* @__PURE__ */ new Map());
3088
- (0, import_react26.useLayoutEffect)(() => {
3107
+ const [items2, setItems] = (0, import_react27.useState)([]);
3108
+ const removals = (0, import_react27.useRef)(/* @__PURE__ */ new Map());
3109
+ (0, import_react27.useLayoutEffect)(() => {
3089
3110
  const ids = new Set(toasts.map((toast) => toast.id));
3090
3111
  setItems((previous) => {
3091
3112
  const old = new Map(previous.map((item) => [item.toast.id, item]));
@@ -3107,15 +3128,15 @@ function usePresentedToasts(toasts, reduced) {
3107
3128
  removals.current.clear();
3108
3129
  }
3109
3130
  }, [toasts, reduced]);
3110
- (0, import_react26.useLayoutEffect)(() => () => {
3131
+ (0, import_react27.useLayoutEffect)(() => () => {
3111
3132
  for (const timer of removals.current.values()) clearTimeout(timer);
3112
3133
  removals.current.clear();
3113
3134
  }, []);
3114
3135
  return items2;
3115
3136
  }
3116
3137
  function usePresentedRequest(current, reduced) {
3117
- const [request, setRequest] = (0, import_react26.useState)(current);
3118
- (0, import_react26.useLayoutEffect)(() => {
3138
+ const [request, setRequest] = (0, import_react27.useState)(current);
3139
+ (0, import_react27.useLayoutEffect)(() => {
3119
3140
  if (!request || request.id === (current == null ? void 0 : current.id) || reduced) {
3120
3141
  setRequest(current);
3121
3142
  return;
@@ -3127,14 +3148,14 @@ function usePresentedRequest(current, reduced) {
3127
3148
  }
3128
3149
 
3129
3150
  // packages/native/src/feedback-context.ts
3130
- var import_react27 = require("react");
3131
- var KjunFeedbackContext = (0, import_react27.createContext)(null);
3151
+ var import_react28 = require("react");
3152
+ var KjunFeedbackContext = (0, import_react28.createContext)(null);
3132
3153
  function useOptionalKjunFeedback() {
3133
- return (0, import_react27.useContext)(KjunFeedbackContext);
3154
+ return (0, import_react28.useContext)(KjunFeedbackContext);
3134
3155
  }
3135
3156
 
3136
3157
  // packages/native/src/toast-stack.tsx
3137
- var import_react29 = require("react");
3158
+ var import_react30 = require("react");
3138
3159
  var import_react_native20 = require("react-native");
3139
3160
  var import_tokens19 = require("@kjun-ui/tokens");
3140
3161
 
@@ -3152,7 +3173,7 @@ function shadowLayers(layers, colors) {
3152
3173
 
3153
3174
  // packages/native/src/toast.tsx
3154
3175
  var import_tokens18 = require("@kjun-ui/tokens");
3155
- var import_react28 = require("react");
3176
+ var import_react29 = require("react");
3156
3177
  var import_react_native19 = require("react-native");
3157
3178
  var import_jsx_runtime18 = require("react/jsx-runtime");
3158
3179
  function ToastView({
@@ -3160,14 +3181,14 @@ function ToastView({
3160
3181
  controller
3161
3182
  }) {
3162
3183
  const m = useKjunMessages();
3163
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), progress = (0, import_react28.useRef)(new import_react_native19.Animated.Value(1)).current;
3164
- const reasons = (0, import_react28.useRef)({
3184
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), progress = (0, import_react29.useRef)(new import_react_native19.Animated.Value(1)).current;
3185
+ const reasons = (0, import_react29.useRef)({
3165
3186
  hover: /* @__PURE__ */ Symbol("hover"),
3166
3187
  actionHover: /* @__PURE__ */ Symbol("actionHover"),
3167
3188
  closeHover: /* @__PURE__ */ Symbol("closeHover"),
3168
3189
  focus: /* @__PURE__ */ Symbol("focus")
3169
3190
  }).current;
3170
- (0, import_react28.useEffect)(() => () => {
3191
+ (0, import_react29.useEffect)(() => () => {
3171
3192
  for (const reason of Object.values(reasons)) controller.resumeToast(toast.id, reason);
3172
3193
  }, [controller, toast.id, reasons]);
3173
3194
  const tone = toast.type === "error" ? "danger" : toast.type || "info", icon = {
@@ -3176,7 +3197,7 @@ function ToastView({
3176
3197
  warning: "alert-triangle",
3177
3198
  info: "info-circle"
3178
3199
  }[tone];
3179
- (0, import_react28.useEffect)(() => {
3200
+ (0, import_react29.useEffect)(() => {
3180
3201
  progress.stopAnimation();
3181
3202
  progress.setValue(toast.duration ? toast.remaining / toast.duration : 1);
3182
3203
  if (!toast.paused && !reduced) {
@@ -3296,17 +3317,17 @@ function useToastReflow(_root, _reduced) {
3296
3317
  // packages/native/src/toast-stack.tsx
3297
3318
  var import_jsx_runtime19 = require("react/jsx-runtime");
3298
3319
  function ToastSlot({ item, controller, boxes }) {
3299
- const born = (0, import_react29.useRef)(Math.min(import_tokens19.tokens.motion.toastEnter, Date.now() - item.born)).current;
3320
+ const born = (0, import_react30.useRef)(Math.min(import_tokens19.tokens.motion.toastEnter, Date.now() - item.born)).current;
3300
3321
  const motion = useNativePresence(!item.exiting, import_tokens19.tokens.motion.toastEnter - born, import_tokens19.tokens.motion.toastExit, true, born / import_tokens19.tokens.motion.toastEnter);
3301
- const offset = (0, import_react29.useRef)(new import_react_native20.Animated.Value(0)).current;
3322
+ const offset = (0, import_react30.useRef)(new import_react_native20.Animated.Value(0)).current;
3302
3323
  const box = boxes.get(item.toast.id);
3303
- (0, import_react29.useLayoutEffect)(() => {
3324
+ (0, import_react30.useLayoutEffect)(() => {
3304
3325
  if (motion.reduced) {
3305
3326
  offset.stopAnimation();
3306
3327
  offset.setValue(0);
3307
3328
  }
3308
3329
  }, [motion.reduced, offset]);
3309
- (0, import_react29.useLayoutEffect)(() => () => offset.stopAnimation(), [offset]);
3330
+ (0, import_react30.useLayoutEffect)(() => () => offset.stopAnimation(), [offset]);
3310
3331
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
3311
3332
  import_react_native20.Animated.View,
3312
3333
  {
@@ -3345,9 +3366,9 @@ function ToastSlot({ item, controller, boxes }) {
3345
3366
  function ToastStack({ items: items2, controller }) {
3346
3367
  var _a;
3347
3368
  const layers = useLayerState();
3348
- const root = (0, import_react29.useRef)(null), reduced = useReducedMotion();
3369
+ const root = (0, import_react30.useRef)(null), reduced = useReducedMotion();
3349
3370
  useToastReflow(root, reduced);
3350
- const boxes = (0, import_react29.useRef)(/* @__PURE__ */ new Map()).current;
3371
+ const boxes = (0, import_react30.useRef)(/* @__PURE__ */ new Map()).current;
3351
3372
  for (const id of boxes.keys()) if (!items2.some((item) => item.toast.id === id)) boxes.delete(id);
3352
3373
  return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_react_native20.View, { ref: root, pointerEvents: "box-none", style: {
3353
3374
  position: "absolute",
@@ -3362,7 +3383,7 @@ function ToastStack({ items: items2, controller }) {
3362
3383
 
3363
3384
  // packages/native/src/feedback.tsx
3364
3385
  var import_tokens20 = require("@kjun-ui/tokens");
3365
- var import_react30 = require("react");
3386
+ var import_react31 = require("react");
3366
3387
  var import_react_native21 = require("react-native");
3367
3388
  var import_tokens21 = require("@kjun-ui/tokens");
3368
3389
  var import_jsx_runtime20 = require("react/jsx-runtime");
@@ -3414,11 +3435,11 @@ function FeedbackDialog({
3414
3435
  );
3415
3436
  }
3416
3437
  function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3417
- const [owned] = (0, import_react30.useState)(() => controllerProp ? void 0 : (0, import_tokens20.createFeedbackController)());
3438
+ const [owned] = (0, import_react31.useState)(() => controllerProp ? void 0 : (0, import_tokens20.createFeedbackController)());
3418
3439
  const controller = controllerProp ? (0, import_tokens20.feedbackControllerOf)(controllerProp) : owned;
3419
- (0, import_react30.useEffect)(() => controller.attach(), [controller]);
3420
- const life = (0, import_react30.useRef)(0);
3421
- const snapshot = (0, import_react30.useSyncExternalStore)(
3440
+ (0, import_react31.useEffect)(() => controller.attach(), [controller]);
3441
+ const life = (0, import_react31.useRef)(0);
3442
+ const snapshot = (0, import_react31.useSyncExternalStore)(
3422
3443
  controller.subscribe,
3423
3444
  controller.getSnapshot,
3424
3445
  controller.getSnapshot
@@ -3426,7 +3447,7 @@ function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3426
3447
  const reduced = useReducedMotion();
3427
3448
  const toasts = usePresentedToasts(snapshot.toasts, reduced);
3428
3449
  const dialog = usePresentedRequest(snapshot.current, reduced);
3429
- (0, import_react30.useEffect)(() => {
3450
+ (0, import_react31.useEffect)(() => {
3430
3451
  const version = ++life.current;
3431
3452
  return () => {
3432
3453
  queueMicrotask(() => {
@@ -3434,8 +3455,8 @@ function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3434
3455
  });
3435
3456
  };
3436
3457
  }, [controller]);
3437
- const [layers, setLayers] = (0, import_react30.useState)([]);
3438
- const register = (0, import_react30.useCallback)((id) => {
3458
+ const [layers, setLayers] = (0, import_react31.useState)([]);
3459
+ const register = (0, import_react31.useCallback)((id) => {
3439
3460
  setLayers((previous) => [...previous, id]);
3440
3461
  return () => setLayers((previous) => previous.filter((item) => item !== id));
3441
3462
  }, []);
@@ -3466,7 +3487,7 @@ function KjunFeedbackProvider({ children, style, controller: controllerProp }) {
3466
3487
  // packages/native/src/choice-controls.tsx
3467
3488
  var import_react_native22 = require("react-native");
3468
3489
  var import_tokens22 = require("@kjun-ui/tokens");
3469
- var import_react31 = require("react");
3490
+ var import_react32 = require("react");
3470
3491
  var import_react_native23 = require("react-native");
3471
3492
  var import_jsx_runtime21 = require("react/jsx-runtime");
3472
3493
  function KjunCheckbox({
@@ -3537,7 +3558,7 @@ function KjunCheckbox({
3537
3558
  }
3538
3559
  function useControlFocus(disabled) {
3539
3560
  const { colors } = useKjunStyles();
3540
- const [focused, setFocused] = (0, import_react31.useState)(false);
3561
+ const [focused, setFocused] = (0, import_react32.useState)(false);
3541
3562
  return {
3542
3563
  handlers: {
3543
3564
  focusRing: false,
@@ -3566,7 +3587,7 @@ function KjunSwitch({
3566
3587
  const offset = width - height;
3567
3588
  const motion = useMotionValue(value ? 1 : 0);
3568
3589
  const focus = useControlFocus(disabled);
3569
- const [hovered, setHovered] = (0, import_react31.useState)(false);
3590
+ const [hovered, setHovered] = (0, import_react32.useState)(false);
3570
3591
  const trackColor = typeof colors.active === "string" && typeof colors.brand === "string" ? motion.interpolate({ inputRange: [0, 1], outputRange: [colors.active, colors.brand] }) : value ? colors.brand : colors.active;
3571
3592
  const offRole = disabled ? colors.borderSecondary : colors.borderStrong;
3572
3593
  const thumbColor = typeof offRole === "string" && typeof colors.switchThumbOn === "string" ? motion.interpolate({ inputRange: [0, 1], outputRange: [offRole, colors.switchThumbOn] }) : value ? colors.switchThumbOn : offRole;
@@ -3651,7 +3672,7 @@ function KjunSwitch({
3651
3672
  }
3652
3673
  );
3653
3674
  }
3654
- var RadioContext = (0, import_react31.createContext)(null);
3675
+ var RadioContext = (0, import_react32.createContext)(null);
3655
3676
  function KjunRadio({
3656
3677
  value,
3657
3678
  val,
@@ -3662,10 +3683,10 @@ function KjunRadio({
3662
3683
  onValueChange,
3663
3684
  onChange
3664
3685
  }) {
3665
- const group = (0, import_react31.useContext)(RadioContext), { colors } = useKjunStyles(), selected = (group ? group.value : value) === val;
3686
+ const group = (0, import_react32.useContext)(RadioContext), { colors } = useKjunStyles(), selected = (group ? group.value : value) === val;
3666
3687
  const geometry2 = import_tokens22.tokens.extensions.radio;
3667
- const [hovered, setHovered] = (0, import_react31.useState)(false);
3668
- (0, import_react31.useEffect)(() => {
3688
+ const [hovered, setHovered] = (0, import_react32.useState)(false);
3689
+ (0, import_react32.useEffect)(() => {
3669
3690
  if (disabled) setHovered(false);
3670
3691
  }, [disabled]);
3671
3692
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
@@ -3737,7 +3758,7 @@ function KjunRadioGroup({
3737
3758
  onValueChange,
3738
3759
  onChange
3739
3760
  }) {
3740
- const root = (0, import_react31.useRef)(null);
3761
+ const root = (0, import_react32.useRef)(null);
3741
3762
  useRadioKeyboard(root);
3742
3763
  return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
3743
3764
  RadioContext.Provider,
@@ -3777,11 +3798,11 @@ function KjunRadioGroup({
3777
3798
 
3778
3799
  // packages/native/src/selection-groups.tsx
3779
3800
  var import_tokens24 = require("@kjun-ui/tokens");
3780
- var import_react33 = require("react");
3801
+ var import_react34 = require("react");
3781
3802
  var import_react_native25 = require("react-native");
3782
3803
 
3783
3804
  // packages/native/src/button-group-motion.tsx
3784
- var import_react32 = require("react");
3805
+ var import_react33 = require("react");
3785
3806
  var import_react_native24 = require("react-native");
3786
3807
  var import_tokens23 = require("@kjun-ui/tokens");
3787
3808
  var import_jsx_runtime22 = require("react/jsx-runtime");
@@ -3790,16 +3811,16 @@ var easing = import_react_native24.Easing.bezier(...curve);
3790
3811
  var sameBox = (a, b) => a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
3791
3812
  function useButtonGroupMotion(selected) {
3792
3813
  const reduced = useReducedMotion();
3793
- const [layouts, setLayouts] = (0, import_react32.useState)(/* @__PURE__ */ new Map());
3794
- const x = (0, import_react32.useRef)(new import_react_native24.Animated.Value(0)).current;
3795
- const width = (0, import_react32.useRef)(new import_react_native24.Animated.Value(0)).current;
3796
- const previous = (0, import_react32.useRef)(null);
3814
+ const [layouts, setLayouts] = (0, import_react33.useState)(/* @__PURE__ */ new Map());
3815
+ const x = (0, import_react33.useRef)(new import_react_native24.Animated.Value(0)).current;
3816
+ const width = (0, import_react33.useRef)(new import_react_native24.Animated.Value(0)).current;
3817
+ const previous = (0, import_react33.useRef)(null);
3797
3818
  const layout = selected && layouts.get(selected.value);
3798
- const updateLayout = (0, import_react32.useCallback)((value, box) => {
3819
+ const updateLayout = (0, import_react33.useCallback)((value, box) => {
3799
3820
  setLayouts((old) => old.has(value) && sameBox(old.get(value), box) ? old : new Map(old).set(value, box));
3800
3821
  }, []);
3801
- const measure = (0, import_react32.useCallback)((value, event) => updateLayout(value, event.nativeEvent.layout), [updateLayout]);
3802
- (0, import_react32.useLayoutEffect)(() => {
3822
+ const measure = (0, import_react33.useCallback)((value, event) => updateLayout(value, event.nativeEvent.layout), [updateLayout]);
3823
+ (0, import_react33.useLayoutEffect)(() => {
3803
3824
  const old = previous.current;
3804
3825
  if (!selected || !layout) {
3805
3826
  previous.current = null;
@@ -3821,7 +3842,7 @@ function useButtonGroupMotion(selected) {
3821
3842
  }
3822
3843
  previous.current = { value: selected.value, box: layout, reduced };
3823
3844
  }, [selected == null ? void 0 : selected.value, layout, reduced, x, width]);
3824
- (0, import_react32.useEffect)(() => () => {
3845
+ (0, import_react33.useEffect)(() => () => {
3825
3846
  x.stopAnimation();
3826
3847
  width.stopAnimation();
3827
3848
  }, [x, width]);
@@ -3829,9 +3850,9 @@ function useButtonGroupMotion(selected) {
3829
3850
  }
3830
3851
  function ButtonGroupLabel({ label, active, size, reduced }) {
3831
3852
  const { colors, fontFamily } = useKjunStyles();
3832
- const progress = (0, import_react32.useRef)(new import_react_native24.Animated.Value(active ? 1 : 0)).current;
3853
+ const progress = (0, import_react33.useRef)(new import_react_native24.Animated.Value(active ? 1 : 0)).current;
3833
3854
  const interpolate = typeof colors.textSecondary === "string" && typeof colors.text === "string";
3834
- (0, import_react32.useEffect)(() => {
3855
+ (0, import_react33.useEffect)(() => {
3835
3856
  progress.stopAnimation();
3836
3857
  if (reduced || !interpolate) progress.setValue(active ? 1 : 0);
3837
3858
  else import_react_native24.Animated.timing(progress, { toValue: active ? 1 : 0, duration: import_tokens23.tokens.motion.indicator, easing, useNativeDriver: false }).start();
@@ -3878,9 +3899,9 @@ function KjunButtonGroup({
3878
3899
  const motion = useButtonGroupMotion(selected);
3879
3900
  const padding = import_tokens24.tokens.buttonGroup.padding[size];
3880
3901
  const itemRadius = import_tokens24.tokens.buttonGroup.itemRadii[size];
3881
- const itemRefs = (0, import_react33.useRef)(/* @__PURE__ */ new Map());
3902
+ const itemRefs = (0, import_react34.useRef)(/* @__PURE__ */ new Map());
3882
3903
  const { updateLayout } = motion;
3883
- (0, import_react33.useLayoutEffect)(() => {
3904
+ (0, import_react34.useLayoutEffect)(() => {
3884
3905
  for (const [value2, node] of itemRefs.current) {
3885
3906
  node.measure((x, y, width, height) => updateLayout(value2, { x, y, width, height }));
3886
3907
  }
@@ -4119,10 +4140,10 @@ function KjunFilterGroup({
4119
4140
 
4120
4141
  // packages/native/src/textarea.tsx
4121
4142
  var import_tokens25 = require("@kjun-ui/tokens");
4122
- var import_react34 = require("react");
4143
+ var import_react35 = require("react");
4123
4144
  var import_react_native26 = require("react-native");
4124
4145
  var import_jsx_runtime24 = require("react/jsx-runtime");
4125
- var KjunTextarea = (0, import_react34.forwardRef)(
4146
+ var KjunTextarea = (0, import_react35.forwardRef)(
4126
4147
  function KjunTextarea2({
4127
4148
  value,
4128
4149
  size = "md",
@@ -4192,7 +4213,7 @@ var KjunTextarea = (0, import_react34.forwardRef)(
4192
4213
 
4193
4214
  // packages/native/src/drawer.tsx
4194
4215
  var import_tokens26 = require("@kjun-ui/tokens");
4195
- var import_react35 = require("react");
4216
+ var import_react36 = require("react");
4196
4217
  var import_react_native27 = require("react-native");
4197
4218
 
4198
4219
  // shared/package-runtime/drawer-geometry.ts
@@ -4221,8 +4242,8 @@ function drawerFrame({ position, windowHeight, safeAreaTop, safeAreaBottom, gap,
4221
4242
  var import_react_native28 = require("react-native");
4222
4243
  var import_jsx_runtime25 = require("react/jsx-runtime");
4223
4244
  function useKeyboardOverlap(enabled, windowHeight) {
4224
- const [overlap, setOverlap] = (0, import_react35.useState)(0);
4225
- (0, import_react35.useEffect)(() => {
4245
+ const [overlap, setOverlap] = (0, import_react36.useState)(0);
4246
+ (0, import_react36.useEffect)(() => {
4226
4247
  var _a, _b;
4227
4248
  setOverlap(0);
4228
4249
  const events = keyboardEvents(import_react_native28.Platform.OS);
@@ -4252,6 +4273,7 @@ function KjunDrawer({
4252
4273
  footer,
4253
4274
  children,
4254
4275
  onClose,
4276
+ onAfterClose,
4255
4277
  ariaLabel,
4256
4278
  safeAreaTop = 0,
4257
4279
  safeAreaBottom = 0,
@@ -4260,7 +4282,7 @@ function KjunDrawer({
4260
4282
  }) {
4261
4283
  const m = useKjunMessages();
4262
4284
  const { colors } = useKjunStyles(), window2 = (0, import_react_native28.useWindowDimensions)(), vertical = position === "left" || position === "right";
4263
- const [rootHeight, setRootHeight] = (0, import_react35.useState)(0);
4285
+ const [rootHeight, setRootHeight] = (0, import_react36.useState)(0);
4264
4286
  const keyboard = useKeyboardOverlap(open && avoidKeyboard, window2.height);
4265
4287
  const frame = drawerFrame({
4266
4288
  position,
@@ -4271,7 +4293,7 @@ function KjunDrawer({
4271
4293
  keyboard,
4272
4294
  maxHeight
4273
4295
  });
4274
- const [panelHeight, setPanelHeight] = (0, import_react35.useState)(0);
4296
+ const [panelHeight, setPanelHeight] = (0, import_react36.useState)(0);
4275
4297
  const motion = useNativePresence(open, import_tokens26.tokens.motion.layerEnter, import_tokens26.tokens.motion.layerExit, vertical || panelHeight > 0, 0, { enterEasing: motionEmphasized });
4276
4298
  const backdrop = useNativePresence(open, import_tokens26.tokens.motion.backdrop, import_tokens26.tokens.motion.backdropExit, true, 0, { fade: import_tokens26.tokens.motion.backdropExit });
4277
4299
  const close = () => {
@@ -4282,10 +4304,15 @@ function KjunDrawer({
4282
4304
  const layer = useLayer(open, motion.present, "window", () => {
4283
4305
  if (closeOnEsc) close();
4284
4306
  });
4307
+ const iosDismiss = import_react_native28.Platform.OS === "ios";
4308
+ useAfterClose(motion.present, onAfterClose, !iosDismiss);
4285
4309
  return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(LayerScope.Provider, { value: layer.id, children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
4286
4310
  ScopedNativeModal,
4287
4311
  {
4288
4312
  visible: motion.present,
4313
+ onDismiss: iosDismiss ? () => {
4314
+ if (!open) onAfterClose == null ? void 0 : onAfterClose();
4315
+ } : void 0,
4289
4316
  transparent: true,
4290
4317
  onRequestClose: () => {
4291
4318
  if (closeOnEsc) close();
@@ -4412,13 +4439,13 @@ function KjunDrawer({
4412
4439
 
4413
4440
  // packages/native/src/dropdown.tsx
4414
4441
  var import_tokens29 = require("@kjun-ui/tokens");
4415
- var import_react38 = require("react");
4442
+ var import_react39 = require("react");
4416
4443
  var import_react_native32 = require("react-native");
4417
4444
 
4418
4445
  // packages/native/src/floating-panel.tsx
4419
4446
  var import_react_native29 = require("react-native");
4420
4447
  var import_tokens27 = require("@kjun-ui/tokens");
4421
- var import_react36 = require("react");
4448
+ var import_react37 = require("react");
4422
4449
  var import_react_native30 = require("react-native");
4423
4450
  var import_react_native_svg4 = __toESM(require("react-native-svg"), 1);
4424
4451
  var import_jsx_runtime26 = require("react/jsx-runtime");
@@ -4427,9 +4454,9 @@ function LayerTrigger({
4427
4454
  onPress,
4428
4455
  disabled = false
4429
4456
  }) {
4430
- if ((0, import_react36.isValidElement)(trigger)) {
4457
+ if ((0, import_react37.isValidElement)(trigger)) {
4431
4458
  const child = trigger;
4432
- return (0, import_react36.cloneElement)(child, {
4459
+ return (0, import_react37.cloneElement)(child, {
4433
4460
  disabled: disabled || child.props.disabled,
4434
4461
  onPress: () => {
4435
4462
  var _a, _b;
@@ -4464,14 +4491,14 @@ function FloatingPanel({
4464
4491
  }) {
4465
4492
  const m = useKjunMessages();
4466
4493
  ariaLabel != null ? ariaLabel : ariaLabel = m.select;
4467
- const [headerHeight, setHeaderHeight] = (0, import_react36.useState)(0);
4468
- const panelRef = (0, import_react36.useRef)(null);
4469
- const scroll = (0, import_react36.useRef)(null), viewport = (0, import_react36.useRef)(0);
4470
- const { colors } = useKjunStyles(), window2 = (0, import_react_native30.useWindowDimensions)(), [anchored, setAnchored] = (0, import_react36.useState)(false), [sized, setSized] = (0, import_react36.useState)(false), [anchor, setAnchor] = (0, import_react36.useState)({ x: 0, y: 0, width: 0, height: 0 }), [panel, setPanel] = (0, import_react36.useState)({ width: 0, height: 0 });
4471
- const measurement = (0, import_react36.useRef)(0);
4494
+ const [headerHeight, setHeaderHeight] = (0, import_react37.useState)(0);
4495
+ const panelRef = (0, import_react37.useRef)(null);
4496
+ const scroll = (0, import_react37.useRef)(null), viewport = (0, import_react37.useRef)(0);
4497
+ const { colors } = useKjunStyles(), window2 = (0, import_react_native30.useWindowDimensions)(), [anchored, setAnchored] = (0, import_react37.useState)(false), [sized, setSized] = (0, import_react37.useState)(false), [anchor, setAnchor] = (0, import_react37.useState)({ x: 0, y: 0, width: 0, height: 0 }), [panel, setPanel] = (0, import_react37.useState)({ width: 0, height: 0 });
4498
+ const measurement = (0, import_react37.useRef)(0);
4472
4499
  const motion = useNativePresence(open, tooltip ? import_tokens27.tokens.motion.tooltipEnter : import_tokens27.tokens.motion.popupEnter, tooltip ? import_tokens27.tokens.motion.tooltipExit : import_tokens27.tokens.motion.popupExit, anchored && sized);
4473
4500
  const layer = useLayer(open, motion.present, tooltip ? "tooltip" : "popup", () => onOpenChange(false), triggerRef);
4474
- (0, import_react36.useLayoutEffect)(() => {
4501
+ (0, import_react37.useLayoutEffect)(() => {
4475
4502
  var _a;
4476
4503
  const revision = ++measurement.current;
4477
4504
  if (open) setAnchored(false);
@@ -4484,20 +4511,20 @@ function FloatingPanel({
4484
4511
  measurement.current++;
4485
4512
  };
4486
4513
  }, [open, window2.width, window2.height, triggerRef]);
4487
- (0, import_react36.useLayoutEffect)(() => {
4514
+ (0, import_react37.useLayoutEffect)(() => {
4488
4515
  if (!motion.present) {
4489
4516
  setSized(false);
4490
4517
  setAnchored(false);
4491
4518
  }
4492
4519
  }, [motion.present]);
4493
- (0, import_react36.useEffect)(() => {
4520
+ (0, import_react37.useEffect)(() => {
4494
4521
  var _a;
4495
4522
  const row = reveal == null ? void 0 : reveal.current;
4496
4523
  if (!open || !anchored || !sized || !row || !viewport.current) return;
4497
4524
  const offset = row.y + row.height + (menu || field ? import_tokens27.tokens.extensions.menu.padding : 0) - viewport.current;
4498
4525
  if (offset > 0) (_a = scroll.current) == null ? void 0 : _a.scrollTo({ y: offset, animated: false });
4499
4526
  }, [open, anchored, sized, reveal, menu, field]);
4500
- (0, import_react36.useEffect)(() => {
4527
+ (0, import_react37.useEffect)(() => {
4501
4528
  if (!open || !anchored || !sized || !focusOnOpen || !panelRef.current) return;
4502
4529
  if (import_react_native30.Platform.OS === "web") {
4503
4530
  const node = panelRef.current;
@@ -4682,7 +4709,7 @@ function FloatingPanel({
4682
4709
  }
4683
4710
 
4684
4711
  // packages/native/src/popover.tsx
4685
- var import_react37 = require("react");
4712
+ var import_react38 = require("react");
4686
4713
  var import_react_native31 = require("react-native");
4687
4714
  var import_tokens28 = require("@kjun-ui/tokens");
4688
4715
  var import_jsx_runtime27 = require("react/jsx-runtime");
@@ -4703,7 +4730,7 @@ function KjunPopover({
4703
4730
  children
4704
4731
  }) {
4705
4732
  const { colors } = useKjunStyles();
4706
- const [internal, setInternal] = (0, import_react37.useState)(false), open = controlled != null ? controlled : internal, ref = (0, import_react37.useRef)(null);
4733
+ const [internal, setInternal] = (0, import_react38.useState)(false), open = controlled != null ? controlled : internal, ref = (0, import_react38.useRef)(null);
4707
4734
  const change = (v) => {
4708
4735
  setInternal(v);
4709
4736
  onOpenChange == null ? void 0 : onOpenChange(v);
@@ -4751,13 +4778,13 @@ function KjunTooltip({
4751
4778
  open: controlled,
4752
4779
  onOpenChange
4753
4780
  }) {
4754
- const { colors } = useKjunStyles(), [internal, setInternal] = (0, import_react37.useState)(false), open = controlled != null ? controlled : internal, latest = (0, import_react37.useRef)({ open, onOpenChange }), setOpen = (value) => {
4781
+ const { colors } = useKjunStyles(), [internal, setInternal] = (0, import_react38.useState)(false), open = controlled != null ? controlled : internal, latest = (0, import_react38.useRef)({ open, onOpenChange }), setOpen = (value) => {
4755
4782
  var _a, _b;
4756
4783
  if (latest.current.open === value) return;
4757
4784
  latest.current.open = value;
4758
4785
  setInternal(value);
4759
4786
  (_b = (_a = latest.current).onOpenChange) == null ? void 0 : _b.call(_a, value);
4760
- }, ref = (0, import_react37.useRef)(null), timer = (0, import_react37.useRef)(void 0);
4787
+ }, ref = (0, import_react38.useRef)(null), timer = (0, import_react38.useRef)(void 0);
4761
4788
  latest.current = { open, onOpenChange };
4762
4789
  const scopeActive = useActiveLayerScope();
4763
4790
  const hide = () => {
@@ -4769,11 +4796,11 @@ function KjunTooltip({
4769
4796
  clearTimeout(timer.current);
4770
4797
  timer.current = setTimeout(() => setOpen(true), delay);
4771
4798
  };
4772
- (0, import_react37.useEffect)(() => {
4799
+ (0, import_react38.useEffect)(() => {
4773
4800
  if (!scopeActive) hide();
4774
4801
  }, [scopeActive]);
4775
- (0, import_react37.useEffect)(() => () => clearTimeout(timer.current), []);
4776
- (0, import_react37.useEffect)(() => {
4802
+ (0, import_react38.useEffect)(() => () => clearTimeout(timer.current), []);
4803
+ (0, import_react38.useEffect)(() => {
4777
4804
  if (import_react_native31.Platform.OS !== "web" || !open) return;
4778
4805
  const escape = (event) => {
4779
4806
  if (event.key === "Escape") hide();
@@ -4781,7 +4808,7 @@ function KjunTooltip({
4781
4808
  document.addEventListener("keydown", escape);
4782
4809
  return () => document.removeEventListener("keydown", escape);
4783
4810
  }, [open]);
4784
- const child = (0, import_react37.isValidElement)(children) ? children : null;
4811
+ const child = (0, import_react38.isValidElement)(children) ? children : null;
4785
4812
  const childProps = child == null ? void 0 : child.props;
4786
4813
  const handlers = {
4787
4814
  // A hint that repeats the trigger's name would be read twice (icon-only RefreshButton, IconToggle).
@@ -4826,7 +4853,7 @@ function KjunTooltip({
4826
4853
  }
4827
4854
  };
4828
4855
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)(import_jsx_runtime27.Fragment, { children: [
4829
- /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_native31.View, { ref, collapsable: false, style: { alignSelf: (childProps == null ? void 0 : childProps.block) ? "stretch" : "flex-start" }, children: child ? (0, import_react37.cloneElement)(child, handlers) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AccessiblePressable, { ...handlers, children }) }),
4856
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(import_react_native31.View, { ref, collapsable: false, style: { alignSelf: (childProps == null ? void 0 : childProps.block) ? "stretch" : "flex-start" }, children: child ? (0, import_react38.cloneElement)(child, handlers) : /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(AccessiblePressable, { ...handlers, children }) }),
4830
4857
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
4831
4858
  FloatingPanel,
4832
4859
  {
@@ -4864,10 +4891,10 @@ function KjunTooltip({
4864
4891
 
4865
4892
  // packages/native/src/dropdown.tsx
4866
4893
  var import_jsx_runtime28 = require("react/jsx-runtime");
4867
- var DropdownContext = (0, import_react38.createContext)(null);
4868
- var MenuIconSlotContext = (0, import_react38.createContext)(false);
4894
+ var DropdownContext = (0, import_react39.createContext)(null);
4895
+ var MenuIconSlotContext = (0, import_react39.createContext)(false);
4869
4896
  function hasLeadingIcon(node) {
4870
- return import_react38.Children.toArray(node).some((child) => (0, import_react38.isValidElement)(child) && (child.type === import_react38.Fragment ? hasLeadingIcon(child.props.children) : child.type === KjunDropdownItem && !!child.props.icon));
4897
+ return import_react39.Children.toArray(node).some((child) => (0, import_react39.isValidElement)(child) && (child.type === import_react39.Fragment ? hasLeadingIcon(child.props.children) : child.type === KjunDropdownItem && !!child.props.icon));
4871
4898
  }
4872
4899
  function KjunDropdown({
4873
4900
  disabled = false,
@@ -4878,11 +4905,11 @@ function KjunDropdown({
4878
4905
  onClose
4879
4906
  }) {
4880
4907
  const m = useKjunMessages();
4881
- const [open, setOpen] = (0, import_react38.useState)(false), currentOpen = (0, import_react38.useRef)(false), ref = (0, import_react38.useRef)(null);
4908
+ const [open, setOpen] = (0, import_react39.useState)(false), currentOpen = (0, import_react39.useRef)(false), ref = (0, import_react39.useRef)(null);
4882
4909
  let control = trigger;
4883
- while ((0, import_react38.isValidElement)(control) && control.type === KjunTooltip)
4910
+ while ((0, import_react39.isValidElement)(control) && control.type === KjunTooltip)
4884
4911
  control = control.props.children;
4885
- const unavailable = disabled || (0, import_react38.isValidElement)(control) && !!(control.props.disabled || control.props.loading);
4912
+ const unavailable = disabled || (0, import_react39.isValidElement)(control) && !!(control.props.disabled || control.props.loading);
4886
4913
  const change = (v) => {
4887
4914
  if (v === currentOpen.current || v && unavailable) return;
4888
4915
  currentOpen.current = v;
@@ -4890,7 +4917,7 @@ function KjunDropdown({
4890
4917
  if (v) onOpen == null ? void 0 : onOpen();
4891
4918
  else onClose == null ? void 0 : onClose();
4892
4919
  };
4893
- (0, import_react38.useEffect)(() => {
4920
+ (0, import_react39.useEffect)(() => {
4894
4921
  if (unavailable) change(false);
4895
4922
  }, [unavailable]);
4896
4923
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(DropdownContext.Provider, { value: () => change(false), children: [
@@ -4924,8 +4951,8 @@ function KjunDropdownItem({
4924
4951
  children,
4925
4952
  onPress
4926
4953
  }) {
4927
- const { colors } = useKjunStyles(), close = (0, import_react38.useContext)(DropdownContext), color = variant === "danger" ? colors.danger : colors.text, iconColor = variant === "danger" ? colors.danger : colors.textSecondary, reserveIcon = (0, import_react38.useContext)(MenuIconSlotContext);
4928
- const [hovered, setHovered] = (0, import_react38.useState)(false);
4954
+ const { colors } = useKjunStyles(), close = (0, import_react39.useContext)(DropdownContext), color = variant === "danger" ? colors.danger : colors.text, iconColor = variant === "danger" ? colors.danger : colors.textSecondary, reserveIcon = (0, import_react39.useContext)(MenuIconSlotContext);
4955
+ const [hovered, setHovered] = (0, import_react39.useState)(false);
4929
4956
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
4930
4957
  AccessiblePressable,
4931
4958
  {
@@ -4986,7 +5013,7 @@ function KjunMenuButton({
4986
5013
  ...props
4987
5014
  }) {
4988
5015
  const m = useKjunMessages();
4989
- const [open, setOpen] = (0, import_react38.useState)(false);
5016
+ const [open, setOpen] = (0, import_react39.useState)(false);
4990
5017
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
4991
5018
  KjunDropdown,
4992
5019
  {
@@ -5026,7 +5053,7 @@ function KjunMenuButton({
5026
5053
  }
5027
5054
 
5028
5055
  // shared/package-runtime/combobox.ts
5029
- var import_react39 = require("react");
5056
+ var import_react40 = require("react");
5030
5057
 
5031
5058
  // shared/package-runtime/options.ts
5032
5059
  var optionValue = (option, key = "value") => typeof option === "object" ? option[key] : option;
@@ -5104,10 +5131,10 @@ function useComboboxModel({
5104
5131
  }) {
5105
5132
  const selected = options.find((option) => optionValue(option, valueKey) === value);
5106
5133
  const selectedLabel = selected !== void 0 ? optionLabel(selected, labelKey) : "";
5107
- const [query, setQuery] = (0, import_react39.useState)(selectedLabel);
5108
- const [open, setOpen] = (0, import_react39.useState)(false);
5109
- (0, import_react39.useEffect)(() => setQuery(selectedLabel), [value, selectedLabel]);
5110
- (0, import_react39.useEffect)(() => {
5134
+ const [query, setQuery] = (0, import_react40.useState)(selectedLabel);
5135
+ const [open, setOpen] = (0, import_react40.useState)(false);
5136
+ (0, import_react40.useEffect)(() => setQuery(selectedLabel), [value, selectedLabel]);
5137
+ (0, import_react40.useEffect)(() => {
5111
5138
  if (disabled) setOpen(false);
5112
5139
  }, [disabled]);
5113
5140
  const change = (next) => {
@@ -5141,7 +5168,7 @@ function useComboboxModel({
5141
5168
 
5142
5169
  // packages/native/src/combobox.tsx
5143
5170
  var import_tokens31 = require("@kjun-ui/tokens");
5144
- var import_react40 = require("react");
5171
+ var import_react41 = require("react");
5145
5172
  var import_react_native34 = require("react-native");
5146
5173
 
5147
5174
  // packages/native/src/select-options.tsx
@@ -5270,9 +5297,9 @@ function SearchField({
5270
5297
  onEnter
5271
5298
  }) {
5272
5299
  const m = useKjunMessages();
5273
- const searchId = "kjun-popup-search-" + (0, import_react40.useId)().replace(/:/g, "");
5274
- const clearing = (0, import_react40.useRef)(false);
5275
- const ref = (0, import_react40.useRef)(null), { colors } = useKjunStyles();
5300
+ const searchId = "kjun-popup-search-" + (0, import_react41.useId)().replace(/:/g, "");
5301
+ const clearing = (0, import_react41.useRef)(false);
5302
+ const ref = (0, import_react41.useRef)(null), { colors } = useKjunStyles();
5276
5303
  const focusGuard = usePopupFocusGuard(ref);
5277
5304
  const openFromPress = () => {
5278
5305
  if (!disabled) {
@@ -5372,7 +5399,7 @@ function SearchField({
5372
5399
 
5373
5400
  // packages/native/src/date-picker.tsx
5374
5401
  var import_tokens32 = require("@kjun-ui/tokens");
5375
- var import_react41 = require("react");
5402
+ var import_react42 = require("react");
5376
5403
  var import_react_native35 = require("react-native");
5377
5404
  var import_jsx_runtime31 = require("react/jsx-runtime");
5378
5405
  function displayMonth(value) {
@@ -5395,7 +5422,7 @@ function KjunDatePicker({
5395
5422
  const scope = useKjunMessageScope();
5396
5423
  placeholder != null ? placeholder : placeholder = scope.messages.datePlaceholder;
5397
5424
  const clear = clearable && !!value && !disabled;
5398
- const { colors } = useKjunStyles(), field = useKjunField(), [open, setOpen] = (0, import_react41.useState)(false), [month, setMonth] = (0, import_react41.useState)(() => displayMonth(value)), ref = (0, import_react41.useRef)(null), spec = import_tokens32.tokens.input[size];
5425
+ const { colors } = useKjunStyles(), field = useKjunField(), [open, setOpen] = (0, import_react42.useState)(false), [month, setMonth] = (0, import_react42.useState)(() => displayMonth(value)), ref = (0, import_react42.useRef)(null), spec = import_tokens32.tokens.input[size];
5399
5426
  const surface = useFieldSurface(size, { disabled, invalid: error || !!(field == null ? void 0 : field.error), open });
5400
5427
  const year = month.getFullYear(), m = month.getMonth(), first = new Date(year, m, 1).getDay(), count = new Date(year, m + 1, 0).getDate();
5401
5428
  const date = (day) => `${year}-${String(m + 1).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
@@ -5570,10 +5597,10 @@ function KjunDatePicker({
5570
5597
  }
5571
5598
 
5572
5599
  // packages/native/src/search-input.tsx
5573
- var import_react43 = require("react");
5600
+ var import_react44 = require("react");
5574
5601
 
5575
5602
  // shared/package-runtime/search-input.ts
5576
- var import_react42 = require("react");
5603
+ var import_react43 = require("react");
5577
5604
  function useSearchInputModel({
5578
5605
  value,
5579
5606
  disabled = false,
@@ -5583,20 +5610,20 @@ function useSearchInputModel({
5583
5610
  onValueChange,
5584
5611
  onSearchError
5585
5612
  }, open) {
5586
- const [query, setQuery] = (0, import_react42.useState)(value), [options, setOptions] = (0, import_react42.useState)([]), [loading, setLoading] = (0, import_react42.useState)(false), [failed, setFailed] = (0, import_react42.useState)(false), version = (0, import_react42.useRef)(0), notify = (0, import_react42.useRef)(onSearchError);
5613
+ const [query, setQuery] = (0, import_react43.useState)(value), [options, setOptions] = (0, import_react43.useState)([]), [loading, setLoading] = (0, import_react43.useState)(false), [failed, setFailed] = (0, import_react43.useState)(false), version = (0, import_react43.useRef)(0), notify = (0, import_react43.useRef)(onSearchError);
5587
5614
  notify.current = onSearchError;
5588
- const timer = (0, import_react42.useRef)(void 0);
5589
- const notifyValue = (0, import_react42.useRef)(onValueChange);
5615
+ const timer = (0, import_react43.useRef)(void 0);
5616
+ const notifyValue = (0, import_react43.useRef)(onValueChange);
5590
5617
  notifyValue.current = onValueChange;
5591
- (0, import_react42.useLayoutEffect)(() => {
5618
+ (0, import_react43.useLayoutEffect)(() => {
5592
5619
  clearTimeout(timer.current);
5593
5620
  setQuery(value);
5594
5621
  }, [value]);
5595
- (0, import_react42.useLayoutEffect)(() => {
5622
+ (0, import_react43.useLayoutEffect)(() => {
5596
5623
  clearTimeout(timer.current);
5597
5624
  return () => clearTimeout(timer.current);
5598
5625
  }, [disabled, debounce, !!loadOptions]);
5599
- (0, import_react42.useEffect)(() => {
5626
+ (0, import_react43.useEffect)(() => {
5600
5627
  const current = ++version.current, abort = new AbortController();
5601
5628
  setFailed(false);
5602
5629
  if (!loadOptions || !open || disabled || query.length < minChars) {
@@ -5687,7 +5714,7 @@ function KjunSearchInput({
5687
5714
  placeholder != null ? placeholder : placeholder = m.search;
5688
5715
  emptyText != null ? emptyText : emptyText = m.noResults;
5689
5716
  errorText != null ? errorText : errorText = m.searchFailed;
5690
- const [open, setOpen] = (0, import_react43.useState)(false);
5717
+ const [open, setOpen] = (0, import_react44.useState)(false);
5691
5718
  const model = useSearchInputModel({ value, disabled, debounce, loadOptions, minChars, onValueChange, onSearchError }, open);
5692
5719
  const { query, options, loading, failed } = model;
5693
5720
  const update = (value2) => {
@@ -5749,30 +5776,30 @@ function KjunSearchInput({
5749
5776
 
5750
5777
  // packages/native/src/select-control.tsx
5751
5778
  var import_tokens34 = require("@kjun-ui/tokens");
5752
- var import_react46 = require("react");
5779
+ var import_react47 = require("react");
5753
5780
 
5754
5781
  // packages/native/src/compound-control.tsx
5755
- var import_react44 = require("react");
5782
+ var import_react45 = require("react");
5756
5783
  var import_react_native36 = require("react-native");
5757
5784
  var import_tokens33 = require("@kjun-ui/tokens");
5758
5785
  var import_jsx_runtime33 = require("react/jsx-runtime");
5759
- var CompoundControlContext = (0, import_react44.createContext)(null);
5786
+ var CompoundControlContext = (0, import_react45.createContext)(null);
5760
5787
  function CompoundTarget({ children, square = false }) {
5761
5788
  const touch = finePointer() ? void 0 : import_tokens33.tokens.native.minimumTouchTarget;
5762
5789
  return /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(import_react_native36.View, { style: { minHeight: touch, minWidth: square ? touch : void 0, alignItems: "center", justifyContent: "center" }, children });
5763
5790
  }
5764
5791
 
5765
5792
  // shared/package-runtime/select.ts
5766
- var import_react45 = require("react");
5793
+ var import_react46 = require("react");
5767
5794
  function useSelectState(controlled, disabled, pageSize, onOpenChange) {
5768
- const [internal, setInternal] = (0, import_react45.useState)(false);
5769
- const [query, setQuery] = (0, import_react45.useState)("");
5770
- const [limit, setLimit] = (0, import_react45.useState)(pageSize);
5771
- const [session, setSession] = (0, import_react45.useState)(0);
5795
+ const [internal, setInternal] = (0, import_react46.useState)(false);
5796
+ const [query, setQuery] = (0, import_react46.useState)("");
5797
+ const [limit, setLimit] = (0, import_react46.useState)(pageSize);
5798
+ const [session, setSession] = (0, import_react46.useState)(0);
5772
5799
  const isControlled = typeof controlled === "boolean";
5773
5800
  const open = !disabled && (isControlled ? controlled : internal);
5774
- const previousOpen = (0, import_react45.useRef)(open);
5775
- (0, import_react45.useEffect)(() => {
5801
+ const previousOpen = (0, import_react46.useRef)(open);
5802
+ (0, import_react46.useEffect)(() => {
5776
5803
  if (disabled && !isControlled) setInternal(false);
5777
5804
  if (previousOpen.current && !open) {
5778
5805
  setQuery("");
@@ -5781,7 +5808,7 @@ function useSelectState(controlled, disabled, pageSize, onOpenChange) {
5781
5808
  }
5782
5809
  previousOpen.current = open;
5783
5810
  }, [open, disabled, isControlled, pageSize]);
5784
- (0, import_react45.useEffect)(() => {
5811
+ (0, import_react46.useEffect)(() => {
5785
5812
  setLimit(pageSize);
5786
5813
  }, [pageSize]);
5787
5814
  const changeOpen = (next) => {
@@ -5831,14 +5858,14 @@ function KjunSelect({
5831
5858
  placeholder != null ? placeholder : placeholder = m.select;
5832
5859
  searchPlaceholder != null ? searchPlaceholder : searchPlaceholder = m.search;
5833
5860
  const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
5834
- const { colors } = useKjunStyles(), field = useKjunField(), ref = (0, import_react46.useRef)(null), spec = import_tokens34.tokens.input[size];
5835
- const trigger = (0, import_react46.useRef)(null);
5836
- const compound = (0, import_react46.useContext)(CompoundControlContext);
5837
- (0, import_react46.useEffect)(() => {
5861
+ const { colors } = useKjunStyles(), field = useKjunField(), ref = (0, import_react47.useRef)(null), spec = import_tokens34.tokens.input[size];
5862
+ const trigger = (0, import_react47.useRef)(null);
5863
+ const compound = (0, import_react47.useContext)(CompoundControlContext);
5864
+ (0, import_react47.useEffect)(() => {
5838
5865
  if (compound == null ? void 0 : compound.focusRef) compound.focusRef.current = trigger.current;
5839
5866
  }, [compound == null ? void 0 : compound.focusRef]);
5840
5867
  const expanded = usePopupExpanded(open, ref);
5841
- const selectedRow = (0, import_react46.useRef)(null);
5868
+ const selectedRow = (0, import_react47.useRef)(null);
5842
5869
  const surface = useFieldSurface(size, { disabled, invalid: error || !!(field == null ? void 0 : field.error), open: expanded });
5843
5870
  const change = (v) => {
5844
5871
  onValueChange == null ? void 0 : onValueChange(v);
@@ -6036,16 +6063,17 @@ var import_tokens37 = require("@kjun-ui/tokens");
6036
6063
 
6037
6064
  // packages/native/src/collapse.tsx
6038
6065
  var import_tokens35 = require("@kjun-ui/tokens");
6039
- var import_react47 = require("react");
6066
+ var import_react48 = require("react");
6040
6067
  var import_react_native38 = require("react-native");
6041
6068
  var import_jsx_runtime35 = require("react/jsx-runtime");
6042
- function Collapse({ open, children }) {
6069
+ function Collapse({ open, keepMounted = false, children }) {
6043
6070
  const reduced = useReducedMotion();
6044
- const [retained, setRetained] = (0, import_react47.useState)(open), [height, setHeight] = (0, import_react47.useState)(null);
6045
- const value = (0, import_react47.useRef)(new import_react_native38.Animated.Value(0)).current;
6046
- const [settled, setSettled] = (0, import_react47.useState)(open);
6047
- const version = (0, import_react47.useRef)(0), first = (0, import_react47.useRef)(open);
6048
- (0, import_react47.useLayoutEffect)(() => {
6071
+ const [retained, setRetained] = (0, import_react48.useState)(open), [height, setHeight] = (0, import_react48.useState)(null);
6072
+ const value = (0, import_react48.useRef)(new import_react_native38.Animated.Value(0)).current;
6073
+ const [settled, setSettled] = (0, import_react48.useState)(open);
6074
+ const version = (0, import_react48.useRef)(0), first = (0, import_react48.useRef)(open), opened = (0, import_react48.useRef)(open);
6075
+ if (open) opened.current = true;
6076
+ (0, import_react48.useLayoutEffect)(() => {
6049
6077
  const revision = ++version.current;
6050
6078
  if (open) setRetained(true);
6051
6079
  if (height === null) return;
@@ -6072,13 +6100,13 @@ function Collapse({ open, children }) {
6072
6100
  value.stopAnimation();
6073
6101
  };
6074
6102
  }, [open, height, reduced, value]);
6075
- return open || retained ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6103
+ return open || retained || keepMounted && opened.current ? /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
6076
6104
  import_react_native38.Animated.View,
6077
6105
  {
6078
6106
  pointerEvents: open ? "auto" : "none",
6079
6107
  accessibilityElementsHidden: !open,
6080
6108
  importantForAccessibility: open ? "auto" : "no-hide-descendants",
6081
- ...!open ? { inert: true } : {},
6109
+ ...!open ? { inert: true, "aria-hidden": true } : {},
6082
6110
  style: { height: settled && open ? void 0 : value, overflow: "hidden" },
6083
6111
  children: /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(import_react_native38.View, { onLayout: (event) => setHeight(event.nativeEvent.layout.height), children })
6084
6112
  }
@@ -6086,10 +6114,10 @@ function Collapse({ open, children }) {
6086
6114
  }
6087
6115
 
6088
6116
  // shared/package-runtime/navigation.ts
6089
- var import_react48 = require("react");
6117
+ var import_react49 = require("react");
6090
6118
  function useInitialTab(value, candidate, change) {
6091
- const requested = (0, import_react48.useRef)(/* @__PURE__ */ new Set());
6092
- (0, import_react48.useEffect)(() => {
6119
+ const requested = (0, import_react49.useRef)(/* @__PURE__ */ new Set());
6120
+ (0, import_react49.useEffect)(() => {
6093
6121
  if (value !== "") {
6094
6122
  requested.current.clear();
6095
6123
  return;
@@ -6100,8 +6128,8 @@ function useInitialTab(value, candidate, change) {
6100
6128
  }, [value, candidate, change]);
6101
6129
  }
6102
6130
  function useAccordionState(multiple) {
6103
- const [opened, setOpened] = (0, import_react48.useState)(/* @__PURE__ */ new Set());
6104
- (0, import_react48.useEffect)(() => {
6131
+ const [opened, setOpened] = (0, import_react49.useState)(/* @__PURE__ */ new Set());
6132
+ (0, import_react49.useEffect)(() => {
6105
6133
  if (!multiple) setOpened((previous) => previous.size > 1 ? new Set([...previous].slice(-1)) : previous);
6106
6134
  }, [multiple]);
6107
6135
  return {
@@ -6125,12 +6153,12 @@ function useAccordionState(multiple) {
6125
6153
  }
6126
6154
 
6127
6155
  // packages/native/src/navigation.tsx
6128
- var import_react50 = require("react");
6156
+ var import_react51 = require("react");
6129
6157
  var import_react_native40 = require("react-native");
6130
6158
 
6131
6159
  // packages/native/src/tabs.tsx
6132
6160
  var import_tokens36 = require("@kjun-ui/tokens");
6133
- var import_react49 = require("react");
6161
+ var import_react50 = require("react");
6134
6162
  var import_react_native39 = require("react-native");
6135
6163
 
6136
6164
  // packages/native/src/tabs-accessibility.ts
@@ -6141,7 +6169,7 @@ function usePanelFocus(_root) {
6141
6169
 
6142
6170
  // packages/native/src/tabs.tsx
6143
6171
  var import_jsx_runtime36 = require("react/jsx-runtime");
6144
- var TabContext = (0, import_react49.createContext)({ value: "", id: "", names: [] });
6172
+ var TabContext = (0, import_react50.createContext)({ value: "", id: "", names: [] });
6145
6173
  function KjunTabs({
6146
6174
  value,
6147
6175
  items: items2 = [],
@@ -6157,21 +6185,21 @@ function KjunTabs({
6157
6185
  var _a, _b;
6158
6186
  const m = useKjunMessages();
6159
6187
  ariaLabel != null ? ariaLabel : ariaLabel = m.tabs;
6160
- const { colors } = useKjunStyles(), panes = import_react49.Children.toArray(children).filter(
6161
- import_react49.isValidElement
6188
+ const { colors } = useKjunStyles(), panes = import_react50.Children.toArray(children).filter(
6189
+ import_react50.isValidElement
6162
6190
  );
6163
6191
  const tabs = items2.length ? items2 : panes.filter((child) => child.type === KjunTabPane).map((child) => child.props);
6164
- const id = "kjun-" + (0, import_react49.useId)(), root = (0, import_react49.useRef)(null);
6165
- const menuState = (0, import_react49.useRef)({ tabs, onTabMenu });
6192
+ const id = "kjun-" + (0, import_react50.useId)(), root = (0, import_react50.useRef)(null);
6193
+ const menuState = (0, import_react50.useRef)({ tabs, onTabMenu });
6166
6194
  menuState.current = { tabs, onTabMenu };
6167
- const pressedMenu = (0, import_react49.useRef)(null);
6168
- (0, import_react49.useLayoutEffect)(() => {
6195
+ const pressedMenu = (0, import_react50.useRef)(null);
6196
+ (0, import_react50.useLayoutEffect)(() => {
6169
6197
  if (!onTabMenu || !tabs.some((tab) => tab.name === pressedMenu.current && !tab.disabled)) pressedMenu.current = null;
6170
6198
  }, [tabs, onTabMenu]);
6171
6199
  const panelNames = panes.filter((child) => child.type === KjunTabPane).map((child) => child.props.name);
6172
6200
  const geometry2 = import_tokens36.tokens.extensions.tabs;
6173
6201
  const underline = variant === "underline";
6174
- const [hoveredTab, setHoveredTab] = (0, import_react49.useState)(null);
6202
+ const [hoveredTab, setHoveredTab] = (0, import_react50.useState)(null);
6175
6203
  const singleLine = import_react_native39.Platform.OS === "web" ? { whiteSpace: "nowrap" } : {};
6176
6204
  const paddingX = !underline ? geometry2.pillsPaddingX : density === "compact" ? geometry2.compactPaddingX : geometry2.paddingX;
6177
6205
  const height = density === "compact" ? geometry2.compactHeight : geometry2.height;
@@ -6180,10 +6208,10 @@ function KjunTabs({
6180
6208
  const roomX = underline ? ringRoom : 0, roomY = Math.max(underline ? ringRoom : 0, slop);
6181
6209
  const selectedTab = tabs.find((tab) => tab.name === value);
6182
6210
  const selection = useButtonGroupMotion(selectedTab ? { ...selectedTab, value: selectedTab.name } : void 0);
6183
- const tabRefs = (0, import_react49.useRef)(/* @__PURE__ */ new Map());
6211
+ const tabRefs = (0, import_react50.useRef)(/* @__PURE__ */ new Map());
6184
6212
  const { updateLayout } = selection;
6185
6213
  const firstName = (_a = tabs[0]) == null ? void 0 : _a.name;
6186
- const measureIndicator = (0, import_react49.useCallback)((name, box) => {
6214
+ const measureIndicator = (0, import_react50.useCallback)((name, box) => {
6187
6215
  const left = underline && name === firstName ? 0 : paddingX;
6188
6216
  updateLayout(name, underline ? {
6189
6217
  x: box.x + left,
@@ -6192,7 +6220,7 @@ function KjunTabs({
6192
6220
  height: geometry2.indicatorHeight
6193
6221
  } : box);
6194
6222
  }, [underline, paddingX, firstName, updateLayout, geometry2]);
6195
- (0, import_react49.useLayoutEffect)(() => {
6223
+ (0, import_react50.useLayoutEffect)(() => {
6196
6224
  for (const [name, node] of tabRefs.current) {
6197
6225
  node.measure((x, y, width, height2) => measureIndicator(name, { x, y, width, height: height2 }));
6198
6226
  }
@@ -6351,8 +6379,8 @@ function KjunTabs({
6351
6379
  ] }) });
6352
6380
  }
6353
6381
  function KjunTabPane({ name, children }) {
6354
- const { value, id, names } = (0, import_react49.useContext)(TabContext);
6355
- const root = (0, import_react49.useRef)(null);
6382
+ const { value, id, names } = (0, import_react50.useContext)(TabContext);
6383
+ const root = (0, import_react50.useRef)(null);
6356
6384
  usePanelFocus(root);
6357
6385
  const hidden = value !== name;
6358
6386
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
@@ -6375,7 +6403,7 @@ function KjunTabPane({ name, children }) {
6375
6403
 
6376
6404
  // packages/native/src/navigation.tsx
6377
6405
  var import_jsx_runtime37 = require("react/jsx-runtime");
6378
- var AccordionContext = (0, import_react50.createContext)(null);
6406
+ var AccordionContext = (0, import_react51.createContext)(null);
6379
6407
  function KjunAccordion({
6380
6408
  multiple = false,
6381
6409
  tone = "card",
@@ -6405,14 +6433,32 @@ function KjunAccordionItem({
6405
6433
  defaultOpen = false,
6406
6434
  disabled = false,
6407
6435
  header,
6436
+ open: openProp,
6437
+ onOpenChange,
6438
+ keepMounted = false,
6408
6439
  children
6409
6440
  }) {
6410
- const { colors } = useKjunStyles(), group = (0, import_react50.useContext)(AccordionContext), id = "kjun-" + (0, import_react50.useId)(), [own, setOwn] = (0, import_react50.useState)(defaultOpen), open = group ? group.opened.has(id) : own;
6441
+ const controlled = openProp !== void 0, context = (0, import_react51.useContext)(AccordionContext), { colors } = useKjunStyles(), group = controlled ? null : context, id = "kjun-" + (0, import_react51.useId)(), [own, setOwn] = (0, import_react51.useState)(defaultOpen), open = controlled ? openProp : group ? group.opened.has(id) : own;
6442
+ const reported = (0, import_react51.useRef)(open), notify = (0, import_react51.useRef)(onOpenChange), registering = (0, import_react51.useRef)(!!group && defaultOpen);
6443
+ notify.current = onOpenChange;
6444
+ (0, import_react51.useEffect)(() => {
6445
+ var _a;
6446
+ if (registering.current) {
6447
+ if (open) {
6448
+ registering.current = false;
6449
+ reported.current = open;
6450
+ }
6451
+ return;
6452
+ }
6453
+ if (controlled || reported.current === open) return;
6454
+ reported.current = open;
6455
+ (_a = notify.current) == null ? void 0 : _a.call(notify, open);
6456
+ }, [open, controlled]);
6411
6457
  const rotation = useMotionValue(open ? 1 : 0, import_tokens37.tokens.motion.collapse, void 0, void 0, true);
6412
6458
  const geometry2 = import_tokens37.tokens.extensions.accordion;
6413
- const [hovered, setHovered] = (0, import_react50.useState)(false);
6459
+ const [hovered, setHovered] = (0, import_react51.useState)(false);
6414
6460
  const wrapping = import_react_native40.Platform.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
6415
- (0, import_react50.useEffect)(() => {
6461
+ (0, import_react51.useEffect)(() => {
6416
6462
  return group == null ? void 0 : group.register(id, defaultOpen);
6417
6463
  }, []);
6418
6464
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react_native40.View, { children: [
@@ -6426,7 +6472,10 @@ function KjunAccordionItem({
6426
6472
  accessibilityLabel: title,
6427
6473
  accessibilityState: { expanded: open, disabled },
6428
6474
  disabled,
6429
- onPress: () => group ? group.toggle(id) : setOwn(!own),
6475
+ onPress: () => {
6476
+ registering.current = false;
6477
+ controlled ? onOpenChange == null ? void 0 : onOpenChange(!open) : group ? group.toggle(id) : setOwn(!own);
6478
+ },
6430
6479
  onHoverIn: () => setHovered(true),
6431
6480
  onHoverOut: () => setHovered(false),
6432
6481
  style: ({ pressed }) => ({
@@ -6446,7 +6495,7 @@ function KjunAccordionItem({
6446
6495
  ]
6447
6496
  }
6448
6497
  ),
6449
- /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Collapse, { open, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
6498
+ /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Collapse, { open, keepMounted, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
6450
6499
  import_react_native40.View,
6451
6500
  {
6452
6501
  nativeID: id + "-panel",
@@ -6489,7 +6538,7 @@ function KjunBreadcrumb({
6489
6538
  }
6490
6539
  )
6491
6540
  ] });
6492
- return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react50.Fragment, { children: [
6541
+ return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react51.Fragment, { children: [
6493
6542
  i > 0 && /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
6494
6543
  KjunIcon,
6495
6544
  {
@@ -6643,7 +6692,7 @@ function KjunPagination({
6643
6692
 
6644
6693
  // packages/native/src/actions.tsx
6645
6694
  var import_tokens38 = require("@kjun-ui/tokens");
6646
- var import_react51 = require("react");
6695
+ var import_react52 = require("react");
6647
6696
  var import_react_native41 = require("react-native");
6648
6697
  var import_jsx_runtime38 = require("react/jsx-runtime");
6649
6698
  function KjunIconToggle({
@@ -6662,7 +6711,7 @@ function KjunIconToggle({
6662
6711
  onToggle
6663
6712
  }) {
6664
6713
  const { colors } = useKjunStyles();
6665
- const navigation = (0, import_react51.useContext)(TopNavigationContext);
6714
+ const navigation = (0, import_react52.useContext)(TopNavigationContext);
6666
6715
  const box = navigation ? navigation.controlSize : size === "xs" ? import_tokens38.tokens.extensions.iconToggle.compactSize : import_tokens38.tokens.extensions.iconToggle.sizes[size];
6667
6716
  return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(KjunTooltip, { content: disabled || loading ? "" : tooltip != null ? tooltip : ariaLabel, placement: tooltipPlacement, delay: tooltipDelay, children: /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
6668
6717
  AccessiblePressable,
@@ -6728,8 +6777,8 @@ function KjunCopyButton({
6728
6777
  }) {
6729
6778
  const m = useKjunMessages();
6730
6779
  successText != null ? successText : successText = m.copied;
6731
- const feedback = useOptionalKjunFeedback(), { colors } = useKjunStyles(), [copied, setCopied] = (0, import_react51.useState)(false), [failed, setFailed] = (0, import_react51.useState)(false), busy = (0, import_react51.useRef)(false), timer = (0, import_react51.useRef)(void 0), mounted = (0, import_react51.useRef)(true);
6732
- (0, import_react51.useEffect)(() => {
6780
+ const feedback = useOptionalKjunFeedback(), { colors } = useKjunStyles(), [copied, setCopied] = (0, import_react52.useState)(false), [failed, setFailed] = (0, import_react52.useState)(false), busy = (0, import_react52.useRef)(false), timer = (0, import_react52.useRef)(void 0), mounted = (0, import_react52.useRef)(true);
6781
+ (0, import_react52.useEffect)(() => {
6733
6782
  mounted.current = true;
6734
6783
  return () => {
6735
6784
  mounted.current = false;
@@ -6884,14 +6933,14 @@ function KjunScrollFade({ children }) {
6884
6933
 
6885
6934
  // packages/native/src/data-state.tsx
6886
6935
  var import_tokens39 = require("@kjun-ui/tokens");
6887
- var import_react53 = require("react");
6936
+ var import_react54 = require("react");
6888
6937
  var import_react_native42 = require("react-native");
6889
6938
 
6890
6939
  // shared/package-runtime/use-loading-reveal.ts
6891
- var import_react52 = require("react");
6940
+ var import_react53 = require("react");
6892
6941
  function useLoadingReveal(active, delay = 0) {
6893
- const [revealed, setRevealed] = (0, import_react52.useState)(false);
6894
- (0, import_react52.useEffect)(() => {
6942
+ const [revealed, setRevealed] = (0, import_react53.useState)(false);
6943
+ (0, import_react53.useEffect)(() => {
6895
6944
  setRevealed(false);
6896
6945
  if (!active || delay <= 0) return;
6897
6946
  const timer = setTimeout(() => setRevealed(true), delay);
@@ -6904,7 +6953,7 @@ function useLoadingReveal(active, delay = 0) {
6904
6953
  var import_jsx_runtime39 = require("react/jsx-runtime");
6905
6954
  function useQueryDisplay(props) {
6906
6955
  var _a;
6907
- const [state, setState] = (0, import_react53.useState)(() => (0, import_tokens39.initialQueryDisplay)(props));
6956
+ const [state, setState] = (0, import_react54.useState)(() => (0, import_tokens39.initialQueryDisplay)(props));
6908
6957
  let next = state;
6909
6958
  if (state.queryKey !== ((_a = props.queryKey) != null ? _a : null) || state.resultKey !== props.resultKey || state.loading !== !!props.loading) {
6910
6959
  next = (0, import_tokens39.advanceQueryDisplay)(state, props);
@@ -7013,7 +7062,7 @@ function BoundaryDescription() {
7013
7062
  const { colors } = useKjunStyles();
7014
7063
  return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(KText, { style: { ...typeStyle({ ...import_tokens39.tokens.typography.caption, fontSizePx: import_tokens39.tokens.extensions.state.descriptionSize }), color: colors.textSecondary, textAlign: "center" }, children: m.retryHint });
7015
7064
  }
7016
- var KjunErrorBoundary = class extends import_react53.Component {
7065
+ var KjunErrorBoundary = class extends import_react54.Component {
7017
7066
  constructor() {
7018
7067
  super(...arguments);
7019
7068
  this.state = { error: false };
@@ -7061,7 +7110,7 @@ KjunErrorBoundary.contextType = KjunMessageContext;
7061
7110
 
7062
7111
  // packages/native/src/skeletons.tsx
7063
7112
  var import_tokens43 = require("@kjun-ui/tokens");
7064
- var import_react55 = require("react");
7113
+ var import_react56 = require("react");
7065
7114
  var import_react_native44 = require("react-native");
7066
7115
  var import_react_native_svg5 = __toESM(require("react-native-svg"), 1);
7067
7116
 
@@ -7108,9 +7157,9 @@ function nativeMarketLayout(columns, showActions, containerWidth) {
7108
7157
 
7109
7158
  // packages/native/src/market-layout.ts
7110
7159
  var import_tokens41 = require("@kjun-ui/tokens");
7111
- var import_react54 = require("react");
7160
+ var import_react55 = require("react");
7112
7161
  function useMarketLayout(columns, showActions) {
7113
- const [containerWidth, setContainerWidth] = (0, import_react54.useState)(0);
7162
+ const [containerWidth, setContainerWidth] = (0, import_react55.useState)(0);
7114
7163
  const onLayout = (event) => setContainerWidth(event.nativeEvent.layout.width);
7115
7164
  return { ...nativeMarketLayout(columns, showActions, containerWidth), onLayout };
7116
7165
  }
@@ -7252,8 +7301,8 @@ function KjunChartSkeleton({
7252
7301
  }) {
7253
7302
  const m = useKjunMessages();
7254
7303
  loadingText != null ? loadingText : loadingText = m.chartLoading;
7255
- const kind = chartSkeletonKind(requestedKind), { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react55.useRef)(new import_react_native44.Animated.Value(1)).current, revealed = useLoadingReveal(true, loadingDelay), [measured, setMeasured] = (0, import_react55.useState)(0), thickness = import_tokens43.tokens.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" };
7256
- (0, import_react55.useEffect)(() => {
7304
+ const kind = chartSkeletonKind(requestedKind), { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react56.useRef)(new import_react_native44.Animated.Value(1)).current, revealed = useLoadingReveal(true, loadingDelay), [measured, setMeasured] = (0, import_react56.useState)(0), thickness = import_tokens43.tokens.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" };
7305
+ (0, import_react56.useEffect)(() => {
7257
7306
  if (reduced || !skeleton) return;
7258
7307
  const loop = import_react_native44.Animated.loop(
7259
7308
  import_react_native44.Animated.sequence([
@@ -7334,7 +7383,7 @@ function KjunChartSkeleton({
7334
7383
 
7335
7384
  // packages/native/src/financial-display.tsx
7336
7385
  var import_tokens46 = require("@kjun-ui/tokens");
7337
- var import_react58 = require("react");
7386
+ var import_react59 = require("react");
7338
7387
  var import_react_native46 = require("react-native");
7339
7388
  var import_react_native_svg6 = __toESM(require("react-native-svg"), 1);
7340
7389
 
@@ -7342,7 +7391,7 @@ var import_react_native_svg6 = __toESM(require("react-native-svg"), 1);
7342
7391
  var import_tokens45 = require("@kjun-ui/tokens");
7343
7392
 
7344
7393
  // shared/package-runtime/use-number-motion.ts
7345
- var import_react56 = require("react");
7394
+ var import_react57 = require("react");
7346
7395
 
7347
7396
  // shared/package-runtime/number-motion.ts
7348
7397
  var import_tokens44 = require("@kjun-ui/tokens");
@@ -7388,14 +7437,14 @@ function createNumberMotion(apply) {
7388
7437
 
7389
7438
  // shared/package-runtime/use-number-motion.ts
7390
7439
  function useNumberMotion(value, animated, fromPrevious, reduced) {
7391
- const [display, setDisplay] = (0, import_react56.useState)(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
7392
- const motion = (0, import_react56.useRef)(null);
7440
+ const [display, setDisplay] = (0, import_react57.useState)(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
7441
+ const motion = (0, import_react57.useRef)(null);
7393
7442
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
7394
- (0, import_react56.useLayoutEffect)(() => {
7443
+ (0, import_react57.useLayoutEffect)(() => {
7395
7444
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
7396
7445
  motion.current.update(value, animated, fromPrevious, reduced);
7397
7446
  }, [value, animated, fromPrevious, reduced]);
7398
- (0, import_react56.useLayoutEffect)(() => () => {
7447
+ (0, import_react57.useLayoutEffect)(() => () => {
7399
7448
  var _a;
7400
7449
  (_a = motion.current) == null ? void 0 : _a.cancel();
7401
7450
  motion.current = null;
@@ -7404,7 +7453,7 @@ function useNumberMotion(value, animated, fromPrevious, reduced) {
7404
7453
  }
7405
7454
 
7406
7455
  // packages/native/src/number-display.tsx
7407
- var import_react57 = require("react");
7456
+ var import_react58 = require("react");
7408
7457
  var import_react_native45 = require("react-native");
7409
7458
  var import_jsx_runtime42 = require("react/jsx-runtime");
7410
7459
  var finiteNumber = (value) => value == null || typeof value === "boolean" || typeof value === "string" && !value.trim() || !["number", "string"].includes(typeof value) || !Number.isFinite(Number(value)) ? null : Number(value) || 0;
@@ -7415,7 +7464,7 @@ var format = (value, decimals = 0) => new Intl.NumberFormat(void 0, {
7415
7464
  function useCountUp(value, animated, fromPrevious) {
7416
7465
  return useNumberMotion(value, animated, fromPrevious, useReducedMotion());
7417
7466
  }
7418
- var MarketQuoteTypeContext = (0, import_react57.createContext)(null);
7467
+ var MarketQuoteTypeContext = (0, import_react58.createContext)(null);
7419
7468
  function KjunAnimatedNumber({
7420
7469
  value,
7421
7470
  decimals = 0,
@@ -7476,7 +7525,7 @@ function KjunPriceCell({
7476
7525
  fetchedAt,
7477
7526
  fromPrevious = true
7478
7527
  }) {
7479
- const { colors } = useKjunStyles(), quoteType = (0, import_react57.useContext)(MarketQuoteTypeContext);
7528
+ const { colors } = useKjunStyles(), quoteType = (0, import_react58.useContext)(MarketQuoteTypeContext);
7480
7529
  return value == null ? /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(KjunSkeleton, { type: "block", height: import_tokens45.tokens.extensions.financial.priceSkeletonHeight, width: import_tokens45.tokens.extensions.financial.priceSkeletonWidth }) : /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(import_react_native45.View, { style: { flexDirection: "row", alignItems: "center", gap: import_tokens45.tokens.extensions.financial.affixGap }, children: [
7481
7530
  /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
7482
7531
  import_react_native45.View,
@@ -7510,7 +7559,7 @@ function KjunSignedValue({
7510
7559
  showFreshness = true,
7511
7560
  formatter
7512
7561
  }) {
7513
- const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), quoteType = (0, import_react57.useContext)(MarketQuoteTypeContext), n = finiteNumber(value), role = n === null || n === 0 ? "priceNeutral" : n > 0 ? "priceUp" : "priceDown", color = loading || n === null ? colors.textSecondary : stale ? colors.textTertiary : domainColor(domainColors, role);
7562
+ const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), quoteType = (0, import_react58.useContext)(MarketQuoteTypeContext), n = finiteNumber(value), role = n === null || n === 0 ? "priceNeutral" : n > 0 ? "priceUp" : "priceDown", color = loading || n === null ? colors.textSecondary : stale ? colors.textTertiary : domainColor(domainColors, role);
7514
7563
  const display = n === null ? "\u2014" : formatter ? formatter(n) : prefix + (showSign && n > 0 ? "+" : "") + format(kind === "percent" && !isRaw ? n * 100 : n, decimals) + (kind === "percent" ? "%" : "") + suffix;
7515
7564
  return /* @__PURE__ */ (0, import_jsx_runtime42.jsxs)(
7516
7565
  import_react_native45.View,
@@ -7806,7 +7855,7 @@ function KjunSparkline({
7806
7855
  stretch = false,
7807
7856
  ariaLabel
7808
7857
  }) {
7809
- const { colors, domainColors } = useKjunStyles(), id = "kjun-" + (0, import_react58.useId)().replace(/:/g, ""), values = data.filter(Number.isFinite), min = Math.min(...values), max = Math.max(...values), range = max - min || 1, points = values.map(
7858
+ const { colors, domainColors } = useKjunStyles(), id = "kjun-" + (0, import_react59.useId)().replace(/:/g, ""), values = data.filter(Number.isFinite), min = Math.min(...values), max = Math.max(...values), range = max - min || 1, points = values.map(
7810
7859
  (v, i) => `${2 + i / Math.max(1, values.length - 1) * (width - 4)},${2 + height - 4 - (v - min) / range * (height - 4)}`
7811
7860
  ).join(" "), change = values.length > 1 ? values[values.length - 1] - values[0] : 0, line = color || (change === 0 ? colors.textTertiary : semantic === "status" ? change > 0 ? colors.success : colors.danger : domainColor(domainColors, change > 0 ? "priceUp" : "priceDown"));
7812
7861
  return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
@@ -7852,7 +7901,7 @@ function KjunSparkline({
7852
7901
 
7853
7902
  // shared/package-runtime/table.ts
7854
7903
  var import_tokens47 = require("@kjun-ui/tokens");
7855
- var import_react59 = require("react");
7904
+ var import_react60 = require("react");
7856
7905
 
7857
7906
  // shared/package-runtime/table-model.ts
7858
7907
  function getValue(row, key) {
@@ -7896,11 +7945,11 @@ function useTableModel(props) {
7896
7945
  expandSingle = false,
7897
7946
  onExpandedRowsChange
7898
7947
  } = props;
7899
- const [internalSort, setSort] = (0, import_react59.useState)({
7948
+ const [internalSort, setSort] = (0, import_react60.useState)({
7900
7949
  key: "",
7901
7950
  order: "asc"
7902
- }), [internalExpanded, setExpanded] = (0, import_react59.useState)([]), [search, setSearch] = (0, import_react59.useState)(""), timer = (0, import_react59.useRef)(void 0);
7903
- (0, import_react59.useEffect)(() => () => clearTimeout(timer.current), []);
7951
+ }), [internalExpanded, setExpanded] = (0, import_react60.useState)([]), [search, setSearch] = (0, import_react60.useState)(""), timer = (0, import_react60.useRef)(void 0);
7952
+ (0, import_react60.useEffect)(() => () => clearTimeout(timer.current), []);
7904
7953
  const sort = props.sort === void 0 ? internalSort : (_a = props.sort) != null ? _a : { key: "", order: "asc" };
7905
7954
  const rows = sortTableRows(data, sort, { sortable, sortMode });
7906
7955
  const key = (row, index = 0) => tableRowKey(row, rowKey, index);
@@ -8061,7 +8110,7 @@ function TableToolbar({
8061
8110
 
8062
8111
  // packages/native/src/table-grid.tsx
8063
8112
  var import_tokens49 = require("@kjun-ui/tokens");
8064
- var import_react60 = require("react");
8113
+ var import_react61 = require("react");
8065
8114
  var import_react_native_svg7 = __toESM(require("react-native-svg"), 1);
8066
8115
  var import_react_native48 = require("react-native");
8067
8116
  var import_jsx_runtime45 = require("react/jsx-runtime");
@@ -8069,7 +8118,7 @@ function TableGrid({ initialLoading, skeletonRows, skeletonHidden, state, onRowC
8069
8118
  const m = useKjunMessages();
8070
8119
  const { colors } = useKjunStyles();
8071
8120
  const geometry2 = import_tokens49.tokens.table;
8072
- const [scroll, setScroll] = (0, import_react60.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + (0, import_react60.useId)().replace(/[^a-z0-9]/gi, "");
8121
+ const [scroll, setScroll] = (0, import_react61.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + (0, import_react61.useId)().replace(/[^a-z0-9]/gi, "");
8073
8122
  const cellPadding = geometry2.cellPadding[compact ? "compact" : "regular"];
8074
8123
  const width = (col) => typeof col.width === "number" ? col.width : typeof col.width === "string" && /^\d+(px)?$/.test(col.width) ? parseFloat(col.width) : geometry2.columnWidth;
8075
8124
  const totalWidth = visible.reduce((sum, col) => sum + width(col), 0) + (selectable ? geometry2.actionColumnWidth : 0) + (expandable ? geometry2.actionColumnWidth : 0);
@@ -8183,7 +8232,7 @@ function TableGrid({ initialLoading, skeletonRows, skeletonHidden, state, onRowC
8183
8232
  ))
8184
8233
  ] }, i)) : !state.rows.length ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(import_react_native48.View, { style: { paddingVertical: geometry2.emptyPadding.y, paddingHorizontal: geometry2.emptyPadding.x, alignItems: "center" }, children: content(emptyContent || emptyText, {
8185
8234
  color: colors.textSecondary
8186
- }) }) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_react60.Fragment, { children: [
8235
+ }) }) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(import_react61.Fragment, { children: [
8187
8236
  /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
8188
8237
  AccessiblePressable,
8189
8238
  {
@@ -8812,7 +8861,7 @@ function KjunKpiHero(props) {
8812
8861
 
8813
8862
  // packages/native/src/kpi-row.tsx
8814
8863
  var import_tokens53 = require("@kjun-ui/tokens");
8815
- var import_react61 = require("react");
8864
+ var import_react62 = require("react");
8816
8865
  var import_react_native53 = require("react-native");
8817
8866
  var import_jsx_runtime50 = require("react/jsx-runtime");
8818
8867
  function KjunKpiRow({
@@ -8827,7 +8876,7 @@ function KjunKpiRow({
8827
8876
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = (0, import_react_native53.useWindowDimensions)().width <= import_tokens53.tokens.responsive.kpiRow, small = size === "sm", summary = mobileSummary && mobile && !small;
8828
8877
  const geometry2 = import_tokens53.tokens.extensions.kpiRow;
8829
8878
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8830
- const [width, setWidth] = (0, import_react61.useState)(0);
8879
+ const [width, setWidth] = (0, import_react62.useState)(0);
8831
8880
  const paddingX = summary ? geometry2.summary.paddingX : spec.paddingX;
8832
8881
  const gapX = summary ? geometry2.summary.gapX : 0;
8833
8882
  const explicit = items2.some(
@@ -9046,7 +9095,7 @@ var import_tokens55 = require("@kjun-ui/tokens");
9046
9095
  var import_react_native55 = require("react-native");
9047
9096
 
9048
9097
  // shared/package-runtime/market-cards.ts
9049
- var import_react62 = require("react");
9098
+ var import_react63 = require("react");
9050
9099
  function useMarketCardsModel(props, persistence) {
9051
9100
  const {
9052
9101
  columns,
@@ -9062,8 +9111,8 @@ function useMarketCardsModel(props, persistence) {
9062
9111
  sortKey: c.sortable ? metricConfig[c.key].sortKey : null,
9063
9112
  isDefaultSort: c.defaultSort
9064
9113
  }));
9065
- const [key, setKey] = (0, import_react62.useState)(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
9066
- const mounted = (0, import_react62.useRef)("");
9114
+ const [key, setKey] = (0, import_react63.useState)(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
9115
+ const mounted = (0, import_react63.useRef)("");
9067
9116
  const save = (key2) => {
9068
9117
  var _a;
9069
9118
  try {
@@ -9071,7 +9120,7 @@ function useMarketCardsModel(props, persistence) {
9071
9120
  } catch (e) {
9072
9121
  }
9073
9122
  };
9074
- (0, import_react62.useEffect)(() => {
9123
+ (0, import_react63.useEffect)(() => {
9075
9124
  var _a, _b;
9076
9125
  if (mounted.current === restoreSignature) return;
9077
9126
  mounted.current = restoreSignature;
@@ -9550,7 +9599,7 @@ function KjunMarketListPanel({
9550
9599
 
9551
9600
  // packages/native/src/market-table.tsx
9552
9601
  var import_tokens58 = require("@kjun-ui/tokens");
9553
- var import_react63 = require("react");
9602
+ var import_react64 = require("react");
9554
9603
  var import_react_native58 = require("react-native");
9555
9604
  var import_react_native_svg8 = __toESM(require("react-native-svg"), 1);
9556
9605
  var import_jsx_runtime55 = require("react/jsx-runtime");
@@ -9637,7 +9686,7 @@ function KjunMarketTable(props) {
9637
9686
  );
9638
9687
  };
9639
9688
  const layout = useMarketLayout(columns, showActions);
9640
- const [scroll, setScroll] = (0, import_react63.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + (0, import_react63.useId)().replace(/[^a-z0-9]/gi, "");
9689
+ const [scroll, setScroll] = (0, import_react64.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + (0, import_react64.useId)().replace(/[^a-z0-9]/gi, "");
9641
9690
  const tableQuote = { price: {}, change: { fontWeight: typeStyle("body").fontWeight } };
9642
9691
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(
9643
9692
  import_react_native58.View,
@@ -9852,24 +9901,25 @@ function KjunMarketTable(props) {
9852
9901
 
9853
9902
  // packages/native/src/list.tsx
9854
9903
  var import_tokens59 = require("@kjun-ui/tokens");
9855
- var import_react64 = require("react");
9904
+ var import_react65 = require("react");
9856
9905
  var import_react_native59 = require("react-native");
9857
9906
  var import_jsx_runtime56 = require("react/jsx-runtime");
9858
- var ListRowContext = (0, import_react64.createContext)({ divider: true, compact: false });
9859
- function KjunListRow({ title, description, leading, trailing, actions, href, disabled = false, destructive = false, chevron = false, onPress }) {
9860
- const { colors } = useKjunStyles(), { divider, compact } = (0, import_react64.useContext)(ListRowContext);
9907
+ var ListRowContext = (0, import_react65.createContext)({ divider: true, compact: false });
9908
+ function KjunListRow({ title, description, leading, trailing, actions, href, disabled = false, destructive = false, chevron = false, onPress, ariaLabel, children }) {
9909
+ const { colors } = useKjunStyles(), { divider, compact } = (0, import_react65.useContext)(ListRowContext);
9861
9910
  const parts = /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_jsx_runtime56.Fragment, { children: [
9862
9911
  hasContent(leading) && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { children: content(leading) }),
9863
9912
  /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native59.View, { style: { flex: 1, minWidth: 0 }, children: [
9864
9913
  /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(KText, { style: { ...typeStyle("label"), ...destructive ? { color: colors.danger } : {} }, children: title }),
9865
- !!description && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(KText, { style: { marginTop: import_tokens59.tokens.extensions.list.descriptionGap, color: colors.textSecondary, ...typeStyle("caption") }, children: description })
9914
+ !!description && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(KText, { style: { marginTop: import_tokens59.tokens.extensions.list.descriptionGap, color: colors.textSecondary, ...typeStyle("caption") }, children: description }),
9915
+ hasContent(children) && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { style: { marginTop: import_tokens59.tokens.extensions.list.descriptionGap }, children: content(children) })
9866
9916
  ] }),
9867
9917
  hasContent(trailing) && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { style: { maxWidth: "35%" }, children: content(trailing) }),
9868
9918
  chevron && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { accessible: false, importantForAccessibility: "no-hide-descendants", accessibilityElementsHidden: true, children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(KjunIcon, { name: "chevron-right", size: import_tokens59.tokens.iconSizes.default, color: colors.textTertiary }) })
9869
9919
  ] });
9870
9920
  const style = { flex: 1, minWidth: 0, minHeight: compact ? import_tokens59.tokens.extensions.list.compactMinimumHeight : import_tokens59.tokens.extensions.list.minimumHeight, flexDirection: "row", alignItems: "center", gap: import_tokens59.tokens.extensions.list.gap, padding: import_tokens59.tokens.extensions.list.padding, ...compact ? { paddingVertical: import_tokens59.tokens.extensions.list.compactPaddingY } : {} };
9871
9921
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(import_react_native59.View, { role: "listitem", style: { flexDirection: "row", alignItems: "center", gap: import_tokens59.tokens.extensions.list.gap, borderBottomWidth: divider ? import_tokens59.tokens.border.defaultWidth : 0, borderBottomColor: colors.divider }, children: [
9872
- onPress || href ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AccessiblePressable, { ...import_react_native59.Platform.OS === "web" && href && !disabled ? { href } : {}, accessibilityRole: href ? "link" : "button", accessibilityLabel: title + (description ? ", " + description : ""), disabled, accessibilityState: { disabled }, onPress, style: ({ pressed }) => ({ ...style, opacity: disabled ? import_tokens59.tokens.states.opacity.disabled : 1, backgroundColor: pressed ? colors.hover : "transparent" }), children: parts }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { style, children: parts }),
9922
+ onPress || href ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(AccessiblePressable, { ...import_react_native59.Platform.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 ? import_tokens59.tokens.states.opacity.disabled : 1, backgroundColor: pressed ? colors.hover : "transparent" }), children: parts }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { style, children: parts }),
9873
9923
  hasContent(actions) && /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { pointerEvents: disabled ? "none" : "auto", ...disabled && import_react_native59.Platform.OS === "web" ? { inert: true } : {}, style: { maxWidth: "45%", flexDirection: "row", flexWrap: "wrap", gap: import_tokens59.tokens.extensions.list.actionsGap, paddingRight: import_tokens59.tokens.extensions.list.actionsPadding, opacity: disabled ? import_tokens59.tokens.states.opacity.disabled : 1 }, children: content(actions) })
9874
9924
  ] });
9875
9925
  }
@@ -9883,11 +9933,11 @@ function KjunListSection({ title, description, actions, children, ariaLabel, sur
9883
9933
  ] }),
9884
9934
  content(actions)
9885
9935
  ] }),
9886
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { role: "list", accessibilityLabel: ariaLabel || title, children: import_react64.Children.toArray(children).map((row, i, rows) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ListRowContext.Provider, { value: { divider: divider && i < rows.length - 1, compact: density === "compact" }, children: row }, i)) })
9936
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { role: "list", accessibilityLabel: ariaLabel || title, children: import_react65.Children.toArray(children).map((row, i, rows) => /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ListRowContext.Provider, { value: { divider: divider && i < rows.length - 1, compact: density === "compact" }, children: row }, i)) })
9887
9937
  ] });
9888
9938
  }
9889
9939
  function KjunListItem({ children }) {
9890
- const { colors } = useKjunStyles(), { divider, compact } = (0, import_react64.useContext)(ListRowContext);
9940
+ const { colors } = useKjunStyles(), { divider, compact } = (0, import_react65.useContext)(ListRowContext);
9891
9941
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { role: "listitem", style: {
9892
9942
  padding: import_tokens59.tokens.extensions.list.padding,
9893
9943
  ...compact ? { paddingVertical: import_tokens59.tokens.extensions.list.compactPaddingY } : {},
@@ -9899,7 +9949,7 @@ function KjunListItem({ children }) {
9899
9949
 
9900
9950
  // packages/native/src/app-navigation.tsx
9901
9951
  var import_tokens60 = require("@kjun-ui/tokens");
9902
- var import_react65 = require("react");
9952
+ var import_react66 = require("react");
9903
9953
  var import_react_native60 = require("react-native");
9904
9954
  var import_jsx_runtime57 = require("react/jsx-runtime");
9905
9955
  function KjunTopNavigation({ title, description, leading, actions, safeAreaTop = 0 }) {
@@ -9908,13 +9958,13 @@ function KjunTopNavigation({ title, description, leading, actions, safeAreaTop =
9908
9958
  const titleInset = Math.max(0, (geometry2.controlSize - import_tokens60.tokens.typography.sectionTitle.lineHeightPx) / 2);
9909
9959
  const wrapping = import_react_native60.Platform.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
9910
9960
  const edgeInset = (geometry2.controlSize - geometry2.iconSize) / 2;
9911
- const [iconEdges, setIconEdges] = (0, import_react65.useState)({ leading: false, trailing: false });
9961
+ const [iconEdges, setIconEdges] = (0, import_react66.useState)({ leading: false, trailing: false });
9912
9962
  const square = (key) => (event) => {
9913
9963
  const { width, height } = event.nativeEvent.layout;
9914
9964
  const next = Math.abs(width - height) < 1 && Math.abs(height - geometry2.controlSize) < 1;
9915
9965
  setIconEdges((current) => current[key] === next ? current : { ...current, [key]: next });
9916
9966
  };
9917
- const flatten2 = (node) => import_react65.Children.toArray(node).flatMap((child) => (0, import_react65.isValidElement)(child) && child.type === import_react65.Fragment ? flatten2(child.props.children) : [child]);
9967
+ const flatten2 = (node) => import_react66.Children.toArray(node).flatMap((child) => (0, import_react66.isValidElement)(child) && child.type === import_react66.Fragment ? flatten2(child.props.children) : [child]);
9918
9968
  const actionList = flatten2(actions);
9919
9969
  return /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TopNavigationContext.Provider, { value: geometry2, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native60.View, { style: { flexShrink: 0, paddingTop: Math.max(0, safeAreaTop), backgroundColor: colors.surface }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_react_native60.View, { style: { minHeight: geometry2.minimumHeight, flexDirection: "row", flexWrap: "wrap", alignItems: "flex-start", gap: geometry2.gap, paddingVertical: geometry2.paddingY, paddingHorizontal: geometry2.paddingX }, children: [
9920
9970
  hasContent(leading) && /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(TopNavigationContext.Provider, { value: { ...geometry2, slot: "leading" }, children: /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(import_react_native60.View, { onLayout: square("leading"), style: { minHeight: geometry2.controlSize, minWidth: 0, maxWidth: "40%", flexShrink: 1, justifyContent: "center", marginLeft: iconEdges.leading ? -edgeInset : 0 }, children: content(leading) }) }),
@@ -9990,7 +10040,7 @@ function KjunBottomNavigation({ items: items2, value, ariaLabel, safeAreaBottom
9990
10040
  }
9991
10041
  function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboardVisible = false, hideOnKeyboard = false }) {
9992
10042
  const { colors } = useKjunStyles();
9993
- const [width, setWidth] = (0, import_react65.useState)(0);
10043
+ const [width, setWidth] = (0, import_react66.useState)(0);
9994
10044
  const geometry2 = import_tokens60.tokens.extensions.navigation;
9995
10045
  const wide = width >= import_tokens60.tokens.responsive.bottomAction + geometry2.padding * 2;
9996
10046
  const wrapping = import_react_native60.Platform.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
@@ -10012,17 +10062,17 @@ function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboa
10012
10062
  }
10013
10063
 
10014
10064
  // packages/native/src/media.tsx
10015
- var import_react66 = require("react");
10065
+ var import_react67 = require("react");
10016
10066
  var import_react_native61 = require("react-native");
10017
10067
  var import_tokens61 = require("@kjun-ui/tokens");
10018
10068
  var import_jsx_runtime58 = require("react/jsx-runtime");
10019
- var ImageBackgroundContext = (0, import_react66.createContext)(void 0);
10069
+ var ImageBackgroundContext = (0, import_react67.createContext)(void 0);
10020
10070
  function KjunImage({ src, source, alt, decorative = false, aspectRatio = 1, fit = "cover", fallback: fallback2, onLoad, onError }) {
10021
- const { colors } = useKjunStyles(), background = (0, import_react66.useContext)(ImageBackgroundContext);
10022
- const request = JSON.stringify(source != null ? source : src), current = (0, import_react66.useRef)({ request, version: 0 });
10071
+ const { colors } = useKjunStyles(), background = (0, import_react67.useContext)(ImageBackgroundContext);
10072
+ const request = JSON.stringify(source != null ? source : src), current = (0, import_react67.useRef)({ request, version: 0 });
10023
10073
  if (current.current.request !== request) current.current = { request, version: current.current.version + 1 };
10024
10074
  const version = current.current.version;
10025
- const [failed, setFailed] = (0, import_react66.useState)(null);
10075
+ const [failed, setFailed] = (0, import_react67.useState)(null);
10026
10076
  const missing = !source && !src;
10027
10077
  return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_react_native61.View, { accessibilityElementsHidden: decorative, importantForAccessibility: decorative ? "no-hide-descendants" : "auto", "aria-hidden": decorative || void 0, style: { width: "100%", aspectRatio: aspectRatio > 0 ? aspectRatio : 1, overflow: "hidden", backgroundColor: background != null ? background : colors.secondary }, children: !missing && failed !== version ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_react_native61.Image, { source: source != null ? source : { uri: src }, accessible: !decorative, accessibilityLabel: decorative ? void 0 : alt, resizeMode: fit, style: { position: "absolute", inset: 0, width: "100%", height: "100%" }, onLoad: () => {
10028
10078
  if (version === current.current.version) onLoad == null ? void 0 : onLoad();
@@ -10087,7 +10137,7 @@ function KjunFab({ icon, ariaLabel, disabled = false, safeAreaBottom = 0, offset
10087
10137
  }
10088
10138
 
10089
10139
  // packages/native/src/range-input.tsx
10090
- var import_react67 = require("react");
10140
+ var import_react68 = require("react");
10091
10141
  var import_react_native63 = require("react-native");
10092
10142
  var import_tokens64 = require("@kjun-ui/tokens");
10093
10143
  var import_jsx_runtime61 = require("react/jsx-runtime");
@@ -10112,18 +10162,18 @@ function RangeInput({
10112
10162
  const valid = domain.valid && (!Array.isArray(value) || value.length === 2) && values.every(domain.accepts) && (values.length === 1 || values[0] <= values[1]);
10113
10163
  const blocked = disabled || !valid;
10114
10164
  const effectiveMax = valid ? domain.snap(max) : min;
10115
- const [hovered, setHovered] = (0, import_react67.useState)(null);
10116
- const [dragging, setDragging] = (0, import_react67.useState)(null);
10117
- const [focused, setFocused] = (0, import_react67.useState)(null);
10118
- const track = (0, import_react67.useRef)(null), measured = (0, import_react67.useRef)({ x: 0, width: 1 }), selected = (0, import_react67.useRef)(0), dirty = (0, import_react67.useRef)(false);
10119
- const latest = (0, import_react67.useRef)(values);
10165
+ const [hovered, setHovered] = (0, import_react68.useState)(null);
10166
+ const [dragging, setDragging] = (0, import_react68.useState)(null);
10167
+ const [focused, setFocused] = (0, import_react68.useState)(null);
10168
+ const track = (0, import_react68.useRef)(null), measured = (0, import_react68.useRef)({ x: 0, width: 1 }), selected = (0, import_react68.useRef)(0), dirty = (0, import_react68.useRef)(false);
10169
+ const latest = (0, import_react68.useRef)(values);
10120
10170
  latest.current = values;
10121
- const callbacks = (0, import_react67.useRef)({ onValueChange, onChangeCommit });
10171
+ const callbacks = (0, import_react68.useRef)({ onValueChange, onChangeCommit });
10122
10172
  callbacks.current = { onValueChange, onChangeCommit };
10123
- (0, import_react67.useEffect)(() => {
10173
+ (0, import_react68.useEffect)(() => {
10124
10174
  if (!valid) console.warn("KJUN Slider: \uBC94\uC704\xB7step\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10125
10175
  }, [valid]);
10126
- (0, import_react67.useEffect)(() => {
10176
+ (0, import_react68.useEffect)(() => {
10127
10177
  if (blocked) {
10128
10178
  setDragging(null);
10129
10179
  setHovered(null);
@@ -10163,7 +10213,7 @@ function RangeInput({
10163
10213
  measured.current = { x: pageX, width: Math.max(1, width) };
10164
10214
  });
10165
10215
  };
10166
- const responder = (0, import_react67.useMemo)(
10216
+ const responder = (0, import_react68.useMemo)(
10167
10217
  () => import_react_native63.PanResponder.create({
10168
10218
  onStartShouldSetPanResponderCapture: () => !disabled && valid,
10169
10219
  onMoveShouldSetPanResponderCapture: (_event, gesture) => !disabled && valid && Math.abs(gesture.dx) > 3 && Math.abs(gesture.dx) > Math.abs(gesture.dy),
@@ -10388,7 +10438,7 @@ function KjunRangeSlider(props) {
10388
10438
  }
10389
10439
 
10390
10440
  // packages/native/src/quantity-stepper.tsx
10391
- var import_react68 = require("react");
10441
+ var import_react69 = require("react");
10392
10442
  var import_react_native64 = require("react-native");
10393
10443
  var import_tokens65 = require("@kjun-ui/tokens");
10394
10444
 
@@ -10411,16 +10461,16 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10411
10461
  const increaseStyle = { ...buttonStyle, borderRadius: 0, borderTopRightRadius: outer, borderBottomRightRadius: outer };
10412
10462
  const domain = (0, import_tokens65.createNumberDomain)({ min, max, step, precision }), valid = domain.valid && domain.accepts(value), blocked = disabled || !valid;
10413
10463
  const surface = useFieldSurface(size, { disabled: blocked, invalid });
10414
- const [draft, setDraft] = (0, import_react68.useState)(String(value));
10415
- const inputRef = (0, import_react68.useRef)(null);
10416
- const composing = (0, import_react68.useRef)(false), dirty = (0, import_react68.useRef)(false), accepted = (0, import_react68.useRef)(value);
10417
- const cancelledEscape = (0, import_react68.useRef)(false);
10418
- (0, import_react68.useEffect)(() => {
10464
+ const [draft, setDraft] = (0, import_react69.useState)(String(value));
10465
+ const inputRef = (0, import_react69.useRef)(null);
10466
+ const composing = (0, import_react69.useRef)(false), dirty = (0, import_react69.useRef)(false), accepted = (0, import_react69.useRef)(value);
10467
+ const cancelledEscape = (0, import_react69.useRef)(false);
10468
+ (0, import_react69.useEffect)(() => {
10419
10469
  setDraft(String(value));
10420
10470
  accepted.current = value;
10421
10471
  dirty.current = false;
10422
10472
  }, [value, precision, min, max, step]);
10423
- (0, import_react68.useEffect)(() => {
10473
+ (0, import_react69.useEffect)(() => {
10424
10474
  if (!valid) console.warn("KJUN QuantityStepper: \uBC94\uC704\xB7step\xB7\uC815\uBC00\uB3C4\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10425
10475
  }, [valid]);
10426
10476
  const emit = (next) => {
@@ -10457,7 +10507,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10457
10507
  } else if (action === "commit") commit();
10458
10508
  else move(action === "increment" ? 1 : -1);
10459
10509
  };
10460
- const handlers = (0, import_react68.useRef)({ key, edit: (text) => {
10510
+ const handlers = (0, import_react69.useRef)({ key, edit: (text) => {
10461
10511
  dirty.current = true;
10462
10512
  setDraft(text);
10463
10513
  } });
@@ -10465,7 +10515,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10465
10515
  dirty.current = true;
10466
10516
  setDraft(text);
10467
10517
  } };
10468
- (0, import_react68.useEffect)(() => {
10518
+ (0, import_react69.useEffect)(() => {
10469
10519
  if (import_react_native64.Platform.OS !== "web") return;
10470
10520
  const input = inputRef.current;
10471
10521
  const keydown = (event) => handlers.current.key(event);
@@ -10537,7 +10587,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
10537
10587
  }
10538
10588
 
10539
10589
  // packages/native/src/time-picker.tsx
10540
- var import_react69 = require("react");
10590
+ var import_react70 = require("react");
10541
10591
  var import_react_native65 = require("react-native");
10542
10592
  var import_tokens66 = require("@kjun-ui/tokens");
10543
10593
  var import_jsx_runtime63 = require("react/jsx-runtime");
@@ -10546,12 +10596,12 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
10546
10596
  ariaLabel != null ? ariaLabel : ariaLabel = m.time;
10547
10597
  const geometry2 = import_tokens66.tokens.extensions.timePicker, spec = import_tokens66.tokens.input[size];
10548
10598
  const { colors } = useKjunStyles();
10549
- const first = (0, import_react69.useRef)(null);
10550
- const [focused, setFocused] = (0, import_react69.useState)(false), [opened, setOpened] = (0, import_react69.useState)(null);
10551
- const field = useKjunField(), uid = (0, import_react69.useId)();
10599
+ const first = (0, import_react70.useRef)(null);
10600
+ const [focused, setFocused] = (0, import_react70.useState)(false), [opened, setOpened] = (0, import_react70.useState)(null);
10601
+ const field = useKjunField(), uid = (0, import_react70.useId)();
10552
10602
  const fieldId = (field == null ? void 0 : field.id) || `kjun-time-${uid}`;
10553
- const domain = (0, import_react69.useMemo)(() => (0, import_tokens66.createTimeDomain)({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
10554
- (0, import_react69.useEffect)(() => {
10603
+ const domain = (0, import_react70.useMemo)(() => (0, import_tokens66.createTimeDomain)({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
10604
+ (0, import_react70.useEffect)(() => {
10555
10605
  if (!valid) console.warn("KJUN TimePicker: \uC2DC\uAC01 \uBC94\uC704\xB7\uAC04\uACA9\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
10556
10606
  }, [valid]);
10557
10607
  const change = (next) => {
@@ -10562,7 +10612,7 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
10562
10612
  };
10563
10613
  const time = value === null ? null : domain.parse(value);
10564
10614
  return /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_react_native65.View, { accessibilityLabel: ariaLabel, style: { flexDirection: "row", alignItems: "center", maxWidth: "100%", minWidth: 0, backgroundColor: colors.inputBg, borderRadius: spec.radius }, children: [
10565
- /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_react_native65.View, { style: { flex: 1, flexDirection: "row", alignItems: "center", minWidth: 0 }, children: [m.hour, m.minute, m.second].slice(0, precision === "second" ? 3 : 2).map((label, index) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_react69.Fragment, { children: [
10615
+ /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_react_native65.View, { style: { flex: 1, flexDirection: "row", alignItems: "center", minWidth: 0 }, children: [m.hour, m.minute, m.second].slice(0, precision === "second" ? 3 : 2).map((label, index) => /* @__PURE__ */ (0, import_jsx_runtime63.jsxs)(import_react70.Fragment, { children: [
10566
10616
  index > 0 && /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(KText, { "aria-hidden": true, style: { ...inputTypeStyle(size), width: geometry2.separatorWidth, textAlign: "center", color: disabled || !valid ? colors.textDisabled : colors.textSecondary }, children: ":" }),
10567
10617
  /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(FieldContext.Provider, { value: { ...field, id: index === 0 ? fieldId : `${fieldId}-${index}` }, children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(CompoundControlContext.Provider, { value: { size, focusRef: index === 0 ? first : void 0, onFocusChange: setFocused, leading: index === 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(import_react_native65.View, { style: { flexShrink: 0, minWidth: geometry2.segmentMinimumWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime63.jsx)(KjunSelect, { value: time === null ? null : domain.part(time, index), options: domain.options(value, index).map((n) => ({ value: n, label: String(n).padStart(2, "0") })), onValueChange: (next) => {
10568
10618
  if (typeof next === "number") change(domain.select(value, index, next));