sellmate-design-system-react 0.1.9 → 0.1.11
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/components/SActionModal/SActionModal.cjs +3 -1
- package/dist/components/SActionModal/SActionModal.cjs.map +1 -1
- package/dist/components/SActionModal/SActionModal.js +3 -1
- package/dist/components/SActionModal/SActionModal.js.map +1 -1
- package/dist/components/SBarcodeInput/SBarcodeInput.cjs +16 -3
- package/dist/components/SBarcodeInput/SBarcodeInput.cjs.map +1 -1
- package/dist/components/SBarcodeInput/SBarcodeInput.d.ts +3 -1
- package/dist/components/SBarcodeInput/SBarcodeInput.js +16 -3
- package/dist/components/SBarcodeInput/SBarcodeInput.js.map +1 -1
- package/dist/components/SCalendar/SCalendar.cjs +2 -0
- package/dist/components/SCalendar/SCalendar.cjs.map +1 -1
- package/dist/components/SCalendar/SCalendar.js +2 -0
- package/dist/components/SCalendar/SCalendar.js.map +1 -1
- package/dist/components/SChip/SChip.cjs +2 -0
- package/dist/components/SChip/SChip.cjs.map +1 -1
- package/dist/components/SChip/SChip.js +2 -0
- package/dist/components/SChip/SChip.js.map +1 -1
- package/dist/components/SChipInput/SChipInput.cjs +22 -4
- package/dist/components/SChipInput/SChipInput.cjs.map +1 -1
- package/dist/components/SChipInput/SChipInput.d.ts +5 -0
- package/dist/components/SChipInput/SChipInput.js +22 -4
- package/dist/components/SChipInput/SChipInput.js.map +1 -1
- package/dist/components/SChipInput/index.d.ts +1 -1
- package/dist/components/SCircleProgress/SCircleProgress.cjs +69 -50
- package/dist/components/SCircleProgress/SCircleProgress.cjs.map +1 -1
- package/dist/components/SCircleProgress/SCircleProgress.d.ts +2 -0
- package/dist/components/SCircleProgress/SCircleProgress.js +69 -50
- package/dist/components/SCircleProgress/SCircleProgress.js.map +1 -1
- package/dist/components/SConfirmModal/SConfirmModal.cjs +13 -10
- package/dist/components/SConfirmModal/SConfirmModal.cjs.map +1 -1
- package/dist/components/SConfirmModal/SConfirmModal.d.ts +7 -4
- package/dist/components/SConfirmModal/SConfirmModal.js +13 -10
- package/dist/components/SConfirmModal/SConfirmModal.js.map +1 -1
- package/dist/components/SDatePicker/SDatePicker.cjs +16 -3
- package/dist/components/SDatePicker/SDatePicker.cjs.map +1 -1
- package/dist/components/SDatePicker/SDatePicker.d.ts +3 -1
- package/dist/components/SDatePicker/SDatePicker.js +16 -3
- package/dist/components/SDatePicker/SDatePicker.js.map +1 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs +16 -3
- package/dist/components/SDateRangePicker/SDateRangePicker.cjs.map +1 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.d.ts +3 -1
- package/dist/components/SDateRangePicker/SDateRangePicker.js +16 -3
- package/dist/components/SDateRangePicker/SDateRangePicker.js.map +1 -1
- package/dist/components/SDropdownButton/SDropdownButton.cjs +2 -0
- package/dist/components/SDropdownButton/SDropdownButton.cjs.map +1 -1
- package/dist/components/SDropdownButton/SDropdownButton.js +2 -0
- package/dist/components/SDropdownButton/SDropdownButton.js.map +1 -1
- package/dist/components/SField/SField.cjs +14 -3
- package/dist/components/SField/SField.cjs.map +1 -1
- package/dist/components/SField/SField.d.ts +4 -1
- package/dist/components/SField/SField.js +14 -3
- package/dist/components/SField/SField.js.map +1 -1
- package/dist/components/SFilePicker/SFilePicker.cjs +51 -19
- package/dist/components/SFilePicker/SFilePicker.cjs.map +1 -1
- package/dist/components/SFilePicker/SFilePicker.d.ts +4 -2
- package/dist/components/SFilePicker/SFilePicker.js +50 -19
- package/dist/components/SFilePicker/SFilePicker.js.map +1 -1
- package/dist/components/SGhostButton/SGhostButton.cjs +2 -0
- package/dist/components/SGhostButton/SGhostButton.cjs.map +1 -1
- package/dist/components/SGhostButton/SGhostButton.js +2 -0
- package/dist/components/SGhostButton/SGhostButton.js.map +1 -1
- package/dist/components/SGuide/SGuide.cjs +2 -0
- package/dist/components/SGuide/SGuide.cjs.map +1 -1
- package/dist/components/SGuide/SGuide.js +2 -0
- package/dist/components/SGuide/SGuide.js.map +1 -1
- package/dist/components/SInput/SInput.cjs +16 -3
- package/dist/components/SInput/SInput.cjs.map +1 -1
- package/dist/components/SInput/SInput.d.ts +4 -1
- package/dist/components/SInput/SInput.js +16 -3
- package/dist/components/SInput/SInput.js.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs +530 -219
- package/dist/components/SKeyValueTable/SKeyValueTable.cjs.map +1 -1
- package/dist/components/SKeyValueTable/SKeyValueTable.d.ts +27 -6
- package/dist/components/SKeyValueTable/SKeyValueTable.js +529 -218
- package/dist/components/SKeyValueTable/SKeyValueTable.js.map +1 -1
- package/dist/components/SLoadingContainer/SLoadingContainer.cjs +69 -50
- package/dist/components/SLoadingContainer/SLoadingContainer.cjs.map +1 -1
- package/dist/components/SLoadingContainer/SLoadingContainer.js +69 -50
- package/dist/components/SLoadingContainer/SLoadingContainer.js.map +1 -1
- package/dist/components/SLoadingContainer/loading.cjs +69 -50
- package/dist/components/SLoadingContainer/loading.cjs.map +1 -1
- package/dist/components/SLoadingContainer/loading.js +69 -50
- package/dist/components/SLoadingContainer/loading.js.map +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.cjs +75 -51
- package/dist/components/SLoadingModal/SLoadingModal.cjs.map +1 -1
- package/dist/components/SLoadingModal/SLoadingModal.d.ts +3 -1
- package/dist/components/SLoadingModal/SLoadingModal.js +75 -51
- package/dist/components/SLoadingModal/SLoadingModal.js.map +1 -1
- package/dist/components/SModalContainer/SModalContainer.cjs +3 -1
- package/dist/components/SModalContainer/SModalContainer.cjs.map +1 -1
- package/dist/components/SModalContainer/SModalContainer.js +3 -1
- package/dist/components/SModalContainer/SModalContainer.js.map +1 -1
- package/dist/components/SNumberInput/SNumberInput.cjs +16 -3
- package/dist/components/SNumberInput/SNumberInput.cjs.map +1 -1
- package/dist/components/SNumberInput/SNumberInput.d.ts +2 -0
- package/dist/components/SNumberInput/SNumberInput.js +16 -3
- package/dist/components/SNumberInput/SNumberInput.js.map +1 -1
- package/dist/components/SPopover/SPopover.cjs +2 -0
- package/dist/components/SPopover/SPopover.cjs.map +1 -1
- package/dist/components/SPopover/SPopover.js +2 -0
- package/dist/components/SPopover/SPopover.js.map +1 -1
- package/dist/components/SPortal/SPortal.cjs +2 -0
- package/dist/components/SPortal/SPortal.cjs.map +1 -1
- package/dist/components/SPortal/SPortal.js +2 -0
- package/dist/components/SPortal/SPortal.js.map +1 -1
- package/dist/components/SRadio/SRadioGroup.cjs +1 -1
- package/dist/components/SRadio/SRadioGroup.cjs.map +1 -1
- package/dist/components/SRadio/SRadioGroup.js +1 -1
- package/dist/components/SRadio/SRadioGroup.js.map +1 -1
- package/dist/components/SSelect/SSelect.cjs +530 -258
- package/dist/components/SSelect/SSelect.cjs.map +1 -1
- package/dist/components/SSelect/SSelect.d.ts +4 -2
- package/dist/components/SSelect/SSelect.js +531 -258
- package/dist/components/SSelect/SSelect.js.map +1 -1
- package/dist/components/STable/STable.cjs +603 -309
- package/dist/components/STable/STable.cjs.map +1 -1
- package/dist/components/STable/STable.js +604 -309
- package/dist/components/STable/STable.js.map +1 -1
- package/dist/components/STextLink/STextLink.cjs +2 -0
- package/dist/components/STextLink/STextLink.cjs.map +1 -1
- package/dist/components/STextLink/STextLink.js +2 -0
- package/dist/components/STextLink/STextLink.js.map +1 -1
- package/dist/components/STextarea/STextarea.cjs +16 -3
- package/dist/components/STextarea/STextarea.cjs.map +1 -1
- package/dist/components/STextarea/STextarea.d.ts +2 -0
- package/dist/components/STextarea/STextarea.js +16 -3
- package/dist/components/STextarea/STextarea.js.map +1 -1
- package/dist/components/SToast/SToast.cjs +2 -0
- package/dist/components/SToast/SToast.cjs.map +1 -1
- package/dist/components/SToast/SToast.js +2 -0
- package/dist/components/SToast/SToast.js.map +1 -1
- package/dist/components/SToast/SToastContainer.cjs +2 -0
- package/dist/components/SToast/SToastContainer.cjs.map +1 -1
- package/dist/components/SToast/SToastContainer.js +2 -0
- package/dist/components/SToast/SToastContainer.js.map +1 -1
- package/dist/components/STooltip/STooltip.cjs +3 -1
- package/dist/components/STooltip/STooltip.cjs.map +1 -1
- package/dist/components/STooltip/STooltip.js +3 -1
- package/dist/components/STooltip/STooltip.js.map +1 -1
- package/dist/index.cjs +522 -248
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +523 -248
- package/dist/index.js.map +1 -1
- package/dist/lib/portal-container.d.ts +7 -0
- package/dist/styles.css +123 -58
- package/dist/theme.css +45 -21
- package/package.json +1 -1
|
@@ -6,7 +6,6 @@ var clsx = require('clsx');
|
|
|
6
6
|
var tailwindMerge = require('tailwind-merge');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
8
8
|
var RCheckbox = require('@radix-ui/react-checkbox');
|
|
9
|
-
var Ariakit = require('@ariakit/react');
|
|
10
9
|
var RPopover2 = require('@radix-ui/react-popover');
|
|
11
10
|
|
|
12
11
|
function _interopNamespace(e) {
|
|
@@ -28,7 +27,6 @@ function _interopNamespace(e) {
|
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
var RCheckbox__namespace = /*#__PURE__*/_interopNamespace(RCheckbox);
|
|
31
|
-
var Ariakit__namespace = /*#__PURE__*/_interopNamespace(Ariakit);
|
|
32
30
|
var RPopover2__namespace = /*#__PURE__*/_interopNamespace(RPopover2);
|
|
33
31
|
|
|
34
32
|
var twMerge = tailwindMerge.extendTailwindMerge({
|
|
@@ -2959,12 +2957,35 @@ var COLOR_MAP = {
|
|
|
2959
2957
|
};
|
|
2960
2958
|
var clamp = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
|
|
2961
2959
|
var SCircleProgress = react.forwardRef(
|
|
2962
|
-
function SCircleProgress2({
|
|
2960
|
+
function SCircleProgress2({
|
|
2961
|
+
value = 0,
|
|
2962
|
+
type = "primary",
|
|
2963
|
+
indeterminate = false,
|
|
2964
|
+
label,
|
|
2965
|
+
innerValue = false,
|
|
2966
|
+
className,
|
|
2967
|
+
style
|
|
2968
|
+
}, ref) {
|
|
2963
2969
|
const v = clamp(value);
|
|
2964
2970
|
const colors = COLOR_MAP[type];
|
|
2965
2971
|
const c = VIEWBOX / 2;
|
|
2966
2972
|
const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
|
|
2967
2973
|
const filled = v / 100 * CIRCUMFERENCE;
|
|
2974
|
+
const showPercent = !indeterminate;
|
|
2975
|
+
const percentNode = /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2976
|
+
"span",
|
|
2977
|
+
{
|
|
2978
|
+
className: cn(
|
|
2979
|
+
"text-center text-[16px] font-bold leading-[26px]",
|
|
2980
|
+
innerValue && "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
|
|
2981
|
+
),
|
|
2982
|
+
style: { color: percentColor },
|
|
2983
|
+
children: [
|
|
2984
|
+
Math.round(v),
|
|
2985
|
+
"%"
|
|
2986
|
+
]
|
|
2987
|
+
}
|
|
2988
|
+
);
|
|
2968
2989
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2969
2990
|
"div",
|
|
2970
2991
|
{
|
|
@@ -2975,57 +2996,53 @@ var SCircleProgress = react.forwardRef(
|
|
|
2975
2996
|
),
|
|
2976
2997
|
style,
|
|
2977
2998
|
children: [
|
|
2978
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
"circle"
|
|
2987
|
-
{
|
|
2988
|
-
cx: c,
|
|
2989
|
-
cy: c,
|
|
2990
|
-
r: RADIUS,
|
|
2991
|
-
fill: "none",
|
|
2992
|
-
strokeWidth: STROKE,
|
|
2993
|
-
style: { stroke: colors.track }
|
|
2994
|
-
}
|
|
2999
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn(innerValue && "relative"), children: [
|
|
3000
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3001
|
+
"svg",
|
|
3002
|
+
{
|
|
3003
|
+
viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
|
|
3004
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3005
|
+
className: cn(
|
|
3006
|
+
"h-[80px] w-[80px]",
|
|
3007
|
+
indeterminate && "origin-center animate-circle-spin"
|
|
2995
3008
|
),
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
"origin-center",
|
|
3007
|
-
indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
|
|
3008
|
-
),
|
|
3009
|
-
style: {
|
|
3010
|
-
stroke: colors.arc,
|
|
3011
|
-
...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
|
|
3009
|
+
children: [
|
|
3010
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3011
|
+
"circle",
|
|
3012
|
+
{
|
|
3013
|
+
cx: c,
|
|
3014
|
+
cy: c,
|
|
3015
|
+
r: RADIUS,
|
|
3016
|
+
fill: "none",
|
|
3017
|
+
strokeWidth: STROKE,
|
|
3018
|
+
style: { stroke: colors.track }
|
|
3012
3019
|
}
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3020
|
+
),
|
|
3021
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3022
|
+
"circle",
|
|
3023
|
+
{
|
|
3024
|
+
cx: c,
|
|
3025
|
+
cy: c,
|
|
3026
|
+
r: RADIUS,
|
|
3027
|
+
fill: "none",
|
|
3028
|
+
strokeWidth: STROKE,
|
|
3029
|
+
strokeLinecap: "round",
|
|
3030
|
+
className: cn(
|
|
3031
|
+
"origin-center",
|
|
3032
|
+
indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
|
|
3033
|
+
),
|
|
3034
|
+
style: {
|
|
3035
|
+
stroke: colors.arc,
|
|
3036
|
+
...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
)
|
|
3040
|
+
]
|
|
3041
|
+
}
|
|
3042
|
+
),
|
|
3043
|
+
showPercent && innerValue && percentNode
|
|
3044
|
+
] }),
|
|
3045
|
+
showPercent && !innerValue && percentNode,
|
|
3029
3046
|
label && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
|
|
3030
3047
|
]
|
|
3031
3048
|
}
|
|
@@ -3116,10 +3133,110 @@ function SPagination({
|
|
|
3116
3133
|
);
|
|
3117
3134
|
}
|
|
3118
3135
|
var PortalContainerContext = react.createContext(null);
|
|
3136
|
+
var InsideModalContext = react.createContext(false);
|
|
3119
3137
|
PortalContainerContext.Provider;
|
|
3138
|
+
InsideModalContext.Provider;
|
|
3120
3139
|
function usePortalContainer() {
|
|
3121
3140
|
return react.useContext(PortalContainerContext) ?? void 0;
|
|
3122
3141
|
}
|
|
3142
|
+
function useInsideModal() {
|
|
3143
|
+
return react.useContext(InsideModalContext);
|
|
3144
|
+
}
|
|
3145
|
+
function runRules(value, rules) {
|
|
3146
|
+
if (!rules || rules.length === 0) return "";
|
|
3147
|
+
for (const rule of rules) {
|
|
3148
|
+
const result = rule(value ?? "");
|
|
3149
|
+
if (result !== true) return typeof result === "string" ? result : "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC12\uC785\uB2C8\uB2E4.";
|
|
3150
|
+
}
|
|
3151
|
+
return "";
|
|
3152
|
+
}
|
|
3153
|
+
var FormContext = react.createContext(null);
|
|
3154
|
+
function useFormContext() {
|
|
3155
|
+
return react.useContext(FormContext);
|
|
3156
|
+
}
|
|
3157
|
+
function useFormField(field) {
|
|
3158
|
+
const ctx = useFormContext();
|
|
3159
|
+
const cbRef = react.useRef(field);
|
|
3160
|
+
cbRef.current = field;
|
|
3161
|
+
const name = field.name ?? "";
|
|
3162
|
+
react.useEffect(() => {
|
|
3163
|
+
if (!ctx) return;
|
|
3164
|
+
return ctx.register({
|
|
3165
|
+
name,
|
|
3166
|
+
validate: () => cbRef.current.validate(),
|
|
3167
|
+
resetValidation: () => cbRef.current.resetValidation()
|
|
3168
|
+
});
|
|
3169
|
+
}, [ctx, name]);
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
// src/lib/sanitize-inline-html.ts
|
|
3173
|
+
var ALLOWED_INLINE_TAGS = /* @__PURE__ */ new Set(["A", "B", "STRONG", "I", "EM", "BR", "SPAN"]);
|
|
3174
|
+
var ALLOWED_ATTRS_BY_TAG = {
|
|
3175
|
+
A: /* @__PURE__ */ new Set(["href", "target", "rel", "class"])
|
|
3176
|
+
};
|
|
3177
|
+
var COMMON_ALLOWED_ATTRS = /* @__PURE__ */ new Set(["class"]);
|
|
3178
|
+
var SAFE_HREF_RE = /^(https?:|mailto:|tel:|\/|#|\.)/i;
|
|
3179
|
+
var DROP_CONTENT_TAGS = /* @__PURE__ */ new Set([
|
|
3180
|
+
"SCRIPT",
|
|
3181
|
+
"STYLE",
|
|
3182
|
+
"IFRAME",
|
|
3183
|
+
"OBJECT",
|
|
3184
|
+
"EMBED",
|
|
3185
|
+
"META",
|
|
3186
|
+
"LINK",
|
|
3187
|
+
"BASE",
|
|
3188
|
+
"NOSCRIPT",
|
|
3189
|
+
// SVG/MATH 는 foreign-content 파싱 모드로 전환되어 재직렬화 시 다른 트리로
|
|
3190
|
+
// 재파싱될 수 있다(mXSS 벡터). 인라인 라벨에 필요 없으므로 통째로 제거한다.
|
|
3191
|
+
"SVG",
|
|
3192
|
+
"MATH",
|
|
3193
|
+
"TEMPLATE"
|
|
3194
|
+
]);
|
|
3195
|
+
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3196
|
+
var sanitizeNode = (node) => {
|
|
3197
|
+
if (node.nodeType === Node.COMMENT_NODE) {
|
|
3198
|
+
node.remove();
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
3202
|
+
const element = node;
|
|
3203
|
+
const tagName = element.tagName;
|
|
3204
|
+
if (DROP_CONTENT_TAGS.has(tagName)) {
|
|
3205
|
+
element.remove();
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3208
|
+
Array.from(element.childNodes).forEach((child) => sanitizeNode(child));
|
|
3209
|
+
if (ALLOWED_INLINE_TAGS.has(tagName)) {
|
|
3210
|
+
if (element.hasAttribute("className")) {
|
|
3211
|
+
const val = element.getAttribute("className");
|
|
3212
|
+
element.removeAttribute("className");
|
|
3213
|
+
if (!element.hasAttribute("class")) element.setAttribute("class", val);
|
|
3214
|
+
}
|
|
3215
|
+
const allowedAttrs = ALLOWED_ATTRS_BY_TAG[tagName] ?? COMMON_ALLOWED_ATTRS;
|
|
3216
|
+
Array.from(element.attributes).forEach((attr) => {
|
|
3217
|
+
if (!allowedAttrs.has(attr.name)) element.removeAttribute(attr.name);
|
|
3218
|
+
});
|
|
3219
|
+
if (tagName === "A") {
|
|
3220
|
+
const href = element.getAttribute("href");
|
|
3221
|
+
if (href !== null && href !== "" && !SAFE_HREF_RE.test(href)) element.removeAttribute("href");
|
|
3222
|
+
if (element.hasAttribute("target")) {
|
|
3223
|
+
element.setAttribute("rel", "noopener noreferrer");
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
return;
|
|
3227
|
+
}
|
|
3228
|
+
const parent = element.parentNode;
|
|
3229
|
+
if (parent == null) return;
|
|
3230
|
+
while (element.firstChild) parent.insertBefore(element.firstChild, element);
|
|
3231
|
+
parent.removeChild(element);
|
|
3232
|
+
};
|
|
3233
|
+
var sanitizeInlineHtml = (value) => {
|
|
3234
|
+
if (typeof document === "undefined") return escapeHtml(value);
|
|
3235
|
+
const template = document.createElement("template");
|
|
3236
|
+
template.innerHTML = value;
|
|
3237
|
+
Array.from(template.content.childNodes).forEach((child) => sanitizeNode(child));
|
|
3238
|
+
return template.innerHTML;
|
|
3239
|
+
};
|
|
3123
3240
|
|
|
3124
3241
|
// src/lib/floating-anim.ts
|
|
3125
3242
|
var FLOATING_SLIDE_ANIM = [
|
|
@@ -3391,7 +3508,7 @@ var STooltip = react.forwardRef(function STooltip2({
|
|
|
3391
3508
|
if (disabled || body == null) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: triggerNode });
|
|
3392
3509
|
const isHover = trigger === "hover";
|
|
3393
3510
|
const contentClass = cn(
|
|
3394
|
-
"z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]
|
|
3511
|
+
"z-50 max-w-xs rounded-[6px] px-[16px] py-[12px] text-[12px] leading-[20px]",
|
|
3395
3512
|
FLOATING_SLIDE_ANIM,
|
|
3396
3513
|
className
|
|
3397
3514
|
);
|
|
@@ -3457,32 +3574,6 @@ var STooltip = react.forwardRef(function STooltip2({
|
|
|
3457
3574
|
] });
|
|
3458
3575
|
});
|
|
3459
3576
|
STooltip.displayName = "STooltip";
|
|
3460
|
-
function runRules(value, rules) {
|
|
3461
|
-
if (!rules || rules.length === 0) return "";
|
|
3462
|
-
for (const rule of rules) {
|
|
3463
|
-
const result = rule(value ?? "");
|
|
3464
|
-
if (result !== true) return typeof result === "string" ? result : "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uAC12\uC785\uB2C8\uB2E4.";
|
|
3465
|
-
}
|
|
3466
|
-
return "";
|
|
3467
|
-
}
|
|
3468
|
-
var FormContext = react.createContext(null);
|
|
3469
|
-
function useFormContext() {
|
|
3470
|
-
return react.useContext(FormContext);
|
|
3471
|
-
}
|
|
3472
|
-
function useFormField(field) {
|
|
3473
|
-
const ctx = useFormContext();
|
|
3474
|
-
const cbRef = react.useRef(field);
|
|
3475
|
-
cbRef.current = field;
|
|
3476
|
-
const name = field.name ?? "";
|
|
3477
|
-
react.useEffect(() => {
|
|
3478
|
-
if (!ctx) return;
|
|
3479
|
-
return ctx.register({
|
|
3480
|
-
name,
|
|
3481
|
-
validate: () => cbRef.current.validate(),
|
|
3482
|
-
resetValidation: () => cbRef.current.resetValidation()
|
|
3483
|
-
});
|
|
3484
|
-
}, [ctx, name]);
|
|
3485
|
-
}
|
|
3486
3577
|
var FIELD_SIZE = {
|
|
3487
3578
|
sm: { height: 28, radius: 4, fieldGap: 12, labelGap: 6, fontSize: 12, lineHeight: 20, icon: 16 },
|
|
3488
3579
|
md: { height: 36, radius: 6, fieldGap: 16, labelGap: 8, fontSize: 14, lineHeight: 24, icon: 16 }
|
|
@@ -3497,6 +3588,7 @@ var SField = react.forwardRef(function SField2({
|
|
|
3497
3588
|
name,
|
|
3498
3589
|
label = "",
|
|
3499
3590
|
icon,
|
|
3591
|
+
iconColor,
|
|
3500
3592
|
labelTooltip = "",
|
|
3501
3593
|
labelTooltipProps,
|
|
3502
3594
|
labelWidth,
|
|
@@ -3574,7 +3666,15 @@ var SField = react.forwardRef(function SField2({
|
|
|
3574
3666
|
lineHeight: `${s.lineHeight}px`
|
|
3575
3667
|
},
|
|
3576
3668
|
children: [
|
|
3577
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3669
|
+
icon && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3670
|
+
SIcon,
|
|
3671
|
+
{
|
|
3672
|
+
name: icon,
|
|
3673
|
+
size: s.icon,
|
|
3674
|
+
color: iconColor,
|
|
3675
|
+
style: { marginRight: s.labelGap }
|
|
3676
|
+
}
|
|
3677
|
+
),
|
|
3578
3678
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
|
|
3579
3679
|
(labelTooltip !== "" || labelTooltipProps) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0", style: { marginLeft: s.labelGap }, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3580
3680
|
STooltip,
|
|
@@ -3624,7 +3724,7 @@ var SField = react.forwardRef(function SField2({
|
|
|
3624
3724
|
borderBottomLeftRadius: s.radius - 1
|
|
3625
3725
|
},
|
|
3626
3726
|
children: [
|
|
3627
|
-
icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon }),
|
|
3727
|
+
icon && !label && /* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: icon, size: s.icon, color: iconColor }),
|
|
3628
3728
|
effectiveAddonLabel
|
|
3629
3729
|
]
|
|
3630
3730
|
}
|
|
@@ -3639,6 +3739,77 @@ var SField = react.forwardRef(function SField2({
|
|
|
3639
3739
|
}
|
|
3640
3740
|
);
|
|
3641
3741
|
});
|
|
3742
|
+
function SPortal({
|
|
3743
|
+
open,
|
|
3744
|
+
onClose,
|
|
3745
|
+
onOpenChange,
|
|
3746
|
+
anchorRef,
|
|
3747
|
+
placement = "bottom",
|
|
3748
|
+
align = "start",
|
|
3749
|
+
offset = 4,
|
|
3750
|
+
alignOffset = 0,
|
|
3751
|
+
fit = false,
|
|
3752
|
+
maxHeight,
|
|
3753
|
+
autoClose = false,
|
|
3754
|
+
persistent = false,
|
|
3755
|
+
viewportPadding = 0,
|
|
3756
|
+
onOpenAutoFocus,
|
|
3757
|
+
onCloseAutoFocus,
|
|
3758
|
+
children,
|
|
3759
|
+
className,
|
|
3760
|
+
style,
|
|
3761
|
+
ariaLabel
|
|
3762
|
+
}) {
|
|
3763
|
+
const portalContainer = usePortalContainer();
|
|
3764
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3765
|
+
RPopover2__namespace.Root,
|
|
3766
|
+
{
|
|
3767
|
+
open,
|
|
3768
|
+
onOpenChange: (next) => {
|
|
3769
|
+
onOpenChange?.(next);
|
|
3770
|
+
if (!next) onClose?.();
|
|
3771
|
+
},
|
|
3772
|
+
children: [
|
|
3773
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Anchor, { virtualRef: anchorRef }),
|
|
3774
|
+
/* @__PURE__ */ jsxRuntime.jsx(RPopover2__namespace.Portal, { container: portalContainer, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3775
|
+
RPopover2__namespace.Content,
|
|
3776
|
+
{
|
|
3777
|
+
side: placement,
|
|
3778
|
+
align,
|
|
3779
|
+
sideOffset: offset,
|
|
3780
|
+
alignOffset,
|
|
3781
|
+
collisionPadding: viewportPadding,
|
|
3782
|
+
"aria-label": ariaLabel,
|
|
3783
|
+
onPointerDownOutside: (e) => {
|
|
3784
|
+
if (persistent || anchorRef.current?.contains(e.target)) {
|
|
3785
|
+
e.preventDefault();
|
|
3786
|
+
}
|
|
3787
|
+
},
|
|
3788
|
+
onFocusOutside: (e) => {
|
|
3789
|
+
if (persistent || anchorRef.current?.contains(e.target)) {
|
|
3790
|
+
e.preventDefault();
|
|
3791
|
+
}
|
|
3792
|
+
},
|
|
3793
|
+
onEscapeKeyDown: persistent ? (e) => e.preventDefault() : void 0,
|
|
3794
|
+
onOpenAutoFocus,
|
|
3795
|
+
onCloseAutoFocus,
|
|
3796
|
+
onClick: autoClose ? () => onClose?.() : void 0,
|
|
3797
|
+
className: cn(
|
|
3798
|
+
"z-50 overflow-hidden rounded-(--cmp-listBox-radius) bg-(--cmp-listBox-bg) py-4 shadow-normal-sm",
|
|
3799
|
+
maxHeight != null && "overflow-y-auto",
|
|
3800
|
+
fit && "min-w-(--radix-popover-trigger-width)",
|
|
3801
|
+
FLOATING_SLIDE_ANIM,
|
|
3802
|
+
className
|
|
3803
|
+
),
|
|
3804
|
+
style: { maxHeight, ...style },
|
|
3805
|
+
children
|
|
3806
|
+
}
|
|
3807
|
+
) })
|
|
3808
|
+
]
|
|
3809
|
+
}
|
|
3810
|
+
);
|
|
3811
|
+
}
|
|
3812
|
+
SPortal.displayName = "SPortal";
|
|
3642
3813
|
|
|
3643
3814
|
// src/components/SSelect/select.config.ts
|
|
3644
3815
|
function flattenOptions(options, depth = 1) {
|
|
@@ -3673,75 +3844,6 @@ function flattenOptions(options, depth = 1) {
|
|
|
3673
3844
|
var selectableOptions = (flat) => flat.filter((o) => !o.isGroup && !o.disabled);
|
|
3674
3845
|
var isHtmlLabel = (label) => /<[a-z][\s\S]*>/i.test(label);
|
|
3675
3846
|
var extractText = (html) => html.replace(/<[^>]*>/g, "");
|
|
3676
|
-
|
|
3677
|
-
// src/lib/sanitize-inline-html.ts
|
|
3678
|
-
var ALLOWED_INLINE_TAGS = /* @__PURE__ */ new Set(["A", "B", "STRONG", "I", "EM", "BR", "SPAN"]);
|
|
3679
|
-
var ALLOWED_ATTRS_BY_TAG = {
|
|
3680
|
-
A: /* @__PURE__ */ new Set(["href", "target", "rel", "class"])
|
|
3681
|
-
};
|
|
3682
|
-
var COMMON_ALLOWED_ATTRS = /* @__PURE__ */ new Set(["class"]);
|
|
3683
|
-
var SAFE_HREF_RE = /^(https?:|mailto:|tel:|\/|#|\.)/i;
|
|
3684
|
-
var DROP_CONTENT_TAGS = /* @__PURE__ */ new Set([
|
|
3685
|
-
"SCRIPT",
|
|
3686
|
-
"STYLE",
|
|
3687
|
-
"IFRAME",
|
|
3688
|
-
"OBJECT",
|
|
3689
|
-
"EMBED",
|
|
3690
|
-
"META",
|
|
3691
|
-
"LINK",
|
|
3692
|
-
"BASE",
|
|
3693
|
-
"NOSCRIPT",
|
|
3694
|
-
// SVG/MATH 는 foreign-content 파싱 모드로 전환되어 재직렬화 시 다른 트리로
|
|
3695
|
-
// 재파싱될 수 있다(mXSS 벡터). 인라인 라벨에 필요 없으므로 통째로 제거한다.
|
|
3696
|
-
"SVG",
|
|
3697
|
-
"MATH",
|
|
3698
|
-
"TEMPLATE"
|
|
3699
|
-
]);
|
|
3700
|
-
var escapeHtml = (value) => value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3701
|
-
var sanitizeNode = (node) => {
|
|
3702
|
-
if (node.nodeType === Node.COMMENT_NODE) {
|
|
3703
|
-
node.remove();
|
|
3704
|
-
return;
|
|
3705
|
-
}
|
|
3706
|
-
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
3707
|
-
const element = node;
|
|
3708
|
-
const tagName = element.tagName;
|
|
3709
|
-
if (DROP_CONTENT_TAGS.has(tagName)) {
|
|
3710
|
-
element.remove();
|
|
3711
|
-
return;
|
|
3712
|
-
}
|
|
3713
|
-
Array.from(element.childNodes).forEach((child) => sanitizeNode(child));
|
|
3714
|
-
if (ALLOWED_INLINE_TAGS.has(tagName)) {
|
|
3715
|
-
if (element.hasAttribute("className")) {
|
|
3716
|
-
const val = element.getAttribute("className");
|
|
3717
|
-
element.removeAttribute("className");
|
|
3718
|
-
if (!element.hasAttribute("class")) element.setAttribute("class", val);
|
|
3719
|
-
}
|
|
3720
|
-
const allowedAttrs = ALLOWED_ATTRS_BY_TAG[tagName] ?? COMMON_ALLOWED_ATTRS;
|
|
3721
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
3722
|
-
if (!allowedAttrs.has(attr.name)) element.removeAttribute(attr.name);
|
|
3723
|
-
});
|
|
3724
|
-
if (tagName === "A") {
|
|
3725
|
-
const href = element.getAttribute("href");
|
|
3726
|
-
if (href !== null && href !== "" && !SAFE_HREF_RE.test(href)) element.removeAttribute("href");
|
|
3727
|
-
if (element.hasAttribute("target")) {
|
|
3728
|
-
element.setAttribute("rel", "noopener noreferrer");
|
|
3729
|
-
}
|
|
3730
|
-
}
|
|
3731
|
-
return;
|
|
3732
|
-
}
|
|
3733
|
-
const parent = element.parentNode;
|
|
3734
|
-
if (parent == null) return;
|
|
3735
|
-
while (element.firstChild) parent.insertBefore(element.firstChild, element);
|
|
3736
|
-
parent.removeChild(element);
|
|
3737
|
-
};
|
|
3738
|
-
var sanitizeInlineHtml = (value) => {
|
|
3739
|
-
if (typeof document === "undefined") return escapeHtml(value);
|
|
3740
|
-
const template = document.createElement("template");
|
|
3741
|
-
template.innerHTML = value;
|
|
3742
|
-
Array.from(template.content.childNodes).forEach((child) => sanitizeNode(child));
|
|
3743
|
-
return template.innerHTML;
|
|
3744
|
-
};
|
|
3745
3847
|
var SEARCH_THRESHOLD = 11;
|
|
3746
3848
|
var SSelect = react.forwardRef(function SSelect2({
|
|
3747
3849
|
value,
|
|
@@ -3765,6 +3867,7 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3765
3867
|
label,
|
|
3766
3868
|
labelWidth,
|
|
3767
3869
|
icon,
|
|
3870
|
+
iconColor,
|
|
3768
3871
|
labelTooltip,
|
|
3769
3872
|
addonLabel,
|
|
3770
3873
|
addonAlign,
|
|
@@ -3776,18 +3879,15 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3776
3879
|
}, ref) {
|
|
3777
3880
|
const multi = type === "multi" || type === "multi_depth";
|
|
3778
3881
|
const portalContainer = usePortalContainer();
|
|
3882
|
+
const insideModal = useInsideModal();
|
|
3779
3883
|
const [search, setSearch] = react.useState("");
|
|
3780
3884
|
const [ruleError, setRuleError] = react.useState("");
|
|
3781
3885
|
const [open, setOpen] = react.useState(false);
|
|
3886
|
+
const [pendingOpen, setPendingOpen] = react.useState(false);
|
|
3887
|
+
const [focusedIndex, setFocusedIndex] = react.useState(-1);
|
|
3782
3888
|
const triggerRef = react.useRef(null);
|
|
3783
|
-
react.
|
|
3784
|
-
|
|
3785
|
-
() => ({
|
|
3786
|
-
focus: () => triggerRef.current?.focus(),
|
|
3787
|
-
open: () => setOpen(true)
|
|
3788
|
-
}),
|
|
3789
|
-
[]
|
|
3790
|
-
);
|
|
3889
|
+
const searchInputRef = react.useRef(null);
|
|
3890
|
+
const listRef = react.useRef(null);
|
|
3791
3891
|
const flat = react.useMemo(() => flattenOptions(options), [options]);
|
|
3792
3892
|
const selectable = react.useMemo(() => selectableOptions(flat), [flat]);
|
|
3793
3893
|
const hasLeaf = react.useMemo(() => flat.some((o) => !o.isGroup), [flat]);
|
|
@@ -3805,6 +3905,46 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3805
3905
|
const arr = Array.isArray(value) ? value : [value];
|
|
3806
3906
|
return arr.map((v) => v != null && typeof v === "object" ? v.value : v).filter((v) => v != null && v !== "").map(String);
|
|
3807
3907
|
}, [value]);
|
|
3908
|
+
const selectedRef = react.useRef(selected);
|
|
3909
|
+
selectedRef.current = selected;
|
|
3910
|
+
const emit = (next) => {
|
|
3911
|
+
if (!onValueChange) return;
|
|
3912
|
+
const mapped = next.map(
|
|
3913
|
+
(v) => emitValue ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
|
|
3914
|
+
);
|
|
3915
|
+
onValueChange(multi ? mapped : mapped[0] ?? (emitValue ? "" : null));
|
|
3916
|
+
};
|
|
3917
|
+
const commitOpen = (next) => {
|
|
3918
|
+
setOpen(next);
|
|
3919
|
+
onOpenChange?.(next);
|
|
3920
|
+
if (!next) {
|
|
3921
|
+
setPendingOpen(false);
|
|
3922
|
+
setSearch("");
|
|
3923
|
+
if (rules && rules.length > 0) {
|
|
3924
|
+
setRuleError(runRules(multi ? selectedRef.current : selectedRef.current[0] ?? "", rules));
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
};
|
|
3928
|
+
const requestOpen = (next) => {
|
|
3929
|
+
if (next && insideModal && portalContainer == null) {
|
|
3930
|
+
setPendingOpen(true);
|
|
3931
|
+
return;
|
|
3932
|
+
}
|
|
3933
|
+
commitOpen(next);
|
|
3934
|
+
};
|
|
3935
|
+
react.useEffect(() => {
|
|
3936
|
+
if (!insideModal || portalContainer == null || !pendingOpen) return;
|
|
3937
|
+
setPendingOpen(false);
|
|
3938
|
+
commitOpen(true);
|
|
3939
|
+
}, [insideModal, pendingOpen, portalContainer]);
|
|
3940
|
+
react.useImperativeHandle(
|
|
3941
|
+
ref,
|
|
3942
|
+
() => ({
|
|
3943
|
+
focus: () => triggerRef.current?.focus(),
|
|
3944
|
+
open: () => requestOpen(true)
|
|
3945
|
+
}),
|
|
3946
|
+
[insideModal, portalContainer]
|
|
3947
|
+
);
|
|
3808
3948
|
useFormField({
|
|
3809
3949
|
name,
|
|
3810
3950
|
validate: () => {
|
|
@@ -3814,13 +3954,6 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3814
3954
|
},
|
|
3815
3955
|
resetValidation: () => setRuleError("")
|
|
3816
3956
|
});
|
|
3817
|
-
const emit = (next) => {
|
|
3818
|
-
if (!onValueChange) return;
|
|
3819
|
-
const mapped = next.map(
|
|
3820
|
-
(v) => emitValue ? rawByValue.get(v) ?? v : optionByValue.get(v) ?? { value: v, label: v }
|
|
3821
|
-
);
|
|
3822
|
-
onValueChange(multi ? mapped : mapped[0] ?? (emitValue ? "" : null));
|
|
3823
|
-
};
|
|
3824
3957
|
const filtered = react.useMemo(() => {
|
|
3825
3958
|
if (!showSearch || search.trim() === "") return flat;
|
|
3826
3959
|
const q = search.trim().toLowerCase();
|
|
@@ -3831,6 +3964,16 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3831
3964
|
const allValues = selectable.map((o) => o.value);
|
|
3832
3965
|
const allSelected = allValues.length > 0 && allValues.every((v) => selected.includes(v));
|
|
3833
3966
|
const hasItems = filtered.some((o) => !o.isGroup);
|
|
3967
|
+
const navigableItems = react.useMemo(() => {
|
|
3968
|
+
const items = [];
|
|
3969
|
+
if (multi && useSelectAll && allValues.length > 0) {
|
|
3970
|
+
items.push({ value: "__select_all__", isSelectAll: true });
|
|
3971
|
+
}
|
|
3972
|
+
filtered.forEach((o) => {
|
|
3973
|
+
if (!o.isGroup && !o.disabled) items.push({ value: o.value });
|
|
3974
|
+
});
|
|
3975
|
+
return items;
|
|
3976
|
+
}, [allValues.length, filtered, multi, useSelectAll]);
|
|
3834
3977
|
const triggerText = (() => {
|
|
3835
3978
|
if (selected.length === 0) return placeholder;
|
|
3836
3979
|
if (multi) {
|
|
@@ -3840,26 +3983,119 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3840
3983
|
return labelByValue.get(selected[0]) ?? selected[0];
|
|
3841
3984
|
})();
|
|
3842
3985
|
const isPlaceholder = selected.length === 0;
|
|
3843
|
-
const
|
|
3844
|
-
|
|
3986
|
+
const handleSelect = (nextValue) => {
|
|
3987
|
+
if (multi) {
|
|
3988
|
+
const next = selected.includes(nextValue) ? selected.filter((v) => v !== nextValue) : [...selected, nextValue];
|
|
3989
|
+
emit(next);
|
|
3990
|
+
return;
|
|
3991
|
+
}
|
|
3992
|
+
emit([nextValue]);
|
|
3993
|
+
commitOpen(false);
|
|
3994
|
+
};
|
|
3995
|
+
const handleSelectAll = () => {
|
|
3996
|
+
emit(allSelected ? [] : allValues);
|
|
3997
|
+
};
|
|
3998
|
+
react.useEffect(() => {
|
|
3999
|
+
if (!open) {
|
|
4000
|
+
setFocusedIndex(-1);
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
|
|
4004
|
+
}, [open, navigableItems.length]);
|
|
4005
|
+
react.useEffect(() => {
|
|
4006
|
+
if (!open) return;
|
|
4007
|
+
setFocusedIndex(navigableItems.length > 0 ? 0 : -1);
|
|
4008
|
+
}, [search, open, navigableItems.length]);
|
|
4009
|
+
react.useEffect(() => {
|
|
4010
|
+
if (!open || focusedIndex < 0) return;
|
|
4011
|
+
const list = listRef.current;
|
|
4012
|
+
const focusedEl = list?.querySelector('[data-select-focused="true"]');
|
|
4013
|
+
if (!list || !focusedEl) return;
|
|
4014
|
+
const listRect = list.getBoundingClientRect();
|
|
4015
|
+
const itemRect = focusedEl.getBoundingClientRect();
|
|
4016
|
+
if (itemRect.top < listRect.top) {
|
|
4017
|
+
list.scrollTop += itemRect.top - listRect.top;
|
|
4018
|
+
} else if (itemRect.bottom > listRect.bottom) {
|
|
4019
|
+
list.scrollTop += itemRect.bottom - listRect.bottom;
|
|
4020
|
+
}
|
|
4021
|
+
}, [focusedIndex, open]);
|
|
4022
|
+
const moveFocusedIndex = (direction) => {
|
|
4023
|
+
if (!open || navigableItems.length === 0) return;
|
|
4024
|
+
setFocusedIndex((current) => {
|
|
4025
|
+
if (direction === "next") {
|
|
4026
|
+
return current < 0 ? 0 : (current + 1) % navigableItems.length;
|
|
4027
|
+
}
|
|
4028
|
+
return current <= 0 ? navigableItems.length - 1 : current - 1;
|
|
4029
|
+
});
|
|
4030
|
+
};
|
|
4031
|
+
const selectFocusedItem = () => {
|
|
4032
|
+
if (focusedIndex < 0 || focusedIndex >= navigableItems.length) return;
|
|
4033
|
+
const focused = navigableItems[focusedIndex];
|
|
4034
|
+
if (focused.isSelectAll) {
|
|
4035
|
+
handleSelectAll();
|
|
4036
|
+
return;
|
|
4037
|
+
}
|
|
4038
|
+
handleSelect(focused.value);
|
|
4039
|
+
};
|
|
4040
|
+
const handleKeyDown = (event) => {
|
|
4041
|
+
if (!open) {
|
|
4042
|
+
if ((event.key === "ArrowDown" || event.key === "ArrowUp") && !effectiveDisabled) {
|
|
4043
|
+
event.preventDefault();
|
|
4044
|
+
requestOpen(true);
|
|
4045
|
+
}
|
|
4046
|
+
return;
|
|
4047
|
+
}
|
|
4048
|
+
if (event.key === "ArrowDown") {
|
|
4049
|
+
event.preventDefault();
|
|
4050
|
+
moveFocusedIndex("next");
|
|
4051
|
+
return;
|
|
4052
|
+
}
|
|
4053
|
+
if (event.key === "ArrowUp") {
|
|
4054
|
+
event.preventDefault();
|
|
4055
|
+
moveFocusedIndex("prev");
|
|
4056
|
+
return;
|
|
4057
|
+
}
|
|
4058
|
+
if (event.key === "Enter") {
|
|
4059
|
+
event.preventDefault();
|
|
4060
|
+
selectFocusedItem();
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
if (event.key === "Escape") {
|
|
4064
|
+
event.preventDefault();
|
|
4065
|
+
commitOpen(false);
|
|
4066
|
+
}
|
|
4067
|
+
};
|
|
4068
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4069
|
+
SField,
|
|
3845
4070
|
{
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
4071
|
+
label,
|
|
4072
|
+
labelWidth,
|
|
4073
|
+
icon,
|
|
4074
|
+
iconColor,
|
|
4075
|
+
labelTooltip,
|
|
4076
|
+
labelTooltipProps,
|
|
4077
|
+
addonLabel,
|
|
4078
|
+
addonAlign,
|
|
4079
|
+
hint,
|
|
4080
|
+
error: error || ruleError !== "",
|
|
4081
|
+
status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
|
|
4082
|
+
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
4083
|
+
disabled: effectiveDisabled,
|
|
4084
|
+
width,
|
|
4085
|
+
className,
|
|
4086
|
+
style,
|
|
3857
4087
|
children: [
|
|
4088
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected.join(",") }),
|
|
3858
4089
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3859
|
-
|
|
4090
|
+
"button",
|
|
3860
4091
|
{
|
|
3861
4092
|
ref: triggerRef,
|
|
4093
|
+
type: "button",
|
|
3862
4094
|
disabled: effectiveDisabled,
|
|
4095
|
+
"aria-haspopup": "listbox",
|
|
4096
|
+
"aria-expanded": open,
|
|
4097
|
+
onClick: () => requestOpen(!open),
|
|
4098
|
+
onKeyDown: handleKeyDown,
|
|
3863
4099
|
className: "flex h-full w-full cursor-pointer items-center justify-between gap-[8px] bg-transparent px-[12px] text-left text-[12px] leading-[20px] outline-none disabled:cursor-not-allowed",
|
|
3864
4100
|
style: {
|
|
3865
4101
|
color: effectiveDisabled ? "var(--cmp-select-text-disabled)" : isPlaceholder ? "var(--cmp-select-icon-default)" : "var(--cmp-select-text-default)"
|
|
@@ -3884,174 +4120,229 @@ var SSelect = react.forwardRef(function SSelect2({
|
|
|
3884
4120
|
]
|
|
3885
4121
|
}
|
|
3886
4122
|
),
|
|
3887
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3888
|
-
|
|
4123
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4124
|
+
SPortal,
|
|
3889
4125
|
{
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
4126
|
+
open,
|
|
4127
|
+
onClose: () => commitOpen(false),
|
|
4128
|
+
onOpenChange: (next) => {
|
|
4129
|
+
if (next) requestOpen(true);
|
|
4130
|
+
},
|
|
4131
|
+
anchorRef: triggerRef,
|
|
4132
|
+
placement: "bottom",
|
|
4133
|
+
align: "start",
|
|
4134
|
+
offset: 4,
|
|
4135
|
+
fit: !dropdownWidth,
|
|
4136
|
+
onOpenAutoFocus: (event) => {
|
|
4137
|
+
if (!showSearch) {
|
|
4138
|
+
event.preventDefault();
|
|
4139
|
+
return;
|
|
4140
|
+
}
|
|
4141
|
+
event.preventDefault();
|
|
4142
|
+
requestAnimationFrame(() => searchInputRef.current?.focus());
|
|
4143
|
+
},
|
|
4144
|
+
onCloseAutoFocus: (event) => {
|
|
4145
|
+
event.preventDefault();
|
|
4146
|
+
triggerRef.current?.focus();
|
|
4147
|
+
},
|
|
4148
|
+
className: "rounded-[var(--cmp-listBox-radius)] bg-[var(--cmp-listBox-bg)] py-[4px] shadow-[2px_2px_12px_2px_rgba(0,0,0,0.1)]",
|
|
3895
4149
|
style: {
|
|
3896
|
-
maxHeight: dropdownHeight,
|
|
3897
4150
|
...dropdownWidth ? { width: dropdownWidth } : {},
|
|
3898
4151
|
maxWidth: maxDropdownWidth
|
|
3899
4152
|
},
|
|
3900
|
-
children:
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
4153
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4154
|
+
"div",
|
|
4155
|
+
{
|
|
4156
|
+
ref: listRef,
|
|
4157
|
+
className: "overflow-auto [scrollbar-width:auto] [&::-webkit-scrollbar]:w-[8px] [&::-webkit-scrollbar]:bg-[var(--color-grey-25)] [&::-webkit-scrollbar:horizontal]:h-[8px] [&::-webkit-scrollbar-thumb]:rounded-[4px] [&::-webkit-scrollbar-thumb]:bg-[var(--color-grey-45)] [&::-webkit-scrollbar-track]:bg-[var(--color-grey-25)]",
|
|
4158
|
+
style: { maxHeight: dropdownHeight },
|
|
4159
|
+
onMouseLeave: () => setFocusedIndex(-1),
|
|
4160
|
+
children: [
|
|
4161
|
+
showSearch && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-[1] bg-[var(--cmp-listBox-bg)] px-[8px] py-[4px]", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-[6px] rounded-[4px] border border-solid border-[color:var(--color-grey-45)] bg-white px-[8px] py-[4px] focus-within:border-[color:var(--sys-color-field-border-focus)]", children: [
|
|
4162
|
+
/* @__PURE__ */ jsxRuntime.jsx(SIcon, { name: "search", size: 16, color: "var(--color-grey-70)", className: "shrink-0" }),
|
|
4163
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4164
|
+
"input",
|
|
4165
|
+
{
|
|
4166
|
+
ref: searchInputRef,
|
|
4167
|
+
value: search,
|
|
4168
|
+
onChange: (e) => setSearch(e.target.value),
|
|
4169
|
+
onKeyDown: handleKeyDown,
|
|
4170
|
+
placeholder: "\uAC80\uC0C9",
|
|
4171
|
+
className: "min-w-0 flex-1 border-none bg-transparent text-[12px] leading-[20px] text-[color:var(--cmp-select-text-default)] outline-none placeholder:text-[color:var(--color-grey-55)]"
|
|
4172
|
+
}
|
|
4173
|
+
),
|
|
4174
|
+
search !== "" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4175
|
+
SGhostButton,
|
|
4176
|
+
{
|
|
4177
|
+
icon: "close",
|
|
4178
|
+
size: "xxs",
|
|
4179
|
+
intent: "default",
|
|
4180
|
+
ariaLabel: "\uAC80\uC0C9\uC5B4 \uC9C0\uC6B0\uAE30",
|
|
4181
|
+
onClick: () => setSearch(""),
|
|
4182
|
+
className: "shrink-0"
|
|
4183
|
+
}
|
|
4184
|
+
)
|
|
4185
|
+
] }) }),
|
|
4186
|
+
hasItems ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4187
|
+
ItemList,
|
|
4188
|
+
{
|
|
4189
|
+
items: filtered,
|
|
4190
|
+
multi,
|
|
4191
|
+
selected,
|
|
4192
|
+
focusedValue: navigableItems[focusedIndex]?.isSelectAll ? "__select_all__" : navigableItems[focusedIndex]?.value,
|
|
4193
|
+
showSelectAll: multi && useSelectAll && allValues.length > 0,
|
|
4194
|
+
selectAllLabel: allSelectedLabel,
|
|
4195
|
+
selectAllSelected: allSelected,
|
|
4196
|
+
onSelectAll: handleSelectAll,
|
|
4197
|
+
onSelect: handleSelect,
|
|
4198
|
+
onHoverValue: (value2) => {
|
|
4199
|
+
const index = navigableItems.findIndex(
|
|
4200
|
+
(item) => item.isSelectAll ? value2 === "__select_all__" : item.value === value2
|
|
4201
|
+
);
|
|
4202
|
+
if (index >= 0) setFocusedIndex(index);
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-[12px] py-[12px] text-left text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-disabled)]", children: "\uD45C\uC2DC\uD560 \uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4." })
|
|
4206
|
+
]
|
|
4207
|
+
}
|
|
4208
|
+
)
|
|
3938
4209
|
}
|
|
3939
4210
|
)
|
|
3940
4211
|
]
|
|
3941
4212
|
}
|
|
3942
4213
|
);
|
|
3943
|
-
const control = showSearch ? /* @__PURE__ */ jsxRuntime.jsx(Ariakit__namespace.ComboboxProvider, { value: search, setValue: setSearch, resetValueOnHide: true, children: selectStore }) : selectStore;
|
|
3944
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3945
|
-
SField,
|
|
3946
|
-
{
|
|
3947
|
-
label,
|
|
3948
|
-
labelWidth,
|
|
3949
|
-
icon,
|
|
3950
|
-
labelTooltip,
|
|
3951
|
-
labelTooltipProps,
|
|
3952
|
-
addonLabel,
|
|
3953
|
-
addonAlign,
|
|
3954
|
-
hint,
|
|
3955
|
-
error: error || ruleError !== "",
|
|
3956
|
-
status: rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0,
|
|
3957
|
-
errorMessage: ruleError !== "" ? ruleError : errorMessage,
|
|
3958
|
-
disabled: effectiveDisabled,
|
|
3959
|
-
width,
|
|
3960
|
-
className,
|
|
3961
|
-
style,
|
|
3962
|
-
children: [
|
|
3963
|
-
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: selected.join(",") }),
|
|
3964
|
-
control
|
|
3965
|
-
]
|
|
3966
|
-
}
|
|
3967
|
-
);
|
|
3968
4214
|
});
|
|
3969
4215
|
SSelect.displayName = "SSelect";
|
|
3970
4216
|
function ItemList({
|
|
3971
4217
|
items,
|
|
3972
4218
|
multi,
|
|
3973
4219
|
selected,
|
|
3974
|
-
|
|
4220
|
+
focusedValue,
|
|
4221
|
+
showSelectAll,
|
|
4222
|
+
selectAllLabel,
|
|
4223
|
+
selectAllSelected,
|
|
4224
|
+
onSelectAll,
|
|
4225
|
+
onSelect,
|
|
4226
|
+
onHoverValue
|
|
3975
4227
|
}) {
|
|
3976
4228
|
const itemBase = cn(
|
|
3977
|
-
|
|
3978
|
-
"group flex cursor-pointer select-none items-center gap-[8px] text-[12px] leading-[20px] outline-none",
|
|
4229
|
+
"group flex w-full cursor-pointer select-none items-center gap-[8px] border-none bg-transparent text-left text-[12px] leading-[20px] outline-none",
|
|
3979
4230
|
"text-[color:var(--cmp-listItem-content-default)]",
|
|
3980
|
-
|
|
3981
|
-
"aria-disabled:cursor-not-allowed aria-disabled:text-[color:var(--cmp-listItem-content-disabled)]"
|
|
4231
|
+
"disabled:cursor-not-allowed disabled:text-[color:var(--cmp-listItem-content-disabled)]"
|
|
3982
4232
|
);
|
|
3983
|
-
const activeClass = "
|
|
3984
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
const isDepth1 = o.depth === 1;
|
|
3988
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3989
|
-
"div",
|
|
3990
|
-
{
|
|
3991
|
-
className: cn(
|
|
3992
|
-
"select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
|
|
3993
|
-
isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
|
|
3994
|
-
// 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
|
|
3995
|
-
// 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
|
|
3996
|
-
o.disabled && "text-[color:var(--cmp-listItem-content-disabled)]",
|
|
3997
|
-
o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
|
|
3998
|
-
),
|
|
3999
|
-
style: { paddingLeft: padLeft },
|
|
4000
|
-
children: o.label
|
|
4001
|
-
},
|
|
4002
|
-
o.value
|
|
4003
|
-
);
|
|
4004
|
-
}
|
|
4005
|
-
const isSelected = selected.includes(o.value);
|
|
4006
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4007
|
-
Ariakit__namespace.SelectItem,
|
|
4233
|
+
const activeClass = "hover:bg-[var(--cmp-listItem-bg-hover)] hover:text-[color:var(--cmp-listItem-content-hover)] focus:bg-[var(--cmp-listItem-bg-hover)] focus:text-[color:var(--cmp-listItem-content-hover)]";
|
|
4234
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "listbox", "aria-multiselectable": multi || void 0, children: [
|
|
4235
|
+
showSelectAll && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4236
|
+
"button",
|
|
4008
4237
|
{
|
|
4009
|
-
|
|
4010
|
-
|
|
4238
|
+
type: "button",
|
|
4239
|
+
"data-select-focused": focusedValue === "__select_all__" ? "true" : void 0,
|
|
4240
|
+
"data-select-active": focusedValue === "__select_all__" ? "true" : void 0,
|
|
4011
4241
|
className: cn(
|
|
4012
4242
|
itemBase,
|
|
4013
|
-
|
|
4014
|
-
activeClass
|
|
4243
|
+
focusedValue === "__select_all__" && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]"
|
|
4015
4244
|
),
|
|
4016
|
-
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft:
|
|
4017
|
-
|
|
4245
|
+
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: 12 },
|
|
4246
|
+
onMouseEnter: () => onHoverValue("__select_all__"),
|
|
4247
|
+
onClick: onSelectAll,
|
|
4018
4248
|
children: [
|
|
4019
|
-
multi && // hover(active) 시 checkbox inverse — 파란 hover 배경 위에서 checked/unchecked 모두 흰 테두리 + 투명 배경
|
|
4020
4249
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4021
4250
|
"span",
|
|
4022
4251
|
{
|
|
4023
4252
|
className: cn(
|
|
4024
4253
|
"flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
4025
|
-
|
|
4026
|
-
// 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
|
|
4027
|
-
"border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
|
|
4028
|
-
) : cn(
|
|
4029
|
-
"group-data-[active-item]:border-[color:var(--cmp-checkbox-checked-border-inverse)]",
|
|
4030
|
-
isSelected ? "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)] group-data-[active-item]:bg-transparent" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-transparent"
|
|
4031
|
-
)
|
|
4254
|
+
selectAllSelected ? focusedValue === "__select_all__" ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
|
|
4032
4255
|
),
|
|
4033
|
-
children:
|
|
4256
|
+
children: selectAllSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4034
4257
|
SIcon,
|
|
4035
4258
|
{
|
|
4036
4259
|
name: "checkboxCheck",
|
|
4037
4260
|
size: 12,
|
|
4038
|
-
color:
|
|
4261
|
+
color: "var(--cmp-checkbox-checked-icon-default)"
|
|
4039
4262
|
}
|
|
4040
4263
|
)
|
|
4041
4264
|
}
|
|
4042
4265
|
),
|
|
4043
|
-
|
|
4044
|
-
"span",
|
|
4045
|
-
{
|
|
4046
|
-
className: "flex-1 truncate",
|
|
4047
|
-
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
|
|
4048
|
-
}
|
|
4049
|
-
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: o.label })
|
|
4266
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: selectAllLabel })
|
|
4050
4267
|
]
|
|
4051
|
-
}
|
|
4052
|
-
|
|
4053
|
-
)
|
|
4054
|
-
|
|
4268
|
+
}
|
|
4269
|
+
),
|
|
4270
|
+
items.map((o) => {
|
|
4271
|
+
const padLeft = o.depth === 1 ? 12 : o.depth === 2 ? 20 : 28;
|
|
4272
|
+
if (o.isGroup) {
|
|
4273
|
+
const isDepth1 = o.depth === 1;
|
|
4274
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4275
|
+
"div",
|
|
4276
|
+
{
|
|
4277
|
+
className: cn(
|
|
4278
|
+
"select-none py-[4px] pr-[12px] text-[12px] leading-[20px] text-[color:var(--cmp-listItem-content-default)]",
|
|
4279
|
+
isDepth1 ? "border-t border-solid border-[color:var(--cmp-listItem-depth1-border-color)] bg-[var(--cmp-listItem-depth1-bg-default)] font-bold" : "bg-[var(--cmp-listItem-depth2-middle-bg)] font-medium",
|
|
4280
|
+
// 하위가 전부 비활성이면(select.config 에서 bubble-up) 어미 그룹도 비활성 처리:
|
|
4281
|
+
// 텍스트는 회색(#888), depth1 그룹은 파란 배경 대신 회색(#EEE)으로 (depth2 는 #F6F6F6 유지)
|
|
4282
|
+
o.disabled && "cursor-not-allowed text-[color:var(--cmp-listItem-content-disabled)]",
|
|
4283
|
+
o.disabled && isDepth1 && "bg-[var(--cmp-listItem-depth1-bg-disabled)]"
|
|
4284
|
+
),
|
|
4285
|
+
style: { paddingLeft: padLeft },
|
|
4286
|
+
children: o.label
|
|
4287
|
+
},
|
|
4288
|
+
o.value
|
|
4289
|
+
);
|
|
4290
|
+
}
|
|
4291
|
+
const isSelected = selected.includes(o.value);
|
|
4292
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4293
|
+
"button",
|
|
4294
|
+
{
|
|
4295
|
+
type: "button",
|
|
4296
|
+
disabled: o.disabled,
|
|
4297
|
+
role: "option",
|
|
4298
|
+
"aria-selected": isSelected,
|
|
4299
|
+
"data-select-focused": focusedValue === o.value ? "true" : void 0,
|
|
4300
|
+
"data-select-active": focusedValue === o.value ? "true" : void 0,
|
|
4301
|
+
className: cn(
|
|
4302
|
+
itemBase,
|
|
4303
|
+
isSelected && !multi && "font-bold text-[color:var(--cmp-listItem-content-selected)]",
|
|
4304
|
+
focusedValue === o.value && "bg-[var(--cmp-listItem-bg-hover)] text-[color:var(--cmp-listItem-content-hover)]",
|
|
4305
|
+
activeClass
|
|
4306
|
+
),
|
|
4307
|
+
style: { paddingTop: 4, paddingBottom: 4, paddingRight: 12, paddingLeft: padLeft },
|
|
4308
|
+
onMouseEnter: () => onHoverValue(o.value),
|
|
4309
|
+
onClick: () => onSelect(o.value),
|
|
4310
|
+
children: [
|
|
4311
|
+
multi && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4312
|
+
"span",
|
|
4313
|
+
{
|
|
4314
|
+
className: cn(
|
|
4315
|
+
"flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center rounded-[2px] border border-solid",
|
|
4316
|
+
o.disabled ? (
|
|
4317
|
+
// 비활성: 회색 채움(#E1E1E1) + 회색 테두리(#CCCCCC)
|
|
4318
|
+
"cursor-not-allowed border-[color:var(--cmp-checkbox-border-disabled)] bg-[var(--cmp-checkbox-bg-disabled)]"
|
|
4319
|
+
) : cn(
|
|
4320
|
+
isSelected ? focusedValue === o.value ? "border-[color:var(--cmp-checkbox-checked-border-inverse)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-checked-bg-default)] bg-[var(--cmp-checkbox-checked-bg-default)]" : "border-[color:var(--cmp-checkbox-unchecked-border-default)] bg-[var(--cmp-checkbox-unchecked-bg-default)]"
|
|
4321
|
+
)
|
|
4322
|
+
),
|
|
4323
|
+
children: isSelected && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4324
|
+
SIcon,
|
|
4325
|
+
{
|
|
4326
|
+
name: "checkboxCheck",
|
|
4327
|
+
size: 12,
|
|
4328
|
+
color: o.disabled ? "var(--cmp-checkbox-checked-icon-disabled)" : "var(--cmp-checkbox-checked-icon-default)"
|
|
4329
|
+
}
|
|
4330
|
+
)
|
|
4331
|
+
}
|
|
4332
|
+
),
|
|
4333
|
+
isHtmlLabel(o.label) ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4334
|
+
"span",
|
|
4335
|
+
{
|
|
4336
|
+
className: "flex-1 truncate",
|
|
4337
|
+
dangerouslySetInnerHTML: { __html: sanitizeInlineHtml(o.label) }
|
|
4338
|
+
}
|
|
4339
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate", children: o.label })
|
|
4340
|
+
]
|
|
4341
|
+
},
|
|
4342
|
+
o.value
|
|
4343
|
+
);
|
|
4344
|
+
})
|
|
4345
|
+
] });
|
|
4055
4346
|
}
|
|
4056
4347
|
var DEFAULT_ROW_HEIGHT = 44;
|
|
4057
4348
|
var DENSE_ROW_HEIGHT = 32;
|
|
@@ -4326,7 +4617,8 @@ var STable = react.forwardRef(function STable2({
|
|
|
4326
4617
|
else onSelectedChange?.([...selected, row]);
|
|
4327
4618
|
};
|
|
4328
4619
|
const radiusClass = radius === "full" ? "rounded-none" : radius === "useTop" ? "rounded-b-[var(--cmp-table-radius)] rounded-t-none" : "rounded-[var(--cmp-table-radius)]";
|
|
4329
|
-
const cellPadY = dense ? "var(--cmp-table-body-dense
|
|
4620
|
+
const cellPadY = dense ? "var(--cmp-table-body-paddingY-dense)" : "var(--cmp-table-body-paddingY-default)";
|
|
4621
|
+
const cellPadX = "var(--cmp-table-body-paddingX-wide)";
|
|
4330
4622
|
const rowH = dense ? "var(--cmp-table-body-dense-height)" : "var(--cmp-table-body-default-height)";
|
|
4331
4623
|
const totalColSpan = visibleCols.length + (selectable ? 1 : 0);
|
|
4332
4624
|
const stickyInfo = (i) => {
|
|
@@ -4501,13 +4793,15 @@ var STable = react.forwardRef(function STable2({
|
|
|
4501
4793
|
className: cn(
|
|
4502
4794
|
// 원본 .td: 컬럼 폭에 맞춰 내용 말줄임(overflow hidden + ellipsis) + 행 구분선(border-b)
|
|
4503
4795
|
// 셀 배경은 흰색으로 채워 뒤 배경이 비치지 않게 하고, hover 시 행 배경(grey_05)을 따른다.
|
|
4504
|
-
"overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)]
|
|
4796
|
+
"overflow-hidden text-ellipsis whitespace-nowrap border-b border-solid border-[color:var(--cmp-table-border-color)] text-[12px] leading-[20px] text-[color:var(--sys-color-fg-primary)]",
|
|
4505
4797
|
rowBg,
|
|
4506
4798
|
"group-hover:bg-[var(--color-grey-05)]",
|
|
4507
4799
|
stickyShadowClass(i),
|
|
4508
4800
|
col.tdClass
|
|
4509
4801
|
),
|
|
4510
4802
|
style: {
|
|
4803
|
+
paddingLeft: cellPadX,
|
|
4804
|
+
paddingRight: cellPadX,
|
|
4511
4805
|
paddingTop: cellPadY,
|
|
4512
4806
|
paddingBottom: cellPadY,
|
|
4513
4807
|
textAlign: col.align ?? "left",
|