@duskmoon-dev/components 0.5.3 → 0.5.4

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.
@@ -855,7 +855,7 @@ DmPagination.displayName = "DmPagination";
855
855
  // src/components/dm-search/DmSearch.tsx
856
856
  import {
857
857
  forwardRef as forwardRef7,
858
- useEffect as useEffect3,
858
+ useEffect as useEffect4,
859
859
  useImperativeHandle as useImperativeHandle3,
860
860
  useMemo as useMemo6,
861
861
  useState as useState8
@@ -1986,7 +1986,15 @@ var Input = Object.assign(InputRoot, {
1986
1986
  Group
1987
1987
  });
1988
1988
  // src/components/select/Select.tsx
1989
- import React7, { forwardRef as forwardRef6, useMemo as useMemo5, useState as useState7 } from "react";
1989
+ import React7, {
1990
+ forwardRef as forwardRef6,
1991
+ useCallback,
1992
+ useEffect as useEffect3,
1993
+ useId as useId2,
1994
+ useMemo as useMemo5,
1995
+ useRef as useRef4,
1996
+ useState as useState7
1997
+ } from "react";
1990
1998
 
1991
1999
  // src/classes/select.ts
1992
2000
  var selectContainerClass = "select-container";
@@ -2140,6 +2148,7 @@ var SelectRoot = forwardRef6(({
2140
2148
  "aria-required": ariaRequired,
2141
2149
  children,
2142
2150
  className,
2151
+ defaultOpen = false,
2143
2152
  defaultValue,
2144
2153
  disabled,
2145
2154
  filterOption,
@@ -2147,6 +2156,9 @@ var SelectRoot = forwardRef6(({
2147
2156
  loading,
2148
2157
  mode,
2149
2158
  onChange,
2159
+ onDropdownVisibleChange,
2160
+ onOpenChange,
2161
+ open: openProp,
2150
2162
  options,
2151
2163
  placeholder,
2152
2164
  showSearch,
@@ -2155,10 +2167,60 @@ var SelectRoot = forwardRef6(({
2155
2167
  value,
2156
2168
  ...props
2157
2169
  }, ref) => {
2170
+ const generatedId = useId2();
2171
+ const cleanId = generatedId.replace(/[^a-zA-Z0-9_-]/g, "");
2172
+ const triggerId = id || `select-${cleanId}`;
2173
+ const dropdownId = `select-dropdown-${cleanId}`;
2174
+ const anchorName = `--dm-select-${cleanId}`;
2175
+ const [internalOpen, setInternalOpen] = useState7(Boolean(defaultOpen));
2176
+ const isControlled = openProp !== undefined;
2177
+ const isOpen = isControlled ? Boolean(openProp) : internalOpen;
2178
+ const containerRef = useRef4(null);
2179
+ const dropdownRef = useRef4(null);
2180
+ const setOpenState = useCallback((nextOpen) => {
2181
+ if (!isControlled) {
2182
+ setInternalOpen(nextOpen);
2183
+ }
2184
+ onDropdownVisibleChange?.(nextOpen);
2185
+ onOpenChange?.(nextOpen);
2186
+ }, [isControlled, onDropdownVisibleChange, onOpenChange]);
2187
+ useEffect3(() => {
2188
+ const dropdown = dropdownRef.current;
2189
+ if (!dropdown || typeof dropdown.showPopover !== "function")
2190
+ return;
2191
+ if (isOpen && !dropdown.matches(":popover-open")) {
2192
+ try {
2193
+ dropdown.showPopover();
2194
+ } catch {}
2195
+ } else if (!isOpen && dropdown.matches(":popover-open")) {
2196
+ try {
2197
+ dropdown.hidePopover();
2198
+ } catch {}
2199
+ }
2200
+ }, [isOpen]);
2201
+ useEffect3(() => {
2202
+ if (!isOpen)
2203
+ return;
2204
+ const handlePointerDown = (event) => {
2205
+ const target = event.target;
2206
+ if (!target)
2207
+ return;
2208
+ if (containerRef.current?.contains(target))
2209
+ return;
2210
+ if (dropdownRef.current?.contains(target))
2211
+ return;
2212
+ setOpenState(false);
2213
+ };
2214
+ document.addEventListener("mousedown", handlePointerDown);
2215
+ document.addEventListener("touchstart", handlePointerDown);
2216
+ return () => {
2217
+ document.removeEventListener("mousedown", handlePointerDown);
2218
+ document.removeEventListener("touchstart", handlePointerDown);
2219
+ };
2220
+ }, [isOpen, setOpenState]);
2158
2221
  const multiple = mode === "multiple" || mode === "tags";
2159
2222
  const sourceOptions = useMemo5(() => options ?? optionsFromChildren(children), [children, options]);
2160
2223
  const flatOptions = useMemo5(() => flattenOptions(sourceOptions), [sourceOptions]);
2161
- const [open, setOpen] = useState7(false);
2162
2224
  const [searchValue, setSearchValue] = useState7("");
2163
2225
  const [internalValue, setInternalValue] = useState7(multiple ? normalizeMultiValue(defaultValue) : normalizeSingleValue(defaultValue));
2164
2226
  const controlled = value !== undefined;
@@ -2193,7 +2255,7 @@ var SelectRoot = forwardRef6(({
2193
2255
  emitChange(nextValues);
2194
2256
  } else {
2195
2257
  emitChange(option.value);
2196
- setOpen(false);
2258
+ setOpenState(false);
2197
2259
  }
2198
2260
  setSearchValue("");
2199
2261
  }
@@ -2249,15 +2311,23 @@ var SelectRoot = forwardRef6(({
2249
2311
  }, `group-${index}`);
2250
2312
  });
2251
2313
  }
2314
+ const setRefs = (node) => {
2315
+ containerRef.current = node;
2316
+ if (typeof ref === "function") {
2317
+ ref(node);
2318
+ } else if (ref) {
2319
+ ref.current = node;
2320
+ }
2321
+ };
2252
2322
  const selection = multiple ? selectedOptions.map((option) => /* @__PURE__ */ jsx8("span", {
2253
2323
  className: selectTagClass,
2254
2324
  children: renderValue(option)
2255
2325
  }, valueKey(option.value))) : renderValue(selectedOptions[0]);
2256
2326
  return /* @__PURE__ */ jsxs7("div", {
2257
2327
  ...props,
2258
- ref,
2328
+ ref: setRefs,
2259
2329
  className: getSelectContainerClasses({
2260
- open,
2330
+ open: isOpen,
2261
2331
  loading,
2262
2332
  disabled,
2263
2333
  full: true,
@@ -2266,7 +2336,7 @@ var SelectRoot = forwardRef6(({
2266
2336
  children: [
2267
2337
  /* @__PURE__ */ jsxs7("button", {
2268
2338
  type: "button",
2269
- id,
2339
+ id: triggerId,
2270
2340
  className: getSelectClasses({ size, status, disabled }),
2271
2341
  disabled: disabled || loading,
2272
2342
  "aria-describedby": ariaDescribedBy,
@@ -2276,8 +2346,14 @@ var SelectRoot = forwardRef6(({
2276
2346
  "aria-labelledby": ariaLabelledBy,
2277
2347
  "aria-required": ariaRequired,
2278
2348
  "aria-haspopup": "listbox",
2279
- "aria-expanded": open,
2280
- onClick: () => setOpen((current) => !current),
2349
+ "aria-expanded": isOpen,
2350
+ "aria-controls": dropdownId,
2351
+ style: { anchorName },
2352
+ onClick: () => {
2353
+ if (disabled || loading)
2354
+ return;
2355
+ setOpenState(!isOpen);
2356
+ },
2281
2357
  children: [
2282
2358
  /* @__PURE__ */ jsx8("span", {
2283
2359
  className: selectSelectionClass,
@@ -2325,10 +2401,22 @@ var SelectRoot = forwardRef6(({
2325
2401
  })
2326
2402
  })
2327
2403
  }) : null,
2328
- open ? /* @__PURE__ */ jsxs7("div", {
2329
- className: selectDropdownClass,
2404
+ isOpen ? /* @__PURE__ */ jsxs7("div", {
2405
+ id: dropdownId,
2406
+ ref: dropdownRef,
2407
+ popover: "auto",
2330
2408
  role: "listbox",
2331
2409
  "aria-multiselectable": multiple || undefined,
2410
+ className: selectDropdownClass,
2411
+ style: { positionAnchor: anchorName },
2412
+ onToggle: (event) => {
2413
+ if (event.target !== event.currentTarget)
2414
+ return;
2415
+ const nextOpen = event.nativeEvent?.newState === "open";
2416
+ if (nextOpen !== isOpen) {
2417
+ setOpenState(nextOpen);
2418
+ }
2419
+ },
2332
2420
  children: [
2333
2421
  searchable ? /* @__PURE__ */ jsx8("input", {
2334
2422
  className: selectSearchClass,
@@ -2462,7 +2550,7 @@ var DmSearch = forwardRef7(({
2462
2550
  const controlled = controlledValues !== undefined;
2463
2551
  const values = controlled ? controlledValues : internalValues;
2464
2552
  const visibleItems = collapsed ? allItems.slice(0, 1) : allItems;
2465
- useEffect3(() => {
2553
+ useEffect4(() => {
2466
2554
  if (!controlled)
2467
2555
  setValues(initialValues(allItems, searchParams));
2468
2556
  }, [allItems, searchParams, controlled]);
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/json-schema-form/JsonSchemaForm.tsx
4
- import { useId as useId5, useMemo as useMemo11, useRef as useRef9, useState as useState20 } from "react";
4
+ import { useId as useId6, useMemo as useMemo11, useRef as useRef10, useState as useState20 } from "react";
5
5
 
6
6
  // src/components/button/Button.tsx
7
7
  import React from "react";
@@ -4061,7 +4061,15 @@ var Segmented = forwardRef15(({
4061
4061
  });
4062
4062
  Segmented.displayName = "Segmented";
4063
4063
  // src/components/select/Select.tsx
4064
- import React15, { forwardRef as forwardRef16, useMemo as useMemo7, useState as useState14 } from "react";
4064
+ import React15, {
4065
+ forwardRef as forwardRef16,
4066
+ useCallback as useCallback3,
4067
+ useEffect as useEffect5,
4068
+ useId as useId5,
4069
+ useMemo as useMemo7,
4070
+ useRef as useRef7,
4071
+ useState as useState14
4072
+ } from "react";
4065
4073
 
4066
4074
  // src/classes/select.ts
4067
4075
  var selectContainerClass = "select-container";
@@ -4215,6 +4223,7 @@ var SelectRoot = forwardRef16(({
4215
4223
  "aria-required": ariaRequired,
4216
4224
  children,
4217
4225
  className,
4226
+ defaultOpen = false,
4218
4227
  defaultValue,
4219
4228
  disabled,
4220
4229
  filterOption,
@@ -4222,6 +4231,9 @@ var SelectRoot = forwardRef16(({
4222
4231
  loading,
4223
4232
  mode,
4224
4233
  onChange,
4234
+ onDropdownVisibleChange,
4235
+ onOpenChange,
4236
+ open: openProp,
4225
4237
  options,
4226
4238
  placeholder,
4227
4239
  showSearch,
@@ -4230,10 +4242,60 @@ var SelectRoot = forwardRef16(({
4230
4242
  value,
4231
4243
  ...props
4232
4244
  }, ref) => {
4245
+ const generatedId = useId5();
4246
+ const cleanId = generatedId.replace(/[^a-zA-Z0-9_-]/g, "");
4247
+ const triggerId = id || `select-${cleanId}`;
4248
+ const dropdownId = `select-dropdown-${cleanId}`;
4249
+ const anchorName = `--dm-select-${cleanId}`;
4250
+ const [internalOpen, setInternalOpen] = useState14(Boolean(defaultOpen));
4251
+ const isControlled = openProp !== undefined;
4252
+ const isOpen = isControlled ? Boolean(openProp) : internalOpen;
4253
+ const containerRef = useRef7(null);
4254
+ const dropdownRef = useRef7(null);
4255
+ const setOpenState = useCallback3((nextOpen) => {
4256
+ if (!isControlled) {
4257
+ setInternalOpen(nextOpen);
4258
+ }
4259
+ onDropdownVisibleChange?.(nextOpen);
4260
+ onOpenChange?.(nextOpen);
4261
+ }, [isControlled, onDropdownVisibleChange, onOpenChange]);
4262
+ useEffect5(() => {
4263
+ const dropdown = dropdownRef.current;
4264
+ if (!dropdown || typeof dropdown.showPopover !== "function")
4265
+ return;
4266
+ if (isOpen && !dropdown.matches(":popover-open")) {
4267
+ try {
4268
+ dropdown.showPopover();
4269
+ } catch {}
4270
+ } else if (!isOpen && dropdown.matches(":popover-open")) {
4271
+ try {
4272
+ dropdown.hidePopover();
4273
+ } catch {}
4274
+ }
4275
+ }, [isOpen]);
4276
+ useEffect5(() => {
4277
+ if (!isOpen)
4278
+ return;
4279
+ const handlePointerDown = (event) => {
4280
+ const target = event.target;
4281
+ if (!target)
4282
+ return;
4283
+ if (containerRef.current?.contains(target))
4284
+ return;
4285
+ if (dropdownRef.current?.contains(target))
4286
+ return;
4287
+ setOpenState(false);
4288
+ };
4289
+ document.addEventListener("mousedown", handlePointerDown);
4290
+ document.addEventListener("touchstart", handlePointerDown);
4291
+ return () => {
4292
+ document.removeEventListener("mousedown", handlePointerDown);
4293
+ document.removeEventListener("touchstart", handlePointerDown);
4294
+ };
4295
+ }, [isOpen, setOpenState]);
4233
4296
  const multiple = mode === "multiple" || mode === "tags";
4234
4297
  const sourceOptions = useMemo7(() => options ?? optionsFromChildren2(children), [children, options]);
4235
4298
  const flatOptions = useMemo7(() => flattenOptions(sourceOptions), [sourceOptions]);
4236
- const [open, setOpen] = useState14(false);
4237
4299
  const [searchValue, setSearchValue] = useState14("");
4238
4300
  const [internalValue, setInternalValue] = useState14(multiple ? normalizeMultiValue(defaultValue) : normalizeSingleValue2(defaultValue));
4239
4301
  const controlled = value !== undefined;
@@ -4268,7 +4330,7 @@ var SelectRoot = forwardRef16(({
4268
4330
  emitChange(nextValues);
4269
4331
  } else {
4270
4332
  emitChange(option.value);
4271
- setOpen(false);
4333
+ setOpenState(false);
4272
4334
  }
4273
4335
  setSearchValue("");
4274
4336
  }
@@ -4324,15 +4386,23 @@ var SelectRoot = forwardRef16(({
4324
4386
  }, `group-${index}`);
4325
4387
  });
4326
4388
  }
4389
+ const setRefs = (node) => {
4390
+ containerRef.current = node;
4391
+ if (typeof ref === "function") {
4392
+ ref(node);
4393
+ } else if (ref) {
4394
+ ref.current = node;
4395
+ }
4396
+ };
4327
4397
  const selection = multiple ? selectedOptions.map((option) => /* @__PURE__ */ jsx17("span", {
4328
4398
  className: selectTagClass,
4329
4399
  children: renderValue(option)
4330
4400
  }, valueKey2(option.value))) : renderValue(selectedOptions[0]);
4331
4401
  return /* @__PURE__ */ jsxs15("div", {
4332
4402
  ...props,
4333
- ref,
4403
+ ref: setRefs,
4334
4404
  className: getSelectContainerClasses({
4335
- open,
4405
+ open: isOpen,
4336
4406
  loading,
4337
4407
  disabled,
4338
4408
  full: true,
@@ -4341,7 +4411,7 @@ var SelectRoot = forwardRef16(({
4341
4411
  children: [
4342
4412
  /* @__PURE__ */ jsxs15("button", {
4343
4413
  type: "button",
4344
- id,
4414
+ id: triggerId,
4345
4415
  className: getSelectClasses({ size, status, disabled }),
4346
4416
  disabled: disabled || loading,
4347
4417
  "aria-describedby": ariaDescribedBy,
@@ -4351,8 +4421,14 @@ var SelectRoot = forwardRef16(({
4351
4421
  "aria-labelledby": ariaLabelledBy,
4352
4422
  "aria-required": ariaRequired,
4353
4423
  "aria-haspopup": "listbox",
4354
- "aria-expanded": open,
4355
- onClick: () => setOpen((current) => !current),
4424
+ "aria-expanded": isOpen,
4425
+ "aria-controls": dropdownId,
4426
+ style: { anchorName },
4427
+ onClick: () => {
4428
+ if (disabled || loading)
4429
+ return;
4430
+ setOpenState(!isOpen);
4431
+ },
4356
4432
  children: [
4357
4433
  /* @__PURE__ */ jsx17("span", {
4358
4434
  className: selectSelectionClass,
@@ -4400,10 +4476,22 @@ var SelectRoot = forwardRef16(({
4400
4476
  })
4401
4477
  })
4402
4478
  }) : null,
4403
- open ? /* @__PURE__ */ jsxs15("div", {
4404
- className: selectDropdownClass,
4479
+ isOpen ? /* @__PURE__ */ jsxs15("div", {
4480
+ id: dropdownId,
4481
+ ref: dropdownRef,
4482
+ popover: "auto",
4405
4483
  role: "listbox",
4406
4484
  "aria-multiselectable": multiple || undefined,
4485
+ className: selectDropdownClass,
4486
+ style: { positionAnchor: anchorName },
4487
+ onToggle: (event) => {
4488
+ if (event.target !== event.currentTarget)
4489
+ return;
4490
+ const nextOpen = event.nativeEvent?.newState === "open";
4491
+ if (nextOpen !== isOpen) {
4492
+ setOpenState(nextOpen);
4493
+ }
4494
+ },
4407
4495
  children: [
4408
4496
  searchable ? /* @__PURE__ */ jsx17("input", {
4409
4497
  className: selectSearchClass,
@@ -4433,9 +4521,9 @@ Select.OptGroup = OptGroup;
4433
4521
  // src/components/slider/Slider.tsx
4434
4522
  import React16, {
4435
4523
  forwardRef as forwardRef17,
4436
- useEffect as useEffect5,
4524
+ useEffect as useEffect6,
4437
4525
  useMemo as useMemo8,
4438
- useRef as useRef7,
4526
+ useRef as useRef8,
4439
4527
  useState as useState15
4440
4528
  } from "react";
4441
4529
 
@@ -4675,8 +4763,8 @@ var Slider = forwardRef17(({
4675
4763
  step,
4676
4764
  range: isRange
4677
4765
  });
4678
- const lastCommittedValue = useRef7(currentValue);
4679
- useEffect5(() => {
4766
+ const lastCommittedValue = useRef8(currentValue);
4767
+ useEffect6(() => {
4680
4768
  lastCommittedValue.current = currentValue;
4681
4769
  }, [currentValue]);
4682
4770
  function commitValue(nextValue) {
@@ -6079,7 +6167,7 @@ TreeSelect.SHOW_ALL = SHOW_ALL;
6079
6167
  TreeSelect.SHOW_PARENT = SHOW_PARENT;
6080
6168
  TreeSelect.SHOW_CHILD = SHOW_CHILD;
6081
6169
  // src/components/upload/Upload.tsx
6082
- import React20, { forwardRef as forwardRef21, useLayoutEffect as useLayoutEffect2, useRef as useRef8, useState as useState19 } from "react";
6170
+ import React20, { forwardRef as forwardRef21, useLayoutEffect as useLayoutEffect2, useRef as useRef9, useState as useState19 } from "react";
6083
6171
 
6084
6172
  // src/classes/upload.ts
6085
6173
  var uploadBaseClass = "file-upload";
@@ -6179,12 +6267,12 @@ function UploadRoot({
6179
6267
  dragger,
6180
6268
  ...props
6181
6269
  }, ref) {
6182
- const inputRef = useRef8(null);
6270
+ const inputRef = useRef9(null);
6183
6271
  const [dragover, setDragover] = useState19(false);
6184
6272
  const [internalFileList, setInternalFileList] = useState19(() => defaultFileList.map(ensureUid));
6185
6273
  const controlled = fileList !== undefined;
6186
6274
  const mergedFileList = (controlled ? fileList : internalFileList).map(ensureUid);
6187
- const currentFileListRef = useRef8(mergedFileList);
6275
+ const currentFileListRef = useRef9(mergedFileList);
6188
6276
  useLayoutEffect2(() => {
6189
6277
  currentFileListRef.current = mergedFileList;
6190
6278
  }, [mergedFileList]);
@@ -7307,8 +7395,8 @@ function JsonSchemaForm({
7307
7395
  const [resetRevision, setResetRevision] = useState20(0);
7308
7396
  const [internalErrors, setErrors] = useState20({});
7309
7397
  const errors = { ...internalErrors, ...suppliedErrors };
7310
- const formRef = useRef9(null);
7311
- const idPrefix = useId5().replaceAll(":", "");
7398
+ const formRef = useRef10(null);
7399
+ const idPrefix = useId6().replaceAll(":", "");
7312
7400
  function changeErrors(next) {
7313
7401
  setErrors(next);
7314
7402
  onErrorsChange?.({ ...next });
@@ -19,12 +19,16 @@ export type SelectChangeValue = SelectValue | SelectValue[] | undefined;
19
19
  export interface SelectProps extends Omit<ComponentProps<"div">, "children" | "defaultValue" | "onChange"> {
20
20
  allowClear?: boolean;
21
21
  children?: ReactNode;
22
+ defaultOpen?: boolean;
22
23
  defaultValue?: SelectChangeValue;
23
24
  disabled?: boolean;
24
25
  filterOption?: boolean | ((inputValue: string, option: SelectOptionType) => boolean);
25
26
  loading?: boolean;
26
27
  mode?: SelectMode;
27
28
  onChange?: (value: SelectChangeValue, option?: SelectOptionType | SelectOptionType[]) => void;
29
+ onDropdownVisibleChange?: (open: boolean) => void;
30
+ onOpenChange?: (open: boolean) => void;
31
+ open?: boolean;
28
32
  options?: SelectOptionInput[];
29
33
  placeholder?: ReactNode;
30
34
  showSearch?: boolean;
@@ -1,7 +1,15 @@
1
1
  "use client";
2
2
 
3
3
  // src/components/select/Select.tsx
4
- import React, { forwardRef, useMemo, useState } from "react";
4
+ import React, {
5
+ forwardRef,
6
+ useCallback,
7
+ useEffect,
8
+ useId,
9
+ useMemo,
10
+ useRef,
11
+ useState
12
+ } from "react";
5
13
 
6
14
  // ../../node_modules/.bun/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
7
15
  function r(e) {
@@ -180,6 +188,7 @@ var SelectRoot = forwardRef(({
180
188
  "aria-required": ariaRequired,
181
189
  children,
182
190
  className,
191
+ defaultOpen = false,
183
192
  defaultValue,
184
193
  disabled,
185
194
  filterOption,
@@ -187,6 +196,9 @@ var SelectRoot = forwardRef(({
187
196
  loading,
188
197
  mode,
189
198
  onChange,
199
+ onDropdownVisibleChange,
200
+ onOpenChange,
201
+ open: openProp,
190
202
  options,
191
203
  placeholder,
192
204
  showSearch,
@@ -195,10 +207,60 @@ var SelectRoot = forwardRef(({
195
207
  value,
196
208
  ...props
197
209
  }, ref) => {
210
+ const generatedId = useId();
211
+ const cleanId = generatedId.replace(/[^a-zA-Z0-9_-]/g, "");
212
+ const triggerId = id || `select-${cleanId}`;
213
+ const dropdownId = `select-dropdown-${cleanId}`;
214
+ const anchorName = `--dm-select-${cleanId}`;
215
+ const [internalOpen, setInternalOpen] = useState(Boolean(defaultOpen));
216
+ const isControlled = openProp !== undefined;
217
+ const isOpen = isControlled ? Boolean(openProp) : internalOpen;
218
+ const containerRef = useRef(null);
219
+ const dropdownRef = useRef(null);
220
+ const setOpenState = useCallback((nextOpen) => {
221
+ if (!isControlled) {
222
+ setInternalOpen(nextOpen);
223
+ }
224
+ onDropdownVisibleChange?.(nextOpen);
225
+ onOpenChange?.(nextOpen);
226
+ }, [isControlled, onDropdownVisibleChange, onOpenChange]);
227
+ useEffect(() => {
228
+ const dropdown = dropdownRef.current;
229
+ if (!dropdown || typeof dropdown.showPopover !== "function")
230
+ return;
231
+ if (isOpen && !dropdown.matches(":popover-open")) {
232
+ try {
233
+ dropdown.showPopover();
234
+ } catch {}
235
+ } else if (!isOpen && dropdown.matches(":popover-open")) {
236
+ try {
237
+ dropdown.hidePopover();
238
+ } catch {}
239
+ }
240
+ }, [isOpen]);
241
+ useEffect(() => {
242
+ if (!isOpen)
243
+ return;
244
+ const handlePointerDown = (event) => {
245
+ const target = event.target;
246
+ if (!target)
247
+ return;
248
+ if (containerRef.current?.contains(target))
249
+ return;
250
+ if (dropdownRef.current?.contains(target))
251
+ return;
252
+ setOpenState(false);
253
+ };
254
+ document.addEventListener("mousedown", handlePointerDown);
255
+ document.addEventListener("touchstart", handlePointerDown);
256
+ return () => {
257
+ document.removeEventListener("mousedown", handlePointerDown);
258
+ document.removeEventListener("touchstart", handlePointerDown);
259
+ };
260
+ }, [isOpen, setOpenState]);
198
261
  const multiple = mode === "multiple" || mode === "tags";
199
262
  const sourceOptions = useMemo(() => options ?? optionsFromChildren(children), [children, options]);
200
263
  const flatOptions = useMemo(() => flattenOptions(sourceOptions), [sourceOptions]);
201
- const [open, setOpen] = useState(false);
202
264
  const [searchValue, setSearchValue] = useState("");
203
265
  const [internalValue, setInternalValue] = useState(multiple ? normalizeMultiValue(defaultValue) : normalizeSingleValue(defaultValue));
204
266
  const controlled = value !== undefined;
@@ -233,7 +295,7 @@ var SelectRoot = forwardRef(({
233
295
  emitChange(nextValues);
234
296
  } else {
235
297
  emitChange(option.value);
236
- setOpen(false);
298
+ setOpenState(false);
237
299
  }
238
300
  setSearchValue("");
239
301
  }
@@ -289,15 +351,23 @@ var SelectRoot = forwardRef(({
289
351
  }, `group-${index}`);
290
352
  });
291
353
  }
354
+ const setRefs = (node) => {
355
+ containerRef.current = node;
356
+ if (typeof ref === "function") {
357
+ ref(node);
358
+ } else if (ref) {
359
+ ref.current = node;
360
+ }
361
+ };
292
362
  const selection = multiple ? selectedOptions.map((option) => /* @__PURE__ */ jsx("span", {
293
363
  className: selectTagClass,
294
364
  children: renderValue(option)
295
365
  }, valueKey(option.value))) : renderValue(selectedOptions[0]);
296
366
  return /* @__PURE__ */ jsxs("div", {
297
367
  ...props,
298
- ref,
368
+ ref: setRefs,
299
369
  className: getSelectContainerClasses({
300
- open,
370
+ open: isOpen,
301
371
  loading,
302
372
  disabled,
303
373
  full: true,
@@ -306,7 +376,7 @@ var SelectRoot = forwardRef(({
306
376
  children: [
307
377
  /* @__PURE__ */ jsxs("button", {
308
378
  type: "button",
309
- id,
379
+ id: triggerId,
310
380
  className: getSelectClasses({ size, status, disabled }),
311
381
  disabled: disabled || loading,
312
382
  "aria-describedby": ariaDescribedBy,
@@ -316,8 +386,14 @@ var SelectRoot = forwardRef(({
316
386
  "aria-labelledby": ariaLabelledBy,
317
387
  "aria-required": ariaRequired,
318
388
  "aria-haspopup": "listbox",
319
- "aria-expanded": open,
320
- onClick: () => setOpen((current) => !current),
389
+ "aria-expanded": isOpen,
390
+ "aria-controls": dropdownId,
391
+ style: { anchorName },
392
+ onClick: () => {
393
+ if (disabled || loading)
394
+ return;
395
+ setOpenState(!isOpen);
396
+ },
321
397
  children: [
322
398
  /* @__PURE__ */ jsx("span", {
323
399
  className: selectSelectionClass,
@@ -365,10 +441,22 @@ var SelectRoot = forwardRef(({
365
441
  })
366
442
  })
367
443
  }) : null,
368
- open ? /* @__PURE__ */ jsxs("div", {
369
- className: selectDropdownClass,
444
+ isOpen ? /* @__PURE__ */ jsxs("div", {
445
+ id: dropdownId,
446
+ ref: dropdownRef,
447
+ popover: "auto",
370
448
  role: "listbox",
371
449
  "aria-multiselectable": multiple || undefined,
450
+ className: selectDropdownClass,
451
+ style: { positionAnchor: anchorName },
452
+ onToggle: (event) => {
453
+ if (event.target !== event.currentTarget)
454
+ return;
455
+ const nextOpen = event.nativeEvent?.newState === "open";
456
+ if (nextOpen !== isOpen) {
457
+ setOpenState(nextOpen);
458
+ }
459
+ },
372
460
  children: [
373
461
  searchable ? /* @__PURE__ */ jsx("input", {
374
462
  className: selectSearchClass,
@@ -1 +1 @@
1
- export declare const version = "0.5.3";
1
+ export declare const version = "0.5.4";