prime-ui-kit 0.7.4 → 0.7.7

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.
Files changed (31) hide show
  1. package/dist/components/index.css +326 -34
  2. package/dist/components/index.css.map +4 -4
  3. package/dist/components/index.d.ts +2 -0
  4. package/dist/components/index.d.ts.map +1 -1
  5. package/dist/components/index.js +811 -110
  6. package/dist/components/index.js.map +4 -4
  7. package/dist/components/select/Select.d.ts +26 -9
  8. package/dist/components/select/Select.d.ts.map +1 -1
  9. package/dist/components/select/examples/pattern-multiple.d.ts +3 -0
  10. package/dist/components/select/examples/pattern-multiple.d.ts.map +1 -0
  11. package/dist/components/tag-select/TagSelect.d.ts +43 -0
  12. package/dist/components/tag-select/TagSelect.d.ts.map +1 -0
  13. package/dist/components/tag-select/examples/pattern-canonical.d.ts +3 -0
  14. package/dist/components/tag-select/examples/pattern-canonical.d.ts.map +1 -0
  15. package/dist/components/tag-select/examples/pattern-features.d.ts +3 -0
  16. package/dist/components/tag-select/examples/pattern-features.d.ts.map +1 -0
  17. package/dist/hooks/usePosition.d.ts.map +1 -1
  18. package/dist/index.css +328 -36
  19. package/dist/index.css.map +4 -4
  20. package/dist/index.js +811 -110
  21. package/dist/index.js.map +4 -4
  22. package/dist/tokens/semantic.d.ts +1 -1
  23. package/package.json +1 -1
  24. package/src/components/select/COMPONENT.md +91 -32
  25. package/src/components/select/examples/pattern-multiple.tsx +30 -0
  26. package/src/components/tag-select/COMPONENT.md +108 -0
  27. package/src/components/tag-select/examples/examples.module.css +14 -0
  28. package/src/components/tag-select/examples/pattern-canonical.tsx +28 -0
  29. package/src/components/tag-select/examples/pattern-features.tsx +32 -0
  30. package/src/styles/theme-dark.css +1 -1
  31. package/src/styles/theme-light.css +1 -1
@@ -3832,11 +3832,15 @@ function usePosition(anchorRef, contentRef, options = {}) {
3832
3832
  (pos) => {
3833
3833
  const content = contentRef.current;
3834
3834
  if (!content) return;
3835
- content.style.position = pos.position;
3836
- content.style.top = `${pos.top}px`;
3837
- content.style.left = `${pos.left}px`;
3838
- content.style.minWidth = pos.minWidth !== void 0 ? `${pos.minWidth}px` : "";
3839
- content.style.maxHeight = pos.maxHeight !== void 0 ? `${pos.maxHeight}px` : "";
3835
+ const nextTop = `${pos.top}px`;
3836
+ const nextLeft = `${pos.left}px`;
3837
+ const nextMinW = pos.minWidth !== void 0 ? `${pos.minWidth}px` : "";
3838
+ const nextMaxH = pos.maxHeight !== void 0 ? `${pos.maxHeight}px` : "";
3839
+ if (content.style.position !== pos.position) content.style.position = pos.position;
3840
+ if (content.style.top !== nextTop) content.style.top = nextTop;
3841
+ if (content.style.left !== nextLeft) content.style.left = nextLeft;
3842
+ if (content.style.minWidth !== nextMinW) content.style.minWidth = nextMinW;
3843
+ if (content.style.maxHeight !== nextMaxH) content.style.maxHeight = nextMaxH;
3840
3844
  },
3841
3845
  [contentRef]
3842
3846
  );
@@ -3854,7 +3858,7 @@ function usePosition(anchorRef, contentRef, options = {}) {
3854
3858
  window.innerHeight,
3855
3859
  { preferredSide, align, offset, viewportPad, flip, matchTriggerMinWidth }
3856
3860
  );
