dishui 0.0.50 → 0.0.54

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.
@@ -21,6 +21,8 @@ export type ButtonProps = {
21
21
  leftSection?: React.ReactNode;
22
22
  rightSection?: React.ReactNode;
23
23
  onClick?: () => void;
24
+ /** 原生 button type;不传时保持浏览器默认行为(表单内默认 submit) */
25
+ type?: 'button' | 'submit' | 'reset';
24
26
  className?: string;
25
27
  states?: ButtonState[];
26
28
  initialStateIndex?: number;
@@ -1,10 +1,10 @@
1
- import $, { useCallback as A, useState as E } from "react";
2
- import { Fragment as D, jsx as b, jsxs as I } from "react/jsx-runtime";
3
- var H = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1, dash: j = !1, soft: s = !1, active: v = !1, disabled: o = !1, wide: r = !1, block: h = !1, square: C = !1, circle: N = !1, leftSection: e, rightSection: l, onClick: i, className: g = "", states: c, initialStateIndex: R = 0, onStateChange: x }) => {
4
- const [B, V] = E(R), [k, q] = E(0), n = c && c.length > 0, m = n ? c[B] : null, L = A(() => {
1
+ import $, { useCallback as D, useState as E } from "react";
2
+ import { Fragment as H, jsx as b, jsxs as I } from "react/jsx-runtime";
3
+ var J = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1, dash: j = !1, soft: s = !1, active: v = !1, disabled: o = !1, wide: r = !1, block: h = !1, square: C = !1, circle: N = !1, leftSection: e, rightSection: l, onClick: i, type: g, className: R = "", states: c, initialStateIndex: V = 0, onStateChange: x }) => {
4
+ const [B, q] = E(V), [k, L] = E(0), n = c && c.length > 0, m = n ? c[B] : null, W = D(() => {
5
5
  if (n) {
6
- const G = k + 1, u = (B + 1) % c.length, z = c[u];
7
- q(G), V(u), x && x(z, G, u);
6
+ const G = k + 1, u = (B + 1) % c.length, A = c[u];
7
+ L(G), q(u), x && x(A, G, u);
8
8
  }
9
9
  i && i();
10
10
  }, [
@@ -14,11 +14,12 @@ var H = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1,
14
14
  k,
15
15
  x,
16
16
  i
17
- ]), w = m?.variant || a, W = n ? /* @__PURE__ */ I(D, { children: [m?.icon && /* @__PURE__ */ b("span", {
17
+ ]), w = m?.variant || a, z = n ? /* @__PURE__ */ I(H, { children: [m?.icon && /* @__PURE__ */ b("span", {
18
18
  className: "mr-1",
19
19
  children: m.icon
20
20
  }), m?.label] }) : f;
21
21
  return /* @__PURE__ */ I("button", {
22
+ type: g,
22
23
  className: [
23
24
  "btn",
24
25
  w ? `btn-${w}` : "",
@@ -31,24 +32,24 @@ var H = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1,
31
32
  h ? "btn-block" : "",
32
33
  C ? "btn-square" : "",
33
34
  N ? "btn-circle" : "",
34
- g
35
+ R
35
36
  ].filter(Boolean).join(" "),
36
37
  disabled: o,
37
- onClick: L,
38
+ onClick: W,
38
39
  title: n ? `当前状态: ${m?.key} (点击次数: ${k})` : void 0,
39
40
  children: [
40
41
  !n && e && /* @__PURE__ */ b("span", {
41
42
  className: "mr-2",
42
43
  children: e
43
44
  }),
44
- W,
45
+ z,
45
46
  !n && l && /* @__PURE__ */ b("span", {
46
47
  className: "ml-2",
47
48
  children: l
48
49
  })
49
50
  ]
50
51
  });
51
- }, J = ({ children: f, vertical: a = !1, className: p = "", rounded: t = "none", radius: j = "full", roundedStyle: s }) => {
52
+ }, K = ({ children: f, vertical: a = !1, className: p = "", rounded: t = "none", radius: j = "full", roundedStyle: s }) => {
52
53
  const v = [
53
54
  "join",
54
55
  a ? "join-vertical" : "join-horizontal",
@@ -65,7 +66,7 @@ var H = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1,
65
66
  return $.cloneElement(C, { className: g });
66
67
  })
67
68
  });
68
- }, K = ({ children: f, className: a = "" }) => /* @__PURE__ */ b("div", {
69
+ }, M = ({ children: f, className: a = "" }) => /* @__PURE__ */ b("div", {
69
70
  className: [
70
71
  "join-item",
71
72
  "flex",
@@ -77,9 +78,9 @@ var H = ({ children: f, variant: a = "primary", size: p = "sm", outline: t = !1,
77
78
  a
78
79
  ].filter(Boolean).join(" "),
79
80
  children: f
80
- }), F = H;
81
- F.Group = J;
82
- F.GroupSection = K;
81
+ }), F = J;
82
+ F.Group = K;
83
+ F.GroupSection = M;
83
84
  export {
84
85
  F as default
85
86
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Button/index.tsx"],"sourcesContent":["import React, { ReactElement, useState, useCallback } from 'react';\n\n// 状态项定义\nexport type ButtonState = {\n label: string; // 显示的字符/文本\n key: string; // 状态的唯一标识\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost' | 'link';\n icon?: React.ReactNode; // 可选的图标\n};\n\nexport type ButtonProps = {\n children?: React.ReactNode;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost' | 'link';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n outline?: boolean;\n dash?: boolean;\n soft?: boolean;\n active?: boolean;\n disabled?: boolean;\n wide?: boolean;\n block?: boolean;\n square?: boolean;\n circle?: boolean;\n leftSection?: React.ReactNode;\n rightSection?: React.ReactNode;\n onClick?: () => void;\n className?: string;\n\n // 状态切换相关\n states?: ButtonState[]; // 状态列表\n initialStateIndex?: number; // 初始状态索引\n onStateChange?: (state: ButtonState, clickCount: number, stateIndex: number) => void; // 状态改变回调\n};\n\nconst Button = ({\n children,\n variant = 'primary',\n size = 'sm',\n outline = false,\n dash = false,\n soft = false,\n active = false,\n disabled = false,\n wide = false,\n block = false,\n square = false,\n circle = false,\n leftSection,\n rightSection,\n onClick,\n className = '',\n states,\n initialStateIndex = 0,\n onStateChange,\n}: ButtonProps) => {\n // 状态管理\n const [currentStateIndex, setCurrentStateIndex] = useState(initialStateIndex);\n const [clickCount, setClickCount] = useState(0);\n\n // 是否是状态按钮\n const isStateful = states && states.length > 0;\n\n // 获取当前状态\n const currentState = isStateful ? states[currentStateIndex] : null;\n\n // 处理点击\n const handleClick = useCallback(() => {\n if (isStateful) {\n const newClickCount = clickCount + 1;\n const newStateIndex = (currentStateIndex + 1) % states.length;\n const newState = states[newStateIndex];\n\n setClickCount(newClickCount);\n setCurrentStateIndex(newStateIndex);\n\n // 调用状态改变回调\n if (onStateChange) {\n onStateChange(newState, newClickCount, newStateIndex);\n }\n }\n\n // 调用原始 onClick\n if (onClick) {\n onClick();\n }\n }, [isStateful, states, currentStateIndex, clickCount, onStateChange, onClick]);\n\n // 确定使用的 variant\n const effectiveVariant = currentState?.variant || variant;\n\n // 确定显示的内容\n const displayContent = isStateful ? (\n <>\n {currentState?.icon && <span className=\"mr-1\">{currentState.icon}</span>}\n {currentState?.label}\n </>\n ) : children;\n\n const baseClass = 'btn';\n const variantClass = effectiveVariant ? `btn-${effectiveVariant}` : '';\n const sizeClass = size ? `btn-${size}` : '';\n const outlineClass = outline ? 'btn-outline' : '';\n const dashClass = dash ? 'btn-dash' : '';\n const softClass = soft ? 'btn-soft' : '';\n const activeClass = active || isStateful ? 'btn-active' : '';\n const wideClass = wide ? 'btn-wide' : '';\n const blockClass = block ? 'btn-block' : '';\n const squareClass = square ? 'btn-square' : '';\n const circleClass = circle ? 'btn-circle' : '';\n\n const buttonClasses = [\n baseClass,\n variantClass,\n sizeClass,\n outlineClass,\n dashClass,\n softClass,\n activeClass,\n wideClass,\n blockClass,\n squareClass,\n circleClass,\n className\n ].filter(Boolean).join(' ');\n\n return (\n <button\n className={buttonClasses}\n disabled={disabled}\n onClick={handleClick}\n title={isStateful ? `当前状态: ${currentState?.key} (点击次数: ${clickCount})` : undefined}\n >\n {!isStateful && leftSection && <span className=\"mr-2\">{leftSection}</span>}\n {displayContent}\n {!isStateful && rightSection && <span className=\"ml-2\">{rightSection}</span>}\n </button>\n );\n};\n\n// Button.Group 组件\nexport type ButtonGroupProps = {\n children: React.ReactNode;\n vertical?: boolean;\n className?: string;\n rounded?: 'left' | 'right' | 'both' | 'none' | 'top' | 'bottom';\n radius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';\n roundedStyle?: {\n left?: string;\n right?: string;\n top?: string;\n bottom?: string;\n };\n};\n\nconst ButtonGroup = ({\n children,\n vertical = false,\n className = '',\n rounded = 'none',\n radius = 'full',\n roundedStyle,\n}: ButtonGroupProps) => {\n const joinClasses = [\n 'join',\n vertical ? 'join-vertical' : 'join-horizontal',\n className\n ].filter(Boolean).join(' ');\n\n // 当rounded不为'none'时,强制使用'full'作为radius值\n const effectiveRadius = rounded !== 'none' ? 'full' : radius;\n\n return (\n <div className={joinClasses}>\n {React.Children.map(children, (child, index) => {\n // 只处理有效的React元素\n if (!React.isValidElement(child)) return child;\n\n const childElement = child as ReactElement<{ className?: string }>;\n const childClassName = childElement.props.className || '';\n const isFirstChild = index === 0;\n const isLastChild = index === React.Children.count(children) - 1;\n\n // 根据rounded属性添加额外的圆角类\n let roundedClasses = '';\n\n if (roundedStyle) {\n // 使用自定义圆角样式\n if (vertical) {\n if ((rounded === 'left' || rounded === 'top') && isFirstChild && roundedStyle.top) {\n roundedClasses = roundedStyle.top;\n } else if ((rounded === 'right' || rounded === 'bottom') && isLastChild && roundedStyle.bottom) {\n roundedClasses = roundedStyle.bottom;\n } else if (rounded === 'both') {\n if (isFirstChild && roundedStyle.top) roundedClasses = roundedStyle.top;\n if (isLastChild && roundedStyle.bottom) roundedClasses = roundedStyle.bottom;\n }\n } else {\n if ((rounded === 'left' || rounded === 'top') && isFirstChild && roundedStyle.left) {\n roundedClasses = roundedStyle.left;\n } else if ((rounded === 'right' || rounded === 'bottom') && isLastChild && roundedStyle.right) {\n roundedClasses = roundedStyle.right;\n } else if (rounded === 'both') {\n if (isFirstChild && roundedStyle.left) roundedClasses = roundedStyle.left;\n if (isLastChild && roundedStyle.right) roundedClasses = roundedStyle.right;\n }\n }\n } else {\n // 使用默认的圆角大小\n if (vertical) {\n // 垂直布局时,圆角应用在上下方\n if (rounded === 'left' || rounded === 'top') {\n if (isFirstChild) roundedClasses = `rounded-t-${effectiveRadius}`;\n } else if (rounded === 'right' || rounded === 'bottom') {\n if (isLastChild) roundedClasses = `rounded-b-${effectiveRadius}`;\n } else if (rounded === 'both') {\n if (isFirstChild) roundedClasses = `rounded-t-${effectiveRadius}`;\n if (isLastChild) roundedClasses = `rounded-b-${effectiveRadius}`;\n }\n } else {\n // 水平布局时,圆角应用在左右方\n if (rounded === 'left' || rounded === 'top') {\n if (isFirstChild) roundedClasses = `rounded-l-${effectiveRadius}`;\n } else if (rounded === 'right' || rounded === 'bottom') {\n if (isLastChild) roundedClasses = `rounded-r-${effectiveRadius}`;\n } else if (rounded === 'both') {\n if (isFirstChild) roundedClasses = `rounded-l-${effectiveRadius}`;\n if (isLastChild) roundedClasses = `rounded-r-${effectiveRadius}`;\n }\n }\n }\n\n const newClassName = `${childClassName} join-item ${roundedClasses}`.trim();\n\n return React.cloneElement(childElement, {\n className: newClassName,\n });\n })}\n </div>\n );\n};\n\n// Button.GroupSection 组件\nexport type ButtonGroupSectionProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ButtonGroupSection = ({\n children,\n className = '',\n}: ButtonGroupSectionProps) => {\n const sectionClasses = [\n 'join-item',\n 'flex',\n 'items-center',\n 'px-4',\n 'bg-base-200',\n 'border',\n 'border-base-300',\n className\n ].filter(Boolean).join(' ');\n\n return (\n <div className={sectionClasses}>\n {children}\n </div>\n );\n};\n\n// 扩展Button组件,添加Group和GroupSection子组件\ninterface ButtonCompound extends React.FC<ButtonProps> {\n Group: React.FC<ButtonGroupProps>;\n GroupSection: React.FC<ButtonGroupSectionProps>;\n}\n\nconst ButtonWithCompounds = Button as ButtonCompound;\nButtonWithCompounds.Group = ButtonGroup;\nButtonWithCompounds.GroupSection = ButtonGroupSection;\n\nexport default ButtonWithCompounds; "],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Button/index.tsx"],"sourcesContent":["import React, { ReactElement, useState, useCallback } from 'react';\n\n// 状态项定义\nexport type ButtonState = {\n label: string; // 显示的字符/文本\n key: string; // 状态的唯一标识\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost' | 'link';\n icon?: React.ReactNode; // 可选的图标\n};\n\nexport type ButtonProps = {\n children?: React.ReactNode;\n variant?: 'neutral' | 'primary' | 'secondary' | 'accent' | 'info' | 'success' | 'warning' | 'error' | 'ghost' | 'link';\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n outline?: boolean;\n dash?: boolean;\n soft?: boolean;\n active?: boolean;\n disabled?: boolean;\n wide?: boolean;\n block?: boolean;\n square?: boolean;\n circle?: boolean;\n leftSection?: React.ReactNode;\n rightSection?: React.ReactNode;\n onClick?: () => void;\n /** 原生 button type;不传时保持浏览器默认行为(表单内默认 submit) */\n type?: 'button' | 'submit' | 'reset';\n className?: string;\n\n // 状态切换相关\n states?: ButtonState[]; // 状态列表\n initialStateIndex?: number; // 初始状态索引\n onStateChange?: (state: ButtonState, clickCount: number, stateIndex: number) => void; // 状态改变回调\n};\n\nconst Button = ({\n children,\n variant = 'primary',\n size = 'sm',\n outline = false,\n dash = false,\n soft = false,\n active = false,\n disabled = false,\n wide = false,\n block = false,\n square = false,\n circle = false,\n leftSection,\n rightSection,\n onClick,\n type,\n className = '',\n states,\n initialStateIndex = 0,\n onStateChange,\n}: ButtonProps) => {\n // 状态管理\n const [currentStateIndex, setCurrentStateIndex] = useState(initialStateIndex);\n const [clickCount, setClickCount] = useState(0);\n\n // 是否是状态按钮\n const isStateful = states && states.length > 0;\n\n // 获取当前状态\n const currentState = isStateful ? states[currentStateIndex] : null;\n\n // 处理点击\n const handleClick = useCallback(() => {\n if (isStateful) {\n const newClickCount = clickCount + 1;\n const newStateIndex = (currentStateIndex + 1) % states.length;\n const newState = states[newStateIndex];\n\n setClickCount(newClickCount);\n setCurrentStateIndex(newStateIndex);\n\n // 调用状态改变回调\n if (onStateChange) {\n onStateChange(newState, newClickCount, newStateIndex);\n }\n }\n\n // 调用原始 onClick\n if (onClick) {\n onClick();\n }\n }, [isStateful, states, currentStateIndex, clickCount, onStateChange, onClick]);\n\n // 确定使用的 variant\n const effectiveVariant = currentState?.variant || variant;\n\n // 确定显示的内容\n const displayContent = isStateful ? (\n <>\n {currentState?.icon && <span className=\"mr-1\">{currentState.icon}</span>}\n {currentState?.label}\n </>\n ) : children;\n\n const baseClass = 'btn';\n const variantClass = effectiveVariant ? `btn-${effectiveVariant}` : '';\n const sizeClass = size ? `btn-${size}` : '';\n const outlineClass = outline ? 'btn-outline' : '';\n const dashClass = dash ? 'btn-dash' : '';\n const softClass = soft ? 'btn-soft' : '';\n const activeClass = active || isStateful ? 'btn-active' : '';\n const wideClass = wide ? 'btn-wide' : '';\n const blockClass = block ? 'btn-block' : '';\n const squareClass = square ? 'btn-square' : '';\n const circleClass = circle ? 'btn-circle' : '';\n\n const buttonClasses = [\n baseClass,\n variantClass,\n sizeClass,\n outlineClass,\n dashClass,\n softClass,\n activeClass,\n wideClass,\n blockClass,\n squareClass,\n circleClass,\n className\n ].filter(Boolean).join(' ');\n\n return (\n <button\n type={type}\n className={buttonClasses}\n disabled={disabled}\n onClick={handleClick}\n title={isStateful ? `当前状态: ${currentState?.key} (点击次数: ${clickCount})` : undefined}\n >\n {!isStateful && leftSection && <span className=\"mr-2\">{leftSection}</span>}\n {displayContent}\n {!isStateful && rightSection && <span className=\"ml-2\">{rightSection}</span>}\n </button>\n );\n};\n\n// Button.Group 组件\nexport type ButtonGroupProps = {\n children: React.ReactNode;\n vertical?: boolean;\n className?: string;\n rounded?: 'left' | 'right' | 'both' | 'none' | 'top' | 'bottom';\n radius?: 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';\n roundedStyle?: {\n left?: string;\n right?: string;\n top?: string;\n bottom?: string;\n };\n};\n\nconst ButtonGroup = ({\n children,\n vertical = false,\n className = '',\n rounded = 'none',\n radius = 'full',\n roundedStyle,\n}: ButtonGroupProps) => {\n const joinClasses = [\n 'join',\n vertical ? 'join-vertical' : 'join-horizontal',\n className\n ].filter(Boolean).join(' ');\n\n // 当rounded不为'none'时,强制使用'full'作为radius值\n const effectiveRadius = rounded !== 'none' ? 'full' : radius;\n\n return (\n <div className={joinClasses}>\n {React.Children.map(children, (child, index) => {\n // 只处理有效的React元素\n if (!React.isValidElement(child)) return child;\n\n const childElement = child as ReactElement<{ className?: string }>;\n const childClassName = childElement.props.className || '';\n const isFirstChild = index === 0;\n const isLastChild = index === React.Children.count(children) - 1;\n\n // 根据rounded属性添加额外的圆角类\n let roundedClasses = '';\n\n if (roundedStyle) {\n // 使用自定义圆角样式\n if (vertical) {\n if ((rounded === 'left' || rounded === 'top') && isFirstChild && roundedStyle.top) {\n roundedClasses = roundedStyle.top;\n } else if ((rounded === 'right' || rounded === 'bottom') && isLastChild && roundedStyle.bottom) {\n roundedClasses = roundedStyle.bottom;\n } else if (rounded === 'both') {\n if (isFirstChild && roundedStyle.top) roundedClasses = roundedStyle.top;\n if (isLastChild && roundedStyle.bottom) roundedClasses = roundedStyle.bottom;\n }\n } else {\n if ((rounded === 'left' || rounded === 'top') && isFirstChild && roundedStyle.left) {\n roundedClasses = roundedStyle.left;\n } else if ((rounded === 'right' || rounded === 'bottom') && isLastChild && roundedStyle.right) {\n roundedClasses = roundedStyle.right;\n } else if (rounded === 'both') {\n if (isFirstChild && roundedStyle.left) roundedClasses = roundedStyle.left;\n if (isLastChild && roundedStyle.right) roundedClasses = roundedStyle.right;\n }\n }\n } else {\n // 使用默认的圆角大小\n if (vertical) {\n // 垂直布局时,圆角应用在上下方\n if (rounded === 'left' || rounded === 'top') {\n if (isFirstChild) roundedClasses = `rounded-t-${effectiveRadius}`;\n } else if (rounded === 'right' || rounded === 'bottom') {\n if (isLastChild) roundedClasses = `rounded-b-${effectiveRadius}`;\n } else if (rounded === 'both') {\n if (isFirstChild) roundedClasses = `rounded-t-${effectiveRadius}`;\n if (isLastChild) roundedClasses = `rounded-b-${effectiveRadius}`;\n }\n } else {\n // 水平布局时,圆角应用在左右方\n if (rounded === 'left' || rounded === 'top') {\n if (isFirstChild) roundedClasses = `rounded-l-${effectiveRadius}`;\n } else if (rounded === 'right' || rounded === 'bottom') {\n if (isLastChild) roundedClasses = `rounded-r-${effectiveRadius}`;\n } else if (rounded === 'both') {\n if (isFirstChild) roundedClasses = `rounded-l-${effectiveRadius}`;\n if (isLastChild) roundedClasses = `rounded-r-${effectiveRadius}`;\n }\n }\n }\n\n const newClassName = `${childClassName} join-item ${roundedClasses}`.trim();\n\n return React.cloneElement(childElement, {\n className: newClassName,\n });\n })}\n </div>\n );\n};\n\n// Button.GroupSection 组件\nexport type ButtonGroupSectionProps = {\n children: React.ReactNode;\n className?: string;\n};\n\nconst ButtonGroupSection = ({\n children,\n className = '',\n}: ButtonGroupSectionProps) => {\n const sectionClasses = [\n 'join-item',\n 'flex',\n 'items-center',\n 'px-4',\n 'bg-base-200',\n 'border',\n 'border-base-300',\n className\n ].filter(Boolean).join(' ');\n\n return (\n <div className={sectionClasses}>\n {children}\n </div>\n );\n};\n\n// 扩展Button组件,添加Group和GroupSection子组件\ninterface ButtonCompound extends React.FC<ButtonProps> {\n Group: React.FC<ButtonGroupProps>;\n GroupSection: React.FC<ButtonGroupSectionProps>;\n}\n\nconst ButtonWithCompounds = Button as ButtonCompound;\nButtonWithCompounds.Group = ButtonGroup;\nButtonWithCompounds.GroupSection = ButtonGroupSection;\n\nexport default ButtonWithCompounds; "],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ export type EmptyStateProps = {
3
+ /** 主图标(通常为 lucide 图标) */
4
+ icon?: React.ReactNode;
5
+ /** 主标题 */
6
+ title: React.ReactNode;
7
+ /** 补充说明 */
8
+ description?: React.ReactNode;
9
+ /** 底部操作(按钮等) */
10
+ action?: React.ReactNode;
11
+ className?: string;
12
+ };
13
+ /**
14
+ * 空状态:虚线边框卡片 + 图标 + 标题 + 说明,统一列表为空时的展示。
15
+ */
16
+ declare const EmptyState: ({ icon, title, description, action, className, }: EmptyStateProps) => React.JSX.Element;
17
+ export default EmptyState;
@@ -0,0 +1,28 @@
1
+ import "react";
2
+ import { jsx as e, jsxs as n } from "react/jsx-runtime";
3
+ var x = ({ icon: t, title: a, description: s, action: r, className: m = "" }) => /* @__PURE__ */ n("div", {
4
+ className: `flex flex-col items-center justify-center rounded-xl border border-dashed border-base-300 bg-base-200/50 py-16 text-center ${m}`.trim(),
5
+ children: [
6
+ t && /* @__PURE__ */ e("span", {
7
+ className: "mb-3 flex size-12 items-center justify-center rounded-full bg-base-content/5 text-base-content/40 [&>svg]:h-6 [&>svg]:w-6",
8
+ children: t
9
+ }),
10
+ /* @__PURE__ */ e("p", {
11
+ className: "text-sm font-medium text-base-content/80",
12
+ children: a
13
+ }),
14
+ s && /* @__PURE__ */ e("p", {
15
+ className: "mt-1 max-w-sm text-xs text-base-content/50",
16
+ children: s
17
+ }),
18
+ r && /* @__PURE__ */ e("div", {
19
+ className: "mt-4",
20
+ children: r
21
+ })
22
+ ]
23
+ });
24
+ export {
25
+ x as default
26
+ };
27
+
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/EmptyState/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type EmptyStateProps = {\n /** 主图标(通常为 lucide 图标) */\n icon?: React.ReactNode;\n /** 主标题 */\n title: React.ReactNode;\n /** 补充说明 */\n description?: React.ReactNode;\n /** 底部操作(按钮等) */\n action?: React.ReactNode;\n className?: string;\n};\n\n/**\n * 空状态:虚线边框卡片 + 图标 + 标题 + 说明,统一列表为空时的展示。\n */\nconst EmptyState = ({\n icon,\n title,\n description,\n action,\n className = '',\n}: EmptyStateProps) => {\n return (\n <div\n className={`flex flex-col items-center justify-center rounded-xl border border-dashed border-base-300 bg-base-200/50 py-16 text-center ${className}`.trim()}\n >\n {icon && (\n <span className=\"mb-3 flex size-12 items-center justify-center rounded-full bg-base-content/5 text-base-content/40 [&>svg]:h-6 [&>svg]:w-6\">\n {icon}\n </span>\n )}\n <p className=\"text-sm font-medium text-base-content/80\">{title}</p>\n {description && (\n <p className=\"mt-1 max-w-sm text-xs text-base-content/50\">{description}</p>\n )}\n {action && <div className=\"mt-4\">{action}</div>}\n </div>\n );\n};\n\nexport default EmptyState;\n"],"mappings":";;AAiBA,IAAM,IAAA,CAAc,EAChB,MAAA,GACA,OAAA,GACA,aAAA,GACA,QAAA,GACA,WAAA,IAAY,GAAA,MAGR,gBAAA,EAAC,OAAD;AAAA,EACI,WAAW,8HAA8H,CAAA,GAAY,KAAK;AAAA,YAD9J;AAAA,IAGK,KACG,gBAAA,EAAC,QAAD;AAAA,MAAM,WAAU;AAAA,gBACX;AAAA,IACC,CAAA;AAAA,IAEV,gBAAA,EAAC,KAAD;AAAA,MAAG,WAAU;AAAA,gBAA4C;AAAA,IAAS,CAAA;AAAA,IACjE,KACG,gBAAA,EAAC,KAAD;AAAA,MAAG,WAAU;AAAA,gBAA8C;AAAA,IAAe,CAAA;AAAA,IAE7E,KAAU,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAQ;AAAA,IAAY,CAAA;AAAA,EAC7C"}
@@ -0,0 +1,27 @@
1
+ import React from 'react';
2
+ export type ModalProps = {
3
+ /** 是否打开 */
4
+ open: boolean;
5
+ /** 关闭回调(遮罩点击 / Esc / 关闭按钮触发) */
6
+ onClose: () => void;
7
+ /** 标题 */
8
+ title?: React.ReactNode;
9
+ /** 标题下的说明文字 */
10
+ description?: React.ReactNode;
11
+ /** 正文内容 */
12
+ children?: React.ReactNode;
13
+ /** 底部操作区(默认右对齐) */
14
+ footer?: React.ReactNode;
15
+ /** 尺寸 */
16
+ size?: 'sm' | 'md' | 'lg';
17
+ /** 点击遮罩是否关闭(默认 true) */
18
+ closeOnOverlay?: boolean;
19
+ /** 是否显示右上角关闭按钮(默认 true) */
20
+ showClose?: boolean;
21
+ className?: string;
22
+ };
23
+ /**
24
+ * 轻量模态框:遮罩 + 居中面板,支持 Esc 关闭、遮罩点击关闭与滚动锁定。
25
+ */
26
+ declare const Modal: ({ open, onClose, title, description, children, footer, size, closeOnOverlay, showClose, className, }: ModalProps) => React.JSX.Element | null;
27
+ export default Modal;
@@ -0,0 +1,73 @@
1
+ import { useEffect as x } from "react";
2
+ import { jsx as e, jsxs as r } from "react/jsx-runtime";
3
+ var f = {
4
+ sm: "max-w-sm",
5
+ md: "max-w-lg",
6
+ lg: "max-w-2xl"
7
+ }, p = ({ open: a, onClose: t, title: s, description: n, children: i, footer: o, size: c = "md", closeOnOverlay: m = !0, showClose: d = !0, className: u = "" }) => (x(() => {
8
+ if (!a) return;
9
+ const l = (v) => {
10
+ v.key === "Escape" && t();
11
+ };
12
+ window.addEventListener("keydown", l);
13
+ const b = document.body.style.overflow;
14
+ return document.body.style.overflow = "hidden", () => {
15
+ window.removeEventListener("keydown", l), document.body.style.overflow = b;
16
+ };
17
+ }, [a, t]), a ? /* @__PURE__ */ r("div", {
18
+ className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",
19
+ children: [/* @__PURE__ */ e("div", {
20
+ className: "absolute inset-0",
21
+ onClick: m ? t : void 0,
22
+ "aria-hidden": !0
23
+ }), /* @__PURE__ */ r("div", {
24
+ role: "dialog",
25
+ "aria-modal": "true",
26
+ className: `card relative w-full bg-base-100 shadow-xl ${f[c]} ${u}`.trim(),
27
+ children: [
28
+ (s || d) && /* @__PURE__ */ r("div", {
29
+ className: "flex items-start justify-between gap-3 border-b border-base-300 px-5 py-3.5",
30
+ children: [/* @__PURE__ */ r("div", {
31
+ className: "min-w-0",
32
+ children: [s && /* @__PURE__ */ e("h3", {
33
+ className: "truncate text-sm font-semibold text-base-content",
34
+ children: s
35
+ }), n && /* @__PURE__ */ e("p", {
36
+ className: "mt-0.5 text-xs text-base-content/60",
37
+ children: n
38
+ })]
39
+ }), d && /* @__PURE__ */ e("button", {
40
+ type: "button",
41
+ onClick: t,
42
+ "aria-label": "Close",
43
+ className: "shrink-0 rounded-md p-1 text-base-content/50 transition-colors hover:bg-base-200 hover:text-base-content",
44
+ children: /* @__PURE__ */ e("svg", {
45
+ className: "h-4 w-4",
46
+ fill: "none",
47
+ viewBox: "0 0 24 24",
48
+ stroke: "currentColor",
49
+ strokeWidth: 2,
50
+ children: /* @__PURE__ */ e("path", {
51
+ strokeLinecap: "round",
52
+ strokeLinejoin: "round",
53
+ d: "M6 18L18 6M6 6l12 12"
54
+ })
55
+ })
56
+ })]
57
+ }),
58
+ /* @__PURE__ */ e("div", {
59
+ className: "max-h-[70vh] overflow-y-auto px-5 py-4",
60
+ children: i
61
+ }),
62
+ o && /* @__PURE__ */ e("div", {
63
+ className: "flex justify-end gap-2 border-t border-base-300 px-5 py-3.5",
64
+ children: o
65
+ })
66
+ ]
67
+ })]
68
+ }) : null);
69
+ export {
70
+ p as default
71
+ };
72
+
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Modal/index.tsx"],"sourcesContent":["import React, { useEffect } from 'react';\n\nexport type ModalProps = {\n /** 是否打开 */\n open: boolean;\n /** 关闭回调(遮罩点击 / Esc / 关闭按钮触发) */\n onClose: () => void;\n /** 标题 */\n title?: React.ReactNode;\n /** 标题下的说明文字 */\n description?: React.ReactNode;\n /** 正文内容 */\n children?: React.ReactNode;\n /** 底部操作区(默认右对齐) */\n footer?: React.ReactNode;\n /** 尺寸 */\n size?: 'sm' | 'md' | 'lg';\n /** 点击遮罩是否关闭(默认 true) */\n closeOnOverlay?: boolean;\n /** 是否显示右上角关闭按钮(默认 true) */\n showClose?: boolean;\n className?: string;\n};\n\nconst SIZE_CLASS: Record<NonNullable<ModalProps['size']>, string> = {\n sm: 'max-w-sm',\n md: 'max-w-lg',\n lg: 'max-w-2xl',\n};\n\n/**\n * 轻量模态框:遮罩 + 居中面板,支持 Esc 关闭、遮罩点击关闭与滚动锁定。\n */\nconst Modal = ({\n open,\n onClose,\n title,\n description,\n children,\n footer,\n size = 'md',\n closeOnOverlay = true,\n showClose = true,\n className = '',\n}: ModalProps) => {\n useEffect(() => {\n if (!open) return;\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKey);\n const prevOverflow = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n return () => {\n window.removeEventListener('keydown', onKey);\n document.body.style.overflow = prevOverflow;\n };\n }, [open, onClose]);\n\n if (!open) return null;\n\n return (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4\">\n <div\n className=\"absolute inset-0\"\n onClick={closeOnOverlay ? onClose : undefined}\n aria-hidden\n />\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n className={`card relative w-full bg-base-100 shadow-xl ${SIZE_CLASS[size]} ${className}`.trim()}\n >\n {(title || showClose) && (\n <div className=\"flex items-start justify-between gap-3 border-b border-base-300 px-5 py-3.5\">\n <div className=\"min-w-0\">\n {title && (\n <h3 className=\"truncate text-sm font-semibold text-base-content\">\n {title}\n </h3>\n )}\n {description && (\n <p className=\"mt-0.5 text-xs text-base-content/60\">{description}</p>\n )}\n </div>\n {showClose && (\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className=\"shrink-0 rounded-md p-1 text-base-content/50 transition-colors hover:bg-base-200 hover:text-base-content\"\n >\n <svg\n className=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n )}\n <div className=\"max-h-[70vh] overflow-y-auto px-5 py-4\">{children}</div>\n {footer && (\n <div className=\"flex justify-end gap-2 border-t border-base-300 px-5 py-3.5\">\n {footer}\n </div>\n )}\n </div>\n </div>\n );\n};\n\nexport default Modal;\n"],"mappings":";;AAwBA,IAAM,IAA8D;AAAA,EAChE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACR,GAKM,IAAA,CAAS,EACX,MAAA,GACA,SAAA,GACA,OAAA,GACA,aAAA,GACA,UAAA,GACA,QAAA,GACA,MAAA,IAAO,MACP,gBAAA,IAAiB,IACjB,WAAA,IAAY,IACZ,WAAA,IAAY,GAAA,OAEZ,EAAA,MAAgB;AACZ,MAAI,CAAC,EAAM;AACX,QAAM,IAAA,CAAS,MAAqB;AAChC,IAAI,EAAE,QAAQ,YAAU,EAAQ;AAAA,EACpC;AACA,SAAO,iBAAiB,WAAW,CAAK;AACxC,QAAM,IAAe,SAAS,KAAK,MAAM;AACzC,kBAAS,KAAK,MAAM,WAAW,UAC/B,MAAa;AACT,WAAO,oBAAoB,WAAW,CAAK,GAC3C,SAAS,KAAK,MAAM,WAAW;AAAA,EACnC;AACJ,GAAG,CAAC,GAAM,CAAO,CAAC,GAEb,IAGD,gBAAA,EAAC,OAAD;AAAA,EAAK,WAAU;AAAA,YAAf,CACI,gBAAA,EAAC,OAAD;AAAA,IACI,WAAU;AAAA,IACV,SAAS,IAAiB,IAAU;AAAA,IACpC,eAAA;AAAA,EACH,CAAA,GACD,gBAAA,EAAC,OAAD;AAAA,IACI,MAAK;AAAA,IACL,cAAW;AAAA,IACX,WAAW,8CAA8C,EAAW,CAAA,CAAA,IAAS,CAAA,GAAY,KAAK;AAAA,cAHlG;AAAA,OAKM,KAAS,MACP,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBAAf,CACI,gBAAA,EAAC,OAAD;AAAA,UAAK,WAAU;AAAA,oBAAf,CACK,KACG,gBAAA,EAAC,MAAD;AAAA,YAAI,WAAU;AAAA,sBACT;AAAA,UACD,CAAA,GAEP,KACG,gBAAA,EAAC,KAAD;AAAA,YAAG,WAAU;AAAA,sBAAuC;AAAA,UAAe,CAAA,CAEtE;AAAA,YACJ,KACG,gBAAA,EAAC,UAAD;AAAA,UACI,MAAK;AAAA,UACL,SAAS;AAAA,UACT,cAAW;AAAA,UACX,WAAU;AAAA,oBAEV,gBAAA,EAAC,OAAD;AAAA,YACI,WAAU;AAAA,YACV,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,QAAO;AAAA,YACP,aAAa;AAAA,sBAEb,gBAAA,EAAC,QAAD;AAAA,cACI,eAAc;AAAA,cACd,gBAAe;AAAA,cACf,GAAE;AAAA,YACL,CAAA;AAAA,UACA,CAAA;AAAA,QACD,CAAA,CAEX;AAAA;MAET,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,QAA0C,UAAA;AAAA,MAAc,CAAA;AAAA,MACtE,KACG,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBACV;AAAA,MACA,CAAA;AAAA,IAER;AAAA,IACJ;KAzDS"}
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ export type PageHeaderProps = {
3
+ /** 页面标题 */
4
+ title: React.ReactNode;
5
+ /** 标题下方的描述文字 */
6
+ description?: React.ReactNode;
7
+ /** 标题左侧的图标(通常为 lucide 图标) */
8
+ icon?: React.ReactNode;
9
+ /** 右侧操作区(按钮组等) */
10
+ actions?: React.ReactNode;
11
+ /** 紧凑模式:标题与间距更小 */
12
+ compact?: boolean;
13
+ className?: string;
14
+ };
15
+ /**
16
+ * 页面头部:统一管理后台等页面的标题 / 描述 / 操作区排版。
17
+ * 相比页面内手写的 `text-3xl` 标题,默认字号更精致(text-lg)。
18
+ */
19
+ declare const PageHeader: ({ title, description, icon, actions, compact, className, }: PageHeaderProps) => React.JSX.Element;
20
+ export default PageHeader;
@@ -0,0 +1,32 @@
1
+ import "react";
2
+ import { jsx as e, jsxs as s } from "react/jsx-runtime";
3
+ var f = ({ title: i, description: a, icon: r, actions: l, compact: t = !0, className: n = "" }) => {
4
+ const m = t ? "text-lg" : "text-2xl", c = t ? "[&>svg]:h-5 [&>svg]:w-5" : "[&>svg]:h-6 [&>svg]:w-6";
5
+ return /* @__PURE__ */ s("div", {
6
+ className: `flex flex-wrap items-start justify-between gap-3 ${t ? "mb-5" : "mb-8"} ${n}`.trim(),
7
+ children: [/* @__PURE__ */ s("div", {
8
+ className: "min-w-0",
9
+ children: [/* @__PURE__ */ s("div", {
10
+ className: "flex items-center gap-2.5",
11
+ children: [r && /* @__PURE__ */ e("span", {
12
+ className: `shrink-0 text-primary ${c}`,
13
+ children: r
14
+ }), /* @__PURE__ */ e("h1", {
15
+ className: `truncate font-bold text-base-content ${m}`,
16
+ children: i
17
+ })]
18
+ }), a && /* @__PURE__ */ e("p", {
19
+ className: "mt-0.5 text-xs text-base-content/60",
20
+ children: a
21
+ })]
22
+ }), l && /* @__PURE__ */ e("div", {
23
+ className: "flex shrink-0 items-center gap-2",
24
+ children: l
25
+ })]
26
+ });
27
+ };
28
+ export {
29
+ f as default
30
+ };
31
+
32
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/PageHeader/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type PageHeaderProps = {\n /** 页面标题 */\n title: React.ReactNode;\n /** 标题下方的描述文字 */\n description?: React.ReactNode;\n /** 标题左侧的图标(通常为 lucide 图标) */\n icon?: React.ReactNode;\n /** 右侧操作区(按钮组等) */\n actions?: React.ReactNode;\n /** 紧凑模式:标题与间距更小 */\n compact?: boolean;\n className?: string;\n};\n\n/**\n * 页面头部:统一管理后台等页面的标题 / 描述 / 操作区排版。\n * 相比页面内手写的 `text-3xl` 标题,默认字号更精致(text-lg)。\n */\nconst PageHeader = ({\n title,\n description,\n icon,\n actions,\n compact = true,\n className = '',\n}: PageHeaderProps) => {\n const titleSize = compact ? 'text-lg' : 'text-2xl';\n const iconSize = compact ? '[&>svg]:h-5 [&>svg]:w-5' : '[&>svg]:h-6 [&>svg]:w-6';\n const spacing = compact ? 'mb-5' : 'mb-8';\n\n return (\n <div className={`flex flex-wrap items-start justify-between gap-3 ${spacing} ${className}`.trim()}>\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2.5\">\n {icon && (\n <span className={`shrink-0 text-primary ${iconSize}`}>{icon}</span>\n )}\n <h1 className={`truncate font-bold text-base-content ${titleSize}`}>{title}</h1>\n </div>\n {description && (\n <p className=\"mt-0.5 text-xs text-base-content/60\">{description}</p>\n )}\n </div>\n {actions && <div className=\"flex shrink-0 items-center gap-2\">{actions}</div>}\n </div>\n );\n};\n\nexport default PageHeader;\n"],"mappings":";;AAoBA,IAAM,IAAA,CAAc,EAChB,OAAA,GACA,aAAA,GACA,MAAA,GACA,SAAA,GACA,SAAA,IAAU,IACV,WAAA,IAAY,GAAA,MACO;AACnB,QAAM,IAAY,IAAU,YAAY,YAClC,IAAW,IAAU,4BAA4B;AAGvD,SACI,gBAAA,EAAC,OAAD;AAAA,IAAK,WAAW,oDAHJ,IAAU,SAAS,MAAA,IAGgD,CAAA,GAAY,KAAK;AAAA,cAAhG,CACI,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAf,CACI,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBAAf,CACK,KACG,gBAAA,EAAC,QAAD;AAAA,UAAM,WAAW,yBAAyB,CAAA;AAAA,oBAAa;AAAA,QAAW,CAAA,GAEtE,gBAAA,EAAC,MAAD;AAAA,UAAI,WAAW,wCAAwC,CAAA;AAAA,oBAAc;AAAA,QAAU,CAAA,CAC9E;AAAA,UACJ,KACG,gBAAA,EAAC,KAAD;AAAA,QAAG,WAAU;AAAA,kBAAuC;AAAA,MAAe,CAAA,CAEtE;AAAA,QACJ,KAAW,gBAAA,EAAC,OAAD;AAAA,MAAK,WAAU;AAAA,gBAAoC;AAAA,IAAa,CAAA,CAC3E;AAAA;AAEb"}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ export type StatCardProps = {
3
+ /** 指标名称 */
4
+ label: React.ReactNode;
5
+ /** 指标值(数字或短文本) */
6
+ value: React.ReactNode;
7
+ /** 右上角图标 */
8
+ icon?: React.ReactNode;
9
+ /** 色调(影响图标底色与文字色) */
10
+ tone?: 'primary' | 'success' | 'warning' | 'info' | 'error' | 'neutral';
11
+ /** 值下方的小字说明 */
12
+ hint?: React.ReactNode;
13
+ /** 加载态:值显示为骨架 */
14
+ loading?: boolean;
15
+ className?: string;
16
+ };
17
+ /**
18
+ * 统计卡片:仪表盘等场景的「标签 + 数值 + 图标」小卡。
19
+ * 内部基于 Card 组件,默认紧凑内边距与小号字体。
20
+ */
21
+ declare const StatCard: ({ label, value, icon, tone, hint, loading, className, }: StatCardProps) => React.JSX.Element;
22
+ export default StatCard;
@@ -0,0 +1,62 @@
1
+ import b from "../Card/index.js";
2
+ import "react";
3
+ import { jsx as e, jsxs as a } from "react/jsx-runtime";
4
+ var x = {
5
+ primary: {
6
+ text: "text-primary",
7
+ bg: "bg-primary/10"
8
+ },
9
+ success: {
10
+ text: "text-success",
11
+ bg: "bg-success/10"
12
+ },
13
+ warning: {
14
+ text: "text-warning",
15
+ bg: "bg-warning/10"
16
+ },
17
+ info: {
18
+ text: "text-info",
19
+ bg: "bg-info/10"
20
+ },
21
+ error: {
22
+ text: "text-error",
23
+ bg: "bg-error/10"
24
+ },
25
+ neutral: {
26
+ text: "text-base-content/70",
27
+ bg: "bg-base-content/5"
28
+ }
29
+ }, u = ({ label: n, value: o, icon: t, tone: c = "primary", hint: r, loading: i = !1, className: m = "" }) => {
30
+ const s = x[c];
31
+ return /* @__PURE__ */ a(b, {
32
+ bordered: !0,
33
+ glass: !1,
34
+ hover: !0,
35
+ className: `bg-base-200 p-4 ${m}`.trim(),
36
+ children: [
37
+ /* @__PURE__ */ a("div", {
38
+ className: "mb-2 flex items-center justify-between gap-2",
39
+ children: [/* @__PURE__ */ e("span", {
40
+ className: "truncate text-xs font-medium text-base-content/60",
41
+ children: n
42
+ }), t && /* @__PURE__ */ e("span", {
43
+ className: `rounded-md p-1.5 ${s.bg} [&>svg]:h-4 [&>svg]:w-4 ${s.text}`.trim(),
44
+ children: t
45
+ })]
46
+ }),
47
+ i ? /* @__PURE__ */ e("div", { className: "h-7 w-14 animate-pulse rounded bg-base-content/10" }) : /* @__PURE__ */ e("p", {
48
+ className: "text-2xl font-bold leading-none text-base-content",
49
+ children: o
50
+ }),
51
+ r && /* @__PURE__ */ e("p", {
52
+ className: "mt-1.5 text-[11px] text-base-content/50",
53
+ children: r
54
+ })
55
+ ]
56
+ });
57
+ };
58
+ export {
59
+ u as default
60
+ };
61
+
62
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/StatCard/index.tsx"],"sourcesContent":["import React from 'react';\nimport Card from '../Card';\n\nexport type StatCardProps = {\n /** 指标名称 */\n label: React.ReactNode;\n /** 指标值(数字或短文本) */\n value: React.ReactNode;\n /** 右上角图标 */\n icon?: React.ReactNode;\n /** 色调(影响图标底色与文字色) */\n tone?: 'primary' | 'success' | 'warning' | 'info' | 'error' | 'neutral';\n /** 值下方的小字说明 */\n hint?: React.ReactNode;\n /** 加载态:值显示为骨架 */\n loading?: boolean;\n className?: string;\n};\n\nconst TONE_CLASS: Record<NonNullable<StatCardProps['tone']>, { text: string; bg: string }> = {\n primary: { text: 'text-primary', bg: 'bg-primary/10' },\n success: { text: 'text-success', bg: 'bg-success/10' },\n warning: { text: 'text-warning', bg: 'bg-warning/10' },\n info: { text: 'text-info', bg: 'bg-info/10' },\n error: { text: 'text-error', bg: 'bg-error/10' },\n neutral: { text: 'text-base-content/70', bg: 'bg-base-content/5' },\n};\n\n/**\n * 统计卡片:仪表盘等场景的「标签 + 数值 + 图标」小卡。\n * 内部基于 Card 组件,默认紧凑内边距与小号字体。\n */\nconst StatCard = ({\n label,\n value,\n icon,\n tone = 'primary',\n hint,\n loading = false,\n className = '',\n}: StatCardProps) => {\n const t = TONE_CLASS[tone];\n\n return (\n <Card bordered glass={false} hover className={`bg-base-200 p-4 ${className}`.trim()}>\n <div className=\"mb-2 flex items-center justify-between gap-2\">\n <span className=\"truncate text-xs font-medium text-base-content/60\">{label}</span>\n {icon && (\n <span className={`rounded-md p-1.5 ${t.bg} [&>svg]:h-4 [&>svg]:w-4 ${t.text}`.trim()}>\n {icon}\n </span>\n )}\n </div>\n {loading ? (\n <div className=\"h-7 w-14 animate-pulse rounded bg-base-content/10\" />\n ) : (\n <p className=\"text-2xl font-bold leading-none text-base-content\">{value}</p>\n )}\n {hint && <p className=\"mt-1.5 text-[11px] text-base-content/50\">{hint}</p>}\n </Card>\n );\n};\n\nexport default StatCard;\n"],"mappings":";;;AAmBA,IAAM,IAAuF;AAAA,EACzF,SAAS;AAAA,IAAE,MAAM;AAAA,IAAgB,IAAI;AAAA,EAAgB;AAAA,EACrD,SAAS;AAAA,IAAE,MAAM;AAAA,IAAgB,IAAI;AAAA,EAAgB;AAAA,EACrD,SAAS;AAAA,IAAE,MAAM;AAAA,IAAgB,IAAI;AAAA,EAAgB;AAAA,EACrD,MAAM;AAAA,IAAE,MAAM;AAAA,IAAa,IAAI;AAAA,EAAa;AAAA,EAC5C,OAAO;AAAA,IAAE,MAAM;AAAA,IAAc,IAAI;AAAA,EAAc;AAAA,EAC/C,SAAS;AAAA,IAAE,MAAM;AAAA,IAAwB,IAAI;AAAA,EAAoB;AACrE,GAMM,IAAA,CAAY,EACd,OAAA,GACA,OAAA,GACA,MAAA,GACA,MAAA,IAAO,WACP,MAAA,GACA,SAAA,IAAU,IACV,WAAA,IAAY,GAAA,MACK;AACjB,QAAM,IAAI,EAAW,CAAA;AAErB,SACI,gBAAA,EAAC,GAAD;AAAA,IAAM,UAAA;AAAA,IAAS,OAAO;AAAA,IAAO,OAAA;AAAA,IAAM,WAAW,mBAAmB,CAAA,GAAY,KAAK;AAAA,cAAlF;AAAA,MACI,gBAAA,EAAC,OAAD;AAAA,QAAK,WAAU;AAAA,kBAAf,CACI,gBAAA,EAAC,QAAD;AAAA,UAAM,WAAU;AAAA,oBAAqD;AAAA,QAAY,CAAA,GAChF,KACG,gBAAA,EAAC,QAAD;AAAA,UAAM,WAAW,oBAAoB,EAAE,EAAA,4BAA8B,EAAE,IAAA,GAAO,KAAK;AAAA,oBAC9E;AAAA,QACC,CAAA,CAET;AAAA;MACJ,IACG,gBAAA,EAAC,OAAD,EAAK,WAAU,oDAAqD,CAAA,IAEpE,gBAAA,EAAC,KAAD;AAAA,QAAG,WAAU;AAAA,kBAAqD;AAAA,MAAS,CAAA;AAAA,MAE9E,KAAQ,gBAAA,EAAC,KAAD;AAAA,QAAG,WAAU;AAAA,kBAA2C;AAAA,MAAQ,CAAA;AAAA,IACvE;AAAA;AAEd"}
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ export type TabItem<T extends string = string> = {
3
+ key: T;
4
+ label: React.ReactNode;
5
+ };
6
+ export type TabsProps<T extends string = string> = {
7
+ items: readonly TabItem<T>[];
8
+ /** 当前激活的 tab key */
9
+ value: T;
10
+ /** 切换回调 */
11
+ onChange: (key: T) => void;
12
+ /** 外观:box(daisyUI 5 的 tabs-box)/ border(tabs-border) */
13
+ variant?: 'box' | 'border';
14
+ className?: string;
15
+ };
16
+ /**
17
+ * 标签页切换条。基于 daisyUI 5 的 `tabs` / `tabs-box` / `tabs-border`,
18
+ * 字号统一使用小号文本,与管理后台紧凑风格一致。
19
+ */
20
+ declare function Tabs<T extends string = string>({ items, value, onChange, variant, className, }: TabsProps<T>): React.JSX.Element;
21
+ export default Tabs;
@@ -0,0 +1,25 @@
1
+ import "react";
2
+ import { jsx as e } from "react/jsx-runtime";
3
+ function c({ items: o, value: a, onChange: r, variant: b = "box", className: l = "" }) {
4
+ return /* @__PURE__ */ e("div", {
5
+ role: "tablist",
6
+ className: [
7
+ "tabs h-auto min-h-0 text-xs",
8
+ b === "box" ? "tabs-box" : "tabs-border",
9
+ l
10
+ ].filter(Boolean).join(" "),
11
+ children: o.map((t) => /* @__PURE__ */ e("button", {
12
+ role: "tab",
13
+ type: "button",
14
+ "aria-selected": a === t.key,
15
+ onClick: () => r(t.key),
16
+ className: ["tab h-8 min-h-0 text-xs", a === t.key && "tab-active"].filter(Boolean).join(" "),
17
+ children: t.label
18
+ }, t.key))
19
+ });
20
+ }
21
+ export {
22
+ c as default
23
+ };
24
+
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/components/Tabs/index.tsx"],"sourcesContent":["import React from 'react';\n\nexport type TabItem<T extends string = string> = {\n key: T;\n label: React.ReactNode;\n};\n\nexport type TabsProps<T extends string = string> = {\n items: readonly TabItem<T>[];\n /** 当前激活的 tab key */\n value: T;\n /** 切换回调 */\n onChange: (key: T) => void;\n /** 外观:box(daisyUI 5 的 tabs-box)/ border(tabs-border) */\n variant?: 'box' | 'border';\n className?: string;\n};\n\n/**\n * 标签页切换条。基于 daisyUI 5 的 `tabs` / `tabs-box` / `tabs-border`,\n * 字号统一使用小号文本,与管理后台紧凑风格一致。\n */\nfunction Tabs<T extends string = string>({\n items,\n value,\n onChange,\n variant = 'box',\n className = '',\n}: TabsProps<T>) {\n const variantClass = variant === 'box' ? 'tabs-box' : 'tabs-border';\n\n return (\n <div\n role=\"tablist\"\n className={['tabs h-auto min-h-0 text-xs', variantClass, className].filter(Boolean).join(' ')}\n >\n {items.map((item) => (\n <button\n key={item.key}\n role=\"tab\"\n type=\"button\"\n aria-selected={value === item.key}\n onClick={() => onChange(item.key)}\n className={['tab h-8 min-h-0 text-xs', value === item.key && 'tab-active'].filter(Boolean).join(' ')}\n >\n {item.label}\n </button>\n ))}\n </div>\n );\n}\n\nexport default Tabs;\n"],"mappings":";;AAsBA,SAAS,EAAgC,EACrC,OAAA,GACA,OAAA,GACA,UAAA,GACA,SAAA,IAAU,OACV,WAAA,IAAY,GAAA,GACC;AAGb,SACI,gBAAA,EAAC,OAAD;AAAA,IACI,MAAK;AAAA,IACL,WAAW;AAAA,MAAC;AAAA,MALC,MAAY,QAAQ,aAAa;AAAA,MAKW;AAAA,IAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,cAE3F,EAAM,IAAA,CAAK,MACR,gBAAA,EAAC,UAAD;AAAA,MAEI,MAAK;AAAA,MACL,MAAK;AAAA,MACL,iBAAe,MAAU,EAAK;AAAA,MAC9B,SAAA,MAAe,EAAS,EAAK,GAAG;AAAA,MAChC,WAAW,CAAC,2BAA2B,MAAU,EAAK,OAAO,YAAY,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,gBAElG,EAAK;AAAA,IACF,GARC,EAAK,GAQN,CACX;AAAA,EACA,CAAA;AAEb"}