@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.
@@ -6337,12 +6337,27 @@ function KjunScrollFade({ children }) {
6337
6337
 
6338
6338
  // packages/native/src/data-state.tsx
6339
6339
  var import_tokens36 = require("@kjun-ui/tokens");
6340
- var import_react54 = require("react");
6340
+ var import_react55 = require("react");
6341
6341
  var import_react_native40 = require("react-native");
6342
+
6343
+ // shared/package-runtime/use-loading-reveal.ts
6344
+ var import_react54 = require("react");
6345
+ function useLoadingReveal(active, delay = 0) {
6346
+ const [revealed, setRevealed] = (0, import_react54.useState)(false);
6347
+ (0, import_react54.useEffect)(() => {
6348
+ setRevealed(false);
6349
+ if (!active || delay <= 0) return;
6350
+ const timer = setTimeout(() => setRevealed(true), delay);
6351
+ return () => clearTimeout(timer);
6352
+ }, [active, delay]);
6353
+ return delay <= 0 || revealed;
6354
+ }
6355
+
6356
+ // packages/native/src/data-state.tsx
6342
6357
  var import_jsx_runtime37 = require("react/jsx-runtime");
6343
6358
  function useQueryDisplay(props) {
6344
6359
  var _a;
6345
- const [state, setState] = (0, import_react54.useState)(() => (0, import_tokens36.initialQueryDisplay)(props));
6360
+ const [state, setState] = (0, import_react55.useState)(() => (0, import_tokens36.initialQueryDisplay)(props));
6346
6361
  let next = state;
6347
6362
  if (state.queryKey !== ((_a = props.queryKey) != null ? _a : null) || state.resultKey !== props.resultKey || state.loading !== !!props.loading) {
6348
6363
  next = (0, import_tokens36.advanceQueryDisplay)(state, props);
@@ -6361,6 +6376,7 @@ function KjunDataState({
6361
6376
  emptyIcon,
6362
6377
  emptyActionText,
6363
6378
  loadingText = "\uB85C\uB529 \uC911...",
6379
+ loadingDelay = 0,
6364
6380
  retryText = "\uB2E4\uC2DC \uC2DC\uB3C4",
6365
6381
  size = "md",
6366
6382
  skeleton = false,
@@ -6374,7 +6390,7 @@ function KjunDataState({
6374
6390
  onEmptyAction,
6375
6391
  ...query
6376
6392
  }) {
6377
- 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 = import_tokens36.tokens.extensions.state.padding[size];
6393
+ 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 = import_tokens36.tokens.extensions.state.padding[size], revealed = useLoadingReveal(state.initialLoading, loadingDelay);
6378
6394
  const { colors } = useKjunStyles();
6379
6395
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(
6380
6396
  import_react_native40.View,
@@ -6407,8 +6423,10 @@ function KjunDataState({
6407
6423
  state.initialLoading ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
6408
6424
  import_react_native40.View,
6409
6425
  {
6410
- accessibilityLabel: loadingText,
6411
- style: { paddingVertical: loadingPadding === "none" ? 0 : padding },
6426
+ accessibilityLabel: revealed ? loadingText : void 0,
6427
+ "aria-hidden": revealed ? void 0 : true,
6428
+ importantForAccessibility: revealed ? void 0 : "no-hide-descendants",
6429
+ style: { paddingVertical: loadingPadding === "none" ? 0 : padding, opacity: revealed ? void 0 : 0 },
6412
6430
  children: loadingContent || (skeleton ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(import_react_native40.View, { style: { gap: import_tokens36.tokens.dimension.value12 }, children: Array.from({ length: skeletonCount }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(KjunSkeleton, { type: skeletonType }, i)) }) : /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(import_react_native40.View, { style: { alignItems: "center", gap: import_tokens36.tokens.dimension.value12 }, children: [
6413
6431
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(KjunSpinner, { size: "md" }),
6414
6432
  /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(KText, { style: { ...typeStyle("body"), color: colors.textSecondary, textAlign: "center", maxWidth: "100%" }, children: loadingText })
@@ -6442,7 +6460,7 @@ function BoundaryDescription() {
6442
6460
  const { colors } = useKjunStyles();
6443
6461
  return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(KText, { style: { ...typeStyle({ ...import_tokens36.tokens.typography.caption, fontSizePx: import_tokens36.tokens.extensions.state.descriptionSize }), color: colors.textSecondary, textAlign: "center" }, children: "\uB2E4\uC2DC \uC2DC\uB3C4\uD558\uBA74 \uBB38\uC81C\uAC00 \uD574\uACB0\uB420 \uC218 \uC788\uC2B5\uB2C8\uB2E4." });
6444
6462
  }
6445
- var KjunErrorBoundary = class extends import_react54.Component {
6463
+ var KjunErrorBoundary = class extends import_react55.Component {
6446
6464
  constructor() {
6447
6465
  super(...arguments);
6448
6466
  this.state = { error: false };
@@ -6489,7 +6507,7 @@ var KjunErrorBoundary = class extends import_react54.Component {
6489
6507
 
6490
6508
  // packages/native/src/skeletons.tsx
6491
6509
  var import_tokens40 = require("@kjun-ui/tokens");
6492
- var import_react56 = require("react");
6510
+ var import_react57 = require("react");
6493
6511
  var import_react_native42 = require("react-native");
6494
6512
  var import_react_native_svg5 = __toESM(require("react-native-svg"), 1);
6495
6513
 
@@ -6518,9 +6536,9 @@ function nativeMarketLayout(columns, showActions, containerWidth) {
6518
6536
 
6519
6537
  // packages/native/src/market-layout.ts
6520
6538
  var import_tokens38 = require("@kjun-ui/tokens");
6521
- var import_react55 = require("react");
6539
+ var import_react56 = require("react");
6522
6540
  function useMarketLayout(columns, showActions) {
6523
- const [containerWidth, setContainerWidth] = (0, import_react55.useState)(0);
6541
+ const [containerWidth, setContainerWidth] = (0, import_react56.useState)(0);
6524
6542
  const onLayout = (event) => setContainerWidth(event.nativeEvent.layout.width);
6525
6543
  return { ...nativeMarketLayout(columns, showActions, containerWidth), onLayout };
6526
6544
  }
@@ -6655,8 +6673,8 @@ function KjunChartSkeleton({
6655
6673
  kind = "line",
6656
6674
  height = import_tokens40.tokens.extensions.chartSkeleton.height
6657
6675
  }) {
6658
- const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react56.useRef)(new import_react_native42.Animated.Value(1)).current;
6659
- (0, import_react56.useEffect)(() => {
6676
+ const { colors } = useKjunStyles(), reduced = useReducedMotion(), opacity = (0, import_react57.useRef)(new import_react_native42.Animated.Value(1)).current;
6677
+ (0, import_react57.useEffect)(() => {
6660
6678
  if (reduced) return;
6661
6679
  const loop = import_react_native42.Animated.loop(
6662
6680
  import_react_native42.Animated.sequence([
@@ -6736,7 +6754,7 @@ function KjunChartSkeleton({
6736
6754
  opacity: (row + col + 2) % 3 === 0 ? 0.55 : 1
6737
6755
  },
6738
6756
  col
6739
- )) }, row)) : (kind === "bar" || kind === "candle") && [60, 100, 85, 140, 110, 165, 180].map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react56.Fragment, { children: [
6757
+ )) }, row)) : (kind === "bar" || kind === "candle") && [60, 100, 85, 140, 110, 165, 180].map((h, i) => /* @__PURE__ */ (0, import_jsx_runtime39.jsxs)(import_react57.Fragment, { children: [
6740
6758
  kind === "candle" && /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
6741
6759
  import_react_native_svg5.Path,
6742
6760
  {
@@ -6769,7 +6787,7 @@ function KjunChartSkeleton({
6769
6787
 
6770
6788
  // packages/native/src/financial-display.tsx
6771
6789
  var import_tokens43 = require("@kjun-ui/tokens");
6772
- var import_react59 = require("react");
6790
+ var import_react60 = require("react");
6773
6791
  var import_react_native44 = require("react-native");
6774
6792
  var import_react_native_svg6 = __toESM(require("react-native-svg"), 1);
6775
6793
 
@@ -6777,7 +6795,7 @@ var import_react_native_svg6 = __toESM(require("react-native-svg"), 1);
6777
6795
  var import_tokens42 = require("@kjun-ui/tokens");
6778
6796
 
6779
6797
  // shared/package-runtime/use-number-motion.ts
6780
- var import_react57 = require("react");
6798
+ var import_react58 = require("react");
6781
6799
 
6782
6800
  // shared/package-runtime/number-motion.ts
6783
6801
  var import_tokens41 = require("@kjun-ui/tokens");
@@ -6823,14 +6841,14 @@ function createNumberMotion(apply) {
6823
6841
 
6824
6842
  // shared/package-runtime/use-number-motion.ts
6825
6843
  function useNumberMotion(value, animated, fromPrevious, reduced) {
6826
- const [display, setDisplay] = (0, import_react57.useState)(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6827
- const motion = (0, import_react57.useRef)(null);
6844
+ const [display, setDisplay] = (0, import_react58.useState)(typeof value === "string" || fromPrevious || !animated || reduced ? value : 0);
6845
+ const motion = (0, import_react58.useRef)(null);
6828
6846
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
6829
- (0, import_react57.useLayoutEffect)(() => {
6847
+ (0, import_react58.useLayoutEffect)(() => {
6830
6848
  if (!motion.current) motion.current = createNumberMotion(setDisplay);
6831
6849
  motion.current.update(value, animated, fromPrevious, reduced);
6832
6850
  }, [value, animated, fromPrevious, reduced]);
6833
- (0, import_react57.useLayoutEffect)(() => () => {
6851
+ (0, import_react58.useLayoutEffect)(() => () => {
6834
6852
  var _a;
6835
6853
  (_a = motion.current) == null ? void 0 : _a.cancel();
6836
6854
  motion.current = null;
@@ -6839,7 +6857,7 @@ function useNumberMotion(value, animated, fromPrevious, reduced) {
6839
6857
  }
6840
6858
 
6841
6859
  // packages/native/src/number-display.tsx
6842
- var import_react58 = require("react");
6860
+ var import_react59 = require("react");
6843
6861
  var import_react_native43 = require("react-native");
6844
6862
 
6845
6863
  // shared/package-runtime/relative-time.ts
@@ -6873,7 +6891,7 @@ var format = (value, decimals = 0) => new Intl.NumberFormat(void 0, {
6873
6891
  function useCountUp(value, animated, fromPrevious) {
6874
6892
  return useNumberMotion(value, animated, fromPrevious, useReducedMotion());
6875
6893
  }
6876
- var MarketQuoteTypeContext = (0, import_react58.createContext)(null);
6894
+ var MarketQuoteTypeContext = (0, import_react59.createContext)(null);
6877
6895
  function KjunAnimatedNumber({
6878
6896
  value,
6879
6897
  decimals = 0,
@@ -6933,7 +6951,7 @@ function KjunPriceCell({
6933
6951
  fetchedAt,
6934
6952
  fromPrevious = true
6935
6953
  }) {
6936
- const { colors } = useKjunStyles(), quoteType = (0, import_react58.useContext)(MarketQuoteTypeContext);
6954
+ const { colors } = useKjunStyles(), quoteType = (0, import_react59.useContext)(MarketQuoteTypeContext);
6937
6955
  return value == null ? /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(KjunSkeleton, { type: "block", height: import_tokens42.tokens.extensions.financial.priceSkeletonHeight, width: import_tokens42.tokens.extensions.financial.priceSkeletonWidth }) : /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native43.View, { style: { flexDirection: "row", alignItems: "center", gap: import_tokens42.tokens.extensions.financial.affixGap }, children: [
6938
6956
  /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
6939
6957
  import_react_native43.View,
@@ -6967,7 +6985,7 @@ function KjunSignedValue({
6967
6985
  showFreshness = true,
6968
6986
  formatter
6969
6987
  }) {
6970
- const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), quoteType = (0, import_react58.useContext)(MarketQuoteTypeContext), n = finiteNumber(value), role = n === null || n === 0 ? "priceNeutral" : n > 0 ? "priceUp" : "priceDown", color = loading || n === null ? colors.textSecondary : stale ? colors.textTertiary : domainColor(domainColors, role);
6988
+ const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), quoteType = (0, import_react59.useContext)(MarketQuoteTypeContext), n = finiteNumber(value), role = n === null || n === 0 ? "priceNeutral" : n > 0 ? "priceUp" : "priceDown", color = loading || n === null ? colors.textSecondary : stale ? colors.textTertiary : domainColor(domainColors, role);
6971
6989
  const display = n === null ? "\u2014" : formatter ? formatter(n) : prefix + (showSign && n > 0 ? "+" : "") + format(kind === "percent" && !isRaw ? n * 100 : n, decimals) + (kind === "percent" ? "%" : "") + suffix;
6972
6990
  return /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(
6973
6991
  import_react_native43.View,
@@ -7006,6 +7024,7 @@ function KjunSignedValue({
7006
7024
 
7007
7025
  // packages/native/src/financial-display.tsx
7008
7026
  var import_jsx_runtime41 = require("react/jsx-runtime");
7027
+ var deviationFill = { neutral: 1, low: import_tokens43.tokens.states.opacity.deviationLow, medium: import_tokens43.tokens.states.opacity.deviationMedium, strong: import_tokens43.tokens.states.opacity.deviationStrong };
7009
7028
  function KjunDeviation({
7010
7029
  value,
7011
7030
  variant = "pill",
@@ -7016,7 +7035,7 @@ function KjunDeviation({
7016
7035
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), n = finiteNumber(value);
7017
7036
  if (n === null)
7018
7037
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsx)(KText, { style: { color: colors.textDisabled }, children: "-" });
7019
- 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) + "%";
7038
+ const abs = Math.abs(n), signal = abs >= signalThreshold, level = (0, import_tokens43.deviationLevel)(n), neutral = level === "neutral", color = neutral ? colors.textSecondary : domainColor(domainColors, n > 0 ? "priceUp" : "priceDown"), label = formatter ? formatter(n) : (n > 0 ? "+" : "") + format(n, decimals) + "%";
7020
7039
  if (variant === "badge")
7021
7040
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
7022
7041
  import_react_native44.View,
@@ -7085,7 +7104,7 @@ function KjunDeviation({
7085
7104
  inset: 0,
7086
7105
  borderRadius: import_tokens43.tokens.extensions.financial.cellRadius,
7087
7106
  backgroundColor: neutral ? colors.secondary : color,
7088
- opacity: neutral ? 1 : abs < 0.5 ? 0.08 : abs < 1 ? 0.14 : 0.22
7107
+ opacity: deviationFill[level]
7089
7108
  }
7090
7109
  }
7091
7110
  ),
@@ -7098,7 +7117,7 @@ function KjunDeviation({
7098
7117
  fontVariant: ["tabular-nums"],
7099
7118
  ...typeStyle("body"),
7100
7119
  // Like Web: control weight, stronger once the deviation reaches 1%.
7101
- fontWeight: abs >= 1 ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
7120
+ fontWeight: level === "strong" ? typeStyle("numberLg").fontWeight : typeStyle("control").fontWeight
7102
7121
  },
7103
7122
  children: label
7104
7123
  }
@@ -7260,7 +7279,7 @@ function KjunSparkline({
7260
7279
  stretch = false,
7261
7280
  ariaLabel
7262
7281
  }) {
7263
- const { colors, domainColors } = useKjunStyles(), id = "kjun-" + (0, import_react59.useId)().replace(/:/g, ""), values = data.filter(Number.isFinite), min = Math.min(...values), max = Math.max(...values), range = max - min || 1, points = values.map(
7282
+ const { colors, domainColors } = useKjunStyles(), id = "kjun-" + (0, import_react60.useId)().replace(/:/g, ""), values = data.filter(Number.isFinite), min = Math.min(...values), max = Math.max(...values), range = max - min || 1, points = values.map(
7264
7283
  (v, i) => `${2 + i / Math.max(1, values.length - 1) * (width - 4)},${2 + height - 4 - (v - min) / range * (height - 4)}`
7265
7284
  ).join(" "), change = values.length > 1 ? values[values.length - 1] - values[0] : 0, line = color || (change === 0 ? colors.textTertiary : semantic === "status" ? change > 0 ? colors.success : colors.danger : domainColor(domainColors, change > 0 ? "priceUp" : "priceDown"));
7266
7285
  return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(
@@ -7306,7 +7325,7 @@ function KjunSparkline({
7306
7325
 
7307
7326
  // shared/package-runtime/table.ts
7308
7327
  var import_tokens44 = require("@kjun-ui/tokens");
7309
- var import_react60 = require("react");
7328
+ var import_react61 = require("react");
7310
7329
 
7311
7330
  // shared/package-runtime/table-model.ts
7312
7331
  function getValue(row, key) {
@@ -7350,11 +7369,11 @@ function useTableModel(props) {
7350
7369
  expandSingle = false,
7351
7370
  onExpandedRowsChange
7352
7371
  } = props;
7353
- const [internalSort, setSort] = (0, import_react60.useState)({
7372
+ const [internalSort, setSort] = (0, import_react61.useState)({
7354
7373
  key: "",
7355
7374
  order: "asc"
7356
- }), [internalExpanded, setExpanded] = (0, import_react60.useState)([]), [search, setSearch] = (0, import_react60.useState)(""), timer = (0, import_react60.useRef)(void 0);
7357
- (0, import_react60.useEffect)(() => () => clearTimeout(timer.current), []);
7375
+ }), [internalExpanded, setExpanded] = (0, import_react61.useState)([]), [search, setSearch] = (0, import_react61.useState)(""), timer = (0, import_react61.useRef)(void 0);
7376
+ (0, import_react61.useEffect)(() => () => clearTimeout(timer.current), []);
7358
7377
  const sort = props.sort === void 0 ? internalSort : (_a = props.sort) != null ? _a : { key: "", order: "asc" };
7359
7378
  const rows = sortTableRows(data, sort, { sortable, sortMode });
7360
7379
  const key = (row, index = 0) => tableRowKey(row, rowKey, index);
@@ -7508,19 +7527,19 @@ function TableToolbar({
7508
7527
 
7509
7528
  // packages/native/src/table-grid.tsx
7510
7529
  var import_tokens46 = require("@kjun-ui/tokens");
7511
- var import_react61 = require("react");
7530
+ var import_react62 = require("react");
7512
7531
  var import_react_native_svg7 = __toESM(require("react-native-svg"), 1);
7513
7532
  var import_react_native46 = require("react-native");
7514
7533
  var import_jsx_runtime43 = require("react/jsx-runtime");
7515
- function TableGrid({ initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7534
+ function TableGrid({ initialLoading, skeletonRows, skeletonHidden, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, sortable, compact, striped, hoverable }) {
7516
7535
  const { colors } = useKjunStyles();
7517
7536
  const geometry2 = import_tokens46.tokens.table;
7518
- const [scroll, setScroll] = (0, import_react61.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + (0, import_react61.useId)().replace(/[^a-z0-9]/gi, "");
7537
+ const [scroll, setScroll] = (0, import_react62.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-table-fade-" + (0, import_react62.useId)().replace(/[^a-z0-9]/gi, "");
7519
7538
  const cellPadding = geometry2.cellPadding[compact ? "compact" : "regular"];
7520
7539
  const width = (col) => typeof col.width === "number" ? col.width : typeof col.width === "string" && /^\d+(px)?$/.test(col.width) ? parseFloat(col.width) : geometry2.columnWidth;
7521
7540
  const totalWidth = visible.reduce((sum, col) => sum + width(col), 0) + (selectable ? geometry2.actionColumnWidth : 0) + (expandable ? geometry2.actionColumnWidth : 0);
7522
7541
  const fade = totalWidth - scroll.viewport - scroll.x > 1;
7523
- return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react_native46.View, { style: { position: "relative", minWidth: 0 }, children: [
7542
+ return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react_native46.View, { style: { position: "relative", minWidth: 0, opacity: skeletonHidden ? 0 : void 0 }, "aria-hidden": skeletonHidden || void 0, children: [
7524
7543
  /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
7525
7544
  import_react_native46.ScrollView,
7526
7545
  {
@@ -7629,7 +7648,7 @@ function TableGrid({ initialLoading, skeletonRows, state, onRowClick, selectable
7629
7648
  ))
7630
7649
  ] }, i)) : !state.rows.length ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native46.View, { style: { paddingVertical: geometry2.emptyPadding.y, paddingHorizontal: geometry2.emptyPadding.x, alignItems: "center" }, children: content(emptyContent || emptyText, {
7631
7650
  color: colors.textSecondary
7632
- }) }) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react61.Fragment, { children: [
7651
+ }) }) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(import_react62.Fragment, { children: [
7633
7652
  /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(
7634
7653
  AccessiblePressable,
7635
7654
  {
@@ -7718,6 +7737,7 @@ var import_jsx_runtime44 = require("react/jsx-runtime");
7718
7737
  function TableCards({
7719
7738
  initialLoading,
7720
7739
  skeletonRows,
7740
+ skeletonHidden,
7721
7741
  state,
7722
7742
  onRowClick,
7723
7743
  selectable,
@@ -7732,149 +7752,156 @@ function TableCards({
7732
7752
  }) {
7733
7753
  const { colors } = useKjunStyles();
7734
7754
  const { title, subtitle, badges, inline, sections, actions, columnsForSection } = layout;
7735
- return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native47.View, { style: { gap: import_tokens47.tokens.extensions.tableCard.gap, padding: import_tokens47.tokens.extensions.tableCard.listPadding }, children: [
7736
- initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7737
- AccessiblePressable,
7738
- {
7739
- accessible: false,
7740
- onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7741
- style: ({ pressed }) => ({
7742
- padding: import_tokens47.tokens.extensions.tableCard.padding,
7743
- borderWidth: import_tokens47.tokens.border.defaultWidth,
7744
- borderColor: colors.border,
7745
- borderRadius: import_tokens47.tokens.extensions.tableCard.radius,
7746
- backgroundColor: pressed ? colors.hover : colors.background
7747
- }),
7748
- children: [
7749
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7750
- import_react_native47.View,
7751
- {
7752
- style: {
7753
- flexDirection: "row",
7754
- alignItems: "center",
7755
- gap: import_tokens47.tokens.extensions.tableCard.gap,
7756
- marginBottom: import_tokens47.tokens.dimension.value8
7757
- },
7758
- children: [
7759
- /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7755
+ return /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7756
+ import_react_native47.View,
7757
+ {
7758
+ style: { gap: import_tokens47.tokens.extensions.tableCard.gap, padding: import_tokens47.tokens.extensions.tableCard.listPadding, opacity: skeletonHidden ? 0 : void 0 },
7759
+ "aria-hidden": skeletonHidden || void 0,
7760
+ children: [
7761
+ initialLoading ? Array.from({ length: skeletonRows }, (_, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(KjunSkeleton, { type: "card" }, i)) : state.rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7762
+ AccessiblePressable,
7763
+ {
7764
+ accessible: false,
7765
+ onPress: () => onRowClick == null ? void 0 : onRowClick(row, i),
7766
+ style: ({ pressed }) => ({
7767
+ padding: import_tokens47.tokens.extensions.tableCard.padding,
7768
+ borderWidth: import_tokens47.tokens.border.defaultWidth,
7769
+ borderColor: colors.border,
7770
+ borderRadius: import_tokens47.tokens.extensions.tableCard.radius,
7771
+ backgroundColor: pressed ? colors.hover : colors.background
7772
+ }),
7773
+ children: [
7774
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7775
+ import_react_native47.View,
7776
+ {
7777
+ style: {
7778
+ flexDirection: "row",
7779
+ alignItems: "center",
7780
+ gap: import_tokens47.tokens.extensions.tableCard.gap,
7781
+ marginBottom: import_tokens47.tokens.dimension.value8
7782
+ },
7783
+ children: [
7784
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7785
+ import_react_native47.View,
7786
+ {
7787
+ style: {
7788
+ flexDirection: "row",
7789
+ flex: 1,
7790
+ alignItems: "center",
7791
+ gap: import_tokens47.tokens.extensions.tableCard.gap,
7792
+ minWidth: 0
7793
+ },
7794
+ children: [
7795
+ selectable && checkbox(row, i),
7796
+ title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7797
+ ]
7798
+ }
7799
+ ),
7800
+ badges.length ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flexDirection: "row", gap: import_tokens47.tokens.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7801
+ inline.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flexDirection: "row", gap: import_tokens47.tokens.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { children: cell(col, row, i) }, col.key)) })
7802
+ ]
7803
+ }
7804
+ ),
7805
+ sections.map((section, index) => {
7806
+ const cols = columnsForSection(row, section);
7807
+ return cols.length ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7760
7808
  import_react_native47.View,
7761
7809
  {
7762
7810
  style: {
7763
- flexDirection: "row",
7764
- flex: 1,
7765
- alignItems: "center",
7766
- gap: import_tokens47.tokens.extensions.tableCard.gap,
7767
- minWidth: 0
7811
+ borderTopWidth: index ? import_tokens47.tokens.border.defaultWidth : 0,
7812
+ borderTopColor: colors.border,
7813
+ paddingTop: index ? import_tokens47.tokens.dimension.value12 : 0,
7814
+ marginTop: index ? import_tokens47.tokens.dimension.value12 : 0
7768
7815
  },
7769
7816
  children: [
7770
- selectable && checkbox(row, i),
7771
- title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flex: 1, minWidth: 0 }, children: cell(title, row, i, "title") })
7772
- ]
7773
- }
7774
- ),
7775
- badges.length ? /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flexDirection: "row", gap: import_tokens47.tokens.extensions.tableCard.fieldGap }, children: badges.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { children: cell(col, row, i) }, col.key)) }) : subtitle ? cell(subtitle, row, i) : null,
7776
- inline.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { flexDirection: "row", gap: import_tokens47.tokens.extensions.tableCard.fieldGap }, children: inline.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { children: cell(col, row, i) }, col.key)) })
7777
- ]
7778
- }
7779
- ),
7780
- sections.map((section, index) => {
7781
- const cols = columnsForSection(row, section);
7782
- return cols.length ? /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7783
- import_react_native47.View,
7784
- {
7785
- style: {
7786
- borderTopWidth: index ? import_tokens47.tokens.border.defaultWidth : 0,
7787
- borderTopColor: colors.border,
7788
- paddingTop: index ? import_tokens47.tokens.dimension.value12 : 0,
7789
- marginTop: index ? import_tokens47.tokens.dimension.value12 : 0
7790
- },
7791
- children: [
7792
- section.label && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7793
- KText,
7794
- {
7795
- style: {
7796
- ...typeStyle("controlSmall"),
7797
- color: colors.textTertiary,
7798
- marginBottom: import_tokens47.tokens.dimension.value6
7799
- },
7800
- children: section.label
7801
- }
7802
- ),
7803
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7804
- import_react_native47.View,
7805
- {
7806
- style: {
7807
- flexDirection: "row",
7808
- flexWrap: "wrap",
7809
- gap: section.layout === "metrics" ? import_tokens47.tokens.extensions.tableCard.gap : import_tokens47.tokens.extensions.tableCard.metricGap
7810
- },
7811
- children: cols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7817
+ section.label && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7818
+ KText,
7819
+ {
7820
+ style: {
7821
+ ...typeStyle("controlSmall"),
7822
+ color: colors.textTertiary,
7823
+ marginBottom: import_tokens47.tokens.dimension.value6
7824
+ },
7825
+ children: section.label
7826
+ }
7827
+ ),
7828
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7812
7829
  import_react_native47.View,
7813
7830
  {
7814
7831
  style: {
7815
- flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7816
- flexGrow: 1,
7817
- minWidth: 0,
7818
- gap: import_tokens47.tokens.extensions.tableCard.valueGap
7832
+ flexDirection: "row",
7833
+ flexWrap: "wrap",
7834
+ gap: section.layout === "metrics" ? import_tokens47.tokens.extensions.tableCard.gap : import_tokens47.tokens.extensions.tableCard.metricGap
7819
7835
  },
7820
- children: [
7821
- /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7822
- KText,
7823
- {
7824
- style: {
7825
- ...typeStyle("meta"),
7826
- color: colors.textTertiary,
7827
- textAlign: section.labelAlign
7828
- },
7829
- children: col.label
7830
- }
7831
- ),
7832
- cell(col, row, i)
7833
- ]
7834
- },
7835
- col.key
7836
- ))
7837
- }
7838
- )
7839
- ]
7840
- },
7841
- section.key || index
7842
- ) : null;
7843
- }),
7844
- expandable && expand(row, i),
7845
- expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7846
- import_react_native47.View,
7847
- {
7848
- style: {
7849
- borderTopWidth: import_tokens47.tokens.border.defaultWidth,
7850
- borderTopColor: colors.border,
7851
- paddingTop: import_tokens47.tokens.dimension.value8,
7852
- marginTop: import_tokens47.tokens.dimension.value4
7853
- },
7854
- children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7855
- }
7856
- ),
7857
- actions && !actions.inlineInCard && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7858
- import_react_native47.View,
7859
- {
7860
- style: {
7861
- borderTopWidth: import_tokens47.tokens.border.defaultWidth,
7862
- borderTopColor: colors.border,
7863
- paddingTop: import_tokens47.tokens.dimension.value8,
7864
- marginTop: import_tokens47.tokens.dimension.value8,
7865
- alignItems: "flex-end"
7866
- },
7867
- children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7868
- }
7869
- )
7870
- ]
7871
- },
7872
- state.key(row, i)
7873
- )),
7874
- !initialLoading && !state.rows.length && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { padding: import_tokens47.tokens.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7875
- color: colors.textTertiary
7876
- }) })
7877
- ] });
7836
+ children: cols.map((col) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
7837
+ import_react_native47.View,
7838
+ {
7839
+ style: {
7840
+ flexBasis: col.fullWidthInCard || section.layout === "stack" ? "100%" : section.layout === "metrics" ? "30%" : "47%",
7841
+ flexGrow: 1,
7842
+ minWidth: 0,
7843
+ gap: import_tokens47.tokens.extensions.tableCard.valueGap
7844
+ },
7845
+ children: [
7846
+ /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7847
+ KText,
7848
+ {
7849
+ style: {
7850
+ ...typeStyle("meta"),
7851
+ color: colors.textTertiary,
7852
+ textAlign: section.labelAlign
7853
+ },
7854
+ children: col.label
7855
+ }
7856
+ ),
7857
+ cell(col, row, i)
7858
+ ]
7859
+ },
7860
+ col.key
7861
+ ))
7862
+ }
7863
+ )
7864
+ ]
7865
+ },
7866
+ section.key || index
7867
+ ) : null;
7868
+ }),
7869
+ expandable && expand(row, i),
7870
+ expandable && state.expanded.includes(state.key(row, i)) && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7871
+ import_react_native47.View,
7872
+ {
7873
+ style: {
7874
+ borderTopWidth: import_tokens47.tokens.border.defaultWidth,
7875
+ borderTopColor: colors.border,
7876
+ paddingTop: import_tokens47.tokens.dimension.value8,
7877
+ marginTop: import_tokens47.tokens.dimension.value4
7878
+ },
7879
+ children: content(renderExpand == null ? void 0 : renderExpand(row, i))
7880
+ }
7881
+ ),
7882
+ actions && !actions.inlineInCard && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
7883
+ import_react_native47.View,
7884
+ {
7885
+ style: {
7886
+ borderTopWidth: import_tokens47.tokens.border.defaultWidth,
7887
+ borderTopColor: colors.border,
7888
+ paddingTop: import_tokens47.tokens.dimension.value8,
7889
+ marginTop: import_tokens47.tokens.dimension.value8,
7890
+ alignItems: "flex-end"
7891
+ },
7892
+ children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { alignSelf: "flex-end" }, children: cell(actions, row, i) })
7893
+ }
7894
+ )
7895
+ ]
7896
+ },
7897
+ state.key(row, i)
7898
+ )),
7899
+ !initialLoading && !state.rows.length && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native47.View, { style: { padding: import_tokens47.tokens.extensions.tableCard.emptyPadding, alignItems: "center" }, children: content(emptyContent || emptyText, {
7900
+ color: colors.textTertiary
7901
+ }) })
7902
+ ]
7903
+ }
7904
+ );
7878
7905
  }
7879
7906
 
7880
7907
  // packages/native/src/table-view.tsx
@@ -7882,6 +7909,9 @@ var import_jsx_runtime45 = require("react/jsx-runtime");
7882
7909
  function KjunTable(props) {
7883
7910
  const {
7884
7911
  skeletonRows = 8,
7912
+ skeleton = true,
7913
+ loadingText = "\uB85C\uB529 \uC911...",
7914
+ loadingDelay = 0,
7885
7915
  emptyText = "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
7886
7916
  hoverable = true,
7887
7917
  searchable = false,
@@ -7902,7 +7932,7 @@ function KjunTable(props) {
7902
7932
  onRowClick,
7903
7933
  onRetry
7904
7934
  } = props;
7905
- const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), mobile = (0, import_react_native48.useWindowDimensions)().width < import_tokens48.tokens.table.mobileBreakpoint;
7935
+ const { colors, domainColors } = useKjunStyles(), state = useTableModel2(props), query = useQueryDisplay(props), revealed = useLoadingReveal(query.initialLoading, skeleton ? loadingDelay : 0), mobile = (0, import_react_native48.useWindowDimensions)().width < import_tokens48.tokens.table.mobileBreakpoint;
7906
7936
  const layout = tablePresentation(props, mobile);
7907
7937
  const { card, visible } = layout;
7908
7938
  const cell = (col, row, index, role) => {
@@ -7981,8 +8011,11 @@ function KjunTable(props) {
7981
8011
  refreshing: query.queryRefreshing,
7982
8012
  loadingPadding: "none",
7983
8013
  onRetry,
8014
+ loading: skeleton ? void 0 : props.loading,
8015
+ loadingText,
8016
+ loadingDelay: skeleton ? 0 : loadingDelay,
7984
8017
  children: [
7985
- card ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TableCards, { ...{ initialLoading: query.initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, layout } }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TableGrid, { ...{ initialLoading: query.initialLoading, skeletonRows, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, visible, maxHeight, stickyHeader, compact, striped, hoverable }, sortable: props.sortable }),
8018
+ card ? /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(TableCards, { ...{ initialLoading: query.initialLoading, skeletonRows, skeletonHidden: query.initialLoading && !revealed, state, onRowClick, selectable, checkbox, cell, expandable, expand, renderExpand, emptyContent, emptyText, layout } }) : /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(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 }),
7986
8019
  pagination && /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
7987
8020
  KjunPagination,
7988
8021
  {
@@ -8040,12 +8073,13 @@ function KjunKpiHero(props) {
8040
8073
  secondary = [],
8041
8074
  animated = true,
8042
8075
  size = "md",
8076
+ surface = "card",
8043
8077
  aside,
8044
8078
  formatter,
8045
8079
  deltaFormatter,
8046
8080
  renderSecondary
8047
8081
  } = props;
8048
- const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = (0, import_react_native50.useWindowDimensions)().width <= import_tokens49.tokens.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
8082
+ const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), windowWidth = (0, import_react_native50.useWindowDimensions)().width, mobile = windowWidth <= import_tokens49.tokens.responsive.kpiHero, small = size === "sm", numberRole = small ? "displaySm" : mobile ? "displayMd" : "displayLg", font = typeStyle(numberRole).fontSize, unitStyle = typeStyle(small ? "numberSm" : mobile ? "numberMd" : "numberLg");
8049
8083
  const geometry2 = import_tokens49.tokens.extensions.kpiHero;
8050
8084
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8051
8085
  const numeric = {
@@ -8075,10 +8109,13 @@ function KjunKpiHero(props) {
8075
8109
  {
8076
8110
  accessibilityState: { busy: loading },
8077
8111
  style: {
8078
- paddingVertical: spec.paddingY,
8079
- paddingHorizontal: spec.paddingX,
8080
- backgroundColor: colors.surface,
8081
- borderRadius: geometry2.radius
8112
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
8113
+ ...surface === "none" ? {} : {
8114
+ paddingVertical: spec.paddingY,
8115
+ paddingHorizontal: spec.paddingX,
8116
+ backgroundColor: colors.surface,
8117
+ borderRadius: geometry2.radius
8118
+ }
8082
8119
  },
8083
8120
  children: [
8084
8121
  /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
@@ -8161,70 +8198,75 @@ function KjunKpiHero(props) {
8161
8198
  borderTopWidth: import_tokens49.tokens.border.defaultWidth,
8162
8199
  borderTopColor: colors.border
8163
8200
  },
8164
- children: secondary.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
8165
- import_react_native50.View,
8166
- {
8167
- style: mobile && !small ? {
8168
- flex: 1,
8169
- minWidth: 0,
8170
- paddingLeft: i ? geometry2.itemPadding : 0,
8171
- paddingRight: i === secondary.length - 1 ? 0 : geometry2.itemPadding,
8172
- borderLeftWidth: i ? import_tokens49.tokens.border.defaultWidth : 0,
8173
- borderLeftColor: colors.border
8174
- } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
8175
- children: [
8176
- /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8177
- KText,
8178
- {
8179
- style: {
8180
- color: colors.textTertiary,
8181
- ...typeStyle("caption"),
8182
- marginBottom: spec.secondaryLabelGap
8183
- },
8184
- children: item.label
8185
- }
8186
- ),
8187
- loading ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8188
- KjunSkeleton,
8189
- {
8190
- type: "block",
8191
- height: typeStyle("numberMd").lineHeight,
8192
- width: geometry2.secondarySkeletonWidth
8193
- }
8194
- ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8195
- KpiNumberLine,
8196
- {
8197
- prefix: item.prefix,
8198
- suffix: item.suffix,
8199
- prefixGap: geometry2.secondaryAffixGap,
8200
- suffixGap: geometry2.secondaryAffixGap,
8201
- unitStyle: typeStyle("caption"),
8202
- style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
8203
- children: kpiFormat(item)
8204
- }
8205
- ),
8206
- item.desc && (loading ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8207
- KjunSkeleton,
8208
- {
8209
- type: "block",
8210
- width: geometry2.descriptionSkeletonWidth,
8211
- height: typeStyle("caption").lineHeight
8212
- }
8213
- ) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8214
- KText,
8215
- {
8216
- style: {
8217
- ...typeStyle("caption"),
8218
- marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8219
- color: item.descColor || colors.textTertiary
8220
- },
8221
- children: item.desc
8222
- }
8223
- ))
8224
- ]
8225
- },
8226
- i
8227
- ))
8201
+ children: secondary.map((item, i) => {
8202
+ const columns = mobile && !small && windowWidth <= import_tokens49.tokens.responsive.kpiHeroSecondary && secondary.length >= 3 ? 2 : 0;
8203
+ const first = columns ? i % columns === 0 : i === 0;
8204
+ const last = columns ? i % columns === columns - 1 || i === secondary.length - 1 : i === secondary.length - 1;
8205
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
8206
+ import_react_native50.View,
8207
+ {
8208
+ style: mobile && !small ? {
8209
+ ...columns ? { width: `${100 / columns}%`, marginTop: i >= columns ? spec.secondaryPadding : 0 } : { flex: 1 },
8210
+ minWidth: 0,
8211
+ paddingLeft: first ? 0 : geometry2.itemPadding,
8212
+ paddingRight: last ? 0 : geometry2.itemPadding,
8213
+ borderLeftWidth: first ? 0 : import_tokens49.tokens.border.defaultWidth,
8214
+ borderLeftColor: colors.border
8215
+ } : { minWidth: 0, maxWidth: "100%", flexShrink: 1 },
8216
+ children: [
8217
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8218
+ KText,
8219
+ {
8220
+ style: {
8221
+ color: colors.textTertiary,
8222
+ ...typeStyle("caption"),
8223
+ marginBottom: spec.secondaryLabelGap
8224
+ },
8225
+ children: item.label
8226
+ }
8227
+ ),
8228
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8229
+ KjunSkeleton,
8230
+ {
8231
+ type: "block",
8232
+ height: typeStyle("numberMd").lineHeight,
8233
+ width: geometry2.secondarySkeletonWidth
8234
+ }
8235
+ ) : (renderSecondary == null ? void 0 : renderSecondary(item, i)) || /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8236
+ KpiNumberLine,
8237
+ {
8238
+ prefix: item.prefix,
8239
+ suffix: item.suffix,
8240
+ prefixGap: geometry2.secondaryAffixGap,
8241
+ suffixGap: geometry2.secondaryAffixGap,
8242
+ unitStyle: typeStyle("caption"),
8243
+ style: { ...numeric, ...typeStyle("numberMd"), color: item.valueColor || (item.semantic === "price" && Number(item.value) !== 0 ? direction(Number(item.value)) : colors.text) },
8244
+ children: kpiFormat(item)
8245
+ }
8246
+ ),
8247
+ item.desc && (loading ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8248
+ KjunSkeleton,
8249
+ {
8250
+ type: "block",
8251
+ width: geometry2.descriptionSkeletonWidth,
8252
+ height: typeStyle("caption").lineHeight
8253
+ }
8254
+ ) : /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
8255
+ KText,
8256
+ {
8257
+ style: {
8258
+ ...typeStyle("caption"),
8259
+ marginTop: small ? geometry2.sm.descriptionGap : geometry2.md.descriptionGap,
8260
+ color: item.descColor || colors.textTertiary
8261
+ },
8262
+ children: item.desc
8263
+ }
8264
+ ))
8265
+ ]
8266
+ },
8267
+ i
8268
+ );
8269
+ })
8228
8270
  }
8229
8271
  )
8230
8272
  ]
@@ -8234,13 +8276,14 @@ function KjunKpiHero(props) {
8234
8276
 
8235
8277
  // packages/native/src/kpi-row.tsx
8236
8278
  var import_tokens50 = require("@kjun-ui/tokens");
8237
- var import_react62 = require("react");
8279
+ var import_react63 = require("react");
8238
8280
  var import_react_native51 = require("react-native");
8239
8281
  var import_jsx_runtime48 = require("react/jsx-runtime");
8240
8282
  function KjunKpiRow({
8241
8283
  loading = false,
8242
8284
  items,
8243
8285
  size = "md",
8286
+ surface = "card",
8244
8287
  mobileSummary = true,
8245
8288
  onItemClick,
8246
8289
  renderValue
@@ -8248,7 +8291,7 @@ function KjunKpiRow({
8248
8291
  const { colors, domainColors, numericFontFamily, fontFamily } = useKjunStyles(), mobile = (0, import_react_native51.useWindowDimensions)().width <= import_tokens50.tokens.responsive.kpiRow, small = size === "sm", summary = mobileSummary && mobile && !small;
8249
8292
  const geometry2 = import_tokens50.tokens.extensions.kpiRow;
8250
8293
  const spec = small ? geometry2.sm : mobile ? geometry2.mobile : geometry2.md;
8251
- const [width, setWidth] = (0, import_react62.useState)(0);
8294
+ const [width, setWidth] = (0, import_react63.useState)(0);
8252
8295
  const paddingX = summary ? geometry2.summary.paddingX : spec.paddingX;
8253
8296
  const gapX = summary ? geometry2.summary.gapX : 0;
8254
8297
  const explicit = items.some(
@@ -8289,10 +8332,13 @@ function KjunKpiRow({
8289
8332
  style: {
8290
8333
  flexDirection: "row",
8291
8334
  flexWrap: mobile ? "wrap" : "nowrap",
8292
- paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8293
- paddingHorizontal: paddingX,
8294
- borderRadius: geometry2.radius,
8295
- backgroundColor: colors.surface,
8335
+ // surface="none" sits inside the app's own card or list, so it drops its own card box.
8336
+ ...surface === "none" ? {} : {
8337
+ paddingVertical: summary ? geometry2.summary.paddingY : spec.paddingY,
8338
+ paddingHorizontal: paddingX,
8339
+ borderRadius: geometry2.radius,
8340
+ backgroundColor: colors.surface
8341
+ },
8296
8342
  rowGap: summary ? geometry2.summary.gapY : 0,
8297
8343
  columnGap: gapX
8298
8344
  },
@@ -8464,7 +8510,7 @@ var import_tokens52 = require("@kjun-ui/tokens");
8464
8510
  var import_react_native53 = require("react-native");
8465
8511
 
8466
8512
  // shared/package-runtime/market-cards.ts
8467
- var import_react63 = require("react");
8513
+ var import_react64 = require("react");
8468
8514
  function useMarketCardsModel(props, persistence) {
8469
8515
  const {
8470
8516
  columns,
@@ -8480,8 +8526,8 @@ function useMarketCardsModel(props, persistence) {
8480
8526
  sortKey: c.sortable ? metricConfig[c.key].sortKey : null,
8481
8527
  isDefaultSort: c.defaultSort
8482
8528
  }));
8483
- const [key, setKey] = (0, import_react63.useState)(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8484
- const mounted = (0, import_react63.useRef)("");
8529
+ const [key, setKey] = (0, import_react64.useState)(""), restoreSignature = JSON.stringify([storageNamespace, pills]);
8530
+ const mounted = (0, import_react64.useRef)("");
8485
8531
  const save = (key2) => {
8486
8532
  var _a;
8487
8533
  try {
@@ -8489,7 +8535,7 @@ function useMarketCardsModel(props, persistence) {
8489
8535
  } catch (e) {
8490
8536
  }
8491
8537
  };
8492
- (0, import_react63.useEffect)(() => {
8538
+ (0, import_react64.useEffect)(() => {
8493
8539
  var _a, _b;
8494
8540
  if (mounted.current === restoreSignature) return;
8495
8541
  mounted.current = restoreSignature;
@@ -8731,7 +8777,7 @@ function KjunMarketCards(props) {
8731
8777
  ...props,
8732
8778
  loadingPadding: "none",
8733
8779
  empty: !rows.length,
8734
- loadingContent: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(KjunListSkeleton, { variant: "compact" }),
8780
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(KjunListSkeleton, { variant: "compact" }),
8735
8781
  emptyContent: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8736
8782
  children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_react_native53.View, { children: [
8737
8783
  state.pill && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(KText, { style: { textAlign: "right", paddingHorizontal: import_tokens52.tokens.dimension.value16, paddingVertical: import_tokens52.tokens.dimension.value8, ...typeStyle("caption"), color: colors.textSecondary }, children: state.pill.label }),
@@ -8842,7 +8888,7 @@ function KjunMarketSimpleList(props) {
8842
8888
  loadingPadding: "none",
8843
8889
  empty: !rows.length,
8844
8890
  emptyText: emptyMessage,
8845
- loadingContent: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(KjunListSkeleton, {}),
8891
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(KjunListSkeleton, {}),
8846
8892
  emptyContent: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
8847
8893
  children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(import_react_native54.View, { children: rows.map((row, i) => {
8848
8894
  var _a, _b;
@@ -8969,7 +9015,7 @@ function KjunMarketListPanel({
8969
9015
 
8970
9016
  // packages/native/src/market-table.tsx
8971
9017
  var import_tokens55 = require("@kjun-ui/tokens");
8972
- var import_react64 = require("react");
9018
+ var import_react65 = require("react");
8973
9019
  var import_react_native56 = require("react-native");
8974
9020
  var import_react_native_svg8 = __toESM(require("react-native-svg"), 1);
8975
9021
  var import_jsx_runtime53 = require("react/jsx-runtime");
@@ -9055,7 +9101,7 @@ function KjunMarketTable(props) {
9055
9101
  );
9056
9102
  };
9057
9103
  const layout = useMarketLayout(columns, showActions);
9058
- const [scroll, setScroll] = (0, import_react64.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + (0, import_react64.useId)().replace(/[^a-z0-9]/gi, "");
9104
+ const [scroll, setScroll] = (0, import_react65.useState)({ viewport: 0, x: 0 }), fadeId = "kjun-market-fade-" + (0, import_react65.useId)().replace(/[^a-z0-9]/gi, "");
9059
9105
  const tableQuote = { price: {}, change: { fontWeight: typeStyle("body").fontWeight } };
9060
9106
  return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
9061
9107
  import_react_native56.View,
@@ -9073,7 +9119,7 @@ function KjunMarketTable(props) {
9073
9119
  loadingPadding: "none",
9074
9120
  empty: !rows.length,
9075
9121
  emptyText: emptyMessage,
9076
- loadingContent: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(KjunMarketTableSkeleton, { columns, showActions }),
9122
+ loadingContent: props.skeleton === false ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(KjunMarketTableSkeleton, { columns, showActions }),
9077
9123
  emptyContent: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(KjunEmpty, { text: emptyMessage, description: emptySubMessage }),
9078
9124
  children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(MarketQuoteTypeContext.Provider, { value: tableQuote, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_react_native56.View, { style: { position: "relative", minWidth: 0 }, children: [
9079
9125
  /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
@@ -9278,12 +9324,12 @@ function KjunMarketTable(props) {
9278
9324
 
9279
9325
  // packages/native/src/list.tsx
9280
9326
  var import_tokens56 = require("@kjun-ui/tokens");
9281
- var import_react65 = require("react");
9327
+ var import_react66 = require("react");
9282
9328
  var import_react_native57 = require("react-native");
9283
9329
  var import_jsx_runtime54 = require("react/jsx-runtime");
9284
- var LastListRow = (0, import_react65.createContext)(false);
9330
+ var LastListRow = (0, import_react66.createContext)(false);
9285
9331
  function KjunListRow({ title, description, leading, trailing, actions, href, disabled = false, onPress }) {
9286
- const { colors } = useKjunStyles(), last = (0, import_react65.useContext)(LastListRow);
9332
+ const { colors } = useKjunStyles(), last = (0, import_react66.useContext)(LastListRow);
9287
9333
  const parts = /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_jsx_runtime54.Fragment, { children: [
9288
9334
  leading && /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_native57.View, { children: content(leading) }),
9289
9335
  /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_react_native57.View, { style: { flex: 1, minWidth: 0 }, children: [
@@ -9308,13 +9354,13 @@ function KjunListSection({ title, description, actions, children, ariaLabel }) {
9308
9354
  ] }),
9309
9355
  content(actions)
9310
9356
  ] }),
9311
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_native57.View, { role: "list", accessibilityLabel: ariaLabel || title, children: import_react65.Children.toArray(children).map((row, i, rows) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(LastListRow.Provider, { value: i === rows.length - 1, children: row }, i)) })
9357
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_native57.View, { role: "list", accessibilityLabel: ariaLabel || title, children: import_react66.Children.toArray(children).map((row, i, rows) => /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(LastListRow.Provider, { value: i === rows.length - 1, children: row }, i)) })
9312
9358
  ] });
9313
9359
  }
9314
9360
 
9315
9361
  // packages/native/src/app-navigation.tsx
9316
9362
  var import_tokens57 = require("@kjun-ui/tokens");
9317
- var import_react66 = require("react");
9363
+ var import_react67 = require("react");
9318
9364
  var import_react_native58 = require("react-native");
9319
9365
  var import_jsx_runtime55 = require("react/jsx-runtime");
9320
9366
  function KjunTopNavigation({ title, description, leading, actions, safeAreaTop = 0 }) {
@@ -9323,13 +9369,13 @@ function KjunTopNavigation({ title, description, leading, actions, safeAreaTop =
9323
9369
  const titleInset = Math.max(0, (geometry2.controlSize - import_tokens57.tokens.typography.sectionTitle.lineHeightPx) / 2);
9324
9370
  const wrapping = import_react_native58.Platform.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
9325
9371
  const edgeInset = (geometry2.controlSize - geometry2.iconSize) / 2;
9326
- const [iconEdges, setIconEdges] = (0, import_react66.useState)({ leading: false, trailing: false });
9372
+ const [iconEdges, setIconEdges] = (0, import_react67.useState)({ leading: false, trailing: false });
9327
9373
  const square = (key) => (event) => {
9328
9374
  const { width, height } = event.nativeEvent.layout;
9329
9375
  const next = Math.abs(width - height) < 1 && Math.abs(height - geometry2.controlSize) < 1;
9330
9376
  setIconEdges((current) => current[key] === next ? current : { ...current, [key]: next });
9331
9377
  };
9332
- const flatten = (node) => import_react66.Children.toArray(node).flatMap((child) => (0, import_react66.isValidElement)(child) && child.type === import_react66.Fragment ? flatten(child.props.children) : [child]);
9378
+ const flatten = (node) => import_react67.Children.toArray(node).flatMap((child) => (0, import_react67.isValidElement)(child) && child.type === import_react67.Fragment ? flatten(child.props.children) : [child]);
9333
9379
  const actionList = flatten(actions);
9334
9380
  return /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TopNavigationContext.Provider, { value: geometry2, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native58.View, { style: { flexShrink: 0, paddingTop: Math.max(0, safeAreaTop), backgroundColor: colors.surface }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)(import_react_native58.View, { style: { minHeight: geometry2.minimumHeight, flexDirection: "row", flexWrap: "wrap", alignItems: "flex-start", gap: geometry2.gap, paddingVertical: geometry2.paddingY, paddingHorizontal: geometry2.paddingX }, children: [
9335
9381
  leading && /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(TopNavigationContext.Provider, { value: { ...geometry2, slot: "leading" }, children: /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(import_react_native58.View, { onLayout: square("leading"), style: { minHeight: geometry2.controlSize, minWidth: 0, maxWidth: "40%", flexShrink: 1, justifyContent: "center", marginLeft: iconEdges.leading ? -edgeInset : 0 }, children: content(leading) }) }),
@@ -9403,7 +9449,7 @@ function KjunBottomNavigation({ items, value, ariaLabel = "\uC8FC\uC694 \uD0D0\u
9403
9449
  }
9404
9450
  function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboardVisible = false, hideOnKeyboard = false }) {
9405
9451
  const { colors } = useKjunStyles();
9406
- const [width, setWidth] = (0, import_react66.useState)(0);
9452
+ const [width, setWidth] = (0, import_react67.useState)(0);
9407
9453
  const geometry2 = import_tokens57.tokens.extensions.navigation;
9408
9454
  const wide = width >= import_tokens57.tokens.responsive.bottomAction + geometry2.padding * 2;
9409
9455
  const wrapping = import_react_native58.Platform.OS === "web" ? { wordBreak: "keep-all", overflowWrap: "anywhere" } : {};
@@ -9425,16 +9471,16 @@ function KjunBottomActionBar({ description, children, safeAreaBottom = 0, keyboa
9425
9471
  }
9426
9472
 
9427
9473
  // packages/native/src/media.tsx
9428
- var import_react67 = require("react");
9474
+ var import_react68 = require("react");
9429
9475
  var import_react_native59 = require("react-native");
9430
9476
  var import_tokens58 = require("@kjun-ui/tokens");
9431
9477
  var import_jsx_runtime56 = require("react/jsx-runtime");
9432
9478
  function KjunImage({ src, source, alt, decorative = false, aspectRatio = 1, fit = "cover", fallback: fallback2, onLoad, onError }) {
9433
9479
  const { colors } = useKjunStyles();
9434
- const request = JSON.stringify(source != null ? source : src), current = (0, import_react67.useRef)({ request, version: 0 });
9480
+ const request = JSON.stringify(source != null ? source : src), current = (0, import_react68.useRef)({ request, version: 0 });
9435
9481
  if (current.current.request !== request) current.current = { request, version: current.current.version + 1 };
9436
9482
  const version = current.current.version;
9437
- const [failed, setFailed] = (0, import_react67.useState)(null);
9483
+ const [failed, setFailed] = (0, import_react68.useState)(null);
9438
9484
  const missing = !source && !src;
9439
9485
  return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.View, { accessibilityElementsHidden: decorative, importantForAccessibility: decorative ? "no-hide-descendants" : "auto", "aria-hidden": decorative || void 0, style: { width: "100%", aspectRatio: aspectRatio > 0 ? aspectRatio : 1, overflow: "hidden", backgroundColor: colors.secondary }, children: !missing && failed !== version ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(import_react_native59.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: () => {
9440
9486
  if (version === current.current.version) onLoad == null ? void 0 : onLoad();
@@ -9464,7 +9510,7 @@ function KjunChip({ label, icon, removable = false, disabled = false, size = "md
9464
9510
  }
9465
9511
 
9466
9512
  // packages/native/src/range-input.tsx
9467
- var import_react68 = require("react");
9513
+ var import_react69 = require("react");
9468
9514
  var import_react_native61 = require("react-native");
9469
9515
  var import_tokens60 = require("@kjun-ui/tokens");
9470
9516
  var import_jsx_runtime58 = require("react/jsx-runtime");
@@ -9488,18 +9534,18 @@ function RangeInput({
9488
9534
  const valid = domain.valid && (!Array.isArray(value) || value.length === 2) && values.every(domain.accepts) && (values.length === 1 || values[0] <= values[1]);
9489
9535
  const blocked = disabled || !valid;
9490
9536
  const effectiveMax = valid ? domain.snap(max) : min;
9491
- const [hovered, setHovered] = (0, import_react68.useState)(null);
9492
- const [dragging, setDragging] = (0, import_react68.useState)(null);
9493
- const [focused, setFocused] = (0, import_react68.useState)(null);
9494
- const track = (0, import_react68.useRef)(null), measured = (0, import_react68.useRef)({ x: 0, width: 1 }), selected = (0, import_react68.useRef)(0), dirty = (0, import_react68.useRef)(false);
9495
- const latest = (0, import_react68.useRef)(values);
9537
+ const [hovered, setHovered] = (0, import_react69.useState)(null);
9538
+ const [dragging, setDragging] = (0, import_react69.useState)(null);
9539
+ const [focused, setFocused] = (0, import_react69.useState)(null);
9540
+ const track = (0, import_react69.useRef)(null), measured = (0, import_react69.useRef)({ x: 0, width: 1 }), selected = (0, import_react69.useRef)(0), dirty = (0, import_react69.useRef)(false);
9541
+ const latest = (0, import_react69.useRef)(values);
9496
9542
  latest.current = values;
9497
- const callbacks = (0, import_react68.useRef)({ onValueChange, onChangeCommit });
9543
+ const callbacks = (0, import_react69.useRef)({ onValueChange, onChangeCommit });
9498
9544
  callbacks.current = { onValueChange, onChangeCommit };
9499
- (0, import_react68.useEffect)(() => {
9545
+ (0, import_react69.useEffect)(() => {
9500
9546
  if (!valid) console.warn("KJUN Slider: \uBC94\uC704\xB7step\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9501
9547
  }, [valid]);
9502
- (0, import_react68.useEffect)(() => {
9548
+ (0, import_react69.useEffect)(() => {
9503
9549
  if (blocked) {
9504
9550
  setDragging(null);
9505
9551
  setHovered(null);
@@ -9539,7 +9585,7 @@ function RangeInput({
9539
9585
  measured.current = { x: pageX, width: Math.max(1, width) };
9540
9586
  });
9541
9587
  };
9542
- const responder = (0, import_react68.useMemo)(
9588
+ const responder = (0, import_react69.useMemo)(
9543
9589
  () => import_react_native61.PanResponder.create({
9544
9590
  onStartShouldSetPanResponderCapture: () => !disabled && valid,
9545
9591
  onMoveShouldSetPanResponderCapture: (_event, gesture) => !disabled && valid && Math.abs(gesture.dx) > 3 && Math.abs(gesture.dx) > Math.abs(gesture.dy),
@@ -9764,7 +9810,7 @@ function KjunRangeSlider(props) {
9764
9810
  }
9765
9811
 
9766
9812
  // packages/native/src/quantity-stepper.tsx
9767
- var import_react69 = require("react");
9813
+ var import_react70 = require("react");
9768
9814
  var import_react_native62 = require("react-native");
9769
9815
  var import_tokens61 = require("@kjun-ui/tokens");
9770
9816
 
@@ -9786,16 +9832,16 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9786
9832
  const increaseStyle = { ...buttonStyle, borderRadius: 0, borderTopRightRadius: outer, borderBottomRightRadius: outer };
9787
9833
  const domain = (0, import_tokens61.createNumberDomain)({ min, max, step, precision }), valid = domain.valid && domain.accepts(value), blocked = disabled || !valid;
9788
9834
  const surface = useFieldSurface(size, { disabled: blocked, invalid });
9789
- const [draft, setDraft] = (0, import_react69.useState)(String(value));
9790
- const inputRef = (0, import_react69.useRef)(null);
9791
- const composing = (0, import_react69.useRef)(false), dirty = (0, import_react69.useRef)(false), accepted = (0, import_react69.useRef)(value);
9792
- const cancelledEscape = (0, import_react69.useRef)(false);
9793
- (0, import_react69.useEffect)(() => {
9835
+ const [draft, setDraft] = (0, import_react70.useState)(String(value));
9836
+ const inputRef = (0, import_react70.useRef)(null);
9837
+ const composing = (0, import_react70.useRef)(false), dirty = (0, import_react70.useRef)(false), accepted = (0, import_react70.useRef)(value);
9838
+ const cancelledEscape = (0, import_react70.useRef)(false);
9839
+ (0, import_react70.useEffect)(() => {
9794
9840
  setDraft(String(value));
9795
9841
  accepted.current = value;
9796
9842
  dirty.current = false;
9797
9843
  }, [value, precision, min, max, step]);
9798
- (0, import_react69.useEffect)(() => {
9844
+ (0, import_react70.useEffect)(() => {
9799
9845
  if (!valid) console.warn("KJUN QuantityStepper: \uBC94\uC704\xB7step\xB7\uC815\uBC00\uB3C4\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9800
9846
  }, [valid]);
9801
9847
  const emit = (next) => {
@@ -9832,7 +9878,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9832
9878
  } else if (action === "commit") commit();
9833
9879
  else move(action === "increment" ? 1 : -1);
9834
9880
  };
9835
- const handlers = (0, import_react69.useRef)({ key, edit: (text) => {
9881
+ const handlers = (0, import_react70.useRef)({ key, edit: (text) => {
9836
9882
  dirty.current = true;
9837
9883
  setDraft(text);
9838
9884
  } });
@@ -9840,7 +9886,7 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9840
9886
  dirty.current = true;
9841
9887
  setDraft(text);
9842
9888
  } };
9843
- (0, import_react69.useEffect)(() => {
9889
+ (0, import_react70.useEffect)(() => {
9844
9890
  if (import_react_native62.Platform.OS !== "web") return;
9845
9891
  const input = inputRef.current;
9846
9892
  const keydown = (event) => handlers.current.key(event);
@@ -9912,19 +9958,19 @@ function KjunQuantityStepper({ value, min = 0, max, step = 1, precision = 0, dis
9912
9958
  }
9913
9959
 
9914
9960
  // packages/native/src/time-picker.tsx
9915
- var import_react70 = require("react");
9961
+ var import_react71 = require("react");
9916
9962
  var import_react_native63 = require("react-native");
9917
9963
  var import_tokens62 = require("@kjun-ui/tokens");
9918
9964
  var import_jsx_runtime60 = require("react/jsx-runtime");
9919
9965
  function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1, secondStep = 1, disabled = false, error = false, clearable = true, size = "md", ariaLabel = "\uC2DC\uAC04", onValueChange, onChangeCommit }) {
9920
9966
  const geometry2 = import_tokens62.tokens.extensions.timePicker, spec = import_tokens62.tokens.input[size];
9921
9967
  const { colors } = useKjunStyles();
9922
- const first = (0, import_react70.useRef)(null);
9923
- const [focused, setFocused] = (0, import_react70.useState)(false), [opened, setOpened] = (0, import_react70.useState)(null);
9924
- const field = useKjunField(), uid = (0, import_react70.useId)();
9968
+ const first = (0, import_react71.useRef)(null);
9969
+ const [focused, setFocused] = (0, import_react71.useState)(false), [opened, setOpened] = (0, import_react71.useState)(null);
9970
+ const field = useKjunField(), uid = (0, import_react71.useId)();
9925
9971
  const fieldId = (field == null ? void 0 : field.id) || `kjun-time-${uid}`;
9926
- const domain = (0, import_react70.useMemo)(() => (0, import_tokens62.createTimeDomain)({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
9927
- (0, import_react70.useEffect)(() => {
9972
+ const domain = (0, import_react71.useMemo)(() => (0, import_tokens62.createTimeDomain)({ precision, min, max, minuteStep, secondStep }), [precision, min, max, minuteStep, secondStep]), valid = domain.valid && domain.accepts(value);
9973
+ (0, import_react71.useEffect)(() => {
9928
9974
  if (!valid) console.warn("KJUN TimePicker: \uC2DC\uAC01 \uBC94\uC704\xB7\uAC04\uACA9\xB7\uAC12\uC744 \uD655\uC778\uD558\uC138\uC694.");
9929
9975
  }, [valid]);
9930
9976
  const change = (next) => {
@@ -9935,7 +9981,7 @@ function KjunTimePicker({ value, precision = "minute", min, max, minuteStep = 1,
9935
9981
  };
9936
9982
  const time = value === null ? null : domain.parse(value);
9937
9983
  return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_react_native63.View, { accessibilityLabel: ariaLabel, style: { flexDirection: "row", alignItems: "center", maxWidth: "100%", minWidth: 0, backgroundColor: colors.inputBg, borderRadius: spec.radius }, children: [
9938
- /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_native63.View, { style: { flex: 1, flexDirection: "row", alignItems: "center", minWidth: 0 }, children: ["\uC2DC", "\uBD84", "\uCD08"].slice(0, precision === "second" ? 3 : 2).map((label, index) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_react70.Fragment, { children: [
9984
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_native63.View, { style: { flex: 1, flexDirection: "row", alignItems: "center", minWidth: 0 }, children: ["\uC2DC", "\uBD84", "\uCD08"].slice(0, precision === "second" ? 3 : 2).map((label, index) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(import_react71.Fragment, { children: [
9939
9985
  index > 0 && /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(KText, { "aria-hidden": true, style: { ...inputTypeStyle(size), width: geometry2.separatorWidth, textAlign: "center", color: disabled || !valid ? colors.textDisabled : colors.textSecondary }, children: ":" }),
9940
9986
  /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(FieldContext.Provider, { value: { ...field, id: index === 0 ? fieldId : `${fieldId}-${index}` }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(CompoundControlContext.Provider, { value: { size, focusRef: index === 0 ? first : void 0, onFocusChange: setFocused, leading: index === 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(import_react_native63.View, { style: { flexShrink: 0, minWidth: geometry2.segmentMinimumWidth }, children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(KjunSelect, { value: time === null ? null : domain.part(time, index), options: domain.options(value, index).map((n) => ({ value: n, label: String(n).padStart(2, "0") })), onValueChange: (next) => {
9941
9987
  if (typeof next === "number") change(domain.select(value, index, next));