sellmate-design-system-react 9.0.0-beta.0 → 9.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { cn } from './lib/cn';
2
2
  export { resolveColor, isColorKey, COLOR_KEYS, type SColor, type SColorKey } from './lib/color';
3
3
  export type { Rule } from './lib/form';
4
4
  export * from './components/SIcon';
5
+ export * from './components/SImage';
5
6
  export * from './components/SBadge';
6
7
  export * from './components/SCard';
7
8
  export * from './components/SDraggableItem';
package/dist/index.js CHANGED
@@ -3113,6 +3113,209 @@ var SIcon = /* @__PURE__ */ forwardRef(function SIcon2({ name, size = 24, color,
3113
3113
  }
3114
3114
  );
3115
3115
  });
3116
+ var VIEWBOX = 80;
3117
+ var RADIUS = 34;
3118
+ var STROKE = 12;
3119
+ var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
3120
+ var COLOR_MAP = {
3121
+ primary: { arc: "var(--cmp-progress-color-active)", track: "var(--cmp-progress-color-track)" },
3122
+ // inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
3123
+ inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
3124
+ error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
3125
+ complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" },
3126
+ // neutral: 콘텐츠가 아직 없는 자리를 채우는 용도 — arc 도 회색이라 진행률보다 "대기"로 읽힌다
3127
+ neutral: { arc: "var(--color-grey-35)", track: "var(--cmp-progress-color-track)" }
3128
+ };
3129
+ var DEFAULT_SIZE = 80;
3130
+ var clamp = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
3131
+ var SCircleProgress = /* @__PURE__ */ forwardRef(
3132
+ function SCircleProgress2({
3133
+ value = 0,
3134
+ type = "primary",
3135
+ indeterminate = false,
3136
+ size = DEFAULT_SIZE,
3137
+ label,
3138
+ innerValue = false,
3139
+ className,
3140
+ style
3141
+ }, ref) {
3142
+ const v = clamp(value);
3143
+ const dimension = typeof size === "number" ? `${size}px` : size;
3144
+ const colors = COLOR_MAP[type];
3145
+ const c = VIEWBOX / 2;
3146
+ const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
3147
+ const filled = v / 100 * CIRCUMFERENCE;
3148
+ const showPercent = !indeterminate;
3149
+ const percentNode = /* @__PURE__ */ jsxs(
3150
+ "span",
3151
+ {
3152
+ className: cn(
3153
+ "text-center text-[16px] font-bold",
3154
+ innerValue ? (
3155
+ // leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
3156
+ // 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
3157
+ "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
3158
+ ) : "leading-[26px]"
3159
+ ),
3160
+ style: { color: percentColor },
3161
+ children: [
3162
+ Math.round(v),
3163
+ "%"
3164
+ ]
3165
+ }
3166
+ );
3167
+ return /* @__PURE__ */ jsxs(
3168
+ "div",
3169
+ {
3170
+ ref,
3171
+ className: cn(
3172
+ "inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
3173
+ className
3174
+ ),
3175
+ style,
3176
+ children: [
3177
+ /* @__PURE__ */ jsxs("div", { className: cn(innerValue && "relative"), children: [
3178
+ /* @__PURE__ */ jsxs(
3179
+ "svg",
3180
+ {
3181
+ viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
3182
+ xmlns: "http://www.w3.org/2000/svg",
3183
+ className: cn(indeterminate && "origin-center animate-circle-spin"),
3184
+ style: { width: dimension, height: dimension },
3185
+ children: [
3186
+ /* @__PURE__ */ jsx(
3187
+ "circle",
3188
+ {
3189
+ cx: c,
3190
+ cy: c,
3191
+ r: RADIUS,
3192
+ fill: "none",
3193
+ strokeWidth: STROKE,
3194
+ style: { stroke: colors.track }
3195
+ }
3196
+ ),
3197
+ /* @__PURE__ */ jsx(
3198
+ "circle",
3199
+ {
3200
+ cx: c,
3201
+ cy: c,
3202
+ r: RADIUS,
3203
+ fill: "none",
3204
+ strokeWidth: STROKE,
3205
+ strokeLinecap: "round",
3206
+ className: cn(
3207
+ "origin-center",
3208
+ indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
3209
+ ),
3210
+ style: {
3211
+ stroke: colors.arc,
3212
+ ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
3213
+ }
3214
+ }
3215
+ )
3216
+ ]
3217
+ }
3218
+ ),
3219
+ showPercent && innerValue && percentNode
3220
+ ] }),
3221
+ showPercent && !innerValue && percentNode,
3222
+ label && /* @__PURE__ */ jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
3223
+ ]
3224
+ }
3225
+ );
3226
+ }
3227
+ );
3228
+ var IMAGE_FITS = ["cover", "contain", "fill", "none", "scale-down"];
3229
+ var EMPTY_ICON_SIZE = "60cqh";
3230
+ var SPINNER_SIZE = "45cqh";
3231
+ var SImage = /* @__PURE__ */ forwardRef(function SImage2({
3232
+ src,
3233
+ alt = "",
3234
+ ratio = 1,
3235
+ fit = "cover",
3236
+ position = "50% 50%",
3237
+ loading: loading2 = "lazy",
3238
+ loadingShowDelay = 0,
3239
+ noSpinner = false,
3240
+ loadingSlot,
3241
+ errorSlot,
3242
+ imgProps,
3243
+ onLoad,
3244
+ onError,
3245
+ className,
3246
+ style,
3247
+ ...rest
3248
+ }, ref) {
3249
+ const [status, setStatus] = useState("loading");
3250
+ const [spinnerVisible, setSpinnerVisible] = useState(loadingShowDelay <= 0);
3251
+ const [trackedSrc, setTrackedSrc] = useState(src);
3252
+ const imgRef = useRef(null);
3253
+ if (src !== trackedSrc) {
3254
+ setTrackedSrc(src);
3255
+ setStatus("loading");
3256
+ }
3257
+ useEffect(() => {
3258
+ if (!src) return;
3259
+ const node = imgRef.current;
3260
+ if (node?.complete && node.naturalWidth > 0) {
3261
+ setStatus((current) => current === "loading" ? "loaded" : current);
3262
+ }
3263
+ }, [src]);
3264
+ useEffect(() => {
3265
+ if (status !== "loading" || loadingShowDelay <= 0) {
3266
+ setSpinnerVisible(status === "loading");
3267
+ return;
3268
+ }
3269
+ setSpinnerVisible(false);
3270
+ const timer = setTimeout(() => setSpinnerVisible(true), loadingShowDelay);
3271
+ return () => clearTimeout(timer);
3272
+ }, [status, loadingShowDelay, src]);
3273
+ const isEmpty = !src;
3274
+ const showFallback = isEmpty || status === "error";
3275
+ const showSpinner = !isEmpty && status === "loading" && !noSpinner && spinnerVisible;
3276
+ return /* @__PURE__ */ jsxs(
3277
+ "div",
3278
+ {
3279
+ ref,
3280
+ className: cn("relative overflow-hidden bg-(--cmp-image-bg)", className),
3281
+ style: { containerType: "size", aspectRatio: ratio, ...style },
3282
+ ...rest,
3283
+ children: [
3284
+ !isEmpty && /* @__PURE__ */ jsx(
3285
+ "img",
3286
+ {
3287
+ ...imgProps,
3288
+ ref: imgRef,
3289
+ src,
3290
+ alt,
3291
+ loading: loading2,
3292
+ onLoad: () => {
3293
+ setStatus("loaded");
3294
+ onLoad?.(src);
3295
+ },
3296
+ onError: (event) => {
3297
+ setStatus("error");
3298
+ onError?.(event);
3299
+ },
3300
+ className: cn(
3301
+ "h-full w-full",
3302
+ // 로딩 중에도 자리를 지켜야 브라우저가 계속 받아온다 — 숨기되 없애지 않는다
3303
+ status === "loaded" ? "visible" : "invisible",
3304
+ imgProps?.className
3305
+ ),
3306
+ style: {
3307
+ objectFit: fit,
3308
+ objectPosition: position,
3309
+ ...imgProps?.style
3310
+ }
3311
+ }
3312
+ ),
3313
+ showFallback && /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: errorSlot ?? /* @__PURE__ */ jsx(SIcon, { name: "image", size: EMPTY_ICON_SIZE, color: "var(--cmp-image-icon)" }) }),
3314
+ showSpinner && /* @__PURE__ */ jsx("span", { className: "absolute inset-0 flex items-center justify-center", children: loadingSlot ?? /* @__PURE__ */ jsx(SCircleProgress, { indeterminate: true, type: "neutral", size: SPINNER_SIZE }) })
3315
+ ]
3316
+ }
3317
+ );
3318
+ });
3116
3319
  var BADGE_COLORS = [
3117
3320
  "red",
3118
3321
  "orange",
@@ -5554,14 +5757,14 @@ var SCallout = /* @__PURE__ */ forwardRef(function SCallout2({ type = "default",
5554
5757
  );
5555
5758
  });
5556
5759
  var FILL_COLOR = {
5557
- primary: "var(--cmp-progress-active-color)",
5558
- error: "var(--cmp-progress-error-color)",
5559
- complete: "var(--cmp-progress-success-color)"
5760
+ primary: "var(--cmp-progress-color-active)",
5761
+ error: "var(--cmp-progress-color-error)",
5762
+ complete: "var(--cmp-progress-color-success)"
5560
5763
  };
5561
- var clamp = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
5764
+ var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
5562
5765
  var SLinearProgress = /* @__PURE__ */ forwardRef(
5563
5766
  function SLinearProgress2({ value = 0, type = "primary", indeterminate = false, label, className, style }, ref) {
5564
- const v = clamp(value);
5767
+ const v = clamp2(value);
5565
5768
  const fill = FILL_COLOR[type];
5566
5769
  const valueColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : fill;
5567
5770
  const valueText = `${Math.round(v)}%`;
@@ -5608,115 +5811,6 @@ var SLinearProgress = /* @__PURE__ */ forwardRef(
5608
5811
  );
5609
5812
  }
5610
5813
  );
5611
- var VIEWBOX = 80;
5612
- var RADIUS = 34;
5613
- var STROKE = 12;
5614
- var CIRCUMFERENCE = 2 * Math.PI * RADIUS;
5615
- var COLOR_MAP = {
5616
- primary: { arc: "var(--cmp-progress-active-color)", track: "var(--cmp-progress-color-track)" },
5617
- // inverse: 어두운 배경용 — arc 흰색, track 은 흰색 40%(회색 링)
5618
- inverse: { arc: "var(--color-white)", track: "rgba(255,255,255,0.4)" },
5619
- error: { arc: "var(--color-red-75)", track: "var(--cmp-progress-color-track)" },
5620
- complete: { arc: "#01BB4B", track: "var(--cmp-progress-color-track)" }
5621
- };
5622
- var clamp2 = (v) => Number.isFinite(v) ? Math.max(0, Math.min(100, v)) : 0;
5623
- var SCircleProgress = /* @__PURE__ */ forwardRef(
5624
- function SCircleProgress2({
5625
- value = 0,
5626
- type = "primary",
5627
- indeterminate = false,
5628
- label,
5629
- innerValue = false,
5630
- className,
5631
- style
5632
- }, ref) {
5633
- const v = clamp2(value);
5634
- const colors = COLOR_MAP[type];
5635
- const c = VIEWBOX / 2;
5636
- const percentColor = v === 0 ? "var(--sys-color-fg-tertiary, #888888)" : colors.arc;
5637
- const filled = v / 100 * CIRCUMFERENCE;
5638
- const showPercent = !indeterminate;
5639
- const percentNode = /* @__PURE__ */ jsxs(
5640
- "span",
5641
- {
5642
- className: cn(
5643
- "text-center text-[16px] font-bold",
5644
- innerValue ? (
5645
- // leading-[normal]: 26px leading 은 폰트 content(19px) 위아래로 홀수(7px)만큼 남아
5646
- // 3px/4px 로 쪼개지고 글자가 링 중심보다 위로 뜬다. (leading-normal 은 1.5 라 동일 문제)
5647
- "absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 leading-[normal]"
5648
- ) : "leading-[26px]"
5649
- ),
5650
- style: { color: percentColor },
5651
- children: [
5652
- Math.round(v),
5653
- "%"
5654
- ]
5655
- }
5656
- );
5657
- return /* @__PURE__ */ jsxs(
5658
- "div",
5659
- {
5660
- ref,
5661
- className: cn(
5662
- "inline-flex flex-col items-center gap-[var(--cmp-progress-circular-gap)]",
5663
- className
5664
- ),
5665
- style,
5666
- children: [
5667
- /* @__PURE__ */ jsxs("div", { className: cn(innerValue && "relative"), children: [
5668
- /* @__PURE__ */ jsxs(
5669
- "svg",
5670
- {
5671
- viewBox: `0 0 ${VIEWBOX} ${VIEWBOX}`,
5672
- xmlns: "http://www.w3.org/2000/svg",
5673
- className: cn(
5674
- "h-[80px] w-[80px]",
5675
- indeterminate && "origin-center animate-circle-spin"
5676
- ),
5677
- children: [
5678
- /* @__PURE__ */ jsx(
5679
- "circle",
5680
- {
5681
- cx: c,
5682
- cy: c,
5683
- r: RADIUS,
5684
- fill: "none",
5685
- strokeWidth: STROKE,
5686
- style: { stroke: colors.track }
5687
- }
5688
- ),
5689
- /* @__PURE__ */ jsx(
5690
- "circle",
5691
- {
5692
- cx: c,
5693
- cy: c,
5694
- r: RADIUS,
5695
- fill: "none",
5696
- strokeWidth: STROKE,
5697
- strokeLinecap: "round",
5698
- className: cn(
5699
- "origin-center",
5700
- indeterminate ? "animate-circle-arc" : "-rotate-90 transition-[stroke-dasharray] duration-[400ms] ease-linear"
5701
- ),
5702
- style: {
5703
- stroke: colors.arc,
5704
- ...indeterminate ? {} : { strokeDasharray: `${filled} ${CIRCUMFERENCE}`, strokeDashoffset: 0 }
5705
- }
5706
- }
5707
- )
5708
- ]
5709
- }
5710
- ),
5711
- showPercent && innerValue && percentNode
5712
- ] }),
5713
- showPercent && !innerValue && percentNode,
5714
- label && /* @__PURE__ */ jsx("span", { className: "text-center text-[12px] font-normal leading-[20px] text-[color:var(--cmp-progress-color-label)]", children: label })
5715
- ]
5716
- }
5717
- );
5718
- }
5719
- );
5720
5814
 
5721
5815
  // src/lib/global-overlay.ts
5722
5816
  var GLOBAL_OVERLAY_ATTR = "data-s-global-overlay";
@@ -6202,10 +6296,15 @@ function SSwitch({
6202
6296
  }
6203
6297
  );
6204
6298
  }
