@composy/layout-runtime 0.0.1 → 0.0.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.
- package/CHANGELOG.md +35 -0
- package/README.md +101 -17
- package/dist/index.js +68 -20
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +191 -1
- package/dist/index.min.js.map +1 -0
- package/es/.dts-output-manifest.json +1 -0
- package/es/.dts.tsbuildinfo +1 -0
- package/es/index.d.ts +0 -1
- package/es/index.js +1 -1
- package/es/material-renderer.d.ts +0 -1
- package/es/material-renderer.js +40 -7
- package/es/material-renderer.js.map +1 -1
- package/es/runtime.d.ts +0 -1
- package/es/runtime.js +27 -12
- package/es/runtime.js.map +1 -1
- package/es/styles.d.ts +0 -1
- package/es/styles.js +3 -3
- package/es/styles.js.map +1 -1
- package/esm/index.js +13 -0
- package/esm/material-renderer.js +102 -0
- package/esm/material-renderer.js.map +1 -0
- package/esm/runtime.js +171 -0
- package/esm/runtime.js.map +1 -0
- package/esm/styles.js +39 -0
- package/esm/styles.js.map +1 -0
- package/lib/index.cjs +1 -1
- package/lib/{index.d.ts → index.d.cts} +0 -1
- package/lib/material-renderer.cjs +40 -7
- package/lib/material-renderer.cjs.map +1 -1
- package/lib/{material-renderer.d.ts → material-renderer.d.cts} +0 -1
- package/lib/runtime.cjs +27 -12
- package/lib/runtime.cjs.map +1 -1
- package/lib/{runtime.d.ts → runtime.d.cts} +0 -1
- package/lib/styles.cjs +3 -3
- package/lib/styles.cjs.map +1 -1
- package/lib/{styles.d.ts → styles.d.cts} +0 -1
- package/package.json +13 -7
- package/es/index.d.ts.map +0 -1
- package/es/material-renderer.d.ts.map +0 -1
- package/es/runtime.d.ts.map +0 -1
- package/es/styles.d.ts.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.2] - 2026-10-12
|
|
4
|
+
|
|
5
|
+
### ✨ 新功能
|
|
6
|
+
|
|
7
|
+
- **layout**: 添加 LDesign 项目配置文件 ([f61ae51](https://gitee.com/swimly/ldesign-layout/commit/f61ae51279dff52720216e15e7dffc6fd0b8c579)) - @swimly
|
|
8
|
+
|
|
9
|
+
### ♻️ 代码重构
|
|
10
|
+
|
|
11
|
+
- 重构项目为pnpm monorepo并初始化全量布局包 ([d6dda52](https://gitee.com/swimly/ldesign-layout/commit/d6dda528e132eff6f316f9dcb37c4dd11d4e98c7)) - @swimly
|
|
12
|
+
|
|
13
|
+
### 📝 文档更新
|
|
14
|
+
|
|
15
|
+
- 更新各包 README 文档 ([41ac588](https://gitee.com/swimly/ldesign-layout/commit/41ac588a7f0d949bc172b94318bccd1bf1ed0d49)) - @swimly
|
|
16
|
+
|
|
17
|
+
### 📦 构建系统
|
|
18
|
+
|
|
19
|
+
- **tsconfig**: 标准化所有包的tsconfig配置并添加声明生成配置 ([3e34f79](https://gitee.com/swimly/ldesign-layout/commit/3e34f79d84f2335710c86f2503dadec050de329e)) - @swimly
|
|
20
|
+
|
|
21
|
+
### 🔧 其他
|
|
22
|
+
|
|
23
|
+
- **layout**: 更新项目配置及依赖版本 ([5344532](https://gitee.com/swimly/ldesign-layout/commit/534453298534e85a3f6776f908290bffdb15b8a6)) - @swimly
|
|
24
|
+
- **layout**: 统一构建配置与文档体系,新增 Playground 示例 ([d8691a0](https://gitee.com/swimly/ldesign-layout/commit/d8691a0721bdf088b6c5585ac2826b1b851d746d)) - @swimly
|
|
25
|
+
- 修复多个package.json文件末尾缺失换行符的问题 ([df9b977](https://gitee.com/swimly/ldesign-layout/commit/df9b977cca8d88cb4df00583f6eea31fd0e8c51b)) - @swimly
|
|
26
|
+
- 更新各包依赖版本 ([1ce08a9](https://gitee.com/swimly/ldesign-layout/commit/1ce08a9e677780eb38298c4cabe92e5693424fc2)) - @swimly
|
|
27
|
+
- update layout (92 files) ([9c28da2](https://gitee.com/swimly/ldesign-layout/commit/9c28da243aebea0d2c1c20ccb4c996aae9f031fc)) - @swimly
|
|
28
|
+
|
|
29
|
+
### 👥 Contributors
|
|
30
|
+
|
|
31
|
+
swimly
|
|
32
|
+
|
|
33
|
+
### 📊 Statistics
|
|
34
|
+
|
|
35
|
+
- Total Commits: **9**
|
|
36
|
+
- Contributors: **1**
|
|
37
|
+
|
|
3
38
|
## 1.0.0-alpha.0
|
|
4
39
|
|
|
5
40
|
- Added the DOM-free CSS Grid runtime and responsive style serialization helpers.
|
package/README.md
CHANGED
|
@@ -1,17 +1,101 @@
|
|
|
1
|
-
# @composy/layout-runtime
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
# @composy/layout-runtime
|
|
2
|
+
|
|
3
|
+
LDesign 布局运行时,把 `LayoutDocument`
|
|
4
|
+
渲染到真实 DOM 容器,自动处理断点切换、Resize 观察与 item 生命周期。
|
|
5
|
+
|
|
6
|
+
## 安装
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm add @composy/layout-runtime @composy/layout-core
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## 目录结构
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
src/
|
|
16
|
+
├── index.ts
|
|
17
|
+
├── runtime.ts # createLayoutRuntime + LayoutRuntime
|
|
18
|
+
├── styles.ts # resolveGridStyle / resolveItemStyle
|
|
19
|
+
└── material-renderer.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 核心 API
|
|
23
|
+
|
|
24
|
+
### 接口:LayoutRuntime
|
|
25
|
+
|
|
26
|
+
| 方法 | 签名 | 说明 |
|
|
27
|
+
| --------------- | --------------------------------- | ---------- |
|
|
28
|
+
| `mount` | `() => void` | 挂载 |
|
|
29
|
+
| `update` | `(doc: LayoutDocument) => void` | 更新文档 |
|
|
30
|
+
| `setBreakpoint` | `(id?: BreakpointId) => void` | 切换断点 |
|
|
31
|
+
| `getBreakpoint` | `() => BreakpointId \| undefined` | 取当前断点 |
|
|
32
|
+
| `getContainer` | `() => HTMLElement` | 取容器 |
|
|
33
|
+
| `destroy` | `() => void` | 销毁 |
|
|
34
|
+
|
|
35
|
+
### 函数
|
|
36
|
+
|
|
37
|
+
| 名称 | 签名 | 用途 |
|
|
38
|
+
| --------------------- | ---------------------------------------------------------------- | -------------- |
|
|
39
|
+
| `createLayoutRuntime` | `(options: LayoutRuntimeOptions) => LayoutRuntime` | 创建运行时 |
|
|
40
|
+
| `resolveGridStyle` | `(doc, breakpointId) => { gridTemplateColumns, gap, direction }` | 计算容器网格 |
|
|
41
|
+
| `resolveItemStyle` | `(item, placement, gridStyle) => CSSStyleDeclaration` | 计算 item 样式 |
|
|
42
|
+
|
|
43
|
+
### LayoutRuntimeOptions
|
|
44
|
+
|
|
45
|
+
| 字段 | 类型 | 说明 |
|
|
46
|
+
| -------------------- | ------------------------------------------- | --------------------- |
|
|
47
|
+
| `container` | `HTMLElement` | 必需 |
|
|
48
|
+
| `document` | `LayoutDocument?` | 初始文档 |
|
|
49
|
+
| `getItemShell` | `(item) => HTMLElement` | 由宿主提供 item shell |
|
|
50
|
+
| `renderItem` | `(ctx) => LayoutRenderHandle` | 自定义渲染钩子 |
|
|
51
|
+
| `materials` | `MaterialRegistry \| MaterialDefinition[]?` | 物料注册表 |
|
|
52
|
+
| `observeResize` | `boolean?` | 是否监听 Resize |
|
|
53
|
+
| `onBreakpointChange` | `(id) => void` | 断点切换回调 |
|
|
54
|
+
| `onError` | `(error) => void` | 错误回调 |
|
|
55
|
+
|
|
56
|
+
## 使用示例
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { createLayoutRuntime } from '@composy/layout-runtime'
|
|
60
|
+
import { createLayoutDocument } from '@composy/layout-core'
|
|
61
|
+
|
|
62
|
+
const container = document.getElementById('layout') as HTMLElement
|
|
63
|
+
const runtime = createLayoutRuntime({
|
|
64
|
+
container,
|
|
65
|
+
observeResize: true,
|
|
66
|
+
renderItem: ctx => {
|
|
67
|
+
ctx.shell.innerHTML = ctx.item.label ?? ''
|
|
68
|
+
return { update: n => (n.shell.innerHTML = n.item.label ?? '') }
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
runtime.mount()
|
|
73
|
+
runtime.update(
|
|
74
|
+
createLayoutDocument({
|
|
75
|
+
version: 1,
|
|
76
|
+
name: 'App',
|
|
77
|
+
defaultBreakpointId: 'lg',
|
|
78
|
+
breakpoints: [{ id: 'lg', min: 1024 }],
|
|
79
|
+
items: [
|
|
80
|
+
{ id: 'a', type: 'panel', label: 'A', placement: { grid: [0, 0, 4, 3] } },
|
|
81
|
+
{ id: 'b', type: 'panel', label: 'B', placement: { grid: [0, 3, 4, 6] } },
|
|
82
|
+
],
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 构建脚本 & 验证命令
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pnpm build
|
|
91
|
+
pnpm type-check
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 产物说明
|
|
95
|
+
|
|
96
|
+
- `es/` / `lib/` / `dist/`。
|
|
97
|
+
|
|
98
|
+
## 备注
|
|
99
|
+
|
|
100
|
+
- 依赖 `@composy/layout-core`。
|
|
101
|
+
- `observeResize: true` 时用 `ResizeObserver` 自动切换断点。
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ***********************************
|
|
3
3
|
* @composy/layout-runtime v0.0.1 *
|
|
4
4
|
* Built with rollup *
|
|
5
|
-
* Build time: 2024-
|
|
5
|
+
* Build time: 2024-10-12 17:44:18 *
|
|
6
6
|
* Build mode: production *
|
|
7
7
|
* Minified: No *
|
|
8
8
|
* ***********************************
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
gap: `${grid.gap}px`,
|
|
24
24
|
direction: grid.direction
|
|
25
25
|
};
|
|
26
|
-
if (document.grid.minRows !== void 0) style.minHeight = `${document.grid.minRows * (grid.rowSize + grid.gap) - grid.gap}px`;
|
|
27
|
-
if (document.grid.maxRows !== void 0) style.maxHeight = `${document.grid.maxRows * (grid.rowSize + grid.gap) - grid.gap}px`;
|
|
26
|
+
if (document.grid.minRows !== void 0) style.minHeight = `${Math.max(0, document.grid.minRows * (grid.rowSize + grid.gap) - grid.gap)}px`;
|
|
27
|
+
if (document.grid.maxRows !== void 0) style.maxHeight = `${Math.max(0, document.grid.maxRows * (grid.rowSize + grid.gap) - grid.gap)}px`;
|
|
28
28
|
if (breakpoint?.canvasWidth) style.gridTemplateColumns = `repeat(${grid.columns}, minmax(0, 1fr))`;
|
|
29
29
|
return style;
|
|
30
30
|
}
|
|
@@ -57,17 +57,26 @@
|
|
|
57
57
|
placement: context.placement,
|
|
58
58
|
breakpointId: context.breakpointId
|
|
59
59
|
});
|
|
60
|
-
if (rendered
|
|
60
|
+
if (isDomNode(rendered)) node = rendered;
|
|
61
61
|
else if (typeof rendered === "string") {
|
|
62
62
|
const wrapper = host.createElement("div");
|
|
63
|
-
wrapper.innerHTML = sanitizeMarkup(rendered);
|
|
63
|
+
wrapper.innerHTML = sanitizeMarkup(host, rendered);
|
|
64
64
|
node = wrapper;
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
if (!node) return void 0;
|
|
68
|
+
const appliedProps = /* @__PURE__ */ new Set();
|
|
68
69
|
const applyProps = (item) => {
|
|
69
|
-
if (!(node
|
|
70
|
-
|
|
70
|
+
if (!isElement(node, host)) return;
|
|
71
|
+
const nextProps = item.props ?? {};
|
|
72
|
+
for (const key of appliedProps) {
|
|
73
|
+
if (key in nextProps) continue;
|
|
74
|
+
node.removeAttribute(key);
|
|
75
|
+
delete node.dataset[`prop${toDataKey(key)}`];
|
|
76
|
+
appliedProps.delete(key);
|
|
77
|
+
}
|
|
78
|
+
for (const [key, value] of Object.entries(nextProps)) {
|
|
79
|
+
appliedProps.add(key);
|
|
71
80
|
try {
|
|
72
81
|
node[key] = value;
|
|
73
82
|
} catch {}
|
|
@@ -90,8 +99,32 @@
|
|
|
90
99
|
function toDataKey(value) {
|
|
91
100
|
return value.replace(/[^a-zA-Z0-9]/g, "");
|
|
92
101
|
}
|
|
93
|
-
function
|
|
94
|
-
return value
|
|
102
|
+
function isDomNode(value) {
|
|
103
|
+
return Boolean(value && typeof value === "object" && "nodeType" in value && typeof value.cloneNode === "function");
|
|
104
|
+
}
|
|
105
|
+
function isElement(value, document) {
|
|
106
|
+
if (!value || value.nodeType !== 1) return false;
|
|
107
|
+
const ElementConstructor = document.defaultView?.HTMLElement;
|
|
108
|
+
return ElementConstructor ? value instanceof ElementConstructor : typeof value.setAttribute === "function";
|
|
109
|
+
}
|
|
110
|
+
function sanitizeMarkup(document, value) {
|
|
111
|
+
const template = document.createElement("template");
|
|
112
|
+
template.innerHTML = value;
|
|
113
|
+
template.content.querySelectorAll("script,style,iframe,object,embed,foreignObject").forEach((node) => node.remove());
|
|
114
|
+
template.content.querySelectorAll("*").forEach((element) => {
|
|
115
|
+
for (const attribute of Array.from(element.attributes)) {
|
|
116
|
+
const name = attribute.name.toLowerCase();
|
|
117
|
+
const content = attribute.value.trim().toLowerCase();
|
|
118
|
+
if (name.startsWith("on") || [
|
|
119
|
+
"href",
|
|
120
|
+
"src",
|
|
121
|
+
"xlink:href",
|
|
122
|
+
"formaction",
|
|
123
|
+
"srcdoc"
|
|
124
|
+
].includes(name) && /^(?:javascript:|data:text\/html)/i.test(content)) element.removeAttribute(attribute.name);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
return template.innerHTML;
|
|
95
128
|
}
|
|
96
129
|
//#endregion
|
|
97
130
|
//#region src/runtime.ts
|
|
@@ -119,15 +152,11 @@
|
|
|
119
152
|
const currentIds = new Set(document.items.map((item) => item.id));
|
|
120
153
|
for (const [id, handle] of handles) {
|
|
121
154
|
if (currentIds.has(id)) continue;
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (shell && ownedShells.has(shell)) shell.remove();
|
|
128
|
-
if (shell) ownedShells.delete(shell);
|
|
129
|
-
shells.delete(id);
|
|
130
|
-
}
|
|
155
|
+
disposeHandle(id, handle);
|
|
156
|
+
const shell = shells.get(id);
|
|
157
|
+
if (shell && ownedShells.has(shell)) shell.remove();
|
|
158
|
+
if (shell) ownedShells.delete(shell);
|
|
159
|
+
shells.delete(id);
|
|
131
160
|
}
|
|
132
161
|
for (const item of document.items) {
|
|
133
162
|
const placement = item.layout[breakpointId];
|
|
@@ -145,7 +174,11 @@
|
|
|
145
174
|
shells.set(item.id, shell);
|
|
146
175
|
}
|
|
147
176
|
Object.assign(shell.style, resolveItemStyle(item, breakpointId));
|
|
148
|
-
if (!placement)
|
|
177
|
+
if (!placement) {
|
|
178
|
+
const handle = handles.get(item.id);
|
|
179
|
+
if (handle) disposeHandle(item.id, handle);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
149
182
|
const context = {
|
|
150
183
|
shell,
|
|
151
184
|
item,
|
|
@@ -163,6 +196,15 @@
|
|
|
163
196
|
}
|
|
164
197
|
}
|
|
165
198
|
}
|
|
199
|
+
function disposeHandle(id, handle = handles.get(id)) {
|
|
200
|
+
if (!handle) return;
|
|
201
|
+
handles.delete(id);
|
|
202
|
+
try {
|
|
203
|
+
handle.destroy?.();
|
|
204
|
+
} catch (error) {
|
|
205
|
+
options.onError?.(error);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
166
208
|
function updateBreakpoint(width) {
|
|
167
209
|
if (!document || manualBreakpoint) return;
|
|
168
210
|
const next = (0, _composy_layout_core.resolveBreakpoint)(document, width).id;
|
|
@@ -203,6 +245,10 @@
|
|
|
203
245
|
render();
|
|
204
246
|
},
|
|
205
247
|
setBreakpoint(id) {
|
|
248
|
+
if (id && document && !document.breakpoints.some((bp) => bp.id === id)) {
|
|
249
|
+
options.onError?.(/* @__PURE__ */ new Error(`Unknown breakpoint ${id}.`));
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
206
252
|
manualBreakpoint = id;
|
|
207
253
|
if (id) activeBreakpoint = id;
|
|
208
254
|
else updateBreakpointFromContainer();
|
|
@@ -218,7 +264,7 @@
|
|
|
218
264
|
if (!mounted) return;
|
|
219
265
|
observer?.disconnect();
|
|
220
266
|
observer = void 0;
|
|
221
|
-
for (const handle of handles
|
|
267
|
+
for (const [id, handle] of handles) disposeHandle(id, handle);
|
|
222
268
|
handles.clear();
|
|
223
269
|
for (const shell of shells.values()) if (ownedShells.has(shell)) shell.remove();
|
|
224
270
|
shells.clear();
|
|
@@ -230,6 +276,8 @@
|
|
|
230
276
|
options.container.style.removeProperty("direction");
|
|
231
277
|
options.container.style.removeProperty("min-height");
|
|
232
278
|
options.container.style.removeProperty("max-height");
|
|
279
|
+
manualBreakpoint = void 0;
|
|
280
|
+
activeBreakpoint = void 0;
|
|
233
281
|
mounted = false;
|
|
234
282
|
}
|
|
235
283
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/styles.ts","../src/material-renderer.ts","../src/runtime.ts"],"sourcesContent":["import type {\n BreakpointId,\n LayoutDocument,\n LayoutNode,\n LayoutPlacement,\n} from '@composy/layout-core'\nimport { getEffectiveGrid, getBreakpoint } from '@composy/layout-core'\n\nexport interface GridStyleResult {\n display: 'grid'\n gridTemplateColumns: string\n gridAutoRows: string\n gap: string\n direction: 'ltr' | 'rtl'\n minHeight?: string\n maxHeight?: string\n}\n\nexport function resolveGridStyle(\n document: LayoutDocument,\n breakpointId: BreakpointId\n): GridStyleResult {\n const grid = getEffectiveGrid(document, breakpointId)\n const breakpoint = getBreakpoint(document, breakpointId)\n const style: GridStyleResult = {\n display: 'grid',\n gridTemplateColumns: `repeat(${grid.columns}, minmax(0, 1fr))`,\n gridAutoRows: `${grid.rowSize}px`,\n gap: `${grid.gap}px`,\n direction: grid.direction,\n }\n if (document.grid.minRows !== undefined)\n style.minHeight = `${document.grid.minRows * (grid.rowSize + grid.gap) - grid.gap}px`\n if (document.grid.maxRows !== undefined)\n style.maxHeight = `${document.grid.maxRows * (grid.rowSize + grid.gap) - grid.gap}px`\n if (breakpoint?.canvasWidth)\n style.gridTemplateColumns = `repeat(${grid.columns}, minmax(0, 1fr))`\n return style\n}\n\nexport function resolveItemStyle(\n node: LayoutNode,\n breakpointId: BreakpointId\n): Record<string, string> {\n const placement = node.layout[breakpointId]\n if (!placement) return { display: 'none' }\n return {\n gridColumn: `${placement.x + 1} / span ${placement.w}`,\n gridRow: `${placement.y + 1} / span ${placement.h}`,\n display: placement.hidden ? 'none' : '',\n }\n}\n","import {\n createMaterialRegistry,\n type LayoutNode,\n type MaterialDefinition,\n type MaterialRegistry,\n} from '@composy/layout-core'\nimport type { LayoutRenderContext, LayoutRenderHandle } from './runtime'\n\nexport type RuntimeMaterialSource =\n MaterialRegistry | readonly MaterialDefinition[] | undefined\n\nexport function normalizeMaterialSource(\n source: RuntimeMaterialSource\n): MaterialRegistry | undefined {\n if (!source) return undefined\n if (Array.isArray(source)) return createMaterialRegistry(source)\n return source as MaterialRegistry\n}\n\nexport function renderRuntimeMaterial(\n context: LayoutRenderContext,\n materials: MaterialRegistry | undefined\n): LayoutRenderHandle | undefined {\n const material = materials?.get(context.item.type)\n const renderer =\n material?.renderers?.webcomponent ?? material?.renderers?.html\n if (!material || !renderer) return undefined\n\n const host = context.shell.ownerDocument\n let node: Node | undefined\n if (renderer.tagName) {\n node = host.createElement(renderer.tagName)\n } else if (renderer.render) {\n const rendered = renderer.render({\n item: context.item,\n placement: context.placement,\n breakpointId: context.breakpointId,\n })\n if (rendered instanceof Node) node = rendered\n else if (typeof rendered === 'string') {\n const wrapper = host.createElement('div')\n wrapper.innerHTML = sanitizeMarkup(rendered)\n node = wrapper\n }\n }\n if (!node) return undefined\n\n const applyProps = (item: LayoutNode): void => {\n if (!(node instanceof HTMLElement)) return\n for (const [key, value] of Object.entries(item.props ?? {})) {\n try {\n ;(node as unknown as Record<string, unknown>)[key] = value\n } catch {\n // Some custom elements expose readonly properties. The attribute is a\n // useful fallback for string-like values.\n }\n if (\n value === null ||\n value === undefined ||\n typeof value === 'object' ||\n typeof value === 'function'\n ) {\n if (value !== null && value !== undefined)\n node.dataset[`prop${toDataKey(key)}`] = JSON.stringify(value)\n } else node.setAttribute(key, String(value))\n }\n }\n applyProps(context.item)\n context.shell.replaceChildren(node)\n return {\n update(next) {\n applyProps(next.item)\n },\n destroy() {\n if (node?.parentNode === context.shell) context.shell.removeChild(node)\n },\n }\n}\n\nfunction toDataKey(value: string): string {\n return value.replace(/[^a-zA-Z0-9]/g, '')\n}\n\nfunction sanitizeMarkup(value: string): string {\n return value\n .replace(/<script\\b[^>]*>[\\s\\S]*?<\\/script\\s*>/gi, '')\n .replace(/\\s+on[a-z]+\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s>]+)/gi, '')\n .replace(/\\s+(?:href|src)\\s*=\\s*(\"|')\\s*javascript:[^\"']*\\1/gi, '')\n}\n","import type {\n BreakpointId,\n LayoutDocument,\n LayoutNode,\n LayoutPlacement,\n MaterialDefinition,\n MaterialRegistry,\n} from '@composy/layout-core'\nimport { resolveBreakpoint, validateLayoutDocument } from '@composy/layout-core'\nimport { resolveGridStyle, resolveItemStyle } from './styles'\nimport {\n normalizeMaterialSource,\n renderRuntimeMaterial,\n} from './material-renderer'\n\nexport interface LayoutRenderContext {\n shell: HTMLElement\n item: LayoutNode\n placement: LayoutPlacement\n breakpointId: BreakpointId\n}\nexport interface LayoutRenderHandle {\n update?(context: LayoutRenderContext): void\n destroy?(): void\n}\nexport interface LayoutRuntimeOptions {\n container: HTMLElement\n document?: LayoutDocument\n /** Lets a host adapter provide an existing light-DOM item shell. */\n getItemShell?: (item: LayoutNode) => HTMLElement | undefined\n renderItem?: (context: LayoutRenderContext) => LayoutRenderHandle | void\n /** Material registry used by the framework-neutral default renderer. */\n materials?: MaterialRegistry | readonly MaterialDefinition[]\n observeResize?: boolean\n onBreakpointChange?: (id: BreakpointId) => void\n onError?: (error: unknown) => void\n}\n\nexport interface LayoutRuntime {\n mount(): void\n update(document: LayoutDocument): void\n setBreakpoint(id?: BreakpointId): void\n getBreakpoint(): BreakpointId | undefined\n getContainer(): HTMLElement\n destroy(): void\n}\n\nexport function createLayoutRuntime(\n options: LayoutRuntimeOptions\n): LayoutRuntime {\n let document = options.document\n let mounted = false\n let manualBreakpoint: BreakpointId | undefined\n let activeBreakpoint: BreakpointId | undefined\n let observer: ResizeObserver | undefined\n const handles = new Map<string, LayoutRenderHandle>()\n const shells = new Map<string, HTMLElement>()\n const ownedShells = new Set<HTMLElement>()\n const materials = normalizeMaterialSource(options.materials)\n\n function render(): void {\n if (!mounted || !document) return\n const result = validateLayoutDocument(document)\n if (!result.valid) {\n options.onError?.(\n new Error(result.issues[0]?.message ?? 'Invalid layout document')\n )\n return\n }\n const breakpointId =\n manualBreakpoint ?? activeBreakpoint ?? document.defaultBreakpointId\n activeBreakpoint = breakpointId\n const gridStyle = resolveGridStyle(document, breakpointId)\n Object.assign(options.container.style, gridStyle)\n const currentIds = new Set(document.items.map(item => item.id))\n for (const [id, handle] of handles) {\n if (currentIds.has(id)) continue\n try {\n handle.destroy?.()\n } finally {\n handles.delete(id)\n const shell = shells.get(id)\n if (shell && ownedShells.has(shell)) shell.remove()\n if (shell) ownedShells.delete(shell)\n shells.delete(id)\n }\n }\n for (const item of document.items) {\n const placement = item.layout[breakpointId]\n let shell = shells.get(item.id)\n if (!shell) {\n shell = options.getItemShell?.(item)\n if (!shell) {\n shell = options.container.ownerDocument.createElement('div')\n shell.className = 'ldesign-layout-item'\n shell.dataset.layoutItemId = item.id\n shell.dataset.layoutType = item.type\n ownedShells.add(shell)\n options.container.appendChild(shell)\n }\n shells.set(item.id, shell)\n }\n Object.assign(shell.style, resolveItemStyle(item, breakpointId))\n if (!placement) continue\n const context = { shell, item, placement, breakpointId }\n try {\n let handle = handles.get(item.id)\n if (!handle) {\n handle = options.renderItem\n ? (options.renderItem(context) ?? {})\n : (renderRuntimeMaterial(context, materials) ?? {})\n handles.set(item.id, handle)\n } else handle.update?.(context)\n } catch (error) {\n options.onError?.(error)\n }\n }\n }\n\n function updateBreakpoint(width: number): void {\n if (!document || manualBreakpoint) return\n const next = resolveBreakpoint(document, width).id\n if (next !== activeBreakpoint) {\n const previous = activeBreakpoint\n activeBreakpoint = next\n options.onBreakpointChange?.(next)\n if (previous !== next) render()\n }\n }\n\n function updateBreakpointFromContainer(): void {\n if (!document || manualBreakpoint) return\n const width =\n options.container.getBoundingClientRect().width ||\n options.container.clientWidth\n // A hidden or detached container has no measurable width. Keep the\n // document default until the first real resize instead of selecting the\n // smallest breakpoint for width 0.\n if (width > 0) updateBreakpoint(width)\n else if (activeBreakpoint !== document.defaultBreakpointId) {\n const previous = activeBreakpoint\n activeBreakpoint = document.defaultBreakpointId\n if (previous) options.onBreakpointChange?.(activeBreakpoint)\n }\n }\n\n return {\n mount() {\n if (mounted) return\n mounted = true\n if (\n options.observeResize !== false &&\n typeof ResizeObserver !== 'undefined'\n ) {\n observer = new ResizeObserver(entries => {\n const width =\n entries[0]?.contentRect.width ?? options.container.clientWidth\n if (width > 0) updateBreakpoint(width)\n else updateBreakpointFromContainer()\n })\n observer.observe(options.container)\n }\n updateBreakpointFromContainer()\n render()\n },\n update(next) {\n document = next\n render()\n },\n setBreakpoint(id) {\n manualBreakpoint = id\n if (id) activeBreakpoint = id\n else updateBreakpointFromContainer()\n render()\n },\n getBreakpoint() {\n return activeBreakpoint\n },\n getContainer() {\n return options.container\n },\n destroy() {\n if (!mounted) return\n observer?.disconnect()\n observer = undefined\n for (const handle of handles.values()) handle.destroy?.()\n handles.clear()\n for (const shell of shells.values())\n if (ownedShells.has(shell)) shell.remove()\n shells.clear()\n ownedShells.clear()\n options.container.style.removeProperty('display')\n options.container.style.removeProperty('grid-template-columns')\n options.container.style.removeProperty('grid-auto-rows')\n options.container.style.removeProperty('gap')\n options.container.style.removeProperty('direction')\n options.container.style.removeProperty('min-height')\n options.container.style.removeProperty('max-height')\n mounted = false\n },\n }\n}\n\nexport { resolveGridStyle, resolveItemStyle }\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/styles.ts","../src/material-renderer.ts","../src/runtime.ts"],"sourcesContent":["import type {\n BreakpointId,\n LayoutDocument,\n LayoutNode,\n LayoutPlacement,\n} from '@composy/layout-core'\nimport { getEffectiveGrid, getBreakpoint } from '@composy/layout-core'\n\nexport interface GridStyleResult {\n display: 'grid'\n gridTemplateColumns: string\n gridAutoRows: string\n gap: string\n direction: 'ltr' | 'rtl'\n minHeight?: string\n maxHeight?: string\n}\n\nexport function resolveGridStyle(\n document: LayoutDocument,\n breakpointId: BreakpointId\n): GridStyleResult {\n const grid = getEffectiveGrid(document, breakpointId)\n const breakpoint = getBreakpoint(document, breakpointId)\n const style: GridStyleResult = {\n display: 'grid',\n gridTemplateColumns: `repeat(${grid.columns}, minmax(0, 1fr))`,\n gridAutoRows: `${grid.rowSize}px`,\n gap: `${grid.gap}px`,\n direction: grid.direction,\n }\n if (document.grid.minRows !== undefined)\n style.minHeight = `${Math.max(\n 0,\n document.grid.minRows * (grid.rowSize + grid.gap) - grid.gap\n )}px`\n if (document.grid.maxRows !== undefined)\n style.maxHeight = `${Math.max(\n 0,\n document.grid.maxRows * (grid.rowSize + grid.gap) - grid.gap\n )}px`\n if (breakpoint?.canvasWidth)\n style.gridTemplateColumns = `repeat(${grid.columns}, minmax(0, 1fr))`\n return style\n}\n\nexport function resolveItemStyle(\n node: LayoutNode,\n breakpointId: BreakpointId\n): Record<string, string> {\n const placement = node.layout[breakpointId]\n if (!placement) return { display: 'none' }\n return {\n gridColumn: `${placement.x + 1} / span ${placement.w}`,\n gridRow: `${placement.y + 1} / span ${placement.h}`,\n display: placement.hidden ? 'none' : '',\n }\n}\n","import {\n createMaterialRegistry,\n type LayoutNode,\n type MaterialDefinition,\n type MaterialRegistry,\n} from '@composy/layout-core'\nimport type { LayoutRenderContext, LayoutRenderHandle } from './runtime'\n\nexport type RuntimeMaterialSource =\n MaterialRegistry | readonly MaterialDefinition[] | undefined\n\nexport function normalizeMaterialSource(\n source: RuntimeMaterialSource\n): MaterialRegistry | undefined {\n if (!source) return undefined\n if (Array.isArray(source)) return createMaterialRegistry(source)\n return source as MaterialRegistry\n}\n\nexport function renderRuntimeMaterial(\n context: LayoutRenderContext,\n materials: MaterialRegistry | undefined\n): LayoutRenderHandle | undefined {\n const material = materials?.get(context.item.type)\n const renderer =\n material?.renderers?.webcomponent ?? material?.renderers?.html\n if (!material || !renderer) return undefined\n\n const host = context.shell.ownerDocument\n let node: Node | undefined\n if (renderer.tagName) {\n node = host.createElement(renderer.tagName)\n } else if (renderer.render) {\n const rendered = renderer.render({\n item: context.item,\n placement: context.placement,\n breakpointId: context.breakpointId,\n })\n if (isDomNode(rendered)) node = rendered\n else if (typeof rendered === 'string') {\n const wrapper = host.createElement('div')\n wrapper.innerHTML = sanitizeMarkup(host, rendered)\n node = wrapper\n }\n }\n if (!node) return undefined\n\n const appliedProps = new Set<string>()\n const applyProps = (item: LayoutNode): void => {\n if (!isElement(node, host)) return\n const nextProps = item.props ?? {}\n for (const key of appliedProps) {\n if (key in nextProps) continue\n node.removeAttribute(key)\n delete node.dataset[`prop${toDataKey(key)}`]\n appliedProps.delete(key)\n }\n for (const [key, value] of Object.entries(nextProps)) {\n appliedProps.add(key)\n try {\n ;(node as unknown as Record<string, unknown>)[key] = value\n } catch {\n // Some custom elements expose readonly properties. The attribute is a\n // useful fallback for string-like values.\n }\n if (\n value === null ||\n value === undefined ||\n typeof value === 'object' ||\n typeof value === 'function'\n ) {\n if (value !== null && value !== undefined)\n node.dataset[`prop${toDataKey(key)}`] = JSON.stringify(value)\n } else node.setAttribute(key, String(value))\n }\n }\n applyProps(context.item)\n context.shell.replaceChildren(node)\n return {\n update(next) {\n applyProps(next.item)\n },\n destroy() {\n if (node?.parentNode === context.shell) context.shell.removeChild(node)\n },\n }\n}\n\nfunction toDataKey(value: string): string {\n return value.replace(/[^a-zA-Z0-9]/g, '')\n}\n\nfunction isDomNode(value: unknown): value is Node {\n return Boolean(\n value &&\n typeof value === 'object' &&\n 'nodeType' in value &&\n typeof (value as { cloneNode?: unknown }).cloneNode === 'function'\n )\n}\n\nfunction isElement(\n value: Node | undefined,\n document: Document\n): value is HTMLElement {\n if (!value || value.nodeType !== 1) return false\n const ElementConstructor = document.defaultView?.HTMLElement\n return ElementConstructor\n ? value instanceof ElementConstructor\n : typeof (value as Element).setAttribute === 'function'\n}\n\nfunction sanitizeMarkup(document: Document, value: string): string {\n const template = document.createElement('template')\n template.innerHTML = value\n template.content\n .querySelectorAll('script,style,iframe,object,embed,foreignObject')\n .forEach(node => node.remove())\n template.content.querySelectorAll<HTMLElement>('*').forEach(element => {\n for (const attribute of Array.from(element.attributes)) {\n const name = attribute.name.toLowerCase()\n const content = attribute.value.trim().toLowerCase()\n if (\n name.startsWith('on') ||\n (['href', 'src', 'xlink:href', 'formaction', 'srcdoc'].includes(name) &&\n /^(?:javascript:|data:text\\/html)/i.test(content))\n )\n element.removeAttribute(attribute.name)\n }\n })\n return template.innerHTML\n}\n","import type {\n BreakpointId,\n LayoutDocument,\n LayoutNode,\n LayoutPlacement,\n MaterialDefinition,\n MaterialRegistry,\n} from '@composy/layout-core'\nimport { resolveBreakpoint, validateLayoutDocument } from '@composy/layout-core'\nimport { resolveGridStyle, resolveItemStyle } from './styles'\nimport {\n normalizeMaterialSource,\n renderRuntimeMaterial,\n} from './material-renderer'\n\nexport interface LayoutRenderContext {\n shell: HTMLElement\n item: LayoutNode\n placement: LayoutPlacement\n breakpointId: BreakpointId\n}\nexport interface LayoutRenderHandle {\n update?(context: LayoutRenderContext): void\n destroy?(): void\n}\nexport interface LayoutRuntimeOptions {\n container: HTMLElement\n document?: LayoutDocument\n /** Lets a host adapter provide an existing light-DOM item shell. */\n getItemShell?: (item: LayoutNode) => HTMLElement | undefined\n renderItem?: (context: LayoutRenderContext) => LayoutRenderHandle | void\n /** Material registry used by the framework-neutral default renderer. */\n materials?: MaterialRegistry | readonly MaterialDefinition[]\n observeResize?: boolean\n onBreakpointChange?: (id: BreakpointId) => void\n onError?: (error: unknown) => void\n}\n\nexport interface LayoutRuntime {\n mount(): void\n update(document: LayoutDocument): void\n setBreakpoint(id?: BreakpointId): void\n getBreakpoint(): BreakpointId | undefined\n getContainer(): HTMLElement\n destroy(): void\n}\n\nexport function createLayoutRuntime(\n options: LayoutRuntimeOptions\n): LayoutRuntime {\n let document = options.document\n let mounted = false\n let manualBreakpoint: BreakpointId | undefined\n let activeBreakpoint: BreakpointId | undefined\n let observer: ResizeObserver | undefined\n const handles = new Map<string, LayoutRenderHandle>()\n const shells = new Map<string, HTMLElement>()\n const ownedShells = new Set<HTMLElement>()\n const materials = normalizeMaterialSource(options.materials)\n\n function render(): void {\n if (!mounted || !document) return\n const result = validateLayoutDocument(document)\n if (!result.valid) {\n options.onError?.(\n new Error(result.issues[0]?.message ?? 'Invalid layout document')\n )\n return\n }\n const breakpointId =\n manualBreakpoint ?? activeBreakpoint ?? document.defaultBreakpointId\n activeBreakpoint = breakpointId\n const gridStyle = resolveGridStyle(document, breakpointId)\n Object.assign(options.container.style, gridStyle)\n const currentIds = new Set(document.items.map(item => item.id))\n for (const [id, handle] of handles) {\n if (currentIds.has(id)) continue\n disposeHandle(id, handle)\n const shell = shells.get(id)\n if (shell && ownedShells.has(shell)) shell.remove()\n if (shell) ownedShells.delete(shell)\n shells.delete(id)\n }\n for (const item of document.items) {\n const placement = item.layout[breakpointId]\n let shell = shells.get(item.id)\n if (!shell) {\n shell = options.getItemShell?.(item)\n if (!shell) {\n shell = options.container.ownerDocument.createElement('div')\n shell.className = 'ldesign-layout-item'\n shell.dataset.layoutItemId = item.id\n shell.dataset.layoutType = item.type\n ownedShells.add(shell)\n options.container.appendChild(shell)\n }\n shells.set(item.id, shell)\n }\n Object.assign(shell.style, resolveItemStyle(item, breakpointId))\n if (!placement) {\n const handle = handles.get(item.id)\n if (handle) disposeHandle(item.id, handle)\n continue\n }\n const context = { shell, item, placement, breakpointId }\n try {\n let handle = handles.get(item.id)\n if (!handle) {\n handle = options.renderItem\n ? (options.renderItem(context) ?? {})\n : (renderRuntimeMaterial(context, materials) ?? {})\n handles.set(item.id, handle)\n } else handle.update?.(context)\n } catch (error) {\n options.onError?.(error)\n }\n }\n }\n\n function disposeHandle(id: string, handle = handles.get(id)): void {\n if (!handle) return\n handles.delete(id)\n try {\n handle.destroy?.()\n } catch (error) {\n options.onError?.(error)\n }\n }\n\n function updateBreakpoint(width: number): void {\n if (!document || manualBreakpoint) return\n const next = resolveBreakpoint(document, width).id\n if (next !== activeBreakpoint) {\n const previous = activeBreakpoint\n activeBreakpoint = next\n options.onBreakpointChange?.(next)\n if (previous !== next) render()\n }\n }\n\n function updateBreakpointFromContainer(): void {\n if (!document || manualBreakpoint) return\n const width =\n options.container.getBoundingClientRect().width ||\n options.container.clientWidth\n // A hidden or detached container has no measurable width. Keep the\n // document default until the first real resize instead of selecting the\n // smallest breakpoint for width 0.\n if (width > 0) updateBreakpoint(width)\n else if (activeBreakpoint !== document.defaultBreakpointId) {\n const previous = activeBreakpoint\n activeBreakpoint = document.defaultBreakpointId\n if (previous) options.onBreakpointChange?.(activeBreakpoint)\n }\n }\n\n return {\n mount() {\n if (mounted) return\n mounted = true\n if (\n options.observeResize !== false &&\n typeof ResizeObserver !== 'undefined'\n ) {\n observer = new ResizeObserver(entries => {\n const width =\n entries[0]?.contentRect.width ?? options.container.clientWidth\n if (width > 0) updateBreakpoint(width)\n else updateBreakpointFromContainer()\n })\n observer.observe(options.container)\n }\n updateBreakpointFromContainer()\n render()\n },\n update(next) {\n document = next\n render()\n },\n setBreakpoint(id) {\n if (id && document && !document.breakpoints.some(bp => bp.id === id)) {\n options.onError?.(new Error(`Unknown breakpoint ${id}.`))\n return\n }\n manualBreakpoint = id\n if (id) activeBreakpoint = id\n else updateBreakpointFromContainer()\n render()\n },\n getBreakpoint() {\n return activeBreakpoint\n },\n getContainer() {\n return options.container\n },\n destroy() {\n if (!mounted) return\n observer?.disconnect()\n observer = undefined\n for (const [id, handle] of handles) disposeHandle(id, handle)\n handles.clear()\n for (const shell of shells.values())\n if (ownedShells.has(shell)) shell.remove()\n shells.clear()\n ownedShells.clear()\n options.container.style.removeProperty('display')\n options.container.style.removeProperty('grid-template-columns')\n options.container.style.removeProperty('grid-auto-rows')\n options.container.style.removeProperty('gap')\n options.container.style.removeProperty('direction')\n options.container.style.removeProperty('min-height')\n options.container.style.removeProperty('max-height')\n manualBreakpoint = undefined\n activeBreakpoint = undefined\n mounted = false\n },\n }\n}\n\nexport { resolveGridStyle, resolveItemStyle }\n"],"mappings":"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"}
|
package/dist/index.min.js
CHANGED
|
@@ -1 +1,191 @@
|
|
|
1
|
-
|
|
1
|
+
/*!
|
|
2
|
+
* ***********************************
|
|
3
|
+
* @composy/layout-runtime v0.0.1 *
|
|
4
|
+
* Built with rollup *
|
|
5
|
+
* Build time: 2024-10-12 17:44:18 *
|
|
6
|
+
* Build mode: production *
|
|
7
|
+
* Minified: No *
|
|
8
|
+
* ***********************************
|
|
9
|
+
*/
|
|
10
|
+
"use strict";
|
|
11
|
+
(function(e, t) {
|
|
12
|
+
"object" == typeof exports && "undefined" != typeof module ? t(exports, require("@composy/layout-core")) : "function" == typeof define && define.amd ? define(["exports", "@composy/layout-core"], t) : t((e = "undefined" != typeof globalThis ? globalThis : e || self).LDesignLayoutRuntime = {}, e.ComposyLayoutCore);
|
|
13
|
+
})(this, function(exports, e) {
|
|
14
|
+
function t(t, n) {
|
|
15
|
+
const o = (0, e.getEffectiveGrid)(t, n), r = (0, e.getBreakpoint)(t, n), i = {
|
|
16
|
+
display: "grid",
|
|
17
|
+
gridTemplateColumns: `repeat(${o.columns}, minmax(0, 1fr))`,
|
|
18
|
+
gridAutoRows: `${o.rowSize}px`,
|
|
19
|
+
gap: `${o.gap}px`,
|
|
20
|
+
direction: o.direction
|
|
21
|
+
};
|
|
22
|
+
return void 0 !== t.grid.minRows && (i.minHeight = `${Math.max(0, t.grid.minRows * (o.rowSize + o.gap) - o.gap)}px`), void 0 !== t.grid.maxRows && (i.maxHeight = `${Math.max(0, t.grid.maxRows * (o.rowSize + o.gap) - o.gap)}px`), r?.canvasWidth && (i.gridTemplateColumns = `repeat(${o.columns}, minmax(0, 1fr))`), i;
|
|
23
|
+
}
|
|
24
|
+
function n(e, t) {
|
|
25
|
+
const n = e.layout[t];
|
|
26
|
+
return n ? {
|
|
27
|
+
gridColumn: `${n.x + 1} / span ${n.w}`,
|
|
28
|
+
gridRow: `${n.y + 1} / span ${n.h}`,
|
|
29
|
+
display: n.hidden ? "none" : ""
|
|
30
|
+
} : { display: "none" };
|
|
31
|
+
}
|
|
32
|
+
function o(e, t) {
|
|
33
|
+
const n = t?.get(e.item.type), o = n?.renderers?.webcomponent ?? n?.renderers?.html;
|
|
34
|
+
if (!n || !o) return;
|
|
35
|
+
const i = e.shell.ownerDocument;
|
|
36
|
+
let a;
|
|
37
|
+
if (o.tagName) a = i.createElement(o.tagName);
|
|
38
|
+
else if (o.render) {
|
|
39
|
+
const t = o.render({
|
|
40
|
+
item: e.item,
|
|
41
|
+
placement: e.placement,
|
|
42
|
+
breakpointId: e.breakpointId
|
|
43
|
+
});
|
|
44
|
+
if (s = t, Boolean(s && "object" == typeof s && "nodeType" in s && "function" == typeof s.cloneNode)) a = t;
|
|
45
|
+
else if ("string" == typeof t) {
|
|
46
|
+
const e = i.createElement("div");
|
|
47
|
+
e.innerHTML = function(e, t) {
|
|
48
|
+
const n = e.createElement("template");
|
|
49
|
+
return n.innerHTML = t, n.content.querySelectorAll("script,style,iframe,object,embed,foreignObject").forEach((e) => e.remove()), n.content.querySelectorAll("*").forEach((e) => {
|
|
50
|
+
for (const t of Array.from(e.attributes)) {
|
|
51
|
+
const n = t.name.toLowerCase(), o = t.value.trim().toLowerCase();
|
|
52
|
+
(n.startsWith("on") || [
|
|
53
|
+
"href",
|
|
54
|
+
"src",
|
|
55
|
+
"xlink:href",
|
|
56
|
+
"formaction",
|
|
57
|
+
"srcdoc"
|
|
58
|
+
].includes(n) && /^(?:javascript:|data:text\/html)/i.test(o)) && e.removeAttribute(t.name);
|
|
59
|
+
}
|
|
60
|
+
}), n.innerHTML;
|
|
61
|
+
}(i, t), a = e;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var s;
|
|
65
|
+
if (!a) return;
|
|
66
|
+
const c = /* @__PURE__ */ new Set(), l = (e) => {
|
|
67
|
+
if (!function(e, t) {
|
|
68
|
+
if (!e || 1 !== e.nodeType) return !1;
|
|
69
|
+
const n = t.defaultView?.HTMLElement;
|
|
70
|
+
return n ? e instanceof n : "function" == typeof e.setAttribute;
|
|
71
|
+
}(a, i)) return;
|
|
72
|
+
const t = e.props ?? {};
|
|
73
|
+
for (const e of c) e in t || (a.removeAttribute(e), delete a.dataset[`prop${r(e)}`], c.delete(e));
|
|
74
|
+
for (const [e, n] of Object.entries(t)) {
|
|
75
|
+
c.add(e);
|
|
76
|
+
try {
|
|
77
|
+
a[e] = n;
|
|
78
|
+
} catch {}
|
|
79
|
+
null == n || "object" == typeof n || "function" == typeof n ? null != n && (a.dataset[`prop${r(e)}`] = JSON.stringify(n)) : a.setAttribute(e, String(n));
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return l(e.item), e.shell.replaceChildren(a), {
|
|
83
|
+
update(e) {
|
|
84
|
+
l(e.item);
|
|
85
|
+
},
|
|
86
|
+
destroy() {
|
|
87
|
+
a?.parentNode === e.shell && e.shell.removeChild(a);
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function r(e) {
|
|
92
|
+
return e.replace(/[^a-zA-Z0-9]/g, "");
|
|
93
|
+
}
|
|
94
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }), exports.createLayoutRuntime = function(r) {
|
|
95
|
+
let i, a, s, c = r.document, l = !1;
|
|
96
|
+
const d = /* @__PURE__ */ new Map(), u = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set(), p = function(t) {
|
|
97
|
+
if (t) return Array.isArray(t) ? (0, e.createMaterialRegistry)(t) : t;
|
|
98
|
+
}(r.materials);
|
|
99
|
+
function f() {
|
|
100
|
+
if (!l || !c) return;
|
|
101
|
+
const s = (0, e.validateLayoutDocument)(c);
|
|
102
|
+
if (!s.valid) return void r.onError?.(new Error(s.issues[0]?.message ?? "Invalid layout document"));
|
|
103
|
+
const f = i ?? a ?? c.defaultBreakpointId;
|
|
104
|
+
a = f;
|
|
105
|
+
const g = t(c, f);
|
|
106
|
+
Object.assign(r.container.style, g);
|
|
107
|
+
const h = new Set(c.items.map((e) => e.id));
|
|
108
|
+
for (const [e, t] of d) {
|
|
109
|
+
if (h.has(e)) continue;
|
|
110
|
+
y(e, t);
|
|
111
|
+
const n = u.get(e);
|
|
112
|
+
n && m.has(n) && n.remove(), n && m.delete(n), u.delete(e);
|
|
113
|
+
}
|
|
114
|
+
for (const e of c.items) {
|
|
115
|
+
const t = e.layout[f];
|
|
116
|
+
let i = u.get(e.id);
|
|
117
|
+
if (i || (i = r.getItemShell?.(e), i || (i = r.container.ownerDocument.createElement("div"), i.className = "ldesign-layout-item", i.dataset.layoutItemId = e.id, i.dataset.layoutType = e.type, m.add(i), r.container.appendChild(i)), u.set(e.id, i)), Object.assign(i.style, n(e, f)), !t) {
|
|
118
|
+
const t = d.get(e.id);
|
|
119
|
+
t && y(e.id, t);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const a = {
|
|
123
|
+
shell: i,
|
|
124
|
+
item: e,
|
|
125
|
+
placement: t,
|
|
126
|
+
breakpointId: f
|
|
127
|
+
};
|
|
128
|
+
try {
|
|
129
|
+
let t = d.get(e.id);
|
|
130
|
+
t ? t.update?.(a) : (t = r.renderItem ? r.renderItem(a) ?? {} : o(a, p) ?? {}, d.set(e.id, t));
|
|
131
|
+
} catch (e) {
|
|
132
|
+
r.onError?.(e);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function y(e, t = d.get(e)) {
|
|
137
|
+
if (t) {
|
|
138
|
+
d.delete(e);
|
|
139
|
+
try {
|
|
140
|
+
t.destroy?.();
|
|
141
|
+
} catch (e) {
|
|
142
|
+
r.onError?.(e);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function g(t) {
|
|
147
|
+
if (!c || i) return;
|
|
148
|
+
const n = (0, e.resolveBreakpoint)(c, t).id;
|
|
149
|
+
if (n !== a) {
|
|
150
|
+
const e = a;
|
|
151
|
+
a = n, r.onBreakpointChange?.(n), e !== n && f();
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function h() {
|
|
155
|
+
if (!c || i) return;
|
|
156
|
+
const e = r.container.getBoundingClientRect().width || r.container.clientWidth;
|
|
157
|
+
if (e > 0) g(e);
|
|
158
|
+
else if (a !== c.defaultBreakpointId) {
|
|
159
|
+
const e = a;
|
|
160
|
+
a = c.defaultBreakpointId, e && r.onBreakpointChange?.(a);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
mount() {
|
|
165
|
+
l || (l = !0, !1 !== r.observeResize && "undefined" != typeof ResizeObserver && (s = new ResizeObserver((e) => {
|
|
166
|
+
const t = e[0]?.contentRect.width ?? r.container.clientWidth;
|
|
167
|
+
t > 0 ? g(t) : h();
|
|
168
|
+
}), s.observe(r.container)), h(), f());
|
|
169
|
+
},
|
|
170
|
+
update(e) {
|
|
171
|
+
c = e, f();
|
|
172
|
+
},
|
|
173
|
+
setBreakpoint(e) {
|
|
174
|
+
e && c && !c.breakpoints.some((t) => t.id === e) ? r.onError?.(/* @__PURE__ */ new Error(`Unknown breakpoint ${e}.`)) : (i = e, e ? a = e : h(), f());
|
|
175
|
+
},
|
|
176
|
+
getBreakpoint: () => a,
|
|
177
|
+
getContainer: () => r.container,
|
|
178
|
+
destroy() {
|
|
179
|
+
if (l) {
|
|
180
|
+
s?.disconnect(), s = void 0;
|
|
181
|
+
for (const [e, t] of d) y(e, t);
|
|
182
|
+
d.clear();
|
|
183
|
+
for (const e of u.values()) m.has(e) && e.remove();
|
|
184
|
+
u.clear(), m.clear(), r.container.style.removeProperty("display"), r.container.style.removeProperty("grid-template-columns"), r.container.style.removeProperty("grid-auto-rows"), r.container.style.removeProperty("gap"), r.container.style.removeProperty("direction"), r.container.style.removeProperty("min-height"), r.container.style.removeProperty("max-height"), i = void 0, a = void 0, l = !1;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
}, exports.resolveGridStyle = t, exports.resolveItemStyle = n;
|
|
189
|
+
});
|
|
190
|
+
/*! End of @composy/layout-runtime | Powered by @composy/builder */
|
|
191
|
+
//# sourceMappingURL=index.min.js.map
|