hd-attribute-set 0.1.0 → 0.1.2

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.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./utils.cjs"),i=require("./use-permission-CbbVGG4p.cjs"),s="0.1.2";exports.debounce=e.debounce;exports.deepClone=e.deepClone;exports.isEmail=e.isEmail;exports.isEmpty=e.isEmpty;exports.isIdCard=e.isIdCard;exports.isPhone=e.isPhone;exports.listToTree=e.listToTree;exports.sleep=e.sleep;exports.throttle=e.throttle;exports.uniqueBy=e.uniqueBy;exports.DEFAULT_PERMISSION_CONFIG=i.DEFAULT_PERMISSION_CONFIG;exports.normalizePermissionId=i.normalizePermissionId;exports.resolvePermissionConfig=i.resolvePermissionConfig;exports.useMemoizedFn=i.useMemoizedFn;exports.usePermission=i.usePermission;exports.version=s;
@@ -1,35 +1,21 @@
1
- import { jsxs as s, Fragment as i, jsx as r } from "react/jsx-runtime";
2
- import { Divider as n, Empty as l, Descriptions as h } from "antd";
3
- function m({ items: a, title: t, column: d = 2, bordered: c = !0, emptyText: p = "暂无属性" }) {
4
- return !a || a.length === 0 ? /* @__PURE__ */ s("div", { className: "hd-attribute-set", children: [
5
- t && /* @__PURE__ */ s(i, { children: [
6
- /* @__PURE__ */ r("div", { className: "hd-attribute-set__title", children: t }),
7
- /* @__PURE__ */ r(n, { style: { margin: "8px 0 16px" } })
8
- ] }),
9
- /* @__PURE__ */ r(l, { image: l.PRESENTED_IMAGE_SIMPLE, description: p })
10
- ] }) : /* @__PURE__ */ s("div", { className: "hd-attribute-set", children: [
11
- t && /* @__PURE__ */ s(i, { children: [
12
- /* @__PURE__ */ r("div", { className: "hd-attribute-set__title", children: t }),
13
- /* @__PURE__ */ r(n, { style: { margin: "8px 0 16px" } })
14
- ] }),
15
- /* @__PURE__ */ r(
16
- h,
17
- {
18
- size: "small",
19
- column: d,
20
- bordered: c,
21
- items: a.map((e) => ({
22
- key: e.key,
23
- label: e.label,
24
- children: e.render ? e.render(e.value) : e.value ?? "-",
25
- span: e.span
26
- }))
27
- }
28
- )
29
- ] });
30
- }
31
- const v = "0.1.0";
1
+ import { debounce as i, deepClone as r, isEmail as n, isEmpty as a, isIdCard as m, isPhone as t, listToTree as l, sleep as d, throttle as p, uniqueBy as u } from "./utils.js";
2
+ import { D as P, n as C, r as E, u as f, a as x } from "./use-permission-DHvtS-2I.js";
3
+ const e = "0.1.2";
32
4
  export {
33
- m as AttributeSet,
34
- v as version
5
+ P as DEFAULT_PERMISSION_CONFIG,
6
+ i as debounce,
7
+ r as deepClone,
8
+ n as isEmail,
9
+ a as isEmpty,
10
+ m as isIdCard,
11
+ t as isPhone,
12
+ l as listToTree,
13
+ C as normalizePermissionId,
14
+ E as resolvePermissionConfig,
15
+ d as sleep,
16
+ p as throttle,
17
+ u as uniqueBy,
18
+ f as useMemoizedFn,
19
+ x as usePermission,
20
+ e as version
35
21
  };
