dishui 0.0.72 → 0.0.74

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/Button/index.d.ts +4 -4
  2. package/dist/components/Button/index.js +18 -17
  3. package/dist/components/Button/index.js.map +1 -1
  4. package/dist/components/Card/Metric.d.ts +17 -0
  5. package/dist/components/Card/Metric2.js +50 -0
  6. package/dist/components/Card/Metric2.js.map +1 -0
  7. package/dist/components/Card/index.d.ts +3 -0
  8. package/dist/components/Card/index.js +118 -117
  9. package/dist/components/Card/index.js.map +1 -1
  10. package/dist/components/Group/index.d.ts +2 -0
  11. package/dist/components/GroupButton/index.d.ts +16 -0
  12. package/dist/components/GroupButton/index.js +41 -0
  13. package/dist/components/GroupButton/index.js.map +1 -0
  14. package/dist/components/GroupedTable/index.d.ts +38 -0
  15. package/dist/components/GroupedTable/index.js +92 -0
  16. package/dist/components/GroupedTable/index.js.map +1 -0
  17. package/dist/components/Layout/index.d.ts +4 -2
  18. package/dist/components/Layout/index.js +1 -1
  19. package/dist/components/Layout/index.js.map +1 -1
  20. package/dist/components/NavigationList/index.d.ts +17 -0
  21. package/dist/components/NavigationList/index.js +48 -0
  22. package/dist/components/NavigationList/index.js.map +1 -0
  23. package/dist/components/Section/index.d.ts +28 -0
  24. package/dist/components/Section/index.js +58 -0
  25. package/dist/components/Section/index.js.map +1 -0
  26. package/dist/components/Select/index.d.ts +2 -0
  27. package/dist/components/Select/index.js +83 -82
  28. package/dist/components/Select/index.js.map +1 -1
  29. package/dist/components/SidebarToggleButton/index.d.ts +16 -1
  30. package/dist/components/SidebarToggleButton/index.js +90 -30
  31. package/dist/components/SidebarToggleButton/index.js.map +1 -1
  32. package/dist/components/Skeleton/index.d.ts +7 -0
  33. package/dist/components/Skeleton/index.js +21 -0
  34. package/dist/components/Skeleton/index.js.map +1 -0
  35. package/dist/components/Tree/Tree.js +5 -2
  36. package/dist/components/Tree/Tree.js.map +1 -1
  37. package/dist/components/pro/RichTextEditor/AIRewrite.js +114 -72
  38. package/dist/components/pro/RichTextEditor/AIRewrite.js.map +1 -1
  39. package/dist/components/pro/RichTextEditor/BlockHandle.js +315 -196
  40. package/dist/components/pro/RichTextEditor/BlockHandle.js.map +1 -1
  41. package/dist/components/pro/RichTextEditor/BubbleToolbar.d.ts +1 -1
  42. package/dist/components/pro/RichTextEditor/BubbleToolbar.js +156 -39
  43. package/dist/components/pro/RichTextEditor/BubbleToolbar.js.map +1 -1
  44. package/dist/components/pro/RichTextEditor/CommentPanel.d.ts +2 -1
  45. package/dist/components/pro/RichTextEditor/CommentPanel.js +100 -81
  46. package/dist/components/pro/RichTextEditor/CommentPanel.js.map +1 -1
  47. package/dist/components/pro/RichTextEditor/CommentPopover.d.ts +2 -1
  48. package/dist/components/pro/RichTextEditor/CommentPopover.js +92 -68
  49. package/dist/components/pro/RichTextEditor/CommentPopover.js.map +1 -1
  50. package/dist/components/pro/RichTextEditor/RichTextEditor.js +24 -22
  51. package/dist/components/pro/RichTextEditor/RichTextEditor.js.map +1 -1
  52. package/dist/components/pro/RichTextEditor/SearchReplace.d.ts +7 -0
  53. package/dist/components/pro/RichTextEditor/SlashMenu.js +132 -73
  54. package/dist/components/pro/RichTextEditor/SlashMenu.js.map +1 -1
  55. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.d.ts +2 -0
  56. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js +9 -9
  57. package/dist/components/pro/RichTextEditor/Toolbar/ColorPicker.js.map +1 -1
  58. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js +8 -13
  59. package/dist/components/pro/RichTextEditor/Toolbar/FloatingDialogMenu.js.map +1 -1
  60. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js +22 -3
  61. package/dist/components/pro/RichTextEditor/Toolbar/MarkdownTemplates.js.map +1 -1
  62. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.d.ts +1 -1
  63. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js +346 -313
  64. package/dist/components/pro/RichTextEditor/Toolbar/Toolbar.js.map +1 -1
  65. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js +120 -146
  66. package/dist/components/pro/RichTextEditor/extensions/CodeBlockView.js.map +1 -1
  67. package/dist/components/pro/RichTextEditor/extensions/CommentMark.js +2 -2
  68. package/dist/components/pro/RichTextEditor/extensions/CommentMark.js.map +1 -1
  69. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js +178 -163
  70. package/dist/components/pro/RichTextEditor/extensions/FloatingDialog.js.map +1 -1
  71. package/dist/components/pro/RichTextEditor/extensions/FontSize.js +8 -5
  72. package/dist/components/pro/RichTextEditor/extensions/FontSize.js.map +1 -1
  73. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.d.ts +6 -0
  74. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js +85 -74
  75. package/dist/components/pro/RichTextEditor/extensions/MarkdownBlock.js.map +1 -1
  76. package/dist/components/pro/RichTextEditor/searchUtils.d.ts +23 -0
  77. package/dist/contexts/AppContext.js +47 -45
  78. package/dist/contexts/AppContext.js.map +1 -1
  79. package/dist/dishui.css +1 -1
  80. package/dist/index-nostyled.d.ts +11 -1
  81. package/dist/index.d.ts +11 -1
  82. package/dist/index.js +119 -114
  83. package/dist/layouts/MainLayout.js +9 -10
  84. package/dist/layouts/MainLayout.js.map +1 -1
  85. package/dist/layouts/Sidebar.d.ts +9 -0
  86. package/dist/layouts/Sidebar.js +99 -80
  87. package/dist/layouts/Sidebar.js.map +1 -1
  88. package/dist/layouts/headbar/Headbar.d.ts +1 -1
  89. package/dist/layouts/headbar/Headbar.js +2 -2
  90. package/dist/layouts/headbar/Headbar.js.map +1 -1
  91. package/dist/lite.d.ts +19 -1
  92. package/dist/lite.js +17 -8
  93. package/dist/styles/themeStyles.js +6 -6
  94. package/dist/styles/themeStyles.js.map +1 -1
  95. package/dist/utils/i18n.d.ts +3 -0
  96. package/dist/utils/i18n.js +78 -0
  97. package/dist/utils/i18n.js.map +1 -1
  98. package/dist/utils/menu.js +23 -6
  99. package/dist/utils/menu.js.map +1 -1
  100. package/package.json +8 -2
@@ -1,33 +1,93 @@
1
1
  import "react";
2
2
  import { Fragment as e, jsx as t, jsxs as n } from "react/jsx-runtime";
3
3
  //#region src/components/SidebarToggleButton/index.tsx
