@king26/wk-react-tools 1.0.0

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,3 @@
1
+ export * from './react';
2
+ export * from './zustand';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./react"), exports);
18
+ __exportStar(require("./zustand"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,4CAA0B"}
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import type { ReactNode } from "react";
3
+ interface ForEachProps<T = unknown> {
4
+ of: T[];
5
+ children: (item: T, index: number) => ReactNode;
6
+ default?: ReactNode;
7
+ keyExtractor?: (item: T, index: number) => string | number;
8
+ }
9
+ export declare function ForEach<T = unknown>({ of: items, children: render, default: defaultChild, keyExtractor, }: ForEachProps<T>): string | number | boolean | Iterable<React.ReactNode> | import("react/jsx-runtime").JSX.Element | null;
10
+ export declare function forEachExample(): import("react/jsx-runtime").JSX.Element;
11
+ export {};
12
+ //# sourceMappingURL=forEach.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forEach.d.ts","sourceRoot":"","sources":["../../src/react/forEach.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,UAAU,YAAY,CAAC,CAAC,GAAG,OAAO;IAChC,EAAE,EAAE,CAAC,EAAE,CAAC;IACR,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IAChD,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,MAAM,CAAC;CAC5D;AAED,wBAAgB,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,EACnC,EAAE,EAAE,KAAK,EACT,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EACrB,YAAkC,GACnC,EAAE,YAAY,CAAC,CAAC,CAAC,0GAcjB;AAED,wBAAgB,cAAc,4CAY7B"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ForEach = ForEach;
7
+ exports.forEachExample = forEachExample;
8
+ const jsx_runtime_1 = require("react/jsx-runtime");
9
+ const react_1 = __importDefault(require("react"));
10
+ function ForEach({ of: items, children: render, default: defaultChild, keyExtractor = (_, index) => index, }) {
11
+ if (!Array.isArray(items) || items.length === 0) {
12
+ return defaultChild ?? null;
13
+ }
14
+ return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: items.map((item, index) => ((0, jsx_runtime_1.jsx)(react_1.default.Fragment, { children: render(item, index) }, keyExtractor(item, index)))) }));
15
+ }
16
+ function forEachExample() {
17
+ const items = ["Apple", "Banana", "Cherry"];
18
+ return ((0, jsx_runtime_1.jsx)(ForEach, { of: items, default: (0, jsx_runtime_1.jsx)("div", { children: "No items" }), children: (item, index) => ((0, jsx_runtime_1.jsxs)("div", { children: [index + 1, ". ", item] }, item)) }));
19
+ }
20
+ //# sourceMappingURL=forEach.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forEach.js","sourceRoot":"","sources":["../../src/react/forEach.tsx"],"names":[],"mappings":";;;;;AAUA,0BAmBC;AAED,wCAYC;;AA3CD,kDAA0B;AAU1B,SAAgB,OAAO,CAAc,EACnC,EAAE,EAAE,KAAK,EACT,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,EACrB,YAAY,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,GAClB;IAChB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAChD,OAAO,YAAY,IAAI,IAAI,CAAC;IAC9B,CAAC;IAED,OAAO,CACL,2DACG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAC1B,uBAAC,eAAK,CAAC,QAAQ,cACZ,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IADD,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,CAE7B,CAClB,CAAC,GACD,CACJ,CAAC;AACJ,CAAC;AAED,SAAgB,cAAc;IAC5B,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAE5C,OAAO,CACL,uBAAC,OAAO,IAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,uDAAmB,YAC7C,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,CAChB,4CACG,KAAK,GAAG,CAAC,QAAI,IAAI,KADV,IAAI,CAER,CACP,GACO,CACX,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { Switch, Case } from './switch';
2
+ export { ForEach } from './forEach';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ForEach = exports.Case = exports.Switch = void 0;
4
+ var switch_1 = require("./switch");
5
+ Object.defineProperty(exports, "Switch", { enumerable: true, get: function () { return switch_1.Switch; } });
6
+ Object.defineProperty(exports, "Case", { enumerable: true, get: function () { return switch_1.Case; } });
7
+ var forEach_1 = require("./forEach");
8
+ Object.defineProperty(exports, "ForEach", { enumerable: true, get: function () { return forEach_1.ForEach; } });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":";;;AAAA,mCAAwC;AAA/B,gGAAA,MAAM,OAAA;AAAE,8FAAA,IAAI,OAAA;AACrB,qCAAoC;AAA3B,kGAAA,OAAO,OAAA"}
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import type { ReactNode } from 'react';
3
+ declare const CASE_TYPE: unique symbol;
4
+ interface SwitchProps {
5
+ condition: unknown;
6
+ children: ReactNode;
7
+ default?: ReactNode;
8
+ }
9
+ interface CaseProps {
10
+ when: unknown;
11
+ children: ReactNode;
12
+ }
13
+ interface CaseComponent extends React.FC<CaseProps> {
14
+ type: typeof CASE_TYPE;
15
+ }
16
+ export declare const Case: CaseComponent;
17
+ export declare function Switch({ condition, children, default: defaultChild }: SwitchProps): React.ReactNode;
18
+ export declare function example(): import("react/jsx-runtime").JSX.Element;
19
+ export {};
20
+ //# sourceMappingURL=switch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.d.ts","sourceRoot":"","sources":["../../src/react/switch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,OAAO,CAAC;AAErC,QAAA,MAAM,SAAS,eAA6B,CAAC;AAE7C,UAAU,WAAW;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;IACpB,OAAO,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,UAAU,SAAS;IACf,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,SAAS,CAAC;CACvB;AAED,UAAU,aAAc,SAAQ,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC;IAC/C,IAAI,EAAE,OAAO,SAAS,CAAC;CAC1B;AAED,eAAO,MAAM,IAAI,EAAE,aAA0C,CAAC;AAG9D,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,WAAW,mBAiBjF;AAED,wBAAgB,OAAO,4CAatB"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Case = void 0;
7
+ exports.Switch = Switch;
8
+ exports.example = example;
9
+ const jsx_runtime_1 = require("react/jsx-runtime");
10
+ const react_1 = __importDefault(require("react"));
11
+ const CASE_TYPE = Symbol.for('@switch/case');
12
+ const Case = ({ children }) => children;
13
+ exports.Case = Case;
14
+ exports.Case.type = CASE_TYPE;
15
+ function Switch({ condition, children, default: defaultChild }) {
16
+ const childrenArray = react_1.default.Children.toArray(children);
17
+ const matchedCase = childrenArray.find((child) => {
18
+ if (!react_1.default.isValidElement(child))
19
+ return false;
20
+ const elementType = child.type;
21
+ if (elementType.type !== CASE_TYPE)
22
+ return false;
23
+ const caseValue = child.props.when;
24
+ return caseValue === condition;
25
+ });
26
+ if (matchedCase) {
27
+ return matchedCase.props.children;
28
+ }
29
+ return defaultChild ?? null;
30
+ }
31
+ function example() {
32
+ const value = 5;
33
+ return ((0, jsx_runtime_1.jsxs)(Switch, { condition: value, default: (0, jsx_runtime_1.jsx)("div", { children: "Default case" }), children: [(0, jsx_runtime_1.jsx)(exports.Case, { when: 5, children: (0, jsx_runtime_1.jsx)("div", { children: "Case 1" }) }), (0, jsx_runtime_1.jsx)(exports.Case, { when: 4, children: (0, jsx_runtime_1.jsx)("div", { children: "Case 2" }) })] }));
34
+ }
35
+ //# sourceMappingURL=switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switch.js","sourceRoot":"","sources":["../../src/react/switch.tsx"],"names":[],"mappings":";;;;;;AAuBA,wBAiBC;AAED,0BAaC;;AAvDD,kDAA0B;AAG1B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;AAiBtC,MAAM,IAAI,GAAkB,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC;AAAjD,QAAA,IAAI,QAA6C;AAC9D,YAAI,CAAC,IAAI,GAAG,SAAS,CAAC;AAEtB,SAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAe;IAC9E,MAAM,aAAa,GAAG,eAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEvD,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;QAC7C,IAAI,CAAC,eAAK,CAAC,cAAc,CAAC,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC/C,MAAM,WAAW,GAAG,KAAK,CAAC,IAAqB,CAAC;QAChD,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAEjD,MAAM,SAAS,GAAI,KAAuC,CAAC,KAAK,CAAC,IAAI,CAAC;QACtE,OAAO,SAAS,KAAK,SAAS,CAAC;IACnC,CAAC,CAA8C,CAAC;IAEhD,IAAI,WAAW,EAAE,CAAC;QACd,OAAO,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC;IACtC,CAAC;IAED,OAAO,YAAY,IAAI,IAAI,CAAC;AAChC,CAAC;AAED,SAAgB,OAAO;IACnB,MAAM,KAAK,GAAG,CAAC,CAAC;IAEhB,OAAO,CACH,wBAAC,MAAM,IAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,2DAAuB,aACtD,uBAAC,YAAI,IAAC,IAAI,EAAE,CAAC,YACT,qDAAiB,GACd,EACP,uBAAC,YAAI,IAAC,IAAI,EAAE,CAAC,YACT,qDAAiB,GACd,IACF,CACZ,CAAC;AACN,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { StateCreator } from 'zustand';
2
+ import type { DevtoolsOptions, PersistOptions, PersistStorage } from 'zustand/middleware';
3
+ export declare function createBox<T extends object>(config: {
4
+ name: string;
5
+ storeCreator: StateCreator<T, [['zustand/immer', never]], [], T>;
6
+ /**
7
+ * Persist 配置
8
+ * - 如果为 false,则跳过持久化
9
+ * - 如果为字符串 'localStorage' 或 'sessionStorage',则使用对应的存储
10
+ * - 如果为对象,则使用完整的 persist 配置
11
+ * - storage 可以是 'localStorage' | 'sessionStorage' 或自定义的 PersistStorage 实现
12
+ * - partialize 的返回类型会自动推断为 PersistedState,无需手动指定第二个泛型参数
13
+ */
14
+ persist?: false | 'localStorage' | 'sessionStorage' | (Omit<PersistOptions<T, unknown>, 'name' | 'storage'> & {
15
+ storage?: 'localStorage' | 'sessionStorage' | PersistStorage<any>;
16
+ });
17
+ /**
18
+ * Devtools 配置
19
+ * 如果为 false,则禁用 devtools
20
+ * 如果为对象,则使用完整的 devtools 配置(name 会自动设置)
21
+ */
22
+ devtools?: boolean | Omit<DevtoolsOptions, 'name'>;
23
+ }): import("zustand").UseBoundStore<import("zustand").StoreApi<T>>;
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/zustand/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAC3C,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EACd,cAAc,EACf,MAAM,oBAAoB,CAAA;AA+G3B,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,YAAY,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;IAChE;;;;;;;OAOG;IACH,OAAO,CAAC,EACJ,KAAK,GACL,cAAc,GACd,gBAAgB,GAChB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG;QACtD,OAAO,CAAC,EAAE,cAAc,GAAG,gBAAgB,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;KAClE,CAAC,CAAA;IACN;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,CAAA;CACnD,kEA6DA"}
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBox = createBox;
4
+ const middleware_1 = require("zustand/middleware");
5
+ const immer_1 = require("zustand/middleware/immer");
6
+ const react_1 = require("zustand/react");
7
+ // 辅助函数:生成 storage key
8
+ function generateStorageKey(name) {
9
+ return name
10
+ .replace(/([A-Z])/g, '-$1')
11
+ .toLowerCase()
12
+ .replace(/^-/, '')
13
+ .concat('-storage');
14
+ }
15
+ // 辅助函数:创建 storage
16
+ function createStorage(storageType) {
17
+ if (typeof storageType === 'string') {
18
+ return (0, middleware_1.createJSONStorage)(() => storageType === 'localStorage' ? localStorage : sessionStorage);
19
+ }
20
+ if (storageType) {
21
+ return storageType;
22
+ }
23
+ // 默认使用 sessionStorage
24
+ return (0, middleware_1.createJSONStorage)(() => sessionStorage);
25
+ }
26
+ function createBox(config) {
27
+ const { name, storeCreator, persist: persistConfig, devtools: devtoolsConfig = true, } = config;
28
+ // 自动生成 storage key
29
+ const storageKey = generateStorageKey(name);
30
+ // 创建基础 store(应用 immer)
31
+ const baseStore = (0, immer_1.immer)(storeCreator);
32
+ // 应用 persist(如果启用)
33
+ // 注意:使用 any 是因为中间件组合会导致复杂的类型,这是 zustand 的类型系统限制
34
+ let storeWithPersist = baseStore;
35
+ if (persistConfig !== false && persistConfig !== undefined) {
36
+ let persistOptions;
37
+ if (typeof persistConfig === 'string') {
38
+ // 简化配置:使用字符串指定存储类型
39
+ const persistStorage = createStorage(persistConfig);
40
+ persistOptions = {
41
+ name: storageKey,
42
+ storage: persistStorage,
43
+ };
44
+ }
45
+ else {
46
+ // 完整配置:处理 storage 选项
47
+ const { storage, ...restOptions } = persistConfig;
48
+ const persistStorage = createStorage(storage);
49
+ // 构建完整的 persist 配置
50
+ persistOptions = {
51
+ name: storageKey,
52
+ storage: persistStorage,
53
+ ...restOptions,
54
+ };
55
+ }
56
+ storeWithPersist = (0, middleware_1.persist)(baseStore, persistOptions);
57
+ }
58
+ // 应用 devtools(如果启用)
59
+ let finalStore = storeWithPersist;
60
+ if (devtoolsConfig !== false) {
61
+ const devtoolsOptions = {
62
+ name,
63
+ enabled: true,
64
+ ...(typeof devtoolsConfig === 'object' && devtoolsConfig),
65
+ };
66
+ finalStore = (0, middleware_1.devtools)(storeWithPersist, devtoolsOptions);
67
+ }
68
+ return (0, react_1.create)()(finalStore);
69
+ }
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/zustand/index.ts"],"names":[],"mappings":";;AAuHA,8BAqFC;AA5MD,mDAAyE;AACzE,oDAAgD;AAChD,yCAAsC;AAwFtC,sBAAsB;AACtB,SAAS,kBAAkB,CAAC,IAAY;IACtC,OAAO,IAAI;SACR,OAAO,CAAC,UAAU,EAAE,KAAK,CAAC;SAC1B,WAAW,EAAE;SACb,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;SACjB,MAAM,CAAC,UAAU,CAAC,CAAA;AACvB,CAAC;AAED,kBAAkB;AAClB,SAAS,aAAa,CACpB,WAIa;IAEb,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,IAAA,8BAAiB,EAAC,GAAG,EAAE,CAC5B,WAAW,KAAK,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAC1C,CAAA;IACxB,CAAC;IACD,IAAI,WAAW,EAAE,CAAC;QAChB,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,sBAAsB;IACtB,OAAO,IAAA,8BAAiB,EAAC,GAAG,EAAE,CAAC,cAAc,CAAsB,CAAA;AACrE,CAAC;AAED,SAAgB,SAAS,CAAmB,MAwB3C;IACC,MAAM,EACJ,IAAI,EACJ,YAAY,EACZ,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,cAAc,GAAG,IAAI,GAChC,GAAG,MAAM,CAAA;IAEV,mBAAmB;IACnB,MAAM,UAAU,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAE3C,uBAAuB;IACvB,MAAM,SAAS,GAAG,IAAA,aAAK,EAAI,YAAY,CAAC,CAAA;IAExC,mBAAmB;IACnB,gDAAgD;IAChD,IAAI,gBAAgB,GAAQ,SAAS,CAAA;IACrC,IAAI,aAAa,KAAK,KAAK,IAAI,aAAa,KAAK,SAAS,EAAE,CAAC;QAI3D,IAAI,cAAyD,CAAA;QAE7D,IAAI,OAAO,aAAa,KAAK,QAAQ,EAAE,CAAC;YACtC,mBAAmB;YACnB,MAAM,cAAc,GAClB,aAAa,CAAyB,aAAa,CAAC,CAAA;YACtD,cAAc,GAAG;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,cAAc;aACxB,CAAA;QACH,CAAC;aAAM,CAAC;YACN,qBAAqB;YACrB,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,EAAE,GAAG,aAAa,CAAA;YACjD,MAAM,cAAc,GAAG,aAAa,CAClC,OAAc,CACf,CAAA;YAED,mBAAmB;YACnB,cAAc,GAAG;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,cAAc;gBACvB,GAAG,WAAW;aAC8B,CAAA;QAChD,CAAC;QAED,gBAAgB,GAAG,IAAA,oBAAO,EAAC,SAAS,EAAE,cAAc,CAAC,CAAA;IACvD,CAAC;IAED,oBAAoB;IACpB,IAAI,UAAU,GAAQ,gBAAgB,CAAA;IACtC,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;QAC7B,MAAM,eAAe,GAAoB;YACvC,IAAI;YACJ,OAAO,EAAE,IAAI;YACb,GAAG,CAAC,OAAO,cAAc,KAAK,QAAQ,IAAI,cAAc,CAAC;SAC1D,CAAA;QACD,UAAU,GAAG,IAAA,qBAAQ,EAAC,gBAAgB,EAAE,eAAe,CAAC,CAAA;IAC1D,CAAC;IAED,OAAO,IAAA,cAAM,GAAK,CAAC,UAAU,CAAC,CAAA;AAChC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@king26/wk-react-tools",
3
+ "version": "1.0.0",
4
+ "description": "React 简化工具包",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./react": {
15
+ "import": "./dist/react/index.js",
16
+ "require": "./dist/react/index.js",
17
+ "types": "./dist/react/index.d.ts"
18
+ },
19
+ "./zustand": {
20
+ "import": "./dist/zustand/index.js",
21
+ "require": "./dist/zustand/index.js",
22
+ "types": "./dist/zustand/index.d.ts"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc",
27
+ "clean": "rm -rf dist",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "keywords": [
31
+ "react",
32
+ "tools",
33
+ "zustand",
34
+ "switch"
35
+ ],
36
+ "author": "zwking",
37
+ "license": "MIT",
38
+ "files": [
39
+ "dist",
40
+ "src"
41
+ ],
42
+ "peerDependencies": {
43
+ "react": "^18.0.0",
44
+ "zustand": "^4.0.0"
45
+ },
46
+ "devDependencies": {
47
+ "@types/react": "^18.0.0",
48
+ "typescript": "^5.0.0"
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './react';
2
+ export * from './zustand';
@@ -0,0 +1,44 @@
1
+ import React from "react";
2
+ import type { ReactNode } from "react";
3
+
4
+ interface ForEachProps<T = unknown> {
5
+ of: T[];
6
+ children: (item: T, index: number) => ReactNode;
7
+ default?: ReactNode;
8
+ keyExtractor?: (item: T, index: number) => string | number;
9
+ }
10
+
11
+ export function ForEach<T = unknown>({
12
+ of: items,
13
+ children: render,
14
+ default: defaultChild,
15
+ keyExtractor = (_, index) => index,
16
+ }: ForEachProps<T>) {
17
+ if (!Array.isArray(items) || items.length === 0) {
18
+ return defaultChild ?? null;
19
+ }
20
+
21
+ return (
22
+ <>
23
+ {items.map((item, index) => (
24
+ <React.Fragment key={keyExtractor(item, index)}>
25
+ {render(item, index)}
26
+ </React.Fragment>
27
+ ))}
28
+ </>
29
+ );
30
+ }
31
+
32
+ export function forEachExample() {
33
+ const items = ["Apple", "Banana", "Cherry"];
34
+
35
+ return (
36
+ <ForEach of={items} default={<div>No items</div>}>
37
+ {(item, index) => (
38
+ <div key={item}>
39
+ {index + 1}. {item}
40
+ </div>
41
+ )}
42
+ </ForEach>
43
+ );
44
+ }
@@ -0,0 +1,2 @@
1
+ export { Switch, Case } from './switch';
2
+ export { ForEach } from './forEach';
@@ -0,0 +1,56 @@
1
+ import React from 'react';
2
+ import type {ReactNode} from 'react';
3
+
4
+ const CASE_TYPE = Symbol.for('@switch/case');
5
+
6
+ interface SwitchProps {
7
+ condition: unknown;
8
+ children: ReactNode;
9
+ default?: ReactNode;
10
+ }
11
+
12
+ interface CaseProps {
13
+ when: unknown;
14
+ children: ReactNode;
15
+ }
16
+
17
+ interface CaseComponent extends React.FC<CaseProps> {
18
+ type: typeof CASE_TYPE;
19
+ }
20
+
21
+ export const Case: CaseComponent = ({ children }) => children;
22
+ Case.type = CASE_TYPE;
23
+
24
+ export function Switch({ condition, children, default: defaultChild }: SwitchProps) {
25
+ const childrenArray = React.Children.toArray(children);
26
+
27
+ const matchedCase = childrenArray.find((child) => {
28
+ if (!React.isValidElement(child)) return false;
29
+ const elementType = child.type as CaseComponent;
30
+ if (elementType.type !== CASE_TYPE) return false;
31
+
32
+ const caseValue = (child as React.ReactElement<CaseProps>).props.when;
33
+ return caseValue === condition;
34
+ }) as React.ReactElement<CaseProps> | undefined;
35
+
36
+ if (matchedCase) {
37
+ return matchedCase.props.children;
38
+ }
39
+
40
+ return defaultChild ?? null;
41
+ }
42
+
43
+ export function example() {
44
+ const value = 5;
45
+
46
+ return (
47
+ <Switch condition={value} default={<div>Default case</div>}>
48
+ <Case when={5}>
49
+ <div>Case 1</div>
50
+ </Case>
51
+ <Case when={4}>
52
+ <div>Case 2</div>
53
+ </Case>
54
+ </Switch>
55
+ );
56
+ }
@@ -0,0 +1,205 @@
1
+ import { createJSONStorage, devtools, persist } from 'zustand/middleware'
2
+ import { immer } from 'zustand/middleware/immer'
3
+ import { create } from 'zustand/react'
4
+ import type { StateCreator } from 'zustand'
5
+ import type {
6
+ DevtoolsOptions,
7
+ PersistOptions,
8
+ PersistStorage,
9
+ } from 'zustand/middleware'
10
+
11
+ /**
12
+ * 约定大于配置的 Store 创建函数
13
+ * 自动应用 immer、persist、devtools 中间件
14
+ *
15
+ * @example
16
+ * // 基础用法 - 只需提供 store 名称和初始状态
17
+ * const useStore = createBox<UserStore>({
18
+ * name: 'UserStore',
19
+ * storeCreator: (set, get) => ({
20
+ * name: '',
21
+ * setName: (name: string) => set({ name }),
22
+ * }),
23
+ * })
24
+ *
25
+ * @example
26
+ * // 简化配置 - 使用字符串指定存储类型
27
+ * const useStore = createBox<UserStore>({
28
+ * name: 'UserStore',
29
+ * storeCreator: (set, get) => ({
30
+ * name: '',
31
+ * setName: (name: string) => set({ name }),
32
+ * }),
33
+ * persist: 'localStorage', // 或 'sessionStorage' (默认)
34
+ * })
35
+ *
36
+ * @example
37
+ * // 完整配置 - 支持所有 persist 和 devtools 选项
38
+ * const useStore = createBox<UserStore>({
39
+ * name: 'UserStore',
40
+ * storeCreator: (set, get) => ({
41
+ * name: '',
42
+ * setName: (name: string) => set({ name }),
43
+ * }),
44
+ * persist: {
45
+ * storage: 'localStorage',
46
+ * partialize: (state) => ({ name: state.name }),
47
+ * version: 1,
48
+ * migrate: (persistedState, version) => ({ ...persistedState, version }),
49
+ * },
50
+ * devtools: {
51
+ * enabled: true,
52
+ * anonymousActionType: 'anonymous',
53
+ * },
54
+ * })
55
+ *
56
+ * @example
57
+ * // 自定义存储 - 使用自定义的 PersistStorage 实现
58
+ * const customStorage: PersistStorage<UserStore> = {
59
+ * getItem: (name) => {
60
+ * // 自定义获取逻辑
61
+ * const str = localStorage.getItem(name)
62
+ * return str ? JSON.parse(str) : null
63
+ * },
64
+ * setItem: (name, value) => {
65
+ * // 自定义存储逻辑
66
+ * localStorage.setItem(name, JSON.stringify(value))
67
+ * },
68
+ * removeItem: (name) => {
69
+ * localStorage.removeItem(name)
70
+ * },
71
+ * }
72
+ * const useStore = createBox<UserStore>({
73
+ * name: 'UserStore',
74
+ * storeCreator: (set, get) => ({
75
+ * name: '',
76
+ * setName: (name: string) => set({ name }),
77
+ * }),
78
+ * persist: {
79
+ * storage: customStorage, // 使用自定义存储
80
+ * },
81
+ * })
82
+ */
83
+ // 辅助类型:从 persist 配置中提取 PersistedState
84
+ // eslint-disable-next-line @typescript-eslint/naming-convention
85
+ type ExtractPersistedState<T, P> = P extends {
86
+ partialize: (state: T) => infer PS
87
+ }
88
+ ? PS
89
+ : T
90
+
91
+ // 辅助函数:生成 storage key
92
+ function generateStorageKey(name: string): string {
93
+ return name
94
+ .replace(/([A-Z])/g, '-$1')
95
+ .toLowerCase()
96
+ .replace(/^-/, '')
97
+ .concat('-storage')
98
+ }
99
+
100
+ // 辅助函数:创建 storage
101
+ function createStorage<T>(
102
+ storageType:
103
+ | 'localStorage'
104
+ | 'sessionStorage'
105
+ | PersistStorage<T>
106
+ | undefined,
107
+ ): PersistStorage<T> {
108
+ if (typeof storageType === 'string') {
109
+ return createJSONStorage(() =>
110
+ storageType === 'localStorage' ? localStorage : sessionStorage,
111
+ ) as PersistStorage<T>
112
+ }
113
+ if (storageType) {
114
+ return storageType
115
+ }
116
+ // 默认使用 sessionStorage
117
+ return createJSONStorage(() => sessionStorage) as PersistStorage<T>
118
+ }
119
+
120
+ export function createBox<T extends object>(config: {
121
+ name: string
122
+ storeCreator: StateCreator<T, [['zustand/immer', never]], [], T>
123
+ /**
124
+ * Persist 配置
125
+ * - 如果为 false,则跳过持久化
126
+ * - 如果为字符串 'localStorage' 或 'sessionStorage',则使用对应的存储
127
+ * - 如果为对象,则使用完整的 persist 配置
128
+ * - storage 可以是 'localStorage' | 'sessionStorage' 或自定义的 PersistStorage 实现
129
+ * - partialize 的返回类型会自动推断为 PersistedState,无需手动指定第二个泛型参数
130
+ */
131
+ persist?:
132
+ | false
133
+ | 'localStorage'
134
+ | 'sessionStorage'
135
+ | (Omit<PersistOptions<T, unknown>, 'name' | 'storage'> & {
136
+ storage?: 'localStorage' | 'sessionStorage' | PersistStorage<any>
137
+ })
138
+ /**
139
+ * Devtools 配置
140
+ * 如果为 false,则禁用 devtools
141
+ * 如果为对象,则使用完整的 devtools 配置(name 会自动设置)
142
+ */
143
+ devtools?: boolean | Omit<DevtoolsOptions, 'name'>
144
+ }) {
145
+ const {
146
+ name,
147
+ storeCreator,
148
+ persist: persistConfig,
149
+ devtools: devtoolsConfig = true,
150
+ } = config
151
+
152
+ // 自动生成 storage key
153
+ const storageKey = generateStorageKey(name)
154
+
155
+ // 创建基础 store(应用 immer)
156
+ const baseStore = immer<T>(storeCreator)
157
+
158
+ // 应用 persist(如果启用)
159
+ // 注意:使用 any 是因为中间件组合会导致复杂的类型,这是 zustand 的类型系统限制
160
+ let storeWithPersist: any = baseStore
161
+ if (persistConfig !== false && persistConfig !== undefined) {
162
+ // 从配置中推断 PersistedState
163
+ type InferredPersistedState = ExtractPersistedState<T, typeof persistConfig>
164
+
165
+ let persistOptions: PersistOptions<T, InferredPersistedState>
166
+
167
+ if (typeof persistConfig === 'string') {
168
+ // 简化配置:使用字符串指定存储类型
169
+ const persistStorage =
170
+ createStorage<InferredPersistedState>(persistConfig)
171
+ persistOptions = {
172
+ name: storageKey,
173
+ storage: persistStorage,
174
+ }
175
+ } else {
176
+ // 完整配置:处理 storage 选项
177
+ const { storage, ...restOptions } = persistConfig
178
+ const persistStorage = createStorage<InferredPersistedState>(
179
+ storage as any,
180
+ )
181
+
182
+ // 构建完整的 persist 配置
183
+ persistOptions = {
184
+ name: storageKey,
185
+ storage: persistStorage,
186
+ ...restOptions,
187
+ } as PersistOptions<T, InferredPersistedState>
188
+ }
189
+
190
+ storeWithPersist = persist(baseStore, persistOptions)
191
+ }
192
+
193
+ // 应用 devtools(如果启用)
194
+ let finalStore: any = storeWithPersist
195
+ if (devtoolsConfig !== false) {
196
+ const devtoolsOptions: DevtoolsOptions = {
197
+ name,
198
+ enabled: true,
199
+ ...(typeof devtoolsConfig === 'object' && devtoolsConfig),
200
+ }
201
+ finalStore = devtools(storeWithPersist, devtoolsOptions)
202
+ }
203
+
204
+ return create<T>()(finalStore)
205
+ }