sellmate-design-system-react 9.0.0-beta.43 → 9.0.0-beta.45
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/AGENTS.md +100 -1
- package/dist/components/SDraggableList/README.md +3 -3
- package/dist/components/SDraggableList/SDraggableList.d.ts +7 -3
- package/dist/components/SFooter/README.md +13 -8
- package/dist/components/SFooter/SFooter.d.ts +14 -9
- package/dist/components/SNumberInput/README.md +3 -2
- package/dist/components/SNumberInput/SNumberInput.d.ts +22 -2
- package/dist/components/SPopup/README.md +5 -6
- package/dist/components/SPopup/SPopup.d.ts +6 -7
- package/dist/components/SSelect/README.md +8 -0
- package/dist/components/SSelect/SSelect.d.ts +44 -0
- package/dist/components/SSelect/row-metrics.d.ts +60 -0
- package/dist/components/SSelect/select.config.d.ts +15 -0
- package/dist/components/STable/README.md +1 -1
- package/dist/components/STable/STable.d.ts +1 -1
- package/dist/components/STextarea/README.md +4 -1
- package/dist/components/STextarea/STextarea.d.ts +25 -2
- package/dist/index.cjs +455 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +455 -59
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +137 -22
- package/dist/llms.txt +100 -1
- package/dist/styles.css +3 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3689,14 +3689,14 @@ function SFooter({
|
|
|
3689
3689
|
]
|
|
3690
3690
|
}
|
|
3691
3691
|
),
|
|
3692
|
-
hasButton &&
|
|
3692
|
+
hasButton && // 스프레드를 먼저 두고 기본값을 뒤에 덮는다 — 순서를 뒤집으면 `{ color: undefined }`
|
|
3693
|
+
// 처럼 값 없이 넘어온 키가 footer 기본값을 지우고 SButton 기본값으로 떨어진다.
|
|
3694
|
+
/* @__PURE__ */ jsx(
|
|
3693
3695
|
SButton,
|
|
3694
3696
|
{
|
|
3697
|
+
...button,
|
|
3698
|
+
size: "md",
|
|
3695
3699
|
color: button.color ?? "primary",
|
|
3696
|
-
outline: button.outline,
|
|
3697
|
-
size: button.size ?? "md",
|
|
3698
|
-
disabled: button.disabled,
|
|
3699
|
-
onClick: () => button.onClick?.(),
|
|
3700
3700
|
label: button.label ?? "\uD655\uC778"
|
|
3701
3701
|
}
|
|
3702
3702
|
)
|
|
@@ -4265,6 +4265,13 @@ function SDraggableProvider({ children }) {
|
|
|
4265
4265
|
function SDraggableGroup({ children, onMove, ...rest }) {
|
|
4266
4266
|
return /* @__PURE__ */ jsx(SDraggableProviderInternal, { defaultGroup: "__legacy", legacyOnMove: onMove, children: /* @__PURE__ */ jsx("div", { ...rest, children }) });
|
|
4267
4267
|
}
|
|
4268
|
+
var INTERACTIVE_DESCENDANT_SELECTOR = 'input,textarea,select,button,a[href],label,[contenteditable="true"],[role="button"],[role="checkbox"],[role="radio"],[role="switch"],[role="tab"],[role="menuitem"]';
|
|
4269
|
+
function isFromInteractiveDescendant(event) {
|
|
4270
|
+
const target = event.target;
|
|
4271
|
+
if (target == null || target === event.currentTarget) return false;
|
|
4272
|
+
const interactive = target.closest?.(INTERACTIVE_DESCENDANT_SELECTOR);
|
|
4273
|
+
return interactive != null && interactive !== event.currentTarget;
|
|
4274
|
+
}
|
|
4268
4275
|
function reorder(items, fromIndex, toIndex) {
|
|
4269
4276
|
if (fromIndex === toIndex) return items;
|
|
4270
4277
|
const nextItems = [...items];
|
|
@@ -4348,6 +4355,7 @@ function SDraggableListInner({
|
|
|
4348
4355
|
const listRef = useRef(null);
|
|
4349
4356
|
const fromIndexRef = useRef(null);
|
|
4350
4357
|
const currentSelectedKey = selectedKey ?? internalSelectedKey;
|
|
4358
|
+
const selectable = selectedKey !== void 0 || defaultSelectedKey !== void 0 || onSelectedKeyChange != null;
|
|
4351
4359
|
const usesDepth = getDepth != null;
|
|
4352
4360
|
const depthEnabled = usesDepth && !gap;
|
|
4353
4361
|
const groupDragging = dragContext?.dragging;
|
|
@@ -4507,20 +4515,28 @@ function SDraggableListInner({
|
|
|
4507
4515
|
setInternalSelectedKey(itemKey);
|
|
4508
4516
|
onSelectedKeyChange?.(itemKey);
|
|
4509
4517
|
};
|
|
4518
|
+
const handleItemClick = (event) => {
|
|
4519
|
+
if (isFromInteractiveDescendant(event)) return;
|
|
4520
|
+
selectItem();
|
|
4521
|
+
};
|
|
4510
4522
|
const handleItemKeyDown = (event) => {
|
|
4523
|
+
if (event.target !== event.currentTarget) return;
|
|
4511
4524
|
if (event.key !== "Enter" && event.key !== " ") return;
|
|
4512
4525
|
event.preventDefault();
|
|
4513
4526
|
selectItem();
|
|
4514
4527
|
};
|
|
4528
|
+
const selectionProps = selectable ? {
|
|
4529
|
+
role: "button",
|
|
4530
|
+
tabIndex: disabled ? -1 : 0,
|
|
4531
|
+
onClick: handleItemClick,
|
|
4532
|
+
onKeyDown: handleItemKeyDown
|
|
4533
|
+
} : {};
|
|
4515
4534
|
return /* @__PURE__ */ jsxs(
|
|
4516
4535
|
"div",
|
|
4517
4536
|
{
|
|
4518
4537
|
"data-draggable-list-item": true,
|
|
4519
|
-
role: "button",
|
|
4520
|
-
tabIndex: disabled ? -1 : 0,
|
|
4521
4538
|
"aria-disabled": disabled || void 0,
|
|
4522
|
-
|
|
4523
|
-
onKeyDown: handleItemKeyDown,
|
|
4539
|
+
...selectionProps,
|
|
4524
4540
|
className: "relative",
|
|
4525
4541
|
children: [
|
|
4526
4542
|
showBefore && /* @__PURE__ */ jsx(
|
|
@@ -12708,6 +12724,130 @@ function collectGroupLeafValues(flat, groupIndex) {
|
|
|
12708
12724
|
}
|
|
12709
12725
|
var isHtmlLabel = (label) => /<[a-z][\s\S]*>/i.test(label);
|
|
12710
12726
|
var extractText = (html) => html.replace(/<[^>]*>/g, "");
|
|
12727
|
+
var OPTION_ROW_HEIGHT = 28;
|
|
12728
|
+
var DEFAULT_VIRTUAL_BUFFER = 10;
|
|
12729
|
+
var DEFAULT_REACH_END_THRESHOLD = 10;
|
|
12730
|
+
var DEFAULT_SEARCH_DEBOUNCE = 300;
|
|
12731
|
+
|
|
12732
|
+
// src/components/SSelect/row-metrics.ts
|
|
12733
|
+
function createRowMetrics(count, estimate) {
|
|
12734
|
+
const safeCount = Math.max(0, Math.floor(count));
|
|
12735
|
+
const safeEstimate = Math.max(1, estimate);
|
|
12736
|
+
const metrics = {
|
|
12737
|
+
sizes: new Array(safeCount).fill(safeEstimate),
|
|
12738
|
+
measured: new Array(safeCount).fill(false),
|
|
12739
|
+
offsets: [],
|
|
12740
|
+
estimate: safeEstimate,
|
|
12741
|
+
measuredCount: 0,
|
|
12742
|
+
measuredTotal: 0,
|
|
12743
|
+
dirtyFrom: 0
|
|
12744
|
+
};
|
|
12745
|
+
rebuildOffsets(metrics);
|
|
12746
|
+
return metrics;
|
|
12747
|
+
}
|
|
12748
|
+
function resizeRowMetrics(metrics, count) {
|
|
12749
|
+
const next = Math.max(0, Math.floor(count));
|
|
12750
|
+
const prev = metrics.sizes.length;
|
|
12751
|
+
if (next === prev) return;
|
|
12752
|
+
if (next < prev) {
|
|
12753
|
+
for (let i = next; i < prev; i++) {
|
|
12754
|
+
if (metrics.measured[i]) {
|
|
12755
|
+
metrics.measuredCount--;
|
|
12756
|
+
metrics.measuredTotal -= metrics.sizes[i];
|
|
12757
|
+
}
|
|
12758
|
+
}
|
|
12759
|
+
metrics.sizes.length = next;
|
|
12760
|
+
metrics.measured.length = next;
|
|
12761
|
+
} else {
|
|
12762
|
+
for (let i = prev; i < next; i++) {
|
|
12763
|
+
metrics.sizes.push(metrics.estimate);
|
|
12764
|
+
metrics.measured.push(false);
|
|
12765
|
+
}
|
|
12766
|
+
}
|
|
12767
|
+
markDirty(metrics, Math.min(prev, next));
|
|
12768
|
+
}
|
|
12769
|
+
function resetRowMetrics(metrics, count) {
|
|
12770
|
+
const fresh = createRowMetrics(count, metrics.estimate);
|
|
12771
|
+
metrics.sizes = fresh.sizes;
|
|
12772
|
+
metrics.measured = fresh.measured;
|
|
12773
|
+
metrics.offsets = fresh.offsets;
|
|
12774
|
+
metrics.measuredCount = 0;
|
|
12775
|
+
metrics.measuredTotal = 0;
|
|
12776
|
+
metrics.dirtyFrom = Infinity;
|
|
12777
|
+
}
|
|
12778
|
+
function setRowSize(metrics, index, size) {
|
|
12779
|
+
if (index < 0 || index >= metrics.sizes.length) return false;
|
|
12780
|
+
const next = Math.max(1, Math.round(size));
|
|
12781
|
+
const wasMeasured = metrics.measured[index];
|
|
12782
|
+
const prev = metrics.sizes[index];
|
|
12783
|
+
if (wasMeasured && prev === next) return false;
|
|
12784
|
+
if (wasMeasured) {
|
|
12785
|
+
metrics.measuredTotal += next - prev;
|
|
12786
|
+
} else {
|
|
12787
|
+
metrics.measured[index] = true;
|
|
12788
|
+
metrics.measuredCount++;
|
|
12789
|
+
metrics.measuredTotal += next;
|
|
12790
|
+
}
|
|
12791
|
+
metrics.sizes[index] = next;
|
|
12792
|
+
let changedFrom = prev === next ? Infinity : index;
|
|
12793
|
+
const average = Math.max(1, Math.round(metrics.measuredTotal / metrics.measuredCount));
|
|
12794
|
+
if (average !== metrics.estimate) {
|
|
12795
|
+
metrics.estimate = average;
|
|
12796
|
+
for (let i = 0; i < metrics.sizes.length; i++) {
|
|
12797
|
+
if (metrics.measured[i] || metrics.sizes[i] === average) continue;
|
|
12798
|
+
metrics.sizes[i] = average;
|
|
12799
|
+
if (i < changedFrom) changedFrom = i;
|
|
12800
|
+
}
|
|
12801
|
+
}
|
|
12802
|
+
if (changedFrom === Infinity) return false;
|
|
12803
|
+
markDirty(metrics, changedFrom);
|
|
12804
|
+
return true;
|
|
12805
|
+
}
|
|
12806
|
+
function markDirty(metrics, from) {
|
|
12807
|
+
metrics.dirtyFrom = Math.min(metrics.dirtyFrom, Math.max(0, from));
|
|
12808
|
+
}
|
|
12809
|
+
function rebuildOffsets(metrics) {
|
|
12810
|
+
const count = metrics.sizes.length;
|
|
12811
|
+
const stale = metrics.offsets.length !== count + 1;
|
|
12812
|
+
if (!stale && metrics.dirtyFrom === Infinity) return;
|
|
12813
|
+
const start = stale ? 0 : Math.min(metrics.dirtyFrom, count);
|
|
12814
|
+
const acc0 = start === 0 ? 0 : metrics.offsets[start] ?? 0;
|
|
12815
|
+
metrics.offsets.length = count + 1;
|
|
12816
|
+
let acc = acc0;
|
|
12817
|
+
for (let i = start; i < count; i++) {
|
|
12818
|
+
metrics.offsets[i] = acc;
|
|
12819
|
+
acc += metrics.sizes[i];
|
|
12820
|
+
}
|
|
12821
|
+
metrics.offsets[count] = acc;
|
|
12822
|
+
metrics.dirtyFrom = Infinity;
|
|
12823
|
+
}
|
|
12824
|
+
function totalSize(metrics) {
|
|
12825
|
+
rebuildOffsets(metrics);
|
|
12826
|
+
return metrics.offsets[metrics.sizes.length] ?? 0;
|
|
12827
|
+
}
|
|
12828
|
+
function offsetOf(metrics, index) {
|
|
12829
|
+
rebuildOffsets(metrics);
|
|
12830
|
+
const clamped = Math.max(0, Math.min(Math.floor(index), metrics.sizes.length));
|
|
12831
|
+
return metrics.offsets[clamped] ?? 0;
|
|
12832
|
+
}
|
|
12833
|
+
function sizeOf(metrics, index) {
|
|
12834
|
+
if (index < 0 || index >= metrics.sizes.length) return metrics.estimate;
|
|
12835
|
+
return metrics.sizes[index];
|
|
12836
|
+
}
|
|
12837
|
+
function indexAtOffset(metrics, y) {
|
|
12838
|
+
rebuildOffsets(metrics);
|
|
12839
|
+
const count = metrics.sizes.length;
|
|
12840
|
+
if (count === 0) return 0;
|
|
12841
|
+
const target = Math.max(0, y);
|
|
12842
|
+
let lo = 0;
|
|
12843
|
+
let hi = count - 1;
|
|
12844
|
+
while (lo < hi) {
|
|
12845
|
+
const mid = lo + hi + 1 >> 1;
|
|
12846
|
+
if (metrics.offsets[mid] <= target) lo = mid;
|
|
12847
|
+
else hi = mid - 1;
|
|
12848
|
+
}
|
|
12849
|
+
return lo;
|
|
12850
|
+
}
|
|
12711
12851
|
var SEARCH_THRESHOLD = 11;
|
|
12712
12852
|
var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
12713
12853
|
value,
|
|
@@ -12729,6 +12869,14 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12729
12869
|
dropdownHeight = "640px",
|
|
12730
12870
|
dropdownWidth,
|
|
12731
12871
|
maxDropdownWidth = "640px",
|
|
12872
|
+
virtualBuffer = DEFAULT_VIRTUAL_BUFFER,
|
|
12873
|
+
onReachEnd,
|
|
12874
|
+
reachEndThreshold = DEFAULT_REACH_END_THRESHOLD,
|
|
12875
|
+
hasMore = false,
|
|
12876
|
+
loading: loading2 = false,
|
|
12877
|
+
serverSearch = false,
|
|
12878
|
+
onSearchChange,
|
|
12879
|
+
searchDebounce = DEFAULT_SEARCH_DEBOUNCE,
|
|
12732
12880
|
label,
|
|
12733
12881
|
labelWidth,
|
|
12734
12882
|
icon,
|
|
@@ -12743,6 +12891,9 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12743
12891
|
style
|
|
12744
12892
|
}, ref) {
|
|
12745
12893
|
const multi = type === "multi" || type === "multi_depth";
|
|
12894
|
+
const isDepth = type === "default_depth" || type === "multi_depth";
|
|
12895
|
+
const pagingEnabled = onReachEnd != null;
|
|
12896
|
+
const partialOptions = pagingEnabled || serverSearch;
|
|
12746
12897
|
const portalContainer = usePortalContainer();
|
|
12747
12898
|
const insideModal = useInsideModal();
|
|
12748
12899
|
const [search, setSearch] = useState("");
|
|
@@ -12750,6 +12901,15 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12750
12901
|
const [open, setOpen] = useState(false);
|
|
12751
12902
|
const [pendingOpen, setPendingOpen] = useState(false);
|
|
12752
12903
|
const [focusedIndex, setFocusedIndex] = useState(-1);
|
|
12904
|
+
const [win, setWin] = useState({ start: 0, end: 0, top: 0, bottom: 0 });
|
|
12905
|
+
const winRef = useRef(win);
|
|
12906
|
+
winRef.current = win;
|
|
12907
|
+
const metricsRef = useRef(null);
|
|
12908
|
+
metricsRef.current ?? (metricsRef.current = createRowMetrics(0, OPTION_ROW_HEIGHT));
|
|
12909
|
+
const [searchBarHeight, setSearchBarHeight] = useState(0);
|
|
12910
|
+
const [selectAllHeight, setSelectAllHeight] = useState(0);
|
|
12911
|
+
const measuredKeyRef = useRef("");
|
|
12912
|
+
const lastReachEndCountRef = useRef(-1);
|
|
12753
12913
|
const triggerRef = useRef(null);
|
|
12754
12914
|
const searchInputRef = useRef(null);
|
|
12755
12915
|
const searchBarRef = useRef(null);
|
|
@@ -12764,7 +12924,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12764
12924
|
const hasLeaf = useMemo(() => flat.some((o) => !o.isGroup), [flat]);
|
|
12765
12925
|
const allOptionsDisabled = hasLeaf && selectable.length === 0;
|
|
12766
12926
|
const effectiveDisabled = disabled || allOptionsDisabled;
|
|
12767
|
-
const searchVisible = showSearch && selectable.length >= SEARCH_THRESHOLD;
|
|
12927
|
+
const searchVisible = showSearch && (partialOptions || selectable.length >= SEARCH_THRESHOLD);
|
|
12768
12928
|
const labelByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.label])), [flat]);
|
|
12769
12929
|
const rawByValue = useMemo(() => new Map(flat.map((o) => [o.value, o.raw])), [flat]);
|
|
12770
12930
|
const optionByValue = useMemo(
|
|
@@ -12776,12 +12936,26 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12776
12936
|
const arr = Array.isArray(value) ? value : [value];
|
|
12777
12937
|
return arr.map((v) => v != null && typeof v === "object" ? v.value : v).filter((v) => v != null && v !== "").map(String);
|
|
12778
12938
|
}, [value]);
|
|
12939
|
+
const valueOptions = useMemo(() => {
|
|
12940
|
+
const map = /* @__PURE__ */ new Map();
|
|
12941
|
+
if (value == null) return map;
|
|
12942
|
+
for (const v of Array.isArray(value) ? value : [value]) {
|
|
12943
|
+
if (v != null && typeof v === "object") {
|
|
12944
|
+
map.set(String(v.value), { value: v.value, label: v.label });
|
|
12945
|
+
}
|
|
12946
|
+
}
|
|
12947
|
+
return map;
|
|
12948
|
+
}, [value]);
|
|
12779
12949
|
const selectedRef = useRef(selected);
|
|
12780
12950
|
selectedRef.current = selected;
|
|
12951
|
+
const selectedSet = useMemo(() => new Set(selected), [selected]);
|
|
12952
|
+
const cbRef = useRef({ onReachEnd, onSearchChange });
|
|
12953
|
+
cbRef.current = { onReachEnd, onSearchChange };
|
|
12954
|
+
const emittedQueryRef = useRef("");
|
|
12781
12955
|
const emit3 = (next) => {
|
|
12782
12956
|
if (!onValueChange) return;
|
|
12783
12957
|
const mapped = next.map(
|
|
12784
|
-
(v) => valueAsPrimitive ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
|
|
12958
|
+
(v) => valueAsPrimitive ? rawByValue.get(v) ?? valueOptions.get(v)?.value ?? v : optionByValue.get(v) ?? valueOptions.get(v) ?? { value: v, label: v }
|
|
12785
12959
|
);
|
|
12786
12960
|
onValueChange(multi ? mapped : mapped[0] ?? (valueAsPrimitive ? "" : null));
|
|
12787
12961
|
};
|
|
@@ -12830,14 +13004,15 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12830
13004
|
resetValidation: () => setRuleError("")
|
|
12831
13005
|
});
|
|
12832
13006
|
const filtered = useMemo(() => {
|
|
12833
|
-
if (!searchVisible || search.trim() === "") return flat;
|
|
13007
|
+
if (serverSearch || !searchVisible || search.trim() === "") return flat;
|
|
12834
13008
|
const q = search.trim().toLowerCase();
|
|
12835
13009
|
return flat.filter(
|
|
12836
13010
|
(o) => o.isGroup || (isHtmlLabel(o.label) ? extractText(o.label) : o.label).toLowerCase().includes(q)
|
|
12837
13011
|
);
|
|
12838
|
-
}, [flat, search, searchVisible]);
|
|
13012
|
+
}, [flat, search, searchVisible, serverSearch]);
|
|
12839
13013
|
const allValues = selectable.map((o) => o.value);
|
|
12840
|
-
const allSelected = allValues.length > 0 && allValues.every((v) =>
|
|
13014
|
+
const allSelected = !partialOptions && allValues.length > 0 && allValues.every((v) => selectedSet.has(v));
|
|
13015
|
+
const selectAllVisible = multi && showSelectAll && !partialOptions && allValues.length > 0;
|
|
12841
13016
|
const hasItems = filtered.some((o) => !o.isGroup);
|
|
12842
13017
|
const groupLeafValues = useMemo(() => {
|
|
12843
13018
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -12848,7 +13023,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12848
13023
|
}, [filtered]);
|
|
12849
13024
|
const navigableItems = useMemo(() => {
|
|
12850
13025
|
const items = [];
|
|
12851
|
-
if (
|
|
13026
|
+
if (selectAllVisible) {
|
|
12852
13027
|
items.push({ key: "__select_all__", isSelectAll: true });
|
|
12853
13028
|
}
|
|
12854
13029
|
filtered.forEach((o, i) => {
|
|
@@ -12863,20 +13038,129 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12863
13038
|
}
|
|
12864
13039
|
});
|
|
12865
13040
|
return items;
|
|
12866
|
-
}, [
|
|
13041
|
+
}, [filtered, groupLeafValues, multi, selectAllVisible]);
|
|
12867
13042
|
const selectedAnchorIndex = useMemo(() => {
|
|
12868
|
-
if (
|
|
12869
|
-
const selectedSet = new Set(selected);
|
|
13043
|
+
if (selectedSet.size === 0) return -1;
|
|
12870
13044
|
return navigableItems.findIndex((item4) => item4.value != null && selectedSet.has(item4.value));
|
|
12871
|
-
}, [navigableItems,
|
|
13045
|
+
}, [navigableItems, selectedSet]);
|
|
12872
13046
|
selectedAnchorRef.current = selectedAnchorIndex;
|
|
13047
|
+
const navigableItemsRef = useRef(navigableItems);
|
|
13048
|
+
navigableItemsRef.current = navigableItems;
|
|
13049
|
+
const rowCount = filtered.length;
|
|
13050
|
+
const metrics = metricsRef.current;
|
|
13051
|
+
const lastSearchRef = useRef(search);
|
|
13052
|
+
if (lastSearchRef.current !== search) {
|
|
13053
|
+
lastSearchRef.current = search;
|
|
13054
|
+
resetRowMetrics(metrics, rowCount);
|
|
13055
|
+
measuredKeyRef.current = "";
|
|
13056
|
+
} else {
|
|
13057
|
+
resizeRowMetrics(metrics, rowCount);
|
|
13058
|
+
}
|
|
13059
|
+
const rowsOffset = searchBarHeight + selectAllHeight;
|
|
13060
|
+
const syncScrollState = useCallback(() => {
|
|
13061
|
+
if (!listEl) return;
|
|
13062
|
+
const m = metricsRef.current;
|
|
13063
|
+
if (m == null) return;
|
|
13064
|
+
const buffer = Math.max(0, Math.floor(virtualBuffer));
|
|
13065
|
+
const viewTop = Math.max(0, listEl.scrollTop - rowsOffset);
|
|
13066
|
+
const viewBottom = viewTop + Math.max(0, listEl.clientHeight);
|
|
13067
|
+
const start = Math.max(0, indexAtOffset(m, viewTop) - buffer);
|
|
13068
|
+
const end = Math.min(rowCount, indexAtOffset(m, viewBottom) + 1 + buffer);
|
|
13069
|
+
const top = offsetOf(m, start);
|
|
13070
|
+
const bottom = Math.max(0, totalSize(m) - offsetOf(m, end));
|
|
13071
|
+
setWin(
|
|
13072
|
+
(prev) => prev.start === start && prev.end === end && prev.top === top && prev.bottom === bottom ? prev : { start, end, top, bottom }
|
|
13073
|
+
);
|
|
13074
|
+
if (!pagingEnabled || !hasMore || loading2) return;
|
|
13075
|
+
const contentHeight = rowsOffset + totalSize(m);
|
|
13076
|
+
const remaining = contentHeight - listEl.scrollTop - listEl.clientHeight;
|
|
13077
|
+
if (remaining > Math.max(1, reachEndThreshold) * m.estimate) return;
|
|
13078
|
+
if (lastReachEndCountRef.current === rowCount) return;
|
|
13079
|
+
lastReachEndCountRef.current = rowCount;
|
|
13080
|
+
cbRef.current.onReachEnd?.();
|
|
13081
|
+
}, [
|
|
13082
|
+
hasMore,
|
|
13083
|
+
listEl,
|
|
13084
|
+
loading2,
|
|
13085
|
+
pagingEnabled,
|
|
13086
|
+
reachEndThreshold,
|
|
13087
|
+
rowCount,
|
|
13088
|
+
rowsOffset,
|
|
13089
|
+
virtualBuffer
|
|
13090
|
+
]);
|
|
13091
|
+
const syncScrollStateRef = useRef(syncScrollState);
|
|
13092
|
+
syncScrollStateRef.current = syncScrollState;
|
|
13093
|
+
useLayoutEffect(() => {
|
|
13094
|
+
if (!open) return;
|
|
13095
|
+
syncScrollState();
|
|
13096
|
+
}, [open, syncScrollState]);
|
|
13097
|
+
useLayoutEffect(() => {
|
|
13098
|
+
if (!open || !listEl) {
|
|
13099
|
+
setSearchBarHeight(0);
|
|
13100
|
+
setSelectAllHeight(0);
|
|
13101
|
+
return;
|
|
13102
|
+
}
|
|
13103
|
+
const nextBar = searchVisible ? searchBarRef.current?.offsetHeight ?? 0 : 0;
|
|
13104
|
+
setSearchBarHeight((prev) => prev === nextBar ? prev : nextBar);
|
|
13105
|
+
const nextSelectAll = selectAllVisible ? listEl.querySelector("[data-select-all-row]")?.offsetHeight ?? 0 : 0;
|
|
13106
|
+
setSelectAllHeight((prev) => prev === nextSelectAll ? prev : nextSelectAll);
|
|
13107
|
+
}, [listEl, open, searchVisible, selectAllVisible]);
|
|
13108
|
+
useLayoutEffect(() => {
|
|
13109
|
+
if (!open || !listEl) return;
|
|
13110
|
+
const m = metricsRef.current;
|
|
13111
|
+
if (m == null) return;
|
|
13112
|
+
const key = `${winRef.current.start}:${winRef.current.end}:${rowCount}`;
|
|
13113
|
+
if (measuredKeyRef.current === key) return;
|
|
13114
|
+
measuredKeyRef.current = key;
|
|
13115
|
+
const anchor = winRef.current.start;
|
|
13116
|
+
const anchorBefore = offsetOf(m, anchor);
|
|
13117
|
+
let changed = false;
|
|
13118
|
+
for (const row of listEl.querySelectorAll("[data-select-row]")) {
|
|
13119
|
+
const index = Number(row.dataset.index);
|
|
13120
|
+
if (!Number.isInteger(index)) continue;
|
|
13121
|
+
if (setRowSize(m, index, row.offsetHeight)) changed = true;
|
|
13122
|
+
}
|
|
13123
|
+
if (!changed) return;
|
|
13124
|
+
const delta = offsetOf(m, anchor) - anchorBefore;
|
|
13125
|
+
if (delta !== 0 && listEl.scrollTop > 0) listEl.scrollTop += delta;
|
|
13126
|
+
syncScrollStateRef.current();
|
|
13127
|
+
});
|
|
13128
|
+
useEffect(() => {
|
|
13129
|
+
if (cbRef.current.onSearchChange == null) return;
|
|
13130
|
+
if (search === emittedQueryRef.current) return;
|
|
13131
|
+
if (!serverSearch) {
|
|
13132
|
+
emittedQueryRef.current = search;
|
|
13133
|
+
cbRef.current.onSearchChange(search);
|
|
13134
|
+
return;
|
|
13135
|
+
}
|
|
13136
|
+
const timer = setTimeout(
|
|
13137
|
+
() => {
|
|
13138
|
+
emittedQueryRef.current = search;
|
|
13139
|
+
cbRef.current.onSearchChange?.(search);
|
|
13140
|
+
},
|
|
13141
|
+
Math.max(0, searchDebounce)
|
|
13142
|
+
);
|
|
13143
|
+
return () => clearTimeout(timer);
|
|
13144
|
+
}, [search, searchDebounce, serverSearch]);
|
|
13145
|
+
const selectAllMisuse = multi && showSelectAll && partialOptions;
|
|
13146
|
+
useEffect(() => {
|
|
13147
|
+
if (!isDev()) return;
|
|
13148
|
+
if (selectAllMisuse) {
|
|
13149
|
+
console.warn(
|
|
13150
|
+
'[SSelect] onReachEnd\xB7serverSearch \uC640 \uD568\uAED8 \uC900 showSelectAll \uC744 \uBB34\uC2DC\uD569\uB2C8\uB2E4. options \uAC00 \uBAA9\uB85D\uC758 \uC870\uAC01\uC77C \uBFD0\uC774\uB77C \uC544\uC9C1 \uBC1B\uC9C0 \uC54A\uC740 \uC635\uC158\uC740 \uACE0\uB97C \uC218 \uC5C6\uACE0, \uBC1B\uC544 \uC628 \uB9CC\uD07C\uB9CC \uACE0\uB978 \uC0C1\uD0DC\uB97C "\uC804\uCCB4"\uB77C\uACE0 \uD45C\uC2DC\uD558\uBA74 \uAC70\uC9D3\uC774 \uB429\uB2C8\uB2E4.'
|
|
13151
|
+
);
|
|
13152
|
+
}
|
|
13153
|
+
}, [selectAllMisuse]);
|
|
13154
|
+
const windowStart = Math.min(win.start, rowCount);
|
|
13155
|
+
const windowEnd = Math.max(windowStart, Math.min(win.end, rowCount));
|
|
13156
|
+
const visibleItems = filtered.slice(windowStart, windowEnd);
|
|
12873
13157
|
const triggerText = (() => {
|
|
12874
13158
|
if (selected.length === 0) return placeholder;
|
|
12875
13159
|
if (multi) {
|
|
12876
13160
|
if (allSelected) return allSelectedLabel;
|
|
12877
|
-
return selected.map((v) => labelByValue.get(v) ?? v).filter(Boolean).join(", ");
|
|
13161
|
+
return selected.map((v) => labelByValue.get(v) ?? valueOptions.get(v)?.label ?? v).filter(Boolean).join(", ");
|
|
12878
13162
|
}
|
|
12879
|
-
return labelByValue.get(selected[0]) ?? selected[0];
|
|
13163
|
+
return labelByValue.get(selected[0]) ?? valueOptions.get(selected[0])?.label ?? selected[0];
|
|
12880
13164
|
})();
|
|
12881
13165
|
const isPlaceholder = selected.length === 0;
|
|
12882
13166
|
const showClear = clearable && !effectiveDisabled && !isPlaceholder;
|
|
@@ -12889,7 +13173,6 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12889
13173
|
const anchor = rangeAnchorRef.current;
|
|
12890
13174
|
if (extend && anchor != null && anchor !== index && filtered[anchor]?.isGroup === false) {
|
|
12891
13175
|
const [from, to] = anchor < index ? [anchor, index] : [index, anchor];
|
|
12892
|
-
const selectedSet = new Set(selected);
|
|
12893
13176
|
const shouldSelect = selectedSet.has(filtered[anchor].value);
|
|
12894
13177
|
const rangeValues = filtered.slice(from, to + 1).filter((o) => !o.isGroup && !o.disabled).map((o) => o.value);
|
|
12895
13178
|
const inRange = new Set(rangeValues);
|
|
@@ -12914,7 +13197,6 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12914
13197
|
const handleToggleGroup = (leafValues) => {
|
|
12915
13198
|
if (leafValues.length === 0) return;
|
|
12916
13199
|
rangeAnchorRef.current = null;
|
|
12917
|
-
const selectedSet = new Set(selected);
|
|
12918
13200
|
const allSelectedInGroup = leafValues.every((v) => selectedSet.has(v));
|
|
12919
13201
|
if (allSelectedInGroup) {
|
|
12920
13202
|
const remove = new Set(leafValues);
|
|
@@ -12923,35 +13205,51 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
12923
13205
|
emit3([...selected, ...leafValues.filter((v) => !selectedSet.has(v))]);
|
|
12924
13206
|
}
|
|
12925
13207
|
};
|
|
13208
|
+
const hasNavigableItems = navigableItems.length > 0;
|
|
12926
13209
|
useEffect(() => {
|
|
12927
|
-
if (!open ||
|
|
13210
|
+
if (!open || !hasNavigableItems) {
|
|
12928
13211
|
setFocusedIndex(-1);
|
|
12929
13212
|
return;
|
|
12930
13213
|
}
|
|
12931
13214
|
const anchor = alignSelectedTopRef.current ? selectedAnchorRef.current : -1;
|
|
12932
13215
|
setFocusedIndex(anchor >= 0 ? anchor : 0);
|
|
12933
|
-
}, [open, search,
|
|
13216
|
+
}, [open, search, hasNavigableItems]);
|
|
13217
|
+
const lastResetSearchRef = useRef(search);
|
|
13218
|
+
useLayoutEffect(() => {
|
|
13219
|
+
if (lastResetSearchRef.current === search) return;
|
|
13220
|
+
lastResetSearchRef.current = search;
|
|
13221
|
+
if (!open || !listEl) return;
|
|
13222
|
+
listEl.scrollTop = 0;
|
|
13223
|
+
syncScrollStateRef.current();
|
|
13224
|
+
}, [listEl, open, search]);
|
|
12934
13225
|
useEffect(() => {
|
|
12935
13226
|
rangeAnchorRef.current = null;
|
|
13227
|
+
lastReachEndCountRef.current = -1;
|
|
12936
13228
|
}, [open, search]);
|
|
12937
13229
|
useLayoutEffect(() => {
|
|
12938
13230
|
if (!open || focusedIndex < 0 || !listEl) return;
|
|
12939
|
-
const
|
|
12940
|
-
if (
|
|
12941
|
-
const
|
|
12942
|
-
const
|
|
12943
|
-
if (
|
|
13231
|
+
const m = metricsRef.current;
|
|
13232
|
+
if (m == null) return;
|
|
13233
|
+
const stickyOffset = searchBarRef.current?.offsetHeight ?? 0;
|
|
13234
|
+
const rowIndex = navigableItemsRef.current[focusedIndex]?.index;
|
|
13235
|
+
if (rowIndex == null) {
|
|
12944
13236
|
alignSelectedTopRef.current = false;
|
|
12945
|
-
|
|
12946
|
-
|
|
13237
|
+
listEl.scrollTop = 0;
|
|
13238
|
+
syncScrollStateRef.current();
|
|
12947
13239
|
return;
|
|
12948
13240
|
}
|
|
12949
|
-
|
|
12950
|
-
|
|
12951
|
-
|
|
12952
|
-
|
|
12953
|
-
|
|
12954
|
-
|
|
13241
|
+
const top = rowsOffset + offsetOf(m, rowIndex);
|
|
13242
|
+
const height = sizeOf(m, rowIndex);
|
|
13243
|
+
if (alignSelectedTopRef.current) {
|
|
13244
|
+
alignSelectedTopRef.current = false;
|
|
13245
|
+
listEl.scrollTop = top - stickyOffset;
|
|
13246
|
+
} else if (top < listEl.scrollTop + stickyOffset) {
|
|
13247
|
+
listEl.scrollTop = top - stickyOffset;
|
|
13248
|
+
} else if (top + height > listEl.scrollTop + listEl.clientHeight) {
|
|
13249
|
+
listEl.scrollTop = top + height - listEl.clientHeight;
|
|
13250
|
+
}
|
|
13251
|
+
syncScrollStateRef.current();
|
|
13252
|
+
}, [focusedIndex, listEl, open, rowsOffset]);
|
|
12955
13253
|
const moveFocusedIndex = (direction) => {
|
|
12956
13254
|
if (!open || navigableItems.length === 0) return;
|
|
12957
13255
|
setFocusedIndex((current) => {
|
|
@@ -13141,6 +13439,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
13141
13439
|
SCROLLBAR_TRACK_BORDER_CLASS
|
|
13142
13440
|
),
|
|
13143
13441
|
style: { maxHeight: clampToAvailableHeight(dropdownHeight, POPOVER_AVAILABLE_HEIGHT) },
|
|
13442
|
+
onScroll: syncScrollState,
|
|
13144
13443
|
onMouseLeave: () => setFocusedIndex(-1),
|
|
13145
13444
|
children: [
|
|
13146
13445
|
searchVisible && /* @__PURE__ */ jsx(
|
|
@@ -13164,12 +13463,16 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
13164
13463
|
hasItems ? /* @__PURE__ */ jsx(
|
|
13165
13464
|
ItemList,
|
|
13166
13465
|
{
|
|
13167
|
-
items:
|
|
13466
|
+
items: visibleItems,
|
|
13467
|
+
indexOffset: windowStart,
|
|
13468
|
+
topSpacer: win.top,
|
|
13469
|
+
bottomSpacer: win.bottom,
|
|
13470
|
+
setSize: isDepth ? void 0 : rowCount,
|
|
13168
13471
|
multi,
|
|
13169
13472
|
selected,
|
|
13170
13473
|
groupLeafValues,
|
|
13171
13474
|
focusedValue: navigableItems[focusedIndex]?.key,
|
|
13172
|
-
showSelectAll:
|
|
13475
|
+
showSelectAll: selectAllVisible,
|
|
13173
13476
|
selectAllLabel: allSelectedLabel,
|
|
13174
13477
|
selectAllSelected: allSelected,
|
|
13175
13478
|
onSelectAll: handleSelectAll,
|
|
@@ -13184,7 +13487,18 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
13184
13487
|
if (index >= 0) setFocusedIndex(index);
|
|
13185
13488
|
}
|
|
13186
13489
|
}
|
|
13187
|
-
) :
|
|
13490
|
+
) : loading2 ? null : (
|
|
13491
|
+
// 첫 페이지를 받는 중에는 "없다"고 단정하지 않는다 — 아래 로딩 표시가 대신 나온다.
|
|
13492
|
+
/* @__PURE__ */ jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
|
|
13493
|
+
),
|
|
13494
|
+
loading2 && /* @__PURE__ */ jsx(
|
|
13495
|
+
"div",
|
|
13496
|
+
{
|
|
13497
|
+
role: "status",
|
|
13498
|
+
className: "px-[12px] py-[12px] text-center text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-disabled)]",
|
|
13499
|
+
children: "\uBD88\uB7EC\uC624\uB294 \uC911..."
|
|
13500
|
+
}
|
|
13501
|
+
)
|
|
13188
13502
|
]
|
|
13189
13503
|
}
|
|
13190
13504
|
)
|
|
@@ -13197,6 +13511,10 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
|
|
|
13197
13511
|
var SSelect2 = /* @__PURE__ */ withDisplayName(SSelectImpl, "SSelect");
|
|
13198
13512
|
function ItemList({
|
|
13199
13513
|
items,
|
|
13514
|
+
indexOffset,
|
|
13515
|
+
topSpacer,
|
|
13516
|
+
bottomSpacer,
|
|
13517
|
+
setSize,
|
|
13200
13518
|
multi,
|
|
13201
13519
|
selected,
|
|
13202
13520
|
groupLeafValues,
|
|
@@ -13221,6 +13539,7 @@ function ItemList({
|
|
|
13221
13539
|
"button",
|
|
13222
13540
|
{
|
|
13223
13541
|
type: "button",
|
|
13542
|
+
"data-select-all-row": true,
|
|
13224
13543
|
"data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
|
|
13225
13544
|
"data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
|
|
13226
13545
|
className: cn(
|
|
@@ -13237,7 +13556,9 @@ function ItemList({
|
|
|
13237
13556
|
]
|
|
13238
13557
|
}
|
|
13239
13558
|
),
|
|
13240
|
-
|
|
13559
|
+
topSpacer > 0 && /* @__PURE__ */ jsx("div", { "aria-hidden": true, style: { height: topSpacer } }),
|
|
13560
|
+
items.map((o, windowIndex) => {
|
|
13561
|
+
const idx = windowIndex + indexOffset;
|
|
13241
13562
|
const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
|
|
13242
13563
|
const rowKey = `${o.value}-${idx}`;
|
|
13243
13564
|
if (o.isGroup) {
|
|
@@ -13254,6 +13575,8 @@ function ItemList({
|
|
|
13254
13575
|
"button",
|
|
13255
13576
|
{
|
|
13256
13577
|
type: "button",
|
|
13578
|
+
"data-select-row": true,
|
|
13579
|
+
"data-index": idx,
|
|
13257
13580
|
role: "option",
|
|
13258
13581
|
"aria-selected": groupState === true,
|
|
13259
13582
|
disabled: groupDisabled,
|
|
@@ -13304,6 +13627,8 @@ function ItemList({
|
|
|
13304
13627
|
return /* @__PURE__ */ jsx(
|
|
13305
13628
|
"div",
|
|
13306
13629
|
{
|
|
13630
|
+
"data-select-row": true,
|
|
13631
|
+
"data-index": idx,
|
|
13307
13632
|
className: cn(
|
|
13308
13633
|
"select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listBoxItem-content-default)]",
|
|
13309
13634
|
groupTone,
|
|
@@ -13323,9 +13648,13 @@ function ItemList({
|
|
|
13323
13648
|
"button",
|
|
13324
13649
|
{
|
|
13325
13650
|
type: "button",
|
|
13651
|
+
"data-select-row": true,
|
|
13652
|
+
"data-index": idx,
|
|
13326
13653
|
disabled: o.disabled,
|
|
13327
13654
|
role: "option",
|
|
13328
13655
|
"aria-selected": isSelected,
|
|
13656
|
+
"aria-setsize": setSize,
|
|
13657
|
+
"aria-posinset": setSize != null ? idx + 1 : void 0,
|
|
13329
13658
|
"data-select-focused": focusedValue === o.value ? "true" : void 0,
|
|
13330
13659
|
"data-select-active": focusedValue === o.value ? "true" : void 0,
|
|
13331
13660
|
className: cn(
|
|
@@ -13360,7 +13689,8 @@ function ItemList({
|
|
|
13360
13689
|
},
|
|
13361
13690
|
rowKey
|
|
13362
13691
|
);
|
|
13363
|
-
})
|
|
13692
|
+
}),
|
|
13693
|
+
bottomSpacer > 0 && /* @__PURE__ */ jsx("div", { "aria-hidden": true, style: { height: bottomSpacer } })
|
|
13364
13694
|
] });
|
|
13365
13695
|
}
|
|
13366
13696
|
function CheckboxBox({
|
|
@@ -14521,12 +14851,29 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
|
|
|
14521
14851
|
}
|
|
14522
14852
|
);
|
|
14523
14853
|
});
|
|
14524
|
-
var
|
|
14854
|
+
var TEXTAREA_SIZE = {
|
|
14855
|
+
sm: {
|
|
14856
|
+
fontSize: 12,
|
|
14857
|
+
lineHeight: 20,
|
|
14858
|
+
paddingX: "var(--cmp-textinput-sm-paddingX)",
|
|
14859
|
+
paddingY: "var(--cmp-textinput-sm-paddingY)"
|
|
14860
|
+
},
|
|
14861
|
+
md: {
|
|
14862
|
+
fontSize: 14,
|
|
14863
|
+
lineHeight: 24,
|
|
14864
|
+
paddingX: "var(--cmp-textinput-md-paddingX)",
|
|
14865
|
+
paddingY: "var(--cmp-textinput-md-paddingY)"
|
|
14866
|
+
}
|
|
14867
|
+
};
|
|
14868
|
+
var MIN_ROWS = 2;
|
|
14525
14869
|
var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
14526
14870
|
value,
|
|
14527
14871
|
onValueChange,
|
|
14528
14872
|
onChange,
|
|
14529
|
-
|
|
14873
|
+
size = "sm",
|
|
14874
|
+
rows = MIN_ROWS,
|
|
14875
|
+
autogrow = false,
|
|
14876
|
+
maxRows,
|
|
14530
14877
|
rules,
|
|
14531
14878
|
status,
|
|
14532
14879
|
focused,
|
|
@@ -14553,8 +14900,30 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
|
14553
14900
|
style,
|
|
14554
14901
|
...rest
|
|
14555
14902
|
}, ref) {
|
|
14556
|
-
const p =
|
|
14903
|
+
const p = TEXTAREA_SIZE[size];
|
|
14904
|
+
const heightForRows = (n) => `calc(${p.lineHeight * n}px + ${p.paddingY} * 2)`;
|
|
14905
|
+
const minHeight = heightForRows(MIN_ROWS);
|
|
14906
|
+
const maxHeight = autogrow && maxRows != null ? heightForRows(maxRows) : void 0;
|
|
14557
14907
|
const [ruleError, setRuleError] = useState("");
|
|
14908
|
+
const innerRef = useRef(null);
|
|
14909
|
+
const setRefs2 = useCallback(
|
|
14910
|
+
(node) => {
|
|
14911
|
+
innerRef.current = node;
|
|
14912
|
+
if (typeof ref === "function") ref(node);
|
|
14913
|
+
else if (ref) ref.current = node;
|
|
14914
|
+
},
|
|
14915
|
+
[ref]
|
|
14916
|
+
);
|
|
14917
|
+
useLayoutEffect(() => {
|
|
14918
|
+
const el = innerRef.current;
|
|
14919
|
+
if (el == null) return;
|
|
14920
|
+
if (!autogrow) {
|
|
14921
|
+
el.style.height = "";
|
|
14922
|
+
return;
|
|
14923
|
+
}
|
|
14924
|
+
el.style.height = "auto";
|
|
14925
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
14926
|
+
}, [autogrow, maxHeight, minHeight, rows, value]);
|
|
14558
14927
|
useFormField({
|
|
14559
14928
|
name: rest.name,
|
|
14560
14929
|
validate: () => {
|
|
@@ -14579,6 +14948,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
|
14579
14948
|
addonLabel,
|
|
14580
14949
|
addonAlign,
|
|
14581
14950
|
hint,
|
|
14951
|
+
size,
|
|
14582
14952
|
error: resolvedError,
|
|
14583
14953
|
status: resolvedStatus,
|
|
14584
14954
|
focused,
|
|
@@ -14593,7 +14963,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
|
14593
14963
|
children: /* @__PURE__ */ jsx(
|
|
14594
14964
|
"textarea",
|
|
14595
14965
|
{
|
|
14596
|
-
ref,
|
|
14966
|
+
ref: setRefs2,
|
|
14597
14967
|
value: value ?? "",
|
|
14598
14968
|
rows,
|
|
14599
14969
|
disabled,
|
|
@@ -14609,15 +14979,21 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
|
14609
14979
|
if (rules && rules.length > 0) setRuleError(runRules(e.target.value, rules));
|
|
14610
14980
|
},
|
|
14611
14981
|
className: cn(
|
|
14612
|
-
"w-full
|
|
14982
|
+
"w-full border-0 bg-transparent outline-none placeholder:text-[color:var(--sys-color-field-text-placeholder)] disabled:cursor-not-allowed",
|
|
14983
|
+
// autogrow 와 끌어서 늘리기는 같은 높이를 두고 다투므로 함께 두지 않는다
|
|
14984
|
+
autogrow ? "resize-none" : "resize-y",
|
|
14613
14985
|
AUTOFILL_RESET_CLASS,
|
|
14614
14986
|
textareaClassName
|
|
14615
14987
|
),
|
|
14616
14988
|
style: {
|
|
14617
|
-
minHeight
|
|
14618
|
-
|
|
14989
|
+
minHeight,
|
|
14990
|
+
maxHeight,
|
|
14991
|
+
// 상한이 있으면 거기 닿았을 때 안에서 스크롤한다. 상한이 없으면 높이가 늘 내용과
|
|
14992
|
+
// 같으므로 스크롤바가 나올 일이 없고, 반올림으로 1px 이 넘쳐 깜빡이는 것만 막는다.
|
|
14993
|
+
overflowY: autogrow ? maxRows != null ? "auto" : "hidden" : void 0,
|
|
14994
|
+
padding: `${p.paddingY} ${p.paddingX}`,
|
|
14619
14995
|
fontSize: p.fontSize,
|
|
14620
|
-
lineHeight:
|
|
14996
|
+
lineHeight: `${p.lineHeight}px`,
|
|
14621
14997
|
color: disabled ? "var(--cmp-textinput-text-disabled)" : "var(--sys-color-field-text-default)",
|
|
14622
14998
|
...textareaStyle
|
|
14623
14999
|
},
|
|
@@ -14627,7 +15003,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
|
|
|
14627
15003
|
}
|
|
14628
15004
|
);
|
|
14629
15005
|
});
|
|
14630
|
-
var
|
|
15006
|
+
var PAD2 = {
|
|
14631
15007
|
sm: { fontSize: 12, lineHeight: 20, stepper: 20, icon: 12 },
|
|
14632
15008
|
md: { fontSize: 14, lineHeight: 24, stepper: 24, icon: 14 }
|
|
14633
15009
|
};
|
|
@@ -14656,6 +15032,16 @@ var formatInputWithCommas = (value) => {
|
|
|
14656
15032
|
const formattedInt = addCommas(intPart === "" ? "0" : intPart);
|
|
14657
15033
|
return `${isNeg ? "-" : ""}${formattedInt}${hasDecimal ? `.${decPart}` : ""}`;
|
|
14658
15034
|
};
|
|
15035
|
+
var getRangeError = (value, min, max) => {
|
|
15036
|
+
if (value === null) return "";
|
|
15037
|
+
const belowMin = value < min;
|
|
15038
|
+
const aboveMax = value > max;
|
|
15039
|
+
if (!belowMin && !aboveMax) return "";
|
|
15040
|
+
if (Number.isFinite(min) && Number.isFinite(max)) {
|
|
15041
|
+
return `${formatWithCommas(min)}~${formatWithCommas(max)} \uC0AC\uC774\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.`;
|
|
15042
|
+
}
|
|
15043
|
+
return belowMin ? `${formatWithCommas(min)} \uC774\uC0C1\uC73C\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.` : `${formatWithCommas(max)} \uC774\uD558\uB85C \uC785\uB825\uD574 \uC8FC\uC138\uC694.`;
|
|
15044
|
+
};
|
|
14659
15045
|
var getDecimalLimit = (allowDecimal, maxDecimalLength) => {
|
|
14660
15046
|
if (!allowDecimal || maxDecimalLength === void 0 || !Number.isFinite(maxDecimalLength)) {
|
|
14661
15047
|
return void 0;
|
|
@@ -14686,6 +15072,7 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
|
|
|
14686
15072
|
min = Number.NEGATIVE_INFINITY,
|
|
14687
15073
|
max = Number.POSITIVE_INFINITY,
|
|
14688
15074
|
step = 1,
|
|
15075
|
+
clampOnBlur = false,
|
|
14689
15076
|
showButton = false,
|
|
14690
15077
|
allowDecimal = false,
|
|
14691
15078
|
maxDecimalLength,
|
|
@@ -14719,12 +15106,13 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
|
|
|
14719
15106
|
className,
|
|
14720
15107
|
style
|
|
14721
15108
|
}, ref) {
|
|
14722
|
-
const p =
|
|
15109
|
+
const p = PAD2[size];
|
|
14723
15110
|
const padX = `var(--cmp-numberInput-${size}-paddingX)`;
|
|
14724
15111
|
const decimalLimit = getDecimalLimit(allowDecimal, maxDecimalLength);
|
|
14725
15112
|
const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
|
|
14726
15113
|
const [display, setDisplay] = useState(() => formatWithCommas(numValue));
|
|
14727
15114
|
const [ruleError, setRuleError] = useState("");
|
|
15115
|
+
const [rangeError, setRangeError] = useState("");
|
|
14728
15116
|
const innerRef = useRef(null);
|
|
14729
15117
|
const valueTooltip = useTruncatedValueTooltip({ enabled: readOnly && !disabled, text: display });
|
|
14730
15118
|
const setRefs2 = (el) => {
|
|
@@ -14742,12 +15130,19 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
|
|
|
14742
15130
|
validate: () => {
|
|
14743
15131
|
const msg = runRules(numValue, rules);
|
|
14744
15132
|
setRuleError(msg);
|
|
14745
|
-
|
|
15133
|
+
const range = clampOnBlur ? "" : getRangeError(numValue, min, max);
|
|
15134
|
+
setRangeError(range);
|
|
15135
|
+
return msg === "" && range === "";
|
|
14746
15136
|
},
|
|
14747
|
-
resetValidation: () =>
|
|
15137
|
+
resetValidation: () => {
|
|
15138
|
+
setRuleError("");
|
|
15139
|
+
setRangeError("");
|
|
15140
|
+
}
|
|
14748
15141
|
});
|
|
14749
|
-
const
|
|
14750
|
-
const
|
|
15142
|
+
const autoError = ruleError !== "" ? ruleError : rangeError;
|
|
15143
|
+
const resolvedError = error || autoError !== "";
|
|
15144
|
+
const resolvedStatus = status ?? (autoError !== "" ? "error" : void 0);
|
|
15145
|
+
const resolvedErrorMessage = ruleError !== "" ? ruleError : (errorMessage ?? "") !== "" ? errorMessage : rangeError;
|
|
14751
15146
|
const restoreCaret = (nextDisplay, logicalCaret) => {
|
|
14752
15147
|
const input = innerRef.current;
|
|
14753
15148
|
if (logicalCaret === void 0 || !input || document.activeElement !== input) return;
|
|
@@ -14879,7 +15274,7 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
|
|
|
14879
15274
|
status: resolvedStatus,
|
|
14880
15275
|
focused,
|
|
14881
15276
|
hovered,
|
|
14882
|
-
errorMessage:
|
|
15277
|
+
errorMessage: resolvedErrorMessage,
|
|
14883
15278
|
width,
|
|
14884
15279
|
disabled,
|
|
14885
15280
|
readOnly,
|
|
@@ -14925,10 +15320,11 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
|
|
|
14925
15320
|
onBlur: (e) => {
|
|
14926
15321
|
const cleaned = display.replace(/,/g, "");
|
|
14927
15322
|
const n = toNumber(cleaned);
|
|
14928
|
-
const clamped = n === null ?
|
|
15323
|
+
const clamped = !clampOnBlur || n === null ? n : Math.min(Math.max(n, min), max);
|
|
14929
15324
|
if (clamped !== n) emit3(clamped);
|
|
14930
15325
|
else setDisplay(n === null ? "" : formatInputWithCommas(cleaned));
|
|
14931
15326
|
if (rules && rules.length > 0) setRuleError(runRules(clamped, rules));
|
|
15327
|
+
setRangeError(clampOnBlur ? "" : getRangeError(clamped, min, max));
|
|
14932
15328
|
onBlur?.(e);
|
|
14933
15329
|
},
|
|
14934
15330
|
className: cn(
|