dishui 0.0.83 → 0.0.89

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 (100) hide show
  1. package/dist/components/Demo/index.js +2 -2
  2. package/dist/components/Demo/index.js.map +1 -1
  3. package/dist/components/Input/index.js +52 -62
  4. package/dist/components/Input/index.js.map +1 -1
  5. package/dist/components/LayoutSuite/index.d.ts +10 -0
  6. package/dist/components/LayoutSuite/index.js +27 -18
  7. package/dist/components/LayoutSuite/index.js.map +1 -1
  8. package/dist/components/Markdown/markdownComponents.js +1 -0
  9. package/dist/components/Markdown/markdownComponents.js.map +1 -1
  10. package/dist/components/Markdown/useMarkdownSource.js +46 -31
  11. package/dist/components/Markdown/useMarkdownSource.js.map +1 -1
  12. package/dist/components/Markdown/useMarkmapRenderer.js +44 -31
  13. package/dist/components/Markdown/useMarkmapRenderer.js.map +1 -1
  14. package/dist/components/Markdown/useMermaidRenderer.js +49 -31
  15. package/dist/components/Markdown/useMermaidRenderer.js.map +1 -1
  16. package/dist/components/Page/index.d.ts +18 -4
  17. package/dist/components/Page/index.js +47 -35
  18. package/dist/components/Page/index.js.map +1 -1
  19. package/dist/components/ProtectedRoute/index.d.ts +2 -1
  20. package/dist/components/ProtectedRoute/index.js +16 -6
  21. package/dist/components/ProtectedRoute/index.js.map +1 -1
  22. package/dist/components/Select/index.d.ts +6 -0
  23. package/dist/components/Select/index.js +166 -136
  24. package/dist/components/Select/index.js.map +1 -1
  25. package/dist/components/Tabs/index.d.ts +12 -1
  26. package/dist/components/Tabs/index.js +42 -17
  27. package/dist/components/Tabs/index.js.map +1 -1
  28. package/dist/components/Text/index.d.ts +1 -1
  29. package/dist/components/Text/index.js +2 -2
  30. package/dist/components/Text/index.js.map +1 -1
  31. package/dist/components/pro/ArticleContextMenu/index.js +7 -7
  32. package/dist/components/pro/CodeEditor/editors/CodeEditor.js +200 -189
  33. package/dist/components/pro/CodeEditor/editors/CodeEditor.js.map +1 -1
  34. package/dist/components/pro/CodeEditor/types.d.ts +3 -0
  35. package/dist/components/pro/DataTable/DataTable.d.ts +1 -1
  36. package/dist/components/pro/DataTable/DataTable.js +98 -240
  37. package/dist/components/pro/DataTable/DataTable.js.map +1 -1
  38. package/dist/components/pro/DataTable/components/TableBody.js +14 -16
  39. package/dist/components/pro/DataTable/components/TableBody.js.map +1 -1
  40. package/dist/components/pro/DataTable/components/TablePagination.d.ts +3 -9
  41. package/dist/components/pro/DataTable/components/TablePagination.js +29 -25
  42. package/dist/components/pro/DataTable/components/TablePagination.js.map +1 -1
  43. package/dist/components/pro/DataTable/tanstack-table.d.ts +2 -2
  44. package/dist/components/pro/DataTable/tanstack-table.js +29 -21
  45. package/dist/components/pro/DataTable/tanstack-table.js.map +1 -1
  46. package/dist/components/pro/DataTable/treeDataUtils.d.ts +2 -0
  47. package/dist/components/pro/DataTable/treeDataUtils.js +18 -19
  48. package/dist/components/pro/DataTable/treeDataUtils.js.map +1 -1
  49. package/dist/components/pro/DataTable/types.d.ts +24 -0
  50. package/dist/components/pro/DataTable/useDataTableModel.d.ts +16 -0
  51. package/dist/components/pro/DataTable/useDataTableModel.js +148 -0
  52. package/dist/components/pro/DataTable/useDataTableModel.js.map +1 -0
  53. package/dist/components/pro/FileExplorer/Breadcrumb.js +12 -12
  54. package/dist/components/pro/Flow/nodes/DataNodeView.js +87 -82
  55. package/dist/components/pro/Flow/nodes/DataNodeView.js.map +1 -1
  56. package/dist/components/pro/Flow/nodes/MediaContent.js +1 -1
  57. package/dist/components/pro/Flow/nodes/MediaContent.js.map +1 -1
  58. package/dist/components/pro/Flow/nodes/MediaOverlay.js +1 -1
  59. package/dist/components/pro/Flow/nodes/MediaOverlay.js.map +1 -1
  60. package/dist/components/pro/Flow/nodes/Model3DView.js +69 -63
  61. package/dist/components/pro/Flow/nodes/Model3DView.js.map +1 -1
  62. package/dist/components/pro/Flow/nodes/chartGeometryBudget.d.ts +14 -0
  63. package/dist/components/pro/Flow/nodes/chartGeometryBudget.js +76 -0
  64. package/dist/components/pro/Flow/nodes/chartGeometryBudget.js.map +1 -0
  65. package/dist/components/pro/Flow/nodes/demandRender.d.ts +11 -0
  66. package/dist/components/pro/Flow/nodes/demandRender.js +26 -0
  67. package/dist/components/pro/Flow/nodes/demandRender.js.map +1 -0
  68. package/dist/components/pro/RichTextEditor/SlashMenu.js +68 -58
  69. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  70. package/dist/contexts/AppContext.d.ts +1 -0
  71. package/dist/contexts/AppContext.js +144 -145
  72. package/dist/contexts/AppContext.js.map +1 -1
  73. package/dist/contexts/authentication.d.ts +7 -0
  74. package/dist/contexts/authentication.js +22 -0
  75. package/dist/contexts/authentication.js.map +1 -0
  76. package/dist/dishui.css +1 -1
  77. package/dist/hooks/useControllableState.d.ts +6 -14
  78. package/dist/hooks/useControllableState.js +21 -15
  79. package/dist/hooks/useControllableState.js.map +1 -1
  80. package/dist/hooks/useTableColumns.d.ts +3 -3
  81. package/dist/hooks/useTableColumns.js +2 -2
  82. package/dist/hooks/useTableColumns.js.map +1 -1
  83. package/dist/hooks/useTableData.d.ts +11 -4
  84. package/dist/hooks/useTableData.js +44 -26
  85. package/dist/hooks/useTableData.js.map +1 -1
  86. package/dist/index-nostyled.d.ts +2 -2
  87. package/dist/index.d.ts +2 -2
  88. package/dist/index.js +97 -97
  89. package/dist/layouts/Sidebar.d.ts +3 -1
  90. package/dist/layouts/Sidebar.js +131 -122
  91. package/dist/layouts/Sidebar.js.map +1 -1
  92. package/dist/utils/i18n.js +1 -1
  93. package/dist/utils/i18n.js.map +1 -1
  94. package/dist/utils/routerBuilder.d.ts +7 -5
  95. package/dist/utils/routerBuilder.js +11 -15
  96. package/dist/utils/routerBuilder.js.map +1 -1
  97. package/dist/utils/safeStorage.d.ts +8 -0
  98. package/dist/utils/safeStorage.js +45 -0
  99. package/dist/utils/safeStorage.js.map +1 -0
  100. package/package.json +22 -5
