@lark-apaas/coding-registry-buildless 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Lark Technologies Pte. Ltd. and/or its affiliates
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,provided that the above copyright notice and this permission notice appear in all copies.
6
+
7
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
8
+ IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
9
+ INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
10
+ EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
11
+ CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
12
+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
13
+ ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # @lark-apaas/coding-registry-buildless
2
+
3
+ > **Status:** alpha (v0.1) — 占位资产,待 SDK owner 填充真实 SDK。
4
+
5
+ **buildless 运行时**的 SDK registry(shadcn 式 copy-in 资产的单一事实源)。运行时契约 = *buildless(浏览器 Babel)+ 全局(window/UMD)+ CDN 钉版依赖*;当前由 design-html 栈使用,但本包按**运行时**而非 stack 命名,任何 buildless-globals 栈都可复用。
6
+
7
+ 被 [miaoda-cli](https://code.byted.org/apaas/miaoda-cli) 的 `miaoda registry` 命令消费:抓本包 tarball → 递归扫含 USAGE 块的 SDK 文件 → 把源码**按目录结构原样拷进**用户项目(项目持有、可改、不覆盖)。
8
+
9
+ **非运行时依赖**:buildless 栈不 `npm install` 本包;它只是个被 CLI 抓取的 catalog,与 template / steering 同分发模型。
10
+
11
+ ## 结构(内容平铺在包根,拷贝时 1:1 落地)
12
+
13
+ ```
14
+ scripts/ # 纯 JS / Web Component(如 deck-stage.js) → 项目 scripts/
15
+ components/ # React / JSX(如 tweaks-panel.jsx) → 项目 components/
16
+ stylesheets/ # CSS(按需) → 项目 stylesheets/
17
+ ```
18
+
19
+ `add` 保留文件相对包根的路径:`scripts/deck-stage.js` → 项目 `scripts/deck-stage.js`。无 `targets` 映射、不拍平。
20
+
21
+ ## 无 registry.json:USAGE 块即事实源
22
+
23
+ 不维护独立 manifest。每个 SDK 文件以 `/* BEGIN USAGE */ … /* END USAGE */` 注释块开头,声明 name / Exports(to window) / Usage / 约束,可选 `// Depends: <name>` 声明跨 SDK 依赖。
24
+
25
+ - 条目 `name` = 文件名去扩展名(`deck-stage.js` → `deck-stage`)。
26
+ - `miaoda registry list` 直接输出各文件 USAGE 块原文供 Agent 消费。
27
+ - `miaoda registry add <name>` 解析 `Depends` 闭包后按结构拷入。
28
+
29
+ ## 解析(CLI 怎么找到本包)
30
+
31
+ CLI 按项目运行时解析:`项目 stack → runtime → registry 包`(`design-html → buildless → @lark-apaas/coding-registry-buildless`)。本包以 `miaodaRegistry.runtime = "buildless"` 标明所服务的运行时。
32
+
33
+ ## 规范
34
+
35
+ SDK 开发规范(USAGE 块 / 全局导出 / CSS 隔离 / postMessage 协议 / data-miaoda-* / 状态持久化 / 画布缩放 / CDN 固定版本契约)见 [`docs/design-html-sdk-spec.md`](../../../docs/design-html-sdk-spec.md)。完整跨仓设计见飞书文档《design-html 组件 Registry —— 跨仓设计 Spec》。
36
+
37
+ ## License
38
+
39
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,92 @@
1
+ /* BEGIN USAGE */
2
+ // tweaks-panel.jsx — 风格切换/精调面板(React/JSX)
3
+ // Exports (to window): TweaksPanel, useTweaks
4
+ //
5
+ // Usage:
6
+ // const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{ "primaryColor": "#2563EB", "dark": false }/*EDITMODE-END*/;
7
+ // <TweaksPanel defaults={TWEAK_DEFAULTS}>
8
+ // <TweaksPanel.Color name="primaryColor" label="主色" />
9
+ // <TweaksPanel.Toggle name="dark" label="暗色" />
10
+ // </TweaksPanel>
11
+ // const { primaryColor } = useTweaks(); // 读当前精调值
12
+ //
13
+ // 约束(不可变契约):导出名 TweaksPanel/useTweaks;postMessage 协议 miaoda:tweaks:*;
14
+ // EDITMODE-BEGIN/END 标记语法;面板根元素带 data-miaoda-chrome。
15
+ // 定制面:精调项定义、控件、标签文案、默认值由 AI 自由编写。
16
+ /* END USAGE */
17
+
18
+ (function () {
19
+ const { createContext, useContext, useState, useEffect } = React;
20
+
21
+ // CSS 隔离:twk- 前缀 + 一次性注入去重
22
+ if (!document.getElementById('twk-styles')) {
23
+ const s = document.createElement('style');
24
+ s.id = 'twk-styles';
25
+ s.textContent = `
26
+ .twk-panel { position: fixed; right: 16px; top: 16px; z-index: 9999;
27
+ background: #fff; color: #111; border-radius: 12px; padding: 12px 14px;
28
+ box-shadow: 0 8px 30px rgba(0,0,0,.18); font: 13px system-ui; min-width: 200px; }
29
+ .twk-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 6px 0; }
30
+ `;
31
+ document.head.appendChild(s);
32
+ }
33
+
34
+ const TweaksCtx = createContext({});
35
+ const useTweaks = () => useContext(TweaksCtx);
36
+
37
+ function TweaksPanel({ defaults = {}, children }) {
38
+ const [values, setValues] = useState(defaults);
39
+
40
+ // 顺序铁律:先注册监听,再 postMessage 宣告可用
41
+ useEffect(() => {
42
+ const onMsg = (e) => {
43
+ if (e.data && e.data.type === 'miaoda:tweaks:set-keys') {
44
+ setValues((v) => ({ ...v, ...e.data.keys }));
45
+ }
46
+ };
47
+ window.addEventListener('message', onMsg);
48
+ try {
49
+ window.parent.postMessage({ type: 'miaoda:tweaks:available' }, '*');
50
+ } catch (_) {}
51
+ return () => window.removeEventListener('message', onMsg);
52
+ }, []);
53
+
54
+ const set = (name, value) => {
55
+ const next = { ...values, [name]: value };
56
+ setValues(next);
57
+ try {
58
+ window.parent.postMessage({ type: 'miaoda:tweaks:set-keys', keys: { [name]: value } }, '*');
59
+ } catch (_) {}
60
+ };
61
+
62
+ return (
63
+ <TweaksCtx.Provider value={{ ...values, __set: set }}>
64
+ <div className="twk-panel" data-miaoda-chrome>
65
+ {children}
66
+ </div>
67
+ </TweaksCtx.Provider>
68
+ );
69
+ }
70
+
71
+ TweaksPanel.Color = function ({ name, label }) {
72
+ const t = useTweaks();
73
+ return (
74
+ <label className="twk-row">
75
+ <span>{label}</span>
76
+ <input type="color" value={t[name] || '#000000'} onChange={(e) => t.__set(name, e.target.value)} />
77
+ </label>
78
+ );
79
+ };
80
+
81
+ TweaksPanel.Toggle = function ({ name, label }) {
82
+ const t = useTweaks();
83
+ return (
84
+ <label className="twk-row">
85
+ <span>{label}</span>
86
+ <input type="checkbox" checked={!!t[name]} onChange={(e) => t.__set(name, e.target.checked)} />
87
+ </label>
88
+ );
89
+ };
90
+
91
+ Object.assign(window, { TweaksPanel, useTweaks });
92
+ })();
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@lark-apaas/coding-registry-buildless",
3
+ "version": "0.1.0",
4
+ "description": "Miaoda registry (buildless runtime) — shadcn-style copy-in SDKs (globals + CDN-pinned, browser Babel) for buildless static HTML stacks",
5
+ "type": "module",
6
+ "files": ["scripts", "components", "stylesheets"],
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "registry": "https://registry.npmjs.org/"
10
+ },
11
+ "keywords": ["miaoda", "coding-registry", "buildless", "sdk", "shadcn", "copy-in"],
12
+ "license": "MIT",
13
+ "miaodaRegistry": {
14
+ "schemaVersion": 1,
15
+ "runtime": "buildless"
16
+ }
17
+ }
@@ -0,0 +1,118 @@
1
+ /* BEGIN USAGE */
2
+ // deck-stage.js — PPT/演示画布(纯 JS Web Component)
3
+ // Exports (to window): <deck-stage> custom element
4
+ //
5
+ // Usage:
6
+ // <deck-stage width="1920" height="1080">
7
+ // <section data-label="封面"><h1>标题</h1></section>
8
+ // <section data-label="目标">...</section>
9
+ // </deck-stage>
10
+ // element.goTo(n) // 跳到第 n 页(0-based)
11
+ // element.addEventListener('slidechange', e => e.detail.index)
12
+ //
13
+ // 约束(不可变契约):标签名 deck-stage;固定画布 width×height(默认 1920×1080);
14
+ // postMessage 协议 miaoda:deck:* / miaoda:canvas:*;导航 UI 带 data-miaoda-chrome。
15
+ // 定制面:每个 <section> 内的内容与样式由 AI 自由编写。
16
+ /* END USAGE */
17
+
18
+ (function () {
19
+ if (customElements.get('deck-stage')) return;
20
+
21
+ class DeckStage extends HTMLElement {
22
+ connectedCallback() {
23
+ const W = Number(this.getAttribute('width')) || 1920;
24
+ const H = Number(this.getAttribute('height')) || 1080;
25
+ this._w = W;
26
+ this._h = H;
27
+ this._index = 0;
28
+
29
+ // 把 light-dom 的 <section> 收为幻灯片
30
+ this._slides = Array.from(this.querySelectorAll(':scope > section'));
31
+
32
+ const shadow = this.attachShadow({ mode: 'open' });
33
+ shadow.innerHTML = `
34
+ <style>
35
+ :host { position: fixed; inset: 0; overflow: hidden; background: #000; }
36
+ .stage { position: absolute; top: 50%; left: 50%; width: ${W}px; height: ${H}px;
37
+ transform-origin: center; }
38
+ ::slotted(section) { position: absolute; inset: 0; box-sizing: border-box; }
39
+ ::slotted(section[hidden]) { display: none; }
40
+ .nav { position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%);
41
+ display: flex; gap: 8px; z-index: 10; }
42
+ .nav button { all: unset; cursor: pointer; padding: 6px 12px; border-radius: 8px;
43
+ background: rgba(255,255,255,.12); color: #fff; font: 13px system-ui; }
44
+ @media print {
45
+ :host { position: static; }
46
+ .stage { position: static; transform: none !important; width: ${W}px; height: ${H}px;
47
+ page-break-after: always; }
48
+ ::slotted(section[hidden]) { display: block !important; }
49
+ .nav { display: none; }
50
+ }
51
+ </style>
52
+ <div class="stage"><slot></slot></div>
53
+ <div class="nav" data-miaoda-chrome>
54
+ <button data-act="prev">‹</button><button data-act="next">›</button>
55
+ </div>
56
+ `;
57
+
58
+ this._stage = shadow.querySelector('.stage');
59
+ shadow.querySelector('[data-act="prev"]').onclick = () => this.goTo(this._index - 1);
60
+ shadow.querySelector('[data-act="next"]').onclick = () => this.goTo(this._index + 1);
61
+
62
+ this._onResize = () => this._fit();
63
+ window.addEventListener('resize', this._onResize);
64
+ this._onKey = (e) => {
65
+ if (e.key === 'ArrowRight') this.goTo(this._index + 1);
66
+ if (e.key === 'ArrowLeft') this.goTo(this._index - 1);
67
+ };
68
+ window.addEventListener('keydown', this._onKey);
69
+
70
+ // 顺序铁律:先注册监听,再宣告可用
71
+ window.addEventListener('message', (e) => {
72
+ if (e.data && e.data.type === 'miaoda:canvas:set-zoom') this._fit(e.data.zoom);
73
+ });
74
+ this._post('miaoda:canvas:present', {});
75
+
76
+ // 初始页可来自 URL ?slide=
77
+ const init = Number(new URLSearchParams(location.search).get('slide')) || 1;
78
+ this._fit();
79
+ this.goTo(init - 1);
80
+ }
81
+
82
+ disconnectedCallback() {
83
+ window.removeEventListener('resize', this._onResize);
84
+ window.removeEventListener('keydown', this._onKey);
85
+ }
86
+
87
+ _fit(zoom) {
88
+ const scale = zoom || Math.min(innerWidth / this._w, innerHeight / this._h);
89
+ this._stage.style.transform = `translate(-50%, -50%) scale(${scale})`;
90
+ this._post('miaoda:canvas:zoom', { zoom: scale });
91
+ }
92
+
93
+ _post(type, extra) {
94
+ try {
95
+ window.parent.postMessage({ type, ...extra }, '*');
96
+ } catch (_) {}
97
+ }
98
+
99
+ goTo(n) {
100
+ if (!this._slides.length) return;
101
+ this._index = Math.max(0, Math.min(n, this._slides.length - 1));
102
+ this._slides.forEach((el, i) => {
103
+ el.hidden = i !== this._index;
104
+ });
105
+ this.dispatchEvent(new CustomEvent('slidechange', { detail: { index: this._index } }));
106
+ this._post('miaoda:deck:slide-changed', { index: this._index });
107
+ const u = new URL(location.href);
108
+ u.searchParams.set('slide', String(this._index + 1));
109
+ history.replaceState(null, '', u);
110
+ }
111
+
112
+ get index() {
113
+ return this._index;
114
+ }
115
+ }
116
+
117
+ customElements.define('deck-stage', DeckStage);
118
+ })();