3857
- setResolvedSide(pos.resolvedSide);
3861
+ setResolvedSide((prev) => pos.resolvedSide === prev ? prev : pos.resolvedSide);
3858
3862
  applyPositionStyle({
3859
3863
  position: "fixed",
3860
3864
  top: pos.top,
@@ -3877,6 +3881,21 @@ function usePosition(anchorRef, contentRef, options = {}) {
3877
3881
  return { resolvedSide, update };
3878
3882
  }
3879
3883
 
3884
+ // src/internal/scrollAncestors.ts
3885
+ var SCROLLABLE = /^(auto|scroll|overlay)$/;
3886
+ function getScrollContainers(node) {
3887
+ const out = [window];
3888
+ if (!node || typeof window === "undefined") return out;
3889
+ for (let el = node.parentElement; el; el = el.parentElement) {
3890
+ const { overflowX, overflowY } = window.getComputedStyle(el);
3891
+ if (SCROLLABLE.test(overflowY) || SCROLLABLE.test(overflowX)) {
3892
+ out.push(el);
3893
+ }
3894
+ }
3895
+ if (window.visualViewport) out.push(window.visualViewport);
3896
+ return out;
3897
+ }
3898
+
3880
3899
  // src/components/select/Select.module.css
3881
3900
  var Select_default = {
3882
3901
  trigger: "Select_trigger2",
@@ -3958,13 +3977,22 @@ function handleSelectListboxKeyDown(e, ctx) {
3958
3977
 
3959
3978
  // src/components/select/Select.tsx
3960
3979
  import { jsx as jsx26, jsxs as jsxs9 } from "react/jsx-runtime";
3980
+ var SELECT_LISTBOX_POSITION_OPTS = {
3981
+ side: "bottom",
3982
+ align: "start"
3983
+ };
3961
3984
  var [SelectProvider, useSelectContext] = createComponentContext("Select");
3962
3985
  function SelectRoot(props) {
3963
- const { native = false, ...rest } = props;
3964
- if (native) {
3965
- return /* @__PURE__ */ jsx26(SelectNativeRoot, { ...rest });
3986
+ if (props.multiple === true) {
3987
+ if (props.native === true) {
3988
+ return /* @__PURE__ */ jsx26(SelectNativeMultiRoot, { ...props });
3989
+ }
3990
+ return /* @__PURE__ */ jsx26(SelectComboboxMultiRoot, { ...props });
3991
+ }
3992
+ if (props.native === true) {
3993
+ return /* @__PURE__ */ jsx26(SelectNativeRoot, { ...props });
3966
3994
  }
3967
- return /* @__PURE__ */ jsx26(SelectComboboxRoot, { ...rest });
3995
+ return /* @__PURE__ */ jsx26(SelectComboboxRoot, { ...props });
3968
3996
  }
3969
3997
  SelectRoot.displayName = "SelectRoot";
3970
3998
  function SelectComboboxRoot({
@@ -4012,32 +4040,138 @@ function SelectComboboxRoot({
4012
4040
  );
4013
4041
  const onClose = React38.useCallback(() => setIsOpen(false), []);
4014
4042
  const onOpen = React38.useCallback(() => setIsOpen(true), []);
4015
- return /* @__PURE__ */ jsx26(
4016
- SelectProvider,
4017
- {
4018
- value: {
4019
- size,
4020
- hasError,
4021
- isOpen,
4022
- selectedValue,
4023
- selectedLabelBinding,
4024
- onSelect,
4025
- onClose,
4026
- onOpen,
4027
- highlightedValue,
4028
- setHighlightedValue,
4029
- triggerId,
4030
- listboxId,
4031
- triggerRef,
4032
- disabled,
4033
- placeholder,
4034
- onInitLabel
4035
- },
4036
- children: /* @__PURE__ */ jsx26(ControlSizeProvider, { value: size, children })
4037
- }
4043
+ const contextValue = React38.useMemo(
4044
+ () => ({
4045
+ size,
4046
+ hasError,
4047
+ isOpen,
4048
+ multiple: false,
4049
+ selectedValue,
4050
+ selectedLabelBinding,
4051
+ selectedValues: [],
4052
+ labelsByValue: {},
4053
+ onSelect,
4054
+ onClose,
4055
+ onOpen,
4056
+ highlightedValue,
4057
+ setHighlightedValue,
4058
+ triggerId,
4059
+ listboxId,
4060
+ triggerRef,
4061
+ disabled,
4062
+ placeholder,
4063
+ onInitLabel
4064
+ }),
4065
+ [
4066
+ size,
4067
+ hasError,
4068
+ isOpen,
4069
+ selectedValue,
4070
+ selectedLabelBinding,
4071
+ onSelect,
4072
+ onClose,
4073
+ onOpen,
4074
+ highlightedValue,
4075
+ triggerId,
4076
+ listboxId,
4077
+ disabled,
4078
+ placeholder,
4079
+ onInitLabel
4080
+ ]
4038
4081
  );
4082
+ return /* @__PURE__ */ jsx26(SelectProvider, { value: contextValue, children: /* @__PURE__ */ jsx26(ControlSizeProvider, { value: size, children }) });
4039
4083
  }
4040
4084
  SelectComboboxRoot.displayName = "SelectComboboxRoot";
4085
+ function SelectComboboxMultiRoot({
4086
+ size = "m",
4087
+ value,
4088
+ defaultValue,
4089
+ onChange,
4090
+ disabled,
4091
+ placeholder,
4092
+ hasError = false,
4093
+ children
4094
+ }) {
4095
+ const handleChange = React38.useCallback(
4096
+ (next) => {
4097
+ onChange?.(next);
4098
+ },
4099
+ [onChange]
4100
+ );
4101
+ const [selectedValues, setSelectedValues] = useControllableState({
4102
+ value,
4103
+ defaultValue: defaultValue ?? [],
4104
+ onChange: handleChange
4105
+ });
4106
+ const [labelsByValue, setLabelsByValue] = React38.useState({});
4107
+ const [isOpen, setIsOpen] = React38.useState(false);
4108
+ const [highlightedValue, setHighlightedValue] = React38.useState(void 0);
4109
+ const generatedId = React38.useId();
4110
+ const triggerId = `${generatedId}-trigger`;
4111
+ const listboxId = `${generatedId}-listbox`;
4112
+ const triggerRef = React38.useRef(null);
4113
+ const onInitLabel = React38.useCallback((val, label) => {
4114
+ setLabelsByValue((prev) => {
4115
+ if (prev[val] === label) return prev;
4116
+ return { ...prev, [val]: label };
4117
+ });
4118
+ }, []);
4119
+ const onSelect = React38.useCallback(
4120
+ (val, label) => {
4121
+ setLabelsByValue((prev) => ({ ...prev, [val]: label }));
4122
+ setSelectedValues((prev) => {
4123
+ if (prev.includes(val)) {
4124
+ return prev.filter((x) => x !== val);
4125
+ }
4126
+ return [...prev, val];
4127
+ });
4128
+ },
4129
+ [setSelectedValues]
4130
+ );
4131
+ const onClose = React38.useCallback(() => setIsOpen(false), []);
4132
+ const onOpen = React38.useCallback(() => setIsOpen(true), []);
4133
+ const contextValue = React38.useMemo(
4134
+ () => ({
4135
+ size,
4136
+ hasError,
4137
+ isOpen,
4138
+ multiple: true,
4139
+ selectedValue: void 0,
4140
+ selectedLabelBinding: void 0,
4141
+ selectedValues,
4142
+ labelsByValue,
4143
+ onSelect,
4144
+ onClose,
4145
+ onOpen,
4146
+ highlightedValue,
4147
+ setHighlightedValue,
4148
+ triggerId,
4149
+ listboxId,
4150
+ triggerRef,
4151
+ disabled,
4152
+ placeholder,
4153
+ onInitLabel
4154
+ }),
4155
+ [
4156
+ size,
4157
+ hasError,
4158
+ isOpen,
4159
+ selectedValues,
4160
+ labelsByValue,
4161
+ onSelect,
4162
+ onClose,
4163
+ onOpen,
4164
+ highlightedValue,
4165
+ triggerId,
4166
+ listboxId,
4167
+ disabled,
4168
+ placeholder,
4169
+ onInitLabel
4170
+ ]
4171
+ );
4172
+ return /* @__PURE__ */ jsx26(SelectProvider, { value: contextValue, children: /* @__PURE__ */ jsx26(ControlSizeProvider, { value: size, children }) });
4173
+ }
4174
+ SelectComboboxMultiRoot.displayName = "SelectComboboxMultiRoot";
4041
4175
  var SelectTrigger = React38.forwardRef(
4042
4176
  ({ className, children, onClick, onKeyDown, ...rest }, forwardedRef) => {
4043
4177
  const { isOpen, onOpen, onClose, triggerId, listboxId, disabled, size, hasError, triggerRef } = useSelectContext();
@@ -4092,7 +4226,20 @@ var SelectTrigger = React38.forwardRef(
4092
4226
  );
4093
4227
  SelectTrigger.displayName = "SelectTrigger";
4094
4228
  function SelectValue({ className }) {
4095
- const { selectedLabelBinding, selectedValue, placeholder } = useSelectContext();
4229
+ const ctx = useSelectContext();
4230
+ if (ctx.multiple) {
4231
+ const { selectedValues, labelsByValue, placeholder: placeholder2 } = ctx;
4232
+ const display2 = selectedValues.length === 0 ? placeholder2 : selectedValues.map((v) => labelsByValue[v] ?? v).join(", ");
4233
+ return /* @__PURE__ */ jsx26(
4234
+ "span",
4235
+ {
4236
+ className: cx(Select_default.triggerValue, className),
4237
+ ...toDataAttributes({ placeholder: display2 == null || display2 === "" }),
4238
+ children: display2
4239
+ }
4240
+ );
4241
+ }
4242
+ const { selectedLabelBinding, selectedValue, placeholder } = ctx;
4096
4243
  const display = selectedLabelBinding && selectedLabelBinding.value === selectedValue ? selectedLabelBinding.label : selectedValue ?? placeholder;
4097
4244
  return /* @__PURE__ */ jsx26(
4098
4245
  "span",
@@ -4119,67 +4266,109 @@ function SelectContent({ className, children }) {
4119
4266
  highlightedValue,
4120
4267
  setHighlightedValue,
4121
4268
  selectedValue,
4269
+ selectedValues,
4270
+ multiple,
4122
4271
  size
4123
4272
  } = useSelectContext();
4273
+ const selectedValueRef = React38.useRef(selectedValue);
4274
+ selectedValueRef.current = selectedValue;
4275
+ const selectedValuesRef = React38.useRef(selectedValues);
4276
+ selectedValuesRef.current = selectedValues;
4277
+ const multipleRef = React38.useRef(multiple);
4278
+ multipleRef.current = multiple;
4124
4279
  const overlayPortalLayer = useOverlayPortalLayer();
4125
4280
  const contentRef = React38.useRef(null);
4126
- const { resolvedSide, update } = usePosition(triggerRef, contentRef, {
4127
- side: "bottom",
4128
- align: "start"
4129
- });
4281
+ const { resolvedSide, update } = usePosition(
4282
+ triggerRef,
4283
+ contentRef,
4284
+ SELECT_LISTBOX_POSITION_OPTS
4285
+ );
4286
+ const updateRef = React38.useRef(update);
4287
+ updateRef.current = update;
4130
4288
  const getItems = React38.useCallback(() => queryEnabledSelectOptions(contentRef.current), []);
4131
4289
  React38.useLayoutEffect(() => {
4132
4290
  if (!isOpen) return;
4133
- update();
4134
- const rafId = requestAnimationFrame(() => update());
4291
+ updateRef.current();
4292
+ const rafId = requestAnimationFrame(() => updateRef.current());
4135
4293
  return () => cancelAnimationFrame(rafId);
4136
- }, [isOpen, update]);
4294
+ }, [isOpen]);
4137
4295
  React38.useEffect(() => {
4138
4296
  if (!isOpen) {
4139
4297
  setHighlightedValue(void 0);
4140
4298
  return;
4141
4299
  }
4142
- const reposition = () => {
4143
- requestAnimationFrame(() => update());
4144
- };
4145
4300
  const bootstrap = () => {
4146
4301
  requestAnimationFrame(() => {
4147
4302
  const el = contentRef.current;
4148
4303
  if (!el) return;
4149
4304
  el.focus({ preventScroll: true });
4150
4305
  const items = queryEnabledSelectOptions(el);
4151
- const selectedIndex = items.findIndex((i) => i.dataset.value === selectedValue);
4152
- if (selectedIndex >= 0 && selectedValue) {
4153
- setHighlightedValue(selectedValue);
4306
+ if (multipleRef.current) {
4307
+ const sv = selectedValuesRef.current;
4308
+ const firstSelected = sv.find((v) => items.some((i) => i.dataset.value === v));
4309
+ setHighlightedValue(firstSelected ?? void 0);
4310
+ } else {
4311
+ const sv = selectedValueRef.current;
4312
+ const selectedIndex = items.findIndex((i) => i.dataset.value === sv);
4313
+ if (selectedIndex >= 0 && sv) {
4314
+ setHighlightedValue(sv);
4315
+ }
4154
4316
  }
4155
4317
  });
4156
4318
  };
4157
4319
  bootstrap();
4158
- window.addEventListener("resize", reposition);
4320
+ }, [isOpen, setHighlightedValue]);
4321
+ React38.useEffect(() => {
4322
+ if (!isOpen) return;
4323
+ let rafCoalesce = 0;
4324
+ const schedule = () => {
4325
+ cancelAnimationFrame(rafCoalesce);
4326
+ rafCoalesce = requestAnimationFrame(() => updateRef.current());
4327
+ };
4328
+ window.addEventListener("resize", schedule);
4329
+ const scrollTargets = getScrollContainers(triggerRef.current);
4330
+ for (const t of scrollTargets) {
4331
+ t.addEventListener("scroll", schedule, { passive: true });
4332
+ }
4159
4333
  const vv = window.visualViewport;
4160
- vv?.addEventListener("resize", reposition);
4334
+ vv?.addEventListener("resize", schedule);
4335
+ const panel = contentRef.current;
4336
+ let ro = null;
4337
+ if (typeof ResizeObserver !== "undefined" && panel) {
4338
+ ro = new ResizeObserver(schedule);
4339
+ ro.observe(panel);
4340
+ }
4161
4341
  return () => {
4162
- window.removeEventListener("resize", reposition);
4163
- vv?.removeEventListener("resize", reposition);
4342
+ cancelAnimationFrame(rafCoalesce);
4343
+ window.removeEventListener("resize", schedule);
4344
+ for (const t of scrollTargets) {
4345
+ t.removeEventListener("scroll", schedule);
4346
+ }
4347
+ vv?.removeEventListener("resize", schedule);
4348
+ ro?.disconnect();
4164
4349
  };
4165
- }, [isOpen, update, selectedValue, setHighlightedValue]);
4350
+ }, [isOpen, triggerRef]);
4166
4351
  useEscapeKey({ enabled: isOpen, onEscape: onClose });
4167
4352
  useOutsideClick({ refs: [triggerRef, contentRef], enabled: isOpen, onOutsideClick: onClose });
4168
- const handleKeyDown = (e) => {
4169
- handleSelectListboxKeyDown(e, {
4170
- items: getItems(),
4171
- highlightedValue,
4172
- setHighlightedValue,
4173
- onSelect,
4174
- onClose
4175
- });
4176
- };
4353
+ const handleKeyDown = React38.useCallback(
4354
+ (e) => {
4355
+ handleSelectListboxKeyDown(e, {
4356
+ items: getItems(),
4357
+ highlightedValue,
4358
+ setHighlightedValue,
4359
+ onSelect,
4360
+ onClose
4361
+ });
4362
+ },
4363
+ [getItems, highlightedValue, setHighlightedValue, onSelect, onClose]
4364
+ );
4177
4365
  return /* @__PURE__ */ jsx26(Portal, { children: /* @__PURE__ */ jsx26(
4178
4366
  ScrollContainer,
4179
4367
  {
4180
4368
  ref: contentRef,
4181
4369
  id: listboxId,
4182
4370
  role: "listbox",
4371
+ "aria-multiselectable": multiple ? true : void 0,
4183
4372
  "aria-labelledby": triggerId,
4184
4373
  "aria-hidden": !isOpen,
4185
4374
  tabIndex: -1,
@@ -4198,6 +4387,17 @@ function SelectItemIcon({ className, children, ...rest }) {
4198
4387
  return /* @__PURE__ */ jsx26("span", { className: cx(Select_default.itemIcon, className), ...rest, children });
4199
4388
  }
4200
4389
  SelectItemIcon.displayName = "SelectItemIcon";
4390
+ var SELECT_ITEM_ICON_MARKER = "__primeSelectItemIcon";
4391
+ Object.assign(SelectItemIcon, { [SELECT_ITEM_ICON_MARKER]: true });
4392
+ function isSelectItemIconType(type) {
4393
+ if (type === SelectItemIcon) return true;
4394
+ if (typeof type === "function") {
4395
+ const fn = type;
4396
+ if (fn[SELECT_ITEM_ICON_MARKER] === true) return true;
4397
+ if (fn.displayName === "SelectItemIcon") return true;
4398
+ }
4399
+ return false;
4400
+ }
4201
4401
  function selectItemTextFromRest(rest) {
4202
4402
  const parts = [];
4203
4403
  for (const node of rest) {
@@ -4212,7 +4412,7 @@ function partitionSelectItemChildren(children) {
4212
4412
  const icons = [];
4213
4413
  const rest = [];
4214
4414
  React38.Children.forEach(children, (child) => {
4215
- if (React38.isValidElement(child) && child.type === SelectItemIcon) {
4415
+ if (React38.isValidElement(child) && isSelectItemIconType(child.type)) {
4216
4416
  icons.push(child);
4217
4417
  } else if (child != null && child !== false) {
4218
4418
  rest.push(child);
@@ -4222,9 +4422,18 @@ function partitionSelectItemChildren(children) {
4222
4422
  }
4223
4423
  var SelectItem = React38.forwardRef(
4224
4424
  ({ value, label, disabled, className, children }, ref) => {
4225
- const { selectedValue, highlightedValue, setHighlightedValue, onSelect, onInitLabel } = useSelectContext();
4425
+ const {
4426
+ multiple,
4427
+ size,
4428
+ selectedValue,
4429
+ selectedValues,
4430
+ highlightedValue,
4431
+ setHighlightedValue,
4432
+ onSelect,
4433
+ onInitLabel
4434
+ } = useSelectContext();
4226
4435
  const { icons, rest } = partitionSelectItemChildren(children);
4227
- const isSelected = selectedValue === value;
4436
+ const isSelected = multiple ? selectedValues.includes(value) : selectedValue === value;
4228
4437
  const isHighlighted = highlightedValue === value;
4229
4438
  const resolvedLabel = label ?? selectItemTextFromRest(rest) ?? (typeof children === "string" ? children : void 0) ?? value;
4230
4439
  React38.useEffect(() => {
@@ -4259,7 +4468,8 @@ var SelectItem = React38.forwardRef(
4259
4468
  label: resolvedLabel,
4260
4469
  selected: isSelected,
4261
4470
  highlighted: isHighlighted,
4262
- disabled: Boolean(disabled)
4471
+ disabled: Boolean(disabled),
4472
+ size
4263
4473
  }),
4264
4474
  children: [
4265
4475
  icons.map(
@@ -4280,7 +4490,8 @@ function SelectGroup({ className, ...rest }) {
4280
4490
  }
4281
4491
  SelectGroup.displayName = "SelectGroup";
4282
4492
  function SelectGroupLabel({ className, ...rest }) {
4283
- return /* @__PURE__ */ jsx26("div", { className: cx(Select_default.groupLabel, className), ...rest });
4493
+ const { size } = useSelectContext();
4494
+ return /* @__PURE__ */ jsx26("div", { className: cx(Select_default.groupLabel, className), ...rest, ...toDataAttributes({ size }) });
4284
4495
  }
4285
4496
  SelectGroupLabel.displayName = "SelectGroupLabel";
4286
4497
  function SelectSeparator({ className, ...rest }) {
@@ -4416,6 +4627,49 @@ function SelectNativeRoot({
4416
4627
  ) });
4417
4628
  }
4418
4629
  SelectNativeRoot.displayName = "SelectNativeRoot";
4630
+ function SelectNativeMultiRoot({
4631
+ size = "m",
4632
+ value,
4633
+ defaultValue,
4634
+ onChange,
4635
+ disabled,
4636
+ hasError = false,
4637
+ children
4638
+ }) {
4639
+ const handleChange = React38.useCallback(
4640
+ (next) => {
4641
+ onChange?.(next);
4642
+ },
4643
+ [onChange]
4644
+ );
4645
+ const [selectedValues, setSelectedValues] = useControllableState({
4646
+ value,
4647
+ defaultValue: defaultValue ?? [],
4648
+ onChange: handleChange
4649
+ });
4650
+ const { nodes: optionNodes } = React38.useMemo(() => walkNativeOptions(children), [children]);
4651
+ const handleNativeChange = React38.useCallback(
4652
+ (e) => {
4653
+ const next = Array.from(e.target.selectedOptions, (o) => o.value);
4654
+ setSelectedValues(next);
4655
+ },
4656
+ [setSelectedValues]
4657
+ );
4658
+ return /* @__PURE__ */ jsx26(ControlSizeProvider, { value: size, children: /* @__PURE__ */ jsx26(
4659
+ "select",
4660
+ {
4661
+ className: Select_default.nativeSelect,
4662
+ "data-multiple": "true",
4663
+ disabled,
4664
+ multiple: true,
4665
+ value: selectedValues,
4666
+ onChange: handleNativeChange,
4667
+ ...toDataAttributes({ size, "has-error": hasError }),
4668
+ children: optionNodes
4669
+ }
4670
+ ) });
4671
+ }
4672
+ SelectNativeMultiRoot.displayName = "SelectNativeMultiRoot";
4419
4673
  var Select = {
4420
4674
  Root: SelectRoot,
4421
4675
  Trigger: SelectTrigger,
@@ -7068,21 +7322,6 @@ function handleMenuNavigationKeyDown(e, container) {
7068
7322
  // src/components/dropdown/useDropdownPosition.ts
7069
7323
  import * as React48 from "react";
7070
7324
 
7071
- // src/internal/scrollAncestors.ts
7072
- var SCROLLABLE = /^(auto|scroll|overlay)$/;
7073
- function getScrollContainers(node) {
7074
- const out = [window];
7075
- if (!node || typeof window === "undefined") return out;
7076
- for (let el = node.parentElement; el; el = el.parentElement) {
7077
- const { overflowX, overflowY } = window.getComputedStyle(el);
7078
- if (SCROLLABLE.test(overflowY) || SCROLLABLE.test(overflowX)) {
7079
- out.push(el);
7080
- }
7081
- }
7082
- if (window.visualViewport) out.push(window.visualViewport);
7083
- return out;
7084
- }
7085
-
7086
7325
  // src/components/dropdown/dropdownGeometry.ts
7087
7326
  var DROPDOWN_MIN_MAX_HEIGHT = 120;
7088
7327
  function getDropdownMaxHeightForAnchorSide(anchor, side, viewportHeight, panelOffsetPx, viewportPadPx) {
@@ -10146,9 +10385,470 @@ function TagIcon({ children, className }) {
10146
10385
  TagIcon.displayName = "TagIcon";
10147
10386
  var Tag = { Root: TagRoot, Icon: TagIcon };
10148
10387
 
10149
- // src/components/textarea/Textarea.tsx
10388
+ // src/components/tag-select/TagSelect.tsx
10150
10389
  import * as React71 from "react";
10151
10390
 
10391
+ // src/components/tag-select/TagSelect.module.css
10392
+ var TagSelect_default = {
10393
+ control: "TagSelect_control2",
10394
+ chips: "TagSelect_chips2",
10395
+ chip: "TagSelect_chip2",
10396
+ chipBadge: "TagSelect_chipBadge2",
10397
+ chipLabel: "TagSelect_chipLabel2",
10398
+ chipRemove: "TagSelect_chipRemove2",
10399
+ removeIcon: "TagSelect_removeIcon2",
10400
+ input: "TagSelect_input2",
10401
+ inputCollapsed: "TagSelect_inputCollapsed2",
10402
+ chevronSlot: "TagSelect_chevronSlot2",
10403
+ chevron: "TagSelect_chevron2",
10404
+ panelInner: "TagSelect_panelInner2",
10405
+ hint: "TagSelect_hint2",
10406
+ optionRow: "TagSelect_optionRow2",
10407
+ createRow: "TagSelect_createRow2",
10408
+ createLabel: "TagSelect_createLabel2"
10409
+ };
10410
+
10411
+ // src/components/tag-select/TagSelect.tsx
10412
+ import { jsx as jsx57, jsxs as jsxs31 } from "react/jsx-runtime";
10413
+ var CREATE_VALUE = "__prime_tag_select_create__";
10414
+ function normalizeList(selected, options, defaultTagColor) {
10415
+ return selected.map((v) => {
10416
+ const o = options.find((x) => x.value === v);
10417
+ return {
10418
+ value: v,
10419
+ label: o?.label ?? v,
10420
+ color: o?.color ?? defaultTagColor
10421
+ };
10422
+ });
10423
+ }
10424
+ function filterOptions(options, query) {
10425
+ const q = query.trim().toLowerCase();
10426
+ if (q.length === 0) return options;
10427
+ return options.filter((o) => {
10428
+ if (o.disabled) return false;
10429
+ return o.label.toLowerCase().includes(q) || o.value.toLowerCase().includes(q);
10430
+ });
10431
+ }
10432
+ function optionsForList(options, query, selected) {
10433
+ return filterOptions(options, query).filter((o) => !selected.includes(o.value));
10434
+ }
10435
+ function shouldShowCreate(creatable, inputTrim, selected, options) {
10436
+ if (!creatable || inputTrim.length === 0) return false;
10437
+ if (selected.includes(inputTrim)) return false;
10438
+ const lower = inputTrim.toLowerCase();
10439
+ const exists = options.some(
10440
+ (o) => o.value === inputTrim || o.label.toLowerCase() === lower || o.value.toLowerCase() === lower
10441
+ );
10442
+ return !exists;
10443
+ }
10444
+ function TagSelectRoot({
10445
+ options,
10446
+ value: valueProp,
10447
+ defaultValue = [],
10448
+ onValueChange,
10449
+ creatable = false,
10450
+ onCreated,
10451
+ defaultTagColor = "gray",
10452
+ hint = "Select an option or create one",
10453
+ createActionLabel = "Create",
10454
+ disabled = false,
10455
+ placeholder = "",
10456
+ hasError = false,
10457
+ size = "m",
10458
+ id: idProp,
10459
+ className,
10460
+ "aria-label": ariaLabel,
10461
+ "aria-labelledby": ariaLabelledBy
10462
+ }) {
10463
+ const generatedId = React71.useId();
10464
+ const rootId = idProp ?? generatedId;
10465
+ const listboxId = `${rootId}-listbox`;
10466
+ const inputId = `${rootId}-input`;
10467
+ const [selected, setSelected] = useControllableState({
10468
+ value: valueProp,
10469
+ defaultValue,
10470
+ onChange: onValueChange
10471
+ });
10472
+ const [inputValue, setInputValue] = React71.useState("");
10473
+ const [inputFocused, setInputFocused] = React71.useState(false);
10474
+ const [open, setOpen] = React71.useState(false);
10475
+ const [highlightedValue, setHighlightedValue] = React71.useState(void 0);
10476
+ const triggerRef = React71.useRef(null);
10477
+ const inputRef = React71.useRef(null);
10478
+ const listboxRef = React71.useRef(null);
10479
+ const overlayPortalLayer = useOverlayPortalLayer();
10480
+ const { resolvedSide, update } = usePosition(triggerRef, listboxRef, {
10481
+ side: "bottom",
10482
+ align: "start"
10483
+ });
10484
+ const updateRef = React71.useRef(update);
10485
+ updateRef.current = update;
10486
+ const inputTrim = inputValue.trim();
10487
+ const filtered = React71.useMemo(
10488
+ () => optionsForList(options, inputValue, selected),
10489
+ [options, inputValue, selected]
10490
+ );
10491
+ const showCreate = shouldShowCreate(creatable, inputTrim, selected, options);
10492
+ const hasPanelContent = filtered.length > 0 || showCreate;
10493
+ const flatOptionValues = React71.useMemo(() => {
10494
+ const v = [];
10495
+ if (showCreate) v.push(CREATE_VALUE);
10496
+ for (const o of filtered) {
10497
+ if (!o.disabled) v.push(o.value);
10498
+ }
10499
+ return v;
10500
+ }, [filtered, showCreate]);
10501
+ React71.useLayoutEffect(() => {
10502
+ if (!open) return;
10503
+ updateRef.current();
10504
+ const raf = requestAnimationFrame(() => updateRef.current());
10505
+ return () => cancelAnimationFrame(raf);
10506
+ }, [open]);
10507
+ React71.useEffect(() => {
10508
+ if (!open) return;
10509
+ let rafCoalesce = 0;
10510
+ const schedule = () => {
10511
+ cancelAnimationFrame(rafCoalesce);
10512
+ rafCoalesce = requestAnimationFrame(() => updateRef.current());
10513
+ };
10514
+ window.addEventListener("resize", schedule);
10515
+ const scrollTargets = getScrollContainers(triggerRef.current);
10516
+ for (const t of scrollTargets) {
10517
+ t.addEventListener("scroll", schedule, { passive: true });
10518
+ }
10519
+ const vv = window.visualViewport;
10520
+ vv?.addEventListener("resize", schedule);
10521
+ const panel = listboxRef.current;
10522
+ let ro = null;
10523
+ if (typeof ResizeObserver !== "undefined" && panel) {
10524
+ ro = new ResizeObserver(schedule);
10525
+ ro.observe(panel);
10526
+ }
10527
+ return () => {
10528
+ cancelAnimationFrame(rafCoalesce);
10529
+ window.removeEventListener("resize", schedule);
10530
+ for (const t of scrollTargets) {
10531
+ t.removeEventListener("scroll", schedule);
10532
+ }
10533
+ vv?.removeEventListener("resize", schedule);
10534
+ ro?.disconnect();
10535
+ };
10536
+ }, [open]);
10537
+ React71.useEffect(() => {
10538
+ if (!open) {
10539
+ setHighlightedValue(void 0);
10540
+ return;
10541
+ }
10542
+ if (flatOptionValues.length === 0) {
10543
+ setHighlightedValue(void 0);
10544
+ return;
10545
+ }
10546
+ setHighlightedValue(
10547
+ (prev) => prev && flatOptionValues.includes(prev) ? prev : flatOptionValues[0]
10548
+ );
10549
+ }, [open, flatOptionValues]);
10550
+ React71.useEffect(() => {
10551
+ if (!open) return;
10552
+ if (!hasPanelContent) setOpen(false);
10553
+ }, [open, hasPanelContent]);
10554
+ useEscapeKey({ enabled: open, onEscape: () => setOpen(false) });
10555
+ useOutsideClick({
10556
+ refs: [triggerRef, listboxRef],
10557
+ enabled: open,
10558
+ onOutsideClick: () => setOpen(false)
10559
+ });
10560
+ const toggleValue = React71.useCallback(
10561
+ (value) => {
10562
+ setSelected((prev) => {
10563
+ if (prev.includes(value)) {
10564
+ return prev.filter((x) => x !== value);
10565
+ }
10566
+ return [...prev, value];
10567
+ });
10568
+ },
10569
+ [setSelected]
10570
+ );
10571
+ const handleSelectFromList = React71.useCallback(
10572
+ (rawValue) => {
10573
+ if (rawValue === CREATE_VALUE) {
10574
+ const v = inputTrim;
10575
+ if (v.length === 0) return;
10576
+ setSelected((prev) => {
10577
+ if (prev.includes(v)) return prev;
10578
+ onCreated?.(v);
10579
+ return [...prev, v];
10580
+ });
10581
+ setInputValue("");
10582
+ return;
10583
+ }
10584
+ toggleValue(rawValue);
10585
+ setInputValue("");
10586
+ },
10587
+ [inputTrim, onCreated, setSelected, toggleValue]
10588
+ );
10589
+ const getItems = React71.useCallback(() => queryEnabledSelectOptions(listboxRef.current), []);
10590
+ const onListboxKeyDown = (e) => {
10591
+ handleSelectListboxKeyDown(e, {
10592
+ items: getItems(),
10593
+ highlightedValue,
10594
+ setHighlightedValue,
10595
+ onSelect: (v) => {
10596
+ handleSelectFromList(v);
10597
+ },
10598
+ onClose: () => setOpen(false)
10599
+ });
10600
+ };
10601
+ const onInputKeyDown = (e) => {
10602
+ if (disabled) return;
10603
+ if (e.key === "Backspace" && inputValue.length === 0 && selected.length > 0) {
10604
+ e.preventDefault();
10605
+ setSelected((prev) => prev.slice(0, -1));
10606
+ return;
10607
+ }
10608
+ if (e.key === "Escape") {
10609
+ if (open) {
10610
+ e.preventDefault();
10611
+ setOpen(false);
10612
+ }
10613
+ return;
10614
+ }
10615
+ if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") {
10616
+ if (!open) {
10617
+ if (e.key === "ArrowDown" || e.key === "ArrowUp") {
10618
+ e.preventDefault();
10619
+ if (filtered.length > 0 || showCreate) setOpen(true);
10620
+ }
10621
+ return;
10622
+ }
10623
+ if (flatOptionValues.length === 0) return;
10624
+ if (e.key === "Enter" || e.key === " ") {
10625
+ e.preventDefault();
10626
+ const hv = highlightedValue ?? flatOptionValues[0];
10627
+ if (hv === CREATE_VALUE) {
10628
+ handleSelectFromList(CREATE_VALUE);
10629
+ } else if (hv) {
10630
+ const o = options.find((x) => x.value === hv);
10631
+ if (o && !o.disabled) {
10632
+ handleSelectFromList(o.value);
10633
+ }
10634
+ }
10635
+ return;
10636
+ }
10637
+ handleSelectListboxKeyDown(e, {
10638
+ items: getItems(),
10639
+ highlightedValue,
10640
+ setHighlightedValue,
10641
+ onSelect: (v) => handleSelectFromList(v),
10642
+ onClose: () => setOpen(false)
10643
+ });
10644
+ }
10645
+ };
10646
+ const chips = normalizeList(selected, options, defaultTagColor);
10647
+ const isEmpty = selected.length === 0 && inputTrim.length === 0;
10648
+ const inputCollapsed = !inputFocused && inputTrim.length === 0 && selected.length > 0;
10649
+ const focusInput = () => {
10650
+ inputRef.current?.focus();
10651
+ };
10652
+ const handleInputBlur = React71.useCallback((e) => {
10653
+ const next = e.relatedTarget;
10654
+ if (next instanceof Node && triggerRef.current?.contains(next)) {
10655
+ return;
10656
+ }
10657
+ window.requestAnimationFrame(() => {
10658
+ if (triggerRef.current?.contains(document.activeElement)) {
10659
+ return;
10660
+ }
10661
+ setInputFocused(false);
10662
+ setInputValue("");
10663
+ });
10664
+ }, []);
10665
+ return /* @__PURE__ */ jsxs31(ControlSizeProvider, { value: size, children: [
10666
+ /* @__PURE__ */ jsxs31(
10667
+ "div",
10668
+ {
10669
+ ref: triggerRef,
10670
+ className: cx(TagSelect_default.control, className),
10671
+ onClick: () => {
10672
+ if (!disabled) {
10673
+ focusInput();
10674
+ if (hasPanelContent) setOpen(true);
10675
+ }
10676
+ },
10677
+ ...toDataAttributes({
10678
+ size,
10679
+ open,
10680
+ empty: isEmpty ? true : void 0,
10681
+ disabled: disabled ? true : void 0,
10682
+ "has-error": hasError ? true : void 0
10683
+ }),
10684
+ children: [
10685
+ /* @__PURE__ */ jsxs31("div", { className: TagSelect_default.chips, children: [
10686
+ chips.map((c) => /* @__PURE__ */ jsx57("span", { className: TagSelect_default.chip, children: /* @__PURE__ */ jsxs31(Badge.Root, { color: c.color, variant: "filled", className: TagSelect_default.chipBadge, children: [
10687
+ /* @__PURE__ */ jsx57("span", { className: TagSelect_default.chipLabel, children: c.label }),
10688
+ /* @__PURE__ */ jsx57(
10689
+ "button",
10690
+ {
10691
+ type: "button",
10692
+ className: TagSelect_default.chipRemove,
10693
+ "aria-label": `Remove ${c.label}`,
10694
+ disabled,
10695
+ onMouseDown: (e) => {
10696
+ e.preventDefault();
10697
+ },
10698
+ onClick: (e) => {
10699
+ e.stopPropagation();
10700
+ setSelected((prev) => prev.filter((x) => x !== c.value));
10701
+ },
10702
+ children: /* @__PURE__ */ jsx57(
10703
+ "svg",
10704
+ {
10705
+ className: TagSelect_default.removeIcon,
10706
+ viewBox: "0 0 12 12",
10707
+ fill: "none",
10708
+ "aria-hidden": "true",
10709
+ children: /* @__PURE__ */ jsx57(
10710
+ "path",
10711
+ {
10712
+ d: "M2 2l8 8M10 2l-8 8",
10713
+ stroke: "currentColor",
10714
+ strokeWidth: "1.5",
10715
+ strokeLinecap: "round"
10716
+ }
10717
+ )
10718
+ }
10719
+ )
10720
+ }
10721
+ )
10722
+ ] }) }, c.value)),
10723
+ /* @__PURE__ */ jsx57(
10724
+ "input",
10725
+ {
10726
+ ref: inputRef,
10727
+ id: inputId,
10728
+ type: "text",
10729
+ role: "combobox",
10730
+ "aria-expanded": open,
10731
+ "aria-controls": listboxId,
10732
+ "aria-autocomplete": "list",
10733
+ "aria-label": ariaLabel,
10734
+ "aria-labelledby": ariaLabelledBy,
10735
+ disabled,
10736
+ placeholder: selected.length === 0 ? placeholder : void 0,
10737
+ className: cx(TagSelect_default.input, inputCollapsed && TagSelect_default.inputCollapsed),
10738
+ value: inputValue,
10739
+ onChange: (e) => {
10740
+ const next = e.target.value;
10741
+ setInputValue(next);
10742
+ const nextTrim = next.trim();
10743
+ const nextFiltered = optionsForList(options, next, selected);
10744
+ const nextShowCreate = shouldShowCreate(creatable, nextTrim, selected, options);
10745
+ if (nextFiltered.length > 0 || nextShowCreate) {
10746
+ setOpen(true);
10747
+ } else {
10748
+ setOpen(false);
10749
+ }
10750
+ },
10751
+ onKeyDown: onInputKeyDown,
10752
+ onFocus: () => {
10753
+ setInputFocused(true);
10754
+ if (!disabled && hasPanelContent) setOpen(true);
10755
+ },
10756
+ onBlur: handleInputBlur
10757
+ }
10758
+ )
10759
+ ] }),
10760
+ /* @__PURE__ */ jsx57("span", { className: TagSelect_default.chevronSlot, "aria-hidden": true, children: /* @__PURE__ */ jsx57("span", { className: TagSelect_default.chevron }) })
10761
+ ]
10762
+ }
10763
+ ),
10764
+ /* @__PURE__ */ jsx57(Portal, { children: /* @__PURE__ */ jsxs31(
10765
+ ScrollContainer,
10766
+ {
10767
+ ref: listboxRef,
10768
+ id: listboxId,
10769
+ role: "listbox",
10770
+ "aria-multiselectable": "true",
10771
+ "aria-hidden": !open,
10772
+ tabIndex: -1,
10773
+ "data-react-aria-top-layer": "true",
10774
+ "data-overlay-portal-layer": overlayPortalLayer,
10775
+ className: cx(Select_default.content, TagSelect_default.panelInner),
10776
+ onKeyDown: onListboxKeyDown,
10777
+ style: { display: open ? void 0 : "none" },
10778
+ ...toDataAttributes({ side: resolvedSide, size }),
10779
+ children: [
10780
+ hint ? /* @__PURE__ */ jsx57("div", { className: TagSelect_default.hint, children: /* @__PURE__ */ jsx57(Typography.Root, { as: "div", variant: "body-small", tone: "muted", children: hint }) }) : null,
10781
+ showCreate ? /* @__PURE__ */ jsxs31(
10782
+ "button",
10783
+ {
10784
+ type: "button",
10785
+ role: "option",
10786
+ "aria-selected": false,
10787
+ className: TagSelect_default.createRow,
10788
+ ...toDataAttributes({
10789
+ value: CREATE_VALUE,
10790
+ label: inputTrim,
10791
+ highlighted: highlightedValue === CREATE_VALUE,
10792
+ disabled: false
10793
+ }),
10794
+ onMouseDown: (e) => {
10795
+ e.preventDefault();
10796
+ },
10797
+ onMouseEnter: () => setHighlightedValue(CREATE_VALUE),
10798
+ onClick: () => handleSelectFromList(CREATE_VALUE),
10799
+ children: [
10800
+ /* @__PURE__ */ jsx57(
10801
+ Typography.Root,
10802
+ {
10803
+ as: "span",
10804
+ variant: "body-small",
10805
+ tone: "muted",
10806
+ className: TagSelect_default.createLabel,
10807
+ children: createActionLabel
10808
+ }
10809
+ ),
10810
+ /* @__PURE__ */ jsx57(Badge.Root, { color: defaultTagColor, variant: "filled", children: inputTrim })
10811
+ ]
10812
+ },
10813
+ CREATE_VALUE
10814
+ ) : null,
10815
+ filtered.map((o) => /* @__PURE__ */ jsx57(
10816
+ "button",
10817
+ {
10818
+ type: "button",
10819
+ role: "option",
10820
+ "aria-selected": false,
10821
+ disabled: o.disabled,
10822
+ className: TagSelect_default.optionRow,
10823
+ ...toDataAttributes({
10824
+ value: o.value,
10825
+ label: o.label,
10826
+ highlighted: highlightedValue === o.value,
10827
+ selected: false,
10828
+ disabled: Boolean(o.disabled)
10829
+ }),
10830
+ onMouseDown: (e) => {
10831
+ if (!o.disabled) e.preventDefault();
10832
+ },
10833
+ onMouseEnter: () => !o.disabled && setHighlightedValue(o.value),
10834
+ onClick: () => !o.disabled && handleSelectFromList(o.value),
10835
+ children: /* @__PURE__ */ jsx57(Badge.Root, { color: o.color ?? defaultTagColor, variant: "filled", children: o.label })
10836
+ },
10837
+ o.value
10838
+ ))
10839
+ ]
10840
+ }
10841
+ ) })
10842
+ ] });
10843
+ }
10844
+ TagSelectRoot.displayName = "TagSelectRoot";
10845
+ var TagSelect = {
10846
+ Root: TagSelectRoot
10847
+ };
10848
+
10849
+ // src/components/textarea/Textarea.tsx
10850
+ import * as React72 from "react";
10851
+
10152
10852
  // src/components/textarea/Textarea.module.css
10153
10853
  var Textarea_default = {
10154
10854
  field: "Textarea_field2",
@@ -10164,11 +10864,11 @@ var Textarea_default = {
10164
10864
  };
10165
10865
 
10166
10866
  // src/components/textarea/Textarea.tsx
10167
- import { jsx as jsx57, jsxs as jsxs31 } from "react/jsx-runtime";
10867
+ import { jsx as jsx58, jsxs as jsxs32 } from "react/jsx-runtime";
10168
10868
  var [TextareaProvider, useTextareaContext] = createComponentContext("Textarea");
10169
10869
  function TextareaCharCounter({ current, max }) {
10170
10870
  const overflow = current > max;
10171
- return /* @__PURE__ */ jsxs31(
10871
+ return /* @__PURE__ */ jsxs32(
10172
10872
  "span",
10173
10873
  {
10174
10874
  className: Textarea_default.charCounter,
@@ -10186,8 +10886,8 @@ TextareaCharCounter.displayName = "Textarea.CharCounter";
10186
10886
  function partitionTextareaChildren(children) {
10187
10887
  const counters = [];
10188
10888
  const rest = [];
10189
- React71.Children.forEach(children, (child) => {
10190
- if (React71.isValidElement(child) && child.type === TextareaCharCounter) {
10889
+ React72.Children.forEach(children, (child) => {
10890
+ if (React72.isValidElement(child) && child.type === TextareaCharCounter) {
10191
10891
  counters.push(child);
10192
10892
  } else if (child != null && child !== false) {
10193
10893
  rest.push(child);
@@ -10195,7 +10895,7 @@ function partitionTextareaChildren(children) {
10195
10895
  });
10196
10896
  return { counters, rest };
10197
10897
  }
10198
- var TextareaRoot = React71.forwardRef(
10898
+ var TextareaRoot = React72.forwardRef(
10199
10899
  ({
10200
10900
  id,
10201
10901
  className,
@@ -10212,12 +10912,12 @@ var TextareaRoot = React71.forwardRef(
10212
10912
  children,
10213
10913
  ...rest
10214
10914
  }, ref) => {
10215
- const rawId = React71.useId();
10915
+ const rawId = React72.useId();
10216
10916
  const inputId = id ?? rawId;
10217
10917
  const hintId = `${inputId}-hint`;
10218
10918
  const errorId = `${inputId}-error`;
10219
- const [hasHint, setHasHint] = React71.useState(false);
10220
- const [hasError, setHasError] = React71.useState(false);
10919
+ const [hasHint, setHasHint] = React72.useState(false);
10920
+ const [hasError, setHasError] = React72.useState(false);
10221
10921
  const invalid = variant === "error" || hasError;
10222
10922
  const resolvedAriaInvalid = ariaInvalid ?? (invalid || void 0);
10223
10923
  const parts = [
@@ -10226,25 +10926,25 @@ var TextareaRoot = React71.forwardRef(
10226
10926
  hasError ? errorId : void 0
10227
10927
  ].filter(Boolean);
10228
10928
  const describedBy = parts.length > 0 ? parts.join(" ") : void 0;
10229
- const registerHint = React71.useCallback(() => setHasHint(true), []);
10230
- const unregisterHint = React71.useCallback(() => setHasHint(false), []);
10231
- const registerError = React71.useCallback(() => setHasError(true), []);
10232
- const unregisterError = React71.useCallback(() => setHasError(false), []);
10233
- const wrapperRef = React71.useRef(null);
10929
+ const registerHint = React72.useCallback(() => setHasHint(true), []);
10930
+ const unregisterHint = React72.useCallback(() => setHasHint(false), []);
10931
+ const registerError = React72.useCallback(() => setHasError(true), []);
10932
+ const unregisterError = React72.useCallback(() => setHasError(false), []);
10933
+ const wrapperRef = React72.useRef(null);
10234
10934
  const { counters: counterChildren, rest: otherChildren } = partitionTextareaChildren(children);
10235
10935
  const showFooter = counterChildren.length > 0;
10236
- React71.useLayoutEffect(() => {
10936
+ React72.useLayoutEffect(() => {
10237
10937
  if (!autoResize || !wrapperRef.current) return;
10238
10938
  const textarea = wrapperRef.current.querySelector("textarea");
10239
10939
  if (textarea) {
10240
10940
  wrapperRef.current.dataset.value = textarea.value;
10241
10941
  }
10242
10942
  }, [autoResize]);
10243
- React71.useEffect(() => {
10943
+ React72.useEffect(() => {
10244
10944
  if (!autoResize || !wrapperRef.current || typeof value !== "string") return;
10245
10945
  wrapperRef.current.dataset.value = value;
10246
10946
  }, [autoResize, value]);
10247
- const handleInput = React71.useCallback(
10947
+ const handleInput = React72.useCallback(
10248
10948
  (e) => {
10249
10949
  if (autoResize && wrapperRef.current) {
10250
10950
  wrapperRef.current.dataset.value = e.currentTarget.value;
@@ -10253,7 +10953,7 @@ var TextareaRoot = React71.forwardRef(
10253
10953
  },
10254
10954
  [autoResize, onInput]
10255
10955
  );
10256
- const ctxValue = React71.useMemo(
10956
+ const ctxValue = React72.useMemo(
10257
10957
  () => ({
10258
10958
  hintId,
10259
10959
  errorId,
@@ -10277,7 +10977,7 @@ var TextareaRoot = React71.forwardRef(
10277
10977
  unregisterError
10278
10978
  ]
10279
10979
  );
10280
- const textareaEl = /* @__PURE__ */ jsx57(
10980
+ const textareaEl = /* @__PURE__ */ jsx58(
10281
10981
  "textarea",
10282
10982
  {
10283
10983
  ref,
@@ -10293,9 +10993,9 @@ var TextareaRoot = React71.forwardRef(
10293
10993
  ...rest
10294
10994
  }
10295
10995
  );
10296
- const textareaBlock = autoResize ? /* @__PURE__ */ jsx57("div", { ref: wrapperRef, className: Textarea_default.autoResize, children: textareaEl }) : textareaEl;
10297
- return /* @__PURE__ */ jsx57(TextareaProvider, { value: ctxValue, children: /* @__PURE__ */ jsx57(ControlSizeProvider, { value: size, children: /* @__PURE__ */ jsxs31("div", { className: Textarea_default.field, ...toDataAttributes({ size }), children: [
10298
- /* @__PURE__ */ jsx57(
10996
+ const textareaBlock = autoResize ? /* @__PURE__ */ jsx58("div", { ref: wrapperRef, className: Textarea_default.autoResize, children: textareaEl }) : textareaEl;
10997
+ return /* @__PURE__ */ jsx58(TextareaProvider, { value: ctxValue, children: /* @__PURE__ */ jsx58(ControlSizeProvider, { value: size, children: /* @__PURE__ */ jsxs32("div", { className: Textarea_default.field, ...toDataAttributes({ size }), children: [
10998
+ /* @__PURE__ */ jsx58(
10299
10999
  "label",
10300
11000
  {
10301
11001
  htmlFor: inputId,
@@ -10306,9 +11006,9 @@ var TextareaRoot = React71.forwardRef(
10306
11006
  readonly: Boolean(readOnly),
10307
11007
  size
10308
11008
  }),
10309
- children: /* @__PURE__ */ jsxs31("div", { className: Textarea_default.controlStack, children: [
10310
- /* @__PURE__ */ jsx57("div", { className: Textarea_default.textareaRegion, children: textareaBlock }),
10311
- showFooter ? /* @__PURE__ */ jsx57("div", { className: Textarea_default.controlFooter, children: counterChildren }) : null
11009
+ children: /* @__PURE__ */ jsxs32("div", { className: Textarea_default.controlStack, children: [
11010
+ /* @__PURE__ */ jsx58("div", { className: Textarea_default.textareaRegion, children: textareaBlock }),
11011
+ showFooter ? /* @__PURE__ */ jsx58("div", { className: Textarea_default.controlFooter, children: counterChildren }) : null
10312
11012
  ] })
10313
11013
  }
10314
11014
  ),
@@ -10319,13 +11019,13 @@ var TextareaRoot = React71.forwardRef(
10319
11019
  TextareaRoot.displayName = "Textarea.Root";
10320
11020
  function TextareaHint({ children, className, ...rest }) {
10321
11021
  const { hintId, registerHint, unregisterHint, size, disabled, readOnly } = useTextareaContext();
10322
- React71.useLayoutEffect(() => {
11022
+ React72.useLayoutEffect(() => {
10323
11023
  registerHint();
10324
11024
  return () => {
10325
11025
  unregisterHint();
10326
11026
  };
10327
11027
  }, [registerHint, unregisterHint]);
10328
- return /* @__PURE__ */ jsx57(
11028
+ return /* @__PURE__ */ jsx58(
10329
11029
  Hint.Root,
10330
11030
  {
10331
11031
  id: hintId,
@@ -10340,13 +11040,13 @@ function TextareaHint({ children, className, ...rest }) {
10340
11040
  TextareaHint.displayName = "Textarea.Hint";
10341
11041
  function TextareaError({ children, className, ...rest }) {
10342
11042
  const { errorId, registerError, unregisterError, size } = useTextareaContext();
10343
- React71.useLayoutEffect(() => {
11043
+ React72.useLayoutEffect(() => {
10344
11044
  registerError();
10345
11045
  return () => {
10346
11046
  unregisterError();
10347
11047
  };
10348
11048
  }, [registerError, unregisterError]);
10349
- return /* @__PURE__ */ jsx57(
11049
+ return /* @__PURE__ */ jsx58(
10350
11050
  Hint.Root,
10351
11051
  {
10352
11052
  id: errorId,
@@ -10419,6 +11119,7 @@ export {
10419
11119
  Switch,
10420
11120
  Tabs,
10421
11121
  Tag,
11122
+ TagSelect,
10422
11123
  Textarea,
10423
11124
  Tooltip,
10424
11125
  Typography,