@done-coding/admin-core 0.22.1 → 0.22.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.
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./AppPage.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const AppPage = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2d4bb608"]]);
4
+ const AppPage = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-2359c6df"]]);
5
5
  export {
6
6
  AppPage as default
7
7
  };
@@ -1,10 +1,16 @@
1
- import { defineComponent, useCssVars, computed, useSlots, ref, shallowRef, inject, provide, readonly, openBlock, createElementBlock, normalizeStyle, createElementVNode, createVNode, unref, withCtx, renderSlot, createBlock, createCommentVNode } from "vue";
1
+ import { defineComponent, useCssVars, computed, useSlots, ref, shallowRef, inject, provide, readonly, openBlock, createElementBlock, normalizeStyle, createElementVNode, unref, createVNode, withCtx, renderSlot, createBlock, createCommentVNode } from "vue";
2
2
  import _debounce from "lodash/debounce";
3
3
  import _sfc_main$1 from "../modal/ModalShelf.vue.mjs";
4
4
  import _sfc_main$2 from "../display/WatchSize.vue.mjs";
5
5
  import { computeAppPageReducedViewportHeight, computeAppPageContentInset, computeAppPageReducedViewportWidth, computeAppPageSlotStyles, computeAppPageSlotShimStyles } from "./app-page-geometry.mjs";
6
6
  import { BODY_CONTENT_VIEWPORT_RECT, SCOPE_VIEWPORT_MAX_HEIGHT, BODY_CONTENT_VIEWPORT_HEIGHT, BODY_CONTENT_VIEWPORT_INSET, APP_PAGE_CONTENT_INSET } from "../../inject/key.mjs";
7
7
  import { useActivated } from "../../hooks/activated.mjs";
8
+ import { SlotRegion } from "../../config/slot-region.mjs";
9
+ const _hoisted_1 = ["data-dc-slot"];
10
+ const _hoisted_2 = ["data-dc-slot"];
11
+ const _hoisted_3 = ["data-dc-slot"];
12
+ const _hoisted_4 = ["data-dc-slot"];
13
+ const _hoisted_5 = ["data-dc-slot"];
8
14
  const cssVar = "--app-viewport-max-height";
9
15
  const _sfc_main = /* @__PURE__ */ defineComponent({
10
16
  ...{
@@ -28,13 +34,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
28
34
  },
29
35
  setup(__props) {
30
36
  useCssVars((_ctx) => ({
31
- "v68a1d5b5": pageCssVars.value.top,
32
- "v0a30a9cb": pageCssVars.value.bottom,
33
- "a8d5d0b2": pageCssVars.value.left,
34
- "v71378308": pageCssVars.value.right,
35
- "v70aaabb4": pageCssVars.value.width,
36
- "v13dba0c7": pageCssVars.value.height,
37
- "v746c0602": props.nextViewportMaxHeight
37
+ "v55181597": pageCssVars.value.top,
38
+ "v5f04c6a9": pageCssVars.value.bottom,
39
+ "v4de6d405": pageCssVars.value.left,
40
+ "v6f4a0dde": pageCssVars.value.right,
41
+ "v6f907988": pageCssVars.value.width,
42
+ "v68afbda5": pageCssVars.value.height,
43
+ "v2e2782e4": props.nextViewportMaxHeight
38
44
  }));
39
45
  const props = __props;
40
46
  const style = computed(() => {
@@ -215,7 +221,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
215
221
  }, [
216
222
  createElementVNode("div", {
217
223
  class: "app-page-shim",
218
- style: normalizeStyle(shimStyle.value)
224
+ style: normalizeStyle(shimStyle.value),
225
+ "data-dc-slot": unref(SlotRegion).AppPage_Default
219
226
  }, [
220
227
  createVNode(unref(_sfc_main$1), { level: "page" }, {
221
228
  default: withCtx(() => [
@@ -223,7 +230,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
223
230
  ]),
224
231
  _: 3
225
232
  })
226
- ], 4),
233
+ ], 12, _hoisted_1),
227
234
  hasTop.value ? (openBlock(), createBlock(unref(_sfc_main$2), {
228
235
  key: 0,
229
236
  mode: "height",
@@ -235,10 +242,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
235
242
  default: withCtx(() => [
236
243
  createElementVNode("div", {
237
244
  class: "app-page-slot-shim",
238
- style: normalizeStyle(shimStyles.value.top)
245
+ style: normalizeStyle(shimStyles.value.top),
246
+ "data-dc-slot": unref(SlotRegion).AppPage_Top
239
247
  }, [
240
248
  renderSlot(_ctx.$slots, "top", {}, void 0, true)
241
- ], 4)
249
+ ], 12, _hoisted_2)
242
250
  ]),
243
251
  _: 3
244
252
  }, 8, ["observe-resize", "style"])) : createCommentVNode("", true),
@@ -253,10 +261,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
253
261
  default: withCtx(() => [
254
262
  createElementVNode("div", {
255
263
  class: "app-page-slot-shim",
256
- style: normalizeStyle(shimStyles.value.bottom)
264
+ style: normalizeStyle(shimStyles.value.bottom),
265
+ "data-dc-slot": unref(SlotRegion).AppPage_Bottom
257
266
  }, [
258
267
  renderSlot(_ctx.$slots, "bottom", {}, void 0, true)
259
- ], 4)
268
+ ], 12, _hoisted_3)
260
269
  ]),
261
270
  _: 3
262
271
  }, 8, ["observe-resize", "style"])) : createCommentVNode("", true),
@@ -271,10 +280,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
271
280
  default: withCtx(() => [
272
281
  createElementVNode("div", {
273
282
  class: "app-page-slot-shim",
274
- style: normalizeStyle(shimStyles.value.left)
283
+ style: normalizeStyle(shimStyles.value.left),
284
+ "data-dc-slot": unref(SlotRegion).AppPage_Left
275
285
  }, [
276
286
  renderSlot(_ctx.$slots, "left", { listLayoutRecommended }, void 0, true)
277
- ], 4)
287
+ ], 12, _hoisted_4)
278
288
  ]),
279
289
  _: 3
280
290
  }, 8, ["observe-resize", "style"])) : createCommentVNode("", true),
@@ -289,10 +299,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
289
299
  default: withCtx(() => [
290
300
  createElementVNode("div", {
291
301
  class: "app-page-slot-shim",
292
- style: normalizeStyle(shimStyles.value.right)
302
+ style: normalizeStyle(shimStyles.value.right),
303
+ "data-dc-slot": unref(SlotRegion).AppPage_Right
293
304
  }, [
294
305
  renderSlot(_ctx.$slots, "right", { listLayoutRecommended }, void 0, true)
295
- ], 4)
306
+ ], 12, _hoisted_5)
296
307
  ]),
297
308
  _: 3
298
309
  }, 8, ["observe-resize", "style"])) : createCommentVNode("", true)
@@ -1,12 +1,14 @@
1
- import { defineComponent, inject, toRefs, useModel, useSlots, ref, computed, h, provide, watch, unref, openBlock, createBlock, createSlots, renderList, withCtx, renderSlot, normalizeProps, guardReactiveProps, resolveDynamicComponent, mergeProps, KeepAlive, createCommentVNode, createVNode, createElementVNode, mergeModels } from "vue";
1
+ import { defineComponent, inject, toRefs, useModel, useSlots, ref, computed, h, provide, watch, unref, openBlock, createBlock, mergeProps, createSlots, renderList, withCtx, renderSlot, normalizeProps, guardReactiveProps, resolveDynamicComponent, KeepAlive, createCommentVNode, createVNode, createElementVNode, mergeModels } from "vue";
2
2
  import { useRoute, useRouter } from "vue-router";
3
3
  import _sfc_main$1 from "./TabsRefineFlow.vue.mjs";
4
4
  import _sfc_main$2 from "./TabsNaturalFlow.vue.mjs";
5
5
  import TabsHeader from "./TabsHeader.vue.mjs";
6
6
  import TabsTile from "./TabsTile.vue.mjs";
