sellmate-design-system-react 9.0.0-beta.89 → 9.0.0-beta.90

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.js CHANGED
@@ -12,6 +12,7 @@ import * as RDropdown5 from '@radix-ui/react-dropdown-menu';
12
12
  import * as RSwitch from '@radix-ui/react-switch';
13
13
  import * as RDialog from '@radix-ui/react-dialog';
14
14
  import * as Ariakit from '@ariakit/react';
15
+ import * as RSlider from '@radix-ui/react-slider';
15
16
 
16
17
  var isSdSpacing = (value) => /^sd-\d+$/.test(value);
17
18
  var SD_SPACING_GROUPS = [
@@ -4870,10 +4871,16 @@ var ALIGN = {
4870
4871
  end: "flex-end"
4871
4872
  };
4872
4873
  var FOCUS_RING_SHADOW = "0px 0px 4px 0px #0071ff66";
4874
+ var fieldLabelId = (controlId) => `${controlId}-label`;
4875
+ function useFieldControlId(id) {
4876
+ const autoId = useId();
4877
+ return id ?? autoId;
4878
+ }
4873
4879
  var cssLen = (v) => v === void 0 || v === "" || v === 0 ? void 0 : typeof v === "number" ? `${v}px` : v;
4874
4880
  var SField = /* @__PURE__ */ forwardRef(function SField2({
4875
4881
  name,
4876
4882
  label = "",
4883
+ controlId,
4877
4884
  subLabel = "",
4878
4885
  icon,
4879
4886
  iconColor,
@@ -4996,7 +5003,19 @@ var SField = /* @__PURE__ */ forwardRef(function SField2({
4996
5003
  style: { marginRight: s.labelGap }
4997
5004
  }
4998
5005
  ),
4999
- /* @__PURE__ */ jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap", children: label }),
5006
+ /* @__PURE__ */ jsx(
5007
+ "label",
5008
+ {
5009
+ id: controlId ? fieldLabelId(controlId) : void 0,
5010
+ htmlFor: controlId,
5011
+ className: "min-w-0 overflow-hidden text-ellipsis whitespace-nowrap",
5012
+ onClick: () => {
5013
+ const control = controlId ? document.getElementById(controlId) : null;
5014
+ if (control && !("labels" in control)) control.focus();
5015
+ },
5016
+ children: label
5017
+ }
5018
+ ),
5000
5019
  subLabel !== "" && // field 라벨 토큰이 아니라 기본 타이포 토큰을 쓴다 — 보조 라벨은 굵기·색이 라벨과
5001
5020
  // 따로 가므로 field 토큰에 묶지 않는다. 크기도 size 와 무관하게 body/sm 고정.
5002
5021
  /* @__PURE__ */ jsx(
@@ -5148,6 +5167,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
5148
5167
  const minHeight = heightForRows(MIN_ROWS);
5149
5168
  const maxHeight = autogrow && maxRows != null ? heightForRows(maxRows) : void 0;
5150
5169
  const [ruleError, setRuleError] = useState("");
5170
+ const controlId = useFieldControlId(rest.id);
5151
5171
  const innerRef = useRef(null);
5152
5172
  const setRefs2 = useCallback(
5153
5173
  (node) => {
@@ -5189,6 +5209,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
5189
5209
  SField,
5190
5210
  {
5191
5211
  label,
5212
+ controlId,
5192
5213
  labelPosition,
5193
5214
  subLabel,
5194
5215
  labelWidth,
@@ -5215,6 +5236,7 @@ var STextarea = /* @__PURE__ */ forwardRef(function STextarea2({
5215
5236
  "textarea",
5216
5237
  {
5217
5238
  ref: setRefs2,
5239
+ id: controlId,
5218
5240
  value: value ?? "",
5219
5241
  rows,
5220
5242
  disabled,
@@ -5265,7 +5287,9 @@ var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
5265
5287
  placeholder = DEFAULT_PLACEHOLDER,
5266
5288
  disabled = false,
5267
5289
  onSend,
5290
+ hasAttachments = false,
5268
5291
  onAttach,
5292
+ onPasteFiles,
5269
5293
  busy = false,
5270
5294
  onStop,
5271
5295
  footerAction,
@@ -5275,17 +5299,26 @@ var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
5275
5299
  textareaClassName,
5276
5300
  ...rest
5277
5301
  }, ref) {
5278
- const canSend = !disabled && !busy && value.trim() !== "";
5302
+ const hasText = value.trim() !== "";
5303
+ const canSend = !disabled && !busy && (hasText || hasAttachments);
5279
5304
  const send = useCallback(() => {
5280
5305
  if (!canSend) return;
5281
- onSend?.(value);
5282
- }, [canSend, onSend, value]);
5306
+ onSend?.(hasText ? value : "");
5307
+ }, [canSend, hasText, onSend, value]);
5283
5308
  const handleKeyDown = (e) => {
5284
5309
  rest.onKeyDown?.(e);
5285
5310
  if (e.key !== "Enter" || e.shiftKey || e.nativeEvent.isComposing) return;
5286
5311
  e.preventDefault();
5287
5312
  send();
5288
5313
  };
5314
+ const handlePaste = (e) => {
5315
+ rest.onPaste?.(e);
5316
+ if (onPasteFiles == null || e.defaultPrevented) return;
5317
+ const files = Array.from(e.clipboardData.files);
5318
+ if (files.length === 0) return;
5319
+ e.preventDefault();
5320
+ onPasteFiles(files);
5321
+ };
5289
5322
  return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col bg-(--cmp-chatInput-bg)", className), style, children: [
5290
5323
  /* @__PURE__ */ jsxs("div", { className: "flex items-end gap-(--cmp-chatInput-gap) p-(--cmp-chatInput-padding)", children: [
5291
5324
  onAttach != null && /* @__PURE__ */ jsx(
@@ -5316,7 +5349,8 @@ var SChatInputImpl = /* @__PURE__ */ forwardRef(function SChatInput({
5316
5349
  textareaClassName,
5317
5350
  textareaStyle: { minHeight: TEXTAREA_MIN_HEIGHT },
5318
5351
  ...rest,
5319
- onKeyDown: handleKeyDown
5352
+ onKeyDown: handleKeyDown,
5353
+ onPaste: handlePaste
5320
5354
  }
5321
5355
  ),
5322
5356
  busy ? /* @__PURE__ */ jsx(
@@ -5577,6 +5611,7 @@ var SChatMessageImpl = /* @__PURE__ */ forwardRef(function SChatMessage({
5577
5611
  readStatus,
5578
5612
  avatarSrc,
5579
5613
  avatarAlt,
5614
+ showAvatar = true,
5580
5615
  continued = false,
5581
5616
  variant = "default",
5582
5617
  actions,
@@ -5607,7 +5642,7 @@ var SChatMessageImpl = /* @__PURE__ */ forwardRef(function SChatMessage({
5607
5642
  ),
5608
5643
  ...rest,
5609
5644
  children: [
5610
- !outgoing && /* @__PURE__ */ jsx(Avatar, { src: avatarSrc, alt: avatarAlt, placeholder: continued }),
5645
+ !outgoing && showAvatar && /* @__PURE__ */ jsx(Avatar, { src: avatarSrc, alt: avatarAlt, placeholder: continued }),
5611
5646
  /* @__PURE__ */ jsxs(
5612
5647
  "div",
5613
5648
  {
@@ -6754,6 +6789,7 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
6754
6789
  className,
6755
6790
  onMouseEnter,
6756
6791
  onMouseLeave,
6792
+ onKeyDown,
6757
6793
  ...rest
6758
6794
  }, ref) {
6759
6795
  const [hovered, setHovered] = useState(false);
@@ -6777,15 +6813,29 @@ var SListItemImpl = /* @__PURE__ */ forwardRef(function SListItem({
6777
6813
  setHovered(false);
6778
6814
  onMouseLeave?.(event);
6779
6815
  };
6816
+ const pressable = isInteractive && rest.onClick != null;
6817
+ const handleKeyDown = (event) => {
6818
+ onKeyDown?.(event);
6819
+ if (!pressable || event.defaultPrevented || event.target !== event.currentTarget) return;
6820
+ if (event.key === "Enter" || event.key === " ") {
6821
+ event.preventDefault();
6822
+ event.currentTarget.click();
6823
+ }
6824
+ };
6780
6825
  return /* @__PURE__ */ jsxs(
6781
6826
  "div",
6782
6827
  {
6783
6828
  ref,
6784
6829
  "aria-disabled": disabled || void 0,
6830
+ role: pressable ? "button" : void 0,
6831
+ tabIndex: pressable ? 0 : void 0,
6785
6832
  onMouseEnter: handleMouseEnter,
6786
6833
  onMouseLeave: handleMouseLeave,
6834
+ onKeyDown: handleKeyDown,
6787
6835
  className: cn(
6788
6836
  "group/list-item relative flex w-full items-center justify-between bg-(--cmp-listItem-bg-default) text-left text-(--cmp-listItem-text-default)",
6837
+ // 링을 안쪽으로 그린다 — bordered 항목은 overflow-hidden 이라 바깥 링이 잘린다
6838
+ pressable && "focus-visible:outline focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--sys-color-border-accent)",
6789
6839
  titleTypo,
6790
6840
  disabled ? "pointer-events-none cursor-not-allowed text-(--sys-color-disabled-text)" : isSelected ? cn(
6791
6841
  "cursor-pointer text-(--cmp-listItem-text-selected)",
@@ -7469,6 +7519,7 @@ function SCheckbox({
7469
7519
  val,
7470
7520
  onValueChange,
7471
7521
  label = "",
7522
+ ariaLabel,
7472
7523
  disabled = false,
7473
7524
  inverse = false,
7474
7525
  className,
@@ -7509,6 +7560,7 @@ function SCheckbox({
7509
7560
  checked: state2,
7510
7561
  disabled,
7511
7562
  onCheckedChange: handleChange,
7563
+ "aria-label": ariaLabel,
7512
7564
  className: cn(
7513
7565
  "flex h-[var(--cmp-checkbox-size)] w-[var(--cmp-checkbox-size)] items-center justify-center rounded-[var(--cmp-checkbox-radius)] border-[length:var(--cmp-checkbox-borderWidth)] border-solid bg-[var(--cb-bg)] border-[color:var(--cb-border)] outline-none",
7514
7566
  disabled ? "cursor-not-allowed" : "cursor-pointer",
@@ -15709,6 +15761,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
15709
15761
  const baseId = useId();
15710
15762
  const listboxId = `${baseId}-listbox`;
15711
15763
  const activeOptionId = `${baseId}-active-option`;
15764
+ const triggerId = `${baseId}-trigger`;
15712
15765
  const [win, setWin] = useState({ start: 0, end: 0, top: 0, bottom: 0 });
15713
15766
  const winRef = useRef(win);
15714
15767
  winRef.current = win;
@@ -16195,6 +16248,7 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
16195
16248
  SField,
16196
16249
  {
16197
16250
  label,
16251
+ controlId: triggerId,
16198
16252
  labelPosition,
16199
16253
  subLabel,
16200
16254
  labelWidth,
@@ -16220,8 +16274,10 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
16220
16274
  "button",
16221
16275
  {
16222
16276
  ref: triggerRef,
16277
+ id: triggerId,
16223
16278
  type: "button",
16224
16279
  disabled: effectiveDisabled,
16280
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerId}` : void 0,
16225
16281
  "aria-haspopup": "listbox",
16226
16282
  "aria-expanded": open,
16227
16283
  "aria-controls": open ? listboxId : void 0,
@@ -16317,7 +16373,12 @@ var SSelectImpl = /* @__PURE__ */ forwardRef(function SSelect({
16317
16373
  event.preventDefault();
16318
16374
  requestAnimationFrame(() => searchInputRef.current?.focus());
16319
16375
  },
16320
- onPointerDownOutside: () => {
16376
+ onPointerDownOutside: (event) => {
16377
+ const target = event.target;
16378
+ if (label && target?.closest?.(`[id="${fieldLabelId(triggerId)}"]`)) {
16379
+ event.preventDefault();
16380
+ return;
16381
+ }
16321
16382
  dismissedByPointerRef.current = true;
16322
16383
  },
16323
16384
  onCloseAutoFocus: (event) => {
@@ -18237,6 +18298,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
18237
18298
  }, ref) {
18238
18299
  const [visible, setVisible] = useState(false);
18239
18300
  const [ruleError, setRuleError] = useState("");
18301
+ const controlId = useFieldControlId(rest.id);
18240
18302
  const f = FONT2[size];
18241
18303
  const isPassword = type === "password";
18242
18304
  const inputType = isPassword ? visible ? "text" : "password" : type;
@@ -18261,6 +18323,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
18261
18323
  SField,
18262
18324
  {
18263
18325
  label,
18326
+ controlId,
18264
18327
  labelPosition,
18265
18328
  subLabel,
18266
18329
  labelWidth,
@@ -18300,6 +18363,7 @@ var SInput = /* @__PURE__ */ forwardRef(function SInput2({
18300
18363
  "input",
18301
18364
  {
18302
18365
  ref: mergeRefs(ref, valueTooltip.valueRef),
18366
+ id: controlId,
18303
18367
  type: inputType,
18304
18368
  value: value ?? "",
18305
18369
  disabled,
@@ -18475,6 +18539,7 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
18475
18539
  const numValue = applyDecimalLimit(toNumber(value), decimalLimit);
18476
18540
  const [display, setDisplay] = useState(() => formatWithCommas(numValue));
18477
18541
  const [ruleError, setRuleError] = useState("");
18542
+ const controlId = useFieldControlId();
18478
18543
  const [rangeError, setRangeError] = useState("");
18479
18544
  const innerRef = useRef(null);
18480
18545
  const valueTooltip = useTruncatedValueTooltip({ enabled: readOnly && !disabled, text: display });
@@ -18624,6 +18689,7 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
18624
18689
  SField,
18625
18690
  {
18626
18691
  label,
18692
+ controlId,
18627
18693
  labelPosition,
18628
18694
  subLabel,
18629
18695
  labelWidth,
@@ -18663,6 +18729,7 @@ var SNumberInput = /* @__PURE__ */ forwardRef(function SNumberInput2({
18663
18729
  "input",
18664
18730
  {
18665
18731
  ref: setRefs2,
18732
+ id: controlId,
18666
18733
  name,
18667
18734
  type: "text",
18668
18735
  inputMode: allowDecimal ? "decimal" : "numeric",
@@ -19364,6 +19431,8 @@ function SDatePicker({
19364
19431
  }) {
19365
19432
  const portalContainer = usePortalContainer();
19366
19433
  const [open, setOpen] = useState(false);
19434
+ const triggerId = useFieldControlId();
19435
+ const triggerTextId = `${triggerId}-text`;
19367
19436
  const [focused, setFocused] = useState(false);
19368
19437
  const [ruleError, setRuleError] = useState("");
19369
19438
  const hasValue = value != null && value !== "";
@@ -19420,6 +19489,7 @@ function SDatePicker({
19420
19489
  return /* @__PURE__ */ jsx(
19421
19490
  SField,
19422
19491
  {
19492
+ controlId: triggerId,
19423
19493
  label,
19424
19494
  labelPosition,
19425
19495
  subLabel,
@@ -19446,8 +19516,10 @@ function SDatePicker({
19446
19516
  /* @__PURE__ */ jsx(RPopover13.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
19447
19517
  "div",
19448
19518
  {
19519
+ id: triggerId,
19449
19520
  role: "button",
19450
19521
  "aria-disabled": disabled,
19522
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerTextId}` : void 0,
19451
19523
  tabIndex: disabled ? -1 : 0,
19452
19524
  "data-name": name,
19453
19525
  onFocus: () => setFocused(true),
@@ -19477,6 +19549,7 @@ function SDatePicker({
19477
19549
  /* @__PURE__ */ jsx(
19478
19550
  "span",
19479
19551
  {
19552
+ id: triggerTextId,
19480
19553
  className: "flex-1 truncate text-center",
19481
19554
  style: {
19482
19555
  minWidth: dims.minW,
@@ -19903,6 +19976,8 @@ function SDateRangePicker({
19903
19976
  }) {
19904
19977
  const portalContainer = usePortalContainer();
19905
19978
  const [open, setOpen] = useState(false);
19979
+ const triggerId = useFieldControlId();
19980
+ const triggerTextId = `${triggerId}-text`;
19906
19981
  const [ruleError, setRuleError] = useState("");
19907
19982
  const [pendingStart, setPendingStart] = useState(null);
19908
19983
  const hasValue = value != null && value[0] !== "" && value[1] !== "";
@@ -19959,6 +20034,7 @@ function SDateRangePicker({
19959
20034
  return /* @__PURE__ */ jsx(
19960
20035
  SField,
19961
20036
  {
20037
+ controlId: triggerId,
19962
20038
  label,
19963
20039
  labelPosition,
19964
20040
  subLabel,
@@ -19994,8 +20070,10 @@ function SDateRangePicker({
19994
20070
  /* @__PURE__ */ jsx(RPopover13.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
19995
20071
  "div",
19996
20072
  {
20073
+ id: triggerId,
19997
20074
  role: "button",
19998
20075
  "aria-disabled": disabled,
20076
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerTextId}` : void 0,
19999
20077
  tabIndex: disabled ? -1 : 0,
20000
20078
  "data-name": name,
20001
20079
  onKeyDown: (event) => {
@@ -20023,6 +20101,7 @@ function SDateRangePicker({
20023
20101
  /* @__PURE__ */ jsx(
20024
20102
  "span",
20025
20103
  {
20104
+ id: triggerTextId,
20026
20105
  className: cn(
20027
20106
  "flex-1 items-center",
20028
20107
  hasDisplay ? "flex" : "block truncate text-center"
@@ -20285,6 +20364,8 @@ function SFilePicker({
20285
20364
  }) {
20286
20365
  const autoId = useId();
20287
20366
  const resolvedName = name ?? autoId;
20367
+ const triggerId = `${autoId}-trigger`;
20368
+ const displayTextId = `${autoId}-text`;
20288
20369
  const inputRef = useRef(null);
20289
20370
  const contentBoxRef = useRef(null);
20290
20371
  const [ruleError, setRuleError] = useState("");
@@ -20385,10 +20466,12 @@ function SFilePicker({
20385
20466
  /* @__PURE__ */ jsxs(
20386
20467
  "button",
20387
20468
  {
20469
+ id: triggerId,
20388
20470
  type: "button",
20389
20471
  disabled,
20390
20472
  onClick: open,
20391
20473
  "aria-label": placeholder,
20474
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${displayTextId}` : void 0,
20392
20475
  className: cn(
20393
20476
  "flex min-w-0 flex-1 items-center bg-transparent text-left",
20394
20477
  gapCls,
@@ -20406,6 +20489,7 @@ function SFilePicker({
20406
20489
  /* @__PURE__ */ jsx(
20407
20490
  "span",
20408
20491
  {
20492
+ id: displayTextId,
20409
20493
  className: cn(
20410
20494
  "min-w-0 flex-1 truncate text-[12px]",
20411
20495
  inlinePlaceholder && "text-[color:var(--cmp-filepicker-text-placeholder)] transition-colors group-hover/filepicker:text-[color:var(--cmp-filepicker-text-default)]"
@@ -20453,6 +20537,7 @@ function SFilePicker({
20453
20537
  {
20454
20538
  borderless: inline,
20455
20539
  label,
20540
+ controlId: triggerId,
20456
20541
  labelPosition,
20457
20542
  subLabel,
20458
20543
  labelWidth,
@@ -25009,8 +25094,12 @@ var EditorBody = /* @__PURE__ */ forwardRef(function EditorBody2({
25009
25094
  bubbleMenu,
25010
25095
  onImageUpload,
25011
25096
  editorClassName,
25012
- editorStyle
25097
+ editorStyle,
25098
+ controlId,
25099
+ labelled
25013
25100
  }, ref) {
25101
+ const labelledRef = useRef(labelled);
25102
+ labelledRef.current = labelled;
25014
25103
  const placeholderRef = useRef(placeholder);
25015
25104
  placeholderRef.current = placeholder;
25016
25105
  const handlers = useRef({ onInput, onFocusChange });
@@ -25025,6 +25114,10 @@ var EditorBody = /* @__PURE__ */ forwardRef(function EditorBody2({
25025
25114
  editable,
25026
25115
  // 소비 앱이 Next.js RSC 라면 첫 렌더가 서버에서 일어난다 — 즉시 렌더하면 하이드레이션이 어긋난다
25027
25116
  immediatelyRender: false,
25117
+ // 본문은 contenteditable 이라 <label for> 가 닿지 않는다 — 레이블 id 로 이름을 잇는다
25118
+ editorProps: {
25119
+ attributes: () => labelledRef.current ? { "id": controlId, "aria-labelledby": fieldLabelId(controlId) } : { id: controlId }
25120
+ },
25028
25121
  onUpdate: ({ editor: e }) => {
25029
25122
  const html = e.isEmpty ? "" : e.getHTML();
25030
25123
  htmlRef.current = html;
@@ -25243,6 +25336,7 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
25243
25336
  }, ref) {
25244
25337
  const [ruleError, setRuleError] = useState("");
25245
25338
  const [selfFocused, setSelfFocused] = useState(false);
25339
+ const controlId = useFieldControlId();
25246
25340
  const htmlRef = useRef(value ?? defaultValue ?? "");
25247
25341
  const bodyRef = useRef(null);
25248
25342
  const pendingFocusRef = useRef(false);
@@ -25313,6 +25407,7 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
25313
25407
  {
25314
25408
  name,
25315
25409
  label,
25410
+ controlId,
25316
25411
  labelPosition,
25317
25412
  subLabel,
25318
25413
  labelWidth,
@@ -25376,6 +25471,8 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
25376
25471
  toolbar: resolvedToolbar,
25377
25472
  bubbleMenu: resolvedBubbleMenu,
25378
25473
  onImageUpload,
25474
+ controlId,
25475
+ labelled: !!label,
25379
25476
  editorClassName,
25380
25477
  editorStyle
25381
25478
  }
@@ -25383,6 +25480,302 @@ var SEditor = /* @__PURE__ */ forwardRef(function SEditor2({
25383
25480
  }
25384
25481
  );
25385
25482
  });
25483
+ var TRACK = 6;
25484
+ var THUMB = 16;
25485
+ var PRESS_SCALE = 1.2;
25486
+ var PRESS_GROW = THUMB * (PRESS_SCALE - 1) / 2;
25487
+ var SHADOW_Y = 2;
25488
+ var SHADOW_BLUR = 4;
25489
+ var KNOB_BLEED = Math.ceil(PRESS_GROW + SHADOW_BLUR);
25490
+ var MARK_DOT = 4;
25491
+ var BUBBLE_HEIGHT = 18;
25492
+ var BUBBLE_GAP = 4;
25493
+ var ROW_HEIGHT = { sm: 28, md: 36 };
25494
+ var COLOR = {
25495
+ track: "var(--sys-color-border-default)",
25496
+ trackDisabled: "var(--sys-color-disabled-bg)",
25497
+ range: "var(--sys-color-bg-accent)",
25498
+ rangeDisabled: "var(--color-brilliantblue-40)",
25499
+ thumbBg: "var(--sys-color-bg-frame)",
25500
+ markOn: "var(--sys-color-bg-frame)",
25501
+ markOff: "var(--sys-color-border-strong)",
25502
+ markOffDisabled: "var(--sys-color-disabled-border)",
25503
+ markLabel: "var(--sys-color-fg-tertiary)",
25504
+ bubbleBg: "var(--sys-color-bg-deep)",
25505
+ bubbleText: "var(--sys-color-fg-inverse)"
25506
+ };
25507
+ var thumbAlignedLeft = (pct) => `calc(${pct}% + ${THUMB / 2 * (1 - pct / 50)}px)`;
25508
+ var toPercent = (v, min, max) => max === min ? 0 : (v - min) / (max - min) * 100;
25509
+ var SSlider = /* @__PURE__ */ forwardRef(function SSlider2({
25510
+ value,
25511
+ onValueChange,
25512
+ onValueCommit,
25513
+ min = 0,
25514
+ max = 100,
25515
+ step = 1,
25516
+ marks,
25517
+ showValue = "drag",
25518
+ formatValue = String,
25519
+ size = "sm",
25520
+ rules,
25521
+ name,
25522
+ status,
25523
+ label,
25524
+ labelPosition,
25525
+ subLabel,
25526
+ labelWidth,
25527
+ icon,
25528
+ iconColor,
25529
+ labelTooltip,
25530
+ labelTooltipProps,
25531
+ hint,
25532
+ error,
25533
+ errorMessage,
25534
+ width,
25535
+ disabled = false,
25536
+ readOnly = false,
25537
+ className,
25538
+ style
25539
+ }, ref) {
25540
+ const isRange = Array.isArray(value);
25541
+ const values = isRange ? value : [value ?? min];
25542
+ const toOut = (v) => isRange ? [v[0], v[1]] : v[0];
25543
+ const [ruleError, setRuleError] = useState("");
25544
+ useFormField({
25545
+ name,
25546
+ validate: () => {
25547
+ const msg = runRules(value, rules);
25548
+ setRuleError(msg);
25549
+ return msg === "";
25550
+ },
25551
+ resetValidation: () => setRuleError("")
25552
+ });
25553
+ const resolvedError = error || ruleError !== "";
25554
+ const resolvedErrorMessage = ruleError !== "" ? ruleError : errorMessage;
25555
+ const resolvedStatus = status ?? (rules && rules.length > 0 ? ruleError !== "" ? "error" : void 0 : void 0);
25556
+ const [dragging, setDragging] = useState(false);
25557
+ const [focusIndex, setFocusIndex] = useState(null);
25558
+ const thumbId = useFieldControlId();
25559
+ const wrapRef = useRef(null);
25560
+ const bubbleRefs = useRef([]);
25561
+ const layoutKey = `${values.join(",")}|${values.map(formatValue).join(",")}`;
25562
+ useLayoutEffect(() => {
25563
+ const wrap = wrapRef.current;
25564
+ if (!wrap) return;
25565
+ const layout = () => {
25566
+ const outer = wrap.clientWidth;
25567
+ const track = outer - KNOB_BLEED * 2;
25568
+ bubbleRefs.current.forEach((el, i) => {
25569
+ if (!el || values[i] === void 0) return;
25570
+ const pct = toPercent(values[i], min, max);
25571
+ const center = KNOB_BLEED + track * pct / 100 + THUMB / 2 * (1 - pct / 50);
25572
+ const half = el.offsetWidth / 2;
25573
+ const shift = center - half < 0 ? half - center : center + half > outer ? outer - half - center : 0;
25574
+ el.style.transform = `translateX(calc(-50% + ${shift}px))`;
25575
+ });
25576
+ };
25577
+ layout();
25578
+ const ro = new ResizeObserver(layout);
25579
+ ro.observe(wrap);
25580
+ return () => ro.disconnect();
25581
+ }, [layoutKey, min, max, showValue]);
25582
+ const rowHeight = ROW_HEIGHT[size];
25583
+ const rowGap = (rowHeight - THUMB) / 2;
25584
+ const topSpace = Math.max(
25585
+ 0,
25586
+ KNOB_BLEED - rowGap,
25587
+ showValue === "none" ? 0 : BUBBLE_HEIGHT + BUBBLE_GAP + PRESS_GROW - rowGap
25588
+ );
25589
+ const bottomSpace = Math.max(0, KNOB_BLEED + SHADOW_Y - rowGap);
25590
+ const markList = marks === true ? Array.from({ length: Math.floor((max - min) / step) + 1 }, (_, i) => ({
25591
+ value: min + i * step
25592
+ })) : Array.isArray(marks) ? marks.filter((m) => m.value >= min && m.value <= max) : [];
25593
+ const hasMarkLabels = markList.some((m) => m.label);
25594
+ const [rangeStart, rangeEnd] = isRange ? [values[0], values[1]] : [min, values[0]];
25595
+ const interactive = !disabled && !readOnly;
25596
+ return /* @__PURE__ */ jsx(
25597
+ SField,
25598
+ {
25599
+ name,
25600
+ label,
25601
+ controlId: thumbId,
25602
+ labelPosition,
25603
+ subLabel,
25604
+ labelWidth,
25605
+ labelHeight: topSpace > 0 ? rowHeight + topSpace * 2 : void 0,
25606
+ icon,
25607
+ iconColor,
25608
+ labelTooltip,
25609
+ labelTooltipProps,
25610
+ hint,
25611
+ size,
25612
+ error: resolvedError,
25613
+ status: resolvedStatus,
25614
+ errorMessage: resolvedErrorMessage,
25615
+ width,
25616
+ disabled,
25617
+ readOnly,
25618
+ borderless: true,
25619
+ multiline: true,
25620
+ className,
25621
+ style,
25622
+ children: /* @__PURE__ */ jsxs(
25623
+ "div",
25624
+ {
25625
+ ref: wrapRef,
25626
+ className: "flex w-full flex-col",
25627
+ style: { padding: `${topSpace}px ${KNOB_BLEED}px ${bottomSpace}px` },
25628
+ children: [
25629
+ /* @__PURE__ */ jsxs(
25630
+ RSlider.Root,
25631
+ {
25632
+ ref,
25633
+ value: values,
25634
+ min,
25635
+ max,
25636
+ step,
25637
+ disabled,
25638
+ minStepsBetweenThumbs: 0,
25639
+ onValueChange: (v) => {
25640
+ if (!interactive) return;
25641
+ const next = toOut(v);
25642
+ onValueChange?.(next);
25643
+ if (ruleError !== "") setRuleError(runRules(next, rules));
25644
+ },
25645
+ onValueCommit: (v) => {
25646
+ if (!interactive) return;
25647
+ const next = toOut(v);
25648
+ onValueCommit?.(next);
25649
+ if (rules && rules.length > 0) setRuleError(runRules(next, rules));
25650
+ },
25651
+ onPointerDown: () => interactive && setDragging(true),
25652
+ onPointerUp: () => setDragging(false),
25653
+ onLostPointerCapture: () => setDragging(false),
25654
+ className: cn(
25655
+ "relative flex w-full touch-none items-center select-none",
25656
+ // 읽기 전용은 포인터로 잡히지 않게 한다 — 키보드 포커스는 남겨 값을 읽을 수 있게 한다
25657
+ readOnly && "pointer-events-none"
25658
+ ),
25659
+ style: { height: rowHeight },
25660
+ children: [
25661
+ /* @__PURE__ */ jsx(
25662
+ RSlider.Track,
25663
+ {
25664
+ className: "relative grow overflow-hidden rounded-full",
25665
+ style: { height: TRACK, background: disabled ? COLOR.trackDisabled : COLOR.track },
25666
+ children: /* @__PURE__ */ jsx(
25667
+ RSlider.Range,
25668
+ {
25669
+ className: "absolute h-full",
25670
+ style: { background: disabled ? COLOR.rangeDisabled : COLOR.range }
25671
+ }
25672
+ )
25673
+ }
25674
+ ),
25675
+ markList.map((m) => {
25676
+ const on = m.value >= rangeStart && m.value <= rangeEnd;
25677
+ return /* @__PURE__ */ jsx(
25678
+ "span",
25679
+ {
25680
+ "aria-hidden": true,
25681
+ className: "pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full",
25682
+ style: {
25683
+ left: thumbAlignedLeft(toPercent(m.value, min, max)),
25684
+ width: MARK_DOT,
25685
+ height: MARK_DOT,
25686
+ background: on ? COLOR.markOn : disabled ? COLOR.markOffDisabled : COLOR.markOff
25687
+ }
25688
+ },
25689
+ m.value
25690
+ );
25691
+ }),
25692
+ values.map((v, i) => {
25693
+ const pressed = interactive && dragging && focusIndex === i;
25694
+ return /* @__PURE__ */ jsxs(
25695
+ RSlider.Thumb,
25696
+ {
25697
+ id: i === 0 ? thumbId : void 0,
25698
+ "aria-label": isRange ? `${label ?? ""} ${i === 0 ? "\uCD5C\uC19F\uAC12" : "\uCD5C\uB313\uAC12"}`.trim() : label,
25699
+ "aria-valuetext": formatValue(v),
25700
+ "aria-readonly": readOnly || void 0,
25701
+ onFocus: () => setFocusIndex(i),
25702
+ onBlur: () => setFocusIndex(null),
25703
+ className: cn(
25704
+ "group/thumb relative block rounded-full outline-none",
25705
+ "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--sys-color-field-border-focus)",
25706
+ interactive ? "cursor-grab active:cursor-grabbing" : disabled && "cursor-not-allowed"
25707
+ ),
25708
+ style: { width: THUMB, height: THUMB },
25709
+ children: [
25710
+ /* @__PURE__ */ jsx(
25711
+ "span",
25712
+ {
25713
+ "aria-hidden": true,
25714
+ className: "absolute inset-0 rounded-full border-3 border-solid shadow-[0_2px_4px_rgba(0,0,0,0.16)] transition-transform duration-150 ease-out",
25715
+ style: {
25716
+ background: COLOR.thumbBg,
25717
+ borderColor: disabled ? COLOR.rangeDisabled : COLOR.range,
25718
+ transform: pressed ? `scale(${PRESS_SCALE})` : void 0
25719
+ }
25720
+ }
25721
+ ),
25722
+ showValue !== "none" && /* @__PURE__ */ jsx(
25723
+ "span",
25724
+ {
25725
+ ref: (el) => {
25726
+ bubbleRefs.current[i] = el;
25727
+ },
25728
+ "aria-hidden": true,
25729
+ className: cn(
25730
+ // 줄 높이로 가운데를 맞추면 줄 상자에 내림 획 자리가 들어 있어 숫자가 위로 1px 가까이 뜬다.
25731
+ // 글자 상자를 대문자 높이~기준선으로 잘라(text-box) 그 상자를 flex 로 가운데 둔다.
25732
+ "typo-body-xs-medium pointer-events-none absolute left-1/2 flex items-center rounded-[6px] px-[6px] whitespace-nowrap transition-opacity",
25733
+ showValue === "always" || pressed ? "opacity-100" : "opacity-0 group-hover/thumb:opacity-100 group-focus-visible/thumb:opacity-100",
25734
+ // 비활성·읽기 전용에서는 조작이 없으므로 drag 말풍선도 띄우지 않는다
25735
+ showValue === "drag" && !interactive && "hidden"
25736
+ ),
25737
+ style: {
25738
+ bottom: `calc(100% + ${BUBBLE_GAP + (pressed ? PRESS_GROW : 0)}px)`,
25739
+ height: BUBBLE_HEIGHT,
25740
+ transform: "translateX(-50%)",
25741
+ background: COLOR.bubbleBg,
25742
+ color: COLOR.bubbleText
25743
+ },
25744
+ children: /* @__PURE__ */ jsx("span", { className: "[text-box:trim-both_cap_alphabetic]", children: formatValue(v) })
25745
+ }
25746
+ )
25747
+ ]
25748
+ },
25749
+ i
25750
+ );
25751
+ })
25752
+ ]
25753
+ }
25754
+ ),
25755
+ hasMarkLabels && /* @__PURE__ */ jsx("div", { className: "relative w-full", style: { height: BUBBLE_HEIGHT }, children: markList.map((m) => {
25756
+ if (!m.label) return null;
25757
+ const pct = toPercent(m.value, min, max);
25758
+ const align = pct <= 0 ? "translateX(0)" : pct >= 100 ? "translateX(-100%)" : "translateX(-50%)";
25759
+ return /* @__PURE__ */ jsx(
25760
+ "span",
25761
+ {
25762
+ className: "typo-body-xs-medium absolute top-0 whitespace-nowrap",
25763
+ style: {
25764
+ left: pct <= 0 ? 0 : pct >= 100 ? "100%" : thumbAlignedLeft(pct),
25765
+ transform: align,
25766
+ color: disabled ? "var(--sys-color-disabled-text)" : COLOR.markLabel
25767
+ },
25768
+ children: m.label
25769
+ },
25770
+ m.value
25771
+ );
25772
+ }) })
25773
+ ]
25774
+ }
25775
+ )
25776
+ }
25777
+ );
25778
+ });
25386
25779
  var CHIPFILTER_LISTBOX_WIDTH = 240;
25387
25780
  var CHIPFILTER_DATE_PRESET_LISTBOX_WIDTH = 246;
25388
25781
  var EDITOR_LISTBOX_MAX_HEIGHT = "min(640px, var(--radix-popover-content-available-height))";
@@ -27263,6 +27656,24 @@ function EmptyItem({ children }) {
27263
27656
  }
27264
27657
  );
27265
27658
  }
27659
+ function splitBySeparators(text, separators) {
27660
+ const seps = separators.filter((s) => s !== "");
27661
+ if (seps.length === 0) return { parts: [], rest: text };
27662
+ const pieces = [];
27663
+ let from = 0;
27664
+ for (let i = 0; i < text.length; ) {
27665
+ const sep = seps.find((s) => text.startsWith(s, i));
27666
+ if (sep) {
27667
+ pieces.push(text.slice(from, i));
27668
+ i += sep.length;
27669
+ from = i;
27670
+ } else {
27671
+ i += 1;
27672
+ }
27673
+ }
27674
+ const parts = pieces.map((p) => p.trim()).filter((p) => p !== "");
27675
+ return { parts, rest: text.slice(from) };
27676
+ }
27266
27677
  var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27267
27678
  values = [],
27268
27679
  onValueChange,
@@ -27273,7 +27684,7 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27273
27684
  disabledChips = [],
27274
27685
  size = "sm",
27275
27686
  disabled = false,
27276
- placeholder = "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D / \uCF64\uB9C8\uB85C \uAD6C\uBD84 / \uB744\uC5B4\uC4F0\uAE30 \uBD88\uAC00)",
27687
+ placeholder: placeholderProp,
27277
27688
  name,
27278
27689
  rules,
27279
27690
  error,
@@ -27286,6 +27697,9 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27286
27697
  recommendedItems = [],
27287
27698
  loadingRecommendedItems = false,
27288
27699
  dropdownMinWidth = 200,
27700
+ commitOnBlur = false,
27701
+ separators,
27702
+ ariaLabel,
27289
27703
  label,
27290
27704
  labelPosition,
27291
27705
  subLabel,
@@ -27301,7 +27715,9 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27301
27715
  className,
27302
27716
  style
27303
27717
  }, ref) {
27718
+ const placeholder = placeholderProp ?? (separators?.includes(",") ? "\uD0DC\uADF8 \uC785\uB825 (Enter\xB7\uCF64\uB9C8\uB85C \uB4F1\uB85D)" : "\uD0DC\uADF8 \uC785\uB825 (Enter\uB85C \uB4F1\uB85D)");
27304
27719
  const autoId = useId();
27720
+ const controlId = `${autoId}-input`;
27305
27721
  const resolvedName = name ?? autoId;
27306
27722
  const listboxId = `${autoId}-listbox`;
27307
27723
  const activeOptionId = `${autoId}-active-option`;
@@ -27348,12 +27764,17 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27348
27764
  const isMax = maxCount != null && values.length >= maxCount;
27349
27765
  const resolvedDropdownMinWidth = dropdownMinWidth == null ? void 0 : typeof dropdownMinWidth === "number" ? `${dropdownMinWidth}px` : dropdownMinWidth;
27350
27766
  const commit = (next) => onValueChange?.(next);
27767
+ const addChips = (vs, rest = "") => {
27768
+ const room = maxCount == null ? vs.length : Math.max(maxCount - values.length, 0);
27769
+ const added = vs.slice(0, room);
27770
+ if (added.length > 0) commit([...values, ...added]);
27771
+ setInputValue(rest);
27772
+ setActiveIndex(-1);
27773
+ onInput?.(rest);
27774
+ };
27351
27775
  const addChip = (v) => {
27352
27776
  if (maxCount != null && values.length >= maxCount) return;
27353
- commit([...values, v]);
27354
- setInputValue("");
27355
- setActiveIndex(-1);
27356
- onInput?.("");
27777
+ addChips([v]);
27357
27778
  inputRef.current?.focus();
27358
27779
  };
27359
27780
  const removeChip = (i) => {
@@ -27438,6 +27859,7 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27438
27859
  SField,
27439
27860
  {
27440
27861
  label,
27862
+ controlId,
27441
27863
  labelPosition,
27442
27864
  subLabel,
27443
27865
  labelWidth,
@@ -27536,7 +27958,9 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27536
27958
  "input",
27537
27959
  {
27538
27960
  ref: inputRef,
27961
+ id: controlId,
27539
27962
  name: resolvedName,
27963
+ "aria-label": ariaLabel,
27540
27964
  size: 1,
27541
27965
  role: "combobox",
27542
27966
  "aria-expanded": showDropdown,
@@ -27560,8 +27984,24 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27560
27984
  placeholder: values.length === 0 ? placeholder : "",
27561
27985
  disabled,
27562
27986
  value: inputValue,
27987
+ onPaste: (e) => {
27988
+ if (!separators) return;
27989
+ const pasted = e.clipboardData.getData("text");
27990
+ if (!separators.some((s) => s !== "" && pasted.includes(s))) return;
27991
+ e.preventDefault();
27992
+ const { parts, rest } = splitBySeparators(inputValue + pasted, separators);
27993
+ const tail = rest.trim();
27994
+ addChips(tail === "" ? parts : [...parts, tail]);
27995
+ },
27563
27996
  onChange: (e) => {
27564
27997
  const nextValue = e.target.value;
27998
+ if (separators && !isComposingRef.current) {
27999
+ const { parts, rest } = splitBySeparators(nextValue, separators);
28000
+ if (parts.length > 0 || rest !== nextValue) {
28001
+ addChips(parts, rest);
28002
+ return;
28003
+ }
28004
+ }
27565
28005
  const wasEmpty = inputValue === "";
27566
28006
  const isEmpty = nextValue === "";
27567
28007
  if (wasEmpty !== isEmpty) {
@@ -27576,8 +28016,11 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27576
28016
  onCompositionStart: () => {
27577
28017
  isComposingRef.current = true;
27578
28018
  },
27579
- onCompositionEnd: () => {
28019
+ onCompositionEnd: (e) => {
27580
28020
  isComposingRef.current = false;
28021
+ if (!separators) return;
28022
+ const { parts, rest } = splitBySeparators(e.currentTarget.value, separators);
28023
+ if (parts.length > 0 || rest !== e.currentTarget.value) addChips(parts, rest);
27581
28024
  },
27582
28025
  onFocus: () => {
27583
28026
  setFocused(true);
@@ -27587,6 +28030,8 @@ var SChipInput = /* @__PURE__ */ forwardRef(function SChipInput2({
27587
28030
  onBlur: () => {
27588
28031
  setFocused(false);
27589
28032
  setActiveIndex(-1);
28033
+ if (commitOnBlur && inputValue.trim() !== "" && !isMax)
28034
+ addChips([inputValue.trim()]);
27590
28035
  onBlur?.();
27591
28036
  }
27592
28037
  }
@@ -27780,6 +28225,7 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
27780
28225
  }, ref) {
27781
28226
  const f = FONT3[size];
27782
28227
  const [ruleError, setRuleError] = useState("");
28228
+ const controlId = useFieldControlId();
27783
28229
  const hasValue = value !== void 0 && value !== null && String(value) !== "";
27784
28230
  useFormField({
27785
28231
  name,
@@ -27800,6 +28246,7 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
27800
28246
  SField,
27801
28247
  {
27802
28248
  label,
28249
+ controlId,
27803
28250
  labelPosition,
27804
28251
  subLabel,
27805
28252
  labelWidth,
@@ -27825,16 +28272,21 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
27825
28272
  ...style
27826
28273
  },
27827
28274
  children: /* @__PURE__ */ jsxs(
27828
- "label",
28275
+ "div",
27829
28276
  {
28277
+ role: "presentation",
27830
28278
  className: "flex h-full w-full items-center",
27831
28279
  style: { gap: f.gap, padding: `0 ${f.paddingX}` },
28280
+ onClick: (e) => {
28281
+ if (e.target === e.currentTarget) e.currentTarget.querySelector("input")?.focus();
28282
+ },
27832
28283
  children: [
27833
28284
  prefix,
27834
28285
  /* @__PURE__ */ jsx(
27835
28286
  "input",
27836
28287
  {
27837
28288
  ref: mergeRefs(ref, valueTooltip.valueRef),
28289
+ id: controlId,
27838
28290
  name,
27839
28291
  type: "text",
27840
28292
  value: value ?? "",
@@ -27872,7 +28324,7 @@ var SBarcodeInput = /* @__PURE__ */ forwardRef(
27872
28324
  {
27873
28325
  icon: "close",
27874
28326
  size: "xxs",
27875
- ariaLabel: "clear",
28327
+ ariaLabel: "\uC9C0\uC6B0\uAE30",
27876
28328
  onClick: () => {
27877
28329
  onValueChange?.("");
27878
28330
  setRuleError(runRules("", rules));
@@ -28189,6 +28641,8 @@ function STimePicker({
28189
28641
  const portalContainer = usePortalContainer();
28190
28642
  const triggerRef = useRef(null);
28191
28643
  const [open, setOpen] = useState(false);
28644
+ const triggerId = useFieldControlId();
28645
+ const triggerTextId = `${triggerId}-text`;
28192
28646
  const [popoverAlignOffset, setPopoverAlignOffset] = useState(0);
28193
28647
  const [focused, setFocused] = useState(false);
28194
28648
  const [ruleError, setRuleError] = useState("");
@@ -28226,6 +28680,7 @@ function STimePicker({
28226
28680
  return /* @__PURE__ */ jsx(
28227
28681
  SField,
28228
28682
  {
28683
+ controlId: triggerId,
28229
28684
  label,
28230
28685
  labelPosition,
28231
28686
  subLabel,
@@ -28253,8 +28708,10 @@ function STimePicker({
28253
28708
  "div",
28254
28709
  {
28255
28710
  ref: triggerRef,
28711
+ id: triggerId,
28256
28712
  role: "button",
28257
28713
  "aria-disabled": disabled,
28714
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerTextId}` : void 0,
28258
28715
  tabIndex: disabled ? -1 : 0,
28259
28716
  "data-name": name,
28260
28717
  onFocus: () => setFocused(true),
@@ -28284,6 +28741,7 @@ function STimePicker({
28284
28741
  /* @__PURE__ */ jsx(
28285
28742
  "span",
28286
28743
  {
28744
+ id: triggerTextId,
28287
28745
  className: "flex-1 truncate text-center",
28288
28746
  style: {
28289
28747
  minWidth: dims.minWidth,
@@ -28659,6 +29117,8 @@ function STimeRangePicker({
28659
29117
  const portalContainer = usePortalContainer();
28660
29118
  const triggerRef = useRef(null);
28661
29119
  const [open, setOpen] = useState(false);
29120
+ const triggerId = useFieldControlId();
29121
+ const triggerTextId = `${triggerId}-text`;
28662
29122
  const [popoverAlignOffset, setPopoverAlignOffset] = useState(0);
28663
29123
  const [focused, setFocused] = useState(false);
28664
29124
  const [ruleError, setRuleError] = useState("");
@@ -28698,6 +29158,7 @@ function STimeRangePicker({
28698
29158
  return /* @__PURE__ */ jsx(
28699
29159
  SField,
28700
29160
  {
29161
+ controlId: triggerId,
28701
29162
  label,
28702
29163
  labelPosition,
28703
29164
  subLabel,
@@ -28725,8 +29186,10 @@ function STimeRangePicker({
28725
29186
  "div",
28726
29187
  {
28727
29188
  ref: triggerRef,
29189
+ id: triggerId,
28728
29190
  role: "button",
28729
29191
  "aria-disabled": disabled,
29192
+ "aria-labelledby": label ? `${fieldLabelId(triggerId)} ${triggerTextId}` : void 0,
28730
29193
  tabIndex: disabled ? -1 : 0,
28731
29194
  "data-name": name,
28732
29195
  onFocus: () => setFocused(true),
@@ -28756,6 +29219,7 @@ function STimeRangePicker({
28756
29219
  /* @__PURE__ */ jsx(
28757
29220
  "span",
28758
29221
  {
29222
+ id: triggerTextId,
28759
29223
  className: "flex-1 truncate text-center",
28760
29224
  style: {
28761
29225
  minWidth: dims.minWidth,
@@ -28809,6 +29273,6 @@ function STimeRangePicker({
28809
29273
  );
28810
29274
  }
28811
29275
 
28812
- export { ACCOUNT_LIST_BOX_ICONS, ACCOUNT_LIST_BOX_ITEM_TONES, ACCOUNT_LIST_BOX_LABELS, ACCOUNT_LIST_BOX_LAYOUT, ACCOUNT_LIST_BOX_TONE_CONFIG, BADGE_COLORS, BAR_GAP, BAR_SIZE_MAX, BAR_SIZE_MIN, BUTTON_COLORS, BUTTON_SIZES, CALENDAR_BOARD_DAY_BG, CALENDAR_BOARD_DAY_COLORS, CALENDAR_BOARD_EVENT_COLORS, CALENDAR_BOARD_EVENT_PRESETS, CALENDAR_BOARD_MAX_VISIBLE_EVENTS, CHAT_ATTACHED_FILE_CONFIG, CHAT_FILE_CONFIG, CHAT_MESSAGE_DIRECTIONS, CHAT_MESSAGE_READ_STATUSES, CHAT_MESSAGE_VARIANTS, CHIP_COLORS, COLOR_KEYS, CONTEXT_ALERT_ICON_COLOR, CONTEXT_ALERT_INTENTS, CONTEXT_ALERT_SURFACE, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, GNB_SYSTEM_COLORS, GNB_SYSTEM_COLOR_CONFIG, GNB_SYSTEM_LAYOUT, GNB_SYSTEM_PLACEMENTS, GNB_SYSTEM_TOP_COLOR_CONFIG, ICONS, IMAGE_FITS, LAUNCHER_LIST_BOX_CONSOLE_HEIGHT, LAUNCHER_LIST_BOX_CONSOLE_ICON, LAUNCHER_LIST_BOX_CONSOLE_LABEL, LAUNCHER_LIST_BOX_LAYOUT, LAUNCHER_LIST_BOX_LOGO_HEIGHT, LAUNCHER_LIST_BOX_TRAILING_ICON, LAUNCHER_LIST_BOX_WIDTH, LAUNCHER_SERVICES, LAUNCHER_SERVICE_CATALOG, LOGO_DEFAULT_SIZE, LOGO_DIRECTIONS, LOGO_MODES, LOGO_NAMES, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, PAGE_CONTENT_WIDTHS, PAGE_HEADER_VARIANTS, PAGE_PADDINGS, RangeCalendar, SAccountListBox, SActionModal, SBadge, SBarChart, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCalendarBoard, SCallout, SCard, SChatAttachedFile2 as SChatAttachedFile, SChatFile2 as SChatFile, SChatInput2 as SChatInput, SChatMessage2 as SChatMessage, SChatSystemMessage2 as SChatSystemMessage, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SContextAlert, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDonutChart, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGnbSystem, SGnbSystemContext, SGuide, SIcon, SImage, SInput, SKELETON_ANIMATIONS, SKELETON_MODES, SKELETON_TYPES, SKELETON_TYPE_CONFIG, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLauncherListBox, SLayout, SLayoutContext, SLineChart, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoginCard2 as SLoginCard, SLogo, SMeatballButton2 as SMeatballButton, SModal, SModalOutlet, SNumberInput, SPage, SPageHeader, SPagination, SPieChart, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioCard, SRadioCardGroup, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSkeleton, SSplitter2 as SSplitter, SStepper, SSwitch, SSystemActionButton, STEPPER_SIZES, STable2 as STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, STimeline2 as STimeline, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, STreeTable, SYSTEM_ACTION_BUTTON_COLORS, SYSTEM_ACTION_BUTTON_COLOR_CONFIG, SYSTEM_ACTION_BUTTON_LAYOUT, SYSTEM_ACTION_BUTTON_TYPES, SYSTEM_ACTION_BUTTON_TYPE_CONFIG, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldWidthValue, fileExtension, findGnbAncestors, findGnbRailValue, formatFileSize, isColorKey, isFieldWidthGrade, loading, normalizeExtension, resolveColor, useSLayout };
29276
+ export { ACCOUNT_LIST_BOX_ICONS, ACCOUNT_LIST_BOX_ITEM_TONES, ACCOUNT_LIST_BOX_LABELS, ACCOUNT_LIST_BOX_LAYOUT, ACCOUNT_LIST_BOX_TONE_CONFIG, BADGE_COLORS, BAR_GAP, BAR_SIZE_MAX, BAR_SIZE_MIN, BUTTON_COLORS, BUTTON_SIZES, CALENDAR_BOARD_DAY_BG, CALENDAR_BOARD_DAY_COLORS, CALENDAR_BOARD_EVENT_COLORS, CALENDAR_BOARD_EVENT_PRESETS, CALENDAR_BOARD_MAX_VISIBLE_EVENTS, CHAT_ATTACHED_FILE_CONFIG, CHAT_FILE_CONFIG, CHAT_MESSAGE_DIRECTIONS, CHAT_MESSAGE_READ_STATUSES, CHAT_MESSAGE_VARIANTS, CHIP_COLORS, COLOR_KEYS, CONTEXT_ALERT_ICON_COLOR, CONTEXT_ALERT_INTENTS, CONTEXT_ALERT_SURFACE, FIELD_WIDTH_GRADES, GNB_COLORS, GNB_COMMON, GNB_FOLD_MS, GNB_FULL_LOGO_WIDTH, GNB_HEADER, GNB_MENU, GNB_MENU_WIDTH, GNB_RAIL, GNB_RAIL_WIDTH, GNB_SYSTEM_COLORS, GNB_SYSTEM_COLOR_CONFIG, GNB_SYSTEM_LAYOUT, GNB_SYSTEM_PLACEMENTS, GNB_SYSTEM_TOP_COLOR_CONFIG, ICONS, IMAGE_FITS, LAUNCHER_LIST_BOX_CONSOLE_HEIGHT, LAUNCHER_LIST_BOX_CONSOLE_ICON, LAUNCHER_LIST_BOX_CONSOLE_LABEL, LAUNCHER_LIST_BOX_LAYOUT, LAUNCHER_LIST_BOX_LOGO_HEIGHT, LAUNCHER_LIST_BOX_TRAILING_ICON, LAUNCHER_LIST_BOX_WIDTH, LAUNCHER_SERVICES, LAUNCHER_SERVICE_CATALOG, LOGO_DEFAULT_SIZE, LOGO_DIRECTIONS, LOGO_MODES, LOGO_NAMES, PAGE_BACKGROUNDS, PAGE_CONTENT_HEIGHTS, PAGE_CONTENT_WIDTHS, PAGE_HEADER_VARIANTS, PAGE_PADDINGS, RangeCalendar, SAccountListBox, SActionModal, SBadge, SBarChart, SBarcodeInput, SButton, SCROLL_AREA_AXES, SCalendar, SCalendarBoard, SCallout, SCard, SChatAttachedFile2 as SChatAttachedFile, SChatFile2 as SChatFile, SChatInput2 as SChatInput, SChatMessage2 as SChatMessage, SChatSystemMessage2 as SChatSystemMessage, SCheckbox, SChip2 as SChip, SChipFilter, SChipInput, SCircleProgress, SConfirmModal, SContextAlert, SDatePicker, SDatePickerMonthListbox, SDatePickerYearListbox, SDateRangePicker, SDivider, SDonutChart, SDraggableGroup, SDraggableItem2 as SDraggableItem, SDraggableList, SDraggableProvider, SDrawer, SDropdownButton2 as SDropdownButton, SEDITOR_DEFAULT_FONT_SIZE, SEDITOR_HEADING_LABELS, SEDITOR_HEADING_LEVELS, SEditor, SExpansionItem, SExpansionList2 as SExpansionList, SField, SFilePicker, SForm, SGhostButton, SGnb, SGnbSystem, SGnbSystemContext, SGuide, SIcon, SImage, SInput, SKELETON_ANIMATIONS, SKELETON_MODES, SKELETON_TYPES, SKELETON_TYPE_CONFIG, SKeyValueTable, SLAYOUT_MIN_WIDTH, SLauncherListBox, SLayout, SLayoutContext, SLineChart, SLinearProgress, SList2 as SList, SListItem2 as SListItem, SLoadingContainer, SLoadingModal, SLoginCard2 as SLoginCard, SLogo, SMeatballButton2 as SMeatballButton, SModal, SModalOutlet, SNumberInput, SPage, SPageHeader, SPagination, SPieChart, SPopover, SPopup, SPortal, SRadio, SRadioButton, SRadioCard, SRadioCardGroup, SRadioGroup, SSPLITTER_UNITS, SScrollArea, SSearchInput, SSectionHeaderCard2 as SSectionHeaderCard, SSelect2 as SSelect, SSkeleton, SSlider, SSplitter2 as SSplitter, SStepper, SSwitch, SSystemActionButton, STEPPER_SIZES, STable2 as STable, STableBar, STabs, STag, STextLink, STextarea, STimePicker, STimeRangePicker, STimeline2 as STimeline, SToast, SToastContainer, SToggle, STooltip2 as STooltip, STree2 as STree, STreeItem2 as STreeItem, STreeTable, SYSTEM_ACTION_BUTTON_COLORS, SYSTEM_ACTION_BUTTON_COLOR_CONFIG, SYSTEM_ACTION_BUTTON_LAYOUT, SYSTEM_ACTION_BUTTON_TYPES, SYSTEM_ACTION_BUTTON_TYPE_CONFIG, TAG_COLORS, TAG_SHAPES, TAG_SIZES, TIMEPICKER_SIZES, TIMEPICKER_SIZE_CONFIG, buttonPreset, cn, fieldLabelId, fieldWidthValue, fileExtension, findGnbAncestors, findGnbRailValue, formatFileSize, isColorKey, isFieldWidthGrade, loading, normalizeExtension, resolveColor, useSLayout };
28813
29277
  //# sourceMappingURL=index.js.map
28814
29278
  //# sourceMappingURL=index.js.map