4
- var r = ({ isCollapsed: e, onToggle: n, sidebarWidth: r, collapsedWidth: i = 64 }) => /* @__PURE__ */ t("div", {
5
- className: "bg-opacity-20",
6
- children: /* @__PURE__ */ t("button", {
7
- onClick: n,
8
- className: "fixed top-1/2 -translate-y-1/2 z-50 bg-success opacity-60 hover:opacity-90 text-primary-content rounded-full p-1.5 sm:p-2.5 shadow-lg transition-all duration-300 ease-in-out backdrop-blur-sm hover:scale-110 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50 lg:flex md:flex hidden",
9
- style: {
10
- left: e ? `${i - 24}px` : `${r - 24}px`,
11
- transform: "translateY(-50%)",
12
- boxShadow: "0 4px 15px rgba(0, 0, 0, 0.1)"
13
- },
14
- "aria-label": e ? "展开侧边栏" : "收起侧边栏",
15
- children: /* @__PURE__ */ t("svg", {
16
- xmlns: "http://www.w3.org/2000/svg",
17
- fill: "none",
18
- viewBox: "0 0 24 24",
19
- stroke: "currentColor",
20
- className: "w-4 h-4 sm:w-5 sm:h-5 transition-transform duration-300",
21
- style: { transform: e ? "rotate(180deg)" : "rotate(0deg)" },
22
- children: /* @__PURE__ */ t("path", {
23
- strokeLinecap: "round",
24
- strokeLinejoin: "round",
25
- strokeWidth: "2",
26
- d: "M15 19l-7-7 7-7"
4
+ var r = 4, i = ({ isCollapsed: e, onToggle: i, collapsedWidth: a = 64, onWidthChange: o, minWidth: s = 160, maxWidth: c = 400, anchorRef: l }) => {
5
+ let u = typeof o == "function";
6
+ return /* @__PURE__ */ n("div", {
7
+ className: "absolute inset-y-0 right-0 z-40 hidden w-3 translate-x-1/2 md:block lg:block",
8
+ style: { cursor: u ? "ew-resize" : "pointer" },
9
+ onPointerDown: u ? (e) => {
10
+ if (!u || e.button !== 0) return;
11
+ let t = e.clientX, n = !1, a = document.body.style.userSelect, d = document.body.style.cursor, f = l?.current?.getBoundingClientRect().left ?? 0, p = (e) => {
12
+ if (!n && Math.abs(e.clientX - t) > r && (n = !0, document.body.style.userSelect = "none", document.body.style.cursor = "ew-resize"), n) {
13
+ let t = Math.max(s, Math.min(e.clientX - f, c));
14
+ o?.(t);
15
+ }
16
+ }, m = () => {
17
+ document.removeEventListener("pointermove", p), document.removeEventListener("pointerup", m), document.body.style.userSelect = a, document.body.style.cursor = d, n || i();
18
+ };
19
+ document.addEventListener("pointermove", p), document.addEventListener("pointerup", m);
20
+ } : void 0,
21
+ onClick: u ? void 0 : i,
22
+ children: [/* @__PURE__ */ t("div", {
23
+ className: "pointer-events-none absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-base-300",
24
+ "aria-hidden": "true"
25
+ }), /* @__PURE__ */ t("button", {
26
+ type: "button",
27
+ tabIndex: 0,
28
+ onClick: u ? void 0 : i,
29
+ className: "group absolute top-1/2 left-1/2 flex h-10 w-4 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-base-300 bg-base-100 text-base-content/40 shadow-md transition-[width,color] duration-200 ease-in-out hover:w-5 hover:text-base-content focus:outline-none focus:ring-2 focus:ring-primary/40",
30
+ style: { cursor: u ? "ew-resize" : "pointer" },
31
+ "aria-label": e ? "展开侧边栏" : u ? "拖拽调整侧边栏宽度,点击收起" : "收起侧边栏",
32
+ "aria-expanded": !e,
33
+ title: u && !e ? "拖拽调节宽度 · 点击折叠" : void 0,
34
+ children: e ? /* @__PURE__ */ t("svg", {
35
+ xmlns: "http://www.w3.org/2000/svg",
36
+ width: "10",
37
+ height: "10",
38
+ fill: "none",
39
+ viewBox: "0 0 24 24",
40
+ stroke: "currentColor",
41
+ className: "pointer-events-none",
42
+ children: /* @__PURE__ */ t("path", {
43
+ strokeLinecap: "round",
44
+ strokeLinejoin: "round",
45
+ strokeWidth: "2.5",
46
+ d: "M9 5l7 7-7 7"
47
+ })
48
+ }) : /* @__PURE__ */ n("svg", {
49
+ width: "6",
50
+ height: "18",
51
+ viewBox: "0 0 6 18",
52
+ fill: "currentColor",
53
+ "aria-hidden": "true",
54
+ className: "pointer-events-none",
55
+ children: [
56
+ /* @__PURE__ */ t("circle", {
57
+ cx: "1.5",
58
+ cy: "3",
59
+ r: "1"
60
+ }),
61
+ /* @__PURE__ */ t("circle", {
62
+ cx: "4.5",
63
+ cy: "3",
64
+ r: "1"
65
+ }),
66
+ /* @__PURE__ */ t("circle", {
67
+ cx: "1.5",
68
+ cy: "9",
69
+ r: "1"
70
+ }),
71
+ /* @__PURE__ */ t("circle", {
72
+ cx: "4.5",
73
+ cy: "9",
74
+ r: "1"
75
+ }),
76
+ /* @__PURE__ */ t("circle", {
77
+ cx: "1.5",
78
+ cy: "15",
79
+ r: "1"
80
+ }),
81
+ /* @__PURE__ */ t("circle", {
82
+ cx: "4.5",
83
+ cy: "15",
84
+ r: "1"
85
+ })
86
+ ]
27
87
  })
28
- })
29
- })
30
- }), i = ({ isCollapsed: e, onToggle: n }) => /* @__PURE__ */ t("button", {
88
+ })]
89
+ });
90
+ }, a = ({ isCollapsed: e, onToggle: n }) => /* @__PURE__ */ t("button", {
31
91
  onClick: n,
32
92
  className: "fixed bottom-6 right-6 z-50 bg-primary bg-opacity-30 hover:bg-opacity-50 text-primary-content rounded-full p-3 shadow-lg transition-all duration-300 ease-in-out backdrop-blur-sm hover:scale-105 md:hidden",
33
93
  style: { boxShadow: "0 4px 20px rgba(0, 0, 0, 0.15)" },
@@ -50,11 +110,11 @@ var r = ({ isCollapsed: e, onToggle: n, sidebarWidth: r, collapsedWidth: i = 64
50
110
  d: "M6 18L18 6M6 6l12 12"
51
111
  })
52
112
  })
53
- }), a = (a) => /* @__PURE__ */ n(e, { children: [/* @__PURE__ */ t(r, { ...a }), /* @__PURE__ */ t(i, {
54
- isCollapsed: a.isCollapsed,
55
- onToggle: a.onToggle
113
+ }), o = (r) => /* @__PURE__ */ n(e, { children: [/* @__PURE__ */ t(i, { ...r }), /* @__PURE__ */ t(a, {
114
+ isCollapsed: r.isCollapsed,
115
+ onToggle: r.onToggle
56
116
  })] });
57
117
  //#endregion
58
- export { r as DesktopSidebarToggleButton, i as MobileSidebarToggleButton, a as SidebarToggleButtons, a as default };
118
+ export { i as DesktopSidebarToggleButton, a as MobileSidebarToggleButton, o as SidebarToggleButtons, o as default };
59
119
 
60
120
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/SidebarToggleButton/index.tsx"],"sourcesContent":["import React from 'react';\n\ninterface SidebarToggleButtonProps {\n /** 侧边栏是否折叠 */\n isCollapsed: boolean;\n /** 切换侧边栏的回调 */\n onToggle: () => void;\n /** 当前侧边栏宽度 */\n sidebarWidth: number;\n /** 折叠时的宽度 */\n collapsedWidth?: number;\n}\n\n/**\n * 桌面端悬浮侧边栏切换按钮\n */\nexport const DesktopSidebarToggleButton: React.FC<SidebarToggleButtonProps> = ({\n isCollapsed,\n onToggle,\n sidebarWidth,\n collapsedWidth = 64,\n}) => {\n return (\n <div className=\"bg-opacity-20\">\n <button\n onClick={onToggle}\n className=\"fixed top-1/2 -translate-y-1/2 z-50 bg-success opacity-60 hover:opacity-90 text-primary-content rounded-full p-1.5 sm:p-2.5 shadow-lg transition-all duration-300 ease-in-out backdrop-blur-sm hover:scale-110 focus:outline-none focus:ring-2 focus:ring-primary focus:ring-opacity-50 lg:flex md:flex hidden\"\n style={{\n left: isCollapsed ? `${collapsedWidth - 24}px` : `${sidebarWidth - 24}px`,\n transform: 'translateY(-50%)',\n boxShadow: '0 4px 15px rgba(0, 0, 0, 0.1)',\n }}\n aria-label={isCollapsed ? '展开侧边栏' : '收起侧边栏'}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n className=\"w-4 h-4 sm:w-5 sm:h-5 transition-transform duration-300\"\n style={{\n transform: isCollapsed ? 'rotate(180deg)' : 'rotate(0deg)',\n }}\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M15 19l-7-7 7-7\" />\n </svg>\n </button>\n </div>\n );\n};\n\n/**\n * 移动端悬浮侧边栏切换按钮\n */\nexport const MobileSidebarToggleButton: React.FC<Pick<SidebarToggleButtonProps, 'isCollapsed' | 'onToggle'>> = ({\n isCollapsed,\n onToggle,\n}) => {\n return (\n <button\n onClick={onToggle}\n className=\"fixed bottom-6 right-6 z-50 bg-primary bg-opacity-30 hover:bg-opacity-50 text-primary-content rounded-full p-3 shadow-lg transition-all duration-300 ease-in-out backdrop-blur-sm hover:scale-105 md:hidden\"\n style={{\n boxShadow: '0 4px 20px rgba(0, 0, 0, 0.15)',\n }}\n aria-label={isCollapsed ? '展开侧边栏' : '收起侧边栏'}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n className=\"w-5 h-5\"\n >\n {isCollapsed ? (\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M4 6h16M4 12h16M4 18h16\" />\n ) : (\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n )}\n </svg>\n </button>\n );\n};\n\n/**\n * 组合的侧边栏切换按钮(包含桌面端和移动端)\n */\nexport const SidebarToggleButtons: React.FC<SidebarToggleButtonProps> = (props) => {\n return (\n <>\n <DesktopSidebarToggleButton {...props} />\n <MobileSidebarToggleButton isCollapsed={props.isCollapsed} onToggle={props.onToggle} />\n </>\n );\n};\n\nexport default SidebarToggleButtons;\n\n"],"mappings":";;;AAgBA,IAAa,KAAkE,EAC7E,gBACA,aACA,iBACA,oBAAiB,SAGf,kBAAC,OAAD;CAAK,WAAU;CACb,UAAA,kBAAC,UAAD;EACE,SAAS;EACT,WAAU;EACV,OAAO;GACL,MAAM,IAAc,GAAG,IAAiB,GAAG,MAAM,GAAG,IAAe,GAAG;GACtE,WAAW;GACX,WAAW;EACb;EACA,cAAY,IAAc,UAAU;EAEpC,UAAA,kBAAC,OAAD;GACE,OAAM;GACN,MAAK;GACL,SAAQ;GACR,QAAO;GACP,WAAU;GACV,OAAO,EACL,WAAW,IAAc,mBAAmB,eAC9C;GAEA,UAAA,kBAAC,QAAD;IAAM,eAAc;IAAQ,gBAAe;IAAQ,aAAY;IAAI,GAAE;GAAmB,CAAA;EACrF,CAAA;CACC,CAAA;AACL,CAAA,GAOI,KAAmG,EAC9G,gBACA,kBAGE,kBAAC,UAAD;CACE,SAAS;CACT,WAAU;CACV,OAAO,EACL,WAAW,iCACb;CACA,cAAY,IAAc,UAAU;CAEpC,UAAA,kBAAC,OAAD;EACE,OAAM;EACN,MAAK;EACL,SAAQ;EACR,QAAO;EACP,WAAU;EAET,UAAA,IACC,kBAAC,QAAD;GAAM,eAAc;GAAQ,gBAAe;GAAQ,aAAY;GAAI,GAAE;EAA2B,CAAA,IAEhG,kBAAC,QAAD;GAAM,eAAc;GAAQ,gBAAe;GAAQ,aAAY;GAAI,GAAE;EAAwB,CAAA;CAE5F,CAAA;AACC,CAAA,GAOC,KAA4D,MAErE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAA4B,GAAI,EAAQ,CAAA,GACxC,kBAAC,GAAD;CAA2B,aAAa,EAAM;CAAa,UAAU,EAAM;AAAW,CAAA,CACtF,EAAA,CAAA"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/SidebarToggleButton/index.tsx"],"sourcesContent":["import React from 'react';\n\ninterface SidebarToggleButtonProps {\n /** 侧边栏是否折叠 */\n isCollapsed: boolean;\n /** 切换侧边栏的回调 */\n onToggle: () => void;\n /** 当前侧边栏宽度 */\n sidebarWidth: number;\n /** 折叠时的宽度 */\n collapsedWidth?: number;\n /** 拖拽调节宽度的回调(传入时支持拖拽缩放) */\n onWidthChange?: (width: number) => void;\n /** 拖拽时的最小宽度(px) */\n minWidth?: number;\n /** 拖拽时的最大宽度(px) */\n maxWidth?: number;\n /**\n * 侧边栏容器元素的引用(用于拖拽时获取左边缘,使宽度计算与内嵌位置无关)。\n */\n anchorRef?: React.RefObject<HTMLElement | null>;\n}\n\n// 超过该位移(px)视为拖拽,否则视为点击切换。\nconst DRAG_THRESHOLD = 4;\n\n/**\n * 桌面端侧边栏切换控件(与右侧纵向边界线一体)\n * - 点击:折叠 / 展开侧边栏\n * - 拖拽:任意调节侧边栏宽度(需传入 onWidthChange)\n *\n * 采用 `absolute` 定位内嵌在侧边栏(relative 容器)右边缘,随侧边栏布局自然移动——\n * 无需测量/追赶,无延迟,也不受其它可变宽度组件影响。\n */\nexport const DesktopSidebarToggleButton: React.FC<SidebarToggleButtonProps> = ({\n isCollapsed,\n onToggle,\n collapsedWidth = 64,\n onWidthChange,\n minWidth = 160,\n maxWidth = 400,\n anchorRef,\n}) => {\n const draggable = typeof onWidthChange === 'function';\n\n const handlePointerDown = (event: React.PointerEvent<HTMLElement>) => {\n if (!draggable || event.button !== 0) return;\n const startX = event.clientX;\n let moved = false;\n const previousUserSelect = document.body.style.userSelect;\n const previousCursor = document.body.style.cursor;\n // 宽度 = 指针位置 - 侧边栏左边缘。有 anchorRef 时取其真实左边缘,否则假设为 0。\n const sidebarLeft = anchorRef?.current?.getBoundingClientRect().left ?? 0;\n\n const handleMove = (moveEvent: PointerEvent) => {\n if (!moved && Math.abs(moveEvent.clientX - startX) > DRAG_THRESHOLD) {\n moved = true;\n document.body.style.userSelect = 'none';\n document.body.style.cursor = 'ew-resize';\n }\n if (moved) {\n const clamped = Math.max(minWidth, Math.min(moveEvent.clientX - sidebarLeft, maxWidth));\n onWidthChange?.(clamped);\n }\n };\n\n const handleUp = () => {\n document.removeEventListener('pointermove', handleMove);\n document.removeEventListener('pointerup', handleUp);\n document.body.style.userSelect = previousUserSelect;\n document.body.style.cursor = previousCursor;\n // 未发生拖拽时视为点击切换。\n if (!moved) onToggle();\n };\n\n document.addEventListener('pointermove', handleMove);\n document.addEventListener('pointerup', handleUp);\n };\n\n return (\n // 与右侧边界线一体:定位在侧边栏右边缘(right:0)的全高约束区,\n // 内嵌纵向边界线 + 坐落在线上的 pill。w-3 作为拖拽热区。\n <div\n className=\"absolute inset-y-0 right-0 z-40 hidden w-3 translate-x-1/2 md:block lg:block\"\n style={{ cursor: draggable ? 'ew-resize' : 'pointer' }}\n onPointerDown={draggable ? handlePointerDown : undefined}\n onClick={draggable ? undefined : onToggle}\n >\n {/* 纵向边界线(居中于热区 = 侧边栏右边缘) */}\n <div className=\"pointer-events-none absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-base-300\" aria-hidden=\"true\" />\n {/* pill 手柄(坐落在线上,与之一体) */}\n <button\n type=\"button\"\n tabIndex={0}\n onClick={draggable ? undefined : onToggle}\n className=\"group absolute top-1/2 left-1/2 flex h-10 w-4 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border border-base-300 bg-base-100 text-base-content/40 shadow-md transition-[width,color] duration-200 ease-in-out hover:w-5 hover:text-base-content focus:outline-none focus:ring-2 focus:ring-primary/40\"\n style={{ cursor: draggable ? 'ew-resize' : 'pointer' }}\n aria-label={isCollapsed ? '展开侧边栏' : (draggable ? '拖拽调整侧边栏宽度,点击收起' : '收起侧边栏')}\n aria-expanded={!isCollapsed}\n title={draggable && !isCollapsed ? '拖拽调节宽度 · 点击折叠' : undefined}\n >\n {isCollapsed ? (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"10\" height=\"10\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" className=\"pointer-events-none\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2.5\" d=\"M9 5l7 7-7 7\" />\n </svg>\n ) : (\n <svg width=\"6\" height=\"18\" viewBox=\"0 0 6 18\" fill=\"currentColor\" aria-hidden=\"true\" className=\"pointer-events-none\">\n <circle cx=\"1.5\" cy=\"3\" r=\"1\" /><circle cx=\"4.5\" cy=\"3\" r=\"1\" />\n <circle cx=\"1.5\" cy=\"9\" r=\"1\" /><circle cx=\"4.5\" cy=\"9\" r=\"1\" />\n <circle cx=\"1.5\" cy=\"15\" r=\"1\" /><circle cx=\"4.5\" cy=\"15\" r=\"1\" />\n </svg>\n )}\n </button>\n </div>\n );\n};\n\n/**\n * 移动端悬浮侧边栏切换按钮\n */\nexport const MobileSidebarToggleButton: React.FC<Pick<SidebarToggleButtonProps, 'isCollapsed' | 'onToggle'>> = ({\n isCollapsed,\n onToggle,\n}) => {\n return (\n <button\n onClick={onToggle}\n className=\"fixed bottom-6 right-6 z-50 bg-primary bg-opacity-30 hover:bg-opacity-50 text-primary-content rounded-full p-3 shadow-lg transition-all duration-300 ease-in-out backdrop-blur-sm hover:scale-105 md:hidden\"\n style={{\n boxShadow: '0 4px 20px rgba(0, 0, 0, 0.15)',\n }}\n aria-label={isCollapsed ? '展开侧边栏' : '收起侧边栏'}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n className=\"w-5 h-5\"\n >\n {isCollapsed ? (\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M4 6h16M4 12h16M4 18h16\" />\n ) : (\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth=\"2\" d=\"M6 18L18 6M6 6l12 12\" />\n )}\n </svg>\n </button>\n );\n};\n\n/**\n * 组合的侧边栏切换按钮(包含桌面端和移动端)\n */\nexport const SidebarToggleButtons: React.FC<SidebarToggleButtonProps> = (props) => {\n return (\n <>\n <DesktopSidebarToggleButton {...props} />\n <MobileSidebarToggleButton isCollapsed={props.isCollapsed} onToggle={props.onToggle} />\n </>\n );\n};\n\nexport default SidebarToggleButtons;\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ export type SkeletonProps = React.HTMLAttributes<HTMLSpanElement> & {
3
+ width?: React.CSSProperties['width'];
4
+ height?: React.CSSProperties['height'];
5
+ };
6
+ /** Static placeholder; the containing data region supplies the loading announcement. */
7
+ export default function Skeleton({ width, height, className, style, ...rest }: SkeletonProps): React.JSX.Element;
@@ -0,0 +1,21 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ /* empty css */
3
+ import "react";
4
+ import { jsx as t } from "react/jsx-runtime";
5
+ //#region src/components/Skeleton/index.tsx
6
+ function n({ width: n = "100%", height: r = "1em", className: i, style: a, ...o }) {
7
+ return /* @__PURE__ */ t("span", {
8
+ ...o,
9
+ "aria-hidden": "true",
10
+ className: e("blade-skeleton", i),
11
+ style: {
12
+ width: n,
13
+ height: r,
14
+ ...a
15
+ }
16
+ });
17
+ }
18
+ //#endregion
19
+ export { n as default };
20
+
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Skeleton/index.tsx"],"sourcesContent":["import React from 'react';\nimport { cn } from '../../utils/cn';\nimport './Skeleton.css';\n\nexport type SkeletonProps = React.HTMLAttributes<HTMLSpanElement> & {\n width?: React.CSSProperties['width'];\n height?: React.CSSProperties['height'];\n};\n\n/** Static placeholder; the containing data region supplies the loading announcement. */\nexport default function Skeleton({ width = '100%', height = '1em', className, style, ...rest }: SkeletonProps) {\n return <span {...rest} aria-hidden=\"true\" className={cn('blade-skeleton', className)} style={{ width, height, ...style }} />;\n}\n"],"mappings":";;;;;AAUA,SAAwB,EAAS,EAAE,WAAQ,QAAQ,YAAS,OAAO,cAAW,UAAO,GAAG,KAAuB;CAC3G,OAAO,kBAAC,QAAD;EAAM,GAAI;EAAM,eAAY;EAAO,WAAW,EAAG,kBAAkB,CAAS;EAAG,OAAO;GAAE;GAAO;GAAQ,GAAG;EAAM;CAAI,CAAA;AAC/H"}
@@ -108,14 +108,17 @@ var c = ({ data: c, onNodeClick: l, onNodeDoubleClick: u, onNodeToggle: d, activ
108
108
  title: e.label,
109
109
  children: e.label
110
110
  }),
111
- r && O && /* @__PURE__ */ s("span", {
111
+ e.meta?.count !== void 0 && e.meta?.count !== null ? /* @__PURE__ */ o("span", {
112
+ className: "tree-node-count text-xs opacity-60",
113
+ children: e.meta.count
114
+ }) : r && O ? /* @__PURE__ */ s("span", {
112
115
  className: "tree-node-count text-xs opacity-60",
113
116
  children: [
114
117
  "(",
115
118
  e.children.length,
116
119
  ")"
117
120
  ]
118
- }),
121
+ }) : null,
119
122
  M === "right" && r && /* @__PURE__ */ o("button", {
120
123
  className: `tree-node-toggle tree-node-toggle-right btn btn-xs btn-ghost ${i ? "tree-node-toggle-expanded" : ""}`,
121
124
  onClick: (t) => {
@@ -1 +1 @@
1
- {"version":3,"file":"Tree.js","names":[],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import React, { useState, useCallback, useMemo } from 'react';\nimport { generateTreeActiveStyles } from '../../styles/themeStyles';\n\n// ============= 类型定义 =============\n\nexport interface TreeNode {\n id: string | number;\n label: string;\n children?: TreeNode[];\n icon?: React.ReactNode;\n disabled?: boolean;\n meta?: Record<string, any>;\n}\n\nexport interface TreeProps {\n /** 树形数据 */\n data: TreeNode[];\n\n /** 节点点击回调 */\n onNodeClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点双击回调 */\n onNodeDoubleClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点展开/折叠回调 */\n onNodeToggle?: (nodeId: string | number, expanded: boolean) => void;\n\n /** 当前激活的节点 ID */\n activeNodeId?: string | number;\n\n /** 默认展开的节点 ID 列表 */\n defaultExpandedIds?: (string | number)[];\n\n /** 是否显示搜索框 */\n showSearch?: boolean;\n\n /** 搜索占位符 */\n searchPlaceholder?: string;\n\n /** 是否显示展开/折叠全部按钮 */\n showExpandAll?: boolean;\n\n /** 展开全部按钮文本 */\n expandAllText?: string;\n\n /** 折叠全部按钮文本 */\n collapseAllText?: string;\n\n /** 是否显示节点图标 */\n showIcon?: boolean;\n\n /** 默认图标 */\n defaultIcon?: React.ReactNode;\n\n /** 展开图标 */\n expandIcon?: React.ReactNode;\n\n /** 折叠图标 */\n collapseIcon?: React.ReactNode;\n\n /** 是否显示连接线 */\n showLine?: boolean;\n\n /** 最大高度 */\n maxHeight?: string;\n\n /** 自定义类名 */\n className?: string;\n\n /** 标题 */\n title?: string;\n\n /** 标题图标 */\n titleIcon?: React.ReactNode;\n\n /** 是否显示节点数量 */\n showCount?: boolean;\n\n /** 空状态文本 */\n emptyText?: string;\n\n /** 搜索无结果文本 */\n noResultsText?: string;\n\n /** 缩进宽度(像素) */\n indent?: number;\n\n /** 展开按钮位置:left(左侧)或 right(右侧) */\n togglePosition?: 'left' | 'right';\n\n /** 是否可拖拽(暂不实现) */\n draggable?: boolean;\n\n /** 是否可选择(暂不实现) */\n checkable?: boolean;\n\n /** 自定义渲染节点 */\n renderNode?: (node: TreeNode, defaultRender: React.ReactNode) => React.ReactNode;\n}\n\n// ============= Tree 组件 =============\n\nconst Tree: React.FC<TreeProps> = ({\n data,\n onNodeClick,\n onNodeDoubleClick,\n onNodeToggle,\n activeNodeId,\n defaultExpandedIds = [],\n showSearch = true,\n searchPlaceholder = 'Search...',\n showExpandAll = true,\n expandAllText = 'Expand All',\n collapseAllText = 'Collapse All',\n showIcon = true,\n defaultIcon,\n expandIcon,\n collapseIcon,\n showLine = false,\n maxHeight = '600px',\n className = '',\n title,\n titleIcon,\n showCount = true,\n emptyText = 'No data',\n noResultsText = 'No results found',\n indent = 16,\n togglePosition = 'left',\n renderNode,\n}) => {\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedIds, setExpandedIds] = useState<Set<string | number>>(\n new Set(defaultExpandedIds)\n );\n\n // 当 defaultExpandedIds 变化时,同步更新 expandedIds(用于异步加载的数据)\n React.useEffect(() => {\n if (defaultExpandedIds.length > 0) {\n setExpandedIds(prev => {\n const newSet = new Set(prev);\n defaultExpandedIds.forEach(id => newSet.add(id));\n return newSet;\n });\n }\n }, [defaultExpandedIds]);\n\n // 默认展开/折叠图标\n const defaultExpandIconEl = expandIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n );\n\n const defaultCollapseIconEl = collapseIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n );\n\n // 默认节点图标\n const defaultIconEl = defaultIcon || (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n );\n\n // 统计节点总数\n const countNodes = useCallback((nodes: TreeNode[]): number => {\n return nodes.reduce((count, node) => {\n return count + 1 + (node.children ? countNodes(node.children) : 0);\n }, 0);\n }, []);\n\n const totalCount = useMemo(() => countNodes(data), [data, countNodes]);\n\n // 过滤节点(支持搜索)\n const filterNodes = useCallback((nodes: TreeNode[], query: string): TreeNode[] => {\n if (!query) return nodes;\n\n const lowerQuery = query.toLowerCase();\n const filtered: TreeNode[] = [];\n\n for (const node of nodes) {\n const matches = node.label.toLowerCase().includes(lowerQuery);\n const filteredChildren = node.children ? filterNodes(node.children, query) : [];\n\n if (matches || filteredChildren.length > 0) {\n filtered.push({\n ...node,\n children: filteredChildren.length > 0 ? filteredChildren : node.children,\n });\n }\n }\n\n return filtered;\n }, []);\n\n const filteredData = useMemo(\n () => filterNodes(data, searchQuery),\n [data, searchQuery, filterNodes]\n );\n\n // 切换节点展开/折叠\n const toggleNode = useCallback(\n (nodeId: string | number) => {\n const newExpanded = new Set(expandedIds);\n if (newExpanded.has(nodeId)) {\n newExpanded.delete(nodeId);\n onNodeToggle?.(nodeId, false);\n } else {\n newExpanded.add(nodeId);\n onNodeToggle?.(nodeId, true);\n }\n setExpandedIds(newExpanded);\n },\n [expandedIds, onNodeToggle]\n );\n\n // 展开所有节点\n const expandAll = useCallback(() => {\n const allIds = new Set<string | number>();\n const collectIds = (nodes: TreeNode[]) => {\n nodes.forEach((node) => {\n if (node.children && node.children.length > 0) {\n allIds.add(node.id);\n collectIds(node.children);\n }\n });\n };\n collectIds(data);\n setExpandedIds(allIds);\n }, [data]);\n\n // 折叠所有节点\n const collapseAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n // 渲染单个节点\n const renderTreeNode = useCallback(\n (node: TreeNode, depth: number = 0, path: (string | number)[] = []) => {\n const hasChildren = node.children && node.children.length > 0;\n const isExpanded = expandedIds.has(node.id);\n const isActive = activeNodeId === node.id;\n const currentPath = [...path, node.id];\n\n const nodeContent = (\n <div\n key={node.id}\n data-node-id={node.id}\n className={`tree-node ${isActive ? 'tree-node-active' : ''} ${node.disabled ? 'tree-node-disabled' : ''\n }`}\n style={{\n paddingLeft: `${depth * indent}px`,\n }}\n >\n <div\n className={`tree-node-content flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer transition-colors ${isActive ? 'tree-node-content-active' : 'tree-node-content-inactive'\n } ${node.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onClick={() => {\n if (!node.disabled) {\n onNodeClick?.(node, currentPath);\n }\n }}\n onDoubleClick={() => {\n if (!node.disabled) {\n onNodeDoubleClick?.(node, currentPath);\n }\n }}\n >\n {/* 左侧展开按钮 */}\n {togglePosition === 'left' && (\n <>\n {hasChildren ? (\n <button\n className={`tree-node-toggle btn btn-xs btn-ghost btn-circle ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n ) : (\n <span className=\"tree-node-toggle-placeholder\" style={{ width: '1.5rem', height: '1.5rem', flexShrink: 0 }}></span>\n )}\n </>\n )}\n\n {/* 节点图标 */}\n {showIcon && (\n <span className=\"tree-node-icon\">{node.icon || defaultIconEl}</span>\n )}\n\n {/* 节点标签 */}\n <span className=\"tree-node-label text-sm truncate flex-1\" title={node.label}>\n {node.label}\n </span>\n\n {/* 子节点数量 */}\n {hasChildren && showCount && (\n <span className=\"tree-node-count text-xs opacity-60\">\n ({node.children!.length})\n </span>\n )}\n\n {/* 右侧展开按钮 */}\n {togglePosition === 'right' && hasChildren && (\n <button\n className={`tree-node-toggle tree-node-toggle-right btn btn-xs btn-ghost ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n )}\n </div>\n\n {/* 子节点 */}\n {hasChildren && (\n <div\n className={`tree-node-children ${isExpanded ? 'tree-node-children-expanded' : 'tree-node-children-collapsed'}`}\n >\n {node.children!.map((child) => renderTreeNode(child, depth + 1, currentPath))}\n </div>\n )}\n </div>\n );\n\n // 自定义渲染\n if (renderNode) {\n return renderNode(node, nodeContent);\n }\n\n return nodeContent;\n },\n [\n expandedIds,\n activeNodeId,\n indent,\n showIcon,\n showCount,\n togglePosition,\n defaultExpandIconEl,\n defaultCollapseIconEl,\n defaultIconEl,\n onNodeClick,\n onNodeDoubleClick,\n toggleNode,\n renderNode,\n ]\n );\n\n return (\n <div className={`tree-component bg-base-100 border border-base-300 rounded-lg p-2 ${className}`}>\n {/* 标题 */}\n {title && (\n <div className=\"tree-header flex items-center gap-2 px-2 py-1 mb-2 border-b border-base-300\">\n {titleIcon}\n <span className=\"font-semibold\">{title}</span>\n {showCount && (\n <span className=\"text-xs opacity-60 ml-auto\">({totalCount})</span>\n )}\n </div>\n )}\n\n {/* 搜索框 */}\n {showSearch && (\n <input\n type=\"text\"\n placeholder={searchPlaceholder}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"tree-search input input-sm input-bordered w-full mb-2\"\n />\n )}\n\n {/* 操作按钮 */}\n {showExpandAll && (\n <div className=\"tree-actions flex gap-1 mb-2\">\n <button className=\"btn btn-xs btn-ghost\" onClick={expandAll}>\n {expandAllText}\n </button>\n <button className=\"btn btn-xs btn-ghost\" onClick={collapseAll}>\n {collapseAllText}\n </button>\n </div>\n )}\n\n {/* 树形列表 */}\n <div\n className=\"tree-content overflow-y-auto\"\n style={{ maxHeight }}\n >\n {filteredData.length === 0 ? (\n <div className=\"tree-empty text-center text-sm opacity-60 py-4\">\n {searchQuery ? noResultsText : emptyText}\n </div>\n ) : (\n <div className={`tree-nodes ${showLine ? 'tree-show-line' : ''}`}>\n {filteredData.map((node) => renderTreeNode(node))}\n </div>\n )}\n </div>\n\n <style>{`\n .tree-node {\n user-select: none;\n }\n \n /* 子节点容器基础样式 */\n .tree-node-children {\n margin-top: 2px;\n overflow: hidden;\n transform-origin: top;\n box-sizing: border-box;\n }\n \n /* 折叠状态 - 初始隐藏 */\n .tree-node-children-collapsed {\n max-height: 0;\n opacity: 0;\n transform: scaleY(0.8);\n border-left: none !important;\n }\n \n /* 展开状态 - 显示内容 */\n .tree-node-children-expanded {\n max-height: 5000px;\n opacity: 1;\n transform: scaleY(1);\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n /* 不对 border 做动画 */\n box-sizing: border-box;\n }\n \n /* 连接线样式 - 在展开状态显示,使用多重选择器提高优先级 */\n .tree-component .tree-show-line .tree-node-children-expanded,\n .tree-show-line .tree-node-children.tree-node-children-expanded {\n border-left: 1px solid var(--fallback-bc, oklch(var(--bc) / 0.2)) !important;\n margin-left: 8px !important;\n padding-left: 8px !important;\n position: relative;\n }\n \n /* 左侧连接线圆点装饰 */\n .tree-show-line .tree-node-children-expanded::before {\n content: '';\n position: absolute;\n left: -3px;\n top: 0;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--fallback-bc, oklch(var(--bc) / 0.3));\n }\n \n /* 折叠过渡 */\n .tree-node-children-collapsed {\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 展开/折叠按钮图标旋转动画 */\n .tree-node-toggle {\n z-index: 2;\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .tree-node-toggle svg {\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 折叠状态的图标 - 向右 */\n .tree-node-toggle:not(.tree-node-toggle-expanded) svg {\n transform: rotate(0deg);\n }\n \n /* 展开状态的图标 - 向下(已经是向下的,所以不需要额外旋转) */\n .tree-node-toggle-expanded svg {\n transform: rotate(0deg);\n }\n \n .tree-component {\n position: relative;\n z-index: 1;\n }\n \n .tree-node-disabled {\n cursor: not-allowed;\n }\n \n .tree-node-disabled .tree-node-content {\n pointer-events: none;\n }\n \n /* 节点内容悬停效果 */\n .tree-node-content {\n transition: background-color 0.15s ease;\n }\n \n /* 优化性能 - 告诉浏览器这些属性会变化 */\n .tree-node-children {\n will-change: max-height, opacity, transform;\n }\n \n /* 动画完成后移除 will-change 以节省资源 */\n .tree-node-children-expanded,\n .tree-node-children-collapsed {\n animation: remove-will-change 0.3s forwards;\n }\n \n @keyframes remove-will-change {\n to {\n will-change: auto;\n }\n }\n \n /* 活跃节点基础样式 */\n .tree-node-content-active {\n font-weight: 600 !important;\n padding-left: calc(0.5rem - 4px) !important;\n border-radius: 0.375rem !important;\n }\n \n /* 主题活跃状态样式 - 从共用配置生成 */\n ${generateTreeActiveStyles()}\n \n /* 非活跃节点的悬停状态 */\n .tree-node-content-inactive:hover {\n background-color: oklch(var(--b2));\n }\n `}</style>\n </div>\n );\n};\n\nexport default Tree;\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tree.js","names":[],"sources":["../../../src/components/Tree/Tree.tsx"],"sourcesContent":["import React, { useState, useCallback, useMemo } from 'react';\nimport { generateTreeActiveStyles } from '../../styles/themeStyles';\n\n// ============= 类型定义 =============\n\nexport interface TreeNode {\n id: string | number;\n label: string;\n children?: TreeNode[];\n icon?: React.ReactNode;\n disabled?: boolean;\n meta?: Record<string, any>;\n}\n\nexport interface TreeProps {\n /** 树形数据 */\n data: TreeNode[];\n\n /** 节点点击回调 */\n onNodeClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点双击回调 */\n onNodeDoubleClick?: (node: TreeNode, path: (string | number)[]) => void;\n\n /** 节点展开/折叠回调 */\n onNodeToggle?: (nodeId: string | number, expanded: boolean) => void;\n\n /** 当前激活的节点 ID */\n activeNodeId?: string | number;\n\n /** 默认展开的节点 ID 列表 */\n defaultExpandedIds?: (string | number)[];\n\n /** 是否显示搜索框 */\n showSearch?: boolean;\n\n /** 搜索占位符 */\n searchPlaceholder?: string;\n\n /** 是否显示展开/折叠全部按钮 */\n showExpandAll?: boolean;\n\n /** 展开全部按钮文本 */\n expandAllText?: string;\n\n /** 折叠全部按钮文本 */\n collapseAllText?: string;\n\n /** 是否显示节点图标 */\n showIcon?: boolean;\n\n /** 默认图标 */\n defaultIcon?: React.ReactNode;\n\n /** 展开图标 */\n expandIcon?: React.ReactNode;\n\n /** 折叠图标 */\n collapseIcon?: React.ReactNode;\n\n /** 是否显示连接线 */\n showLine?: boolean;\n\n /** 最大高度 */\n maxHeight?: string;\n\n /** 自定义类名 */\n className?: string;\n\n /** 标题 */\n title?: string;\n\n /** 标题图标 */\n titleIcon?: React.ReactNode;\n\n /** 是否显示节点数量 */\n showCount?: boolean;\n\n /** 空状态文本 */\n emptyText?: string;\n\n /** 搜索无结果文本 */\n noResultsText?: string;\n\n /** 缩进宽度(像素) */\n indent?: number;\n\n /** 展开按钮位置:left(左侧)或 right(右侧) */\n togglePosition?: 'left' | 'right';\n\n /** 是否可拖拽(暂不实现) */\n draggable?: boolean;\n\n /** 是否可选择(暂不实现) */\n checkable?: boolean;\n\n /** 自定义渲染节点 */\n renderNode?: (node: TreeNode, defaultRender: React.ReactNode) => React.ReactNode;\n}\n\n// ============= Tree 组件 =============\n\nconst Tree: React.FC<TreeProps> = ({\n data,\n onNodeClick,\n onNodeDoubleClick,\n onNodeToggle,\n activeNodeId,\n defaultExpandedIds = [],\n showSearch = true,\n searchPlaceholder = 'Search...',\n showExpandAll = true,\n expandAllText = 'Expand All',\n collapseAllText = 'Collapse All',\n showIcon = true,\n defaultIcon,\n expandIcon,\n collapseIcon,\n showLine = false,\n maxHeight = '600px',\n className = '',\n title,\n titleIcon,\n showCount = true,\n emptyText = 'No data',\n noResultsText = 'No results found',\n indent = 16,\n togglePosition = 'left',\n renderNode,\n}) => {\n const [searchQuery, setSearchQuery] = useState('');\n const [expandedIds, setExpandedIds] = useState<Set<string | number>>(\n new Set(defaultExpandedIds)\n );\n\n // 当 defaultExpandedIds 变化时,同步更新 expandedIds(用于异步加载的数据)\n React.useEffect(() => {\n if (defaultExpandedIds.length > 0) {\n setExpandedIds(prev => {\n const newSet = new Set(prev);\n defaultExpandedIds.forEach(id => newSet.add(id));\n return newSet;\n });\n }\n }, [defaultExpandedIds]);\n\n // 默认展开/折叠图标\n const defaultExpandIconEl = expandIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M19 9l-7 7-7-7\" />\n </svg>\n );\n\n const defaultCollapseIconEl = collapseIcon || (\n <svg className=\"w-3 h-3\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" strokeWidth={2} d=\"M9 5l7 7-7 7\" />\n </svg>\n );\n\n // 默认节点图标\n const defaultIconEl = defaultIcon || (\n <svg className=\"w-4 h-4\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n );\n\n // 统计节点总数\n const countNodes = useCallback((nodes: TreeNode[]): number => {\n return nodes.reduce((count, node) => {\n return count + 1 + (node.children ? countNodes(node.children) : 0);\n }, 0);\n }, []);\n\n const totalCount = useMemo(() => countNodes(data), [data, countNodes]);\n\n // 过滤节点(支持搜索)\n const filterNodes = useCallback((nodes: TreeNode[], query: string): TreeNode[] => {\n if (!query) return nodes;\n\n const lowerQuery = query.toLowerCase();\n const filtered: TreeNode[] = [];\n\n for (const node of nodes) {\n const matches = node.label.toLowerCase().includes(lowerQuery);\n const filteredChildren = node.children ? filterNodes(node.children, query) : [];\n\n if (matches || filteredChildren.length > 0) {\n filtered.push({\n ...node,\n children: filteredChildren.length > 0 ? filteredChildren : node.children,\n });\n }\n }\n\n return filtered;\n }, []);\n\n const filteredData = useMemo(\n () => filterNodes(data, searchQuery),\n [data, searchQuery, filterNodes]\n );\n\n // 切换节点展开/折叠\n const toggleNode = useCallback(\n (nodeId: string | number) => {\n const newExpanded = new Set(expandedIds);\n if (newExpanded.has(nodeId)) {\n newExpanded.delete(nodeId);\n onNodeToggle?.(nodeId, false);\n } else {\n newExpanded.add(nodeId);\n onNodeToggle?.(nodeId, true);\n }\n setExpandedIds(newExpanded);\n },\n [expandedIds, onNodeToggle]\n );\n\n // 展开所有节点\n const expandAll = useCallback(() => {\n const allIds = new Set<string | number>();\n const collectIds = (nodes: TreeNode[]) => {\n nodes.forEach((node) => {\n if (node.children && node.children.length > 0) {\n allIds.add(node.id);\n collectIds(node.children);\n }\n });\n };\n collectIds(data);\n setExpandedIds(allIds);\n }, [data]);\n\n // 折叠所有节点\n const collapseAll = useCallback(() => {\n setExpandedIds(new Set());\n }, []);\n\n // 渲染单个节点\n const renderTreeNode = useCallback(\n (node: TreeNode, depth: number = 0, path: (string | number)[] = []) => {\n const hasChildren = node.children && node.children.length > 0;\n const isExpanded = expandedIds.has(node.id);\n const isActive = activeNodeId === node.id;\n const currentPath = [...path, node.id];\n\n const nodeContent = (\n <div\n key={node.id}\n data-node-id={node.id}\n className={`tree-node ${isActive ? 'tree-node-active' : ''} ${node.disabled ? 'tree-node-disabled' : ''\n }`}\n style={{\n paddingLeft: `${depth * indent}px`,\n }}\n >\n <div\n className={`tree-node-content flex items-center gap-2 px-2 py-1.5 rounded cursor-pointer transition-colors ${isActive ? 'tree-node-content-active' : 'tree-node-content-inactive'\n } ${node.disabled ? 'opacity-50 cursor-not-allowed' : ''}`}\n onClick={() => {\n if (!node.disabled) {\n onNodeClick?.(node, currentPath);\n }\n }}\n onDoubleClick={() => {\n if (!node.disabled) {\n onNodeDoubleClick?.(node, currentPath);\n }\n }}\n >\n {/* 左侧展开按钮 */}\n {togglePosition === 'left' && (\n <>\n {hasChildren ? (\n <button\n className={`tree-node-toggle btn btn-xs btn-ghost btn-circle ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n ) : (\n <span className=\"tree-node-toggle-placeholder\" style={{ width: '1.5rem', height: '1.5rem', flexShrink: 0 }}></span>\n )}\n </>\n )}\n\n {/* 节点图标 */}\n {showIcon && (\n <span className=\"tree-node-icon\">{node.icon || defaultIconEl}</span>\n )}\n\n {/* 节点标签 */}\n <span className=\"tree-node-label text-sm truncate flex-1\" title={node.label}>\n {node.label}\n </span>\n\n {/* 子节点数量(优先使用 meta.count,否则回退到子节点个数) */}\n {node.meta?.count !== undefined && node.meta?.count !== null ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n {node.meta.count}\n </span>\n ) : hasChildren && showCount ? (\n <span className=\"tree-node-count text-xs opacity-60\">\n ({node.children!.length})\n </span>\n ) : null}\n\n {/* 右侧展开按钮 */}\n {togglePosition === 'right' && hasChildren && (\n <button\n className={`tree-node-toggle tree-node-toggle-right btn btn-xs btn-ghost ${isExpanded ? 'tree-node-toggle-expanded' : ''\n }`}\n onClick={(e) => {\n e.stopPropagation();\n if (!node.disabled) {\n toggleNode(node.id);\n }\n }}\n disabled={node.disabled}\n >\n {isExpanded ? defaultExpandIconEl : defaultCollapseIconEl}\n </button>\n )}\n </div>\n\n {/* 子节点 */}\n {hasChildren && (\n <div\n className={`tree-node-children ${isExpanded ? 'tree-node-children-expanded' : 'tree-node-children-collapsed'}`}\n >\n {node.children!.map((child) => renderTreeNode(child, depth + 1, currentPath))}\n </div>\n )}\n </div>\n );\n\n // 自定义渲染\n if (renderNode) {\n return renderNode(node, nodeContent);\n }\n\n return nodeContent;\n },\n [\n expandedIds,\n activeNodeId,\n indent,\n showIcon,\n showCount,\n togglePosition,\n defaultExpandIconEl,\n defaultCollapseIconEl,\n defaultIconEl,\n onNodeClick,\n onNodeDoubleClick,\n toggleNode,\n renderNode,\n ]\n );\n\n return (\n <div className={`tree-component bg-base-100 border border-base-300 rounded-lg p-2 ${className}`}>\n {/* 标题 */}\n {title && (\n <div className=\"tree-header flex items-center gap-2 px-2 py-1 mb-2 border-b border-base-300\">\n {titleIcon}\n <span className=\"font-semibold\">{title}</span>\n {showCount && (\n <span className=\"text-xs opacity-60 ml-auto\">({totalCount})</span>\n )}\n </div>\n )}\n\n {/* 搜索框 */}\n {showSearch && (\n <input\n type=\"text\"\n placeholder={searchPlaceholder}\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"tree-search input input-sm input-bordered w-full mb-2\"\n />\n )}\n\n {/* 操作按钮 */}\n {showExpandAll && (\n <div className=\"tree-actions flex gap-1 mb-2\">\n <button className=\"btn btn-xs btn-ghost\" onClick={expandAll}>\n {expandAllText}\n </button>\n <button className=\"btn btn-xs btn-ghost\" onClick={collapseAll}>\n {collapseAllText}\n </button>\n </div>\n )}\n\n {/* 树形列表 */}\n <div\n className=\"tree-content overflow-y-auto\"\n style={{ maxHeight }}\n >\n {filteredData.length === 0 ? (\n <div className=\"tree-empty text-center text-sm opacity-60 py-4\">\n {searchQuery ? noResultsText : emptyText}\n </div>\n ) : (\n <div className={`tree-nodes ${showLine ? 'tree-show-line' : ''}`}>\n {filteredData.map((node) => renderTreeNode(node))}\n </div>\n )}\n </div>\n\n <style>{`\n .tree-node {\n user-select: none;\n }\n \n /* 子节点容器基础样式 */\n .tree-node-children {\n margin-top: 2px;\n overflow: hidden;\n transform-origin: top;\n box-sizing: border-box;\n }\n \n /* 折叠状态 - 初始隐藏 */\n .tree-node-children-collapsed {\n max-height: 0;\n opacity: 0;\n transform: scaleY(0.8);\n border-left: none !important;\n }\n \n /* 展开状态 - 显示内容 */\n .tree-node-children-expanded {\n max-height: 5000px;\n opacity: 1;\n transform: scaleY(1);\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n /* 不对 border 做动画 */\n box-sizing: border-box;\n }\n \n /* 连接线样式 - 在展开状态显示,使用多重选择器提高优先级 */\n .tree-component .tree-show-line .tree-node-children-expanded,\n .tree-show-line .tree-node-children.tree-node-children-expanded {\n border-left: 1px solid var(--fallback-bc, oklch(var(--bc) / 0.2)) !important;\n margin-left: 8px !important;\n padding-left: 8px !important;\n position: relative;\n }\n \n /* 左侧连接线圆点装饰 */\n .tree-show-line .tree-node-children-expanded::before {\n content: '';\n position: absolute;\n left: -3px;\n top: 0;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background-color: var(--fallback-bc, oklch(var(--bc) / 0.3));\n }\n \n /* 折叠过渡 */\n .tree-node-children-collapsed {\n transition: \n max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),\n opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),\n transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 展开/折叠按钮图标旋转动画 */\n .tree-node-toggle {\n z-index: 2;\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n .tree-node-toggle svg {\n transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);\n }\n \n /* 折叠状态的图标 - 向右 */\n .tree-node-toggle:not(.tree-node-toggle-expanded) svg {\n transform: rotate(0deg);\n }\n \n /* 展开状态的图标 - 向下(已经是向下的,所以不需要额外旋转) */\n .tree-node-toggle-expanded svg {\n transform: rotate(0deg);\n }\n \n .tree-component {\n position: relative;\n z-index: 1;\n }\n \n .tree-node-disabled {\n cursor: not-allowed;\n }\n \n .tree-node-disabled .tree-node-content {\n pointer-events: none;\n }\n \n /* 节点内容悬停效果 */\n .tree-node-content {\n transition: background-color 0.15s ease;\n }\n \n /* 优化性能 - 告诉浏览器这些属性会变化 */\n .tree-node-children {\n will-change: max-height, opacity, transform;\n }\n \n /* 动画完成后移除 will-change 以节省资源 */\n .tree-node-children-expanded,\n .tree-node-children-collapsed {\n animation: remove-will-change 0.3s forwards;\n }\n \n @keyframes remove-will-change {\n to {\n will-change: auto;\n }\n }\n \n /* 活跃节点基础样式 */\n .tree-node-content-active {\n font-weight: 600 !important;\n padding-left: calc(0.5rem - 4px) !important;\n border-radius: 0.375rem !important;\n }\n \n /* 主题活跃状态样式 - 从共用配置生成 */\n ${generateTreeActiveStyles()}\n \n /* 非活跃节点的悬停状态 */\n .tree-node-content-inactive:hover {\n background-color: oklch(var(--b2));\n }\n `}</style>\n </div>\n );\n};\n\nexport default Tree;\n\n"],"mappings":"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"}