@kjun-ui/native 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +59 -16
- package/dist/index.js +59 -16
- package/dist/index.web.cjs +59 -16
- package/dist/index.web.js +59 -16
- package/dist/types/packages/native/src/select-control.d.cts +5 -1
- package/dist/types/packages/native/src/select-control.d.ts +5 -1
- package/dist/types/shared/package-runtime/layer-state.d.cts +3 -0
- package/dist/types/shared/package-runtime/layer-state.d.ts +3 -0
- package/dist/types/shared/package-runtime/options.d.cts +5 -1
- package/dist/types/shared/package-runtime/options.d.ts +5 -1
- package/dist/types/shared/package-runtime/table-presentation.d.cts +4 -0
- package/dist/types/shared/package-runtime/table-presentation.d.ts +4 -0
- package/dist/types/shared/package-runtime/use-layer.d.cts +3 -1
- package/dist/types/shared/package-runtime/use-layer.d.ts +3 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -234,6 +234,10 @@ function installLayerKeyboard(document2, state, keyupFallback = false) {
|
|
|
234
234
|
var import_react2 = require("react");
|
|
235
235
|
|
|
236
236
|
// shared/package-runtime/layer-state.ts
|
|
237
|
+
function chooseReturnTarget(chosen, fallback2) {
|
|
238
|
+
if (chosen === false) return void 0;
|
|
239
|
+
return chosen && chosen.isConnected !== false ? chosen : fallback2;
|
|
240
|
+
}
|
|
237
241
|
function createLayerState() {
|
|
238
242
|
const entries = /* @__PURE__ */ new Map(), listeners = /* @__PURE__ */ new Set();
|
|
239
243
|
const restoredFocus = /* @__PURE__ */ new WeakSet();
|
|
@@ -254,6 +258,7 @@ function createLayerState() {
|
|
|
254
258
|
return !layer.blocked && (layer.kind === "window" ? ((_a = topWindow()) == null ? void 0 : _a.id) === layer.id : ((_b = topWindow()) == null ? void 0 : _b.id) === layer.owner);
|
|
255
259
|
};
|
|
256
260
|
const top = () => [...entries.values()].filter(active).sort((a, b) => a.order - b.order).at(-1);
|
|
261
|
+
const topPopup = () => [...entries.values()].filter((layer) => layer.kind !== "tooltip" && active(layer)).sort((a, b) => a.order - b.order).at(-1);
|
|
257
262
|
function dismiss(layer) {
|
|
258
263
|
if (layer.closeRequested) return;
|
|
259
264
|
layer.closeRequested = true;
|
|
@@ -273,6 +278,7 @@ function createLayerState() {
|
|
|
273
278
|
entries,
|
|
274
279
|
topWindow,
|
|
275
280
|
top,
|
|
281
|
+
topPopup,
|
|
276
282
|
windowOf,
|
|
277
283
|
isRestoredFocus(target) {
|
|
278
284
|
return !!target && restoredFocus.has(target);
|
|
@@ -421,21 +427,31 @@ function focusTrigger(target) {
|
|
|
421
427
|
}
|
|
422
428
|
return target;
|
|
423
429
|
}
|
|
424
|
-
function restoreFocus(target, state, id) {
|
|
430
|
+
function restoreFocus(target, state, id, fallback2) {
|
|
431
|
+
const usable = (item) => (item == null ? void 0 : item.isConnected) !== false && !(typeof HTMLElement !== "undefined" && item instanceof HTMLElement && item.closest("[inert]"));
|
|
425
432
|
const restore = () => {
|
|
426
|
-
var _a, _b, _c, _d;
|
|
433
|
+
var _a, _b, _c, _d, _e;
|
|
427
434
|
if (state.entries.has(id)) return;
|
|
428
|
-
if ((target
|
|
429
|
-
else (
|
|
435
|
+
if (usable(target)) (_a = target == null ? void 0 : target.focus) == null ? void 0 : _a.call(target, { preventScroll: true });
|
|
436
|
+
else if (fallback2 && fallback2 !== target && usable(fallback2)) (_b = fallback2.focus) == null ? void 0 : _b.call(fallback2, { preventScroll: true });
|
|
437
|
+
else (_e = (_d = (_c = state.topWindow()) == null ? void 0 : _c.root) == null ? void 0 : _d.focus) == null ? void 0 : _e.call(_d, { preventScroll: true });
|
|
430
438
|
};
|
|
431
439
|
if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(restore);
|
|
432
440
|
else queueMicrotask(restore);
|
|
433
441
|
}
|
|
434
|
-
function useLayer(open, present, kind, close, trigger) {
|
|
442
|
+
function useLayer(open, present, kind, close, trigger, returnFocus) {
|
|
435
443
|
var _a;
|
|
436
444
|
const state = useLayerState(), parent = (0, import_react2.useContext)(LayerScope), id = (0, import_react2.useId)();
|
|
437
445
|
const callback = (0, import_react2.useRef)(close);
|
|
438
446
|
callback.current = close;
|
|
447
|
+
const returnRef = (0, import_react2.useRef)(returnFocus);
|
|
448
|
+
returnRef.current = returnFocus;
|
|
449
|
+
const fallbackFocus = (0, import_react2.useRef)(null);
|
|
450
|
+
const removeLayer = () => {
|
|
451
|
+
const removed = state.remove(id, currentFocus());
|
|
452
|
+
if (removed) fallbackFocus.current = removed;
|
|
453
|
+
return removed && returnRef.current ? chooseReturnTarget(returnRef.current(), removed) : removed;
|
|
454
|
+
};
|
|
439
455
|
const openingFocus = (0, import_react2.useRef)(null);
|
|
440
456
|
const wasOpen = (0, import_react2.useRef)(false);
|
|
441
457
|
const pendingFocus = (0, import_react2.useRef)(null);
|
|
@@ -447,17 +463,17 @@ function useLayer(open, present, kind, close, trigger) {
|
|
|
447
463
|
state.open(id, kind, parent, () => callback.current(), focusTrigger(trigger == null ? void 0 : trigger.current) || openingFocus.current);
|
|
448
464
|
} else if (kind === "window" && present) state.markClosing(id);
|
|
449
465
|
else if (kind !== "window" || !present) {
|
|
450
|
-
const target =
|
|
466
|
+
const target = removeLayer();
|
|
451
467
|
if (target) pendingFocus.current = target;
|
|
452
468
|
if (!present && pendingFocus.current) {
|
|
453
|
-
restoreFocus(pendingFocus.current, state, id);
|
|
469
|
+
restoreFocus(pendingFocus.current, state, id, fallbackFocus.current);
|
|
454
470
|
pendingFocus.current = null;
|
|
455
471
|
}
|
|
456
472
|
}
|
|
457
473
|
}, [open, present, state, id, kind, parent, trigger]);
|
|
458
474
|
(0, import_react2.useLayoutEffect)(() => () => {
|
|
459
|
-
const target =
|
|
460
|
-
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id);
|
|
475
|
+
const target = removeLayer();
|
|
476
|
+
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id, fallbackFocus.current);
|
|
461
477
|
}, [state, id]);
|
|
462
478
|
const entry = state.entries.get(id);
|
|
463
479
|
return {
|
|
@@ -3065,7 +3081,7 @@ function KjunRadioGroup({
|
|
|
3065
3081
|
accessibilityLabel: ariaLabel,
|
|
3066
3082
|
style: {
|
|
3067
3083
|
flexDirection: direction === "vertical" ? "column" : "row",
|
|
3068
|
-
flexWrap: "wrap",
|
|
3084
|
+
flexWrap: direction === "vertical" ? "nowrap" : "wrap",
|
|
3069
3085
|
gap: direction === "vertical" ? import_tokens18.tokens.dimension.value8 : import_tokens18.tokens.dimension.value16
|
|
3070
3086
|
},
|
|
3071
3087
|
children: children || options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
@@ -4254,6 +4270,17 @@ function nextOptionValue(value, option, key, multiple) {
|
|
|
4254
4270
|
if (!multiple) return id;
|
|
4255
4271
|
return Array.isArray(value) && value.includes(id) ? value.filter((item) => item !== id) : [...Array.isArray(value) ? value : [], id];
|
|
4256
4272
|
}
|
|
4273
|
+
function optionMatchRank(option, query, labelKey, searchKeys = []) {
|
|
4274
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
4275
|
+
if (!needle) return 0;
|
|
4276
|
+
const label = optionLabel(option, labelKey).toLocaleLowerCase();
|
|
4277
|
+
if (label.startsWith(needle)) return 0;
|
|
4278
|
+
if (label.includes(needle)) return 1;
|
|
4279
|
+
return typeof option === "object" && searchKeys.some((key) => {
|
|
4280
|
+
var _a;
|
|
4281
|
+
return String((_a = option[key]) != null ? _a : "").toLocaleLowerCase().includes(needle);
|
|
4282
|
+
}) ? 2 : -1;
|
|
4283
|
+
}
|
|
4257
4284
|
function selectOptions({
|
|
4258
4285
|
options,
|
|
4259
4286
|
value,
|
|
@@ -4263,10 +4290,13 @@ function selectOptions({
|
|
|
4263
4290
|
pageSize,
|
|
4264
4291
|
limit,
|
|
4265
4292
|
loading,
|
|
4266
|
-
multiple
|
|
4293
|
+
multiple,
|
|
4294
|
+
filterFn,
|
|
4295
|
+
searchKeys = []
|
|
4267
4296
|
}) {
|
|
4268
4297
|
const selected = (option) => optionSelected(value, option, valueKey);
|
|
4269
|
-
const
|
|
4298
|
+
const indexed = options.map((option, index) => ({ option, key: optionKey(option, valueKey, index) }));
|
|
4299
|
+
const matching = filterFn ? indexed.filter(({ option }) => filterFn(option, query)) : indexed.map((item, index) => ({ item, index, rank: optionMatchRank(item.option, query, labelKey, searchKeys) })).filter(({ rank }) => rank >= 0).sort((a, b) => a.rank - b.rank || a.index - b.index).map(({ item }) => item);
|
|
4270
4300
|
const visible = loading ? [] : pageSize > 0 ? matching.slice(0, limit) : matching;
|
|
4271
4301
|
const selectedOption = options.find(selected);
|
|
4272
4302
|
const label = multiple && Array.isArray(value) && value.length > 1 ? `${value.length}\uAC1C \uC120\uD0DD\uB428` : selectedOption !== void 0 ? optionLabel(selectedOption, labelKey) : "";
|
|
@@ -5001,7 +5031,9 @@ function KjunSelect({
|
|
|
5001
5031
|
onChange,
|
|
5002
5032
|
onOpenChange,
|
|
5003
5033
|
onSearch,
|
|
5004
|
-
onClear
|
|
5034
|
+
onClear,
|
|
5035
|
+
filterFn,
|
|
5036
|
+
searchKeys
|
|
5005
5037
|
}) {
|
|
5006
5038
|
const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
|
|
5007
5039
|
const { colors } = useKjunStyles(), field = useKjunField(), ref = (0, import_react44.useRef)(null), spec = import_tokens30.tokens.input[size];
|
|
@@ -5026,7 +5058,9 @@ function KjunSelect({
|
|
|
5026
5058
|
pageSize: optionPageSize,
|
|
5027
5059
|
limit,
|
|
5028
5060
|
loading,
|
|
5029
|
-
multiple
|
|
5061
|
+
multiple,
|
|
5062
|
+
filterFn,
|
|
5063
|
+
searchKeys
|
|
5030
5064
|
});
|
|
5031
5065
|
const firstSelected = visible.findIndex(({ option }) => selected(option));
|
|
5032
5066
|
if (firstSelected < 0) selectedRow.current = null;
|
|
@@ -5988,7 +6022,7 @@ function KjunRefreshButton({
|
|
|
5988
6022
|
...props
|
|
5989
6023
|
}) {
|
|
5990
6024
|
const reduced = useReducedMotion();
|
|
5991
|
-
const label = ariaLabel || [targetName, "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6025
|
+
const label = ariaLabel || [targetName, mode === "text" ? text : "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
5992
6026
|
const hint = tooltip != null ? tooltip : mode === "icon" ? label : "";
|
|
5993
6027
|
const button = /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(KjunTooltip, { content: props.disabled || props.loading ? "" : hint, placement: tooltipPlacement, delay: tooltipDelay, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
5994
6028
|
KjunButton,
|
|
@@ -7152,9 +7186,18 @@ function tablePresentation(props, mobile) {
|
|
|
7152
7186
|
}
|
|
7153
7187
|
};
|
|
7154
7188
|
}
|
|
7189
|
+
var warnedFormats = /* @__PURE__ */ new Set();
|
|
7190
|
+
function columnFormat(column) {
|
|
7191
|
+
if (typeof column.format === "function") return column.format;
|
|
7192
|
+
if (column.format != null && !warnedFormats.has(column.key)) {
|
|
7193
|
+
warnedFormats.add(column.key);
|
|
7194
|
+
console.warn(`KJUN Table: ${column.key} \uC5F4\uC758 format\uC740 \uD568\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.`);
|
|
7195
|
+
}
|
|
7196
|
+
return void 0;
|
|
7197
|
+
}
|
|
7155
7198
|
function tableCellValue(props, column, row, index) {
|
|
7156
7199
|
const value = getValue(row, column.key);
|
|
7157
|
-
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : column
|
|
7200
|
+
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : columnFormat(column) ? columnFormat(column)(value, row) : props.formatValue ? props.formatValue(value, column, row) : value == null ? "-" : typeof value === "number" && column.type === "number" ? new Intl.NumberFormat().format(value) : String(value);
|
|
7158
7201
|
return { value, body };
|
|
7159
7202
|
}
|
|
7160
7203
|
|
package/dist/index.js
CHANGED
|
@@ -119,6 +119,10 @@ function installLayerKeyboard(document2, state, keyupFallback = false) {
|
|
|
119
119
|
import { createContext as createContext2, useContext as useContext2, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
120
120
|
|
|
121
121
|
// shared/package-runtime/layer-state.ts
|
|
122
|
+
function chooseReturnTarget(chosen, fallback2) {
|
|
123
|
+
if (chosen === false) return void 0;
|
|
124
|
+
return chosen && chosen.isConnected !== false ? chosen : fallback2;
|
|
125
|
+
}
|
|
122
126
|
function createLayerState() {
|
|
123
127
|
const entries = /* @__PURE__ */ new Map(), listeners = /* @__PURE__ */ new Set();
|
|
124
128
|
const restoredFocus = /* @__PURE__ */ new WeakSet();
|
|
@@ -139,6 +143,7 @@ function createLayerState() {
|
|
|
139
143
|
return !layer.blocked && (layer.kind === "window" ? ((_a = topWindow()) == null ? void 0 : _a.id) === layer.id : ((_b = topWindow()) == null ? void 0 : _b.id) === layer.owner);
|
|
140
144
|
};
|
|
141
145
|
const top = () => [...entries.values()].filter(active).sort((a, b) => a.order - b.order).at(-1);
|
|
146
|
+
const topPopup = () => [...entries.values()].filter((layer) => layer.kind !== "tooltip" && active(layer)).sort((a, b) => a.order - b.order).at(-1);
|
|
142
147
|
function dismiss(layer) {
|
|
143
148
|
if (layer.closeRequested) return;
|
|
144
149
|
layer.closeRequested = true;
|
|
@@ -158,6 +163,7 @@ function createLayerState() {
|
|
|
158
163
|
entries,
|
|
159
164
|
topWindow,
|
|
160
165
|
top,
|
|
166
|
+
topPopup,
|
|
161
167
|
windowOf,
|
|
162
168
|
isRestoredFocus(target) {
|
|
163
169
|
return !!target && restoredFocus.has(target);
|
|
@@ -306,21 +312,31 @@ function focusTrigger(target) {
|
|
|
306
312
|
}
|
|
307
313
|
return target;
|
|
308
314
|
}
|
|
309
|
-
function restoreFocus(target, state, id) {
|
|
315
|
+
function restoreFocus(target, state, id, fallback2) {
|
|
316
|
+
const usable = (item) => (item == null ? void 0 : item.isConnected) !== false && !(typeof HTMLElement !== "undefined" && item instanceof HTMLElement && item.closest("[inert]"));
|
|
310
317
|
const restore = () => {
|
|
311
|
-
var _a, _b, _c, _d;
|
|
318
|
+
var _a, _b, _c, _d, _e;
|
|
312
319
|
if (state.entries.has(id)) return;
|
|
313
|
-
if ((target
|
|
314
|
-
else (
|
|
320
|
+
if (usable(target)) (_a = target == null ? void 0 : target.focus) == null ? void 0 : _a.call(target, { preventScroll: true });
|
|
321
|
+
else if (fallback2 && fallback2 !== target && usable(fallback2)) (_b = fallback2.focus) == null ? void 0 : _b.call(fallback2, { preventScroll: true });
|
|
322
|
+
else (_e = (_d = (_c = state.topWindow()) == null ? void 0 : _c.root) == null ? void 0 : _d.focus) == null ? void 0 : _e.call(_d, { preventScroll: true });
|
|
315
323
|
};
|
|
316
324
|
if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(restore);
|
|
317
325
|
else queueMicrotask(restore);
|
|
318
326
|
}
|
|
319
|
-
function useLayer(open, present, kind, close, trigger) {
|
|
327
|
+
function useLayer(open, present, kind, close, trigger, returnFocus) {
|
|
320
328
|
var _a;
|
|
321
329
|
const state = useLayerState(), parent = useContext2(LayerScope), id = useId();
|
|
322
330
|
const callback = useRef(close);
|
|
323
331
|
callback.current = close;
|
|
332
|
+
const returnRef = useRef(returnFocus);
|
|
333
|
+
returnRef.current = returnFocus;
|
|
334
|
+
const fallbackFocus = useRef(null);
|
|
335
|
+
const removeLayer = () => {
|
|
336
|
+
const removed = state.remove(id, currentFocus());
|
|
337
|
+
if (removed) fallbackFocus.current = removed;
|
|
338
|
+
return removed && returnRef.current ? chooseReturnTarget(returnRef.current(), removed) : removed;
|
|
339
|
+
};
|
|
324
340
|
const openingFocus = useRef(null);
|
|
325
341
|
const wasOpen = useRef(false);
|
|
326
342
|
const pendingFocus = useRef(null);
|
|
@@ -332,17 +348,17 @@ function useLayer(open, present, kind, close, trigger) {
|
|
|
332
348
|
state.open(id, kind, parent, () => callback.current(), focusTrigger(trigger == null ? void 0 : trigger.current) || openingFocus.current);
|
|
333
349
|
} else if (kind === "window" && present) state.markClosing(id);
|
|
334
350
|
else if (kind !== "window" || !present) {
|
|
335
|
-
const target =
|
|
351
|
+
const target = removeLayer();
|
|
336
352
|
if (target) pendingFocus.current = target;
|
|
337
353
|
if (!present && pendingFocus.current) {
|
|
338
|
-
restoreFocus(pendingFocus.current, state, id);
|
|
354
|
+
restoreFocus(pendingFocus.current, state, id, fallbackFocus.current);
|
|
339
355
|
pendingFocus.current = null;
|
|
340
356
|
}
|
|
341
357
|
}
|
|
342
358
|
}, [open, present, state, id, kind, parent, trigger]);
|
|
343
359
|
useLayoutEffect(() => () => {
|
|
344
|
-
const target =
|
|
345
|
-
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id);
|
|
360
|
+
const target = removeLayer();
|
|
361
|
+
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id, fallbackFocus.current);
|
|
346
362
|
}, [state, id]);
|
|
347
363
|
const entry = state.entries.get(id);
|
|
348
364
|
return {
|
|
@@ -3031,7 +3047,7 @@ function KjunRadioGroup({
|
|
|
3031
3047
|
accessibilityLabel: ariaLabel,
|
|
3032
3048
|
style: {
|
|
3033
3049
|
flexDirection: direction === "vertical" ? "column" : "row",
|
|
3034
|
-
flexWrap: "wrap",
|
|
3050
|
+
flexWrap: direction === "vertical" ? "nowrap" : "wrap",
|
|
3035
3051
|
gap: direction === "vertical" ? tokens16.dimension.value8 : tokens16.dimension.value16
|
|
3036
3052
|
},
|
|
3037
3053
|
children: children || options.map((option) => /* @__PURE__ */ jsx19(
|
|
@@ -4269,6 +4285,17 @@ function nextOptionValue(value, option, key, multiple) {
|
|
|
4269
4285
|
if (!multiple) return id;
|
|
4270
4286
|
return Array.isArray(value) && value.includes(id) ? value.filter((item) => item !== id) : [...Array.isArray(value) ? value : [], id];
|
|
4271
4287
|
}
|
|
4288
|
+
function optionMatchRank(option, query, labelKey, searchKeys = []) {
|
|
4289
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
4290
|
+
if (!needle) return 0;
|
|
4291
|
+
const label = optionLabel(option, labelKey).toLocaleLowerCase();
|
|
4292
|
+
if (label.startsWith(needle)) return 0;
|
|
4293
|
+
if (label.includes(needle)) return 1;
|
|
4294
|
+
return typeof option === "object" && searchKeys.some((key) => {
|
|
4295
|
+
var _a;
|
|
4296
|
+
return String((_a = option[key]) != null ? _a : "").toLocaleLowerCase().includes(needle);
|
|
4297
|
+
}) ? 2 : -1;
|
|
4298
|
+
}
|
|
4272
4299
|
function selectOptions({
|
|
4273
4300
|
options,
|
|
4274
4301
|
value,
|
|
@@ -4278,10 +4305,13 @@ function selectOptions({
|
|
|
4278
4305
|
pageSize,
|
|
4279
4306
|
limit,
|
|
4280
4307
|
loading,
|
|
4281
|
-
multiple
|
|
4308
|
+
multiple,
|
|
4309
|
+
filterFn,
|
|
4310
|
+
searchKeys = []
|
|
4282
4311
|
}) {
|
|
4283
4312
|
const selected = (option) => optionSelected(value, option, valueKey);
|
|
4284
|
-
const
|
|
4313
|
+
const indexed = options.map((option, index) => ({ option, key: optionKey(option, valueKey, index) }));
|
|
4314
|
+
const matching = filterFn ? indexed.filter(({ option }) => filterFn(option, query)) : indexed.map((item, index) => ({ item, index, rank: optionMatchRank(item.option, query, labelKey, searchKeys) })).filter(({ rank }) => rank >= 0).sort((a, b) => a.rank - b.rank || a.index - b.index).map(({ item }) => item);
|
|
4285
4315
|
const visible = loading ? [] : pageSize > 0 ? matching.slice(0, limit) : matching;
|
|
4286
4316
|
const selectedOption = options.find(selected);
|
|
4287
4317
|
const label = multiple && Array.isArray(value) && value.length > 1 ? `${value.length}\uAC1C \uC120\uD0DD\uB428` : selectedOption !== void 0 ? optionLabel(selectedOption, labelKey) : "";
|
|
@@ -5016,7 +5046,9 @@ function KjunSelect({
|
|
|
5016
5046
|
onChange,
|
|
5017
5047
|
onOpenChange,
|
|
5018
5048
|
onSearch,
|
|
5019
|
-
onClear
|
|
5049
|
+
onClear,
|
|
5050
|
+
filterFn,
|
|
5051
|
+
searchKeys
|
|
5020
5052
|
}) {
|
|
5021
5053
|
const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
|
|
5022
5054
|
const { colors } = useKjunStyles(), field = useKjunField(), ref = useRef23(null), spec = tokens28.input[size];
|
|
@@ -5041,7 +5073,9 @@ function KjunSelect({
|
|
|
5041
5073
|
pageSize: optionPageSize,
|
|
5042
5074
|
limit,
|
|
5043
5075
|
loading,
|
|
5044
|
-
multiple
|
|
5076
|
+
multiple,
|
|
5077
|
+
filterFn,
|
|
5078
|
+
searchKeys
|
|
5045
5079
|
});
|
|
5046
5080
|
const firstSelected = visible.findIndex(({ option }) => selected(option));
|
|
5047
5081
|
if (firstSelected < 0) selectedRow.current = null;
|
|
@@ -6010,7 +6044,7 @@ function KjunRefreshButton({
|
|
|
6010
6044
|
...props
|
|
6011
6045
|
}) {
|
|
6012
6046
|
const reduced = useReducedMotion();
|
|
6013
|
-
const label = ariaLabel || [targetName, "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6047
|
+
const label = ariaLabel || [targetName, mode === "text" ? text : "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6014
6048
|
const hint = tooltip != null ? tooltip : mode === "icon" ? label : "";
|
|
6015
6049
|
const button = /* @__PURE__ */ jsx36(KjunTooltip, { content: props.disabled || props.loading ? "" : hint, placement: tooltipPlacement, delay: tooltipDelay, children: /* @__PURE__ */ jsx36(
|
|
6016
6050
|
KjunButton,
|
|
@@ -7191,9 +7225,18 @@ function tablePresentation(props, mobile) {
|
|
|
7191
7225
|
}
|
|
7192
7226
|
};
|
|
7193
7227
|
}
|
|
7228
|
+
var warnedFormats = /* @__PURE__ */ new Set();
|
|
7229
|
+
function columnFormat(column) {
|
|
7230
|
+
if (typeof column.format === "function") return column.format;
|
|
7231
|
+
if (column.format != null && !warnedFormats.has(column.key)) {
|
|
7232
|
+
warnedFormats.add(column.key);
|
|
7233
|
+
console.warn(`KJUN Table: ${column.key} \uC5F4\uC758 format\uC740 \uD568\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.`);
|
|
7234
|
+
}
|
|
7235
|
+
return void 0;
|
|
7236
|
+
}
|
|
7194
7237
|
function tableCellValue(props, column, row, index) {
|
|
7195
7238
|
const value = getValue(row, column.key);
|
|
7196
|
-
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : column
|
|
7239
|
+
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : columnFormat(column) ? columnFormat(column)(value, row) : props.formatValue ? props.formatValue(value, column, row) : value == null ? "-" : typeof value === "number" && column.type === "number" ? new Intl.NumberFormat().format(value) : String(value);
|
|
7197
7240
|
return { value, body };
|
|
7198
7241
|
}
|
|
7199
7242
|
|
package/dist/index.web.cjs
CHANGED
|
@@ -234,6 +234,10 @@ function installLayerKeyboard(document2, state, keyupFallback = false) {
|
|
|
234
234
|
var import_react2 = require("react");
|
|
235
235
|
|
|
236
236
|
// shared/package-runtime/layer-state.ts
|
|
237
|
+
function chooseReturnTarget(chosen, fallback2) {
|
|
238
|
+
if (chosen === false) return void 0;
|
|
239
|
+
return chosen && chosen.isConnected !== false ? chosen : fallback2;
|
|
240
|
+
}
|
|
237
241
|
function createLayerState() {
|
|
238
242
|
const entries = /* @__PURE__ */ new Map(), listeners = /* @__PURE__ */ new Set();
|
|
239
243
|
const restoredFocus = /* @__PURE__ */ new WeakSet();
|
|
@@ -254,6 +258,7 @@ function createLayerState() {
|
|
|
254
258
|
return !layer.blocked && (layer.kind === "window" ? ((_a = topWindow()) == null ? void 0 : _a.id) === layer.id : ((_b = topWindow()) == null ? void 0 : _b.id) === layer.owner);
|
|
255
259
|
};
|
|
256
260
|
const top = () => [...entries.values()].filter(active).sort((a, b) => a.order - b.order).at(-1);
|
|
261
|
+
const topPopup = () => [...entries.values()].filter((layer) => layer.kind !== "tooltip" && active(layer)).sort((a, b) => a.order - b.order).at(-1);
|
|
257
262
|
function dismiss(layer) {
|
|
258
263
|
if (layer.closeRequested) return;
|
|
259
264
|
layer.closeRequested = true;
|
|
@@ -273,6 +278,7 @@ function createLayerState() {
|
|
|
273
278
|
entries,
|
|
274
279
|
topWindow,
|
|
275
280
|
top,
|
|
281
|
+
topPopup,
|
|
276
282
|
windowOf,
|
|
277
283
|
isRestoredFocus(target) {
|
|
278
284
|
return !!target && restoredFocus.has(target);
|
|
@@ -421,21 +427,31 @@ function focusTrigger(target) {
|
|
|
421
427
|
}
|
|
422
428
|
return target;
|
|
423
429
|
}
|
|
424
|
-
function restoreFocus(target, state, id) {
|
|
430
|
+
function restoreFocus(target, state, id, fallback2) {
|
|
431
|
+
const usable = (item) => (item == null ? void 0 : item.isConnected) !== false && !(typeof HTMLElement !== "undefined" && item instanceof HTMLElement && item.closest("[inert]"));
|
|
425
432
|
const restore = () => {
|
|
426
|
-
var _a, _b, _c, _d;
|
|
433
|
+
var _a, _b, _c, _d, _e;
|
|
427
434
|
if (state.entries.has(id)) return;
|
|
428
|
-
if ((target
|
|
429
|
-
else (
|
|
435
|
+
if (usable(target)) (_a = target == null ? void 0 : target.focus) == null ? void 0 : _a.call(target, { preventScroll: true });
|
|
436
|
+
else if (fallback2 && fallback2 !== target && usable(fallback2)) (_b = fallback2.focus) == null ? void 0 : _b.call(fallback2, { preventScroll: true });
|
|
437
|
+
else (_e = (_d = (_c = state.topWindow()) == null ? void 0 : _c.root) == null ? void 0 : _d.focus) == null ? void 0 : _e.call(_d, { preventScroll: true });
|
|
430
438
|
};
|
|
431
439
|
if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(restore);
|
|
432
440
|
else queueMicrotask(restore);
|
|
433
441
|
}
|
|
434
|
-
function useLayer(open, present, kind, close, trigger) {
|
|
442
|
+
function useLayer(open, present, kind, close, trigger, returnFocus) {
|
|
435
443
|
var _a;
|
|
436
444
|
const state = useLayerState(), parent = (0, import_react2.useContext)(LayerScope), id = (0, import_react2.useId)();
|
|
437
445
|
const callback = (0, import_react2.useRef)(close);
|
|
438
446
|
callback.current = close;
|
|
447
|
+
const returnRef = (0, import_react2.useRef)(returnFocus);
|
|
448
|
+
returnRef.current = returnFocus;
|
|
449
|
+
const fallbackFocus = (0, import_react2.useRef)(null);
|
|
450
|
+
const removeLayer = () => {
|
|
451
|
+
const removed = state.remove(id, currentFocus());
|
|
452
|
+
if (removed) fallbackFocus.current = removed;
|
|
453
|
+
return removed && returnRef.current ? chooseReturnTarget(returnRef.current(), removed) : removed;
|
|
454
|
+
};
|
|
439
455
|
const openingFocus = (0, import_react2.useRef)(null);
|
|
440
456
|
const wasOpen = (0, import_react2.useRef)(false);
|
|
441
457
|
const pendingFocus = (0, import_react2.useRef)(null);
|
|
@@ -447,17 +463,17 @@ function useLayer(open, present, kind, close, trigger) {
|
|
|
447
463
|
state.open(id, kind, parent, () => callback.current(), focusTrigger(trigger == null ? void 0 : trigger.current) || openingFocus.current);
|
|
448
464
|
} else if (kind === "window" && present) state.markClosing(id);
|
|
449
465
|
else if (kind !== "window" || !present) {
|
|
450
|
-
const target =
|
|
466
|
+
const target = removeLayer();
|
|
451
467
|
if (target) pendingFocus.current = target;
|
|
452
468
|
if (!present && pendingFocus.current) {
|
|
453
|
-
restoreFocus(pendingFocus.current, state, id);
|
|
469
|
+
restoreFocus(pendingFocus.current, state, id, fallbackFocus.current);
|
|
454
470
|
pendingFocus.current = null;
|
|
455
471
|
}
|
|
456
472
|
}
|
|
457
473
|
}, [open, present, state, id, kind, parent, trigger]);
|
|
458
474
|
(0, import_react2.useLayoutEffect)(() => () => {
|
|
459
|
-
const target =
|
|
460
|
-
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id);
|
|
475
|
+
const target = removeLayer();
|
|
476
|
+
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id, fallbackFocus.current);
|
|
461
477
|
}, [state, id]);
|
|
462
478
|
const entry = state.entries.get(id);
|
|
463
479
|
return {
|
|
@@ -3227,7 +3243,7 @@ function KjunRadioGroup({
|
|
|
3227
3243
|
accessibilityLabel: ariaLabel,
|
|
3228
3244
|
style: {
|
|
3229
3245
|
flexDirection: direction === "vertical" ? "column" : "row",
|
|
3230
|
-
flexWrap: "wrap",
|
|
3246
|
+
flexWrap: direction === "vertical" ? "nowrap" : "wrap",
|
|
3231
3247
|
gap: direction === "vertical" ? import_tokens19.tokens.dimension.value8 : import_tokens19.tokens.dimension.value16
|
|
3232
3248
|
},
|
|
3233
3249
|
children: children || options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
@@ -4416,6 +4432,17 @@ function nextOptionValue(value, option, key, multiple) {
|
|
|
4416
4432
|
if (!multiple) return id;
|
|
4417
4433
|
return Array.isArray(value) && value.includes(id) ? value.filter((item) => item !== id) : [...Array.isArray(value) ? value : [], id];
|
|
4418
4434
|
}
|
|
4435
|
+
function optionMatchRank(option, query, labelKey, searchKeys = []) {
|
|
4436
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
4437
|
+
if (!needle) return 0;
|
|
4438
|
+
const label = optionLabel(option, labelKey).toLocaleLowerCase();
|
|
4439
|
+
if (label.startsWith(needle)) return 0;
|
|
4440
|
+
if (label.includes(needle)) return 1;
|
|
4441
|
+
return typeof option === "object" && searchKeys.some((key) => {
|
|
4442
|
+
var _a;
|
|
4443
|
+
return String((_a = option[key]) != null ? _a : "").toLocaleLowerCase().includes(needle);
|
|
4444
|
+
}) ? 2 : -1;
|
|
4445
|
+
}
|
|
4419
4446
|
function selectOptions({
|
|
4420
4447
|
options,
|
|
4421
4448
|
value,
|
|
@@ -4425,10 +4452,13 @@ function selectOptions({
|
|
|
4425
4452
|
pageSize,
|
|
4426
4453
|
limit,
|
|
4427
4454
|
loading,
|
|
4428
|
-
multiple
|
|
4455
|
+
multiple,
|
|
4456
|
+
filterFn,
|
|
4457
|
+
searchKeys = []
|
|
4429
4458
|
}) {
|
|
4430
4459
|
const selected = (option) => optionSelected(value, option, valueKey);
|
|
4431
|
-
const
|
|
4460
|
+
const indexed = options.map((option, index) => ({ option, key: optionKey(option, valueKey, index) }));
|
|
4461
|
+
const matching = filterFn ? indexed.filter(({ option }) => filterFn(option, query)) : indexed.map((item, index) => ({ item, index, rank: optionMatchRank(item.option, query, labelKey, searchKeys) })).filter(({ rank }) => rank >= 0).sort((a, b) => a.rank - b.rank || a.index - b.index).map(({ item }) => item);
|
|
4432
4462
|
const visible = loading ? [] : pageSize > 0 ? matching.slice(0, limit) : matching;
|
|
4433
4463
|
const selectedOption = options.find(selected);
|
|
4434
4464
|
const label = multiple && Array.isArray(value) && value.length > 1 ? `${value.length}\uAC1C \uC120\uD0DD\uB428` : selectedOption !== void 0 ? optionLabel(selectedOption, labelKey) : "";
|
|
@@ -5163,7 +5193,9 @@ function KjunSelect({
|
|
|
5163
5193
|
onChange,
|
|
5164
5194
|
onOpenChange,
|
|
5165
5195
|
onSearch,
|
|
5166
|
-
onClear
|
|
5196
|
+
onClear,
|
|
5197
|
+
filterFn,
|
|
5198
|
+
searchKeys
|
|
5167
5199
|
}) {
|
|
5168
5200
|
const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
|
|
5169
5201
|
const { colors } = useKjunStyles(), field = useKjunField(), ref = (0, import_react47.useRef)(null), spec = import_tokens31.tokens.input[size];
|
|
@@ -5188,7 +5220,9 @@ function KjunSelect({
|
|
|
5188
5220
|
pageSize: optionPageSize,
|
|
5189
5221
|
limit,
|
|
5190
5222
|
loading,
|
|
5191
|
-
multiple
|
|
5223
|
+
multiple,
|
|
5224
|
+
filterFn,
|
|
5225
|
+
searchKeys
|
|
5192
5226
|
});
|
|
5193
5227
|
const firstSelected = visible.findIndex(({ option }) => selected(option));
|
|
5194
5228
|
if (firstSelected < 0) selectedRow.current = null;
|
|
@@ -6243,7 +6277,7 @@ function KjunRefreshButton({
|
|
|
6243
6277
|
...props
|
|
6244
6278
|
}) {
|
|
6245
6279
|
const reduced = useReducedMotion();
|
|
6246
|
-
const label = ariaLabel || [targetName, "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6280
|
+
const label = ariaLabel || [targetName, mode === "text" ? text : "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6247
6281
|
const hint = tooltip != null ? tooltip : mode === "icon" ? label : "";
|
|
6248
6282
|
const button = /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(KjunTooltip, { content: props.disabled || props.loading ? "" : hint, placement: tooltipPlacement, delay: tooltipDelay, children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
6249
6283
|
KjunButton,
|
|
@@ -7407,9 +7441,18 @@ function tablePresentation(props, mobile) {
|
|
|
7407
7441
|
}
|
|
7408
7442
|
};
|
|
7409
7443
|
}
|
|
7444
|
+
var warnedFormats = /* @__PURE__ */ new Set();
|
|
7445
|
+
function columnFormat(column) {
|
|
7446
|
+
if (typeof column.format === "function") return column.format;
|
|
7447
|
+
if (column.format != null && !warnedFormats.has(column.key)) {
|
|
7448
|
+
warnedFormats.add(column.key);
|
|
7449
|
+
console.warn(`KJUN Table: ${column.key} \uC5F4\uC758 format\uC740 \uD568\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.`);
|
|
7450
|
+
}
|
|
7451
|
+
return void 0;
|
|
7452
|
+
}
|
|
7410
7453
|
function tableCellValue(props, column, row, index) {
|
|
7411
7454
|
const value = getValue(row, column.key);
|
|
7412
|
-
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : column
|
|
7455
|
+
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : columnFormat(column) ? columnFormat(column)(value, row) : props.formatValue ? props.formatValue(value, column, row) : value == null ? "-" : typeof value === "number" && column.type === "number" ? new Intl.NumberFormat().format(value) : String(value);
|
|
7413
7456
|
return { value, body };
|
|
7414
7457
|
}
|
|
7415
7458
|
|
package/dist/index.web.js
CHANGED
|
@@ -119,6 +119,10 @@ function installLayerKeyboard(document2, state, keyupFallback = false) {
|
|
|
119
119
|
import { createContext as createContext2, useContext as useContext2, useId, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
120
120
|
|
|
121
121
|
// shared/package-runtime/layer-state.ts
|
|
122
|
+
function chooseReturnTarget(chosen, fallback2) {
|
|
123
|
+
if (chosen === false) return void 0;
|
|
124
|
+
return chosen && chosen.isConnected !== false ? chosen : fallback2;
|
|
125
|
+
}
|
|
122
126
|
function createLayerState() {
|
|
123
127
|
const entries = /* @__PURE__ */ new Map(), listeners = /* @__PURE__ */ new Set();
|
|
124
128
|
const restoredFocus = /* @__PURE__ */ new WeakSet();
|
|
@@ -139,6 +143,7 @@ function createLayerState() {
|
|
|
139
143
|
return !layer.blocked && (layer.kind === "window" ? ((_a = topWindow()) == null ? void 0 : _a.id) === layer.id : ((_b = topWindow()) == null ? void 0 : _b.id) === layer.owner);
|
|
140
144
|
};
|
|
141
145
|
const top = () => [...entries.values()].filter(active).sort((a, b) => a.order - b.order).at(-1);
|
|
146
|
+
const topPopup = () => [...entries.values()].filter((layer) => layer.kind !== "tooltip" && active(layer)).sort((a, b) => a.order - b.order).at(-1);
|
|
142
147
|
function dismiss(layer) {
|
|
143
148
|
if (layer.closeRequested) return;
|
|
144
149
|
layer.closeRequested = true;
|
|
@@ -158,6 +163,7 @@ function createLayerState() {
|
|
|
158
163
|
entries,
|
|
159
164
|
topWindow,
|
|
160
165
|
top,
|
|
166
|
+
topPopup,
|
|
161
167
|
windowOf,
|
|
162
168
|
isRestoredFocus(target) {
|
|
163
169
|
return !!target && restoredFocus.has(target);
|
|
@@ -306,21 +312,31 @@ function focusTrigger(target) {
|
|
|
306
312
|
}
|
|
307
313
|
return target;
|
|
308
314
|
}
|
|
309
|
-
function restoreFocus(target, state, id) {
|
|
315
|
+
function restoreFocus(target, state, id, fallback2) {
|
|
316
|
+
const usable = (item) => (item == null ? void 0 : item.isConnected) !== false && !(typeof HTMLElement !== "undefined" && item instanceof HTMLElement && item.closest("[inert]"));
|
|
310
317
|
const restore = () => {
|
|
311
|
-
var _a, _b, _c, _d;
|
|
318
|
+
var _a, _b, _c, _d, _e;
|
|
312
319
|
if (state.entries.has(id)) return;
|
|
313
|
-
if ((target
|
|
314
|
-
else (
|
|
320
|
+
if (usable(target)) (_a = target == null ? void 0 : target.focus) == null ? void 0 : _a.call(target, { preventScroll: true });
|
|
321
|
+
else if (fallback2 && fallback2 !== target && usable(fallback2)) (_b = fallback2.focus) == null ? void 0 : _b.call(fallback2, { preventScroll: true });
|
|
322
|
+
else (_e = (_d = (_c = state.topWindow()) == null ? void 0 : _c.root) == null ? void 0 : _d.focus) == null ? void 0 : _e.call(_d, { preventScroll: true });
|
|
315
323
|
};
|
|
316
324
|
if (typeof requestAnimationFrame !== "undefined") requestAnimationFrame(restore);
|
|
317
325
|
else queueMicrotask(restore);
|
|
318
326
|
}
|
|
319
|
-
function useLayer(open, present, kind, close, trigger) {
|
|
327
|
+
function useLayer(open, present, kind, close, trigger, returnFocus) {
|
|
320
328
|
var _a;
|
|
321
329
|
const state = useLayerState(), parent = useContext2(LayerScope), id = useId();
|
|
322
330
|
const callback = useRef(close);
|
|
323
331
|
callback.current = close;
|
|
332
|
+
const returnRef = useRef(returnFocus);
|
|
333
|
+
returnRef.current = returnFocus;
|
|
334
|
+
const fallbackFocus = useRef(null);
|
|
335
|
+
const removeLayer = () => {
|
|
336
|
+
const removed = state.remove(id, currentFocus());
|
|
337
|
+
if (removed) fallbackFocus.current = removed;
|
|
338
|
+
return removed && returnRef.current ? chooseReturnTarget(returnRef.current(), removed) : removed;
|
|
339
|
+
};
|
|
324
340
|
const openingFocus = useRef(null);
|
|
325
341
|
const wasOpen = useRef(false);
|
|
326
342
|
const pendingFocus = useRef(null);
|
|
@@ -332,17 +348,17 @@ function useLayer(open, present, kind, close, trigger) {
|
|
|
332
348
|
state.open(id, kind, parent, () => callback.current(), focusTrigger(trigger == null ? void 0 : trigger.current) || openingFocus.current);
|
|
333
349
|
} else if (kind === "window" && present) state.markClosing(id);
|
|
334
350
|
else if (kind !== "window" || !present) {
|
|
335
|
-
const target =
|
|
351
|
+
const target = removeLayer();
|
|
336
352
|
if (target) pendingFocus.current = target;
|
|
337
353
|
if (!present && pendingFocus.current) {
|
|
338
|
-
restoreFocus(pendingFocus.current, state, id);
|
|
354
|
+
restoreFocus(pendingFocus.current, state, id, fallbackFocus.current);
|
|
339
355
|
pendingFocus.current = null;
|
|
340
356
|
}
|
|
341
357
|
}
|
|
342
358
|
}, [open, present, state, id, kind, parent, trigger]);
|
|
343
359
|
useLayoutEffect(() => () => {
|
|
344
|
-
const target =
|
|
345
|
-
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id);
|
|
360
|
+
const target = removeLayer();
|
|
361
|
+
if (target || pendingFocus.current) restoreFocus(target || pendingFocus.current, state, id, fallbackFocus.current);
|
|
346
362
|
}, [state, id]);
|
|
347
363
|
const entry = state.entries.get(id);
|
|
348
364
|
return {
|
|
@@ -3193,7 +3209,7 @@ function KjunRadioGroup({
|
|
|
3193
3209
|
accessibilityLabel: ariaLabel,
|
|
3194
3210
|
style: {
|
|
3195
3211
|
flexDirection: direction === "vertical" ? "column" : "row",
|
|
3196
|
-
flexWrap: "wrap",
|
|
3212
|
+
flexWrap: direction === "vertical" ? "nowrap" : "wrap",
|
|
3197
3213
|
gap: direction === "vertical" ? tokens17.dimension.value8 : tokens17.dimension.value16
|
|
3198
3214
|
},
|
|
3199
3215
|
children: children || options.map((option) => /* @__PURE__ */ jsx19(
|
|
@@ -4431,6 +4447,17 @@ function nextOptionValue(value, option, key, multiple) {
|
|
|
4431
4447
|
if (!multiple) return id;
|
|
4432
4448
|
return Array.isArray(value) && value.includes(id) ? value.filter((item) => item !== id) : [...Array.isArray(value) ? value : [], id];
|
|
4433
4449
|
}
|
|
4450
|
+
function optionMatchRank(option, query, labelKey, searchKeys = []) {
|
|
4451
|
+
const needle = query.trim().toLocaleLowerCase();
|
|
4452
|
+
if (!needle) return 0;
|
|
4453
|
+
const label = optionLabel(option, labelKey).toLocaleLowerCase();
|
|
4454
|
+
if (label.startsWith(needle)) return 0;
|
|
4455
|
+
if (label.includes(needle)) return 1;
|
|
4456
|
+
return typeof option === "object" && searchKeys.some((key) => {
|
|
4457
|
+
var _a;
|
|
4458
|
+
return String((_a = option[key]) != null ? _a : "").toLocaleLowerCase().includes(needle);
|
|
4459
|
+
}) ? 2 : -1;
|
|
4460
|
+
}
|
|
4434
4461
|
function selectOptions({
|
|
4435
4462
|
options,
|
|
4436
4463
|
value,
|
|
@@ -4440,10 +4467,13 @@ function selectOptions({
|
|
|
4440
4467
|
pageSize,
|
|
4441
4468
|
limit,
|
|
4442
4469
|
loading,
|
|
4443
|
-
multiple
|
|
4470
|
+
multiple,
|
|
4471
|
+
filterFn,
|
|
4472
|
+
searchKeys = []
|
|
4444
4473
|
}) {
|
|
4445
4474
|
const selected = (option) => optionSelected(value, option, valueKey);
|
|
4446
|
-
const
|
|
4475
|
+
const indexed = options.map((option, index) => ({ option, key: optionKey(option, valueKey, index) }));
|
|
4476
|
+
const matching = filterFn ? indexed.filter(({ option }) => filterFn(option, query)) : indexed.map((item, index) => ({ item, index, rank: optionMatchRank(item.option, query, labelKey, searchKeys) })).filter(({ rank }) => rank >= 0).sort((a, b) => a.rank - b.rank || a.index - b.index).map(({ item }) => item);
|
|
4447
4477
|
const visible = loading ? [] : pageSize > 0 ? matching.slice(0, limit) : matching;
|
|
4448
4478
|
const selectedOption = options.find(selected);
|
|
4449
4479
|
const label = multiple && Array.isArray(value) && value.length > 1 ? `${value.length}\uAC1C \uC120\uD0DD\uB428` : selectedOption !== void 0 ? optionLabel(selectedOption, labelKey) : "";
|
|
@@ -5178,7 +5208,9 @@ function KjunSelect({
|
|
|
5178
5208
|
onChange,
|
|
5179
5209
|
onOpenChange,
|
|
5180
5210
|
onSearch,
|
|
5181
|
-
onClear
|
|
5211
|
+
onClear,
|
|
5212
|
+
filterFn,
|
|
5213
|
+
searchKeys
|
|
5182
5214
|
}) {
|
|
5183
5215
|
const { open, query, limit, changeOpen, search, showMore } = useSelectState(controlled, disabled, optionPageSize, onOpenChange);
|
|
5184
5216
|
const { colors } = useKjunStyles(), field = useKjunField(), ref = useRef24(null), spec = tokens29.input[size];
|
|
@@ -5203,7 +5235,9 @@ function KjunSelect({
|
|
|
5203
5235
|
pageSize: optionPageSize,
|
|
5204
5236
|
limit,
|
|
5205
5237
|
loading,
|
|
5206
|
-
multiple
|
|
5238
|
+
multiple,
|
|
5239
|
+
filterFn,
|
|
5240
|
+
searchKeys
|
|
5207
5241
|
});
|
|
5208
5242
|
const firstSelected = visible.findIndex(({ option }) => selected(option));
|
|
5209
5243
|
if (firstSelected < 0) selectedRow.current = null;
|
|
@@ -6265,7 +6299,7 @@ function KjunRefreshButton({
|
|
|
6265
6299
|
...props
|
|
6266
6300
|
}) {
|
|
6267
6301
|
const reduced = useReducedMotion();
|
|
6268
|
-
const label = ariaLabel || [targetName, "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6302
|
+
const label = ariaLabel || [targetName, mode === "text" ? text : "\uC0C8\uB85C\uACE0\uCE68"].filter(Boolean).join(" ");
|
|
6269
6303
|
const hint = tooltip != null ? tooltip : mode === "icon" ? label : "";
|
|
6270
6304
|
const button = /* @__PURE__ */ jsx36(KjunTooltip, { content: props.disabled || props.loading ? "" : hint, placement: tooltipPlacement, delay: tooltipDelay, children: /* @__PURE__ */ jsx36(
|
|
6271
6305
|
KjunButton,
|
|
@@ -7446,9 +7480,18 @@ function tablePresentation(props, mobile) {
|
|
|
7446
7480
|
}
|
|
7447
7481
|
};
|
|
7448
7482
|
}
|
|
7483
|
+
var warnedFormats = /* @__PURE__ */ new Set();
|
|
7484
|
+
function columnFormat(column) {
|
|
7485
|
+
if (typeof column.format === "function") return column.format;
|
|
7486
|
+
if (column.format != null && !warnedFormats.has(column.key)) {
|
|
7487
|
+
warnedFormats.add(column.key);
|
|
7488
|
+
console.warn(`KJUN Table: ${column.key} \uC5F4\uC758 format\uC740 \uD568\uC218\uC5EC\uC57C \uD569\uB2C8\uB2E4.`);
|
|
7489
|
+
}
|
|
7490
|
+
return void 0;
|
|
7491
|
+
}
|
|
7449
7492
|
function tableCellValue(props, column, row, index) {
|
|
7450
7493
|
const value = getValue(row, column.key);
|
|
7451
|
-
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : column
|
|
7494
|
+
const body = props.renderCell ? props.renderCell(value, column, row, index) : column.render ? column.render(value, row, index) : columnFormat(column) ? columnFormat(column)(value, row) : props.formatValue ? props.formatValue(value, column, row) : value == null ? "-" : typeof value === "number" && column.type === "number" ? new Intl.NumberFormat().format(value) : String(value);
|
|
7452
7495
|
return { value, body };
|
|
7453
7496
|
}
|
|
7454
7497
|
|
|
@@ -25,6 +25,10 @@ export interface KjunSelectProps<T extends SelectOption = SelectOption> {
|
|
|
25
25
|
onChange?: (v: OptionValue | OptionValue[] | null) => void;
|
|
26
26
|
onOpenChange?: (v: boolean) => void;
|
|
27
27
|
onSearch?: (v: string) => void;
|
|
28
|
+
/** Replaces the default ranked label/searchKeys match; results keep the original order. */
|
|
29
|
+
filterFn?: (option: T, query: string) => boolean;
|
|
30
|
+
/** Extra option fields searched after the label. */
|
|
31
|
+
searchKeys?: string[];
|
|
28
32
|
onClear?: () => void;
|
|
29
33
|
}
|
|
30
|
-
export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, filterFn, searchKeys, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -25,6 +25,10 @@ export interface KjunSelectProps<T extends SelectOption = SelectOption> {
|
|
|
25
25
|
onChange?: (v: OptionValue | OptionValue[] | null) => void;
|
|
26
26
|
onOpenChange?: (v: boolean) => void;
|
|
27
27
|
onSearch?: (v: string) => void;
|
|
28
|
+
/** Replaces the default ranked label/searchKeys match; results keep the original order. */
|
|
29
|
+
filterFn?: (option: T, query: string) => boolean;
|
|
30
|
+
/** Extra option fields searched after the label. */
|
|
31
|
+
searchKeys?: string[];
|
|
28
32
|
onClear?: () => void;
|
|
29
33
|
}
|
|
30
|
-
export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
export declare function KjunSelect<T extends SelectOption = SelectOption>({ value, options, placeholder, ariaLabel, labelKey, valueKey, size, disabled, searchable, open: controlled, loading, searchPlaceholder, optionPageSize, clearable, multiple, error, menuHeader, renderOption, renderSelected, onValueChange, onChange, onOpenChange, onSearch, onClear, filterFn, searchKeys, }: KjunSelectProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -6,6 +6,8 @@ export interface FocusTarget {
|
|
|
6
6
|
}) => void;
|
|
7
7
|
isConnected?: boolean;
|
|
8
8
|
}
|
|
9
|
+
/** A caller-chosen return target wins while it is still in the document; false means the caller moves focus itself. */
|
|
10
|
+
export declare function chooseReturnTarget(chosen: FocusTarget | null | false | undefined, fallback: FocusTarget | null | undefined): FocusTarget | null | undefined;
|
|
9
11
|
export interface LayerEntry {
|
|
10
12
|
id: string;
|
|
11
13
|
kind: LayerKind;
|
|
@@ -24,6 +26,7 @@ export declare function createLayerState(): {
|
|
|
24
26
|
entries: Map<string, LayerEntry>;
|
|
25
27
|
topWindow: () => LayerEntry | undefined;
|
|
26
28
|
top: () => LayerEntry | undefined;
|
|
29
|
+
topPopup: () => LayerEntry | undefined;
|
|
27
30
|
windowOf: (id?: string) => string | undefined;
|
|
28
31
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
29
32
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
|
@@ -6,6 +6,8 @@ export interface FocusTarget {
|
|
|
6
6
|
}) => void;
|
|
7
7
|
isConnected?: boolean;
|
|
8
8
|
}
|
|
9
|
+
/** A caller-chosen return target wins while it is still in the document; false means the caller moves focus itself. */
|
|
10
|
+
export declare function chooseReturnTarget(chosen: FocusTarget | null | false | undefined, fallback: FocusTarget | null | undefined): FocusTarget | null | undefined;
|
|
9
11
|
export interface LayerEntry {
|
|
10
12
|
id: string;
|
|
11
13
|
kind: LayerKind;
|
|
@@ -24,6 +26,7 @@ export declare function createLayerState(): {
|
|
|
24
26
|
entries: Map<string, LayerEntry>;
|
|
25
27
|
topWindow: () => LayerEntry | undefined;
|
|
26
28
|
top: () => LayerEntry | undefined;
|
|
29
|
+
topPopup: () => LayerEntry | undefined;
|
|
27
30
|
windowOf: (id?: string) => string | undefined;
|
|
28
31
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
29
32
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
|
@@ -8,7 +8,9 @@ export declare const optionDisabled: (option: SelectOption) => boolean;
|
|
|
8
8
|
export declare function optionKey(option: SelectOption, key: string, index: number): string;
|
|
9
9
|
export declare function optionSelected(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string): boolean;
|
|
10
10
|
export declare function nextOptionValue(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string, multiple: boolean): OptionValue | OptionValue[];
|
|
11
|
-
|
|
11
|
+
/** 0 label starts with the query, 1 label contains it, 2 a searchKeys field contains it, -1 no match; an empty query matches as 0. */
|
|
12
|
+
export declare function optionMatchRank(option: SelectOption, query: string, labelKey: string, searchKeys?: readonly string[]): 0 | 1 | -1 | 2;
|
|
13
|
+
export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, filterFn, searchKeys, }: {
|
|
12
14
|
options: T[];
|
|
13
15
|
value: OptionValue | OptionValue[] | null;
|
|
14
16
|
labelKey: string;
|
|
@@ -18,6 +20,8 @@ export declare function selectOptions<T extends SelectOption>({ options, value,
|
|
|
18
20
|
limit: number;
|
|
19
21
|
loading: boolean;
|
|
20
22
|
multiple: boolean;
|
|
23
|
+
filterFn?: (option: T, query: string) => boolean;
|
|
24
|
+
searchKeys?: readonly string[];
|
|
21
25
|
}): {
|
|
22
26
|
selected: (option: T) => boolean;
|
|
23
27
|
matching: {
|
|
@@ -8,7 +8,9 @@ export declare const optionDisabled: (option: SelectOption) => boolean;
|
|
|
8
8
|
export declare function optionKey(option: SelectOption, key: string, index: number): string;
|
|
9
9
|
export declare function optionSelected(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string): boolean;
|
|
10
10
|
export declare function nextOptionValue(value: OptionValue | OptionValue[] | null, option: SelectOption, key: string, multiple: boolean): OptionValue | OptionValue[];
|
|
11
|
-
|
|
11
|
+
/** 0 label starts with the query, 1 label contains it, 2 a searchKeys field contains it, -1 no match; an empty query matches as 0. */
|
|
12
|
+
export declare function optionMatchRank(option: SelectOption, query: string, labelKey: string, searchKeys?: readonly string[]): 0 | 1 | -1 | 2;
|
|
13
|
+
export declare function selectOptions<T extends SelectOption>({ options, value, labelKey, valueKey, query, pageSize, limit, loading, multiple, filterFn, searchKeys, }: {
|
|
12
14
|
options: T[];
|
|
13
15
|
value: OptionValue | OptionValue[] | null;
|
|
14
16
|
labelKey: string;
|
|
@@ -18,6 +20,8 @@ export declare function selectOptions<T extends SelectOption>({ options, value,
|
|
|
18
20
|
limit: number;
|
|
19
21
|
loading: boolean;
|
|
20
22
|
multiple: boolean;
|
|
23
|
+
filterFn?: (option: T, query: string) => boolean;
|
|
24
|
+
searchKeys?: readonly string[];
|
|
21
25
|
}): {
|
|
22
26
|
selected: (option: T) => boolean;
|
|
23
27
|
matching: {
|
|
@@ -11,6 +11,10 @@ export declare function tablePresentation<Row extends object>(props: TableProps<
|
|
|
11
11
|
sections: TableCardSection[];
|
|
12
12
|
columnsForSection(row: Row, section: TableCardSection): TableColumn<Row>[];
|
|
13
13
|
};
|
|
14
|
+
export declare function columnFormat<Format>(column: {
|
|
15
|
+
key: string;
|
|
16
|
+
format?: Format;
|
|
17
|
+
}): Format | undefined;
|
|
14
18
|
export declare function tableCellValue<Row extends object>(props: TableProps<Row, unknown>, column: TableColumn<Row>, row: Row, index: number): {
|
|
15
19
|
value: unknown;
|
|
16
20
|
body: ReactNode;
|
|
@@ -11,6 +11,10 @@ export declare function tablePresentation<Row extends object>(props: TableProps<
|
|
|
11
11
|
sections: TableCardSection[];
|
|
12
12
|
columnsForSection(row: Row, section: TableCardSection): TableColumn<Row>[];
|
|
13
13
|
};
|
|
14
|
+
export declare function columnFormat<Format>(column: {
|
|
15
|
+
key: string;
|
|
16
|
+
format?: Format;
|
|
17
|
+
}): Format | undefined;
|
|
14
18
|
export declare function tableCellValue<Row extends object>(props: TableProps<Row, unknown>, column: TableColumn<Row>, row: Row, index: number): {
|
|
15
19
|
value: unknown;
|
|
16
20
|
body: ReactNode;
|
|
@@ -9,6 +9,7 @@ export declare function useLayerState(): {
|
|
|
9
9
|
entries: Map<string, import("./layer-state.cjs").LayerEntry>;
|
|
10
10
|
topWindow: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
11
11
|
top: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
12
|
+
topPopup: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
12
13
|
windowOf: (id?: string) => string | undefined;
|
|
13
14
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
14
15
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
|
@@ -36,12 +37,13 @@ export declare function useActiveLayerScope(): boolean;
|
|
|
36
37
|
export declare function focusTrigger(target: FocusTarget | null | undefined): FocusTarget | HTMLElement | null | undefined;
|
|
37
38
|
export declare function useLayer(open: boolean, present: boolean, kind: LayerKind, close: () => void, trigger?: {
|
|
38
39
|
current: FocusTarget | null;
|
|
39
|
-
}): {
|
|
40
|
+
}, returnFocus?: () => FocusTarget | null | false | undefined): {
|
|
40
41
|
id: string;
|
|
41
42
|
state: {
|
|
42
43
|
entries: Map<string, import("./layer-state.cjs").LayerEntry>;
|
|
43
44
|
topWindow: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
44
45
|
top: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
46
|
+
topPopup: () => import("./layer-state.cjs").LayerEntry | undefined;
|
|
45
47
|
windowOf: (id?: string) => string | undefined;
|
|
46
48
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
47
49
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
|
@@ -9,6 +9,7 @@ export declare function useLayerState(): {
|
|
|
9
9
|
entries: Map<string, import("./layer-state.js").LayerEntry>;
|
|
10
10
|
topWindow: () => import("./layer-state.js").LayerEntry | undefined;
|
|
11
11
|
top: () => import("./layer-state.js").LayerEntry | undefined;
|
|
12
|
+
topPopup: () => import("./layer-state.js").LayerEntry | undefined;
|
|
12
13
|
windowOf: (id?: string) => string | undefined;
|
|
13
14
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
14
15
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
|
@@ -36,12 +37,13 @@ export declare function useActiveLayerScope(): boolean;
|
|
|
36
37
|
export declare function focusTrigger(target: FocusTarget | null | undefined): FocusTarget | HTMLElement | null | undefined;
|
|
37
38
|
export declare function useLayer(open: boolean, present: boolean, kind: LayerKind, close: () => void, trigger?: {
|
|
38
39
|
current: FocusTarget | null;
|
|
39
|
-
}): {
|
|
40
|
+
}, returnFocus?: () => FocusTarget | null | false | undefined): {
|
|
40
41
|
id: string;
|
|
41
42
|
state: {
|
|
42
43
|
entries: Map<string, import("./layer-state.js").LayerEntry>;
|
|
43
44
|
topWindow: () => import("./layer-state.js").LayerEntry | undefined;
|
|
44
45
|
top: () => import("./layer-state.js").LayerEntry | undefined;
|
|
46
|
+
topPopup: () => import("./layer-state.js").LayerEntry | undefined;
|
|
45
47
|
windowOf: (id?: string) => string | undefined;
|
|
46
48
|
isRestoredFocus(target?: FocusTarget | null): boolean;
|
|
47
49
|
clearRestoredFocus(target?: FocusTarget | null): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kjun-ui/native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://ui.kjun.dev",
|
|
6
6
|
"repository": {
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"./package.json": "./package.json"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@kjun-ui/tokens": "0.
|
|
51
|
-
"@kjun-ui/icons": "0.
|
|
50
|
+
"@kjun-ui/tokens": "0.9.0",
|
|
51
|
+
"@kjun-ui/icons": "0.9.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"react": "^19.2.3",
|