@kjun-ui/native 0.6.0 → 0.7.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.web.js CHANGED
@@ -6364,12 +6364,27 @@ import {
6364
6364
  initialQueryDisplay,
6365
6365
  queryDisplayStatus
6366
6366
  } from "@kjun-ui/tokens";
6367
- import { Component, useState as useState30 } from "react";
6367
+ import { Component, useState as useState31 } from "react";
6368
6368
  import { Platform as Platform23, View as View31 } from "react-native";
6369
+
6370
+ // shared/package-runtime/use-loading-reveal.ts
6371
+ import { useEffect as useEffect21, useState as useState30 } from "react";
6372
+ function useLoadingReveal(active, delay = 0) {
6373
+ const [revealed, setRevealed] = useState30(false);
6374
+ useEffect21(() => {
6375
+ setRevealed(false);
6376
+ if (!active || delay <= 0) return;
6377
+ const timer = setTimeout(() => setRevealed(true), delay);
6378
+ return () => clearTimeout(timer);
6379
+ }, [active, delay]);
6380
+ return delay <= 0 || revealed;
6381
+ }
6382
+
6383
+ // packages/native/src/data-state.tsx
6369
6384
  import { jsx as jsx37, jsxs as jsxs25 } from "react/jsx-runtime";
6370
6385
  function useQueryDisplay(props) {
6371
6386
  var _a;
6372
- const [state, setState] = useState30(() => initialQueryDisplay(props));
6387
+ const [state, setState] = useState31(() => initialQueryDisplay(props));
6373
6388
  let next = state;
6374
6389
  if (state.queryKey !== ((_a = props.queryKey) != null ? _a : null) || state.resultKey !== props.resultKey || state.loading !== !!props.loading) {
6375
6390
  next = advanceQueryDisplay(state, props);
@@ -6388,6 +6403,7 @@ function KjunDataState({
6388
6403
  emptyIcon,
6389
6404
  emptyActionText,
6390
6405
  loadingText = "\uB85C\uB529 \uC911...",
6406
+ loadingDelay = 0,
6391
6407
  retryText = "\uB2E4\uC2DC \uC2DC\uB3C4",
6392
6408
  size = "md",
6393
6409
  skeleton = false,
@@ -6401,7 +6417,7 @@ function KjunDataState({
6401
6417
  onEmptyAction,
6402
6418
  ...query
6403
6419
  }) {
6404
- const state = useQueryDisplay(query), blockingError = query.error && !(state.usesQueryState && state.hasCurrentResult), visibleRefreshError = refreshError || (state.usesQueryState && state.hasCurrentResult ? query.error : null), concealed = state.initialLoading || !!blockingError || empty, padding = tokens34.extensions.state.padding[size];
6420
+ const state = useQueryDisplay(query), blockingError = query.error && !(state.usesQueryState && state.hasCurrentResult), visibleRefreshError = refreshError || (state.usesQueryState && state.hasCurrentResult ? query.error : null), concealed = state.initialLoading || !!blockingError || empty, padding = tokens34.extensions.state.padding[size], revealed = useLoadingReveal(state.initialLoading, loadingDelay);
6405
6421
  const { colors } = useKjunStyles();
6406
6422
  return /* @__PURE__ */ jsxs25(
6407
6423
  View31,
@@ -6434,8 +6450,10 @@ function KjunDataState({
6434
6450
  state.initialLoading ? /* @__PURE__ */ jsx37(
6435
6451
  View31,
6436
6452
  {
6437
- accessibilityLabel: loadingText,
6438
- style: { paddingVertical: loadingPadding === "none" ? 0 : padding },
6453
+ accessibilityLabel: revealed ? loadingText : void 0,
6454
+ "aria-hidden": revealed ? void 0 : true,
6455
+ importantForAccessibility: revealed ? void 0 : "no-hide-descendants",
6456
+ style: { paddingVertical: loadingPadding === "none" ? 0 : padding, opacity: revealed ? void 0 : 0 },
6439
6457
  children: loadingContent || (skeleton ? /* @__PURE__ */ jsx37(View31, { style: { gap: tokens34.dimension.value12 }, children: Array.from({ length: skeletonCount }, (_, i) => /* @__PURE__ */ jsx37(KjunSkeleton, { type: skeletonType }, i)) }) : /* @__PURE__ */ jsxs25(View31, { style: { alignItems: "center", gap: tokens34.dimension.value12 }, children: [
6440
6458
  /* @__PURE__ */ jsx37(KjunSpinner, { size: "md" }),
6441
6459
  /* @__PURE__ */ jsx37(KText, { style: { ...typeStyle("body"), color: colors.textSecondary, textAlign: "center", maxWidth: "100%" }, children: loadingText })
@@ -6516,7 +6534,7 @@ var KjunErrorBoundary = class extends Component {
6516
6534
 
6517
6535
  // packages/native/src/skeletons.tsx
6518
6536
  import { tokens as tokens38 } from "@kjun-ui/tokens";
6519
- import { Fragment as Fragment12, useEffect as useEffect21, useRef as useRef30 } from "react";
6537
+ import { Fragment as Fragment12, useEffect as useEffect22, useRef as useRef30 } from "react";
6520
6538
  import { Animated as Animated17, View as View33, useWindowDimensions as useWindowDimensions6 } from "react-native";
6521
6539
  import Svg5, { G as G2, Path as Path4, Rect as Rect3 } from "react-native-svg";
6522
6540
 
@@ -6545,9 +6563,9 @@ function nativeMarketLayout(columns, showActions, containerWidth) {
6545
6563
 
6546
6564
  // packages/native/src/market-layout.ts
6547
6565
  import { tokens as tokens36 } from "@kjun-ui/tokens";
6548
- import { useState as useState31 } from "react";
6566
+ import { useState as useState32 } from "react";
6549
6567
  function useMarketLayout(columns, showActions) {
6550
- const [containerWidth, setContainerWidth] = useState31(0);
6568
+ const [containerWidth, setContainerWidth] = useState32(0);
6551
6569
  const onLayout = (event) => setContainerWidth(event.nativeEvent.layout.width);
6552
6570
  return { ...nativeMarketLayout(columns, showActions, containerWidth), onLayout };
6553
6571
  }
@@ -6683,7 +6701,7 @@ function KjunChartSkeleton({
6683
6701
  height = tokens38.extensions.chartSkeleton.height
6684
6702
  }) {
6685
6703
  const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef30(new Animated17.Value(1)).current;
6686
- useEffect21(() => {
6704
+ useEffect22(() => {
6687
6705
  if (reduced) return;
6688
6706
  const loop = Animated17.loop(
6689
6707
  Animated17.sequence([
@@ -6795,7 +6813,7 @@ function KjunChartSkeleton({
6795
6813
  }
6796
6814
 
6797
6815
  // packages/native/src/financial-display.tsx
6798
- import { tokens as tokens41 } from "@kjun-ui/tokens";
6816
+ import { deviationLevel, tokens as tokens41 } from "@kjun-ui/tokens";
6799
6817
  import { useId as useId8 } from "react";
6800
6818
  import {
6801
6819
  View as View35
@@ -6813,7 +6831,7 @@ import Svg6, {
6813
6831
  import { tokens as tokens40 } from "@kjun-ui/tokens";
6814
6832
 
6815
6833
  // shared/package-runtime/use-number-motion.ts
6816
- import { useLayoutEffect as useLayoutEffect16, useRef as useRef31, useState as useState32 } from "react";
6834
+ import { useLayoutEffect as useLayoutEffect16, useRef as useRef31, useState as useState33 } from "react";
6817
6835
 
6818
6836
  // shared/package-runtime/number-motion.ts
6819
6837
  import { tokens as tokens39 } from "@kjun-ui/tokens";
@@ -6859,7 +6877,7 @@ function createNumberMotion(apply) {
6859
6877
 
6860
6878
  // shared/package-runtime/use-number-motion.ts
6861
6879
  function useNumberMotion(value, animated, fromPrevious, reduced) {
6862
- const [display, setDisplay] = useState32(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6880
+ const [display, setDisplay] = useState33(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6863
6881
  const motion = useRef31(null);
6864
6882
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
6865
6883
  useLayoutEffect16(() => {
@@ -7045,6 +7063,7 @@ function KjunSignedValue({
7045
7063
 
7046
7064
  // packages/native/src/financial-display.tsx
7047
7065
  import { Fragment as Fragment13, jsx as jsx41, jsxs as jsxs29 } from "react/jsx-runtime";
7066
+ var deviationFill = { neutral: 1, low: tokens41.states.opacity.deviationLow, medium: tokens41.states.opacity.deviationMedium, strong: tokens41.states.opacity.deviationStrong };
7048
7067
  function KjunDeviation({
7049
7068
  value,
7050
7069
  variant = "pill",
@@ -7055,7 +7074,7 @@ function KjunDeviation({
7055
7074
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), n = finiteNumber(value);
7056
7075
  if (n === null)
7057
7076
  return /* @__PURE__ */ jsx41(KText, { style: { color: colors.textDisabled }, children: "-" });
7058
- const abs = Math.abs(n), signal = abs >= signalThreshold, neutral = abs < 0.1, color = neutral ? colors.textSecondary : domainColor(domainColors, n > 0 ? "priceUp" : "priceDown"), label = formatter ? formatter(n) : (n > 0 ? "+" : "") + format(n, decimals) + "%";
7077
+ const abs = Math.abs(n), signal = abs >= signalThreshold, level = deviationLevel(n), neutral = level === "neutral", color = neutral ? colors.textSecondary : domainColor(domainColors, n > 0 ? "priceUp" : "priceDown"), label = formatter ? formatter(n) : (n > 0 ? "+" : "") + format(n, decimals) + "%";
7059
7078
  if (variant === "badge")
7060
7079
  return /* @__PURE__ */ jsxs29(
7061
7080
  View35,
@@ -7124,7 +7143,7 @@ function KjunDeviation({
7124
7143
  inset: 0,
7125
7144
  borderRadius: tokens41.extensions.financial.cellRadius,
7126
7145
  backgroundColor: neutral ? colors.secondary : color,
7127
- opacity: neutral ? 1 : abs < 0.5 ? 0.08 : abs < 1 ? 0.14 : 0.22
7146
+ opacity: deviationFill[level]
7128
7147
  }
7129
7148
  }
7130
7149
  ),
@@ -7137,7 +7156,7 @@ function KjunDeviation({
7137
7156
  fontVariant: ["tabular-nums"],
7138
7157
  ...typeStyle("body"),
7139
7158
  // Like Web: control weight, stronger once the deviation reaches 1%.
7140
- fontWeight: abs >= 1 ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
7159
+ fontWeight: level === "strong" ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
7141
7160
  },
7142
7161
  children: label
7143
7162
  }
@@ -7345,7 +7364,7 @@ function KjunSparkline({
7345
7364
 
7346
7365
  // shared/package-runtime/table.ts
7347
7366
  import { nextTableSort } from "@kjun-ui/tokens";
7348
- import { useEffect as useEffect23, useRef as useRef33, useState as useState34 } from "react";
7367
+ import { useEffect as useEffect24, useRef as useRef33, useState as useState35 } from "react";
7349
7368
 
7350
7369
  // shared/package-runtime/table-model.ts
7351
7370
  function getValue(row, key) {
@@ -7389,11 +7408,11 @@ function useTableModel(props) {
7389
7408
  expandSingle = false,
7390
7409
  onExpandedRowsChange
7391
7410
  } = props;
7392
- const [internalSort, setSort] = useState34({
7411
+ const [internalSort, setSort] = useState35({
7393
7412
  key: "",
7394
7413
  order: "asc"
7395
- }), [internalExpanded, setExpanded] = useState34([]), [search, setSearch] = useState34(""), timer = useRef33(void 0);
7396
- useEffect23(() => () => clearTimeout(timer.current), []);
7414
+ }), [internalExpanded, setExpanded] = useState35([]), [search, setSearch] = useState35(""), timer = useRef33(void 0);
7415
+ useEffect24(() => () => clearTimeout(timer.current), []);
7397
7416
  const sort = props.sort === void 0 ? internalSort : (_a = props.sort) != null ? _a : { key: "", order: "asc" };
7398
7417
  const rows = sortTableRows(data, sort, { sortable, sortMode });
7399
7418
  const key = (row, index = 0) => tableRowKey(row, rowKey, index);
@@ -7547,19 +7566,19 @@ function TableToolbar({
7547
7566
 
7548
7567
  // packages/native/src/table-grid.tsx
7549
7568
  import { tokens as tokens43 } from "@kjun-ui/tokens";
7550
- import { Fragment as Fragment15, useId as useId9, useState as useState35 } from "react";
7569
+ import { Fragment as Fragment15, useId as useId9, useState as useState36 } from "react";
7551
7570
  import Svg7, { Defs as Defs3, LinearGradient as LinearGradient3, Rect as Rect4, Stop as Stop3 } from "react-native-svg";
7552
7571
  import { ScrollView as ScrollView9, View as View37 } from "react-native";
7553
7572
  import { jsx as jsx43, jsxs as jsxs31 } from "react/jsx-runtime";
7554
- function TableGrid({ initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7573
+ function TableGrid({ initialLoading, skeletonRows, skeletonHidden, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7555
7574
  const { colors } = useKjunStyles();
7556
7575
  const geometry2 = tokens43.table;
7557
- const [scroll, setScroll] = useState35({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + useId9().replace(/[^a-z0-9]/gi, "");
7576
+ const [scroll, setScroll] = useState36({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + useId9().replace(/[^a-z0-9]/gi, "");
7558
7577
  const cellPadding = geometry2.cellPadding[compact ? "compact" : "regular"];
7559
7578
  const width = (col) => typeof col.width === "number" ? col.width : typeof col.width === "string" && /^\d+(px)?$/.test(col.width) ? parseFloat(col.width) : geometry2.columnWidth;
7560
7579
  const totalWidth = visible.reduce((sum, col) => sum + width(col), 0) + (selectable ? geometry2.actionColumnWidth : 0) + (expandable ? geometry2.actionColumnWidth : 0);
7561
7580
  const fade = totalWidth - scroll.viewport - scroll.x > 1;
7562
- return /* @__PURE__ */ jsxs31(View37, { style: { position: "relative", minWidth: 0 }, children: [
7581
+ return /* @__PURE__ */ jsxs31(View37, { style: { position: "relative", minWidth: 0, opacity: skeletonHidden ? 0 : void 0 }, "aria-hidden": skeletonHidden || void 0, children: [
7563
7582
  /* @__PURE__ */ jsx43(
7564
7583
  ScrollView9,
7565
7584
  {
@@ -7762,6 +7781,7 @@ import { jsx as jsx44, jsxs as jsxs32 } from "react/jsx-runtime";
7762
7781
  function TableCards({
7763
7782
  initialLoading,
7764
7783
  skeletonRows,
7784
+ skeletonHidden,
7765
7785
  state,
7766
7786
  onRowClick,
7767
7787
  selectable,
@@ -7776,149 +7796,156 @@ function TableCards({
7776
7796
  }) {
7777
7797
  const { colors } = useKjunStyles();
7778
7798
  const { title, subtitle, badges, inline, sections, actions, columnsForSection } = layout;
7779
- return /* @__PURE__ */ jsxs32(View38, { style: { gap: tokens44.extensions.tableCard.gap, padding: tokens44.extensions.tableCard.listPadding }, children: [
7780
- initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ jsx44(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ jsxs32(
7781
- AccessiblePressable,
7782
- {
7783
- accessible: false,
7784
- onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7785
- style: ({ pressed }) => ({
7786
- padding: tokens44.extensions.tableCard.padding,
7787
- borderWidth: tokens44.border.defaultWidth,
7788
- borderColor: colors.border,
7789
- borderRadius: tokens44.extensions.tableCard.radius,
7790
- backgroundColor: pressed ? colors.hover : colors.background
7791
- }),
7792
- children: [
7793
- /* @__PURE__ */ jsxs32(
7794
- View38,
7795
- {
7796
- style: {
7797
- flexDirection: "row",
7798
- alignItems: "center",
7799
- gap: tokens44.extensions.tableCard.gap,
7800
- marginBottom: tokens44.dimension.value8
7801
- },
7802
- children: [
7803
- /* @__PURE__ */ jsxs32(
7799
+ return /* @__PURE__ */ jsxs32(
7800
+ View38,
7801
+ {
7802
+ style: { gap: tokens44.extensions.tableCard.gap, padding: tokens44.extensions.tableCard.listPadding, opacity: skeletonHidden ? 0 : void 0 },
7803
+ "aria-hidden": skeletonHidden || void 0,
7804
+ children: [
7805
+ initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ jsx44(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ jsxs32(
7806
+ AccessiblePressable,
7807
+ {
7808
+ accessible: false,
7809
+ onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7810
+ style: ({ pressed }) => ({
7811
+ padding: tokens44.extensions.tableCard.padding,
7812
+ borderWidth: tokens44.border.defaultWidth,
7813
+ borderColor: colors.border,
7814
+ borderRadius: tokens44.extensions.tableCard.radius,
7815
+ backgroundColor: pressed ? colors.hover : colors.background
7816
+ }),
7817
+ children: [
7818
+ /* @__PURE__ */ jsxs32(
7819
+ View38,
7820
+ {
7821
+ style: {
7822
+ flexDirection: "row",
7823
+ alignItems: "center",
7824
+ gap: tokens44.extensions.tableCard.gap,
7825
+ marginBottom: tokens44.dimension.value8
7826
+ },
7827
+ children: [
7828
+ /* @__PURE__ */ jsxs32(
7829
+ View38,
7830
+ {
7831
+ style: {
7832
+ flexDirection: "row",
7833
+ flex: 1,
7834
+ alignItems: "center",
7835
+ gap: tokens44.extensions.tableCard.gap,
7836
+ minWidth: 0
7837
+ },
7838
+ children: [
7839
+ selectable && checkbox(row, i),
7840
+ title && /* @__PURE__ */ jsx44(View38, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7841
+ ]
7842
+ }
7843
+ ),
7844
+ badges.length ? /* @__PURE__ */ jsx44(View38, { style: { flexDirection: "row", gap: tokens44.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ jsx44(View38, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7845
+ inline.length > 0 && /* @__PURE__ */ jsx44(View38, { style: { flexDirection: "row", gap: tokens44.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ jsx44(View38, { children: cell(col, row, i) }, col.key)) })
7846
+ ]
7847
+ }
7848
+ ),
7849
+ sections.map((section, index) => {
7850
+ const cols = columnsForSection(row, section);
7851
+ return cols.length ? /* @__PURE__ */ jsxs32(
7804
7852
  View38,
7805
7853
  {
7806
7854
  style: {
7807
- flexDirection: "row",
7808
- flex: 1,
7809
- alignItems: "center",
7810
- gap: tokens44.extensions.tableCard.gap,
7811
- minWidth: 0
7855
+ borderTopWidth: index ? tokens44.border.defaultWidth : 0,
7856
+ borderTopColor: colors.border,
7857
+ paddingTop: index ? tokens44.dimension.value12 : 0,
7858
+ marginTop: index ? tokens44.dimension.value12 : 0
7812
7859
  },
7813
7860
  children: [
7814
- selectable && checkbox(row, i),
7815
- title && /* @__PURE__ */ jsx44(View38, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7816
- ]
7817
- }
7818
- ),
7819
- badges.length ? /* @__PURE__ */ jsx44(View38, { style: { flexDirection: "row", gap: tokens44.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ jsx44(View38, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7820
- inline.length > 0 && /* @__PURE__ */ jsx44(View38, { style: { flexDirection: "row", gap: tokens44.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ jsx44(View38, { children: cell(col, row, i) }, col.key)) })
7821
- ]
7822
- }
7823
- ),
7824
- sections.map((section, index) => {
7825
- const cols = columnsForSection(row, section);
7826
- return cols.length ? /* @__PURE__ */ jsxs32(
7827
- View38,
7828
- {
7829
- style: {
7830
- borderTopWidth: index ? tokens44.border.defaultWidth : 0,
7831
- borderTopColor: colors.border,
7832
- paddingTop: index ? tokens44.dimension.value12 : 0,
7833
- marginTop: index ? tokens44.dimension.value12 : 0
7834
- },
7835
- children: [
7836
- section.label && /* @__PURE__ */ jsx44(
7837
- KText,
7838
- {
7839
- style: {
7840
- ...typeStyle("controlSmall"),
7841
- color: colors.textTertiary,
7842
- marginBottom: tokens44.dimension.value6
7843
- },
7844
- children: section.label
7845
- }
7846
- ),
7847
- /* @__PURE__ */ jsx44(
7848
- View38,
7849
- {
7850
- style: {
7851
- flexDirection: "row",
7852
- flexWrap: "wrap",
7853
- gap: section.layout === "metrics" ? tokens44.extensions.tableCard.gap : tokens44.extensions.tableCard.metricGap
7854
- },
7855
- children: cols.map((col) => /* @__PURE__ */ jsxs32(
7861
+ section.label && /* @__PURE__ */ jsx44(
7862
+ KText,
7863
+ {
7864
+ style: {
7865
+ ...typeStyle("controlSmall"),
7866
+ color: colors.textTertiary,
7867
+ marginBottom: tokens44.dimension.value6
7868
+ },
7869
+ children: section.label
7870
+ }
7871
+ ),
7872
+ /* @__PURE__ */ jsx44(
7856
7873
  View38,
7857
7874
  {
7858
7875
  style: {
7859
- flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7860
- flexGrow: 1,
7861
- minWidth: 0,
7862
- gap: tokens44.extensions.tableCard.valueGap
7876
+ flexDirection: "row",
7877
+ flexWrap: "wrap",
7878
+ gap: section.layout === "metrics" ? tokens44.extensions.tableCard.gap : tokens44.extensions.tableCard.metricGap
7863
7879
  },
7864
- children: [
7865
- /* @__PURE__ */ jsx44(
7866
- KText,
7867
- {
7868
- style: {
7869
- ...typeStyle("meta"),
7870
- color: colors.textTertiary,
7871
- textAlign: section.labelAlign
7872
- },
7873
- children: col.label
7874
- }
7875
- ),
7876
- cell(col, row, i)
7877
- ]
7878
- },
7879
- col.key
7880
- ))
7881
- }
7882
- )
7883
- ]
7884
- },
7885
- section.key || index
7886
- ) : null;
7887
- }),
7888
- expandable && expand(row, i),
7889
- expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ jsx44(
7890
- View38,
7891
- {
7892
- style: {
7893
- borderTopWidth: tokens44.border.defaultWidth,
7894
- borderTopColor: colors.border,
7895
- paddingTop: tokens44.dimension.value8,
7896
- marginTop: tokens44.dimension.value4
7897
- },
7898
- children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7899
- }
7900
- ),
7901
- actions && !actions.inlineInCard && /* @__PURE__ */ jsx44(
7902
- View38,
7903
- {
7904
- style: {
7905
- borderTopWidth: tokens44.border.defaultWidth,
7906
- borderTopColor: colors.border,
7907
- paddingTop: tokens44.dimension.value8,
7908
- marginTop: tokens44.dimension.value8,
7909
- alignItems: "flex-end"
7910
- },
7911
- children: /* @__PURE__ */ jsx44(View38, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7912
- }
7913
- )
7914
- ]
7915
- },
7916
- state.key(row, i)
7917
- )),
7918
- !initialLoading && !state.rows.length && /* @__PURE__ */ jsx44(View38, { style: { padding: tokens44.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7919
- color: colors.textTertiary
7920
- }) })
7921
- ] });
7880
+ children: cols.map((col) => /* @__PURE__ */ jsxs32(
7881
+ View38,
7882
+ {
7883
+ style: {
7884
+ flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7885
+ flexGrow: 1,
7886
+ minWidth: 0,
7887
+ gap: tokens44.extensions.tableCard.valueGap
7888
+ },
7889
+ children: [
7890
+ /* @__PURE__ */ jsx44(
7891
+ KText,
7892
+ {
7893
+ style: {
7894
+ ...typeStyle("meta"),
7895
+ color: colors.textTertiary,
7896
+ textAlign: section.labelAlign
7897
+ },
7898
+ children: col.label
7899
+ }
7900
+ ),
7901
+ cell(col, row, i)
7902
+ ]
7903
+ },
7904
+ col.key
7905
+ ))
7906
+ }
7907
+ )
7908
+ ]
7909
+ },
7910
+ section.key || index
7911
+ ) : null;
7912
+ }),
7913
+ expandable && expand(row, i),
7914
+ expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ jsx44(
7915
+ View38,
7916
+ {
7917
+ style: {
7918
+ borderTopWidth: tokens44.border.defaultWidth,
7919
+ borderTopColor: colors.border,
7920
+ paddingTop: tokens44.dimension.value8,
7921
+ marginTop: tokens44.dimension.value4
7922
+ },
7923
+ children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7924
+ }
7925
+ ),
7926
+ actions && !actions.inlineInCard && /* @__PURE__ */ jsx44(
7927
+ View38,
7928
+ {
7929
+ style: {
7930
+ borderTopWidth: tokens44.border.defaultWidth,
7931
+ borderTopColor: colors.border,
7932
+ paddingTop: tokens44.dimension.value8,
7933
+ marginTop: tokens44.dimension.value8,
7934
+ alignItems: "flex-end"
7935
+ },
7936
+ children: /* @__PURE__ */ jsx44(View38, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7937
+ }
7938
+ )
7939
+ ]
7940
+ },
7941
+ state.key(row, i)
7942
+ )),
7943
+ !initialLoading && !state.rows.length && /* @__PURE__ */ jsx44(View38, { style: { padding: tokens44.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7944
+ color: colors.textTertiary
7945
+ }) })
7946
+ ]
7947
+ }
7948
+ );
7922
7949
  }
7923
7950
 
7924
7951
  // packages/native/src/table-view.tsx
@@ -7926,6 +7953,9 @@ import { jsx as jsx45, jsxs as jsxs33 } from "react/jsx-runtime";
7926
7953
  function KjunTable(props) {
7927
7954
  const {
7928
7955
  skeletonRows = 8,
7956
+ skeleton = true,
7957
+ loadingText = "\uB85C\uB529 \uC911...",
7958
+ loadingDelay = 0,
7929
7959
  emptyText = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
7930
7960
  hoverable = true,
7931
7961
  searchable = false,
@@ -7946,7 +7976,7 @@ function KjunTable(props) {
7946
7976
  onRowClick,
7947
7977
  onRetry
7948
7978
  } = props;
7949
- const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), mobile = useWindowDimensions7().width < tokens45.table.mobileBreakpoint;
7979
+ const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), revealed = useLoadingReveal(query.initialLoading, skeleton ? loadingDelay : 0), mobile = useWindowDimensions7().width < tokens45.table.mobileBreakpoint;
7950
7980
  const layout = tablePresentation(props, mobile);
7951
7981
  const { card, visible } = layout;
7952
7982
  const cell = (col, row, index, role) => {
@@ -8025,8 +8055,11 @@ function KjunTable(props) {
8025
8055
  refreshing: query.queryRefreshing,
8026
8056
  loadingPadding: "none",
8027
8057
  onRetry,
8058
+ loading: skeleton ? void 0 : props.loading,
8059
+ loadingText,
8060
+ loadingDelay: skeleton ? 0 : loadingDelay,
8028
8061
  children: [
8029
- card ? /* @__PURE__ */ jsx45(TableCards, { ...{ initialLoading: query.initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, layout } }) : /* @__PURE__ */ jsx45(TableGrid, { ...{ initialLoading: query.initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, compact, striped, hoverable }, sortable: props.sortable }),
8062
+ card ? /* @__PURE__ */ jsx45(TableCards, { ...{ initialLoading: query.initialLoading, skeletonRows, skeletonHidden: query.initialLoading && !revealed, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, layout } }) : /* @__PURE__ */ jsx45(TableGrid, { ...{ initialLoading: query.initialLoading, skeletonRows, skeletonHidden: query.initialLoading && !revealed, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, compact, striped, hoverable }, sortable: props.sortable }),
8030
8063
  pagination && /* @__PURE__ */ jsx45(
8031
8064
  KjunPagination,
8032
8065
  {
@@ -8087,12 +8120,13 @@ function KjunKpiHero(props) {
8087
8120
  secondary = [],
8088
8121
  animated = true,
8089
8122
  size = "md",
8123
+ surface = "card",
8090
8124
  aside,
8091
8125
  formatter,
8092
8126
  deltaFormatter,
8093
8127
  renderSecondary
8094
8128
  } = props;
8095
- const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = useWindowDimensions8().width <= tokens46.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
8129
+ const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), windowWidth = useWindowDimensions8().width, mobile = windowWidth <= tokens46.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
8096
8130
  const geometry2 = tokens46.extensions.kpiHero;
8097
8131
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8098
8132
  const numeric = {
@@ -8122,10 +8156,13 @@ function KjunKpiHero(props) {
8122
8156
  {
8123
8157
  accessibilityState: { busy: loading },
8124
8158
  style: {
8125
- paddingVertical: spec.paddingY,
8126
- paddingHorizontal: spec.paddingX,
8127
- backgroundColor: colors.surface,
8128
- borderRadius: geometry2.radius
8159
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
8160
+ ...surface === "none" ? {} : {
8161
+ paddingVertical: spec.paddingY,
8162
+ paddingHorizontal: spec.paddingX,
8163
+ backgroundColor: colors.surface,
8164
+ borderRadius: geometry2.radius
8165
+ }
8129
8166
  },
8130
8167
  children: [
8131
8168
  /* @__PURE__ */ jsxs35(
@@ -8208,70 +8245,75 @@ function KjunKpiHero(props) {
8208
8245
  borderTopWidth: tokens46.border.defaultWidth,
8209
8246
  borderTopColor: colors.border
8210
8247
  },
8211
- children: secondary.map((item, i) => /* @__PURE__ */ jsxs35(
8212
- View41,
8213
- {
8214
- style: mobile && !small ? {
8215
- flex: 1,
8216
- minWidth: 0,
8217
- paddingLeft: i ? geometry2.itemPadding : 0,
8218
- paddingRight: i === secondary.length - 1 ? 0 : geometry2.itemPadding,
8219
- borderLeftWidth: i ? tokens46.border.defaultWidth : 0,
8220
- borderLeftColor: colors.border
8221
- } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
8222
- children: [
8223
- /* @__PURE__ */ jsx47(
8224
- KText,
8225
- {
8226
- style: {
8227
- color: colors.textTertiary,
8228
- ...typeStyle("caption"),
8229
- marginBottom: spec.secondaryLabelGap
8230
- },
8231
- children: item.label
8232
- }
8233
- ),
8234
- loading ? /* @__PURE__ */ jsx47(
8235
- KjunSkeleton,
8236
- {
8237
- type: "block",
8238
- height: typeStyle("numberMd").lineHeight,
8239
- width: geometry2.secondarySkeletonWidth
8240
- }
8241
- ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ jsx47(
8242
- KpiNumberLine,
8243
- {
8244
- prefix: item.prefix,
8245
- suffix: item.suffix,
8246
- prefixGap: geometry2.secondaryAffixGap,
8247
- suffixGap: geometry2.secondaryAffixGap,
8248
- unitStyle: typeStyle("caption"),
8249
- style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
8250
- children: kpiFormat(item)
8251
- }
8252
- ),
8253
- item.desc && (loading ? /* @__PURE__ */ jsx47(
8254
- KjunSkeleton,
8255
- {
8256
- type: "block",
8257
- width: geometry2.descriptionSkeletonWidth,
8258
- height: typeStyle("caption").lineHeight
8259
- }
8260
- ) : /* @__PURE__ */ jsx47(
8261
- KText,
8262
- {
8263
- style: {
8264
- ...typeStyle("caption"),
8265
- marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8266
- color: item.descColor || colors.textTertiary
8267
- },
8268
- children: item.desc
8269
- }
8270
- ))
8271
- ]
8272
- },
8273
- i
8274
- ))
8248
+ children: secondary.map((item, i) => {
8249
+ const columns = mobile && !small && windowWidth <= tokens46.responsive.kpiHeroSecondary && secondary.length >= 3 ? 2 : 0;
8250
+ const first = columns ? i % columns === 0 : i === 0;
8251
+ const last = columns ? i % columns === columns - 1 || i === secondary.length - 1 : i === secondary.length - 1;
8252
+ return /* @__PURE__ */ jsxs35(
8253
+ View41,
8254
+ {
8255
+ style: mobile && !small ? {
8256
+ ...columns ? { width: `${100 / columns}%`, marginTop: i >= columns ? spec.secondaryPadding : 0 } : { flex: 1 },
8257
+ minWidth: 0,
8258
+ paddingLeft: first ? 0 : geometry2.itemPadding,
8259
+ paddingRight: last ? 0 : geometry2.itemPadding,
8260
+ borderLeftWidth: first ? 0 : tokens46.border.defaultWidth,
8261
+ borderLeftColor: colors.border
8262
+ } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
8263
+ children: [
8264
+ /* @__PURE__ */ jsx47(
8265
+ KText,
8266
+ {
8267
+ style: {
8268
+ color: colors.textTertiary,
8269
+ ...typeStyle("caption"),
8270
+ marginBottom: spec.secondaryLabelGap
8271
+ },
8272
+ children: item.label
8273
+ }
8274
+ ),
8275
+ loading ? /* @__PURE__ */ jsx47(
8276
+ KjunSkeleton,
8277
+ {
8278
+ type: "block",
8279
+ height: typeStyle("numberMd").lineHeight,
8280
+ width: geometry2.secondarySkeletonWidth
8281
+ }
8282
+ ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ jsx47(
8283
+ KpiNumberLine,
8284
+ {
8285
+ prefix: item.prefix,
8286
+ suffix: item.suffix,
8287
+ prefixGap: geometry2.secondaryAffixGap,
8288
+ suffixGap: geometry2.secondaryAffixGap,
8289
+ unitStyle: typeStyle("caption"),
8290
+ style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
8291
+ children: kpiFormat(item)
8292
+ }
8293
+ ),
8294
+ item.desc && (loading ? /* @__PURE__ */ jsx47(
8295
+ KjunSkeleton,
8296
+ {
8297
+ type: "block",
8298
+ width: geometry2.descriptionSkeletonWidth,
8299
+ height: typeStyle("caption").lineHeight
8300
+ }
8301
+ ) : /* @__PURE__ */ jsx47(
8302
+ KText,
8303
+ {
8304
+ style: {
8305
+ ...typeStyle("caption"),
8306
+ marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8307
+ color: item.descColor || colors.textTertiary
8308
+ },
8309
+ children: item.desc
8310
+ }
8311
+ ))
8312
+ ]
8313
+ },
8314
+ i
8315
+ );
8316
+ })
8275
8317
  }
8276
8318
  )
8277
8319
  ]
@@ -8281,7 +8323,7 @@ function KjunKpiHero(props) {
8281
8323
 
8282
8324
  // packages/native/src/kpi-row.tsx
8283
8325
  import { tokens as tokens47 } from "@kjun-ui/tokens";
8284
- import { useState as useState36 } from "react";
8326
+ import { useState as useState37 } from "react";
8285
8327
  import {
8286
8328
  Text as Text6,
8287
8329
  View as View42,
@@ -8292,6 +8334,7 @@ function KjunKpiRow({
8292
8334
  loading = false,
8293
8335
  items,
8294
8336
  size = "md",
8337
+ surface = "card",
8295
8338
  mobileSummary = true,
8296
8339
  onItemClick,
8297
8340
  renderValue
@@ -8299,7 +8342,7 @@ function KjunKpiRow({
8299
8342
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = useWindowDimensions9().width <= tokens47.responsive.kpiRow, small = size === "sm", summary = mobileSummary && mobile && !small;
8300
8343
  const geometry2 = tokens47.extensions.kpiRow;
8301
8344
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8302
- const [width, setWidth] = useState36(0);
8345
+ const [width, setWidth] = useState37(0);
8303
8346
  const paddingX = summary ? geometry2.summary.paddingX : spec.paddingX;
8304
8347
  const gapX = summary ? geometry2.summary.gapX : 0;
8305
8348
  const explicit = items.some(
@@ -8340,10 +8383,13 @@ function KjunKpiRow({
8340
8383
  style: {
8341
8384
  flexDirection: "row",
8342
8385
  flexWrap: mobile ? "wrap" : "nowrap",
8343
- paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8344
- paddingHorizontal: paddingX,
8345
- borderRadius: geometry2.radius,
8346
- backgroundColor: colors.surface,
8386
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
8387
+ ...surface === "none" ? {} : {
8388
+ paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8389
+ paddingHorizontal: paddingX,
8390
+ borderRadius: geometry2.radius,
8391
+ backgroundColor: colors.surface
8392
+ },
8347
8393
  rowGap: summary ? geometry2.summary.gapY : 0,
8348
8394
  columnGap: gapX
8349
8395
  },
@@ -8515,7 +8561,7 @@ import { tokens as tokens49 } from "@kjun-ui/tokens";
8515
8561
  import { ScrollView as ScrollView10, View as View44 } from "react-native";
8516
8562
 
8517
8563
  // shared/package-runtime/market-cards.ts
8518
- import { useEffect as useEffect24, useRef as useRef34, useState as useState37 } from "react";
8564
+ import { useEffect as useEffect25, useRef as useRef34, useState as useState38 } from "react";
8519
8565
  function useMarketCardsModel(props, persistence) {
8520
8566
  const {
8521
8567
  columns,
@@ -8531,7 +8577,7 @@ function useMarketCardsModel(props, persistence) {
8531
8577
  sortKey: c.sortable ? metricConfig[c.key].sortKey : null,
8532
8578
  isDefaultSort: c.defaultSort
8533
8579
  }));
8534
- const [key, setKey] = useState37(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8580
+ const [key, setKey] = useState38(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8535
8581
  const mounted = useRef34("");
8536
8582
  const save = (key2) => {
8537
8583
  var _a;
@@ -8540,7 +8586,7 @@ function useMarketCardsModel(props, persistence) {
8540
8586
  } catch (e) {
8541
8587
  }
8542
8588
  };
8543
- useEffect24(() => {
8589
+ useEffect25(() => {
8544
8590
  var _a, _b;
8545
8591
  if (mounted.current === restoreSignature) return;
8546
8592
  mounted.current = restoreSignature;
@@ -8782,7 +8828,7 @@ function KjunMarketCards(props) {
8782
8828
  ...props,
8783
8829
  loadingPadding: "none",
8784
8830
  empty: !rows.length,
8785
- loadingContent: /* @__PURE__ */ jsx50(KjunListSkeleton, { variant: "compact" }),
8831
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx50(KjunListSkeleton, { variant: "compact" }),
8786
8832
  emptyContent: /* @__PURE__ */ jsx50(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8787
8833
  children: /* @__PURE__ */ jsxs38(View44, { children: [
8788
8834
  state.pill && /* @__PURE__ */ jsx50(KText, { style: { textAlign: "right", paddingHorizontal: tokens49.dimension.value16, paddingVertical: tokens49.dimension.value8, ...typeStyle("caption"), color: colors.textSecondary }, children: state.pill.label }),
@@ -8893,7 +8939,7 @@ function KjunMarketSimpleList(props) {
8893
8939
  loadingPadding: "none",
8894
8940
  empty: !rows.length,
8895
8941
  emptyText: emptyMessage,
8896
- loadingContent: /* @__PURE__ */ jsx51(KjunListSkeleton, {}),
8942
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx51(KjunListSkeleton, {}),
8897
8943
  emptyContent: /* @__PURE__ */ jsx51(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8898
8944
  children: /* @__PURE__ */ jsx51(View45, { children: rows.map((row, i) => {
8899
8945
  var _a, _b;
@@ -9020,7 +9066,7 @@ function KjunMarketListPanel({
9020
9066
 
9021
9067
  // packages/native/src/market-table.tsx
9022
9068
  import { tokens as tokens52 } from "@kjun-ui/tokens";
9023
- import { useId as useId10, useState as useState38 } from "react";
9069
+ import { useId as useId10, useState as useState39 } from "react";
9024
9070
  import { ScrollView as ScrollView11, View as View47 } from "react-native";
9025
9071
  import Svg8, { Defs as Defs4, LinearGradient as LinearGradient4, Rect as Rect5, Stop as Stop4 } from "react-native-svg";
9026
9072
  import { jsx as jsx53, jsxs as jsxs41 } from "react/jsx-runtime";
@@ -9106,7 +9152,7 @@ function KjunMarketTable(props) {
9106
9152
  );
9107
9153
  };
9108
9154
  const layout = useMarketLayout(columns, showActions);
9109
- const [scroll, setScroll] = useState38({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + useId10().replace(/[^a-z0-9]/gi, "");
9155
+ const [scroll, setScroll] = useState39({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + useId10().replace(/[^a-z0-9]/gi, "");
9110
9156
  const tableQuote = { price: {}, change: { fontWeight: typeStyle("body").fontWeight } };
9111
9157
  return /* @__PURE__ */ jsxs41(
9112
9158
  View47,
@@ -9124,7 +9170,7 @@ function KjunMarketTable(props) {
9124
9170
  loadingPadding: "none",
9125
9171
  empty: !rows.length,
9126
9172
  emptyText: emptyMessage,
9127
- loadingContent: /* @__PURE__ */ jsx53(KjunMarketTableSkeleton, { columns, showActions }),
9173
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx53(KjunMarketTableSkeleton, { columns, showActions }),
9128
9174
  emptyContent: /* @__PURE__ */ jsx53(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
9129
9175
  children: /* @__PURE__ */ jsx53(MarketQuoteTypeContext.Provider, { value: tableQuote, children: /* @__PURE__ */ jsxs41(View47, { style: { position: "relative", minWidth: 0 }, children: [
9130
9176
  /* @__PURE__ */ jsx53(
@@ -9365,7 +9411,7 @@ function KjunListSection({ title, description, actions, children, ariaLabel }) {
9365
9411
 
9366
9412
  // packages/native/src/app-navigation.tsx
9367
9413
  import { tokens as tokens54 } from "@kjun-ui/tokens";
9368
- import { Children as Children5, Fragment as Fragment20, isValidElement as isValidElement7, useState as useState39 } from "react";
9414
+ import { Children as Children5, Fragment as Fragment20, isValidElement as isValidElement7, useState as useState40 } from "react";
9369
9415
  import { View as View49, Platform as Platform25 } from "react-native";
9370
9416
  import { jsx as jsx55, jsxs as jsxs43 } from "react/jsx-runtime";
9371
9417
  function KjunTopNavigation({ title, description, leading, actions, safeAreaTop = 0 }) {
@@ -9374,7 +9420,7 @@ function KjunTopNavigation({ title, description, leading, actions, safeAreaTop =
9374
9420
  const titleInset = Math.max(0, (geometry2.controlSize - tokens54.typography.sectionTitle.lineHeightPx) / 2);
9375
9421
  const wrapping = Platform25.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
9376
9422
  const edgeInset = (geometry2.controlSize - geometry2.iconSize) / 2;
9377
- const [iconEdges, setIconEdges] = useState39({ leading: false, trailing: false });
9423
+ const [iconEdges, setIconEdges] = useState40({ leading: false, trailing: false });
9378
9424
  const square = (key) => (event) => {
9379
9425
  const { width, height } = event.nativeEvent.layout;
9380
9426
  const next = Math.abs(width - height) < 1 && Math.abs(height - geometry2.controlSize) < 1;
@@ -9454,7 +9500,7 @@ function KjunBottomNavigation({ items, value, ariaLabel = "\uC8FC\uC694 \uD0D0\u
9454
9500
  }
9455
9501
  function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboardVisible = false, hideOnKeyboard = false }) {
9456
9502
  const { colors } = useKjunStyles();
9457
- const [width, setWidth] = useState39(0);
9503
+ const [width, setWidth] = useState40(0);
9458
9504
  const geometry2 = tokens54.extensions.navigation;
9459
9505
  const wide = width >= tokens54.responsive.bottomAction + geometry2.padding * 2;
9460
9506
  const wrapping = Platform25.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
@@ -9476,7 +9522,7 @@ function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboa
9476
9522
  }
9477
9523
 
9478
9524
  // packages/native/src/media.tsx
9479
- import { useRef as useRef35, useState as useState40 } from "react";
9525
+ import { useRef as useRef35, useState as useState41 } from "react";
9480
9526
  import { Image, View as View50 } from "react-native";
9481
9527
  import { tokens as tokens55 } from "@kjun-ui/tokens";
9482
9528
  import { jsx as jsx56 } from "react/jsx-runtime";
@@ -9485,7 +9531,7 @@ function KjunImage({ src, source, alt, decorative = false, aspectRatio = 1, fit
9485
9531
  const request = JSON.stringify(source != null ? source : src), current = useRef35({ request, version: 0 });
9486
9532
  if (current.current.request !== request) current.current = { request, version: current.current.version + 1 };
9487
9533
  const version = current.current.version;
9488
- const [failed, setFailed] = useState40(null);
9534
+ const [failed, setFailed] = useState41(null);
9489
9535
  const missing = !source && !src;
9490
9536
  return /* @__PURE__ */ jsx56(View50, { accessibilityElementsHidden: decorative, importantForAccessibility: decorative ? "no-hide-descendants" : "auto", "aria-hidden": decorative || void 0, style: { width: "100%", aspectRatio: aspectRatio > 0 ? aspectRatio : 1, overflow: "hidden", backgroundColor: colors.secondary }, children: !missing && failed !== version ? /* @__PURE__ */ jsx56(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: () => {
9491
9537
  if (version === current.current.version) onLoad == null ? void 0 : onLoad();
@@ -9515,7 +9561,7 @@ function KjunChip({ label, icon, removable = false, disabled = false, size = "md
9515
9561
  }
9516
9562
 
9517
9563
  // packages/native/src/range-input.tsx
9518
- import { useEffect as useEffect25, useMemo as useMemo2, useRef as useRef36, useState as useState41 } from "react";
9564
+ import { useEffect as useEffect26, useMemo as useMemo2, useRef as useRef36, useState as useState42 } from "react";
9519
9565
  import { PanResponder, Platform as Platform26, Pressable as Pressable3, View as View52 } from "react-native";
9520
9566
  import { tokens as tokens57, createSliderDomain, sliderKey } from "@kjun-ui/tokens";
9521
9567
  import { jsx as jsx58, jsxs as jsxs45 } from "react/jsx-runtime";
@@ -9539,18 +9585,18 @@ function RangeInput({
9539
9585
  const valid = domain.valid && (!Array.isArray(value) || value.length === 2) && values.every(domain.accepts) && (values.length === 1 || values[0] <= values[1]);
9540
9586
  const blocked = disabled || !valid;
9541
9587
  const effectiveMax = valid ? domain.snap(max) : min;
9542
- const [hovered, setHovered] = useState41(null);
9543
- const [dragging, setDragging] = useState41(null);
9544
- const [focused, setFocused] = useState41(null);
9588
+ const [hovered, setHovered] = useState42(null);
9589
+ const [dragging, setDragging] = useState42(null);
9590
+ const [focused, setFocused] = useState42(null);
9545
9591
  const track = useRef36(null), measured = useRef36({ x: 0, width: 1 }), selected = useRef36(0), dirty = useRef36(false);
9546
9592
  const latest = useRef36(values);
9547
9593
  latest.current = values;
9548
9594
  const callbacks = useRef36({ onValueChange, onChangeCommit });
9549
9595
  callbacks.current = { onValueChange, onChangeCommit };
9550
- useEffect25(() => {
9596
+ useEffect26(() => {
9551
9597
  if (!valid) console.warn("KJUN Slider: \uBC94\uC704\xB7step\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9552
9598
  }, [valid]);
9553
- useEffect25(() => {
9599
+ useEffect26(() => {
9554
9600
  if (blocked) {
9555
9601
  setDragging(null);
9556
9602
  setHovered(null);
@@ -9815,7 +9861,7 @@ function KjunRangeSlider(props) {
9815
9861
  }
9816
9862
 
9817
9863
  // packages/native/src/quantity-stepper.tsx
9818
- import { useEffect as useEffect26, useRef as useRef37, useState as useState42 } from "react";
9864
+ import { useEffect as useEffect27, useRef as useRef37, useState as useState43 } from "react";
9819
9865
  import { Platform as Platform27, View as View53 } from "react-native";
9820
9866
  import { createNumberDomain, quantityKeyAction, tokens as tokens58 } from "@kjun-ui/tokens";
9821
9867
 
@@ -9837,16 +9883,16 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9837
9883
  const increaseStyle = { ...buttonStyle, borderRadius: 0, borderTopRightRadius: outer, borderBottomRightRadius: outer };
9838
9884
  const domain = createNumberDomain({ min, max, step, precision }), valid = domain.valid && domain.accepts(value), blocked = disabled || !valid;
9839
9885
  const surface = useFieldSurface(size, { disabled: blocked, invalid });
9840
- const [draft, setDraft] = useState42(String(value));
9886
+ const [draft, setDraft] = useState43(String(value));
9841
9887
  const inputRef = useRef37(null);
9842
9888
  const composing = useRef37(false), dirty = useRef37(false), accepted = useRef37(value);
9843
9889
  const cancelledEscape = useRef37(false);
9844
- useEffect26(() => {
9890
+ useEffect27(() => {
9845
9891
  setDraft(String(value));
9846
9892
  accepted.current = value;
9847
9893
  dirty.current = false;
9848
9894
  }, [value, precision, min, max, step]);
9849
- useEffect26(() => {
9895
+ useEffect27(() => {
9850
9896
  if (!valid) console.warn("KJUN QuantityStepper: \uBC94\uC704\xB7step\xB7\uC815\uBC00\uB3C4\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9851
9897
  }, [valid]);
9852
9898
  const emit = (next) => {
@@ -9891,7 +9937,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9891
9937
  dirty.current = true;
9892
9938
  setDraft(text);
9893
9939
  } };
9894
- useEffect26(() => {
9940
+ useEffect27(() => {
9895
9941
  if (Platform27.OS !== "web") return;
9896
9942
  const input = inputRef.current;
9897
9943
  const keydown = (event) => handlers.current.key(event);
@@ -9963,7 +10009,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9963
10009
  }
9964
10010
 
9965
10011
  // packages/native/src/time-picker.tsx
9966
- import { Fragment as Fragment21, useEffect as useEffect27, useId as useId11, useMemo as useMemo3, useRef as useRef38, useState as useState43 } from "react";
10012
+ import { Fragment as Fragment21, useEffect as useEffect28, useId as useId11, useMemo as useMemo3, useRef as useRef38, useState as useState44 } from "react";
9967
10013
  import { View as View54 } from "react-native";
9968
10014
  import { createTimeDomain, tokens as tokens59 } from "@kjun-ui/tokens";
9969
10015
  import { jsx as jsx60, jsxs as jsxs47 } from "react/jsx-runtime";
@@ -9971,11 +10017,11 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
9971
10017
  const geometry2 = tokens59.extensions.timePicker, spec = tokens59.input[size];
9972
10018
  const { colors } = useKjunStyles();
9973
10019
  const first = useRef38(null);
9974
- const [focused, setFocused] = useState43(false), [opened, setOpened] = useState43(null);
10020
+ const [focused, setFocused] = useState44(false), [opened, setOpened] = useState44(null);
9975
10021
  const field = useKjunField(), uid = useId11();
9976
10022
  const fieldId = (field == null ? void 0 : field.id) || `kjun-time-${uid}`;
9977
10023
  const domain = useMemo3(() => createTimeDomain({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
9978
- useEffect27(() => {
10024
+ useEffect28(() => {
9979
10025
  if (!valid) console.warn("KJUN TimePicker: \uC2DC\uAC01 \uBC94\uC704\xB7\uAC04\uACA9\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9980
10026
  }, [valid]);
9981
10027
  const change = (next) => {