@@ -0,0 +1,7 @@
1
+ /**
2
+ * hooks 统一出口(barrel 文件)
3
+ * 新增 hook 文件后,只需在此处加一行 `export * from './xxx';`
4
+ * 即可从 'hd-attribute-set/hooks' 子路径引入。
5
+ */
6
+ export * from './use-memoized-fn';
7
+ export * from './use-permission';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 返回引用稳定的函数:外层引用永远不变,内部始终执行最新的实现。
3
+ * 用于替代 ahooks 的 useMemoizedFn,避免组件库引入额外运行时依赖。
4
+ *
5
+ * @example
6
+ * const handleClick = useMemoizedFn((id: string) => { ... });
7
+ */
8
+ export declare function useMemoizedFn<T extends (...args: any[]) => any>(fn: T): T;
9
+ export default useMemoizedFn;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * 权限判断 hook(与 redux / ahooks 解耦版)
3
+ * 权限配置由调用方通过参数传入,可以是 redux 中的 accessConfig,也可以是任意数据源。
4
+ *
5
+ * @example
6
+ * // 直接传 redux 中的数据
7
+ * const accessConfig = useAppSelector(selectAccessConfig);
8
+ * const { shouldShowButton, isNoPermissionShow } = usePermission(accessConfig);
9
+ *
10
+ * @example
11
+ * // 传 getter:每次调用时取最新值,避免闭包拿到旧数据
12
+ * const { hasPermission } = usePermission(() => store.getState().auth.userInfo?.accessConfig);
13
+ */
14
+ /** 权限配置(一般来自 redux 的 accessConfig) */
15
+ export interface PermissionConfig {
16
+ /** 无权限时是否在页面上展示(由消费方决定提示 / 禁用) */
17
+ noPermissionShow?: boolean;
18
+ /** 当前用户拥有的权限编号列表 */
19
+ list?: (number | string)[];
20
+ /** 是否拥有全部权限 */
21
+ selectAll?: boolean;
22
+ }
23
+ /** 权限配置来源:直接传对象,或传 getter(每次调用读取最新值,适配 redux / context 等外部数据源) */
24
+ export type PermissionConfigSource = PermissionConfig | (() => PermissionConfig | null | undefined);
25
+ export interface UsePermissionReturn {
26
+ /** 检查是否有权限 */
27
+ hasPermission: (permissionId?: number | string) => boolean;
28
+ /** 检查按钮是否应该显示 */
29
+ shouldShowButton: (permissionId?: number | string) => boolean;
30
+ /** 检查菜单是否应该显示 */
31
+ shouldShowMenu: (permissionId?: number | string) => {
32
+ noPermissionShow: boolean;
33
+ hasPerm: boolean;
34
+ };
35
+ /** 检查没权限时是否需要在页面上提示 / 禁用 */
36
+ isNoPermissionShow: (permissionId?: number | string) => boolean;
37
+ }
38
+ /** 没有权限配置时的兜底:视为拥有全部权限 */
39
+ export declare const DEFAULT_PERMISSION_CONFIG: PermissionConfig;
40
+ /**
41
+ * 权限编号归一化:平台权限编号是「定长分层编号」(导航 60000 → 二级菜单 62000 → 三级菜单 62100 → 按钮 62101),
42
+ * 而菜单配置里的三级菜单编号可能多补一位 0(如 621000),导致精确比较匹配不上、有权限的菜单显示不出来。
43
+ * 这里去掉编号末尾的补位 0(621000 与 62100 都归一化为 621)后再比较一次。
44
+ */
45
+ export declare const normalizePermissionId: (permissionId: number | string) => string;
46
+ /** 解析权限配置(支持 getter,保证拿到外部数据源的最新值) */
47
+ export declare const resolvePermissionConfig: (source?: PermissionConfigSource) => PermissionConfig;
48
+ export declare function usePermission(source?: PermissionConfigSource): UsePermissionReturn;
49
+ export default usePermission;
package/dist/hooks.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./use-permission-CbbVGG4p.cjs");exports.DEFAULT_PERMISSION_CONFIG=e.DEFAULT_PERMISSION_CONFIG;exports.normalizePermissionId=e.normalizePermissionId;exports.resolvePermissionConfig=e.resolvePermissionConfig;exports.useMemoizedFn=e.useMemoizedFn;exports.usePermission=e.usePermission;
@@ -0,0 +1,2 @@
1
+ export * from './hooks/index'
2
+ export {}
package/dist/hooks.js ADDED
@@ -0,0 +1,8 @@
1
+ import { D as i, n as o, r, u as a, a as n } from "./use-permission-DHvtS-2I.js";
2
+ export {
3
+ i as DEFAULT_PERMISSION_CONFIG,
4
+ o as normalizePermissionId,
5
+ r as resolvePermissionConfig,
6
+ a as useMemoizedFn,
7
+ n as usePermission
8
+ };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,8 @@
1
- export * from './components/attribute-set';
1
+ /**
2
+ * 包主入口(根路径)
3
+ * - utils / hooks 都可以从根入口引入
4
+ * - 也保留子路径引入:'hd-attribute-set/utils'、'hd-attribute-set/hooks'
5
+ */
6
+ export * from './utils';
7
+ export * from './hooks';
2
8
  export declare const version: string;
