@manohub/app-kit 0.2.5 → 0.2.6

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/CONTRACT.md CHANGED
@@ -783,9 +783,14 @@ pnpm --filter @manohub/app-kit test:unit # vitest(契约单测)+ 护栏
783
783
  而令牌(`--ui-*`)与主题桥接(`--f-theme-*`)都锚在 `.app-container` 上、微前端下应用侧 CSS 还被
784
784
  scopecss 限定在容器内 —— 落到 body 会让弹窗**内容里所有组件与应用样式一起失效**。
785
785
  `AppDialog` / `modalService` 内部已改投 `.app-container`,消费方无需也不应干预渲染宿主。
786
- 11. **抽屉的宿主与包含块**:`AppDrawer`(§4.18)同样把内容投到 `.app-container`(否则样式全丢),
787
- 而上游在「宿主不是 `body`」时会顺手给抽屉根节点加 `f-drawer-inline`(把 `position: fixed` 改成 `absolute`)——
788
- 微前端里绝对定位的包含块不可控(`.app-container` 自身未定位、宿主层级随门户而变),抽屉与遮罩会错位。
786
+ 11. **抽屉的宿主只接受「选择器字符串」**:`AppDrawer`(§4.18)同样把内容投到 `.app-container`(否则样式全丢),
787
+ 但**不能像 `AppDialog` 那样传 Element**:上游 `FDrawer` 算 `f-drawer-inline` 时写的是
788
+ `document.querySelector(host)`,传 Element 会拿 `"[object HTMLDivElement]"` 当选择器解析并抛
789
+ `SyntaxError: not a valid selector`(整页渲染中断,已在 mcp 实测)。本件走容器唯一 id 的
790
+ `#id` 字符串(`resolveAppContainerSelector()`)。
791
+ 随之而来的定位问题:上游在「宿主不是 `body`」时会给抽屉根节点加 `f-drawer-inline`
792
+ (把 `position: fixed` 改成 `absolute`)—— 微前端里绝对定位的包含块不可控
793
+ (`.app-container` 自身未定位、宿主层级随门户而变),抽屉与遮罩会错位。
789
794
  包内桥接层因此把 `.f-drawer.f-drawer-inline` 的定位压回 `fixed`:**覆盖范围与改造前 `host: "body"` 完全一致**。
790
795
  另:上游 `showFooter` 默认 `true` 且高度取 `footerHeight`(默认 60px),不给内容也留一条空白 ——
791
796
  `AppDrawer` 在无页脚时直接关掉该区块,应用侧不必再写「隐藏空 footer」的覆盖样式。
@@ -9,8 +9,12 @@ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
9
9
  * 吃掉的上游坑:
10
10
  * 1. **被当 DOM 容器的宽度**:上游 `width` 声明成 `String`、默认 `"300"`,值会原样落进行内 style
11
11
  * ⇒ `width:300` 不是合法 CSS,抽屉宽度会退化成「内容宽度」。本件默认 `width: 480`(数值 ⇒ `480px`)。
12
- * 2. **渲染宿主固定为 `.app-container`**:上游 `host` 默认 `"body"`,抽屉落容器外会同时丢令牌
13
- * (`--ui-*`)与应用侧样式(微前端下被 scopecss 限定在容器内)—— 与 AppDialog 同一件事。
12
+ * 2. **渲染宿主固定为 `.app-container`,且必须传「选择器字符串」**:上游 `host` 默认 `"body"`,
13
+ * 抽屉落容器外会同时丢令牌(`--ui-*`)与应用侧样式(微前端下被 scopecss 限定在容器内)——
14
+ * 与 AppDialog 同一件事。但**传法不同**:`FModal` 的 `host` 是 `Object`(可传 Element),
15
+ * `FDrawer` 算 `f-drawer-inline` 时写的是 `document.querySelector(host)` —— 传 Element 会拿
16
+ * `"[object HTMLDivElement]"` 当选择器解析并抛 `SyntaxError`(非法选择器,整页渲染中断)。
17
+ * 故这里走 `resolveAppContainerSelector()`(给容器补唯一 id 再返回 `#id`)。
14
18
  * 随之而来的第二个坑:上游在 host ≠ body 时给根节点加 `f-drawer-inline`(`position: absolute`),
15
19
  * 而绝对定位的包含块在微前端里不可控,包内桥接层已把它改回 `fixed`
