@kjun-ui/native 0.6.1 → 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.js CHANGED
@@ -6109,12 +6109,27 @@ import {
6109
6109
  initialQueryDisplay,
6110
6110
  queryDisplayStatus
6111
6111
  } from "@kjun-ui/tokens";
6112
- import { Component, useState as useState29 } from "react";
6112
+ import { Component, useState as useState30 } from "react";
6113
6113
  import { Platform as Platform23, View as View30 } from "react-native";
6114
+
6115
+ // shared/package-runtime/use-loading-reveal.ts
6116
+ import { useEffect as useEffect21, useState as useState29 } from "react";
6117
+ function useLoadingReveal(active, delay = 0) {
6118
+ const [revealed, setRevealed] = useState29(false);
6119
+ useEffect21(() => {
6120
+ setRevealed(false);
6121
+ if (!active || delay <= 0) return;
6122
+ const timer = setTimeout(() => setRevealed(true), delay);
6123
+ return () => clearTimeout(timer);
6124
+ }, [active, delay]);
6125
+ return delay <= 0 || revealed;
6126
+ }
6127
+
6128
+ // packages/native/src/data-state.tsx
6114
6129
  import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
6115
6130
  function useQueryDisplay(props) {
6116
6131
  var _a;
6117
- const [state, setState] = useState29(() => initialQueryDisplay(props));
6132
+ const [state, setState] = useState30(() => initialQueryDisplay(props));
6118
6133
  let next = state;
6119
6134
  if (state.queryKey !== ((_a = props.queryKey) != null ? _a : null) || state.resultKey !== props.resultKey || state.loading !== !!props.loading) {
6120
6135
  next = advanceQueryDisplay(state, props);
@@ -6133,6 +6148,7 @@ function KjunDataState({
6133
6148
  emptyIcon,
6134
6149
  emptyActionText,
6135
6150
  loadingText = "\uB85C\uB529 \uC911...",
6151
+ loadingDelay = 0,
6136
6152
  retryText = "\uB2E4\uC2DC \uC2DC\uB3C4",
6137
6153
  size = "md",
6138
6154
  skeleton = false,
@@ -6146,7 +6162,7 @@ function KjunDataState({
6146
6162
  onEmptyAction,
6147
6163
  ...query
6148
6164
  }) {
6149
- 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 = tokens33.extensions.state.padding[size];
6165
+ 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 = tokens33.extensions.state.padding[size], revealed = useLoadingReveal(state.initialLoading, loadingDelay);
6150
6166
  const { colors } = useKjunStyles();
6151
6167
  return /* @__PURE__ */ jsxs24(
6152
6168
  View30,
@@ -6179,8 +6195,10 @@ function KjunDataState({
6179
6195
  state.initialLoading ? /* @__PURE__ */ jsx37(
6180
6196
  View30,
6181
6197
  {
6182
- accessibilityLabel: loadingText,
6183
- style: { paddingVertical: loadingPadding === "none" ? 0 : padding },
6198
+ accessibilityLabel: revealed ? loadingText : void 0,
6199
+ "aria-hidden": revealed ? void 0 : true,
6200
+ importantForAccessibility: revealed ? void 0 : "no-hide-descendants",
6201
+ style: { paddingVertical: loadingPadding === "none" ? 0 : padding, opacity: revealed ? void 0 : 0 },
6184
6202
  children: loadingContent || (skeleton ? /* @__PURE__ */ jsx37(View30, { style: { gap: tokens33.dimension.value12 }, children: Array.from({ length: skeletonCount }, (_, i) => /* @__PURE__ */ jsx37(KjunSkeleton, { type: skeletonType }, i)) }) : /* @__PURE__ */ jsxs24(View30, { style: { alignItems: "center", gap: tokens33.dimension.value12 }, children: [
6185
6203
  /* @__PURE__ */ jsx37(KjunSpinner, { size: "md" }),
6186
6204
  /* @__PURE__ */ jsx37(KText, { style: { ...typeStyle("body"), color: colors.textSecondary, textAlign: "center", maxWidth: "100%" }, children: loadingText })
@@ -6261,7 +6279,7 @@ var KjunErrorBoundary = class extends Component {
6261
6279
 
6262
6280
  // packages/native/src/skeletons.tsx
6263
6281
  import { tokens as tokens37 } from "@kjun-ui/tokens";
6264
- import { Fragment as Fragment11, useEffect as useEffect21, useRef as useRef28 } from "react";
6282
+ import { Fragment as Fragment11, useEffect as useEffect22, useRef as useRef28 } from "react";
6265
6283
  import { Animated as Animated17, View as View32, useWindowDimensions as useWindowDimensions6 } from "react-native";
6266
6284
  import Svg5, { G as G2, Path as Path4, Rect as Rect3 } from "react-native-svg";
6267
6285
 
@@ -6290,9 +6308,9 @@ function nativeMarketLayout(columns, showActions, containerWidth) {
6290
6308
 
6291
6309
  // packages/native/src/market-layout.ts
6292
6310
  import { tokens as tokens35 } from "@kjun-ui/tokens";
6293
- import { useState as useState30 } from "react";
6311
+ import { useState as useState31 } from "react";
6294
6312
  function useMarketLayout(columns, showActions) {
6295
- const [containerWidth, setContainerWidth] = useState30(0);
6313
+ const [containerWidth, setContainerWidth] = useState31(0);
6296
6314
  const onLayout = (event) => setContainerWidth(event.nativeEvent.layout.width);
6297
6315
  return { ...nativeMarketLayout(columns, showActions, containerWidth), onLayout };
6298
6316
  }
@@ -6428,7 +6446,7 @@ function KjunChartSkeleton({
6428
6446
  height = tokens37.extensions.chartSkeleton.height
6429
6447
  }) {
6430
6448
  const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = useRef28(new Animated17.Value(1)).current;
6431
- useEffect21(() => {
6449
+ useEffect22(() => {
6432
6450
  if (reduced) return;
6433
6451
  const loop = Animated17.loop(
6434
6452
  Animated17.sequence([
@@ -6540,7 +6558,7 @@ function KjunChartSkeleton({
6540
6558
  }
6541
6559
 
6542
6560
  // packages/native/src/financial-display.tsx
6543
- import { tokens as tokens40 } from "@kjun-ui/tokens";
6561
+ import { deviationLevel, tokens as tokens40 } from "@kjun-ui/tokens";
6544
6562
  import { useId as useId8 } from "react";
6545
6563
  import {
6546
6564
  View as View34
@@ -6558,7 +6576,7 @@ import Svg6, {
6558
6576
  import { tokens as tokens39 } from "@kjun-ui/tokens";
6559
6577
 
6560
6578
  // shared/package-runtime/use-number-motion.ts
6561
- import { useLayoutEffect as useLayoutEffect12, useRef as useRef29, useState as useState31 } from "react";
6579
+ import { useLayoutEffect as useLayoutEffect12, useRef as useRef29, useState as useState32 } from "react";
6562
6580
 
6563
6581
  // shared/package-runtime/number-motion.ts
6564
6582
  import { tokens as tokens38 } from "@kjun-ui/tokens";
@@ -6604,7 +6622,7 @@ function createNumberMotion(apply) {
6604
6622
 
6605
6623
  // shared/package-runtime/use-number-motion.ts
6606
6624
  function useNumberMotion(value, animated, fromPrevious, reduced) {
6607
- const [display, setDisplay] = useState31(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6625
+ const [display, setDisplay] = useState32(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6608
6626
  const motion = useRef29(null);
6609
6627
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
6610
6628
  useLayoutEffect12(() => {
@@ -6790,6 +6808,7 @@ function KjunSignedValue({
6790
6808
 
6791
6809
  // packages/native/src/financial-display.tsx
6792
6810
  import { Fragment as Fragment12, jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
6811
+ var deviationFill = { neutral: 1, low: tokens40.states.opacity.deviationLow, medium: tokens40.states.opacity.deviationMedium, strong: tokens40.states.opacity.deviationStrong };
6793
6812
  function KjunDeviation({
6794
6813
  value,
6795
6814
  variant = "pill",
@@ -6800,7 +6819,7 @@ function KjunDeviation({
6800
6819
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), n = finiteNumber(value);
6801
6820
  if (n === null)
6802
6821
  return /* @__PURE__ */ jsx41(KText, { style: { color: colors.textDisabled }, children: "-" });
6803
- 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) + "%";
6822
+ 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) + "%";
6804
6823
  if (variant === "badge")
6805
6824
  return /* @__PURE__ */ jsxs28(
6806
6825
  View34,
@@ -6869,7 +6888,7 @@ function KjunDeviation({
6869
6888
  inset: 0,
6870
6889
  borderRadius: tokens40.extensions.financial.cellRadius,
6871
6890
  backgroundColor: neutral ? colors.secondary : color,
6872
- opacity: neutral ? 1 : abs < 0.5 ? 0.08 : abs < 1 ? 0.14 : 0.22
6891
+ opacity: deviationFill[level]
6873
6892
  }
6874
6893
  }
6875
6894
  ),
@@ -6882,7 +6901,7 @@ function KjunDeviation({
6882
6901
  fontVariant: ["tabular-nums"],
6883
6902
  ...typeStyle("body"),
6884
6903
  // Like Web: control weight, stronger once the deviation reaches 1%.
6885
- fontWeight: abs >= 1 ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
6904
+ fontWeight: level === "strong" ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
6886
6905
  },
6887
6906
  children: label
6888
6907
  }
@@ -7090,7 +7109,7 @@ function KjunSparkline({
7090
7109
 
7091
7110
  // shared/package-runtime/table.ts
7092
7111
  import { nextTableSort } from "@kjun-ui/tokens";
7093
- import { useEffect as useEffect23, useRef as useRef31, useState as useState33 } from "react";
7112
+ import { useEffect as useEffect24, useRef as useRef31, useState as useState34 } from "react";
7094
7113
 
7095
7114
  // shared/package-runtime/table-model.ts
7096
7115
  function getValue(row, key) {
@@ -7134,11 +7153,11 @@ function useTableModel(props) {
7134
7153
  expandSingle = false,
7135
7154
  onExpandedRowsChange
7136
7155
  } = props;
7137
- const [internalSort, setSort] = useState33({
7156
+ const [internalSort, setSort] = useState34({
7138
7157
  key: "",
7139
7158
  order: "asc"
7140
- }), [internalExpanded, setExpanded] = useState33([]), [search, setSearch] = useState33(""), timer = useRef31(void 0);
7141
- useEffect23(() => () => clearTimeout(timer.current), []);
7159
+ }), [internalExpanded, setExpanded] = useState34([]), [search, setSearch] = useState34(""), timer = useRef31(void 0);
7160
+ useEffect24(() => () => clearTimeout(timer.current), []);
7142
7161
  const sort = props.sort === void 0 ? internalSort : (_a = props.sort) != null ? _a : { key: "", order: "asc" };
7143
7162
  const rows = sortTableRows(data, sort, { sortable, sortMode });
7144
7163
  const key = (row, index = 0) => tableRowKey(row, rowKey, index);
@@ -7292,19 +7311,19 @@ function TableToolbar({
7292
7311
 
7293
7312
  // packages/native/src/table-grid.tsx
7294
7313
  import { tokens as tokens42 } from "@kjun-ui/tokens";
7295
- import { Fragment as Fragment14, useId as useId9, useState as useState34 } from "react";
7314
+ import { Fragment as Fragment14, useId as useId9, useState as useState35 } from "react";
7296
7315
  import Svg7, { Defs as Defs3, LinearGradient as LinearGradient3, Rect as Rect4, Stop as Stop3 } from "react-native-svg";
7297
7316
  import { ScrollView as ScrollView9, View as View36 } from "react-native";
7298
7317
  import { jsx as jsx43, jsxs as jsxs30 } from "react/jsx-runtime";
7299
- function TableGrid({ initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7318
+ function TableGrid({ initialLoading, skeletonRows, skeletonHidden, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7300
7319
  const { colors } = useKjunStyles();
7301
7320
  const geometry2 = tokens42.table;
7302
- const [scroll, setScroll] = useState34({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + useId9().replace(/[^a-z0-9]/gi, "");
7321
+ const [scroll, setScroll] = useState35({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + useId9().replace(/[^a-z0-9]/gi, "");
7303
7322
  const cellPadding = geometry2.cellPadding[compact ? "compact" : "regular"];
7304
7323
  const width = (col) => typeof col.width === "number" ? col.width : typeof col.width === "string" && /^\d+(px)?$/.test(col.width) ? parseFloat(col.width) : geometry2.columnWidth;
7305
7324
  const totalWidth = visible.reduce((sum, col) => sum + width(col), 0) + (selectable ? geometry2.actionColumnWidth : 0) + (expandable ? geometry2.actionColumnWidth : 0);
7306
7325
  const fade = totalWidth - scroll.viewport - scroll.x > 1;
7307
- return /* @__PURE__ */ jsxs30(View36, { style: { position: "relative", minWidth: 0 }, children: [
7326
+ return /* @__PURE__ */ jsxs30(View36, { style: { position: "relative", minWidth: 0, opacity: skeletonHidden ? 0 : void 0 }, "aria-hidden": skeletonHidden || void 0, children: [
7308
7327
  /* @__PURE__ */ jsx43(
7309
7328
  ScrollView9,
7310
7329
  {
@@ -7507,6 +7526,7 @@ import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
7507
7526
  function TableCards({
7508
7527
  initialLoading,
7509
7528
  skeletonRows,
7529
+ skeletonHidden,
7510
7530
  state,
7511
7531
  onRowClick,
7512
7532
  selectable,
@@ -7521,149 +7541,156 @@ function TableCards({
7521
7541
  }) {
7522
7542
  const { colors } = useKjunStyles();
7523
7543
  const { title, subtitle, badges, inline, sections, actions, columnsForSection } = layout;
7524
- return /* @__PURE__ */ jsxs31(View37, { style: { gap: tokens43.extensions.tableCard.gap, padding: tokens43.extensions.tableCard.listPadding }, children: [
7525
- initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ jsx44(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ jsxs31(
7526
- AccessiblePressable,
7527
- {
7528
- accessible: false,
7529
- onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7530
- style: ({ pressed }) => ({
7531
- padding: tokens43.extensions.tableCard.padding,
7532
- borderWidth: tokens43.border.defaultWidth,
7533
- borderColor: colors.border,
7534
- borderRadius: tokens43.extensions.tableCard.radius,
7535
- backgroundColor: pressed ? colors.hover : colors.background
7536
- }),
7537
- children: [
7538
- /* @__PURE__ */ jsxs31(
7539
- View37,
7540
- {
7541
- style: {
7542
- flexDirection: "row",
7543
- alignItems: "center",
7544
- gap: tokens43.extensions.tableCard.gap,
7545
- marginBottom: tokens43.dimension.value8
7546
- },
7547
- children: [
7548
- /* @__PURE__ */ jsxs31(
7544
+ return /* @__PURE__ */ jsxs31(
7545
+ View37,
7546
+ {
7547
+ style: { gap: tokens43.extensions.tableCard.gap, padding: tokens43.extensions.tableCard.listPadding, opacity: skeletonHidden ? 0 : void 0 },
7548
+ "aria-hidden": skeletonHidden || void 0,
7549
+ children: [
7550
+ initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ jsx44(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ jsxs31(
7551
+ AccessiblePressable,
7552
+ {
7553
+ accessible: false,
7554
+ onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7555
+ style: ({ pressed }) => ({
7556
+ padding: tokens43.extensions.tableCard.padding,
7557
+ borderWidth: tokens43.border.defaultWidth,
7558
+ borderColor: colors.border,
7559
+ borderRadius: tokens43.extensions.tableCard.radius,
7560
+ backgroundColor: pressed ? colors.hover : colors.background
7561
+ }),
7562
+ children: [
7563
+ /* @__PURE__ */ jsxs31(
7564
+ View37,
7565
+ {
7566
+ style: {
7567
+ flexDirection: "row",
7568
+ alignItems: "center",
7569
+ gap: tokens43.extensions.tableCard.gap,
7570
+ marginBottom: tokens43.dimension.value8
7571
+ },
7572
+ children: [
7573
+ /* @__PURE__ */ jsxs31(
7574
+ View37,
7575
+ {
7576
+ style: {
7577
+ flexDirection: "row",
7578
+ flex: 1,
7579
+ alignItems: "center",
7580
+ gap: tokens43.extensions.tableCard.gap,
7581
+ minWidth: 0
7582
+ },
7583
+ children: [
7584
+ selectable && checkbox(row, i),
7585
+ title && /* @__PURE__ */ jsx44(View37, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7586
+ ]
7587
+ }
7588
+ ),
7589
+ badges.length ? /* @__PURE__ */ jsx44(View37, { style: { flexDirection: "row", gap: tokens43.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ jsx44(View37, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7590
+ inline.length > 0 && /* @__PURE__ */ jsx44(View37, { style: { flexDirection: "row", gap: tokens43.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ jsx44(View37, { children: cell(col, row, i) }, col.key)) })
7591
+ ]
7592
+ }
7593
+ ),
7594
+ sections.map((section, index) => {
7595
+ const cols = columnsForSection(row, section);
7596
+ return cols.length ? /* @__PURE__ */ jsxs31(
7549
7597
  View37,
7550
7598
  {
7551
7599
  style: {
7552
- flexDirection: "row",
7553
- flex: 1,
7554
- alignItems: "center",
7555
- gap: tokens43.extensions.tableCard.gap,
7556
- minWidth: 0
7600
+ borderTopWidth: index ? tokens43.border.defaultWidth : 0,
7601
+ borderTopColor: colors.border,
7602
+ paddingTop: index ? tokens43.dimension.value12 : 0,
7603
+ marginTop: index ? tokens43.dimension.value12 : 0
7557
7604
  },
7558
7605
  children: [
7559
- selectable && checkbox(row, i),
7560
- title && /* @__PURE__ */ jsx44(View37, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7561
- ]
7562
- }
7563
- ),
7564
- badges.length ? /* @__PURE__ */ jsx44(View37, { style: { flexDirection: "row", gap: tokens43.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ jsx44(View37, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7565
- inline.length > 0 && /* @__PURE__ */ jsx44(View37, { style: { flexDirection: "row", gap: tokens43.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ jsx44(View37, { children: cell(col, row, i) }, col.key)) })
7566
- ]
7567
- }
7568
- ),
7569
- sections.map((section, index) => {
7570
- const cols = columnsForSection(row, section);
7571
- return cols.length ? /* @__PURE__ */ jsxs31(
7572
- View37,
7573
- {
7574
- style: {
7575
- borderTopWidth: index ? tokens43.border.defaultWidth : 0,
7576
- borderTopColor: colors.border,
7577
- paddingTop: index ? tokens43.dimension.value12 : 0,
7578
- marginTop: index ? tokens43.dimension.value12 : 0
7579
- },
7580
- children: [
7581
- section.label && /* @__PURE__ */ jsx44(
7582
- KText,
7583
- {
7584
- style: {
7585
- ...typeStyle("controlSmall"),
7586
- color: colors.textTertiary,
7587
- marginBottom: tokens43.dimension.value6
7588
- },
7589
- children: section.label
7590
- }
7591
- ),
7592
- /* @__PURE__ */ jsx44(
7593
- View37,
7594
- {
7595
- style: {
7596
- flexDirection: "row",
7597
- flexWrap: "wrap",
7598
- gap: section.layout === "metrics" ? tokens43.extensions.tableCard.gap : tokens43.extensions.tableCard.metricGap
7599
- },
7600
- children: cols.map((col) => /* @__PURE__ */ jsxs31(
7606
+ section.label && /* @__PURE__ */ jsx44(
7607
+ KText,
7608
+ {
7609
+ style: {
7610
+ ...typeStyle("controlSmall"),
7611
+ color: colors.textTertiary,
7612
+ marginBottom: tokens43.dimension.value6
7613
+ },
7614
+ children: section.label
7615
+ }
7616
+ ),
7617
+ /* @__PURE__ */ jsx44(
7601
7618
  View37,
7602
7619
  {
7603
7620
  style: {
7604
- flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7605
- flexGrow: 1,
7606
- minWidth: 0,
7607
- gap: tokens43.extensions.tableCard.valueGap
7621
+ flexDirection: "row",
7622
+ flexWrap: "wrap",
7623
+ gap: section.layout === "metrics" ? tokens43.extensions.tableCard.gap : tokens43.extensions.tableCard.metricGap
7608
7624
  },
7609
- children: [
7610
- /* @__PURE__ */ jsx44(
7611
- KText,
7612
- {
7613
- style: {
7614
- ...typeStyle("meta"),
7615
- color: colors.textTertiary,
7616
- textAlign: section.labelAlign
7617
- },
7618
- children: col.label
7619
- }
7620
- ),
7621
- cell(col, row, i)
7622
- ]
7623
- },
7624
- col.key
7625
- ))
7626
- }
7627
- )
7628
- ]
7629
- },
7630
- section.key || index
7631
- ) : null;
7632
- }),
7633
- expandable && expand(row, i),
7634
- expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ jsx44(
7635
- View37,
7636
- {
7637
- style: {
7638
- borderTopWidth: tokens43.border.defaultWidth,
7639
- borderTopColor: colors.border,
7640
- paddingTop: tokens43.dimension.value8,
7641
- marginTop: tokens43.dimension.value4
7642
- },
7643
- children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7644
- }
7645
- ),
7646
- actions && !actions.inlineInCard && /* @__PURE__ */ jsx44(
7647
- View37,
7648
- {
7649
- style: {
7650
- borderTopWidth: tokens43.border.defaultWidth,
7651
- borderTopColor: colors.border,
7652
- paddingTop: tokens43.dimension.value8,
7653
- marginTop: tokens43.dimension.value8,
7654
- alignItems: "flex-end"
7655
- },
7656
- children: /* @__PURE__ */ jsx44(View37, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7657
- }
7658
- )
7659
- ]
7660
- },
7661
- state.key(row, i)
7662
- )),
7663
- !initialLoading && !state.rows.length && /* @__PURE__ */ jsx44(View37, { style: { padding: tokens43.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7664
- color: colors.textTertiary
7665
- }) })
7666
- ] });
7625
+ children: cols.map((col) => /* @__PURE__ */ jsxs31(
7626
+ View37,
7627
+ {
7628
+ style: {
7629
+ flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7630
+ flexGrow: 1,
7631
+ minWidth: 0,
7632
+ gap: tokens43.extensions.tableCard.valueGap
7633
+ },
7634
+ children: [
7635
+ /* @__PURE__ */ jsx44(
7636
+ KText,
7637
+ {
7638
+ style: {
7639
+ ...typeStyle("meta"),
7640
+ color: colors.textTertiary,
7641
+ textAlign: section.labelAlign
7642
+ },
7643
+ children: col.label
7644
+ }
7645
+ ),
7646
+ cell(col, row, i)
7647
+ ]
7648
+ },
7649
+ col.key
7650
+ ))
7651
+ }
7652
+ )
7653
+ ]
7654
+ },
7655
+ section.key || index
7656
+ ) : null;
7657
+ }),
7658
+ expandable && expand(row, i),
7659
+ expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ jsx44(
7660
+ View37,
7661
+ {
7662
+ style: {
7663
+ borderTopWidth: tokens43.border.defaultWidth,
7664
+ borderTopColor: colors.border,
7665
+ paddingTop: tokens43.dimension.value8,
7666
+ marginTop: tokens43.dimension.value4
7667
+ },
7668
+ children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7669
+ }
7670
+ ),
7671
+ actions && !actions.inlineInCard && /* @__PURE__ */ jsx44(
7672
+ View37,
7673
+ {
7674
+ style: {
7675
+ borderTopWidth: tokens43.border.defaultWidth,
7676
+ borderTopColor: colors.border,
7677
+ paddingTop: tokens43.dimension.value8,
7678
+ marginTop: tokens43.dimension.value8,
7679
+ alignItems: "flex-end"
7680
+ },
7681
+ children: /* @__PURE__ */ jsx44(View37, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7682
+ }
7683
+ )
7684
+ ]
7685
+ },
7686
+ state.key(row, i)
7687
+ )),
7688
+ !initialLoading && !state.rows.length && /* @__PURE__ */ jsx44(View37, { style: { padding: tokens43.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7689
+ color: colors.textTertiary
7690
+ }) })
7691
+ ]
7692
+ }
7693
+ );
7667
7694
  }
7668
7695
 
7669
7696
  // packages/native/src/table-view.tsx
@@ -7671,6 +7698,9 @@ import { jsx as jsx45, jsxs as jsxs32 } from "react/jsx-runtime";
7671
7698
  function KjunTable(props) {
7672
7699
  const {
7673
7700
  skeletonRows = 8,
7701
+ skeleton = true,
7702
+ loadingText = "\uB85C\uB529 \uC911...",
7703
+ loadingDelay = 0,
7674
7704
  emptyText = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
7675
7705
  hoverable = true,
7676
7706
  searchable = false,
@@ -7691,7 +7721,7 @@ function KjunTable(props) {
7691
7721
  onRowClick,
7692
7722
  onRetry
7693
7723
  } = props;
7694
- const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), mobile = useWindowDimensions7().width < tokens44.table.mobileBreakpoint;
7724
+ const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), revealed = useLoadingReveal(query.initialLoading, skeleton ? loadingDelay : 0), mobile = useWindowDimensions7().width < tokens44.table.mobileBreakpoint;
7695
7725
  const layout = tablePresentation(props, mobile);
7696
7726
  const { card, visible } = layout;
7697
7727
  const cell = (col, row, index, role) => {
@@ -7770,8 +7800,11 @@ function KjunTable(props) {
7770
7800
  refreshing: query.queryRefreshing,
7771
7801
  loadingPadding: "none",
7772
7802
  onRetry,
7803
+ loading: skeleton ? void 0 : props.loading,
7804
+ loadingText,
7805
+ loadingDelay: skeleton ? 0 : loadingDelay,
7773
7806
  children: [
7774
- 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 }),
7807
+ 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 }),
7775
7808
  pagination && /* @__PURE__ */ jsx45(
7776
7809
  KjunPagination,
7777
7810
  {
@@ -7832,12 +7865,13 @@ function KjunKpiHero(props) {
7832
7865
  secondary = [],
7833
7866
  animated = true,
7834
7867
  size = "md",
7868
+ surface = "card",
7835
7869
  aside,
7836
7870
  formatter,
7837
7871
  deltaFormatter,
7838
7872
  renderSecondary
7839
7873
  } = props;
7840
- const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = useWindowDimensions8().width <= tokens45.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
7874
+ const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), windowWidth = useWindowDimensions8().width, mobile = windowWidth <= tokens45.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
7841
7875
  const geometry2 = tokens45.extensions.kpiHero;
7842
7876
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
7843
7877
  const numeric = {
@@ -7867,10 +7901,13 @@ function KjunKpiHero(props) {
7867
7901
  {
7868
7902
  accessibilityState: { busy: loading },
7869
7903
  style: {
7870
- paddingVertical: spec.paddingY,
7871
- paddingHorizontal: spec.paddingX,
7872
- backgroundColor: colors.surface,
7873
- borderRadius: geometry2.radius
7904
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
7905
+ ...surface === "none" ? {} : {
7906
+ paddingVertical: spec.paddingY,
7907
+ paddingHorizontal: spec.paddingX,
7908
+ backgroundColor: colors.surface,
7909
+ borderRadius: geometry2.radius
7910
+ }
7874
7911
  },
7875
7912
  children: [
7876
7913
  /* @__PURE__ */ jsxs34(
@@ -7953,70 +7990,75 @@ function KjunKpiHero(props) {
7953
7990
  borderTopWidth: tokens45.border.defaultWidth,
7954
7991
  borderTopColor: colors.border
7955
7992
  },
7956
- children: secondary.map((item, i) => /* @__PURE__ */ jsxs34(
7957
- View40,
7958
- {
7959
- style: mobile && !small ? {
7960
- flex: 1,
7961
- minWidth: 0,
7962
- paddingLeft: i ? geometry2.itemPadding : 0,
7963
- paddingRight: i === secondary.length - 1 ? 0 : geometry2.itemPadding,
7964
- borderLeftWidth: i ? tokens45.border.defaultWidth : 0,
7965
- borderLeftColor: colors.border
7966
- } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
7967
- children: [
7968
- /* @__PURE__ */ jsx47(
7969
- KText,
7970
- {
7971
- style: {
7972
- color: colors.textTertiary,
7973
- ...typeStyle("caption"),
7974
- marginBottom: spec.secondaryLabelGap
7975
- },
7976
- children: item.label
7977
- }
7978
- ),
7979
- loading ? /* @__PURE__ */ jsx47(
7980
- KjunSkeleton,
7981
- {
7982
- type: "block",
7983
- height: typeStyle("numberMd").lineHeight,
7984
- width: geometry2.secondarySkeletonWidth
7985
- }
7986
- ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ jsx47(
7987
- KpiNumberLine,
7988
- {
7989
- prefix: item.prefix,
7990
- suffix: item.suffix,
7991
- prefixGap: geometry2.secondaryAffixGap,
7992
- suffixGap: geometry2.secondaryAffixGap,
7993
- unitStyle: typeStyle("caption"),
7994
- style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
7995
- children: kpiFormat(item)
7996
- }
7997
- ),
7998
- item.desc && (loading ? /* @__PURE__ */ jsx47(
7999
- KjunSkeleton,
8000
- {
8001
- type: "block",
8002
- width: geometry2.descriptionSkeletonWidth,
8003
- height: typeStyle("caption").lineHeight
8004
- }
8005
- ) : /* @__PURE__ */ jsx47(
8006
- KText,
8007
- {
8008
- style: {
8009
- ...typeStyle("caption"),
8010
- marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8011
- color: item.descColor || colors.textTertiary
8012
- },
8013
- children: item.desc
8014
- }
8015
- ))
8016
- ]
8017
- },
8018
- i
8019
- ))
7993
+ children: secondary.map((item, i) => {
7994
+ const columns = mobile && !small && windowWidth <= tokens45.responsive.kpiHeroSecondary && secondary.length >= 3 ? 2 : 0;
7995
+ const first = columns ? i % columns === 0 : i === 0;
7996
+ const last = columns ? i % columns === columns - 1 || i === secondary.length - 1 : i === secondary.length - 1;
7997
+ return /* @__PURE__ */ jsxs34(
7998
+ View40,
7999
+ {
8000
+ style: mobile && !small ? {
8001
+ ...columns ? { width: `${100 / columns}%`, marginTop: i >= columns ? spec.secondaryPadding : 0 } : { flex: 1 },
8002
+ minWidth: 0,
8003
+ paddingLeft: first ? 0 : geometry2.itemPadding,
8004
+ paddingRight: last ? 0 : geometry2.itemPadding,
8005
+ borderLeftWidth: first ? 0 : tokens45.border.defaultWidth,
8006
+ borderLeftColor: colors.border
8007
+ } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
8008
+ children: [
8009
+ /* @__PURE__ */ jsx47(
8010
+ KText,
8011
+ {
8012
+ style: {
8013
+ color: colors.textTertiary,
8014
+ ...typeStyle("caption"),
8015
+ marginBottom: spec.secondaryLabelGap
8016
+ },
8017
+ children: item.label
8018
+ }
8019
+ ),
8020
+ loading ? /* @__PURE__ */ jsx47(
8021
+ KjunSkeleton,
8022
+ {
8023
+ type: "block",
8024
+ height: typeStyle("numberMd").lineHeight,
8025
+ width: geometry2.secondarySkeletonWidth
8026
+ }
8027
+ ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ jsx47(
8028
+ KpiNumberLine,
8029
+ {
8030
+ prefix: item.prefix,
8031
+ suffix: item.suffix,
8032
+ prefixGap: geometry2.secondaryAffixGap,
8033
+ suffixGap: geometry2.secondaryAffixGap,
8034
+ unitStyle: typeStyle("caption"),
8035
+ style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
8036
+ children: kpiFormat(item)
8037
+ }
8038
+ ),
8039
+ item.desc && (loading ? /* @__PURE__ */ jsx47(
8040
+ KjunSkeleton,
8041
+ {
8042
+ type: "block",
8043
+ width: geometry2.descriptionSkeletonWidth,
8044
+ height: typeStyle("caption").lineHeight
8045
+ }
8046
+ ) : /* @__PURE__ */ jsx47(
8047
+ KText,
8048
+ {
8049
+ style: {
8050
+ ...typeStyle("caption"),
8051
+ marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8052
+ color: item.descColor || colors.textTertiary
8053
+ },
8054
+ children: item.desc
8055
+ }
8056
+ ))
8057
+ ]
8058
+ },
8059
+ i
8060
+ );
8061
+ })
8020
8062
  }
8021
8063
  )
8022
8064
  ]
@@ -8026,7 +8068,7 @@ function KjunKpiHero(props) {
8026
8068
 
8027
8069
  // packages/native/src/kpi-row.tsx
8028
8070
  import { tokens as tokens46 } from "@kjun-ui/tokens";
8029
- import { useState as useState35 } from "react";
8071
+ import { useState as useState36 } from "react";
8030
8072
  import {
8031
8073
  Text as Text6,
8032
8074
  View as View41,
@@ -8037,6 +8079,7 @@ function KjunKpiRow({
8037
8079
  loading = false,
8038
8080
  items,
8039
8081
  size = "md",
8082
+ surface = "card",
8040
8083
  mobileSummary = true,
8041
8084
  onItemClick,
8042
8085
  renderValue
@@ -8044,7 +8087,7 @@ function KjunKpiRow({
8044
8087
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = useWindowDimensions9().width <= tokens46.responsive.kpiRow, small = size === "sm", summary = mobileSummary && mobile && !small;
8045
8088
  const geometry2 = tokens46.extensions.kpiRow;
8046
8089
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8047
- const [width, setWidth] = useState35(0);
8090
+ const [width, setWidth] = useState36(0);
8048
8091
  const paddingX = summary ? geometry2.summary.paddingX : spec.paddingX;
8049
8092
  const gapX = summary ? geometry2.summary.gapX : 0;
8050
8093
  const explicit = items.some(
@@ -8085,10 +8128,13 @@ function KjunKpiRow({
8085
8128
  style: {
8086
8129
  flexDirection: "row",
8087
8130
  flexWrap: mobile ? "wrap" : "nowrap",
8088
- paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8089
- paddingHorizontal: paddingX,
8090
- borderRadius: geometry2.radius,
8091
- backgroundColor: colors.surface,
8131
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
8132
+ ...surface === "none" ? {} : {
8133
+ paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8134
+ paddingHorizontal: paddingX,
8135
+ borderRadius: geometry2.radius,
8136
+ backgroundColor: colors.surface
8137
+ },
8092
8138
  rowGap: summary ? geometry2.summary.gapY : 0,
8093
8139
  columnGap: gapX
8094
8140
  },
@@ -8260,7 +8306,7 @@ import { tokens as tokens48 } from "@kjun-ui/tokens";
8260
8306
  import { ScrollView as ScrollView10, View as View43 } from "react-native";
8261
8307
 
8262
8308
  // shared/package-runtime/market-cards.ts
8263
- import { useEffect as useEffect24, useRef as useRef32, useState as useState36 } from "react";
8309
+ import { useEffect as useEffect25, useRef as useRef32, useState as useState37 } from "react";
8264
8310
  function useMarketCardsModel(props, persistence) {
8265
8311
  const {
8266
8312
  columns,
@@ -8276,7 +8322,7 @@ function useMarketCardsModel(props, persistence) {
8276
8322
  sortKey: c.sortable ? metricConfig[c.key].sortKey : null,
8277
8323
  isDefaultSort: c.defaultSort
8278
8324
  }));
8279
- const [key, setKey] = useState36(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8325
+ const [key, setKey] = useState37(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8280
8326
  const mounted = useRef32("");
8281
8327
  const save = (key2) => {
8282
8328
  var _a;
@@ -8285,7 +8331,7 @@ function useMarketCardsModel(props, persistence) {
8285
8331
  } catch (e) {
8286
8332
  }
8287
8333
  };
8288
- useEffect24(() => {
8334
+ useEffect25(() => {
8289
8335
  var _a, _b;
8290
8336
  if (mounted.current === restoreSignature) return;
8291
8337
  mounted.current = restoreSignature;
@@ -8527,7 +8573,7 @@ function KjunMarketCards(props) {
8527
8573
  ...props,
8528
8574
  loadingPadding: "none",
8529
8575
  empty: !rows.length,
8530
- loadingContent: /* @__PURE__ */ jsx50(KjunListSkeleton, { variant: "compact" }),
8576
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx50(KjunListSkeleton, { variant: "compact" }),
8531
8577
  emptyContent: /* @__PURE__ */ jsx50(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8532
8578
  children: /* @__PURE__ */ jsxs37(View43, { children: [
8533
8579
  state.pill && /* @__PURE__ */ jsx50(KText, { style: { textAlign: "right", paddingHorizontal: tokens48.dimension.value16, paddingVertical: tokens48.dimension.value8, ...typeStyle("caption"), color: colors.textSecondary }, children: state.pill.label }),
@@ -8638,7 +8684,7 @@ function KjunMarketSimpleList(props) {
8638
8684
  loadingPadding: "none",
8639
8685
  empty: !rows.length,
8640
8686
  emptyText: emptyMessage,
8641
- loadingContent: /* @__PURE__ */ jsx51(KjunListSkeleton, {}),
8687
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx51(KjunListSkeleton, {}),
8642
8688
  emptyContent: /* @__PURE__ */ jsx51(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8643
8689
  children: /* @__PURE__ */ jsx51(View44, { children: rows.map((row, i) => {
8644
8690
  var _a, _b;
@@ -8765,7 +8811,7 @@ function KjunMarketListPanel({
8765
8811
 
8766
8812
  // packages/native/src/market-table.tsx
8767
8813
  import { tokens as tokens51 } from "@kjun-ui/tokens";
8768
- import { useId as useId10, useState as useState37 } from "react";
8814
+ import { useId as useId10, useState as useState38 } from "react";
8769
8815
  import { ScrollView as ScrollView11, View as View46 } from "react-native";
8770
8816
  import Svg8, { Defs as Defs4, LinearGradient as LinearGradient4, Rect as Rect5, Stop as Stop4 } from "react-native-svg";
8771
8817
  import { jsx as jsx53, jsxs as jsxs40 } from "react/jsx-runtime";
@@ -8851,7 +8897,7 @@ function KjunMarketTable(props) {
8851
8897
  );
8852
8898
  };
8853
8899
  const layout = useMarketLayout(columns, showActions);
8854
- const [scroll, setScroll] = useState37({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + useId10().replace(/[^a-z0-9]/gi, "");
8900
+ const [scroll, setScroll] = useState38({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + useId10().replace(/[^a-z0-9]/gi, "");
8855
8901
  const tableQuote = { price: {}, change: { fontWeight: typeStyle("body").fontWeight } };
8856
8902
  return /* @__PURE__ */ jsxs40(
8857
8903
  View46,
@@ -8869,7 +8915,7 @@ function KjunMarketTable(props) {
8869
8915
  loadingPadding: "none",
8870
8916
  empty: !rows.length,
8871
8917
  emptyText: emptyMessage,
8872
- loadingContent: /* @__PURE__ */ jsx53(KjunMarketTableSkeleton, { columns, showActions }),
8918
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ jsx53(KjunMarketTableSkeleton, { columns, showActions }),
8873
8919
  emptyContent: /* @__PURE__ */ jsx53(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8874
8920
  children: /* @__PURE__ */ jsx53(MarketQuoteTypeContext.Provider, { value: tableQuote, children: /* @__PURE__ */ jsxs40(View46, { style: { position: "relative", minWidth: 0 }, children: [
8875
8921
  /* @__PURE__ */ jsx53(
@@ -9110,7 +9156,7 @@ function KjunListSection({ title, description, actions, children, ariaLabel }) {
9110
9156
 
9111
9157
  // packages/native/src/app-navigation.tsx
9112
9158
  import { tokens as tokens53 } from "@kjun-ui/tokens";
9113
- import { Children as Children5, Fragment as Fragment19, isValidElement as isValidElement7, useState as useState38 } from "react";
9159
+ import { Children as Children5, Fragment as Fragment19, isValidElement as isValidElement7, useState as useState39 } from "react";
9114
9160
  import { View as View48, Platform as Platform25 } from "react-native";
9115
9161
  import { jsx as jsx55, jsxs as jsxs42 } from "react/jsx-runtime";
9116
9162
  function KjunTopNavigation({ title, description, leading, actions, safeAreaTop = 0 }) {
@@ -9119,7 +9165,7 @@ function KjunTopNavigation({ title, description, leading, actions, safeAreaTop =
9119
9165
  const titleInset = Math.max(0, (geometry2.controlSize - tokens53.typography.sectionTitle.lineHeightPx) / 2);
9120
9166
  const wrapping = Platform25.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
9121
9167
  const edgeInset = (geometry2.controlSize - geometry2.iconSize) / 2;
9122
- const [iconEdges, setIconEdges] = useState38({ leading: false, trailing: false });
9168
+ const [iconEdges, setIconEdges] = useState39({ leading: false, trailing: false });
9123
9169
  const square = (key) => (event) => {
9124
9170
  const { width, height } = event.nativeEvent.layout;
9125
9171
  const next = Math.abs(width - height) < 1 && Math.abs(height - geometry2.controlSize) < 1;
@@ -9199,7 +9245,7 @@ function KjunBottomNavigation({ items, value, ariaLabel = "\uC8FC\uC694 \uD0D0\u
9199
9245
  }
9200
9246
  function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboardVisible = false, hideOnKeyboard = false }) {
9201
9247
  const { colors } = useKjunStyles();
9202
- const [width, setWidth] = useState38(0);
9248
+ const [width, setWidth] = useState39(0);
9203
9249
  const geometry2 = tokens53.extensions.navigation;
9204
9250
  const wide = width >= tokens53.responsive.bottomAction + geometry2.padding * 2;
9205
9251
  const wrapping = Platform25.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
@@ -9221,7 +9267,7 @@ function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboa
9221
9267
  }
9222
9268
 
9223
9269
  // packages/native/src/media.tsx
9224
- import { useRef as useRef33, useState as useState39 } from "react";
9270
+ import { useRef as useRef33, useState as useState40 } from "react";
9225
9271
  import { Image, View as View49 } from "react-native";
9226
9272
  import { tokens as tokens54 } from "@kjun-ui/tokens";
9227
9273
  import { jsx as jsx56 } from "react/jsx-runtime";
@@ -9230,7 +9276,7 @@ function KjunImage({ src, source, alt, decorative = false, aspectRatio = 1, fit
9230
9276
  const request = JSON.stringify(source != null ? source : src), current = useRef33({ request, version: 0 });
9231
9277
  if (current.current.request !== request) current.current = { request, version: current.current.version + 1 };
9232
9278
  const version = current.current.version;
9233
- const [failed, setFailed] = useState39(null);
9279
+ const [failed, setFailed] = useState40(null);
9234
9280
  const missing = !source && !src;
9235
9281
  return /* @__PURE__ */ jsx56(View49, { 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: () => {
9236
9282
  if (version === current.current.version) onLoad == null ? void 0 : onLoad();
@@ -9260,7 +9306,7 @@ function KjunChip({ label, icon, removable = false, disabled = false, size = "md
9260
9306
  }
9261
9307
 
9262
9308
  // packages/native/src/range-input.tsx
9263
- import { useEffect as useEffect25, useMemo as useMemo2, useRef as useRef34, useState as useState40 } from "react";
9309
+ import { useEffect as useEffect26, useMemo as useMemo2, useRef as useRef34, useState as useState41 } from "react";
9264
9310
  import { PanResponder, Platform as Platform26, Pressable as Pressable3, View as View51 } from "react-native";
9265
9311
  import { tokens as tokens56, createSliderDomain, sliderKey } from "@kjun-ui/tokens";
9266
9312
  import { jsx as jsx58, jsxs as jsxs44 } from "react/jsx-runtime";
@@ -9284,18 +9330,18 @@ function RangeInput({
9284
9330
  const valid = domain.valid && (!Array.isArray(value) || value.length === 2) && values.every(domain.accepts) && (values.length === 1 || values[0] <= values[1]);
9285
9331
  const blocked = disabled || !valid;
9286
9332
  const effectiveMax = valid ? domain.snap(max) : min;
9287
- const [hovered, setHovered] = useState40(null);
9288
- const [dragging, setDragging] = useState40(null);
9289
- const [focused, setFocused] = useState40(null);
9333
+ const [hovered, setHovered] = useState41(null);
9334
+ const [dragging, setDragging] = useState41(null);
9335
+ const [focused, setFocused] = useState41(null);
9290
9336
  const track = useRef34(null), measured = useRef34({ x: 0, width: 1 }), selected = useRef34(0), dirty = useRef34(false);
9291
9337
  const latest = useRef34(values);
9292
9338
  latest.current = values;
9293
9339
  const callbacks = useRef34({ onValueChange, onChangeCommit });
9294
9340
  callbacks.current = { onValueChange, onChangeCommit };
9295
- useEffect25(() => {
9341
+ useEffect26(() => {
9296
9342
  if (!valid) console.warn("KJUN Slider: \uBC94\uC704\xB7step\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9297
9343
  }, [valid]);
9298
- useEffect25(() => {
9344
+ useEffect26(() => {
9299
9345
  if (blocked) {
9300
9346
  setDragging(null);
9301
9347
  setHovered(null);
@@ -9560,7 +9606,7 @@ function KjunRangeSlider(props) {
9560
9606
  }
9561
9607
 
9562
9608
  // packages/native/src/quantity-stepper.tsx
9563
- import { useEffect as useEffect26, useRef as useRef35, useState as useState41 } from "react";
9609
+ import { useEffect as useEffect27, useRef as useRef35, useState as useState42 } from "react";
9564
9610
  import { Platform as Platform27, View as View52 } from "react-native";
9565
9611
  import { createNumberDomain, quantityKeyAction, tokens as tokens57 } from "@kjun-ui/tokens";
9566
9612
 
@@ -9582,16 +9628,16 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9582
9628
  const increaseStyle = { ...buttonStyle, borderRadius: 0, borderTopRightRadius: outer, borderBottomRightRadius: outer };
9583
9629
  const domain = createNumberDomain({ min, max, step, precision }), valid = domain.valid && domain.accepts(value), blocked = disabled || !valid;
9584
9630
  const surface = useFieldSurface(size, { disabled: blocked, invalid });
9585
- const [draft, setDraft] = useState41(String(value));
9631
+ const [draft, setDraft] = useState42(String(value));
9586
9632
  const inputRef = useRef35(null);
9587
9633
  const composing = useRef35(false), dirty = useRef35(false), accepted = useRef35(value);
9588
9634
  const cancelledEscape = useRef35(false);
9589
- useEffect26(() => {
9635
+ useEffect27(() => {
9590
9636
  setDraft(String(value));
9591
9637
  accepted.current = value;
9592
9638
  dirty.current = false;
9593
9639
  }, [value, precision, min, max, step]);
9594
- useEffect26(() => {
9640
+ useEffect27(() => {
9595
9641
  if (!valid) console.warn("KJUN QuantityStepper: \uBC94\uC704\xB7step\xB7\uC815\uBC00\uB3C4\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9596
9642
  }, [valid]);
9597
9643
  const emit = (next) => {
@@ -9636,7 +9682,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9636
9682
  dirty.current = true;
9637
9683
  setDraft(text);
9638
9684
  } };
9639
- useEffect26(() => {
9685
+ useEffect27(() => {
9640
9686
  if (Platform27.OS !== "web") return;
9641
9687
  const input = inputRef.current;
9642
9688
  const keydown = (event) => handlers.current.key(event);
@@ -9708,7 +9754,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9708
9754
  }
9709
9755
 
9710
9756
  // packages/native/src/time-picker.tsx
9711
- import { Fragment as Fragment20, useEffect as useEffect27, useId as useId11, useMemo as useMemo3, useRef as useRef36, useState as useState42 } from "react";
9757
+ import { Fragment as Fragment20, useEffect as useEffect28, useId as useId11, useMemo as useMemo3, useRef as useRef36, useState as useState43 } from "react";
9712
9758
  import { View as View53 } from "react-native";
9713
9759
  import { createTimeDomain, tokens as tokens58 } from "@kjun-ui/tokens";
9714
9760
  import { jsx as jsx60, jsxs as jsxs46 } from "react/jsx-runtime";
@@ -9716,11 +9762,11 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
9716
9762
  const geometry2 = tokens58.extensions.timePicker, spec = tokens58.input[size];
9717
9763
  const { colors } = useKjunStyles();
9718
9764
  const first = useRef36(null);
9719
- const [focused, setFocused] = useState42(false), [opened, setOpened] = useState42(null);
9765
+ const [focused, setFocused] = useState43(false), [opened, setOpened] = useState43(null);
9720
9766
  const field = useKjunField(), uid = useId11();
9721
9767
  const fieldId = (field == null ? void 0 : field.id) || `kjun-time-${uid}`;
9722
9768
  const domain = useMemo3(() => createTimeDomain({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
9723
- useEffect27(() => {
9769
+ useEffect28(() => {
9724
9770
  if (!valid) console.warn("KJUN TimePicker: \uC2DC\uAC01 \uBC94\uC704\xB7\uAC04\uACA9\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9725
9771
  }, [valid]);
9726
9772
  const change = (next) => {