@kine-design/crud 0.0.1-beta.20 → 0.0.1-beta.23
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.
- package/dist/crud.js +141 -18
- package/package.json +3 -3
- package/setup.ts +12 -11
package/dist/crud.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Comment, Fragment, Teleport, computed, createApp, createTextVNode, createVNode, defineComponent, h, inject, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, reactive, ref, resolveComponent, shallowRef, toRef, triggerRef, watch } from "vue";
|
|
1
|
+
import { Comment, Fragment, Teleport, cloneVNode, computed, createApp, createTextVNode, createVNode, defineComponent, h, inject, isRef, mergeProps, nextTick, onBeforeUnmount, onMounted, onUnmounted, provide, reactive, ref, resolveComponent, shallowRef, toRef, triggerRef, watch } from "vue";
|
|
2
2
|
import { QueryClient, VueQueryPlugin, useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
|
|
3
3
|
import { createPinia, defineStore } from "pinia";
|
|
4
4
|
import { useRoute, useRouter } from "vue-router";
|
|
@@ -283,22 +283,127 @@ function useTable() {
|
|
|
283
283
|
};
|
|
284
284
|
}
|
|
285
285
|
//#endregion
|
|
286
|
-
//#region ../
|
|
286
|
+
//#region ../core/components/template/table/index.ts
|
|
287
287
|
/**
|
|
288
|
-
* @description
|
|
288
|
+
* @description table core 导出
|
|
289
289
|
* @author 阿怪
|
|
290
|
-
* @date 2026/2/
|
|
290
|
+
* @date 2026/2/25
|
|
291
291
|
* @version v1.0.0
|
|
292
292
|
*
|
|
293
293
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
294
294
|
*/
|
|
295
|
-
var
|
|
295
|
+
var TableCore = {
|
|
296
296
|
props: props$10,
|
|
297
297
|
useTable
|
|
298
298
|
};
|
|
299
|
-
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region ../core/compositions/common/testAnchor.ts
|
|
301
|
+
/**
|
|
302
|
+
* @description Test anchor system: provide/inject keys, types, and kDefineComponent wrapper
|
|
303
|
+
* @author kine-design
|
|
304
|
+
* @date 2026/4/28
|
|
305
|
+
* @version v1.0.0
|
|
306
|
+
*
|
|
307
|
+
* Renders business-semantic `data-k` attributes on DOM elements when testAnchor is enabled,
|
|
308
|
+
* allowing E2E tests to target components by stable identifiers.
|
|
309
|
+
*/
|
|
310
|
+
/** Global switch provided by KConfigProvider to enable data-k rendering */
|
|
311
|
+
var K_TEST_ANCHOR_KEY = Symbol("k-test-anchor");
|
|
312
|
+
/** Field identity provided by KFormItem so child inputs inherit field name */
|
|
313
|
+
var K_FIELD_KEY = Symbol("k-field");
|
|
314
|
+
/**
|
|
315
|
+
* Extract text content from a VNode tree (for slotText mode).
|
|
316
|
+
* Walks children recursively, concatenating string segments.
|
|
317
|
+
*/
|
|
318
|
+
function extractSlotText(nodes) {
|
|
319
|
+
if (!nodes) return "";
|
|
320
|
+
let text = "";
|
|
321
|
+
for (const node of nodes) if (typeof node.children === "string") text += node.children;
|
|
322
|
+
else if (Array.isArray(node.children)) text += extractSlotText(node.children);
|
|
323
|
+
return text.trim();
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Resolve the data-k value for a component instance.
|
|
327
|
+
* Returns undefined when testAnchor is off or no identity can be derived.
|
|
328
|
+
*/
|
|
329
|
+
function resolveDataK(config, props, attrs, fieldFromParent, slotNodes) {
|
|
330
|
+
const override = attrs[`k-${config.type}`];
|
|
331
|
+
if (typeof override === "string" && override) return `${config.type}:${override}`;
|
|
332
|
+
if (config.prop) {
|
|
333
|
+
const val = props[config.prop];
|
|
334
|
+
if (typeof val === "string" && val) return `${config.type}:${val}`;
|
|
335
|
+
}
|
|
336
|
+
if (config.slotText && slotNodes) {
|
|
337
|
+
const text = extractSlotText(slotNodes);
|
|
338
|
+
if (text) return `${config.type}:${text}`;
|
|
339
|
+
}
|
|
340
|
+
if (config.slotText && typeof props.text === "string" && props.text) return `${config.type}:${props.text}`;
|
|
341
|
+
if (config.type === "field" && !config.prop && fieldFromParent) return `${config.type}:${fieldFromParent}`;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Inject data-k attribute into a VNode.
|
|
345
|
+
* Uses cloneVNode to avoid mutating the original.
|
|
346
|
+
*/
|
|
347
|
+
function injectDataK(vnode, dataK) {
|
|
348
|
+
return cloneVNode(vnode, { "data-k": dataK });
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Wrapper around Vue's defineComponent that automatically injects `data-k`
|
|
352
|
+
* test anchor attributes when testAnchor is enabled via KConfigProvider.
|
|
353
|
+
*
|
|
354
|
+
* Usage:
|
|
355
|
+
* ```tsx
|
|
356
|
+
* export default kDefineComponent((_props, ctx) => {
|
|
357
|
+
* return () => <div class="k-form-item">...</div>;
|
|
358
|
+
* }, {
|
|
359
|
+
* name: 'KFormItem',
|
|
360
|
+
* props: FormCore.formItemProps,
|
|
361
|
+
* kAnchor: { type: 'field', prop: 'prop' },
|
|
362
|
+
* });
|
|
363
|
+
* ```
|
|
364
|
+
*/
|
|
365
|
+
function kDefineComponent(setup, options) {
|
|
366
|
+
const { kAnchor, ...defineOptions } = options;
|
|
367
|
+
return defineComponent((rawProps, ctx) => {
|
|
368
|
+
const render = setup(rawProps, ctx);
|
|
369
|
+
if (!kAnchor) return render;
|
|
370
|
+
const testAnchor = inject(K_TEST_ANCHOR_KEY, void 0);
|
|
371
|
+
const parentField = kAnchor.type === "field" && !kAnchor.prop ? inject(K_FIELD_KEY, void 0) : void 0;
|
|
372
|
+
return () => {
|
|
373
|
+
const vnode = render();
|
|
374
|
+
if (!testAnchor?.value) return vnode;
|
|
375
|
+
const props = rawProps;
|
|
376
|
+
const slotNodes = kAnchor.slotText ? ctx.slots.default?.() ?? void 0 : void 0;
|
|
377
|
+
const dataK = resolveDataK(kAnchor, props, ctx.attrs, parentField?.value, slotNodes);
|
|
378
|
+
if (!dataK) return vnode;
|
|
379
|
+
if (vnode === null || vnode === void 0) return vnode;
|
|
380
|
+
if (Array.isArray(vnode)) {
|
|
381
|
+
if (vnode.length === 0) return vnode;
|
|
382
|
+
const first = vnode[0];
|
|
383
|
+
if (first && typeof first === "object") return [injectDataK(first, dataK), ...vnode.slice(1)];
|
|
384
|
+
return vnode;
|
|
385
|
+
}
|
|
386
|
+
return injectDataK(vnode, dataK);
|
|
387
|
+
};
|
|
388
|
+
}, defineOptions);
|
|
389
|
+
}
|
|
390
|
+
//#endregion
|
|
391
|
+
//#region ../ui/components/table/KTable.tsx
|
|
392
|
+
/**
|
|
393
|
+
* @description kine-ui table 组件
|
|
394
|
+
* @author 阿怪
|
|
395
|
+
* @date 2026/2/26
|
|
396
|
+
* @version v1.1.0
|
|
397
|
+
*
|
|
398
|
+
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
399
|
+
*
|
|
400
|
+
* v1.1.0 migrate to kDefineComponent for data-k test anchor 2026/4/28
|
|
401
|
+
*/
|
|
402
|
+
var { props: props$9 } = TableCore;
|
|
403
|
+
var KTable_default = kDefineComponent((_props, { slots }) => {
|
|
300
404
|
const p = _props;
|
|
301
405
|
const { initTable } = useTable();
|
|
406
|
+
const testAnchor = inject(K_TEST_ANCHOR_KEY, void 0);
|
|
302
407
|
return () => {
|
|
303
408
|
const columns = [];
|
|
304
409
|
(slots.default?.() ?? []).forEach((s) => {
|
|
@@ -314,6 +419,7 @@ var KTable_default = /* @__PURE__ */ defineComponent((_props, { slots }) => {
|
|
|
314
419
|
empty: createVNode("tbody", { "class": "m-table-empty k-table-empty" }, [createVNode("tr", null, [createVNode("th", { "colspan": columns.length }, [slots.empty?.() ?? "暂无数据"])])]),
|
|
315
420
|
tbodyTr: ({ data, param, slot, style: cellStyle, slotInfo }) => createVNode("td", {
|
|
316
421
|
"style": cellStyle,
|
|
422
|
+
"data-k": testAnchor?.value && param ? `col:${param}` : void 0,
|
|
317
423
|
"class": [
|
|
318
424
|
"m-td",
|
|
319
425
|
"k-td",
|
|
@@ -360,7 +466,11 @@ var KTable_default = /* @__PURE__ */ defineComponent((_props, { slots }) => {
|
|
|
360
466
|
};
|
|
361
467
|
}, {
|
|
362
468
|
name: "KTable",
|
|
363
|
-
props: props$9
|
|
469
|
+
props: props$9,
|
|
470
|
+
kAnchor: {
|
|
471
|
+
type: "table",
|
|
472
|
+
prop: "name"
|
|
473
|
+
}
|
|
364
474
|
});
|
|
365
475
|
//#endregion
|
|
366
476
|
//#region ../core/components/base/input/api.ts
|
|
@@ -7068,11 +7178,13 @@ function useComponentSize(props) {
|
|
|
7068
7178
|
* @description kine-ui button 组件
|
|
7069
7179
|
* @author 阿怪
|
|
7070
7180
|
* @date 2026/2/27
|
|
7071
|
-
* @version v1.
|
|
7181
|
+
* @version v1.2.0
|
|
7072
7182
|
*
|
|
7073
7183
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
7184
|
+
*
|
|
7185
|
+
* v1.2.0 migrate to kDefineComponent for data-k test anchor 2026/4/28
|
|
7074
7186
|
*/
|
|
7075
|
-
var KButton_default =
|
|
7187
|
+
var KButton_default = kDefineComponent((_props, ctx) => {
|
|
7076
7188
|
const props = _props;
|
|
7077
7189
|
const componentSize = useComponentSize(props);
|
|
7078
7190
|
return () => {
|
|
@@ -7095,7 +7207,11 @@ var KButton_default = /* @__PURE__ */ defineComponent((_props, ctx) => {
|
|
|
7095
7207
|
};
|
|
7096
7208
|
}, {
|
|
7097
7209
|
name: "KButton",
|
|
7098
|
-
props: ButtonCore.props
|
|
7210
|
+
props: ButtonCore.props,
|
|
7211
|
+
kAnchor: {
|
|
7212
|
+
type: "action",
|
|
7213
|
+
slotText: true
|
|
7214
|
+
}
|
|
7099
7215
|
});
|
|
7100
7216
|
//#endregion
|
|
7101
7217
|
//#region components/searchTable/KSearchTable.tsx
|
|
@@ -7396,11 +7512,13 @@ var KImage_default = /* @__PURE__ */ defineComponent((_props, { slots, emit }) =
|
|
|
7396
7512
|
* @description kine-ui input 组件
|
|
7397
7513
|
* @author 阿怪
|
|
7398
7514
|
* @date 2026/2/26
|
|
7399
|
-
* @version v1.
|
|
7515
|
+
* @version v1.1.0
|
|
7400
7516
|
*
|
|
7401
7517
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
7518
|
+
*
|
|
7519
|
+
* v1.1.0 migrate to kDefineComponent for data-k test anchor 2026/4/28
|
|
7402
7520
|
*/
|
|
7403
|
-
var KInput_default =
|
|
7521
|
+
var KInput_default = kDefineComponent((_props, ctx) => {
|
|
7404
7522
|
const props = _props;
|
|
7405
7523
|
const size = useComponentSize(props);
|
|
7406
7524
|
return () => {
|
|
@@ -7447,7 +7565,8 @@ var KInput_default = /* @__PURE__ */ defineComponent((_props, ctx) => {
|
|
|
7447
7565
|
"focus",
|
|
7448
7566
|
"blur",
|
|
7449
7567
|
"clear"
|
|
7450
|
-
]
|
|
7568
|
+
],
|
|
7569
|
+
kAnchor: { type: "field" }
|
|
7451
7570
|
});
|
|
7452
7571
|
//#endregion
|
|
7453
7572
|
//#region ../ui/constants.ts
|
|
@@ -7465,14 +7584,15 @@ var DROPDOWN_HIDDEN_STYLE = {
|
|
|
7465
7584
|
* @description kine-ui select 组件
|
|
7466
7585
|
* @author 阿怪
|
|
7467
7586
|
* @date 2026/2/26
|
|
7468
|
-
* @version v1.0
|
|
7587
|
+
* @version v1.1.0
|
|
7469
7588
|
*
|
|
7470
7589
|
* 江湖的业务千篇一律,复杂的代码好几百行。
|
|
7471
7590
|
*
|
|
7472
7591
|
* v1.0.1 消费 inputReadonly,支持 filterable 可搜索模式 阿怪 2026/2/27
|
|
7592
|
+
* v1.1.0 migrate to kDefineComponent for data-k test anchor 2026/4/28
|
|
7473
7593
|
*/
|
|
7474
7594
|
var { props: selectProps, useSelect } = SelectCore;
|
|
7475
|
-
var KSelect_default =
|
|
7595
|
+
var KSelect_default = kDefineComponent((_props, _ctx) => {
|
|
7476
7596
|
const props = _props;
|
|
7477
7597
|
const { slots, expose } = _ctx;
|
|
7478
7598
|
const componentSize = useComponentSize(props);
|
|
@@ -7657,7 +7777,8 @@ var KSelect_default = /* @__PURE__ */ defineComponent((_props, _ctx) => {
|
|
|
7657
7777
|
"select",
|
|
7658
7778
|
"focus",
|
|
7659
7779
|
"blur"
|
|
7660
|
-
]
|
|
7780
|
+
],
|
|
7781
|
+
kAnchor: { type: "field" }
|
|
7661
7782
|
});
|
|
7662
7783
|
//#endregion
|
|
7663
7784
|
//#region components/pageHeader/KPageHeader.tsx
|
|
@@ -8751,7 +8872,6 @@ function createCrudAppWithOptions(rootComponent, options) {
|
|
|
8751
8872
|
options.router.beforeEach(guard);
|
|
8752
8873
|
}
|
|
8753
8874
|
}
|
|
8754
|
-
if (options.router) app.use(options.router);
|
|
8755
8875
|
setupCrud(app, options.query);
|
|
8756
8876
|
if (options.request) {
|
|
8757
8877
|
const requestOptions = { ...options.request };
|
|
@@ -8763,7 +8883,10 @@ function createCrudAppWithOptions(rootComponent, options) {
|
|
|
8763
8883
|
if (options.error) createErrorHandler(app, options.error);
|
|
8764
8884
|
const enhancedApp = Object.create(app);
|
|
8765
8885
|
enhancedApp.mount = (rootContainer) => {
|
|
8766
|
-
const doMount = () =>
|
|
8886
|
+
const doMount = () => {
|
|
8887
|
+
if (options.router) app.use(options.router);
|
|
8888
|
+
app.mount(rootContainer);
|
|
8889
|
+
};
|
|
8767
8890
|
if (auth) auth.restore().finally(doMount);
|
|
8768
8891
|
else doMount();
|
|
8769
8892
|
return app;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kine-design/crud",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.23",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/crud.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"pinia": "^3.0.3",
|
|
10
10
|
"vue": "^3.5.30",
|
|
11
11
|
"vue-router": "^5.0.3",
|
|
12
|
-
"@kine-design/core": "0.0.1-beta.
|
|
13
|
-
"kine-ui": "0.0.1-beta.
|
|
12
|
+
"@kine-design/core": "0.0.1-beta.7",
|
|
13
|
+
"kine-ui": "0.0.1-beta.15"
|
|
14
14
|
},
|
|
15
15
|
"publishConfig": {
|
|
16
16
|
"access": "public",
|
package/setup.ts
CHANGED
|
@@ -244,22 +244,15 @@ function createCrudAppWithOptions(
|
|
|
244
244
|
}
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
// 2.
|
|
248
|
-
if (options.router) {
|
|
249
|
-
app.use(options.router as { install: (app: App) => void });
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// 3. TanStack Query
|
|
247
|
+
// 2. TanStack Query
|
|
253
248
|
setupCrud(app, options.query);
|
|
254
249
|
|
|
255
|
-
//
|
|
250
|
+
// 3. Request
|
|
256
251
|
if (options.request) {
|
|
257
252
|
const requestOptions: RequestOptions = { ...options.request };
|
|
258
|
-
// 如果有 auth,自动注入 getToken
|
|
259
253
|
if (auth && !requestOptions.getToken) {
|
|
260
254
|
requestOptions.getToken = () => auth!.token.value;
|
|
261
255
|
}
|
|
262
|
-
// 如果有 auth,自动注入 onUnauthorized
|
|
263
256
|
if (auth && !requestOptions.onUnauthorized) {
|
|
264
257
|
requestOptions.onUnauthorized = options.auth?.onUnauthorized;
|
|
265
258
|
}
|
|
@@ -267,15 +260,23 @@ function createCrudAppWithOptions(
|
|
|
267
260
|
app.provide(REQUEST_CLIENT_KEY, client);
|
|
268
261
|
}
|
|
269
262
|
|
|
270
|
-
//
|
|
263
|
+
// 4. Error Handler
|
|
271
264
|
if (options.error) {
|
|
272
265
|
createErrorHandler(app, options.error);
|
|
273
266
|
}
|
|
274
267
|
|
|
275
268
|
// 返回增强的 app,mount 前先恢复 auth
|
|
269
|
+
// Router 安装延迟到 doMount:app.use(router) 会触发初始导航,
|
|
270
|
+
// 必须在 auth.restore() 完成(permissions 已加载)之后执行,否则
|
|
271
|
+
// authGuard 会在 permissions 为空时将受保护路由重定向到 /403。
|
|
276
272
|
const enhancedApp: EnhancedApp = Object.create(app);
|
|
277
273
|
enhancedApp.mount = (rootContainer: string | Element): App => {
|
|
278
|
-
const doMount = () =>
|
|
274
|
+
const doMount = () => {
|
|
275
|
+
if (options.router) {
|
|
276
|
+
app.use(options.router as { install: (app: App) => void });
|
|
277
|
+
}
|
|
278
|
+
app.mount(rootContainer);
|
|
279
|
+
};
|
|
279
280
|
if (auth) {
|
|
280
281
|
auth.restore().finally(doMount);
|
|
281
282
|
} else {
|