16
20
  * (覆盖范围与改造前 `host: "body"` 一致)。
@@ -1,6 +1,6 @@
1
1
  import { FDrawer } from "@farris/ui-vue";
2
2
  import { defineComponent, computed, h } from "vue";
3
- import { resolveAppContainer } from "../services/app-container.js";
3
+ import { resolveAppContainerSelector } from "../services/app-container.js";
4
4
  const FarrisDrawer = FDrawer;
5
5
  let drawerSeq = 0;
6
6
  const AppDrawer = /* @__PURE__ */ defineComponent({
@@ -80,8 +80,8 @@ const AppDrawer = /* @__PURE__ */ defineComponent({
80
80
  * 无内容时关掉上游页脚区块 —— 否则恒定渲染一条 `footerHeight`(默认 60px)的空白。
81
81
  */
82
82
  showFooter: hasFooter,
83
- /** 渲染宿主:见头注释第 2 条(farris 默认 `"body"` 会让抽屉样式全丢) */
84
- host: resolveAppContainer(),
83
+ /** 渲染宿主:见头注释第 2 条(farris 默认 `"body"` 会让抽屉样式全丢;且上游只吃字符串选择器) */
84
+ host: resolveAppContainerSelector(),
85
85
  customClass: ["ak-drawer", attrs.class].filter(Boolean).join(" "),
86
86
  customStyle: attrs.style,
87
87
  "onUpdate:modelValue": handleUpdate
@@ -13,3 +13,17 @@
13
13
  * → `document.body`(兜底,行为与改写前一致,不会更差)。
14
14
  */
15
15
  export declare function resolveAppContainer(): Element;
16
+ /**
17
+ * 同 `resolveAppContainer`,但返回**选择器字符串** —— 给「上游只吃字符串宿主」的件用。
18
+ *
19
+ * 为什么不能直接给 Element:farris `FDrawer` 算 `f-drawer-inline` 时写的是
20
+ * `typeof host === 'string' ? host !== 'body' : document.querySelector(host)` ——
21
+ * 传 Element 会落到后半段,`document.querySelector(元素)` 拿到的是 `"[object HTMLDivElement]"`
22
+ * 这个**非法选择器**,当场抛 `SyntaxError: ... is not a valid selector`(实测,整页渲染因此中断)。
23
+ * (对照:`FModal` 的 `host` 声明为 `Object`,传 Element 正常 —— 两个件不是一套规则。)
24
+ *
25
+ * 给字符串又要避免「门户里多应用并存时串到第一个 `.app-container`」,故给容器补一个
26
+ * **进程内唯一 id** 再用 `#id` 定位;容器已有 id 时直接用它的。
27
+ * 兜底到 `document.body` 时返回 `"body"`(上游对该值有专门分支,不查 DOM)。
28
+ */
29
+ export declare function resolveAppContainerSelector(): string;
@@ -2,6 +2,21 @@ import { getCurrentAppContainer } from "./app-context.js";
2
2
  function resolveAppContainer() {
3
3
  return getCurrentAppContainer() ?? document.querySelector(".app-container") ?? document.body;
4
4
  }
5
+ const containerIds = /* @__PURE__ */ new WeakMap();
6
+ let containerSeq = 0;
7
+ function resolveAppContainerSelector() {
8
+ const container = resolveAppContainer();
9
+ if (container === document.body) return "body";
10
+ if (container.id) return `#${container.id}`;
11
+ let id = containerIds.get(container);
12
+ if (!id) {
13
+ id = `ak-app-container-${containerSeq += 1}`;
14
+ containerIds.set(container, id);
15
+ container.id = id;
16
+ }
17
+ return `#${id}`;
18
+ }
5
19
  export {
6
- resolveAppContainer
20
+ resolveAppContainer,
21
+ resolveAppContainerSelector
7
22
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@manohub/app-kit",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "子应用统一骨架层:入口编排(createSubApp)、布局契约(AppShell)、页面组件、原子件、服务、样式底座。farris 被收敛在本包内部,对外只暴露标准 API。",
@@ -63,7 +63,7 @@
63
63
  },
64
64
  "dependencies": {
65
65
  "@farris/ui-vue": "^1.8.4",
66
- "@manohub/icon": "^0.2.5"
66
+ "@manohub/icon": "^0.2.6"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@tanstack/vue-query": "catalog:",