7
7
  import { watchTabToQuery, getTabQuery } from "./use-tabs-query-sync.mjs";
8
+ import { useContextDefaults } from "../../hooks/use-context-defaults.mjs";
8
9
  import { TABS_MAIN_VISUAL_LEVEL } from "../../inject/key.mjs";
9
10
  import { useActivated } from "../../hooks/activated.mjs";
11
+ import { SlotRegion } from "../../config/slot-region.mjs";
10
12
  const _sfc_main = /* @__PURE__ */ defineComponent({
11
13
  __name: "TabsMain",
12
14
  props: /* @__PURE__ */ mergeModels({
@@ -16,14 +18,15 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
16
18
  channel: {},
17
19
  parentChannel: {},
18
20
  padding: {},
19
- refine: { type: Boolean, default: false },
21
+ refine: { type: Boolean, default: void 0 },
20
22
  refineReduceHeight: { default: 0 },
21
23
  variant: {},
22
24
  queryKey: {},
23
25
  tile: { type: Boolean },
24
26
  navPosition: {},
25
27
  navMode: {},
26
- navOffset: {}
28
+ navOffset: {},
29
+ showNav: { type: Boolean, default: void 0 }
27
30
  }, {
28
31
  "modelValue": {},
29
32
  "modelModifiers": {}
@@ -31,6 +34,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
31
34
  emits: ["update:modelValue"],
32
35
  setup(__props) {
33
36
  const props = __props;
37
+ const { ctxRefine } = useContextDefaults({
38
+ getProps: () => props,
39
+ defaults: {
40
+ refine: ({ parentInfo, props: rawProps }) => rawProps.refine ?? (parentInfo === SlotRegion.AppPage_Default ? true : void 0)
41
+ }
42
+ });
34
43
  const parentVisualLevel = inject(TABS_MAIN_VISUAL_LEVEL, 0);
35
44
  const selfVisualLevel = parentVisualLevel + 1;
36
45
  const {
@@ -39,14 +48,14 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
39
48
  channel,
40
49
  parentChannel,
41
50
  padding,
42
- refine,
43
51
  refineReduceHeight,
44
52
  variant,
45
53
  tabs,
46
54
  tile,
47
55
  navPosition,
48
56
  navMode,
49
- navOffset
57
+ navOffset,
58
+ showNav
50
59
  } = toRefs(props);
51
60
  const model = useModel(__props, "modelValue");
52
61
  const route = useRoute();
@@ -68,10 +77,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
68
77
  const slots = useSlots();
69
78
  const contentViewportHeight = ref(void 0);
70
79
  const wrapperComponent = computed(
71
- () => refine.value ? _sfc_main$1 : _sfc_main$2
80
+ () => ctxRefine.value ? _sfc_main$1 : _sfc_main$2
72
81
  );
73
82
  const wrapperProps = computed(
74
- () => refine.value ? {
83
+ () => ctxRefine.value ? {
75
84
  viewportHeight: viewportHeight.value,
76
85
  minHeight: minHeight.value,
77
86
  channel: channel.value,
@@ -80,6 +89,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
80
89
  refineReduceHeight: refineReduceHeight.value
81
90
  } : {}
82
91
  );
92
+ const tileShowNavBind = computed(
93
+ () => showNav.value !== void 0 ? { showNav: showNav.value } : {}
94
+ );
83
95
  const tabByKey = (key) => props.tabs.find((tab) => tab.key === key);
84
96
  const onViewportHeightChange = (value) => {
85
97
  contentViewportHeight.value = value;
@@ -117,20 +129,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
117
129
  { immediate: true }
118
130
  );
119
131
  return (_ctx, _cache) => {
120
- return unref(tile) ? (openBlock(), createBlock(TabsTile, {
132
+ return unref(tile) ? (openBlock(), createBlock(TabsTile, mergeProps({
121
133
  key: 0,
122
134
  modelValue: model.value,
123
135
  "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => model.value = $event),
124
136
  class: "dc-tabs-main",
125
137
  tabs: unref(tabs),
126
- refine: unref(refine),
138
+ refine: unref(ctxRefine),
127
139
  "viewport-height": unref(viewportHeight),
128
140
  "min-height": unref(minHeight),
129
141
  "parent-channel": unref(parentChannel),
130
142
  "nav-position": unref(navPosition),
131
143
  "nav-mode": unref(navMode),
132
144
  "nav-offset": unref(navOffset)
133
- }, createSlots({ _: 2 }, [
145
+ }, tileShowNavBind.value), createSlots({ _: 2 }, [
134
146
  renderList(unref(tabs), (tab) => {
135
147
  return {
136
148
  name: tab.key,
@@ -147,7 +159,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
147
159
  ])
148
160
  };
149
161
  })
150
- ]), 1032, ["modelValue", "tabs", "refine", "viewport-height", "min-height", "parent-channel", "nav-position", "nav-mode", "nav-offset"])) : (openBlock(), createBlock(resolveDynamicComponent(wrapperComponent.value), mergeProps({
162
+ ]), 1040, ["modelValue", "tabs", "refine", "viewport-height", "min-height", "parent-channel", "nav-position", "nav-mode", "nav-offset"])) : (openBlock(), createBlock(resolveDynamicComponent(wrapperComponent.value), mergeProps({
151
163
  key: 1,
152
164
  class: "dc-tabs-main"
153
165
  }, wrapperProps.value, { onViewportHeightChange }), {
@@ -1,5 +1,7 @@
1
- import { defineComponent, onMounted, openBlock, createElementBlock, renderSlot } from "vue";
1
+ import { defineComponent, onMounted, openBlock, createElementBlock, renderSlot, createElementVNode, unref } from "vue";
2
+ import { SlotRegion } from "../../config/slot-region.mjs";
2
3
  const _hoisted_1 = { class: "tabs-natural-flow" };
4
+ const _hoisted_2 = ["data-dc-slot"];
3
5
  const _sfc_main = /* @__PURE__ */ defineComponent({
4
6
  __name: "TabsNaturalFlow",
5
7
  emits: ["viewportHeightChange"],
@@ -11,7 +13,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
11
13
  return (_ctx, _cache) => {
12
14
  return openBlock(), createElementBlock("div", _hoisted_1, [
13
15
  renderSlot(_ctx.$slots, "header"),
14
- renderSlot(_ctx.$slots, "default")
16
+ createElementVNode("div", {
17
+ class: "tabs-natural-flow__content",
18
+ "data-dc-slot": unref(SlotRegion).TabsMain_Item
19
+ }, [
20
+ renderSlot(_ctx.$slots, "default")
21
+ ], 8, _hoisted_2)
15
22
  ]);
16
23
  };
17
24
  }
@@ -1,8 +1,10 @@
1
- import { defineComponent, ref, computed, provide, watch, openBlock, createElementBlock, createVNode, createSlots, withCtx, createElementVNode, normalizeStyle, renderSlot } from "vue";
1
+ import { defineComponent, ref, computed, provide, watch, openBlock, createElementBlock, createVNode, createSlots, withCtx, createElementVNode, unref, normalizeStyle, renderSlot } from "vue";
2
2
  import _sfc_main$1 from "./HeightProvider.vue.mjs";
3
3
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
4
4
  import { SCOPE_VIEWPORT_MAX_HEIGHT } from "../../inject/key.mjs";
5
+ import { SlotRegion } from "../../config/slot-region.mjs";
5
6
  const _hoisted_1 = { class: "tabs-refine-flow" };
7
+ const _hoisted_2 = ["data-dc-slot"];
6
8
  const _sfc_main = /* @__PURE__ */ defineComponent({
7
9
  __name: "TabsRefineFlow",
8
10
  props: {
@@ -53,10 +55,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
53
55
  }, createSlots({
54
56
  default: withCtx(() => [
55
57
  createElementVNode("div", {
56
- style: normalizeStyle(paddingWrapStyle.value)
58
+ style: normalizeStyle(paddingWrapStyle.value),
59
+ "data-dc-slot": unref(SlotRegion).TabsMain_Item
57
60
  }, [
58
61
  renderSlot(_ctx.$slots, "default")
59
- ], 4)
62
+ ], 12, _hoisted_2)
60
63
  ]),
61
64
  _: 2
62
65
  }, [
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./TabsTile.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-efffefb9"]]);
4
+ const TabsTile = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-d9f0f521"]]);
5
5
  export {
6
6
  TabsTile as default
7
7
  };
@@ -5,8 +5,9 @@ import { getId } from "../../utils/id.mjs";
5
5
  import { APP_PAGE_CONTENT_INSET } from "../../inject/key.mjs";
6
6
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
7
7
  import { useActivated } from "../../hooks/activated.mjs";
8
+ import { SlotRegion } from "../../config/slot-region.mjs";
8
9
  import { domClosestScrollableAncestor } from "../../utils/dom.mjs";
9
- const _hoisted_1 = ["id", "data-tab-key"];
10
+ const _hoisted_1 = ["id", "data-tab-key", "data-dc-slot"];
10
11
  const _sfc_main = /* @__PURE__ */ defineComponent({
11
12
  __name: "TabsTile",
12
13
  props: /* @__PURE__ */ mergeModels({
@@ -17,7 +18,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
17
18
  parentChannel: {},
18
19
  navPosition: { default: "bottom-right" },
19
20
  navMode: { default: "auto" },
20
- navOffset: { default: 12 }
21
+ navOffset: { default: 12 },
22
+ showNav: { type: Boolean, default: void 0 }
21
23
  }, {
22
24
  "modelValue": {},
23
25
  "modelModifiers": {}
@@ -69,6 +71,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
69
71
  () => props.navMode === "auto" ? props.refine ? "absolute" : "sticky" : props.navMode
70
72
  );
71
73
  const rootClass = computed(() => `dc-tabs-tile--nav-${navModeResolved.value}`);
74
+ const navVisible = computed(() => props.showNav ?? props.refine);
72
75
  const navStyle = computed(() => {
73
76
  const offset = `${props.navOffset}px`;
74
77
  const isTop = props.navPosition.startsWith("top");
@@ -178,7 +181,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
178
181
  id: paneId(index),
179
182
  key: tab.key,
180
183
  class: "dc-tabs-tile__item",
181
- "data-tab-key": tab.key
184
+ "data-tab-key": tab.key,
185
+ "data-dc-slot": unref(SlotRegion).TabsMain_Item
182
186
  }, [
183
187
  createVNode(_sfc_main$1, {
184
188
  tag: unref(ElCard),
@@ -205,7 +209,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
205
209
  ], 8, _hoisted_1);
206
210
  }), 128))
207
211
  ], 4),
208
- createElementVNode("div", {
212
+ navVisible.value ? (openBlock(), createElementBlock("div", {
213
+ key: 0,
209
214
  class: "dc-tabs-tile__nav",
210
215
  style: normalizeStyle(navStyle.value),
211
216
  onClick: _cache[0] || (_cache[0] = withModifiers(() => {
@@ -230,7 +235,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
230
235
  ]),
231
236
  _: 1
232
237
  }, 8, ["container", "offset"])
233
- ], 4)
238
+ ], 4)) : createCommentVNode("", true)
234
239
  ], 2);
235
240
  };
236
241
  }
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./ListLayout.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const ListLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-8527d1df"]]);
4
+ const ListLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ce5a651b"]]);
5
5
  export {
6
6
  ListLayout as default
7
7
  };
@@ -3,6 +3,7 @@ import { vLoading } from "element-plus";
3
3
  import FormActiveFilter from "../form/FormActiveFilter.vue.mjs";
4
4
  import FormSearch from "../form/FormSearch.vue.mjs";
5
5
  import { generateFormData, stringifyFormData } from "../form/utils.mjs";
6
+ import { useContextDefaults } from "../../hooks/use-context-defaults.mjs";
6
7
  import { useListLayoutSticky } from "./use-list-layout-sticky.mjs";
7
8
  import { useActiveFilter } from "./use-active-filter.mjs";
8
9
  import _sfc_main$1 from "../display/WatchSize.vue.mjs";
@@ -11,6 +12,7 @@ import SlotLayoutFlowAside from "../slot-layout/SlotLayoutFlowAside.vue.mjs";
11
12
  import _pick from "lodash/pick";
12
13
  import _cloneDeep from "lodash/cloneDeep";
13
14
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
15
+ import { SlotRegion } from "../../config/slot-region.mjs";
14
16
  const _sfc_main = /* @__PURE__ */ defineComponent({
15
17
  __name: "ListLayout",
16
18
  props: /* @__PURE__ */ mergeModels({
@@ -52,14 +54,20 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
52
54
  emits: /* @__PURE__ */ mergeModels(["dataChange", "pageInfoChange"], ["update:isAutoRefresh", "update:refreshInterval", "update:customView"]),
53
55
  setup(__props, { expose: __expose, emit: __emit }) {
54
56
  useCssVars((_ctx) => ({
55
- "v3483351c": minHeight.value,
56
- "v5ccbcb06": unref(searchStickyTop),
57
- "e69ab810": unref(toolbarStickyTop),
58
- "v5631fb30": unref(pagerStickyBottom)
57
+ "bbc8b4b6": minHeight.value,
58
+ "v2ce52870": unref(searchStickyTop),
59
+ "ca6d5736": unref(toolbarStickyTop),
60
+ "v0af15863": unref(pagerStickyBottom)
59
61
  }));
60
62
  const props = __props;
61
63
  const listLayoutEmits = __emit;
62
64
  const slots = useSlots();
65
+ const { ctxTableMainProps } = useContextDefaults({
66
+ getProps: () => props,
67
+ defaults: {
68
+ tableMainProps: ({ parentInfo, props: rawProps }) => rawProps.tableMainProps ?? (parentInfo === SlotRegion.AppPage_Left || parentInfo === SlotRegion.AppPage_Right ? { pageLayout: "prev, pager, next", paginationBackground: false } : void 0)
69
+ }
70
+ });
63
71
  const hasHeader = computed(() => !!slots.header);
64
72
  const hasOperation = computed(() => !!slots.operation);
65
73
  const isAutoRefresh = useModel(__props, "isAutoRefresh");
@@ -371,7 +379,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
371
379
  toolbar: __props.toolbar,
372
380
  showSwitchView: __props.showSwitchView,
373
381
  "initial-search": __props.initialSearch
374
- }, __props.tableMainProps, {
382
+ }, unref(ctxTableMainProps), {
375
383
  refine: false,
376
384
  injectInfo: injectInfoAdjust.value,
377
385
  onLoadingChange,
@@ -1,7 +1,7 @@
1
1
  import _sfc_main from "./ViewLayout.vue2.mjs";
2
2
  /* empty css */
3
3
  import _export_sfc from "../../_virtual/_plugin-vue_export-helper.mjs";
4
- const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-3c537d41"]]);
4
+ const ViewLayout = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-f0ed342f"]]);
5
5
  export {
6
6
  ViewLayout as default
7
7
  };
@@ -1,10 +1,12 @@
1
- import { defineComponent, shallowRef, ref, computed, provide, watch, openBlock, createElementBlock, createBlock, unref, withCtx, createElementVNode, normalizeStyle, renderSlot, withDirectives, createVNode, vShow, Fragment } from "vue";
1
+ import { defineComponent, shallowRef, ref, computed, provide, watch, openBlock, createElementBlock, unref, createBlock, withCtx, createElementVNode, normalizeStyle, renderSlot, withDirectives, createVNode, vShow, Fragment } from "vue";
2
2
  import AutoRefreshGroup from "../misc/AutoRefreshGroup.vue.mjs";
3
3
  import _sfc_main$1 from "../display/HeightProvider.vue.mjs";
4
4
  import _sfc_main$2 from "../display/ActionBtnGroup.vue.mjs";
5
+ import { useContextDefaults } from "../../hooks/use-context-defaults.mjs";
5
6
  import { useChannelViewportHeight } from "../../hooks/use-channel-viewport-height.mjs";
6
7
  import { useActivated } from "../../hooks/activated.mjs";
7
8
  import { SCOPE_VIEWPORT_MAX_HEIGHT } from "../../inject/key.mjs";
9
+ import { SlotRegion } from "../../config/slot-region.mjs";
8
10
  const _hoisted_1 = { class: "dc-view-layout view-layout" };
9
11
  const _hoisted_2 = { class: "view-layout-toolbar" };
10
12
  const _hoisted_3 = { class: "view-layout-toolbar__left" };
@@ -18,7 +20,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
18
20
  props: {
19
21
  api: {},
20
22
  params: {},
21
- refine: { type: Boolean, default: false },
23
+ refine: { type: Boolean, default: void 0 },
22
24
  viewportHeight: {},
23
25
  channel: {},
24
26
  parentChannel: {},
@@ -30,6 +32,12 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
30
32
  },
31
33
  setup(__props) {
32
34
  const props = __props;
35
+ const { ctxRefine } = useContextDefaults({
36
+ getProps: () => props,
37
+ defaults: {
38
+ refine: ({ parentInfo, props: rawProps }) => rawProps.refine ?? (parentInfo === SlotRegion.AppPage_Default || parentInfo === SlotRegion.TabsMain_Item ? true : void 0)
39
+ }
40
+ });
33
41
  const { viewportHeightFinal, nearestScope } = useChannelViewportHeight(props);
34
42
  const data = shallowRef(void 0);
35
43
  const loading = ref(false);
@@ -63,13 +71,13 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
63
71
  const onChildViewportHeightChange = (value) => {
64
72
  childViewportHeightChange.value = value;
65
73
  };
66
- if (props.refine) {
67
- provide(SCOPE_VIEWPORT_MAX_HEIGHT, {
68
- scope: props.channel,
69
- viewportMaxHeight: computed(() => childViewportHeightChange.value),
70
- parent: nearestScope
71
- });
72
- }
74
+ provide(SCOPE_VIEWPORT_MAX_HEIGHT, {
75
+ scope: props.channel,
76
+ viewportMaxHeight: computed(
77
+ () => ctxRefine.value ? childViewportHeightChange.value : (nearestScope == null ? void 0 : nearestScope.viewportMaxHeight.value) ?? 0
78
+ ),
79
+ parent: nearestScope
80
+ });
73
81
  watch(
74
82
  // eslint-disable-next-line vue/no-setup-props-destructure
75
83
  () => props.channel,
@@ -77,7 +85,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
77
85
  );
78
86
  return (_ctx, _cache) => {
79
87
  return openBlock(), createElementBlock("div", _hoisted_1, [
80
- __props.refine ? (openBlock(), createBlock(unref(_sfc_main$1), {
88
+ unref(ctxRefine) ? (openBlock(), createBlock(unref(_sfc_main$1), {
81
89
  key: 0,
82
90
  viewportHeight: heightProviderViewportHeight.value,
83
91
  minHeight: __props.minHeight,
@@ -0,0 +1,21 @@
1
+ const DC_SLOT_ATTR = "data-dc-slot";
2
+ var SlotRegion = /* @__PURE__ */ ((SlotRegion2) => {
3
+ SlotRegion2[SlotRegion2["AppPage_Default"] = 1] = "AppPage_Default";
4
+ SlotRegion2[SlotRegion2["AppPage_Top"] = 2] = "AppPage_Top";
5
+ SlotRegion2[SlotRegion2["AppPage_Right"] = 3] = "AppPage_Right";
6
+ SlotRegion2[SlotRegion2["AppPage_Bottom"] = 4] = "AppPage_Bottom";
7
+ SlotRegion2[SlotRegion2["AppPage_Left"] = 5] = "AppPage_Left";
8
+ SlotRegion2[SlotRegion2["TabsMain_Item"] = 6] = "TabsMain_Item";
9
+ return SlotRegion2;
10
+ })(SlotRegion || {});
11
+ const parseSlotRegion = (raw) => {
12
+ if (raw === null || raw === void 0 || raw === "") return void 0;
13
+ const num = Number(raw);
14
+ if (!Number.isInteger(num)) return void 0;
15
+ return num in SlotRegion ? num : void 0;
16
+ };
17
+ export {
18
+ DC_SLOT_ATTR,
19
+ SlotRegion,
20
+ parseSlotRegion
21
+ };
@@ -0,0 +1,44 @@
1
+ import { getCurrentInstance, shallowRef, computed } from "vue";
2
+ import { useActivated } from "./activated.mjs";
3
+ import { DC_SLOT_ATTR, parseSlotRegion } from "../config/slot-region.mjs";
4
+ const useContextDefaults = (options) => {
5
+ var _a, _b;
6
+ const instance = getCurrentInstance();
7
+ const region = shallowRef(void 0);
8
+ useActivated((info) => {
9
+ var _a2, _b2;
10
+ if (info.isActivated && region.value === void 0) {
11
+ const el = (_a2 = instance == null ? void 0 : instance.proxy) == null ? void 0 : _a2.$el;
12
+ const raw = (_b2 = el == null ? void 0 : el.parentElement) == null ? void 0 : _b2.getAttribute(DC_SLOT_ATTR);
13
+ region.value = parseSlotRegion(raw);
14
+ }
15
+ });
16
+ try {
17
+ const defs = (_b = (_a = instance == null ? void 0 : instance.vnode) == null ? void 0 : _a.type) == null ? void 0 : _b.props;
18
+ if (defs) {
19
+ for (const key of Object.keys(options.defaults)) {
20
+ const def = defs[key];
21
+ if (def && "default" in def && def.default !== void 0) {
22
+ console.warn(
23
+ `[useContextDefaults] prop "${key}" 在 withDefaults 设了内建默认(${String(
24
+ def.default
25
+ )})——会短路 \`props.xx ?? 上下文默认\` 合并,上下文默认静默失效。[MUST] 上下文默认 prop 的 withDefaults 只填 undefined。详见 spec 2026-08-14 useContextDefaults。`
26
+ );
27
+ }
28
+ }
29
+ }
30
+ } catch {
31
+ }
32
+ const result = {};
33
+ for (const key of Object.keys(options.defaults)) {
34
+ const resolver = options.defaults[key];
35
+ const ctxKey = `ctx${key.charAt(0).toUpperCase()}${key.slice(1)}`;
36
+ result[ctxKey] = computed(
37
+ () => resolver({ props: options.getProps(), parentInfo: region.value })
38
+ );
39
+ }
40
+ return result;
41
+ };
42
+ export {
43
+ useContextDefaults
44
+ };
package/es/index.mjs CHANGED
@@ -44,6 +44,7 @@ import { default as default41 } from "./components/misc/AutoRefresh.vue.mjs";
44
44
  import { default as default42 } from "./components/misc/AutoRefreshGroup.vue.mjs";
45
45
  import { CORE_VIEWPORT_DECOR_ZINDEX_ABOVE, CORE_VIEWPORT_DECOR_ZINDEX_BELOW } from "./components/app-layout/viewport.mjs";
46
46
  import { default as default43, default as default44 } from "./components/modal/ModalConfirm.vue.mjs";
47
+ import { DC_SLOT_ATTR, SlotRegion, parseSlotRegion } from "./config/slot-region.mjs";
47
48
  import { EXPORT_MAX_LIMIT, OPERATE_COLUMN_PROP, exportCSV, pickExportColumns } from "./utils/export.mjs";
48
49
  import { FORM_CONFIG_SELECT_ALL_VALUE, getConfirmPasswordRule, passwordRule, setFormComponentType } from "./helpers/form.mjs";
49
50
  import { FORM_ITEM_CHANGE_LOADING, NEST_LAYOUT_TIERS, ceilToTier, generateFormData, getBlurSubmit, getChangeSubmit, getDatePickerShortcuts, getEnterSubmit, getPlaceholder, getVModelSugar, parseFormData, resolveFormLayout, resolveLayoutSpan, setInputComponent, setSelectComponent, stringifyFormData, swiftFormItemConfig } from "./components/form/utils.mjs";
@@ -138,6 +139,7 @@ export {
138
139
  CORE_VIEWPORT_DECOR_ZINDEX_ABOVE,
139
140
  CORE_VIEWPORT_DECOR_ZINDEX_BELOW,
140
141
  default43 as ConfirmModal,
142
+ DC_SLOT_ATTR,
141
143
  default5 as DetailModal,
142
144
  EXPORT_MAX_LIMIT,
143
145
  FORM_CONFIG_SELECT_ALL_VALUE,
@@ -194,6 +196,7 @@ export {
194
196
  default26 as ShadowClone,
195
197
  default66 as SlotLayoutFlowAside,
196
198
  default27 as SlotLayoutTemplate,
199
+ SlotRegion,
197
200
  TABLE_COLUMN_KEY_OPERATE,
198
201
  TABLE_COLUMN_KEY_SELECTION,
199
202
  TABS_MAIN_VISUAL_LEVEL,
@@ -245,6 +248,7 @@ export {
245
248
  nestPanelForm,
246
249
  nestPanelItem,
247
250
  parseFormData,
251
+ parseSlotRegion,
248
252
  passwordRule,
249
253
  pickExportColumns,
250
254
  resolveBreakpointByWidth,
package/es/style.css CHANGED
@@ -321,23 +321,23 @@
321
321
  color: var(--dc-core-primary-color);
322
322
  font-weight: 600;
323
323
  }
324
- .dc-tabs-tile--nav-absolute[data-v-efffefb9],
325
- .dc-tabs-tile--nav-fixed[data-v-efffefb9] {
324
+ .dc-tabs-tile--nav-absolute[data-v-d9f0f521],
325
+ .dc-tabs-tile--nav-fixed[data-v-d9f0f521] {
326
326
  position: relative;
327
327
  }
328
- .dc-tabs-tile--nav-sticky[data-v-efffefb9] {
328
+ .dc-tabs-tile--nav-sticky[data-v-d9f0f521] {
329
329
  display: flex;
330
330
  flex-direction: column;
331
331
  }
332
- .dc-tabs-tile__scroll[data-v-efffefb9] {
332
+ .dc-tabs-tile__scroll[data-v-d9f0f521] {
333
333
  display: flex;
334
334
  flex-direction: column;
335
335
  gap: 12px;
336
336
  }
337
- .dc-tabs-tile__card[data-v-efffefb9] {
337
+ .dc-tabs-tile__card[data-v-d9f0f521] {
338
338
  width: 100%;
339
339
  }
340
- .dc-tabs-tile__nav[data-v-efffefb9] {
340
+ .dc-tabs-tile__nav[data-v-d9f0f521] {
341
341
  z-index: 2;
342
342
  max-height: 60%;
343
343
  overflow: auto;
@@ -602,18 +602,18 @@
602
602
  .app-layout_noLogin[data-v-b45bcdfd] .app-footer {
603
603
  transition: none !important;
604
604
  }
605
- .app-page[data-v-2d4bb608] {
606
- --dc-page-content-viewport-top: var(--v68a1d5b5);
607
- --dc-page-content-viewport-bottom: var(--v0a30a9cb);
608
- --dc-page-content-viewport-left: var(--a8d5d0b2);
609
- --dc-page-content-viewport-right: var(--v71378308);
610
- --dc-page-content-viewport-width: var(--v70aaabb4);
611
- --dc-page-content-viewport-height: var(--v13dba0c7);
605
+ .app-page[data-v-2359c6df] {
606
+ --dc-page-content-viewport-top: var(--v55181597);
607
+ --dc-page-content-viewport-bottom: var(--v5f04c6a9);
608
+ --dc-page-content-viewport-left: var(--v4de6d405);
609
+ --dc-page-content-viewport-right: var(--v6f4a0dde);
610
+ --dc-page-content-viewport-width: var(--v6f907988);
611
+ --dc-page-content-viewport-height: var(--v68afbda5);
612
612
  }
613
- .app-page-shim[data-v-2d4bb608] {
614
- --app-viewport-max-height: var(--v746c0602);
613
+ .app-page-shim[data-v-2359c6df] {
614
+ --app-viewport-max-height: var(--v2e2782e4);
615
615
  }
616
- .app-page-slot-shim[data-v-2d4bb608] {
616
+ .app-page-slot-shim[data-v-2359c6df] {
617
617
  box-sizing: border-box;
618
618
  width: 100%;
619
619
  height: 100%;
@@ -1122,40 +1122,40 @@ to {
1122
1122
  .dc-slot-layout-flow-aside-main[data-v-5c6ef74b] {
1123
1123
  width: var(--v7e1d11ca);
1124
1124
  }
1125
- .list-layout[data-v-8527d1df] {
1126
- min-height: var(--v3483351c);
1125
+ .list-layout[data-v-ce5a651b] {
1126
+ min-height: var(--bbc8b4b6);
1127
1127
  }
1128
- .list-layout-header[data-v-8527d1df] {
1128
+ .list-layout-header[data-v-ce5a651b] {
1129
1129
  margin-bottom: 10px;
1130
1130
  }
1131
- .list-layout-operation[data-v-8527d1df] {
1131
+ .list-layout-operation[data-v-ce5a651b] {
1132
1132
  margin-bottom: 10px;
1133
1133
  }
1134
- .list-layout_search-sticky[data-v-8527d1df] .form-search {
1134
+ .list-layout_search-sticky[data-v-ce5a651b] .form-search {
1135
1135
  position: sticky;
1136
- top: var(--v5ccbcb06);
1136
+ top: var(--v2ce52870);
1137
1137
  z-index: 10;
1138
1138
  background: var(--dc-core-surface, var(--el-bg-color));
1139
1139
  box-shadow: 0 1px 0 0 var(--dc-core-border-color, var(--el-border-color-lighter));
1140
1140
  }
1141
- .list-layout_toolbar-sticky[data-v-8527d1df] .dc-table-main__toolbar {
1141
+ .list-layout_toolbar-sticky[data-v-ce5a651b] .dc-table-main__toolbar {
1142
1142
  position: sticky;
1143
- top: var(--e69ab810);
1143
+ top: var(--ca6d5736);
1144
1144
  z-index: 9;
1145
1145
  padding-top: 10px;
1146
1146
  background: var(--dc-core-surface, var(--el-bg-color));
1147
1147
  box-shadow: 0 1px 0 0 var(--dc-core-border-color, var(--el-border-color-lighter));
1148
1148
  }
1149
- .list-layout_pager-sticky[data-v-8527d1df] .dc-table-main__pagination {
1149
+ .list-layout_pager-sticky[data-v-ce5a651b] .dc-table-main__pagination {
1150
1150
  position: sticky;
1151
- bottom: var(--v5631fb30);
1151
+ bottom: var(--v0af15863);
1152
1152
  z-index: 9;
1153
1153
  margin-top: 0;
1154
1154
  padding-top: 10px;
1155
1155
  background: var(--dc-core-surface, var(--el-bg-color));
1156
1156
  box-shadow: 0 -1px 0 0 var(--dc-core-border-color, var(--el-border-color-lighter));
1157
1157
  }
1158
- .list-layout[data-v-8527d1df] .el-loading-mask {
1158
+ .list-layout[data-v-ce5a651b] .el-loading-mask {
1159
1159
  left: -10px;
1160
1160
  top: -10px;
1161
1161
  right: -10px;
@@ -1167,24 +1167,24 @@ to {
1167
1167
  gap: 8px;
1168
1168
  margin-top: 8px;
1169
1169
  }
1170
- .view-layout[data-v-3c537d41] {
1170
+ .view-layout[data-v-f0ed342f] {
1171
1171
  display: flex;
1172
1172
  flex-direction: column;
1173
1173
  gap: 8px;
1174
1174
  }
1175
- .view-layout-toolbar[data-v-3c537d41] {
1175
+ .view-layout-toolbar[data-v-f0ed342f] {
1176
1176
  display: flex;
1177
1177
  justify-content: space-between;
1178
1178
  align-items: center;
1179
1179
  padding-bottom: 8px;
1180
1180
  gap: 20px;
1181
1181
  }
1182
- .view-layout-toolbar__left[data-v-3c537d41],
1183
- .view-layout-toolbar__right[data-v-3c537d41] {
1182
+ .view-layout-toolbar__left[data-v-f0ed342f],
1183
+ .view-layout-toolbar__right[data-v-f0ed342f] {
1184
1184
  display: flex;
1185
1185
  align-items: center;
1186
1186
  gap: 10px;
1187
1187
  }
1188
- .view-layout-content[data-v-3c537d41] {
1188
+ .view-layout-content[data-v-f0ed342f] {
1189
1189
  overflow: auto;
1190
1190
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@done-coding/admin-core",
3
- "version": "0.22.1",
3
+ "version": "0.22.2",
4
4
  "description": "内部前端库",
5
5
  "private": false,
6
6
  "main": "es/index.mjs",
@@ -80,5 +80,5 @@
80
80
  "node": ">=18.0.0",
81
81
  "pnpm": ">=9.0.0"
82
82
  },
83
- "gitHead": "4f36d70046a0dd917906a086dfeae956e1f72489"
83
+ "gitHead": "e23d3f11214fc43bc0a6e1149ebe56e014a89d8e"
84
84
  }
@@ -67,6 +67,8 @@
67
67
 
68
68
  **性质**:固定内置推荐值(写死、非运行时开关、不做响应式探测),仅经 `#left`/`#right` 插槽 scoped 带出。面向「列表放进 left/right 窄栏」的展示形态推荐;消费者拿到后直接 `v-bind` 展开进 ListLayout,可按需 spread 覆盖(`v-bind="{ ...listLayoutRecommended, customView: false }"`)。
69
69
 
70
+ > ⚠️ **`tableMainProps` 部分已自动**:`#left` / `#right` 内直接放 `ListLayout` 时,分页窄栏化(`pageLayout` / `paginationBackground`)已由 `ListLayout` 的 `useContextDefaults` 直系父上下文默认自动提供,无需再经本推荐配置传 `tableMainProps`;仍需要 `customView: true`(卡片形态)才显式 `v-bind="listLayoutRecommended"`(或只取 `customView`)。
71
+
70
72
  **形状**(与 ListLayout props 平铺对齐):
71
73
 
72
74
  | 字段 | 类型 | 固定值 | 语义 |
@@ -44,6 +44,17 @@ const tabs = [
44
44
  - **variant:默认按 level 推导(1-4 级依次 card / indicator / indicator-compact / plain)即够用**,仅特殊视觉需求显式覆盖。
45
45
  - **完整能力演示**(基础 + queryKey + 嵌套链 + 平铺各态):`apps/reference/src/pages/display/tabs/showcase/`、`pages/display/tabs/nested-channel/`、`pages/display/tabs/tile/`——能力展示,非推荐默认。
46
46
 
47
+ ## 上下文默认值(直系父上下文)
48
+
49
+ 置于特定父容器槽位时,`TabsMain` 的 `refine` 自动获得上下文默认值(`useContextDefaults` 解析直系父 DOM 的 `data-dc-slot`),消费方零传参;显式传 `refine` 仍优先。
50
+
51
+ | 场景 | prop | 自动默认 |
52
+ | --- | --- | --- |
53
+ | AppPage `#default` | `refine` | `true`(精细流) |
54
+ | 其他容器 / 独立使用 | `refine` | 不处理(undefined ≡ false,自然流) |
55
+
56
+ > ⚠️ 需上下文动态默认的 prop 不写 `withDefaults` 默认(详见 spec:`docs/specs/2026-08-14-080509-moderate-usecontextdefaults直系父上下文默认/spec.md`)。
57
+
47
58
  ## API
48
59
  > ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
49
60
 
@@ -57,7 +68,7 @@ const tabs = [
57
68
  | `channel` | `string?` | — | 作为父时的 scope 标识。⚠️ 与 parentChannel 均 [MUST NOT] 响应式变更(setup 期快照);且仅 refine=true 路径生效 |
58
69
  | `parentChannel` | `string?` | — | 作为子时定向消费的祖先 scope 标识(沿对象链 parent 找匹配) |
59
70
  | `padding` | `TabsMainPadding`(= [top,right,bottom,left] px) | `[10,10,0,10]` | 默认插槽容器内置 padding(withDefaults 实证);top+bottom 同步从 slot scope / channel viewportHeight 扣减 |
60
- | `refine` | `boolean?` | `false` | false=自然流(TabsNaturalFlow,不包 HeightProvider,scope viewportHeight 为 undefined);true=精细流(TabsRefineFlow,HeightProvider 精确扣 header reserve + padding |
71
+ | `refine` | `boolean?` | 上下文默认 | false=自然流(TabsNaturalFlow,不包 HeightProvider,scope viewportHeight 为 undefined);true=精细流(TabsRefineFlow,HeightProvider 精确扣 header reserve + padding)。默认由 `useContextDefaults` 按直系父解析:AppPage `#default` 内 `true`,否则 `false`;显式传值优先 |
61
72
  | `refineReduceHeight` | `number?` | `0` | 从 viewportHeightFinal 预扣的高度(refine=false 时同样生效) |
62
73
  | `variant` | `TabsHeaderVariant?` | 按 level 推导 | "card"\|"indicator"\|"indicator-compact"\|"plain";level 1-4 默认依次 card/indicator/indicator-compact/plain。字号始终跟 level(inject TABS_MAIN_VISUAL_LEVEL +1 每层) |
63
74
  | `queryKey` | `string?` | 不传=不同步 | 激活 tab ↔ 路由 query 双向同步的 key:切 tab → router.replace `?{queryKey}={key}`(不压栈);激活/刷新/前进后退读 query 反向恢复;无 vue-router 环境静默失效 |
@@ -60,6 +60,18 @@ const { listPageConfig } = useSpaceConfig({
60
60
  - **高度链 prop(`refine` / `viewportHeight` / `parentChannel`):默认 ListLayout 内部已接管**(refine 默认 true)——常规无需干预,仅特殊高度场景覆写。
61
61
  - **完整能力演示**(toolbar 全形态 + 粘性三件套 + keepAlive 组合):`apps/reference/src/pages/list-layout/guide/`(最佳实践)、`pages/list-layout/sticky/`(粘性)、`pages/list-layout/module-demo/`(keepAlive 模块组合)——能力展示,非推荐默认。
62
62
 
63
+ ## 上下文默认值(直系父上下文)
64
+
65
+ 置于特定父容器槽位时,`ListLayout` 自动获得上下文默认值(`useContextDefaults` 解析直系父 DOM 的 `data-dc-slot`),消费方零传参;显式传 prop 仍优先。
66
+
67
+ | 场景 | prop | 自动默认 |
68
+ | --- | --- | --- |
69
+ | AppPage `#left` / `#right` 窄栏 | `tableMainProps` | 分页窄栏化:`{ pageLayout: "prev, pager, next", paginationBackground: false }` |
70
+ | 其他容器 / 独立使用 | `tableMainProps` | 不处理(透传 TableMain 默认分页) |
71
+
72
+ > ⚠️ 需上下文动态默认的 prop 不写 `withDefaults` 默认(详见 spec:`docs/specs/2026-08-14-080509-moderate-usecontextdefaults直系父上下文默认/spec.md`)。
73
+ > `ListLayout.refine` 默认恒 `true`(withDefaults),不参与上下文解析。
74
+
63
75
  ## API
64
76
  > ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
65
77
 
@@ -81,7 +93,7 @@ const { listPageConfig } = useSpaceConfig({
81
93
  | `rowKey` | `Extract<keyof T, string> \| ((row:T)=>string)`(必填) | — | 行键 |
82
94
  | `api` | `(params: TableApiParams<ExtractFormStringifyFromObject<PO,SO> & SQ>) => Promise<TableApiResult<T>>`(必填) | — | 列表取数 |
83
95
  | `refine` / `refineReduceHeight` / `viewportHeight` / `parentChannel` / `toolbar` / `showSwitchView` | 同 TableMain | refine `true`、refineReduceHeight `0` | 常用配置提升为直属扁平 prop(内部自行消化视口高度链;TableMain 恒收 `:refine="false"`,高度计算由 ListLayout 接管) |
84
- | `tableMainProps` | `Partial<Omit<TableMainProps, 上述 6 键 \| "api" \| "query" \| "injectInfo">>` | 未设 | TableMain 透传袋 |
96
+ | `tableMainProps` | `Partial<Omit<TableMainProps, 上述 6 键 \| "api" \| "query" \| "injectInfo">>` | 未设(上下文默认) | TableMain 透传袋;⚠️ 置于 AppPage `#left` / `#right` 窄栏时分页自动窄栏化(默认补 `{ pageLayout: "prev, pager, next", paginationBackground: false }`,经 `useContextDefaults` 直系父上下文解析,见下);显式传 `tableMainProps` 仍优先 |
85
97
 
86
98
  **直属行为 props**
87
99
 
@@ -1,6 +1,6 @@
1
1
  # ViewLayout(展示布局)
2
2
 
3
- > 展示空间布局壳:`props.api` 数据拉取(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容 + 精细流高度链(refine 默认开)。
3
+ > 展示空间布局壳:`props.api` 数据拉取(内部 `useActivated` 激活拉取)+ toolbar 对齐 `TableToolbar`(左/右 `ActionBtnGroup` extra 按钮 + 右侧 `AutoRefreshGroup` 自动刷新 / 手动刷新)+ 默认插槽自由内容 + 精细流高度链(refine 上下文默认:AppPage#default / TabsMain 页签内容内开)。
4
4
  > 范式页:`apps/reference/src/pages/view-layout/guide/`
5
5
 
6
6
  ## 定位
@@ -29,12 +29,12 @@
29
29
  - 激活即拉取:首访 mounted / KeepAlive 重新激活自动拉取,失活不拉(数据保留)
30
30
  - 右上角 AutoRefreshGroup 自动接管刷新按钮 / 自动刷新开关(`showAutoRefresh` / `showRefresh` 控制显隐)
31
31
  - toolbar 对齐 `TableToolbar` 结构:`leftExtraButtons` / `rightExtraButtons`(`ActionBtnGroup` 配置,`default-size="small"`)左右分栏;不含表格特有能力(导出 / 批量下载 / 视图切换)
32
- - **refine 默认开**:内容区可用高 = 视口高 − toolbar 高(`scope.viewportHeight` + 容器 max-height 双出口)——超高内滚
32
+ - **refine 上下文默认**:置于 AppPage `#default` / TabsMain 页签内容内默认开(精细流)——内容区可用高 = 视口高 − toolbar 高(`scope.viewportHeight` + 容器 max-height 双出口)——超高内滚;其余容器 / 独立使用回落自然流(按自身尺寸)
33
33
 
34
34
  ## 能力边界 / 按需使用
35
35
 
36
36
  - **默认即够用**:`api` + 默认插槽即得完整展示布局——refine 精细流 + 自动刷新开关/刷新按钮默认开。
37
- - **refine(精细流):默认 `true` 即够用。** 仅当展示内容无需视口高度预算(按自身尺寸渲染即可)才关 `refine`——关闭后 scope viewportHeight 为 undefined
37
+ - **refine(精细流):上下文默认。** 置于 AppPage `#default` / TabsMain 页签内容内默认 `true`(精细流);其他容器 / 独立使用默认 `false`(自然流,scope viewportHeight 为 undefined)。需精细流而上下文未命中时显式补 `refine`;展示内容无需视口高度预算(按自身尺寸渲染即可)时显式关。显式传 `refine` 恒优先。
38
38
  - `viewportHeight` / `channel` / `parentChannel`:默认不用。仅当 ViewLayout 需要参与可用高 scope 链(显式视口高 / 作为父提供 scope / 作为子定向消费祖先 scope)才配;⚠️ 每级 [MUST] 显式 `refine`、channel 名 [MUST NOT] 响应式变更。
39
39
  - `params`:仅当 api 需要拉取参数时传;⚠️ **响应式变化不自动重拉**(需要时调 `scope.refresh()`)。
40
40
  - `showAutoRefresh` / `showRefresh`:仅当不需要自动刷新或手动刷新时关。
@@ -42,6 +42,18 @@
42
42
  - **插槽内容自由编排**:纯展示 [MUST NOT] 套 PanelMain 作页级根(已废弃场景);需要结构化字段面板时在插槽内用 PanelMain,自由内容直接写。
43
43
  - **完整能力演示**:`apps/reference/src/pages/view-layout/guide/`——能力展示,非推荐默认。
44
44
 
45
+ ## 上下文默认值(直系父上下文)
46
+
47
+ 置于特定父容器槽位时,`ViewLayout` 的 `refine` 自动获得上下文默认值(`useContextDefaults` 解析直系父 DOM 的 `data-dc-slot`),消费方零传参;显式传 `refine` 仍优先。
48
+
49
+ | 场景 | prop | 自动默认 |
50
+ | --- | --- | --- |
51
+ | AppPage `#default` | `refine` | `true`(精细流) |
52
+ | TabsMain 页签内容内 | `refine` | `true`(精细流) |
53
+ | 其他容器 / 独立使用 | `refine` | 不处理(undefined ≡ false,自然流) |
54
+
55
+ > ⚠️ 需上下文动态默认的 prop 不写 `withDefaults` 默认(详见 spec:`docs/specs/2026-08-14-080509-moderate-usecontextdefaults直系父上下文默认/spec.md`)。
56
+
45
57
  ## API
46
58
  > ⚠️ API 以 types.ts 与组件源码为真相源;与文档冲突时以源码为准。
47
59
 
@@ -51,7 +63,7 @@
51
63
  | --- | --- | --- | --- |
52
64
  | `api` | `(params?: P) => Promise<R>`(必填) | — | 数据拉取函数;每次拉取(激活 / 手动刷新 / 自动刷新)传入 props.params(未传收 undefined) |
53
65
  | `params` | `P?` | — | 拉取参数;响应式变化不自动重拉(调 `scope.refresh()`) |
54
- | `refine` | `boolean?` | `true` | 精细流:包 HeightProvider 精确扣 toolbar reserve(WatchSize 量高),内容区可用高 + scope viewportHeight;false=自然流 |
66
+ | `refine` | `boolean?` | 上下文默认 | 精细流:包 HeightProvider 精确扣 toolbar reserve(WatchSize 量高),内容区可用高 + scope viewportHeight;false=自然流。默认由 `useContextDefaults` 按直系父解析:AppPage `#default` / TabsMain 页签内容内 `true`,否则 `false`;显式传值优先 |
55
67
  | `viewportHeight` | `number?` | — | 显式视口高,优先级最高;未传降级 inject SCOPE_VIEWPORT_MAX_HEIGHT scope 链 |
56
68
  | `channel` | `string?` | — | 作为父时的 scope 标识。⚠️ 与 parentChannel 均 [MUST NOT] 响应式变更(setup 期快照);且仅 refine=true 路径生效 |
57
69
  | `parentChannel` | `string?` | — | 作为子时定向消费的祖先 scope 标识(沿对象链 parent 找匹配) |
@@ -34,6 +34,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_PublicProps,
34
34
  minHeight: number;
35
35
  refineReduceHeight: number;
36
36
  refine: boolean;
37
+ showNav: boolean;
37
38
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
38
39
  declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
39
40
  export default _default;
@@ -16,6 +16,12 @@ type __VLS_Props = {
16
16
  navMode?: TabsMainTileNavMode;
17
17
  /** 角落 nav 距角像素 */
18
18
  navOffset?: number;
19
+ /**
20
+ * 角落 nav 显隐默认,默认 undefined(= **动态默认**:`refine` 显示 / 自然流隐藏,避免自然流
21
+ * sticky 占文档流);显式传 true/false 覆盖。⚠️ Boolean prop 缺席强转 false 会短路 `?? refine`,
22
+ * 故 withDefaults 填 undefined 使缺席 ≡ undefined(navVisible 才生效)。
23
+ */
24
+ showNav?: boolean;
19
25
  };
20
26
  type __VLS_PublicProps = {
21
27
  modelValue?: string;
@@ -238,6 +244,7 @@ declare const __VLS_component: import('vue').DefineComponent<__VLS_PublicProps,
238
244
  navPosition: TabsMainTileNavPosition;
239
245
  navMode: TabsMainTileNavMode;
240
246
  navOffset: number;
247
+ showNav: boolean;
241
248
  }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
242
249
  scrollRootRef: HTMLDivElement;
243
250
  anchorRef: ({
@@ -220,6 +220,11 @@ export interface TabsMainProps {
220
220
  * 平铺模式角落 nav 距角像素,默认 `12`。仅 `tile=true` 生效。
221
221
  */
222
222
  navOffset?: number;
223
+ /**
224
+ * 平铺模式角落 nav 显隐默认,默认 `undefined`(= **动态默认**:`refine=true` 显示 / 自然流隐藏,避免
225
+ * 自然流 sticky 占文档流)。显式传 `true`/`false` 覆盖动态默认。仅 `tile=true` 生效。
226
+ */
227
+ showNav?: boolean;
223
228
  }
224
229
  /** BooleanTag 标签色彩类型(派生 ElTag type,不重定义) */
225
230
  export type BooleanTagType = NonNullable<TagProps["type"]>;
@@ -1,2 +1,3 @@
1
1
  export * from './list-model';
2
2
  export * from './route';
3
+ export * from './slot-region';
@@ -0,0 +1,35 @@
1
+ /**
2
+ * 直系父上下文槽位标识(useContextDefaults 消费)。
3
+ *
4
+ * 宿主(AppPage / TabsMain)在槽内容**直系父包裹元素**上挂 `DC_SLOT_ATTR`,
5
+ * 消费 hook(useContextDefaults)读 `$el.parentElement` 命中 → 按 prop 解析上下文默认。
6
+ * 详见 spec:`docs/specs/2026-08-14-080509-moderate-usecontextdefaults直系父上下文默认/spec.md`
7
+ */
8
+ /** 槽位 attr key(唯一共享来源,宿主 / 消费方 / hook 同源 import)。 */
9
+ export declare const DC_SLOT_ATTR = "data-dc-slot";
10
+ /**
11
+ * 槽位区域数字枚举(宿主前缀命名)。
12
+ *
13
+ * 值用数字:运行期 DOM 只见数字、看不出槽位语义(防"有心人"扫 DOM 一眼识别);
14
+ * ⚠️ 注意这只是防扫一眼,**不是安全边界**——core 在公网 npm,枚举映射在包产物里可还原
15
+ * (L2/LiveView 才是秘方保护正解)。
16
+ */
17
+ export declare enum SlotRegion {
18
+ /** AppPage 默认槽(页面主体,ModalShelf 透明包裹后 `.app-page-shim` 为直系父) */
19
+ AppPage_Default = 1,
20
+ /** AppPage top 槽(通栏悬浮区) */
21
+ AppPage_Top = 2,
22
+ /** AppPage right 槽(侧向悬浮区) */
23
+ AppPage_Right = 3,
24
+ /** AppPage bottom 槽(通栏悬浮区) */
25
+ AppPage_Bottom = 4,
26
+ /** AppPage left 槽(侧向悬浮区) */
27
+ AppPage_Left = 5,
28
+ /** TabsMain 页签内容(tab item) */
29
+ TabsMain_Item = 6
30
+ }
31
+ /**
32
+ * 读 DOM 槽位数字值并守卫:数字读回是字符串,[MUST] 经本函数 `Number()` 强转 + 枚举值校验;
33
+ * 缺失 / 非法 → `undefined`(未命中 region = 不处理,由消费 hook 决定原样透传)。
34
+ */
35
+ export declare const parseSlotRegion: (raw: string | null | undefined) => SlotRegion | undefined;
@@ -0,0 +1,39 @@
1
+ import { ComputedRef } from 'vue';
2
+ import { SlotRegion } from '../config';
3
+ /** useContextDefaults resolver 上下文(resolver 内自带"显式 > 上下文 > 内建"合并)。 */
4
+ export interface UseContextDefaultsResolverCtx<P extends Record<string, any>> {
5
+ /** 直系父解析到的槽位区域(未命中 = undefined) */
6
+ parentInfo: SlotRegion | undefined;
7
+ /** props 原始值(未含上下文默认,含显式传值) */
8
+ props: P;
9
+ }
10
+ /**
11
+ * 直系父上下文默认值解析 hook(core 内部组合函数,**[MUST NOT] 出桶导出**——hooks 桶 index 注释锁面,规则 22;
12
+ * 使用者可枚举:ListLayout / ViewLayout / TabsMain)。
13
+ *
14
+ * 核心一句话:core 组件在特定父容器(槽位)中自动获得上下文默认值(如 ListLayout 放 AppPage#left/right
15
+ * 窄栏 → 分页配置自动窄栏化;ViewLayout/TabsMain refine 在 AppPage#default / TabsMain item → 默认 true),
16
+ * 消费方零传参;显式传 prop 仍优先。详见 spec:`docs/specs/2026-08-14-080509-moderate-usecontextdefaults直系父上下文默认/spec.md`
17
+ *
18
+ * 导出面 = `defaults` 声明过的键(动态名 `ctx${首字母大写}`,每个为 ComputedRef 最终值):
19
+ * `defaults: { refine }` → 返回 `{ ctxRefine: ComputedRef<...> }`;组件 `const { ctxRefine } = useContextDefaults(...)`。
20
+ * **[MUST NOT] 导出 defaults 之外的 props 键(不替代 props)**——组件其余 prop 照常 `props.xx`。
21
+ *
22
+ * 机制:
23
+ * - 直系父 DOM(`$el.parentElement`)上的 `DC_SLOT_ATTR`(数字)→ `parseSlotRegion` 守卫 → resolver 拿 `parentInfo`。
24
+ * - 对 `defaults` 每个键产独立 computed:`resolver({ props: getProps(), parentInfo: region })`;未命中 region
25
+ * 也跑 resolver——resolver 返回 `props.xx`(≡ 透传,零差异)。
26
+ * - resolver 自带合并:`props.xx ?? (parentInfo===X ? 上下文默认 : undefined)`(`??` 只在 undefined 走上下文 = 显式优先)。
27
+ * - region 结构静态(槽位不随生命周期变),挂载 / 激活后解析一次并缓存。
28
+ *
29
+ * 使用注意(规范注释,[MUST] 遵守):
30
+ * - 需上下文动态默认的 prop **[MUST NOT] 写 withDefaults 内建默认**(Boolean prop 缺席被 Vue 强转 false 会
31
+ * 短路 `??`,withDefaults 填 `undefined` 使缺席 ≡ undefined、合法;填内建 true/false 违规 → hook 首次调用
32
+ * 发 console.warn 防呆提示——次要流程,不阻塞)。详见本文件底部 warn 逻辑。
33
+ * - 模板 / 脚本一律用解构出的 `ctxXx`(模板 ComputedRef 自动解包),[MUST NOT] 用 `props.xx`(原始未解析值)。
34
+ * - resolver 内 `??` 与 `?:` 混用 [MUST] 加括号(`??` 优先级高于 `?:`,裸写会解析错)。
35
+ */
36
+ export declare const useContextDefaults: <P extends Record<string, any>, D extends Record<string, (ctx: UseContextDefaultsResolverCtx<P>) => unknown>>(options: {
37
+ getProps: () => P;
38
+ defaults: D;
39
+ }) => { [K in keyof D as `ctx${Capitalize<K & string>}`]: ComputedRef<D[K] extends (ctx: UseContextDefaultsResolverCtx<P>) => infer R ? R : unknown>; };
@@ -1,6 +1,6 @@
1
1
  declare const _default: {
2
2
  "name": "@done-coding/admin-core",
3
- "version": "0.22.1",
3
+ "version": "0.22.2",
4
4
  "description": "内部前端库"
5
5
  };
6
6