6299
+ var SIZE_CLASSES = {
6300
+ xs: "h-[24px] px-[8px] text-[12px] font-normal leading-[20px]",
6301
+ sm: "h-[28px] px-[12px] text-[14px] font-medium leading-[24px]"
6302
+ };
6205
6303
  function SToggle({
6206
6304
  value = false,
6207
6305
  label = "",
6208
6306
  disabled = false,
6307
+ size = "sm",
6209
6308
  onValueChange,
6210
6309
  className,
6211
6310
  style
@@ -6221,7 +6320,8 @@ function SToggle({
6221
6320
  "aria-pressed": value,
6222
6321
  onClick: () => !disabled && onValueChange?.(!value),
6223
6322
  className: cn(
6224
- "box-border inline-flex h-[28px] items-center justify-center whitespace-nowrap rounded-full border border-solid px-[12px] text-[14px] font-medium leading-[24px] transition-colors",
6323
+ "box-border inline-flex items-center justify-center whitespace-nowrap rounded-full border border-solid transition-colors",
6324
+ SIZE_CLASSES[size],
6225
6325
  disabled ? "cursor-not-allowed" : "cursor-pointer",
6226
6326
  // 미선택(off) hover 시 파란 채움 + 흰 글자
6227
6327
  !disabled && !value && "hover:!bg-[var(--cmp-toggle-bg-hover)] hover:!text-[color:var(--cmp-toggle-content-hover)] hover:!border-[color:var(--cmp-toggle-bg-hover)]",
@@ -16360,6 +16460,6 @@ function STimeRangePicker({
16360
16460
  );
16361
16461
  }
16362
16462
 
16363
- export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, PAGE_BACKGROUNDS, RangeCalendar, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, findGnbAncestors, findGnbRailValue, isColorKey, loading, resolveColor, useSLayout };
16463
+ export { BADGE_COLORS, BUTTON_COLORS, BUTTON_SIZES, COLOR_KEYS, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, ICONS, IMAGE_FITS, PAGE_BACKGROUNDS, RangeCalendar, SActionModal, SBadge, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCallout, SCard, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SDatePicker, SDateRangePicker, SDivider, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGuide, SIcon, SImage, SInput, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLayout, SLayoutContext, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoadingViewport, SModal, SModalOutlet, SNumberInput, SPage, SPagination, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSplitter2 as SSplitter, SStepper, SSwitch, STEPPER_SIZES, STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, findGnbAncestors, findGnbRailValue, isColorKey, loading, resolveColor, useSLayout };
16364
16464
  //# sourceMappingURL=index.js.map
16365
16465
  //# sourceMappingURL=index.js.map