@@ -9,7 +9,8 @@ export type ProtectedRouteProps = {
9
9
  /**
10
10
  * ProtectedRoute 组件
11
11
  *
12
- * 用于保护需要认证或特定角色才能访问的路由
12
+ * 用于保护需要认证或特定角色才能访问的页面内容。
13
+ * 组件渲染晚于 loader;数据访问必须使用路由 beforeLoad 和服务端授权。
13
14
  *
14
15
  * @example
15
16
  * ```tsx
@@ -1,12 +1,22 @@
1
1
  import { useAuth as e } from "../../contexts/AppContext.js";
2
- import "react";
3
- import { Fragment as t, jsx as n } from "react/jsx-runtime";
2
+ import { useEffect as t, useRef as n } from "react";
3
+ import { Fragment as r, jsx as i } from "react/jsx-runtime";
4
4
  //#region src/components/ProtectedRoute/index.tsx
5
- var r = ({ children: r, requiredRoles: i = [], requireAny: a = !1, fallbackPath: o = "/login", fallback: s }) => {
6
- let { isAuthenticated: c, hasRole: l, hasAnyRole: u } = e();
7
- return c ? i.length > 0 && !(a ? u(i) : i.every((e) => l(e))) ? s ? /* @__PURE__ */ n(t, { children: s }) : (typeof window < "u" && (window.location.href = "/unauthorized"), null) : /* @__PURE__ */ n(t, { children: r }) : s ? /* @__PURE__ */ n(t, { children: s }) : (typeof window < "u" && (window.location.href = o), null);
5
+ var a = ({ children: a, requiredRoles: o = [], requireAny: s = !1, fallbackPath: c = "/login", fallback: l }) => {
6
+ let { isAuthenticated: u, hasRole: d, hasAnyRole: f } = e(), p = o.length === 0 || (s ? f(o) : o.every((e) => d(e))), m = !u || !p, h = u ? "/unauthorized" : c, g = l != null, _ = n(null);
7
+ return t(() => {
8
+ if (!m || g) {
9
+ _.current = null;
10
+ return;
11
+ }
12
+ typeof window < "u" && _.current !== h && (_.current = h, window.location.href = h);
13
+ }, [
14
+ m,
15
+ g,
16
+ h
17
+ ]), m ? g ? /* @__PURE__ */ i(r, { children: l }) : null : /* @__PURE__ */ i(r, { children: a });
8
18
  };
9
19
  //#endregion
10
- export { r as ProtectedRoute, r as default };
20
+ export { a as ProtectedRoute, a as default };
11
21
 
12
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/ProtectedRoute/index.tsx"],"sourcesContent":["import React from 'react';\nimport { useAuth } from '../../contexts/AppContext';\n\nexport type ProtectedRouteProps = {\n children: React.ReactNode;\n requiredRoles?: string[];\n requireAny?: boolean; // 如果为 true,只需要满足任一角色;如果为 false,需要满足所有角色\n fallbackPath?: string;\n fallback?: React.ReactNode;\n};\n\n/**\n * ProtectedRoute 组件\n * \n * 用于保护需要认证或特定角色才能访问的路由\n * \n * @example\n * ```tsx\n * // 基本用法 - 只需要认证\n * <ProtectedRoute>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要特定角色\n * <ProtectedRoute requiredRoles={['admin']}>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要任一角色\n * <ProtectedRoute requiredRoles={['admin', 'moderator']} requireAny>\n * <ModeratorPanel />\n * </ProtectedRoute>\n * \n * // 自定义回退路径\n * <ProtectedRoute fallbackPath=\"/unauthorized\">\n * <SecretPage />\n * </ProtectedRoute>\n * \n * // 自定义回退组件\n * <ProtectedRoute fallback={<UnauthorizedMessage />}>\n * <SecretPage />\n * </ProtectedRoute>\n * ```\n */\nexport const ProtectedRoute: React.FC<ProtectedRouteProps> = ({\n children,\n requiredRoles = [],\n requireAny = false,\n fallbackPath = '/login',\n fallback,\n}) => {\n const { isAuthenticated, hasRole, hasAnyRole } = useAuth();\n\n // 检查是否已认证\n if (!isAuthenticated) {\n if (fallback) {\n return <>{fallback}</>;\n }\n // 使用 window.location 进行重定向,避免类型问题\n if (typeof window !== 'undefined') {\n window.location.href = fallbackPath;\n }\n return null;\n }\n\n // 如果需要特定角色\n if (requiredRoles.length > 0) {\n const hasRequiredRoles = requireAny \n ? hasAnyRole(requiredRoles)\n : requiredRoles.every(role => hasRole(role));\n\n if (!hasRequiredRoles) {\n if (fallback) {\n return <>{fallback}</>;\n }\n // 使用 window.location 进行重定向\n if (typeof window !== 'undefined') {\n window.location.href = '/unauthorized';\n }\n return null;\n }\n }\n\n return <>{children}</>;\n};\n\nexport default ProtectedRoute;\n\n"],"mappings":";;;;AA4CA,IAAa,KAAiD,EAC5D,aACA,mBAAgB,CAAC,GACjB,gBAAa,IACb,kBAAe,UACf,kBACI;CACJ,IAAM,EAAE,oBAAiB,YAAS,kBAAe,EAAQ;CAgCzD,OA7BK,IAYD,EAAc,SAAS,KAKrB,EAJqB,IACrB,EAAW,CAAa,IACxB,EAAc,OAAM,MAAQ,EAAQ,CAAI,CAAC,KAGvC,IACK,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA,KAGnB,OAAO,SAAW,QACpB,OAAO,SAAS,OAAO,kBAElB,QAIJ,kBAAA,GAAA,EAAG,YAAW,CAAA,IA5Bf,IACK,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA,KAGnB,OAAO,SAAW,QACpB,OAAO,SAAS,OAAO,IAElB;AAsBX"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/ProtectedRoute/index.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport { useAuth } from '../../contexts/AppContext';\n\nexport type ProtectedRouteProps = {\n children: React.ReactNode;\n requiredRoles?: string[];\n requireAny?: boolean; // 如果为 true,只需要满足任一角色;如果为 false,需要满足所有角色\n fallbackPath?: string;\n fallback?: React.ReactNode;\n};\n\n/**\n * ProtectedRoute 组件\n * \n * 用于保护需要认证或特定角色才能访问的页面内容。\n * 组件渲染晚于 loader;数据访问必须使用路由 beforeLoad 和服务端授权。\n * \n * @example\n * ```tsx\n * // 基本用法 - 只需要认证\n * <ProtectedRoute>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要特定角色\n * <ProtectedRoute requiredRoles={['admin']}>\n * <AdminPanel />\n * </ProtectedRoute>\n * \n * // 需要任一角色\n * <ProtectedRoute requiredRoles={['admin', 'moderator']} requireAny>\n * <ModeratorPanel />\n * </ProtectedRoute>\n * \n * // 自定义回退路径\n * <ProtectedRoute fallbackPath=\"/unauthorized\">\n * <SecretPage />\n * </ProtectedRoute>\n * \n * // 自定义回退组件\n * <ProtectedRoute fallback={<UnauthorizedMessage />}>\n * <SecretPage />\n * </ProtectedRoute>\n * ```\n */\nexport const ProtectedRoute: React.FC<ProtectedRouteProps> = ({\n children,\n requiredRoles = [],\n requireAny = false,\n fallbackPath = '/login',\n fallback,\n}) => {\n const { isAuthenticated, hasRole, hasAnyRole } = useAuth();\n\n const hasRequiredRoles = requiredRoles.length === 0 || (requireAny\n ? hasAnyRole(requiredRoles)\n : requiredRoles.every(role => hasRole(role)));\n const denied = !isAuthenticated || !hasRequiredRoles;\n const destination = !isAuthenticated ? fallbackPath : '/unauthorized';\n const hasFallback = fallback !== undefined && fallback !== null;\n const lastRedirect = useRef<string | null>(null);\n\n useEffect(() => {\n if (!denied || hasFallback) {\n lastRedirect.current = null;\n return;\n }\n // StrictMode replays effects; a second hard navigation can abort the first.\n if (typeof window !== 'undefined' && lastRedirect.current !== destination) {\n lastRedirect.current = destination;\n window.location.href = destination;\n }\n }, [denied, hasFallback, destination]);\n\n if (denied) return hasFallback ? <>{fallback}</> : null;\n return <>{children}</>;\n};\n\nexport default ProtectedRoute;\n\n"],"mappings":";;;;AA6CA,IAAa,KAAiD,EAC5D,aACA,mBAAgB,CAAC,GACjB,gBAAa,IACb,kBAAe,UACf,kBACI;CACJ,IAAM,EAAE,oBAAiB,YAAS,kBAAe,EAAQ,GAEnD,IAAmB,EAAc,WAAW,MAAM,IACpD,EAAW,CAAa,IACxB,EAAc,OAAM,MAAQ,EAAQ,CAAI,CAAC,IACvC,IAAS,CAAC,KAAmB,CAAC,GAC9B,IAAe,IAAiC,kBAAf,GACjC,IAAc,KAAuC,MACrD,IAAe,EAAsB,IAAI;CAe/C,OAbA,QAAgB;EACd,IAAI,CAAC,KAAU,GAAa;GAC1B,EAAa,UAAU;GACvB;EACF;EAEA,AAAI,OAAO,SAAW,OAAe,EAAa,YAAY,MAC5D,EAAa,UAAU,GACvB,OAAO,SAAS,OAAO;CAE3B,GAAG;EAAC;EAAQ;EAAa;CAAW,CAAC,GAEjC,IAAe,IAAc,kBAAA,GAAA,EAAA,UAAG,EAAW,CAAA,IAAI,OAC5C,kBAAA,GAAA,EAAG,YAAW,CAAA;AACvB"}
@@ -2,10 +2,16 @@ import React from 'react';
2
2
  export interface Option {
3
3
  value: string | number;
4
4
  label: string;
5
+ disabled?: boolean;
5
6
  }
6
7
  export interface SelectProps {
7
8
  /** Accessible name for the combobox. */
8
9
  'aria-label'?: string;
10
+ 'aria-labelledby'?: string;
11
+ 'aria-describedby'?: string;
12
+ /** Optional ID for the combobox; generated per instance when omitted. */
13
+ id?: string;
14
+ disabled?: boolean;
9
15
  options: Option[];
10
16
  value?: string | number | (string | number)[];
11
17
  onChange: (value: string | number | (string | number)[]) => void;
@@ -1,9 +1,8 @@
1
- import { useClickOutside as e } from "../../hooks/useClickOutside.js";
2
- import { useCallback as t, useEffect as n, useRef as r, useState as i } from "react";
3
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
4
- import { createPortal as s } from "react-dom";
1
+ import { useCallback as e, useEffect as t, useId as n, useMemo as r, useRef as i, useState as a } from "react";
2
+ import { jsx as o, jsxs as s } from "react/jsx-runtime";
3
+ import { createPortal as c } from "react-dom";
5
4
  //#region src/components/Select/index.tsx
6
- var c = ({ isOpen: e }) => /* @__PURE__ */ a("svg", {
5
+ var l = ({ isOpen: e }) => /* @__PURE__ */ o("svg", {
7
6
  xmlns: "http://www.w3.org/2000/svg",
8
7
  fill: "none",
9
8
  viewBox: "0 0 24 24",
@@ -16,200 +15,225 @@ var c = ({ isOpen: e }) => /* @__PURE__ */ a("svg", {
16
15
  transform: e ? "rotate(180deg)" : "rotate(0deg)",
17
16
  transition: "transform 200ms ease-in-out"
18
17
  },
19
- children: /* @__PURE__ */ a("path", {
18
+ children: /* @__PURE__ */ o("path", {
20
19
  strokeLinecap: "round",
21
20
  strokeLinejoin: "round",
22
21
  d: "M19 9l-7 7-7-7"
23
22
  })
24
- }), l = () => /* @__PURE__ */ a("svg", {
23
+ }), u = () => /* @__PURE__ */ o("svg", {
25
24
  xmlns: "http://www.w3.org/2000/svg",
26
25
  className: "h-3 w-3",
27
26
  fill: "none",
28
27
  viewBox: "0 0 24 24",
29
28
  stroke: "currentColor",
30
29
  strokeWidth: 3,
31
- children: /* @__PURE__ */ a("path", {
30
+ children: /* @__PURE__ */ o("path", {
32
31
  strokeLinecap: "round",
33
32
  strokeLinejoin: "round",
34
33
  d: "M6 18L18 6M6 6l12 12"
35
34
  })
36
- }), u = ({ options: u, value: d, onChange: f, "aria-label": p, placeholder: m = "Select...", multiple: h = !1, fixedHeight: g = !1, style: _, className: v }) => {
37
- let [y, b] = i(!1), [x, S] = i(-1), [C, w] = i(""), [T, E] = i(!0), [D, O] = i({}), k = r(null), A = r(null), j = r(null), M = r(null);
38
- n(() => {
39
- if (!y) return;
35
+ }), d = ({ options: d, value: f, onChange: p, "aria-label": m, "aria-labelledby": h, "aria-describedby": g, id: _, disabled: v = !1, placeholder: y = "Select...", multiple: b = !1, fixedHeight: x = !1, style: S, className: C }) => {
36
+ let w = n(), T = _ ?? `select-${w}`, E = `${T}-listbox`, D = (e) => `${E}-${typeof e.value}-${encodeURIComponent(String(e.value))}`, [O, k] = a(!1), A = O && !v;
37
+ v && O && k(!1);
38
+ let [j, M] = a(null), [N, P] = a(""), [F, I] = a(!0), [L, R] = a({}), z = i(null), B = i(null), V = i(null), H = i(null), U = i(null), W = i(!1);
39
+ t(() => {
40
+ if (!A) return;
40
41
  let e = (e) => {
41
42
  let t = e.target;
42
- k.current?.contains(t) || j.current?.contains(t) || b(!1);
43
+ z.current?.contains(t) || H.current?.contains(t) || k(!1);
43
44
  };
44
- return document.addEventListener("pointerdown", e), document.addEventListener("mousedown", e), () => {
45
- document.removeEventListener("pointerdown", e), document.removeEventListener("mousedown", e);
45
+ return document.addEventListener("pointerdown", e), () => {
46
+ document.removeEventListener("pointerdown", e);
46
47
  };
47
- }, [y]);
48
- let N = Array.isArray(d) ? d : d == null ? [] : [d];
49
- e(k, t(() => b(!1), []));
50
- let P = t(() => {
51
- let e = k.current;
48
+ }, [A]);
49
+ let G = r(() => Array.isArray(f) ? f : f == null ? [] : [f], [f]), K = d.flatMap((e, t) => e.disabled ? [] : [t]), q = d.findIndex((e) => !e.disabled && G.includes(e.value)), J = d.findIndex((e) => !e.disabled && e.value === j), Y = J >= 0 ? J : q >= 0 ? q : K[0] ?? -1, X = (e) => {
50
+ let t = e.relatedTarget;
51
+ (!t || !z.current?.contains(t) && !H.current?.contains(t)) && k(!1);
52
+ }, Z = e(() => {
53
+ let e = z.current;
52
54
  if (!e) return;
53
- let t = e.getBoundingClientRect(), n = Math.min(u.length, 8) * 36 + 8, r = t.bottom + 4 + n <= window.innerHeight;
54
- O({
55
+ let t = e.getBoundingClientRect(), n = Math.min(d.length, 8) * 36 + 8, r = t.bottom + 4 + n <= window.innerHeight;
56
+ R({
55
57
  position: "fixed",
56
58
  left: t.left,
57
59
  top: r ? t.bottom + 4 : Math.max(8, t.top - n - 4),
58
60
  width: t.width,
59
61
  zIndex: 1e4
60
62
  });
61
- }, [u.length]);
62
- n(() => {
63
- if (y) return P(), window.addEventListener("resize", P), window.addEventListener("scroll", P, !0), () => {
64
- window.removeEventListener("resize", P), window.removeEventListener("scroll", P, !0);
63
+ }, [d.length]);
64
+ t(() => {
65
+ if (A) return Z(), window.addEventListener("resize", Z), window.addEventListener("scroll", Z, !0), () => {
66
+ window.removeEventListener("resize", Z), window.removeEventListener("scroll", Z, !0);
65
67
  };
66
- }, [y, P]), n(() => {
67
- let e = k.current;
68
+ }, [A, Z]), t(() => {
69
+ let e = z.current;
68
70
  if (!e) return;
69
- let t = () => E(e.clientWidth >= 88);
71
+ let t = () => I(e.clientWidth >= 88);
70
72
  t();
71
73
  let n = new ResizeObserver(t);
72
74
  return n.observe(e), () => n.disconnect();
73
- }, []), n(() => {
74
- if (!y) return;
75
- let e = (e) => {
75
+ }, []), t(() => {
76
+ if (A && H.current && Y >= 0) {
77
+ let e = H.current, t = e.children[Y];
78
+ if (t) {
79
+ let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
80
+ r.bottom > n.bottom ? e.scrollTop += r.bottom - n.bottom : r.top < n.top && (e.scrollTop -= n.top - r.top);
81
+ }
82
+ }
83
+ }, [A, Y]);
84
+ let Q = (e = "first") => {
85
+ if (v) return;
86
+ let t = q >= 0 ? q : e === "last" ? K.at(-1) : K[0];
87
+ M(t !== void 0 && t >= 0 ? d[t].value : null), k(!0), Z();
88
+ }, ee = () => {
89
+ v || (B.current?.focus({ preventScroll: !0 }), A ? k(!1) : Q());
90
+ }, te = (e) => {
91
+ if (e.key === "Tab") {
92
+ k(!1);
93
+ return;
94
+ }
95
+ if (!(e.target !== B.current || v || e.defaultPrevented || e.nativeEvent.isComposing || e.altKey || e.ctrlKey || e.metaKey)) {
76
96
  switch (e.key) {
77
97
  case "ArrowDown":
78
- e.preventDefault(), S((e) => e < u.length - 1 ? e + 1 : 0), F();
79
- break;
80
98
  case "ArrowUp":
81
- e.preventDefault(), S((e) => e > 0 ? e - 1 : u.length - 1), F();
99
+ if (!A) Q(e.key === "ArrowUp" ? "last" : "first");
100
+ else if (K.length) {
101
+ let t = K.indexOf(Y), n = e.key === "ArrowDown" ? 1 : -1, r = K[(t + n + K.length) % K.length];
102
+ M(d[r].value);
103
+ }
82
104
  break;
105
+ case "Home":
106
+ case "End": {
107
+ A || Q();
108
+ let t = e.key === "Home" ? K[0] : K.at(-1);
109
+ M(t === void 0 ? null : d[t].value);
110
+ break;
111
+ }
83
112
  case "Enter":
84
113
  case " ":
85
- e.preventDefault(), x >= 0 && x < u.length && L(u[x]), h || b(!1);
114
+ A ? Y >= 0 && $(d[Y]) : Q();
86
115
  break;
87
- case "Escape": b(!1);
88
- }
89
- };
90
- return document.addEventListener("keydown", e), () => {
91
- document.removeEventListener("keydown", e);
92
- };
93
- }, [
94
- y,
95
- x,
96
- u,
97
- h
98
- ]);
99
- let F = t(() => {
100
- if (j.current && x >= 0) {
101
- let e = j.current, t = e.children[x];
102
- if (t) {
103
- let n = e.getBoundingClientRect(), r = t.getBoundingClientRect();
104
- r.bottom > n.bottom ? e.scrollTop += r.bottom - n.bottom : r.top < n.top && (e.scrollTop -= n.top - r.top);
116
+ case "Escape":
117
+ if (!A) return;
118
+ k(!1);
119
+ break;
120
+ default: return;
105
121
  }
122
+ e.preventDefault(), e.stopPropagation();
123
+ }
124
+ }, $ = (e) => {
125
+ if (!(v || e.disabled)) {
126
+ if (M(e.value), B.current?.focus({ preventScroll: !0 }), b) {
127
+ let t = Array.isArray(f) ? f : [], n;
128
+ n = t.includes(e.value) ? t.filter((t) => t !== e.value) : [...t, e.value], p(n);
129
+ } else p(e.value), k(!1);
106
130
  }
107
- }, [x]), I = () => {
108
- let e = !y;
109
- b(e), S(e ? 0 : -1), e && P();
110
- }, L = (e) => {
111
- if (h) {
112
- let t = Array.isArray(d) ? d : [], n;
113
- n = t.includes(e.value) ? t.filter((t) => t !== e.value) : [...t, e.value], f(n);
114
- } else f(e.value), b(!1);
115
- }, R = (e, t) => {
116
- if (e.pointerType === "mouse") {
117
- e.preventDefault(), e.stopPropagation(), L(t);
131
+ }, ne = (e, t) => {
132
+ if (W.current = !1, e.pointerType === "mouse") {
133
+ e.preventDefault(), e.stopPropagation(), $(t);
118
134
  return;
119
135
  }
120
- e.stopPropagation(), M.current = {
136
+ e.stopPropagation(), U.current = {
121
137
  pointerId: e.pointerId,
122
138
  x: e.clientX,
123
139
  y: e.clientY
124
140
  };
125
- }, z = (e, t) => {
126
- let n = M.current;
127
- M.current = null, n && e.pointerId === n.pointerId && Math.hypot(e.clientX - n.x, e.clientY - n.y) < 10 && (e.stopPropagation(), L(t));
128
- }, B = () => {
129
- M.current = null;
130
- }, V = (e, t) => {
131
- e.stopPropagation(), f((Array.isArray(d) ? d : []).filter((e) => e !== t));
141
+ }, re = (e) => {
142
+ let t = U.current;
143
+ if (U.current = null, !t || e.pointerId !== t.pointerId) return;
144
+ let n = Math.hypot(e.clientX - t.x, e.clientY - t.y);
145
+ W.current = n < 10, e.stopPropagation();
146
+ }, ie = () => {
147
+ U.current = null, W.current = !1;
148
+ }, ae = (e, t) => {
149
+ e.stopPropagation(), !(v || d.find((e) => e.value === t)?.disabled) && (B.current?.focus({ preventScroll: !0 }), p((Array.isArray(f) ? f : []).filter((e) => e !== t)));
132
150
  };
133
- n(() => {
134
- if (h && A.current) {
135
- let e = A.current, t = u.filter((e) => N.includes(e.value)).map((e) => e.label).join(", "), n = e.scrollWidth > e.clientWidth;
136
- w(n ? t : "");
137
- } else w("");
151
+ t(() => {
152
+ if (b && V.current) {
153
+ let e = V.current, t = d.filter((e) => G.includes(e.value)).map((e) => e.label).join(", "), n = e.scrollWidth > e.clientWidth;
154
+ P(n ? t : "");
155
+ } else P("");
138
156
  }, [
157
+ b,
139
158
  d,
140
- h,
141
- u,
142
- N
159
+ G
143
160
  ]);
144
- let H = () => {
145
- if (N.length === 0) return /* @__PURE__ */ a("span", {
161
+ let oe = () => {
162
+ if (G.length === 0) return /* @__PURE__ */ o("span", {
146
163
  className: "text-base-content/60 italic",
147
- children: m
164
+ children: y
148
165
  });
149
- let e = u.filter((e) => N.includes(e.value));
150
- if (h) {
151
- let t = g;
152
- return /* @__PURE__ */ a("div", {
153
- ref: A,
166
+ let e = d.filter((e) => G.includes(e.value));
167
+ if (b) {
168
+ let t = x;
169
+ return /* @__PURE__ */ o("div", {
170
+ ref: V,
154
171
  className: `
155
172
  flex gap-1
156
173
  ${t ? "flex-nowrap overflow-x-auto overflow-y-hidden" : "flex-wrap overflow-hidden"} // Enable horizontal scroll, hide vertical scrollbar if any
157
- ${C ? "tooltip tooltip-bottom" : ""} // Keep tooltip for overflow
174
+ ${N ? "tooltip tooltip-bottom" : ""} // Keep tooltip for overflow
158
175
  `,
159
- "data-tip": C || void 0,
176
+ "data-tip": N || void 0,
160
177
  style: {
161
178
  scrollbarWidth: "thin",
162
179
  ...t ? { paddingRight: "1.75rem" } : {}
163
180
  },
164
- children: e.map((e) => /* @__PURE__ */ o("span", {
181
+ children: e.map((e) => /* @__PURE__ */ s("span", {
165
182
  className: "badge badge-ghost gap-1 text-xs items-center whitespace-nowrap flex-shrink-0",
166
- children: [e.label, /* @__PURE__ */ a("button", {
183
+ children: [e.label, /* @__PURE__ */ o("button", {
167
184
  type: "button",
168
- onClick: (t) => V(t, e.value),
185
+ disabled: v || e.disabled,
186
+ onClick: (t) => ae(t, e.value),
169
187
  className: "btn btn-xs btn-ghost btn-circle p-0 m-0 hover:bg-error hover:text-error-content",
170
188
  "aria-label": `Remove ${e.label}`,
171
- children: /* @__PURE__ */ a(l, {})
189
+ children: /* @__PURE__ */ o(u, {})
172
190
  })]
173
- }, e.value))
191
+ }, D(e)))
174
192
  });
175
193
  }
176
194
  {
177
- let e = u.find((e) => e.value === N[0]);
178
- return e ? /* @__PURE__ */ a("span", {
195
+ let e = d.find((e) => e.value === G[0]);
196
+ return e ? /* @__PURE__ */ o("span", {
179
197
  className: "truncate",
180
198
  children: e.label
181
- }) : /* @__PURE__ */ a("span", {
199
+ }) : /* @__PURE__ */ o("span", {
182
200
  className: "text-base-content/60 italic",
183
- children: m
201
+ children: y
184
202
  });
185
203
  }
186
- }, U = `
204
+ }, se = `
187
205
  relative border border-base-300 rounded-lg bg-base-100 w-full
188
206
  flex justify-between items-center cursor-pointer px-3 text-sm
189
207
  focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50
190
208
  hover:border-base-content/30
191
- ${h ? g ? "h-8" : "min-h-8 h-auto py-1" : "h-8"}
209
+ ${b ? x ? "h-8" : "min-h-8 h-auto py-1" : "h-8"}
192
210
  `;
193
- return /* @__PURE__ */ o("div", {
194
- ref: k,
195
- style: _,
196
- className: `relative w-full font-sans select-none ${v || ""}`,
197
- children: [/* @__PURE__ */ o("div", {
198
- tabIndex: 0,
199
- className: U,
200
- onClick: I,
201
- onKeyDown: (e) => {
202
- (e.key === "Enter" || e.key === " ") && I();
203
- },
211
+ return /* @__PURE__ */ s("div", {
212
+ ref: z,
213
+ style: S,
214
+ className: `relative w-full font-sans select-none ${C || ""}`,
215
+ onBlur: X,
216
+ onKeyDown: te,
217
+ children: [/* @__PURE__ */ s("div", {
218
+ ref: B,
219
+ id: T,
220
+ tabIndex: v ? -1 : 0,
221
+ className: `${se} ${v ? "opacity-50 cursor-not-allowed" : ""}`,
222
+ onClick: ee,
204
223
  role: "combobox",
205
- "aria-label": p,
224
+ "aria-label": m ?? (h ? void 0 : y),
225
+ "aria-labelledby": h,
226
+ "aria-describedby": g,
206
227
  "aria-haspopup": "listbox",
207
- "aria-expanded": y,
208
- children: [/* @__PURE__ */ a("div", {
228
+ "aria-expanded": A,
229
+ "aria-disabled": v || void 0,
230
+ "aria-controls": A ? E : void 0,
231
+ "aria-activedescendant": A && Y >= 0 ? D(d[Y]) : void 0,
232
+ children: [/* @__PURE__ */ o("div", {
209
233
  className: "flex-1 min-w-0 overflow-hidden",
210
- style: { paddingRight: T ? 28 : 0 },
211
- children: H()
212
- }), T && /* @__PURE__ */ a("div", {
234
+ style: { paddingRight: F ? 28 : 0 },
235
+ children: oe()
236
+ }), F && /* @__PURE__ */ o("div", {
213
237
  "aria-hidden": "true",
214
238
  style: {
215
239
  position: "absolute",
@@ -223,33 +247,39 @@ var c = ({ isOpen: e }) => /* @__PURE__ */ a("svg", {
223
247
  width: 16,
224
248
  height: 16
225
249
  },
226
- children: /* @__PURE__ */ a(c, { isOpen: y })
250
+ children: /* @__PURE__ */ o(l, { isOpen: A })
227
251
  })]
228
- }), y && typeof document < "u" && s(/* @__PURE__ */ a("ul", {
229
- ref: j,
252
+ }), A && typeof document < "u" && c(/* @__PURE__ */ o("ul", {
253
+ ref: H,
254
+ id: E,
230
255
  className: "bg-base-100 border border-base-300 rounded-md shadow-lg list-none p-0 m-0 max-h-60 overflow-y-auto focus:outline-none",
231
256
  style: {
232
- ...D,
257
+ ...L,
233
258
  touchAction: "pan-y"
234
259
  },
235
260
  onPointerDown: (e) => e.stopPropagation(),
236
261
  role: "listbox",
237
- "aria-activedescendant": x >= 0 ? `option-${u[x]?.value}` : void 0,
262
+ "aria-labelledby": h ?? T,
263
+ "aria-multiselectable": b || void 0,
264
+ onFocus: () => B.current?.focus({ preventScroll: !0 }),
238
265
  tabIndex: -1,
239
- children: u.length > 0 ? u.map((e, t) => /* @__PURE__ */ a("li", {
240
- id: `option-${e.value}`,
241
- className: `p-2 cursor-pointer whitespace-nowrap overflow-hidden text-ellipsis hover:bg-base-200 ${t === x ? "bg-base-300" : ""} ${N.includes(e.value) && !h ? "font-semibold bg-base-200" : ""} ${N.includes(e.value) && h ? "font-semibold" : ""}`,
242
- onPointerDown: (t) => R(t, e),
243
- onPointerUp: (t) => z(t, e),
244
- onPointerCancel: B,
245
- onClick: (e) => {
246
- e.preventDefault(), e.stopPropagation();
266
+ children: d.length > 0 ? d.map((e, t) => /* @__PURE__ */ o("li", {
267
+ id: D(e),
268
+ className: `p-2 ${e.disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:bg-base-200"} whitespace-nowrap overflow-hidden text-ellipsis ${t === Y ? "bg-base-300" : ""} ${G.includes(e.value) && !b ? "font-semibold bg-base-200" : ""} ${G.includes(e.value) && b ? "font-semibold" : ""}`,
269
+ onPointerDown: (t) => ne(t, e),
270
+ onPointerUp: re,
271
+ onPointerCancel: ie,
272
+ onClick: (t) => {
273
+ t.preventDefault(), t.stopPropagation(), (W.current || t.detail === 0) && $(e), W.current = !1;
274
+ },
275
+ onPointerMove: (t) => {
276
+ t.pointerType === "mouse" && (t.movementX || t.movementY) && !e.disabled && M(e.value);
247
277
  },
248
- onMouseEnter: () => S(t),
249
278
  role: "option",
250
- "aria-selected": N.includes(e.value),
279
+ "aria-disabled": e.disabled || void 0,
280
+ "aria-selected": G.includes(e.value),
251
281
  children: e.label
252
- }, e.value)) : /* @__PURE__ */ a("li", {
282
+ }, D(e))) : /* @__PURE__ */ o("li", {
253
283
  className: "p-2 text-base-content/60 italic",
254
284
  children: "No options available"
255
285
  })
@@ -257,6 +287,6 @@ var c = ({ isOpen: e }) => /* @__PURE__ */ a("svg", {
257
287
  });
258
288
  };
259
289
  //#endregion
260
- export { u as default };
290
+ export { d as default };
261
291
 
262
292
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Select/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useClickOutside } from '../../hooks/useClickOutside';\n\nexport interface Option {\n value: string | number;\n label: string;\n}\n\nexport interface SelectProps {\n /** Accessible name for the combobox. */\n 'aria-label'?: string;\n options: Option[];\n value?: string | number | (string | number)[];\n onChange: (value: string | number | (string | number)[]) => void;\n placeholder?: string;\n multiple?: boolean;\n fixedHeight?: boolean;\n style?: React.CSSProperties; // Allow passing inline styles\n className?: string; // Allow passing CSS classes for the wrapper\n}\n\n// SVG component for the dropdown arrow\nconst DropdownArrow: React.FC<{ isOpen: boolean }> = ({ isOpen }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n style={{\n display: 'block',\n width: 16,\n height: 16,\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-in-out',\n }}\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\n// SVG component for the remove button 'x'\nconst RemoveIcon: React.FC = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n);\n\n// Select Component Implementation using daisyUI/Tailwind\nconst Select: React.FC<SelectProps> = ({\n options,\n value,\n onChange,\n 'aria-label': ariaLabel,\n placeholder = 'Select...',\n multiple = false,\n fixedHeight = false,\n style,\n className // This className applies to the wrapper\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const [highlightedIndex, setHighlightedIndex] = useState(-1);\n const [tooltipText, setTooltipText] = useState('');\n const [showArrow, setShowArrow] = useState(true);\n const [dropdownStyle, setDropdownStyle] = useState<React.CSSProperties>({});\n const wrapperRef = useRef<HTMLDivElement>(null);\n const headerRef = useRef<HTMLDivElement>(null); // Ref for the header div\n const optionsListRef = useRef<HTMLUListElement>(null);\n // Tracks a touch/pen press on an option so a tap selects while a drag scrolls.\n // (pointerdown on touch must NOT preventDefault — that blocks native scrolling.)\n const touchPressRef = useRef<{ pointerId: number; x: number; y: number } | null>(null);\n\n useEffect(() => {\n if (!isOpen) return;\n const handlePointerDown = (event: MouseEvent) => {\n const target = event.target as Node;\n if (wrapperRef.current?.contains(target) || optionsListRef.current?.contains(target)) return;\n setIsOpen(false);\n };\n document.addEventListener('pointerdown', handlePointerDown);\n document.addEventListener('mousedown', handlePointerDown);\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown);\n document.removeEventListener('mousedown', handlePointerDown);\n };\n }, [isOpen]);\n\n const selectedValuesArray = Array.isArray(value) ? value : (value !== undefined && value !== null ? [value] : []);\n\n // Close dropdown when clicking outside\n useClickOutside(wrapperRef, useCallback(() => setIsOpen(false), []));\n\n const updateDropdownPosition = useCallback(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n const estimatedHeight = Math.min(options.length, 8) * 36 + 8;\n const fitsBelow = rect.bottom + 4 + estimatedHeight <= window.innerHeight;\n setDropdownStyle({\n position: 'fixed',\n left: rect.left,\n top: fitsBelow ? rect.bottom + 4 : Math.max(8, rect.top - estimatedHeight - 4),\n width: rect.width,\n zIndex: 10000,\n });\n }, [options.length]);\n\n useEffect(() => {\n if (!isOpen) return;\n updateDropdownPosition();\n window.addEventListener('resize', updateDropdownPosition);\n window.addEventListener('scroll', updateDropdownPosition, true);\n return () => {\n window.removeEventListener('resize', updateDropdownPosition);\n window.removeEventListener('scroll', updateDropdownPosition, true);\n };\n }, [isOpen, updateDropdownPosition]);\n\n // Hide the decorative arrow when the control becomes too narrow to reserve\n // space for both it and a useful amount of label text.\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const update = () => setShowArrow(wrapper.clientWidth >= 88);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(wrapper);\n return () => observer.disconnect();\n }, []);\n\n // Keyboard navigation\n useEffect(() => {\n if (!isOpen) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setHighlightedIndex(prev => (prev < options.length - 1 ? prev + 1 : 0));\n scrollToHighlightedOption();\n break;\n case 'ArrowUp':\n event.preventDefault();\n setHighlightedIndex(prev => (prev > 0 ? prev - 1 : options.length - 1));\n scrollToHighlightedOption();\n break;\n case 'Enter':\n case ' ': // Space key\n event.preventDefault();\n if (highlightedIndex >= 0 && highlightedIndex < options.length) {\n handleOptionClick(options[highlightedIndex]);\n if (!multiple) setIsOpen(false); // Close dropdown on selection if single mode\n } else if (!multiple) {\n setIsOpen(false); // Close dropdown if Enter/Space is pressed without a highlighted option in single mode\n }\n break;\n case 'Escape':\n setIsOpen(false);\n break;\n default:\n // Optional: Implement type-ahead find\n break;\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, highlightedIndex, options, multiple]); // Added multiple to dependencies\n\n const scrollToHighlightedOption = useCallback(() => {\n if (optionsListRef.current && highlightedIndex >= 0) {\n const list = optionsListRef.current;\n const optionElement = list.children[highlightedIndex] as HTMLLIElement;\n if (optionElement) {\n const listRect = list.getBoundingClientRect();\n const optionRect = optionElement.getBoundingClientRect();\n\n if (optionRect.bottom > listRect.bottom) {\n list.scrollTop += optionRect.bottom - listRect.bottom;\n } else if (optionRect.top < listRect.top) {\n list.scrollTop -= listRect.top - optionRect.top;\n }\n }\n }\n }, [highlightedIndex]);\n\n const toggleDropdown = () => {\n const next = !isOpen;\n setIsOpen(next);\n setHighlightedIndex(next ? 0 : -1); // Reset or set initial highlight\n if (next) updateDropdownPosition();\n };\n\n const handleOptionClick = (option: Option) => {\n if (multiple) {\n const currentValues = Array.isArray(value) ? value : [];\n let newValue;\n if (currentValues.includes(option.value)) {\n newValue = currentValues.filter(v => v !== option.value);\n } else {\n newValue = [...currentValues, option.value];\n }\n onChange(newValue);\n } else {\n onChange(option.value);\n setIsOpen(false); // Close dropdown on single select\n }\n // Keep highlight on the selected item in multi-select? Maybe not.\n // setHighlightedIndex(options.findIndex(o => o.value === option.value));\n };\n\n // Mouse: select immediately on press (existing desktop behavior).\n // Touch/pen: only record the press — selection happens on pointerup if the\n // gesture turned out to be a tap rather than a scroll. preventDefault() on a\n // touch pointerdown suppresses the browser's native pan gesture, which made\n // long dropdowns impossible to scroll on mobile (and every scroll attempt\n // selected an option instead).\n const handleOptionPointerDown = (event: React.PointerEvent<HTMLLIElement>, option: Option) => {\n if (event.pointerType === 'mouse') {\n event.preventDefault();\n event.stopPropagation();\n handleOptionClick(option);\n return;\n }\n event.stopPropagation();\n touchPressRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };\n };\n\n const handleOptionPointerUp = (event: React.PointerEvent<HTMLLIElement>, option: Option) => {\n const press = touchPressRef.current;\n touchPressRef.current = null;\n if (!press || event.pointerId !== press.pointerId) return;\n // Select only if the finger did not move much — otherwise it was a scroll.\n const moved = Math.hypot(event.clientX - press.x, event.clientY - press.y);\n if (moved < 10) {\n event.stopPropagation();\n handleOptionClick(option);\n }\n };\n\n const handleOptionPointerCancel = () => {\n touchPressRef.current = null;\n };\n\n const handleRemoveItem = (e: React.MouseEvent, itemValue: string | number) => {\n e.stopPropagation(); // Prevent dropdown from opening/closing\n const currentValues = Array.isArray(value) ? value : [];\n onChange(currentValues.filter(v => v !== itemValue));\n };\n\n // Update tooltip text and check for overflow\n useEffect(() => {\n if (multiple && headerRef.current) {\n const header = headerRef.current;\n const selectedLabels = options\n .filter(opt => selectedValuesArray.includes(opt.value))\n .map(opt => opt.label)\n .join(', ');\n\n // Check if the content (scrollWidth) exceeds the visible area (clientWidth)\n const isOverflowing = header.scrollWidth > header.clientWidth;\n setTooltipText(isOverflowing ? selectedLabels : ''); // Only set text if overflowing\n } else {\n setTooltipText(''); // Clear tooltip for single select or empty multi-select\n }\n }, [value, multiple, options, selectedValuesArray]);\n\n\n const renderSelectedValue = () => {\n if (selectedValuesArray.length === 0) {\n return <span className=\"text-base-content/60 italic\">{placeholder}</span>;\n }\n\n const selectedOptions = options.filter(opt => selectedValuesArray.includes(opt.value));\n\n if (multiple) {\n const isFixed = fixedHeight;\n // Apply overflow-x-auto for horizontal scrolling in fixedHeight mode\n const containerClasses = `\n flex gap-1 \n ${isFixed ? 'flex-nowrap overflow-x-auto overflow-y-hidden' : 'flex-wrap overflow-hidden'} // Enable horizontal scroll, hide vertical scrollbar if any\n ${tooltipText ? 'tooltip tooltip-bottom' : ''} // Keep tooltip for overflow\n `;\n // Removed showEllipsisPrefix\n\n return (\n <div\n ref={headerRef}\n className={containerClasses}\n data-tip={tooltipText ? tooltipText : undefined} // Keep tooltip logic\n // Add scrollbar styling if desired (e.g., using ::-webkit-scrollbar pseudo-element via CSS or a utility)\n style={{\n scrollbarWidth: 'thin',\n // 为固定高度模式添加右侧内边距,避免与下拉图标重叠\n ...(isFixed ? { paddingRight: '1.75rem' } : {})\n }}\n >\n {/* Removed wrapper for ellipsis and its popup */}\n\n {/* Render the badges */}\n {selectedOptions.map(option => (\n <span key={option.value} className=\"badge badge-ghost gap-1 text-xs items-center whitespace-nowrap flex-shrink-0\">\n {option.label}\n <button\n type=\"button\"\n onClick={(e) => handleRemoveItem(e, option.value)}\n className=\"btn btn-xs btn-ghost btn-circle p-0 m-0 hover:bg-error hover:text-error-content\"\n aria-label={`Remove ${option.label}`}\n >\n <RemoveIcon />\n </button>\n </span>\n ))}\n </div>\n );\n } else {\n const selectedOption = options.find(opt => opt.value === selectedValuesArray[0]);\n return selectedOption ? <span className=\"truncate\">{selectedOption.label}</span> : <span className=\"text-base-content/60 italic\">{placeholder}</span>;\n }\n };\n\n // Match the default control height to a normal line of form text. Multi-select\n // may still grow when wrapping tags unless fixedHeight is requested.\n const selectClasses = `\n relative border border-base-300 rounded-lg bg-base-100 w-full\n flex justify-between items-center cursor-pointer px-3 text-sm\n focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50\n hover:border-base-content/30\n ${multiple\n ? (fixedHeight ? 'h-8' : 'min-h-8 h-auto py-1')\n : 'h-8'}\n `;\n\n return (\n <div\n ref={wrapperRef}\n style={style}\n className={`relative w-full font-sans select-none ${className || ''}`}\n >\n {/* Header */}\n <div\n tabIndex={0}\n className={selectClasses}\n onClick={toggleDropdown}\n onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') toggleDropdown(); }}\n role=\"combobox\"\n aria-label={ariaLabel}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n >\n <div\n className=\"flex-1 min-w-0 overflow-hidden\"\n style={{ paddingRight: showArrow ? 28 : 0 }}\n >\n {renderSelectedValue()}\n </div>\n {/* Inline positioning avoids utility CSS/theme overrides moving the icon. */}\n {showArrow && (\n <div\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n right: 10,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 16,\n height: 16,\n }}\n >\n <DropdownArrow isOpen={isOpen} />\n </div>\n )}\n </div>\n\n {/* Dropdown Options */}\n {isOpen && typeof document !== 'undefined' && createPortal(\n <ul\n ref={optionsListRef}\n className=\"bg-base-100 border border-base-300 rounded-md shadow-lg list-none p-0 m-0 max-h-60 overflow-y-auto focus:outline-none\"\n style={{ ...dropdownStyle, touchAction: 'pan-y' }}\n onPointerDown={(event) => event.stopPropagation()}\n role=\"listbox\" // ARIA role\n aria-activedescendant={highlightedIndex >= 0 ? `option-${options[highlightedIndex]?.value}` : undefined} // For screen readers\n tabIndex={-1} // Allows focus programmatically but not via tab\n >\n {options.length > 0 ? (\n options.map((option, index) => (\n <li\n key={option.value}\n id={`option-${option.value}`} // ID for aria-activedescendant\n className={`p-2 cursor-pointer whitespace-nowrap overflow-hidden text-ellipsis hover:bg-base-200 ${index === highlightedIndex ? 'bg-base-300' : '' // Highlight style\n } ${selectedValuesArray.includes(option.value) && !multiple ? 'font-semibold bg-base-200' : '' // Style for selected single item\n } ${selectedValuesArray.includes(option.value) && multiple ? 'font-semibold' : '' // Style for selected multi items (less prominent background)\n }`}\n onPointerDown={(event) => handleOptionPointerDown(event, option)}\n onPointerUp={(event) => handleOptionPointerUp(event, option)}\n onPointerCancel={handleOptionPointerCancel}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n }}\n onMouseEnter={() => setHighlightedIndex(index)} // Highlight on hover\n role=\"option\" // ARIA role\n aria-selected={selectedValuesArray.includes(option.value)}\n >\n {/* Optional: Add a checkmark or similar for selected items, especially in multi-select */}\n {option.label}\n </li>\n ))\n ) : (\n <li className=\"p-2 text-base-content/60 italic\">\n No options available\n </li>\n )}\n </ul>,\n document.body,\n )}\n </div>\n );\n};\n\nexport default Select; "],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Select/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback, useId, useMemo } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport interface Option {\n value: string | number;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectProps {\n /** Accessible name for the combobox. */\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n /** Optional ID for the combobox; generated per instance when omitted. */\n id?: string;\n disabled?: boolean;\n options: Option[];\n value?: string | number | (string | number)[];\n onChange: (value: string | number | (string | number)[]) => void;\n placeholder?: string;\n multiple?: boolean;\n fixedHeight?: boolean;\n style?: React.CSSProperties; // Allow passing inline styles\n className?: string; // Allow passing CSS classes for the wrapper\n}\n\n// SVG component for the dropdown arrow\nconst DropdownArrow: React.FC<{ isOpen: boolean }> = ({ isOpen }) => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n style={{\n display: 'block',\n width: 16,\n height: 16,\n transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',\n transition: 'transform 200ms ease-in-out',\n }}\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n);\n\n// SVG component for the remove button 'x'\nconst RemoveIcon: React.FC = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" className=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M6 18L18 6M6 6l12 12\" />\n </svg>\n);\n\n// Select Component Implementation using daisyUI/Tailwind\nconst Select: React.FC<SelectProps> = ({\n options,\n value,\n onChange,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledby,\n 'aria-describedby': ariaDescribedby,\n id,\n disabled = false,\n placeholder = 'Select...',\n multiple = false,\n fixedHeight = false,\n style,\n className // This className applies to the wrapper\n}) => {\n const generatedId = useId();\n const comboboxId = id ?? `select-${generatedId}`;\n const listboxId = `${comboboxId}-listbox`;\n const optionId = (option: Option) => `${listboxId}-${typeof option.value}-${encodeURIComponent(String(option.value))}`;\n const [open, setIsOpen] = useState(false);\n const isOpen = open && !disabled;\n if (disabled && open) setIsOpen(false);\n const [highlightedValue, setHighlightedValue] = useState<Option['value'] | null>(null);\n const [tooltipText, setTooltipText] = useState('');\n const [showArrow, setShowArrow] = useState(true);\n const [dropdownStyle, setDropdownStyle] = useState<React.CSSProperties>({});\n const wrapperRef = useRef<HTMLDivElement>(null);\n const comboboxRef = useRef<HTMLDivElement>(null);\n const headerRef = useRef<HTMLDivElement>(null); // Ref for the header div\n const optionsListRef = useRef<HTMLUListElement>(null);\n // Tracks a touch/pen press on an option so a tap selects while a drag scrolls.\n // (pointerdown on touch must NOT preventDefault — that blocks native scrolling.)\n const touchPressRef = useRef<{ pointerId: number; x: number; y: number } | null>(null);\n const touchTapRef = useRef(false);\n\n useEffect(() => {\n if (!isOpen) return;\n const handlePointerDown = (event: MouseEvent) => {\n const target = event.target as Node;\n if (wrapperRef.current?.contains(target) || optionsListRef.current?.contains(target)) return;\n setIsOpen(false);\n };\n document.addEventListener('pointerdown', handlePointerDown);\n\n return () => {\n document.removeEventListener('pointerdown', handlePointerDown);\n };\n }, [isOpen]);\n\n const selectedValuesArray = useMemo(() => Array.isArray(value) ? value : (value !== undefined && value !== null ? [value] : []), [value]);\n\n const enabledIndices = options.flatMap((option, index) => option.disabled ? [] : [index]);\n const selectedIndex = options.findIndex(option => !option.disabled && selectedValuesArray.includes(option.value));\n const storedIndex = options.findIndex(option => !option.disabled && option.value === highlightedValue);\n // Derive a valid active option even when options are removed, reordered or disabled.\n const highlightedIndex = storedIndex >= 0 ? storedIndex : selectedIndex >= 0 ? selectedIndex : enabledIndices[0] ?? -1;\n\n\n const handleBlur = (event: React.FocusEvent) => {\n const next = event.relatedTarget as Node | null;\n if (!next || (!wrapperRef.current?.contains(next) && !optionsListRef.current?.contains(next))) {\n setIsOpen(false);\n }\n };\n\n const updateDropdownPosition = useCallback(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const rect = wrapper.getBoundingClientRect();\n const estimatedHeight = Math.min(options.length, 8) * 36 + 8;\n const fitsBelow = rect.bottom + 4 + estimatedHeight <= window.innerHeight;\n setDropdownStyle({\n position: 'fixed',\n left: rect.left,\n top: fitsBelow ? rect.bottom + 4 : Math.max(8, rect.top - estimatedHeight - 4),\n width: rect.width,\n zIndex: 10000,\n });\n }, [options.length]);\n\n useEffect(() => {\n if (!isOpen) return;\n updateDropdownPosition();\n window.addEventListener('resize', updateDropdownPosition);\n window.addEventListener('scroll', updateDropdownPosition, true);\n return () => {\n window.removeEventListener('resize', updateDropdownPosition);\n window.removeEventListener('scroll', updateDropdownPosition, true);\n };\n }, [isOpen, updateDropdownPosition]);\n\n // Hide the decorative arrow when the control becomes too narrow to reserve\n // space for both it and a useful amount of label text.\n useEffect(() => {\n const wrapper = wrapperRef.current;\n if (!wrapper) return;\n const update = () => setShowArrow(wrapper.clientWidth >= 88);\n update();\n const observer = new ResizeObserver(update);\n observer.observe(wrapper);\n return () => observer.disconnect();\n }, []);\n\n // Scroll after React commits the new active option, not using the previous index.\n useEffect(() => {\n if (isOpen && optionsListRef.current && highlightedIndex >= 0) {\n const list = optionsListRef.current;\n const optionElement = list.children[highlightedIndex] as HTMLLIElement;\n if (optionElement) {\n const listRect = list.getBoundingClientRect();\n const optionRect = optionElement.getBoundingClientRect();\n\n if (optionRect.bottom > listRect.bottom) {\n list.scrollTop += optionRect.bottom - listRect.bottom;\n } else if (optionRect.top < listRect.top) {\n list.scrollTop -= listRect.top - optionRect.top;\n }\n }\n }\n }, [isOpen, highlightedIndex]);\n\n const openDropdown = (edge: 'first' | 'last' = 'first') => {\n if (disabled) return;\n const index = selectedIndex >= 0 ? selectedIndex : edge === 'last' ? enabledIndices.at(-1) : enabledIndices[0];\n setHighlightedValue(index !== undefined && index >= 0 ? options[index].value : null);\n setIsOpen(true);\n updateDropdownPosition();\n };\n\n const toggleDropdown = () => {\n if (disabled) return;\n comboboxRef.current?.focus({ preventScroll: true });\n if (isOpen) setIsOpen(false);\n else openDropdown();\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key === 'Tab') {\n setIsOpen(false); // Preserve native Tab / Shift+Tab focus traversal, including tag buttons.\n return;\n }\n if (event.target !== comboboxRef.current || disabled || event.defaultPrevented || event.nativeEvent.isComposing || event.altKey || event.ctrlKey || event.metaKey) return;\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowUp': {\n if (!isOpen) openDropdown(event.key === 'ArrowUp' ? 'last' : 'first');\n else if (enabledIndices.length) {\n const current = enabledIndices.indexOf(highlightedIndex);\n const step = event.key === 'ArrowDown' ? 1 : -1;\n const next = enabledIndices[(current + step + enabledIndices.length) % enabledIndices.length];\n setHighlightedValue(options[next].value);\n }\n break;\n }\n case 'Home':\n case 'End': {\n if (!isOpen) openDropdown();\n const next = event.key === 'Home' ? enabledIndices[0] : enabledIndices.at(-1);\n setHighlightedValue(next === undefined ? null : options[next].value);\n break;\n }\n case 'Enter':\n case ' ':\n if (!isOpen) openDropdown();\n else if (highlightedIndex >= 0) handleOptionClick(options[highlightedIndex]);\n break;\n case 'Escape':\n if (!isOpen) return;\n setIsOpen(false);\n break;\n default:\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n };\n\n const handleOptionClick = (option: Option) => {\n if (disabled || option.disabled) return;\n setHighlightedValue(option.value);\n comboboxRef.current?.focus({ preventScroll: true });\n if (multiple) {\n const currentValues = Array.isArray(value) ? value : [];\n let newValue;\n if (currentValues.includes(option.value)) {\n newValue = currentValues.filter(v => v !== option.value);\n } else {\n newValue = [...currentValues, option.value];\n }\n onChange(newValue);\n } else {\n onChange(option.value);\n setIsOpen(false); // Close dropdown on single select\n }\n };\n\n // Mouse: select immediately on press (existing desktop behavior).\n // Touch/pen: confirm a tap on pointerup, then select on click. Unmounting the\n // option on pointerup would send compatibility mouse events to the page behind\n // the portal, stealing focus. preventDefault() on a\n // touch pointerdown suppresses the browser's native pan gesture, which made\n // long dropdowns impossible to scroll on mobile (and every scroll attempt\n // selected an option instead).\n const handleOptionPointerDown = (event: React.PointerEvent<HTMLLIElement>, option: Option) => {\n touchTapRef.current = false;\n if (event.pointerType === 'mouse') {\n event.preventDefault();\n event.stopPropagation();\n handleOptionClick(option);\n return;\n }\n event.stopPropagation();\n touchPressRef.current = { pointerId: event.pointerId, x: event.clientX, y: event.clientY };\n };\n\n const handleOptionPointerUp = (event: React.PointerEvent<HTMLLIElement>) => {\n const press = touchPressRef.current;\n touchPressRef.current = null;\n if (!press || event.pointerId !== press.pointerId) return;\n // Select only if the finger did not move much — otherwise it was a scroll.\n const moved = Math.hypot(event.clientX - press.x, event.clientY - press.y);\n touchTapRef.current = moved < 10;\n event.stopPropagation();\n };\n\n const handleOptionPointerCancel = () => {\n touchPressRef.current = null;\n touchTapRef.current = false;\n };\n\n const handleRemoveItem = (e: React.MouseEvent, itemValue: string | number) => {\n e.stopPropagation(); // Prevent dropdown from opening/closing\n if (disabled || options.find(option => option.value === itemValue)?.disabled) return;\n comboboxRef.current?.focus({ preventScroll: true });\n const currentValues = Array.isArray(value) ? value : [];\n onChange(currentValues.filter(v => v !== itemValue));\n };\n\n // Update tooltip text and check for overflow\n useEffect(() => {\n if (multiple && headerRef.current) {\n const header = headerRef.current;\n const selectedLabels = options\n .filter(opt => selectedValuesArray.includes(opt.value))\n .map(opt => opt.label)\n .join(', ');\n\n // Check if the content (scrollWidth) exceeds the visible area (clientWidth)\n const isOverflowing = header.scrollWidth > header.clientWidth;\n setTooltipText(isOverflowing ? selectedLabels : ''); // Only set text if overflowing\n } else {\n setTooltipText(''); // Clear tooltip for single select or empty multi-select\n }\n }, [multiple, options, selectedValuesArray]);\n\n\n const renderSelectedValue = () => {\n if (selectedValuesArray.length === 0) {\n return <span className=\"text-base-content/60 italic\">{placeholder}</span>;\n }\n\n const selectedOptions = options.filter(opt => selectedValuesArray.includes(opt.value));\n\n if (multiple) {\n const isFixed = fixedHeight;\n // Apply overflow-x-auto for horizontal scrolling in fixedHeight mode\n const containerClasses = `\n flex gap-1 \n ${isFixed ? 'flex-nowrap overflow-x-auto overflow-y-hidden' : 'flex-wrap overflow-hidden'} // Enable horizontal scroll, hide vertical scrollbar if any\n ${tooltipText ? 'tooltip tooltip-bottom' : ''} // Keep tooltip for overflow\n `;\n // Removed showEllipsisPrefix\n\n return (\n <div\n ref={headerRef}\n className={containerClasses}\n data-tip={tooltipText ? tooltipText : undefined} // Keep tooltip logic\n // Add scrollbar styling if desired (e.g., using ::-webkit-scrollbar pseudo-element via CSS or a utility)\n style={{\n scrollbarWidth: 'thin',\n // 为固定高度模式添加右侧内边距,避免与下拉图标重叠\n ...(isFixed ? { paddingRight: '1.75rem' } : {})\n }}\n >\n {/* Removed wrapper for ellipsis and its popup */}\n\n {/* Render the badges */}\n {selectedOptions.map(option => (\n <span key={optionId(option)} className=\"badge badge-ghost gap-1 text-xs items-center whitespace-nowrap flex-shrink-0\">\n {option.label}\n <button\n type=\"button\"\n disabled={disabled || option.disabled}\n onClick={(e) => handleRemoveItem(e, option.value)}\n className=\"btn btn-xs btn-ghost btn-circle p-0 m-0 hover:bg-error hover:text-error-content\"\n aria-label={`Remove ${option.label}`}\n >\n <RemoveIcon />\n </button>\n </span>\n ))}\n </div>\n );\n } else {\n const selectedOption = options.find(opt => opt.value === selectedValuesArray[0]);\n return selectedOption ? <span className=\"truncate\">{selectedOption.label}</span> : <span className=\"text-base-content/60 italic\">{placeholder}</span>;\n }\n };\n\n // Match the default control height to a normal line of form text. Multi-select\n // may still grow when wrapping tags unless fixedHeight is requested.\n const selectClasses = `\n relative border border-base-300 rounded-lg bg-base-100 w-full\n flex justify-between items-center cursor-pointer px-3 text-sm\n focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50\n hover:border-base-content/30\n ${multiple\n ? (fixedHeight ? 'h-8' : 'min-h-8 h-auto py-1')\n : 'h-8'}\n `;\n\n return (\n <div\n ref={wrapperRef}\n style={style}\n className={`relative w-full font-sans select-none ${className || ''}`}\n onBlur={handleBlur}\n onKeyDown={handleKeyDown}\n >\n {/* Header */}\n <div\n ref={comboboxRef}\n id={comboboxId}\n tabIndex={disabled ? -1 : 0}\n className={`${selectClasses} ${disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onClick={toggleDropdown}\n\n role=\"combobox\"\n aria-label={ariaLabel ?? (ariaLabelledby ? undefined : placeholder)}\n aria-labelledby={ariaLabelledby}\n aria-describedby={ariaDescribedby}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-disabled={disabled || undefined}\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={isOpen && highlightedIndex >= 0 ? optionId(options[highlightedIndex]) : undefined}\n >\n <div\n className=\"flex-1 min-w-0 overflow-hidden\"\n style={{ paddingRight: showArrow ? 28 : 0 }}\n >\n {renderSelectedValue()}\n </div>\n {/* Inline positioning avoids utility CSS/theme overrides moving the icon. */}\n {showArrow && (\n <div\n aria-hidden=\"true\"\n style={{\n position: 'absolute',\n right: 10,\n top: '50%',\n transform: 'translateY(-50%)',\n pointerEvents: 'none',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: 16,\n height: 16,\n }}\n >\n <DropdownArrow isOpen={isOpen} />\n </div>\n )}\n </div>\n\n {/* Dropdown Options */}\n {isOpen && typeof document !== 'undefined' && createPortal(\n <ul\n ref={optionsListRef}\n id={listboxId}\n className=\"bg-base-100 border border-base-300 rounded-md shadow-lg list-none p-0 m-0 max-h-60 overflow-y-auto focus:outline-none\"\n style={{ ...dropdownStyle, touchAction: 'pan-y' }}\n onPointerDown={(event) => event.stopPropagation()}\n role=\"listbox\"\n aria-labelledby={ariaLabelledby ?? comboboxId}\n aria-multiselectable={multiple || undefined}\n // Keep DOM focus on the combobox even when touch focuses the portal.\n onFocus={() => comboboxRef.current?.focus({ preventScroll: true })}\n tabIndex={-1}\n >\n {options.length > 0 ? (\n options.map((option, index) => (\n <li\n key={optionId(option)}\n id={optionId(option)}\n className={`p-2 ${option.disabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-base-200'} whitespace-nowrap overflow-hidden text-ellipsis ${index === highlightedIndex ? 'bg-base-300' : '' // Highlight style\n } ${selectedValuesArray.includes(option.value) && !multiple ? 'font-semibold bg-base-200' : '' // Style for selected single item\n } ${selectedValuesArray.includes(option.value) && multiple ? 'font-semibold' : '' // Style for selected multi items (less prominent background)\n }`}\n onPointerDown={(event) => handleOptionPointerDown(event, option)}\n onPointerUp={handleOptionPointerUp}\n onPointerCancel={handleOptionPointerCancel}\n onClick={(event) => {\n event.preventDefault();\n event.stopPropagation();\n if (touchTapRef.current || event.detail === 0) handleOptionClick(option);\n touchTapRef.current = false;\n }}\n onPointerMove={event => {\n // Scrolling under a stationary pointer must not undo keyboard navigation.\n if (event.pointerType === 'mouse' && (event.movementX || event.movementY) && !option.disabled) {\n setHighlightedValue(option.value);\n }\n }}\n role=\"option\"\n aria-disabled={option.disabled || undefined}\n aria-selected={selectedValuesArray.includes(option.value)}\n >\n {/* Optional: Add a checkmark or similar for selected items, especially in multi-select */}\n {option.label}\n </li>\n ))\n ) : (\n <li className=\"p-2 text-base-content/60 italic\">\n No options available\n </li>\n )}\n </ul>,\n document.body,\n )}\n </div>\n );\n};\n\nexport default Select; "],"mappings":"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"}