@21stware/rpui 0.1.1 → 0.3.1
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/README.md +47 -87
- package/dist/canvas/annotation.d.ts +6 -0
- package/dist/core/icons.d.ts +1 -1
- package/dist/core/style.d.ts +1 -1
- package/dist/gallery.d.ts +5 -0
- package/dist/gallery.js +2654 -0
- package/dist/gallery.js.map +1 -0
- package/dist/primitives/agent.d.ts +39 -0
- package/dist/primitives/controls.d.ts +21 -0
- package/dist/primitives/data-display.d.ts +75 -0
- package/dist/primitives/ios.d.ts +33 -0
- package/dist/primitives/layout.d.ts +9 -0
- package/dist/primitives/macos.d.ts +33 -0
- package/dist/primitives/navigation.d.ts +21 -0
- package/dist/rpml-loader.d.ts +2 -0
- package/dist/rpml-loader.js +27 -0
- package/dist/rpml-loader.js.map +1 -0
- package/dist/rpui.d.ts +2 -1
- package/dist/rpui.js +1769 -235
- package/dist/rpui.js.map +1 -1
- package/dist/serve/cli.d.ts +1 -0
- package/dist/serve.js +143 -0
- package/package.json +14 -22
- package/LICENSE +0 -20
- package/llms.txt +0 -195
- package/skill.txt +0 -143
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/serve.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { existsSync, statSync, readFileSync, readdirSync } from "node:fs";
|
|
4
|
+
import { dirname, join, resolve, sep, relative } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const GALLERY_JS = join(__dirname$1, "gallery.js");
|
|
8
|
+
function collectRpml(dir) {
|
|
9
|
+
const out = [];
|
|
10
|
+
const walk = (d) => {
|
|
11
|
+
for (const name of readdirSync(d)) {
|
|
12
|
+
if (name.startsWith(".") || name === "node_modules") continue;
|
|
13
|
+
const full = join(d, name);
|
|
14
|
+
const st = statSync(full);
|
|
15
|
+
if (st.isDirectory()) walk(full);
|
|
16
|
+
else if (/\.rpml$/i.test(name)) {
|
|
17
|
+
out.push({ path: relative(dir, full).split(sep).join("/"), source: readFileSync(full, "utf8") });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
walk(dir);
|
|
22
|
+
return out.sort((a, b) => a.path.localeCompare(b.path));
|
|
23
|
+
}
|
|
24
|
+
function escapeHtml(s) {
|
|
25
|
+
return s.replace(/[&<>]/g, (c) => ({ "&": "&", "<": "<", ">": ">" })[c]);
|
|
26
|
+
}
|
|
27
|
+
function buildHtml(dir, title, galleryJs) {
|
|
28
|
+
const docs = collectRpml(dir);
|
|
29
|
+
const data = JSON.stringify(docs).replace(/<\/script/gi, "<\\/script").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
30
|
+
return `<!doctype html>
|
|
31
|
+
<html lang="zh-CN">
|
|
32
|
+
<head>
|
|
33
|
+
<meta charset="UTF-8" />
|
|
34
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
35
|
+
<title>${escapeHtml(title)}</title>
|
|
36
|
+
<style>html,body{margin:0;height:100%}</style>
|
|
37
|
+
</head>
|
|
38
|
+
<body>
|
|
39
|
+
<script>globalThis.__RPML_DOCS__ = ${data};<\/script>
|
|
40
|
+
<script type="module">
|
|
41
|
+
${galleryJs}
|
|
42
|
+
<\/script>
|
|
43
|
+
</body>
|
|
44
|
+
</html>
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
function parseArgs(argv) {
|
|
48
|
+
let dir = ".";
|
|
49
|
+
let port = 3e3;
|
|
50
|
+
let host = "localhost";
|
|
51
|
+
let sawPositional = false;
|
|
52
|
+
for (let i = 0; i < argv.length; i++) {
|
|
53
|
+
const a = argv[i];
|
|
54
|
+
if (a === "-p" || a === "--port") port = Number(argv[++i]) || port;
|
|
55
|
+
else if (a === "--host") host = argv[++i] || host;
|
|
56
|
+
else if (a === "-h" || a === "--help") usage();
|
|
57
|
+
else if (!a.startsWith("-") && !sawPositional) {
|
|
58
|
+
dir = a;
|
|
59
|
+
sawPositional = true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { dir, port, host };
|
|
63
|
+
}
|
|
64
|
+
function usage() {
|
|
65
|
+
console.error(`Usage: rpui serve [dir] [--port 3000] [--host localhost]
|
|
66
|
+
|
|
67
|
+
Host a directory of .rpml files as one navigable gallery.
|
|
68
|
+
|
|
69
|
+
dir directory to serve (default: current directory)
|
|
70
|
+
-p, --port port (default 3000; auto-increments if busy)
|
|
71
|
+
--host host (default localhost)`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
function listen(server, port, host) {
|
|
75
|
+
return new Promise((res, rej) => {
|
|
76
|
+
const onError = (err) => {
|
|
77
|
+
if (err.code === "EADDRINUSE" && port < 65535) {
|
|
78
|
+
server.listen(++port, host);
|
|
79
|
+
} else {
|
|
80
|
+
rej(err);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
server.on("error", onError);
|
|
84
|
+
server.listen(port, host, () => {
|
|
85
|
+
server.off("error", onError);
|
|
86
|
+
res(port);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
async function serve(argv) {
|
|
91
|
+
const { dir, port, host } = parseArgs(argv);
|
|
92
|
+
const root = resolve(dir);
|
|
93
|
+
if (!existsSync(root) || !statSync(root).isDirectory()) {
|
|
94
|
+
console.error(`✗ Not a directory: ${dir}`);
|
|
95
|
+
process.exit(1);
|
|
96
|
+
}
|
|
97
|
+
if (!existsSync(GALLERY_JS)) {
|
|
98
|
+
console.error(`✗ Missing runtime bundle (gallery.js). Reinstall @21stware/rpui or run the build.`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
const galleryJs = readFileSync(GALLERY_JS, "utf8");
|
|
102
|
+
const title = root.split(sep).pop() || "RPML";
|
|
103
|
+
const server = createServer((req, res) => {
|
|
104
|
+
const url = (req.url || "/").split("?")[0];
|
|
105
|
+
try {
|
|
106
|
+
if (url === "/" || !url.endsWith(".rpml")) {
|
|
107
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
108
|
+
res.end(buildHtml(root, title, galleryJs));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const file = join(root, decodeURIComponent(url.replace(/^\/+/, "")));
|
|
112
|
+
if (file.startsWith(root) && existsSync(file)) {
|
|
113
|
+
res.writeHead(200, { "content-type": "text/plain; charset=utf-8" });
|
|
114
|
+
res.end(readFileSync(file));
|
|
115
|
+
} else {
|
|
116
|
+
res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
|
|
117
|
+
res.end("Not found");
|
|
118
|
+
}
|
|
119
|
+
} catch (e) {
|
|
120
|
+
res.writeHead(500, { "content-type": "text/plain; charset=utf-8" });
|
|
121
|
+
res.end("Error: " + e.message);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const actualPort = await listen(server, port, host);
|
|
125
|
+
const count = collectRpml(root).length;
|
|
126
|
+
const addr = `http://${host}:${actualPort}`;
|
|
127
|
+
console.log(``);
|
|
128
|
+
console.log(` RPUI serving ${count} .rpml file${count === 1 ? "" : "s"} from ${root}`);
|
|
129
|
+
console.log(``);
|
|
130
|
+
console.log(` Local: ${addr}`);
|
|
131
|
+
console.log(``);
|
|
132
|
+
console.log(` Press Ctrl+C to stop`);
|
|
133
|
+
}
|
|
134
|
+
const [sub, ...rest] = process.argv.slice(2);
|
|
135
|
+
if (sub === "serve") {
|
|
136
|
+
serve(rest);
|
|
137
|
+
} else if (sub === "-h" || sub === "--help" || sub === void 0) {
|
|
138
|
+
usage();
|
|
139
|
+
} else {
|
|
140
|
+
console.error(`Unknown command: ${sub}
|
|
141
|
+
`);
|
|
142
|
+
usage();
|
|
143
|
+
}
|
package/package.json
CHANGED
|
@@ -1,46 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@21stware/rpui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "RPUI: static UI prototype renderer (RPML Web Components runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/rpui.js",
|
|
7
7
|
"module": "dist/rpui.js",
|
|
8
8
|
"types": "dist/rpui.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"rpui": "dist/serve.js"
|
|
11
|
+
},
|
|
9
12
|
"exports": {
|
|
10
13
|
".": {
|
|
11
14
|
"types": "./dist/rpui.d.ts",
|
|
12
15
|
"default": "./dist/rpui.js"
|
|
13
16
|
},
|
|
14
17
|
"./dist/rpui.js": "./dist/rpui.js",
|
|
15
|
-
"./llms.txt": "
|
|
16
|
-
"./
|
|
18
|
+
"./llms.txt": "../../llms.txt",
|
|
19
|
+
"./SKILL.md": "../../SKILL.md"
|
|
17
20
|
},
|
|
18
21
|
"sideEffects": true,
|
|
19
22
|
"files": [
|
|
20
|
-
"dist"
|
|
21
|
-
"llms.txt",
|
|
22
|
-
"skill.txt",
|
|
23
|
-
"README.md",
|
|
24
|
-
"LICENSE"
|
|
23
|
+
"dist"
|
|
25
24
|
],
|
|
26
25
|
"scripts": {
|
|
27
|
-
"dev": "vite --open /preview/",
|
|
26
|
+
"dev": "vite --open /preview/ --config vite.config.ts",
|
|
28
27
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
29
|
-
"build:js": "vite build",
|
|
28
|
+
"build:js": "vite build --config vite.config.ts && vite build --config vite.gallery.config.ts && vite build --config vite.serve.config.ts",
|
|
30
29
|
"build:types": "tsc -p tsconfig.types.json",
|
|
31
|
-
"build": "
|
|
32
|
-
"
|
|
33
|
-
"
|
|
30
|
+
"build": "bun run clean && bun run typecheck && bun run build:js && bun run build:types",
|
|
31
|
+
"clean": "rm -rf dist && mkdir -p dist",
|
|
32
|
+
"release": "bun run build"
|
|
34
33
|
},
|
|
35
|
-
"keywords": [
|
|
36
|
-
"web-components",
|
|
37
|
-
"prototype",
|
|
38
|
-
"ui",
|
|
39
|
-
"snapshot",
|
|
40
|
-
"llm"
|
|
41
|
-
],
|
|
42
|
-
"license": "UNLICENSED",
|
|
43
34
|
"devDependencies": {
|
|
35
|
+
"rpml-parser": "workspace:*",
|
|
44
36
|
"typescript": "^5.8.3",
|
|
45
37
|
"vite": "^5.4.11"
|
|
46
38
|
}
|
package/LICENSE
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
Copyright (c) 2026 21st Ware. All Rights Reserved.
|
|
2
|
-
|
|
3
|
-
PROPRIETARY AND CONFIDENTIAL
|
|
4
|
-
|
|
5
|
-
This software and its source code are the proprietary and confidential
|
|
6
|
-
property of the copyright holder. No part of this software, in source or
|
|
7
|
-
compiled form, may be copied, reproduced, modified, published, uploaded,
|
|
8
|
-
posted, transmitted, distributed, sublicensed, or otherwise exploited in
|
|
9
|
-
any way, in whole or in part, without the prior express written permission
|
|
10
|
-
of the copyright holder.
|
|
11
|
-
|
|
12
|
-
Unauthorized copying, distribution, or modification of this software, via
|
|
13
|
-
any medium, is strictly prohibited.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
19
|
-
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
|
20
|
-
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/llms.txt
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
# RPUI Web Components Reference for LLMs
|
|
2
|
-
|
|
3
|
-
RPUI means Readable Prototype UI. It is a static prototype specification and rendering runtime implemented with native Web Components.
|
|
4
|
-
|
|
5
|
-
A generated prototype imports one file only:
|
|
6
|
-
|
|
7
|
-
```html
|
|
8
|
-
<script type="module" src="./dist/rpui.js"></script>
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
`dist/rpui.js` registers all custom elements and injects runtime CSS plus Lucide-style inline SVG icons. Do not import external CSS, image CDNs, icon CDNs, or UI frameworks.
|
|
12
|
-
|
|
13
|
-
## Core model
|
|
14
|
-
|
|
15
|
-
RPUI has two layers:
|
|
16
|
-
|
|
17
|
-
1. Canvas layer: page shell, main snapshot view, numbered pins, annotations, nested annotations, and state enums.
|
|
18
|
-
2. Snapshot Primitive layer: static UI building blocks for product UI snapshots and annotation slices.
|
|
19
|
-
|
|
20
|
-
Use `rp-*` tags for new work. Compatibility aliases are available:
|
|
21
|
-
|
|
22
|
-
- `proto-*` aliases exist for canvas tags.
|
|
23
|
-
- `snap-*` aliases exist for snapshot primitive tags.
|
|
24
|
-
|
|
25
|
-
## Canvas tags
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<rp-page title="页面标题" route="/route" description="页面说明">
|
|
29
|
-
<rp-main-view device="web" scale="0.65">
|
|
30
|
-
<rp-viewport device="web">
|
|
31
|
-
<!-- fixed-width, auto-height main snapshot built with rp-* primitives -->
|
|
32
|
-
</rp-viewport>
|
|
33
|
-
</rp-main-view>
|
|
34
|
-
|
|
35
|
-
<rp-annotation id="1" label="区域说明">...</rp-annotation>
|
|
36
|
-
</rp-page>
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Tags:
|
|
40
|
-
|
|
41
|
-
- `<rp-page title="..." route="..." description="...">` — root document canvas. It keeps the title/main snapshot on the left and moves top-level annotations to the right-side scroll pane.
|
|
42
|
-
- `<rp-main-view device="web|ipad|mobile" width="..." height="auto|900" scale="0.65">` — scaled main snapshot frame. Device presets are fixed width with auto height unless a numeric `height` is provided.
|
|
43
|
-
- `<rp-viewport device="web|ipad|mobile" width="..." height="auto|900">` — snapshot viewport. Use the same `device` as the main view for clarity.
|
|
44
|
-
- `<rp-annotation id="1" label="...">` — top-level annotation linked to `data-pin="1"`; rendered in the right annotation pane.
|
|
45
|
-
- `<rp-annotation label="...">` — nested annotation; no `id` required.
|
|
46
|
-
- `<rp-enum>` — horizontal state/variant container.
|
|
47
|
-
- `<rp-enum-item label="..." description="...">` — one explicit state/variant card with optional short description.
|
|
48
|
-
|
|
49
|
-
## Pin rule
|
|
50
|
-
|
|
51
|
-
Inside `<rp-main-view>`, add `data-pin="N"` to meaningful regions. Number pins from 1 without gaps.
|
|
52
|
-
|
|
53
|
-
Every `data-pin="N"` must have a matching top-level annotation:
|
|
54
|
-
|
|
55
|
-
```html
|
|
56
|
-
<rp-navbar data-pin="1">...</rp-navbar>
|
|
57
|
-
<rp-annotation id="1" label="顶部导航">...</rp-annotation>
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
RPUI renders water-drop pins automatically. Never write pin DOM manually.
|
|
61
|
-
|
|
62
|
-
## Layout and state rules
|
|
63
|
-
|
|
64
|
-
- RPUI is static. Do not create interactions.
|
|
65
|
-
- Do not use `onclick`, hover behavior, runtime focus, timers, API calls, or framework state.
|
|
66
|
-
- Do not use external images; use `<rp-image-placeholder>`.
|
|
67
|
-
- Do not use `position:absolute` or `position:fixed` in snapshot content. RPUI owns pin positioning.
|
|
68
|
-
- Do not use raw `div`, `button`, `input`, or `table` to represent product UI. Use `rp-*` primitives.
|
|
69
|
-
- Basic text and simple inline HTML are allowed inside annotations.
|
|
70
|
-
- Top-level annotations render automatically in the right-side annotation pane. Do not manually create annotation pane wrappers.
|
|
71
|
-
- The title/route/description and main snapshot stay visible on the left while the annotation pane scrolls independently on both axes.
|
|
72
|
-
- Keep annotations compact and document-flow oriented. Do not stretch annotation content to full width.
|
|
73
|
-
- Choose a device preset for new prototypes: `web` (1440px), `ipad` (834px), or `mobile` (390px). Presets use fixed width and auto height unless a numeric height is provided.
|
|
74
|
-
- In the main snapshot, keep selects/dropdowns/popovers collapsed unless the page's primary representative state truly requires the overlay to be visible. Prefer showing expanded select/dropdown contents in annotation enums so they do not obscure the main layout.
|
|
75
|
-
- Use `<rp-enum>` for state families, permission variants, hidden interaction results, and validation branches. Use `rp-enum-item description="..."` for a short clarification of a state.
|
|
76
|
-
|
|
77
|
-
## Snapshot primitives
|
|
78
|
-
|
|
79
|
-
### Containers
|
|
80
|
-
|
|
81
|
-
- `<rp-viewport device="web|ipad|mobile" width="1440" height="auto|900">` — fixed-width snapshot viewport; presets default to auto height.
|
|
82
|
-
- `<rp-layout columns="260px 1fr" rows="auto" gap="16">` — CSS grid container.
|
|
83
|
-
- `<rp-panel padding="24" elevation="1|2">` — white panel/card shell.
|
|
84
|
-
- `<rp-card title="..." subtitle="..." has-image has-footer>` — content card.
|
|
85
|
-
- `<rp-modal width="480" title="..." has-footer>` — static opened modal.
|
|
86
|
-
- `<rp-drawer side="left|right" width="360" title="...">` — static opened drawer.
|
|
87
|
-
- `<rp-dropdown width="300" title="...">` — static opened dropdown.
|
|
88
|
-
- `<rp-popover width="300" title="...">` — static opened popover.
|
|
89
|
-
- `<rp-tooltip text="..." position="top|bottom|left|right">` — visible tooltip bubble.
|
|
90
|
-
|
|
91
|
-
### Navigation
|
|
92
|
-
|
|
93
|
-
- `<rp-navbar height="64">` — top navigation container.
|
|
94
|
-
- `<rp-sidebar width="260" collapsed>` — side navigation container.
|
|
95
|
-
- `<rp-logo size="82" label="LOGO">` — logo placeholder.
|
|
96
|
-
- `<rp-list items="4" state="first-selected">` — generated list when no children are provided.
|
|
97
|
-
- `<rp-list-item label="..." icon="inbox" badge="12" state="default|selected|disabled">`.
|
|
98
|
-
- `<rp-tabs active="0">` with `<rp-tab label="全部" badge="12">`; `active` can be index or label.
|
|
99
|
-
- `<rp-breadcrumb items="首页,设置,用户管理">`.
|
|
100
|
-
- `<rp-pagination total="128" current="2" page-size="20">`.
|
|
101
|
-
- `<rp-steps steps="填写信息,确认,完成" active="1">`.
|
|
102
|
-
|
|
103
|
-
### Data and content display
|
|
104
|
-
|
|
105
|
-
- `<rp-table rows="6" columns="发件人,消息预览,时间,状态" has-checkbox has-action>` — generated static table.
|
|
106
|
-
- `<rp-table-row state="default|selected|unread|highlighted|disabled">` — standalone row slice.
|
|
107
|
-
- `<rp-bulk-action-bar count="3" actions="标为已读,归档,删除">`.
|
|
108
|
-
- `<rp-empty label="暂无数据" description="..." has-action>`.
|
|
109
|
-
- `<rp-loading rows="4" kind="skeleton|spinner">` (`style="spinner"` also works for compatibility).
|
|
110
|
-
- `<rp-image-placeholder width="160" height="100" label="Image">`.
|
|
111
|
-
- `<rp-avatar size="32" initials="OC">`.
|
|
112
|
-
- `<rp-badge count="120" max="99">`.
|
|
113
|
-
- `<rp-tag label="已启用" color="green|orange|red" closable>`.
|
|
114
|
-
- `<rp-stat-card label="活跃用户" value="12,480" trend="up|down|flat" change="+12%">`.
|
|
115
|
-
|
|
116
|
-
### Forms and controls
|
|
117
|
-
|
|
118
|
-
All form states are explicit through attributes; there is no runtime focus or input behavior.
|
|
119
|
-
|
|
120
|
-
- `<rp-search state="default|focus|filled|error|disabled" placeholder="..." value="..." has-clear-button>`.
|
|
121
|
-
- `<rp-input state="default|focus|filled|error|disabled" label="..." placeholder="..." value="..." has-clear-button error-message="...">`.
|
|
122
|
-
- `<rp-textarea state="default|focus|filled|error|disabled" rows="3" placeholder="..." value="...">`.
|
|
123
|
-
- `<rp-select state="collapsed|expanded|disabled" label="..." value="..." options="A,B,C">`.
|
|
124
|
-
- `<rp-date-picker state="default|focus|filled|error|disabled" value="2026-06-07">`.
|
|
125
|
-
- `<rp-checkbox state="unchecked|checked|indeterminate|disabled" label="...">`.
|
|
126
|
-
- `<rp-radio state="unchecked|checked|disabled" label="...">`.
|
|
127
|
-
- `<rp-toggle state="on|off|disabled" label="...">`.
|
|
128
|
-
- `<rp-button label="..." variant="primary|secondary|ghost|danger|link" state="default|disabled|loading" icon="plus" size="sm|md|lg">`.
|
|
129
|
-
- `<rp-button-group>...</rp-button-group>`.
|
|
130
|
-
- `<rp-form layout="vertical|horizontal">`.
|
|
131
|
-
- `<rp-form-item label="..." required error="...">...</rp-form-item>`.
|
|
132
|
-
- `<rp-upload state="empty|has-file|uploading" file="document.pdf" progress="60">`.
|
|
133
|
-
|
|
134
|
-
### Feedback
|
|
135
|
-
|
|
136
|
-
- `<rp-alert type="info|success|warning|error" title="..." message="..." closable>`.
|
|
137
|
-
- `<rp-toast type="info|success|warning|error" title="..." message="..." closable>`.
|
|
138
|
-
- `<rp-progress value="40" kind="bar|circle" status="success|error">`.
|
|
139
|
-
|
|
140
|
-
## Icon rule
|
|
141
|
-
|
|
142
|
-
Use Lucide icon names through the `icon` attribute when available:
|
|
143
|
-
|
|
144
|
-
```html
|
|
145
|
-
<rp-button label="新建" icon="plus" variant="primary"></rp-button>
|
|
146
|
-
<rp-list-item label="已归档" icon="archive"></rp-list-item>
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
The runtime renders inline SVG. Do not import lucide or any icon CDN.
|
|
150
|
-
|
|
151
|
-
## State coverage checklist
|
|
152
|
-
|
|
153
|
-
For each page, consider whether these states apply:
|
|
154
|
-
|
|
155
|
-
- loaded with normal data
|
|
156
|
-
- empty data
|
|
157
|
-
- loading/skeleton/spinner
|
|
158
|
-
- error/retry
|
|
159
|
-
- search default/focus/filled/no-result
|
|
160
|
-
- filter collapsed/expanded
|
|
161
|
-
- row default/selected/unread/highlighted/disabled
|
|
162
|
-
- bulk selection off/on
|
|
163
|
-
- pagination first/middle/last/no more pages
|
|
164
|
-
- permission variants: readonly/admin/owner/external collaborator
|
|
165
|
-
- destructive confirmation
|
|
166
|
-
- validation default/filled/error/disabled
|
|
167
|
-
|
|
168
|
-
## Recommended complete HTML shape
|
|
169
|
-
|
|
170
|
-
```html
|
|
171
|
-
<!doctype html>
|
|
172
|
-
<html lang="zh-CN">
|
|
173
|
-
<head>
|
|
174
|
-
<meta charset="UTF-8" />
|
|
175
|
-
<script type="module" src="./dist/rpui.js"></script>
|
|
176
|
-
</head>
|
|
177
|
-
<body>
|
|
178
|
-
<rp-page title="页面标题" route="/route" description="页面说明">
|
|
179
|
-
<rp-main-view device="web" scale="0.65">
|
|
180
|
-
<rp-viewport device="web">
|
|
181
|
-
<!-- main snapshot built only with rp-* primitives -->
|
|
182
|
-
</rp-viewport>
|
|
183
|
-
</rp-main-view>
|
|
184
|
-
|
|
185
|
-
<rp-annotation id="1" label="区域说明">
|
|
186
|
-
简短说明此区域的职责。
|
|
187
|
-
<rp-enum>
|
|
188
|
-
<rp-enum-item label="默认" description="正常可用的数据态。"><rp-empty label="示例"></rp-empty></rp-enum-item>
|
|
189
|
-
<rp-enum-item label="加载" description="首次进入或刷新时展示。"><rp-loading rows="3"></rp-loading></rp-enum-item>
|
|
190
|
-
</rp-enum>
|
|
191
|
-
</rp-annotation>
|
|
192
|
-
</rp-page>
|
|
193
|
-
</body>
|
|
194
|
-
</html>
|
|
195
|
-
```
|
package/skill.txt
DELETED
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# RPUI Prototype Implementation Skill
|
|
2
|
-
|
|
3
|
-
Use this skill when converting product requirements, screenshots, existing UI code, or design notes into a static RPUI prototype.
|
|
4
|
-
|
|
5
|
-
## Goal
|
|
6
|
-
|
|
7
|
-
Create one readable, static, self-contained HTML prototype that fully exposes a product page's UI structure, interaction states, permissions, loading states, empty states, error states, validation states, and edge cases.
|
|
8
|
-
|
|
9
|
-
RPUI does not simulate interaction. It lays out interaction results spatially so reviewers can understand the complete state space without clicking anything. Treat it like baking time-based UI behavior into a document-flow canvas.
|
|
10
|
-
|
|
11
|
-
## Required inputs
|
|
12
|
-
|
|
13
|
-
Prefer these inputs, in priority order:
|
|
14
|
-
|
|
15
|
-
1. Product requirement or user story.
|
|
16
|
-
2. Screenshot or design draft.
|
|
17
|
-
3. Existing code with conditional rendering.
|
|
18
|
-
4. Permission matrix or role notes.
|
|
19
|
-
5. Known loading, empty, error, validation, and edge cases.
|
|
20
|
-
|
|
21
|
-
If some inputs are missing, infer common SaaS/product UI states and make assumptions explicit in annotations.
|
|
22
|
-
|
|
23
|
-
## Output contract
|
|
24
|
-
|
|
25
|
-
Output a complete HTML file that imports exactly one RPUI runtime file:
|
|
26
|
-
|
|
27
|
-
```html
|
|
28
|
-
<script type="module" src="./dist/rpui.js"></script>
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
The document must contain:
|
|
32
|
-
|
|
33
|
-
1. one `<rp-page>` root with `title`, `route`, and `description`,
|
|
34
|
-
2. exactly one `<rp-main-view>` containing the main page snapshot,
|
|
35
|
-
3. snapshot content built with `rp-*` primitives,
|
|
36
|
-
4. numbered `data-pin="N"` anchors on meaningful main-view regions,
|
|
37
|
-
5. matching top-level `<rp-annotation id="N" label="...">` blocks,
|
|
38
|
-
6. `<rp-enum>` and `<rp-enum-item>` blocks for conditional states and variants.
|
|
39
|
-
|
|
40
|
-
## Implementation steps
|
|
41
|
-
|
|
42
|
-
1. Identify the page route, page title, and one-sentence description.
|
|
43
|
-
2. Choose a device preset: `web` for desktop/admin pages, `ipad` for tablet layouts, or `mobile` for phone layouts. Prefer fixed-width, auto-height prototypes.
|
|
44
|
-
3. Choose the most complex representative main snapshot: loaded data, selected rows, expanded drawers/modals when they are central to the page, active validation, and role-specific controls when relevant.
|
|
45
|
-
4. Build the main snapshot inside `<rp-main-view device="web|ipad|mobile">` using only `rp-*` snapshot primitives, usually inside an `<rp-viewport device="web|ipad|mobile">`.
|
|
46
|
-
5. Add `data-pin="N"` to every meaningful UI region. Number pins from 1 without gaps.
|
|
47
|
-
6. For every `data-pin="N"`, create one top-level `<rp-annotation id="N" label="...">`. The runtime places top-level annotations in the right-side annotation pane.
|
|
48
|
-
7. Keep annotation text concise and specific. Avoid large prose blocks and card-like padding wrappers.
|
|
49
|
-
8. Use nested `<rp-annotation>` only when a rule belongs to a smaller sub-region.
|
|
50
|
-
9. Put repeated/conditional state families in `<rp-enum>`.
|
|
51
|
-
10. Use `<rp-enum-item label="..." description="...">` for every state: default, focus, filled, selected, disabled, empty, loading, error, permission-specific, and data-size variants. `description` is optional and should be short.
|
|
52
|
-
11. Validate that no interactive JavaScript, event attributes, external images, external CSS, or CDN icons are used.
|
|
53
|
-
|
|
54
|
-
## Authoring rules
|
|
55
|
-
|
|
56
|
-
- Use `rp-*` tags for new work. `proto-*` and `snap-*` are compatibility aliases only.
|
|
57
|
-
- Use `<rp-page>`, not arbitrary root containers.
|
|
58
|
-
- Use `<rp-main-view>` once per prototype page.
|
|
59
|
-
- Use `rp-*` tags for both the main snapshot and UI slices inside annotations.
|
|
60
|
-
- Do not use direct `div`, `button`, `input`, `table`, or similar product UI HTML. Use RPUI primitives instead. Basic text and simple inline annotation markup are allowed.
|
|
61
|
-
- Do not write CSS or JavaScript in the prototype unless implementing or extending RPUI itself.
|
|
62
|
-
- Do not use `position:absolute` or `position:fixed` in snapshot content. RPUI owns pin positioning.
|
|
63
|
-
- Do not hide important content behind interactions. Expand it into the annotation area with `<rp-enum>`.
|
|
64
|
-
- Do not stretch annotation blocks to full width. The runtime provides a right-side annotation pane; keep annotation content compact inside it.
|
|
65
|
-
- Keep select/dropdown/popover overlays collapsed in the main snapshot unless visibility is essential to the representative state. Put expanded overlay contents in annotation enums or local slices so the main layout remains readable.
|
|
66
|
-
- Use `rp-enum-item description="..."` for short state notes, not long prose.
|
|
67
|
-
- Prefer `device="web"`, `device="ipad"`, or `device="mobile"` over hand-tuned width/height values. Use explicit numeric `height` only when a fixed-height clipped viewport is intentional.
|
|
68
|
-
|
|
69
|
-
## State coverage checklist
|
|
70
|
-
|
|
71
|
-
For every page, check whether these states apply:
|
|
72
|
-
|
|
73
|
-
- Loaded with normal data.
|
|
74
|
-
- Empty data.
|
|
75
|
-
- Loading or skeleton/spinner.
|
|
76
|
-
- Error or retry.
|
|
77
|
-
- Search default, focus, filled, no result.
|
|
78
|
-
- Filter collapsed and expanded.
|
|
79
|
-
- Row default, selected, unread, highlighted, disabled.
|
|
80
|
-
- Bulk selection off and on.
|
|
81
|
-
- Pagination first, middle, last, no more pages.
|
|
82
|
-
- Permission variants such as readonly, admin, owner, external collaborator.
|
|
83
|
-
- Destructive action confirmation.
|
|
84
|
-
- Validation default, filled, error, disabled.
|
|
85
|
-
- Overlay states such as dropdown, popover, modal, drawer, tooltip.
|
|
86
|
-
- Upload empty, has-file, uploading.
|
|
87
|
-
|
|
88
|
-
## Primitive selection guide
|
|
89
|
-
|
|
90
|
-
Use the smallest primitive that communicates the requirement:
|
|
91
|
-
|
|
92
|
-
- page shell: `rp-page`, `rp-main-view`, `rp-viewport`
|
|
93
|
-
- layout: `rp-layout`, `rp-panel`, `rp-card`
|
|
94
|
-
- navigation: `rp-navbar`, `rp-sidebar`, `rp-tabs`, `rp-breadcrumb`, `rp-pagination`, `rp-steps`
|
|
95
|
-
- data: `rp-table`, `rp-table-row`, `rp-list`, `rp-list-item`, `rp-stat-card`, `rp-tag`, `rp-badge`, `rp-avatar`
|
|
96
|
-
- forms: `rp-input`, `rp-search`, `rp-textarea`, `rp-select`, `rp-date-picker`, `rp-checkbox`, `rp-radio`, `rp-toggle`, `rp-form`, `rp-form-item`, `rp-upload`, `rp-button`
|
|
97
|
-
- states: `rp-empty`, `rp-loading`, `rp-alert`, `rp-toast`, `rp-progress`
|
|
98
|
-
- overlays: `rp-dropdown`, `rp-popover`, `rp-tooltip`, `rp-modal`, `rp-drawer`
|
|
99
|
-
|
|
100
|
-
Refer to `llms.txt` for the complete component attributes.
|
|
101
|
-
|
|
102
|
-
## Minimal template
|
|
103
|
-
|
|
104
|
-
```html
|
|
105
|
-
<!doctype html>
|
|
106
|
-
<html lang="zh-CN">
|
|
107
|
-
<head>
|
|
108
|
-
<meta charset="UTF-8" />
|
|
109
|
-
<script type="module" src="./dist/rpui.js"></script>
|
|
110
|
-
</head>
|
|
111
|
-
<body>
|
|
112
|
-
<rp-page title="页面标题" route="/route" description="页面说明">
|
|
113
|
-
<rp-main-view device="web" scale="0.65">
|
|
114
|
-
<rp-viewport device="web">
|
|
115
|
-
<!-- main snapshot -->
|
|
116
|
-
</rp-viewport>
|
|
117
|
-
</rp-main-view>
|
|
118
|
-
|
|
119
|
-
<rp-annotation id="1" label="区域说明">
|
|
120
|
-
简短说明此区域的职责。
|
|
121
|
-
<rp-enum>
|
|
122
|
-
<rp-enum-item label="默认" description="正常可用的数据态。"><rp-empty label="示例"></rp-empty></rp-enum-item>
|
|
123
|
-
<rp-enum-item label="加载中" description="首次进入或刷新时展示。"><rp-loading rows="3"></rp-loading></rp-enum-item>
|
|
124
|
-
<rp-enum-item label="错误" description="服务端或网络异常时展示。"><rp-alert type="error" title="加载失败" message="请重试"></rp-alert></rp-enum-item>
|
|
125
|
-
</rp-enum>
|
|
126
|
-
</rp-annotation>
|
|
127
|
-
</rp-page>
|
|
128
|
-
</body>
|
|
129
|
-
</html>
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
## Quality bar
|
|
133
|
-
|
|
134
|
-
A good RPUI prototype can be reviewed by engineering, product, design, and QA without running the real application. QA should be able to derive test cases from annotations. Engineering should be able to derive conditional rendering requirements from enum items. Design should be able to see whether hidden states were missed.
|
|
135
|
-
|
|
136
|
-
Before finishing, check:
|
|
137
|
-
|
|
138
|
-
- pin numbers are continuous and all have matching annotations,
|
|
139
|
-
- the main snapshot shows the most complex useful state,
|
|
140
|
-
- hidden interaction results are expanded into enums,
|
|
141
|
-
- role/permission differences are visible,
|
|
142
|
-
- annotations are compact and document-flow oriented,
|
|
143
|
-
- no forbidden direct product UI HTML, scripts, event handlers, or external resources are present.
|