@@ -0,0 +1 @@
1
+ "use strict";const f=require("react");function r(n){const e=f.useRef(n);e.current=n;const s=f.useRef(null);return s.current||(s.current=(...u)=>{var i;return(i=e.current)==null?void 0:i.call(e,...u)}),s.current}const P={noPermissionShow:!0,list:[],selectAll:!0},m=n=>String(n).replace(/0+$/,""),c=n=>(typeof n=="function"?n():n)||P;function g(n){const e=r(o=>{if(!o)return!0;const t=c(n);if(t.selectAll)return!0;const l=t.list||[];if(l.includes(Number(o)))return!0;const S=m(o);return l.some(h=>m(h)===S)}),s=r(o=>e(o)),u=r(o=>({noPermissionShow:!!c(n).noPermissionShow,hasPerm:e(o)})),i=r(o=>!!c(n).noPermissionShow&&!e(o));return{hasPermission:e,shouldShowButton:s,shouldShowMenu:u,isNoPermissionShow:i}}exports.DEFAULT_PERMISSION_CONFIG=P;exports.normalizePermissionId=m;exports.resolvePermissionConfig=c;exports.useMemoizedFn=r;exports.usePermission=g;
@@ -0,0 +1,47 @@
1
+ import { useRef as l } from "react";
2
+ function i(n) {
3
+ const o = l(n);
4
+ o.current = n;
5
+ const r = l(null);
6
+ return r.current || (r.current = (...c) => {
7
+ var s;
8
+ return (s = o.current) == null ? void 0 : s.call(o, ...c);
9
+ }), r.current;
10
+ }
11
+ const P = {
12
+ noPermissionShow: !0,
13
+ list: [],
14
+ selectAll: !0
15
+ }, f = (n) => String(n).replace(/0+$/, ""), u = (n) => (typeof n == "function" ? n() : n) || P;
16
+ function g(n) {
17
+ const o = i((e) => {
18
+ if (!e)
19
+ return !0;
20
+ const t = u(n);
21
+ if (t.selectAll)
22
+ return !0;
23
+ const m = t.list || [];
24
+ if (m.includes(Number(e)))
25
+ return !0;
26
+ const a = f(e);
27
+ return m.some((h) => f(h) === a);
28
+ }), r = i(
29
+ (e) => o(e)
30
+ ), c = i((e) => ({
31
+ noPermissionShow: !!u(n).noPermissionShow,
32
+ hasPerm: o(e)
33
+ })), s = i((e) => !!u(n).noPermissionShow && !o(e));
34
+ return {
35
+ hasPermission: o,
36
+ shouldShowButton: r,
37
+ shouldShowMenu: c,
38
+ isNoPermissionShow: s
39
+ };
40
+ }
41
+ export {
42
+ P as D,
43
+ g as a,
44
+ f as n,
45
+ u as r,
46
+ i as u
47
+ };
@@ -0,0 +1,9 @@
1
+ /** 防抖 */
2
+ export declare function debounce<T extends (...args: never[]) => void>(fn: T, wait?: number): {
3
+ (...args: Parameters<T>): void;
4
+ cancel(): void;
5
+ };
6
+ /** 节流 */
7
+ export declare function throttle<T extends (...args: never[]) => void>(fn: T, wait?: number): (...args: Parameters<T>) => void;
8
+ /** 睡眠 */
9
+ export declare function sleep(ms: number): Promise<void>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * utils 统一出口(barrel 文件)
3
+ * 新增工具文件后,只需在此处加一行 `export * from './xxx';`
4
+ * 即可从包根路径或 'hd-attribute-set/utils' 子路径引入。
5
+ */
6
+ export * from './validate';
7
+ export * from './object';
8
+ export * from './fn';
@@ -0,0 +1,13 @@
1
+ /** 深拷贝:优先 structuredClone,失败降级 JSON */
2
+ export declare function deepClone<T>(source: T): T;
3
+ /** 数组去重(按 key 或值) */
4
+ export declare function uniqueBy<T>(list: T[], key?: keyof T): T[];
5
+ /** 数组转树(扁平结构构建树形结构) */
6
+ export interface TreeNode<T> extends Record<string, unknown> {
7
+ children?: TreeNode<T>[];
8
+ }
9
+ export declare function listToTree<T extends Record<string, unknown>>(list: T[], { idKey, parentKey, childrenKey }?: {
10
+ idKey?: string | undefined;
11
+ parentKey?: string | undefined;
12
+ childrenKey?: string | undefined;
13
+ }): TreeNode<T>[];
@@ -0,0 +1,8 @@
1
+ /** 判断空值:undefined / null / 空字符串 / 空数组 / 空 MapSet / 空对象 */
2
+ export declare function isEmpty(value: unknown): boolean;
3
+ /** 手机号校验(中国大陆) */
4
+ export declare function isPhone(value: string): boolean;
5
+ /** 身份证校验(18 位) */
6
+ export declare function isIdCard(value: string): boolean;
7
+ /** 邮箱校验 */
8
+ export declare function isEmail(value: string): boolean;
package/dist/utils.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function f(t){return t==null||t===""?!0:Array.isArray(t)?t.length===0:t instanceof Map||t instanceof Set?t.size===0:typeof t=="object"?Object.keys(t).length===0:!1}function d(t){return/^1[3-9]\d{9}$/.test(t)}function a(t){return/^\d{17}[\dXx]$/.test(t)}function l(t){return/^[\w.+-]+@[\w-]+(\.[\w-]+)+$/.test(t)}function p(t){if(typeof structuredClone=="function")try{return structuredClone(t)}catch{}return JSON.parse(JSON.stringify(t))}function h(t,n){if(!n)return Array.from(new Set(t));const e=new Set;return t.filter(o=>{const r=o[n];return e.has(r)?!1:(e.add(r),!0)})}function m(t,{idKey:n="id",parentKey:e="parentId",childrenKey:o="children"}={}){const r=new Map,s=[];return t.forEach(i=>{r.set(i[n],{...i,[o]:[]})}),t.forEach(i=>{const u=r.get(i[n]),c=r.get(i[e]);c?c[o].push(u):s.push(u)}),s}function y(t,n=300){let e;const o=(...r)=>{e&&clearTimeout(e),e=setTimeout(()=>t(...r),n)};return o.cancel=()=>{e&&clearTimeout(e),e=void 0},o}function w(t,n=300){let e=0;return(...o)=>{const r=Date.now();r-e>=n&&(e=r,t(...o))}}function T(t){return new Promise(n=>setTimeout(n,t))}exports.debounce=y;exports.deepClone=p;exports.isEmail=l;exports.isEmpty=f;exports.isIdCard=a;exports.isPhone=d;exports.listToTree=m;exports.sleep=T;exports.throttle=w;exports.uniqueBy=h;
@@ -0,0 +1,2 @@
1
+ export * from './utils/index'
2
+ export {}
package/dist/utils.js ADDED
@@ -0,0 +1,68 @@
1
+ function f(t) {
2
+ return t == null || t === "" ? !0 : Array.isArray(t) ? t.length === 0 : t instanceof Map || t instanceof Set ? t.size === 0 : typeof t == "object" ? Object.keys(t).length === 0 : !1;
3
+ }
4
+ function d(t) {
5
+ return /^1[3-9]\d{9}$/.test(t);
6
+ }
7
+ function a(t) {
8
+ return /^\d{17}[\dXx]$/.test(t);
9
+ }
10
+ function p(t) {
11
+ return /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/.test(t);
12
+ }
13
+ function h(t) {
14
+ if (typeof structuredClone == "function")
15
+ try {
16
+ return structuredClone(t);
17
+ } catch {
18
+ }
19
+ return JSON.parse(JSON.stringify(t));
20
+ }
21
+ function l(t, e) {
22
+ if (!e) return Array.from(new Set(t));
23
+ const n = /* @__PURE__ */ new Set();
24
+ return t.filter((o) => {
25
+ const r = o[e];
26
+ return n.has(r) ? !1 : (n.add(r), !0);
27
+ });
28
+ }
29
+ function w(t, { idKey: e = "id", parentKey: n = "parentId", childrenKey: o = "children" } = {}) {
30
+ const r = /* @__PURE__ */ new Map(), s = [];
31
+ return t.forEach((i) => {
32
+ r.set(i[e], { ...i, [o]: [] });
33
+ }), t.forEach((i) => {
34
+ const u = r.get(i[e]), c = r.get(i[n]);
35
+ c ? c[o].push(u) : s.push(u);
36
+ }), s;
37
+ }
38
+ function m(t, e = 300) {
39
+ let n;
40
+ const o = (...r) => {
41
+ n && clearTimeout(n), n = setTimeout(() => t(...r), e);
42
+ };
43
+ return o.cancel = () => {
44
+ n && clearTimeout(n), n = void 0;
45
+ }, o;
46
+ }
47
+ function y(t, e = 300) {
48
+ let n = 0;
49
+ return (...o) => {
50
+ const r = Date.now();
51
+ r - n >= e && (n = r, t(...o));
52
+ };
53
+ }
54
+ function T(t) {
55
+ return new Promise((e) => setTimeout(e, t));
56
+ }
57
+ export {
58
+ m as debounce,
59
+ h as deepClone,
60
+ p as isEmail,
61
+ f as isEmpty,
62
+ a as isIdCard,
63
+ d as isPhone,
64
+ w as listToTree,
65
+ T as sleep,
66
+ y as throttle,
67
+ l as uniqueBy
68
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hd-attribute-set",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "属性集组件库,基于 React + antd",
5
5
  "keywords": [
6
6
  "react",
@@ -31,17 +31,36 @@
31
31
  "dist",
32
32
  "README.md"
33
33
  ],
34
- "main": "dist/hd-attribute-set.umd.cjs",
34
+ "main": "dist/hd-attribute-set.cjs",
35
35
  "module": "dist/hd-attribute-set.js",
36
36
  "types": "dist/index.d.ts",
37
37
  "exports": {
38
38
  ".": {
39
39
  "types": "./dist/index.d.ts",
40
40
  "import": "./dist/hd-attribute-set.js",
41
- "require": "./dist/hd-attribute-set.umd.cjs"
41
+ "require": "./dist/hd-attribute-set.cjs"
42
42
  },
43
- "./dist/*": "./dist/*",
44
- "./dist/hd-attribute-set.css": "./dist/hd-attribute-set.css"
43
+ "./utils": {
44
+ "types": "./dist/utils.d.ts",
45
+ "import": "./dist/utils.js",
46
+ "require": "./dist/utils.cjs"
47
+ },
48
+ "./hooks": {
49
+ "types": "./dist/hooks.d.ts",
50
+ "import": "./dist/hooks.js",
51
+ "require": "./dist/hooks.cjs"
52
+ },
53
+ "./dist/*": "./dist/*"
54
+ },
55
+ "typesVersions": {
56
+ "*": {
57
+ "utils": [
58
+ "./dist/utils.d.ts"
59
+ ],
60
+ "hooks": [
61
+ "./dist/hooks.d.ts"
62
+ ]
63
+ }
45
64
  },
46
65
  "scripts": {
47
66
  "dev": "vite",
@@ -57,6 +76,7 @@
57
76
  "devDependencies": {
58
77
  "@types/react": "^18.3.0",
59
78
  "@types/react-dom": "^18.3.0",
79
+ "@types/node": "^20.14.0",
60
80
  "@vitejs/plugin-react": "^4.3.0",
61
81
  "antd": "^5.21.0",
62
82
  "less": "^4.2.0",
@@ -66,4 +86,4 @@
66
86
  "vite": "^5.4.0",
67
87
  "vite-plugin-dts": "^4.2.0"
68
88
  }
69
- }
89
+ }
package/readme.md ADDED
@@ -0,0 +1,113 @@
1
+ # hd-attribute-set
2
+
3
+ 基于 **TypeScript** 的工具/组件库,使用 Vite 库模式构建,通过 [CNB 云原生构建](https://docs.cnb.cool/) 自动发布到 npm。
4
+
5
+ ## 目录结构
6
+
7
+ ```
8
+ ├── .cnb.yml # CNB 云原生构建流水线配置
9
+ ├── index.html # 本地调试入口(playground)
10
+ ├── src
11
+ │ ├── index.ts # 包主入口(构建产物入口)
12
+ │ ├── App.tsx / main.tsx # 调试页面
13
+ │ ├── utils # 公共工具方法(多文件)
14
+ │ │ ├── index.ts # 统一出口(barrel)
15
+ │ │ ├── format.ts
16
+ │ │ ├── validate.ts
17
+ │ │ ├── object.ts
18
+ │ │ └── fn.ts
19
+ │ └── hooks # 业务 Hook(解耦后版本)
20
+ │ ├── index.ts
21
+ │ ├── use-btn-deal.ts
22
+ │ ├── use-permission.ts
23
+ │ ├── use-row-selection.ts
24
+ │ └── use-memoized-fn.ts
25
+ ├── vite.config.ts # Vite 配置(lib 模式,多入口)
26
+ └── tsconfig.json
27
+ ```
28
+
29
+ ## 本地开发
30
+
31
+ ```bash
32
+ npm install
33
+ npm run dev # 启动 playground 调试
34
+ npm run build # 构建产物到 dist/
35
+ npm pack --dry-run # 查看将要发布到 npm 的文件清单
36
+ ```
37
+
38
+ ## 新增工具方法
39
+
40
+ 1. 在 `src/utils/` 下新建文件(如 `string.ts`)并 `export` 方法;
41
+ 2. 在 `src/utils/index.ts` 加一行 `export * from './string';`;
42
+ 3. `npm run build`,新方法即自动出现在包根路径与 `hd-attribute-set/utils` 两个入口。
43
+
44
+ ## 在其他项目中使用
45
+
46
+ 安装:
47
+
48
+ ```bash
49
+ npm i hd-attribute-set
50
+ ```
51
+
52
+ 引入方式(三个入口,按需选择):
53
+
54
+ ```ts
55
+ // 1. 根路径:通用工具
56
+ import { formatMoney, version } from 'hd-attribute-set';
57
+
58
+ // 2. utils 子路径
59
+ import { isEmail, listToTree } from 'hd-attribute-set/utils';
60
+
61
+ // 3. hooks 子路径(已对权限/按钮/表格做解耦,可与任意数据源配合)
62
+ import { useBtnDeal, usePermission, useRowSelection } from 'hd-attribute-set/hooks';
63
+ ```
64
+
65
+ CommonJS 环境:
66
+
67
+ ```js
68
+ const { formatMoney } = require('hd-attribute-set');
69
+ const { isPhone } = require('hd-attribute-set/utils');
70
+ const { useBtnDeal } = require('hd-attribute-set/hooks');
71
+ ```
72
+
73
+ ### hooks 用法示例
74
+
75
+ > 所有 hooks 都已与 Redux/ahooks 解耦,权限数据通过 `getAccessConfig` 注入。
76
+
77
+ ```tsx
78
+ import { useSelector } from 'react-redux';
79
+ import { useBtnDeal, usePermission } from 'hd-attribute-set/hooks';
80
+
81
+ // 接 Redux
82
+ const access = useSelector(s => s.auth.accessConfig);
83
+ const { controlShowStatus } = useBtnDeal(() => access);
84
+ // 或接任意数据源
85
+ const { hasPermission } = usePermission(() => ({ noPermissionShow: true, list: [], selectAll: true }));
86
+
87
+ const [editVisible, editBtn] = controlShowStatus({
88
+ type: 'edit',
89
+ detail: rowData,
90
+ configBtns: btnConfigs, // 来自后端/配置的按钮列表
91
+ });
92
+ {editVisible && <Button {...editBtn}>编辑</Button>}
93
+ ```
94
+
95
+ ## 发布到 npm(云原生构建)
96
+
97
+ 1. 在 npmjs.com 生成 Access Token(Classic Token 选 **Automation**,或 Granular Token 勾选 **Read and write**)。
98
+ 2. 在 CNB 仓库设置中配置环境变量 `NPM_TOKEN`(或放入密钥仓库,并在 `.cnb.yml` 的 `tag_push` 中增加 `imports` 指向密钥仓库)。
99
+ 3. push 到 `main` 分支会自动执行安装 + 构建校验;发布正式版时推送 tag:
100
+
101
+ ```bash
102
+ npm version patch # 0.1.0 -> 0.1.1,自动提交 tag
103
+ git push origin main --tags
104
+ ```
105
+
106
+ 流水线将自动构建并执行 `npm publish`(`prepublishOnly` 也会兜底执行构建)。
107
+
108
+ ## 发布前检查清单
109
+
110
+ - [ ] `package.json` 的 `version` 已升版(与 tag 一致)。
111
+ - [ ] `npm run build` 通过,`dist` 含 `hd-attribute-set.js/.cjs`、`utils.js/.cjs` 及对应 `.d.ts`。
112
+ - [ ] `npm pack --dry-run` 中仅包含 `dist` 与 `README.md`,无源码泄露。
113
+ - [ ] 如使用了组件,需确认使用方已安装 `antd`(peer 依赖,不打包进产物)。
package/README.md DELETED
@@ -1,62 +0,0 @@
1
- # hd-attribute-set
2
-
3
- 基于 **React + TypeScript + antd** 的属性集组件库,使用 Vite 库模式构建,通过 [CNB 云原生构建](https://docs.cnb.cool/) 自动发布到 npm。
4
-
5
- ## 目录结构
6
-
7
- ```
8
- ├── .cnb.yml # CNB 云原生构建流水线配置
9
- ├── index.html # 本地调试入口(playground)
10
- ├── src
11
- │ ├── index.ts # 组件库入口(构建产物入口)
12
- │ ├── App.tsx # 调试页面
13
- │ ├── main.tsx # 调试页面挂载入口
14
- │ └── components
15
- │ └── attribute-set # 属性集组件(antd)
16
- ├── vite.config.ts # Vite 配置(lib 模式)
17
- └── tsconfig.json
18
- ```
19
-
20
- ## 本地开发
21
-
22
- ```bash
23
- npm install
24
- npm run dev # 启动 playground 调试组件
25
- npm run build # 构建产物到 dist/(ESM + UMD + CSS + 类型声明)
26
- npm pack --dry-run # 查看将要发布到 npm 的文件清单
27
- ```
28
-
29
- ## 使用示例
30
-
31
- ```tsx
32
- import { AttributeSet } from 'hd-attribute-set';
33
- import 'hd-attribute-set/dist/hd-attribute-set.css';
34
-
35
- <AttributeSet
36
- title="基础属性"
37
- items={[
38
- { key: 'cpu', label: 'CPU', value: '8 核' },
39
- { key: 'memory', label: '内存', value: '16 GB' },
40
- ]}
41
- />
42
- ```
43
-
44
- ## 发布到 npm(云原生构建)
45
-
46
- 1. 在 npmjs.com 生成 Access Token。
47
- 2. 在 CNB 仓库设置中配置环境变量 `NPM_TOKEN`(或放入密钥仓库,并在 `.cnb.yml` 的 `tag_push` 中增加 `imports` 指向密钥仓库)。
48
- 3. push 到 `main` 分支会自动执行安装 + 构建校验;发布正式版时推送 tag:
49
-
50
- ```bash
51
- npm version patch # 0.1.0 -> 0.1.1,自动提交 tag
52
- git push origin main --tags
53
- ```
54
-
55
- 流水线将自动构建并执行 `npm publish`(`prepublishOnly` 也会兜底执行构建)。
56
-
57
- ## 发布前检查清单
58
-
59
- - [ ] `package.json` 的 `version` 已升版(与 tag 一致)。
60
- - [ ] `npm run build` 通过,`dist` 含 `hd-attribute-set.js`、`hd-attribute-set.umd.cjs`、`hd-attribute-set.css`、`index.d.ts`。
61
- - [ ] `npm pack --dry-run` 中仅包含 `dist` 与 `README.md`,无源码泄露。
62
- - [ ] 使用方已安装 `antd`(peer 依赖,不在包内打包)。
@@ -1,7 +0,0 @@
1
- import { AttributeItem, AttributeSetProps } from './types';
2
- export type { AttributeItem, AttributeSetProps };
3
- /**
4
- * 属性集组件:以 antd Descriptions 展示一组键值属性
5
- */
6
- export declare function AttributeSet({ items, title, column, bordered, emptyText }: AttributeSetProps): import("react").JSX.Element;
7
- export default AttributeSet;
@@ -1,27 +0,0 @@
1
- import { ReactNode } from 'react';
2
- /** 单个属性项 */
3
- export interface AttributeItem {
4
- /** 唯一标识 */
5
- key: string;
6
- /** 属性名 */
7
- label: ReactNode;
8
- /** 属性值 */
9
- value?: ReactNode;
10
- /** 自定义渲染 */
11
- render?: (value?: ReactNode) => ReactNode;
12
- /** Descriptions 的栅格跨度 */
13
- span?: number;
14
- }
15
- /** AttributeSet 组件属性 */
16
- export interface AttributeSetProps {
17
- /** 属性集标题 */
18
- title?: ReactNode;
19
- /** 属性项列表 */
20
- items: AttributeItem[];
21
- /** 每行列数,默认 2 */
22
- column?: number;
23
- /** 是否显示边框,默认 true */
24
- bordered?: boolean;
25
- /** 空数据提示文案 */
26
- emptyText?: string;
27
- }
@@ -1 +0,0 @@
1
- .hd-attribute-set__title{font-size:16px;font-weight:600}
@@ -1 +0,0 @@
1
- (function(r,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("react/jsx-runtime"),require("antd")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","antd"],e):(r=typeof globalThis<"u"?globalThis:r||self,e(r.HdAttributeSet={},r.jsxRuntime,r.antd))})(this,function(r,e,s){"use strict";function n({items:d,title:i,column:l=2,bordered:c=!0,emptyText:p="暂无属性"}){return!d||d.length===0?e.jsxs("div",{className:"hd-attribute-set",children:[i&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"hd-attribute-set__title",children:i}),e.jsx(s.Divider,{style:{margin:"8px 0 16px"}})]}),e.jsx(s.Empty,{image:s.Empty.PRESENTED_IMAGE_SIMPLE,description:p})]}):e.jsxs("div",{className:"hd-attribute-set",children:[i&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"hd-attribute-set__title",children:i}),e.jsx(s.Divider,{style:{margin:"8px 0 16px"}})]}),e.jsx(s.Descriptions,{size:"small",column:l,bordered:c,items:d.map(t=>({key:t.key,label:t.label,children:t.render?t.render(t.value):t.value??"-",span:t.span}))})]})}const a="0.1.0";r.AttributeSet=n,r.version=a,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})});