@21stware/rpui 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/README.md +113 -0
- package/dist/canvas/annotation.d.ts +10 -0
- package/dist/canvas/main-view.d.ts +9 -0
- package/dist/canvas/page.d.ts +3 -0
- package/dist/core/dom.d.ts +12 -0
- package/dist/core/icons.d.ts +2 -0
- package/dist/core/style.d.ts +3 -0
- package/dist/primitives/controls.d.ts +40 -0
- package/dist/primitives/data-display.d.ts +40 -0
- package/dist/primitives/layout.d.ts +21 -0
- package/dist/primitives/navigation.d.ts +27 -0
- package/dist/registry.d.ts +1 -0
- package/dist/rpui.d.ts +2 -0
- package/dist/rpui.js +982 -0
- package/dist/rpui.js.map +1 -0
- package/llms.txt +195 -0
- package/package.json +46 -0
- package/skill.txt +143 -0
package/dist/rpui.js
ADDED
|
@@ -0,0 +1,982 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
function attr(el, name, fallback = "") {
|
|
5
|
+
return el.getAttribute(name) ?? fallback;
|
|
6
|
+
}
|
|
7
|
+
function intAttr(el, name, fallback) {
|
|
8
|
+
const raw = el.getAttribute(name);
|
|
9
|
+
const value = raw === null || raw === "" ? NaN : Number(raw);
|
|
10
|
+
return Number.isFinite(value) ? value : fallback;
|
|
11
|
+
}
|
|
12
|
+
function escapeHtml(value) {
|
|
13
|
+
return value.replace(/[&<>'"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", "'": "'", '"': """ })[c] || c);
|
|
14
|
+
}
|
|
15
|
+
function csv(el, name, fallback) {
|
|
16
|
+
return attr(el, name, fallback).split(",").map((s) => s.trim()).filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
const deviceWidths = { web: 1440, ipad: 834, mobile: 390 };
|
|
19
|
+
function resolveWidth(el, fallback) {
|
|
20
|
+
const raw = el.getAttribute("width");
|
|
21
|
+
const width = raw === null || raw === "" ? NaN : Number(raw);
|
|
22
|
+
if (Number.isFinite(width)) return width;
|
|
23
|
+
return deviceWidths[attr(el, "device")] ?? fallback;
|
|
24
|
+
}
|
|
25
|
+
function hasExplicitNumericHeight(el) {
|
|
26
|
+
const raw = el.getAttribute("height");
|
|
27
|
+
return raw !== null && raw !== "" && Number.isFinite(Number(raw));
|
|
28
|
+
}
|
|
29
|
+
function usesAutoHeight(el) {
|
|
30
|
+
const raw = el.getAttribute("height");
|
|
31
|
+
return raw === "auto" || el.hasAttribute("auto-height") || !!el.getAttribute("device") && !hasExplicitNumericHeight(el);
|
|
32
|
+
}
|
|
33
|
+
function resolveHeight(el, fallback) {
|
|
34
|
+
const raw = el.getAttribute("height");
|
|
35
|
+
const height = raw === null || raw === "" ? NaN : Number(raw);
|
|
36
|
+
return Number.isFinite(height) ? height : fallback;
|
|
37
|
+
}
|
|
38
|
+
function isTopAnnotation(node) {
|
|
39
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
40
|
+
const tag = node.tagName.toLowerCase();
|
|
41
|
+
return tag === "rp-annotation" || tag === "proto-annotation";
|
|
42
|
+
}
|
|
43
|
+
function isViewportNode(node) {
|
|
44
|
+
if (!(node instanceof HTMLElement)) return false;
|
|
45
|
+
const tag = node.tagName.toLowerCase();
|
|
46
|
+
return tag === "rp-viewport" || tag === "snap-viewport";
|
|
47
|
+
}
|
|
48
|
+
function define(name, ctor) {
|
|
49
|
+
if (customElements.get(name)) return;
|
|
50
|
+
const Alias = class extends ctor {
|
|
51
|
+
};
|
|
52
|
+
customElements.define(name, Alias);
|
|
53
|
+
}
|
|
54
|
+
const RPUI_STYLE_ID = "rpui-runtime-style";
|
|
55
|
+
const style = `
|
|
56
|
+
:root { --rp-bg:#f0f2f5; --rp-surface:#fff; --rp-surface-soft:#f9fafb; --rp-text:#111827; --rp-muted:#6b7280; --rp-border:#e5e7eb; --rp-border-strong:#d1d5db; --rp-primary:#2563eb; --rp-success:#059669; --rp-warning:#d97706; --rp-danger:#dc2626; --rp-purple:#7c3aed; --rp-radius-sm:4px; --rp-radius-md:8px; --rp-radius-lg:12px; --rp-shadow:0 8px 28px rgba(15,23,42,.08); --rp-font:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; }
|
|
57
|
+
* { box-sizing:border-box; }
|
|
58
|
+
body { margin:0; font-family:var(--rp-font); color:var(--rp-text); background:var(--rp-bg); }
|
|
59
|
+
.rp-icon { display:inline-block; flex:0 0 auto; vertical-align:-0.16em; }
|
|
60
|
+
rp-page, proto-page { display:block; min-height:100vh; padding:32px 40px; overflow:auto; }
|
|
61
|
+
.rp-page-shell { display:grid; grid-template-columns:max-content max-content; gap:24px; min-height:100vh; align-items:start; }
|
|
62
|
+
.rp-page-main { display:flex; flex-direction:column; min-width:0; overflow:visible; }
|
|
63
|
+
.rp-page-header { flex:0 0 auto; width:fit-content; max-width:none; margin:0 0 22px; }
|
|
64
|
+
.rp-page-title-row { display:flex; align-items:baseline; gap:12px; flex-wrap:wrap; }
|
|
65
|
+
.rp-page-title { margin:0; font-size:28px; line-height:1.2; letter-spacing:-.02em; }
|
|
66
|
+
.rp-page-route { font-size:13px; color:var(--rp-muted); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; background:rgba(255,255,255,.7); border:1px solid var(--rp-border); border-radius:999px; padding:3px 9px; }
|
|
67
|
+
.rp-page-description { margin:10px 0 0; color:#374151; line-height:1.6; font-size:14px; }
|
|
68
|
+
.rp-page-body { flex:0 1 auto; display:block; width:fit-content; max-width:100%; min-height:0; overflow:visible; }
|
|
69
|
+
.rp-annotation-pane { min-width:380px; max-width:680px; position:sticky; top:0; height:100vh; overflow-y:auto; overflow-x:auto; padding:0 0 48px 0; align-self:start; }
|
|
70
|
+
.rp-annotation-pane-inner { padding:4px 12px 24px 6px; }
|
|
71
|
+
rp-main-view, proto-main-view { display:block; width:fit-content; margin:0 0 28px; position:relative; }
|
|
72
|
+
.rp-main-shell { position:relative; overflow:visible; border:1px solid var(--rp-border-strong); border-radius:var(--rp-radius-md); background:var(--rp-surface); box-shadow:var(--rp-shadow); }
|
|
73
|
+
.rp-main-stage-clip { overflow:hidden; border-radius:var(--rp-radius-md); }
|
|
74
|
+
.rp-main-stage { position:relative; transform-origin:top left; background:var(--rp-surface); }
|
|
75
|
+
.rp-pin { position:absolute; z-index:20; display:grid; place-items:center; width:24px; height:24px; color:#fff; font-size:11px; font-weight:700; background:var(--rp-primary); border-radius:50% 50% 50% 0; transform:translate(-6px,-6px) rotate(-45deg); box-shadow:0 2px 8px rgba(37,99,235,.25); cursor:pointer; }
|
|
76
|
+
.rp-pin > span { transform:rotate(45deg); }
|
|
77
|
+
.rp-pin:hover { opacity:0.85; }
|
|
78
|
+
rp-annotation, proto-annotation { display:block; width:fit-content; max-width:980px; margin:14px 0; line-height:1.65; color:#1f2937; font-size:14px; }
|
|
79
|
+
rp-annotation rp-annotation, proto-annotation proto-annotation, rp-annotation proto-annotation, proto-annotation rp-annotation { margin:10px 0 8px 22px; }
|
|
80
|
+
.rp-annotation-head { display:flex; align-items:center; gap:8px; margin:0 0 4px; width:fit-content; }
|
|
81
|
+
.rp-annotation-title { font-weight:700; color:#111827; }
|
|
82
|
+
.rp-annotation-marker { display:inline-grid; place-items:center; flex:0 0 auto; color:#fff; font-size:10px; font-weight:700; line-height:1; }
|
|
83
|
+
.rp-annotation-marker.drop { width:22px; height:22px; background:var(--rp-primary); border-radius:50% 50% 50% 0; transform:rotate(-45deg); }
|
|
84
|
+
.rp-annotation-marker.drop > span { transform:rotate(45deg); }
|
|
85
|
+
.rp-annotation-marker.circle { width:13px; height:13px; background:var(--rp-purple); border-radius:50%; }
|
|
86
|
+
.rp-annotation-marker.triangle { width:0; height:0; border-left:7px solid transparent; border-right:7px solid transparent; border-bottom:13px solid var(--rp-success); }
|
|
87
|
+
.rp-annotation-body { display:block; width:fit-content; max-width:920px; }
|
|
88
|
+
.rp-annotation-body > :not(rp-annotation):not(proto-annotation):not(rp-enum):not(proto-enum) { max-width:820px; }
|
|
89
|
+
.rp-annotation-pane rp-annotation, .rp-annotation-pane proto-annotation { max-width:none; }
|
|
90
|
+
.rp-annotation-pane .rp-annotation-body { max-width:none; }
|
|
91
|
+
.rp-annotation-pane .rp-annotation-body > :not(rp-annotation):not(proto-annotation):not(rp-enum):not(proto-enum) { max-width:420px; }
|
|
92
|
+
.rp-annotation-body p { margin:0 0 8px; }
|
|
93
|
+
rp-enum, proto-enum { display:flex; align-items:flex-start; flex-wrap:wrap; gap:10px; width:fit-content; margin:8px 0 12px; }
|
|
94
|
+
.rp-annotation-pane rp-enum, .rp-annotation-pane proto-enum { flex-wrap:wrap; }
|
|
95
|
+
rp-enum-item, proto-enum-item { display:block; flex:0 0 auto; width:fit-content; min-width:180px; max-width:600px; border:1px solid #f0f0f0; border-radius:var(--rp-radius-md); background:#fff; overflow:hidden; }
|
|
96
|
+
.rp-enum-label { display:flex; align-items:flex-start; gap:6px; padding:5px 9px 4px; font-size:12px; font-weight:650; color:#374151; }
|
|
97
|
+
.rp-enum-index { display:inline-grid; place-items:center; min-width:16px; height:16px; padding:0 4px; background:#111827; color:#fff; font-size:10px; font-weight:750; border-radius:3px; flex:0 0 auto; margin-top:1px; }
|
|
98
|
+
.rp-enum-label-text { display:block; }
|
|
99
|
+
.rp-enum-description { display:block; margin-top:2px; font-size:11px; line-height:1.35; font-weight:400; color:var(--rp-muted); }
|
|
100
|
+
.rp-enum-content { display:block; width:fit-content; padding:8px; }
|
|
101
|
+
.rp-annotation-title { font-weight:700; color:#111827; cursor:pointer; }
|
|
102
|
+
.rp-annotation-title:hover { color:var(--rp-primary); }
|
|
103
|
+
.rp-section-focus { outline:2px dashed var(--rp-primary); outline-offset:4px; border-radius:4px; }
|
|
104
|
+
snap-viewport, rp-viewport { display:flex; flex-direction:column; width:var(--snap-width,1440px); height:var(--snap-height,900px); background:#f8fafc; overflow:hidden; color:#111827; }
|
|
105
|
+
snap-layout, rp-layout { display:grid; grid-template-columns:var(--snap-columns,1fr); grid-template-rows:var(--snap-rows,auto); gap:var(--snap-gap,0); align-content:start; width:fit-content; max-width:100%; min-width:0; }
|
|
106
|
+
snap-layout > *, rp-layout > * { min-width:0; }
|
|
107
|
+
snap-viewport snap-layout, rp-viewport rp-layout { width:100%; }
|
|
108
|
+
snap-viewport > snap-layout, rp-viewport > rp-layout { flex:1 1 auto; min-height:0; }
|
|
109
|
+
snap-viewport > snap-navbar, rp-viewport > rp-navbar { flex:0 0 auto; }
|
|
110
|
+
snap-panel, rp-panel { display:block; width:fit-content; max-width:100%; background:#fff; border:1px solid var(--rp-border); border-radius:var(--rp-radius-md); padding:var(--snap-padding,16px); }
|
|
111
|
+
snap-viewport snap-panel, rp-viewport rp-panel { width:auto; min-width:0; }
|
|
112
|
+
snap-panel[elevation="1"], rp-panel[elevation="1"] { box-shadow:0 4px 16px rgba(15,23,42,.06); }
|
|
113
|
+
snap-panel[elevation="2"], rp-panel[elevation="2"] { box-shadow:var(--rp-shadow); }
|
|
114
|
+
snap-navbar, rp-navbar { display:flex; align-items:center; gap:14px; height:var(--snap-height,64px); padding:0 24px; background:#fff; border-bottom:1px solid var(--rp-border); }
|
|
115
|
+
snap-sidebar, rp-sidebar { display:block; width:var(--snap-width,260px); min-height:0; background:#fff; border-right:1px solid var(--rp-border); padding:14px; }
|
|
116
|
+
snap-viewport snap-sidebar, rp-viewport rp-sidebar { min-height:100%; }
|
|
117
|
+
snap-sidebar[collapsed], rp-sidebar[collapsed] { width:72px; }
|
|
118
|
+
snap-logo, rp-logo { display:inline-grid; place-items:center; width:var(--snap-size,82px); height:32px; border-radius:8px; background:#111827; color:#fff; font-size:12px; font-weight:800; letter-spacing:.08em; }
|
|
119
|
+
snap-search, rp-search, snap-input, rp-input, snap-date-picker, rp-date-picker { display:inline-flex; align-items:center; gap:8px; width:280px; min-height:36px; padding:0 11px; border:1px solid var(--rp-border-strong); border-radius:8px; background:#fff; color:#111827; }
|
|
120
|
+
snap-textarea, rp-textarea { display:block; width:320px; min-height:calc(var(--snap-rows,3) * 24px + 22px); padding:9px 11px; border:1px solid var(--rp-border-strong); border-radius:8px; background:#fff; color:#111827; white-space:pre-wrap; }
|
|
121
|
+
snap-search[state="focus"], rp-search[state="focus"], snap-input[state="focus"], rp-input[state="focus"], snap-textarea[state="focus"], rp-textarea[state="focus"], snap-date-picker[state="focus"], rp-date-picker[state="focus"] { border-color:var(--rp-primary); box-shadow:0 0 0 3px rgba(37,99,235,.12); }
|
|
122
|
+
snap-search[state="filled"], rp-search[state="filled"], snap-input[state="filled"], rp-input[state="filled"], snap-textarea[state="filled"], rp-textarea[state="filled"], snap-date-picker[state="filled"], rp-date-picker[state="filled"] { border-color:#93c5fd; background:#f8fbff; }
|
|
123
|
+
snap-search[state="error"], rp-search[state="error"], snap-input[state="error"], rp-input[state="error"], snap-textarea[state="error"], rp-textarea[state="error"], snap-date-picker[state="error"], rp-date-picker[state="error"] { border-color:var(--rp-danger); box-shadow:0 0 0 3px rgba(220,38,38,.1); }
|
|
124
|
+
snap-search[state="disabled"], rp-search[state="disabled"], snap-input[state="disabled"], rp-input[state="disabled"], snap-textarea[state="disabled"], rp-textarea[state="disabled"], snap-date-picker[state="disabled"], rp-date-picker[state="disabled"] { opacity:.55; background:#f3f4f6; }
|
|
125
|
+
snap-input[label], rp-input[label], snap-date-picker[label], rp-date-picker[label] { display:inline-grid; align-items:start; gap:6px; width:280px; min-height:0; padding:0; border:0; background:transparent; box-shadow:none; }
|
|
126
|
+
snap-input[label][state="focus"], rp-input[label][state="focus"], snap-input[label][state="filled"], rp-input[label][state="filled"], snap-input[label][state="error"], rp-input[label][state="error"], snap-date-picker[label][state="focus"], rp-date-picker[label][state="focus"], snap-date-picker[label][state="filled"], rp-date-picker[label][state="filled"], snap-date-picker[label][state="error"], rp-date-picker[label][state="error"] { border:0; background:transparent; box-shadow:none; }
|
|
127
|
+
.rp-field-control { display:flex; align-items:center; gap:8px; min-height:36px; padding:0 11px; border:1px solid var(--rp-border-strong); border-radius:8px; background:#fff; color:#111827; }
|
|
128
|
+
snap-input[state="focus"] .rp-field-control, rp-input[state="focus"] .rp-field-control, snap-date-picker[state="focus"] .rp-field-control, rp-date-picker[state="focus"] .rp-field-control { border-color:var(--rp-primary); box-shadow:0 0 0 3px rgba(37,99,235,.12); }
|
|
129
|
+
snap-input[state="filled"] .rp-field-control, rp-input[state="filled"] .rp-field-control, snap-date-picker[state="filled"] .rp-field-control, rp-date-picker[state="filled"] .rp-field-control { border-color:#93c5fd; background:#f8fbff; }
|
|
130
|
+
snap-input[state="error"] .rp-field-control, rp-input[state="error"] .rp-field-control, snap-date-picker[state="error"] .rp-field-control, rp-date-picker[state="error"] .rp-field-control { border-color:var(--rp-danger); box-shadow:0 0 0 3px rgba(220,38,38,.1); }
|
|
131
|
+
.rp-field-label { display:block; margin:0 0 6px; color:#374151; font-size:12px; font-weight:650; }
|
|
132
|
+
.rp-placeholder { color:#9ca3af; }
|
|
133
|
+
.rp-value { color:#111827; }
|
|
134
|
+
.rp-error-text { color:var(--rp-danger); font-size:12px; }
|
|
135
|
+
snap-select, rp-select { display:inline-block; width:var(--snap-width,280px); }
|
|
136
|
+
.rp-select-control { display:flex; align-items:center; gap:8px; min-height:36px; padding:0 11px; border:1px solid var(--rp-border-strong); border-radius:8px; background:#fff; }
|
|
137
|
+
snap-select[state="expanded"] .rp-select-control, rp-select[state="expanded"] .rp-select-control { border-color:var(--rp-primary); box-shadow:0 0 0 3px rgba(37,99,235,.12); }
|
|
138
|
+
snap-select[state="disabled"], rp-select[state="disabled"] { opacity:.55; }
|
|
139
|
+
.rp-select-value { flex:1 1 auto; min-width:0; }
|
|
140
|
+
.rp-select-options { display:none; margin-top:6px; padding:5px; border:1px solid var(--rp-border); border-radius:8px; background:#fff; box-shadow:0 10px 18px rgba(15,23,42,.08); }
|
|
141
|
+
snap-select[state="expanded"] .rp-select-options, rp-select[state="expanded"] .rp-select-options { display:grid; gap:2px; }
|
|
142
|
+
.rp-select-option { padding:7px 8px; border-radius:6px; font-size:13px; color:#374151; }
|
|
143
|
+
.rp-select-option.selected { background:#eff6ff; color:#1d4ed8; font-weight:700; }
|
|
144
|
+
snap-badge, rp-badge { display:inline-grid; place-items:center; min-width:20px; height:20px; padding:0 6px; border-radius:999px; background:#ef4444; color:#fff; font-size:11px; font-weight:750; }
|
|
145
|
+
snap-avatar, rp-avatar { display:inline-grid; place-items:center; width:var(--snap-size,32px); height:var(--snap-size,32px); border-radius:999px; background:#e0e7ff; color:#3730a3; font-size:12px; font-weight:800; }
|
|
146
|
+
snap-list, rp-list { display:flex; flex-direction:column; gap:4px; width:100%; }
|
|
147
|
+
snap-list-item, rp-list-item { display:flex; align-items:center; gap:8px; width:100%; min-width:180px; height:36px; padding:0 10px; border-radius:8px; color:#374151; }
|
|
148
|
+
snap-list-item[state="selected"], rp-list-item[state="selected"] { background:#eff6ff; color:#1d4ed8; font-weight:700; }
|
|
149
|
+
snap-list-item[state="disabled"], rp-list-item[state="disabled"] { opacity:.5; }
|
|
150
|
+
.rp-list-label { flex:1 1 auto; }
|
|
151
|
+
.rp-list-badge { margin-left:auto; min-width:18px; height:18px; border-radius:999px; display:grid; place-items:center; padding:0 6px; background:#e5e7eb; color:#374151; font-size:11px; font-weight:700; }
|
|
152
|
+
snap-tabs, rp-tabs { display:flex; gap:6px; border-bottom:1px solid var(--rp-border); margin-bottom:12px; width:fit-content; }
|
|
153
|
+
snap-tab, rp-tab { display:inline-flex; align-items:center; gap:6px; padding:9px 13px; border-bottom:2px solid transparent; color:#6b7280; font-size:14px; }
|
|
154
|
+
snap-tab.rp-tab-active, rp-tab.rp-tab-active { color:var(--rp-primary); border-bottom-color:var(--rp-primary); font-weight:700; }
|
|
155
|
+
snap-button, rp-button { display:inline-flex; align-items:center; justify-content:center; gap:7px; min-height:34px; padding:0 12px; border-radius:8px; border:1px solid var(--rp-border); background:#fff; color:#374151; font-size:13px; font-weight:650; }
|
|
156
|
+
snap-button[size="sm"], rp-button[size="sm"] { min-height:28px; padding:0 9px; font-size:12px; border-radius:6px; }
|
|
157
|
+
snap-button[size="lg"], rp-button[size="lg"] { min-height:40px; padding:0 16px; font-size:14px; }
|
|
158
|
+
snap-button[variant="primary"], rp-button[variant="primary"] { border-color:var(--rp-primary); background:var(--rp-primary); color:#fff; }
|
|
159
|
+
snap-button[variant="secondary"], rp-button[variant="secondary"] { border-color:#bfdbfe; background:#eff6ff; color:#1d4ed8; }
|
|
160
|
+
snap-button[variant="danger"], rp-button[variant="danger"] { border-color:var(--rp-danger); color:var(--rp-danger); }
|
|
161
|
+
snap-button[variant="link"], rp-button[variant="link"] { border-color:transparent; background:transparent; color:var(--rp-primary); padding-inline:2px; }
|
|
162
|
+
snap-button[variant="ghost"], rp-button[variant="ghost"] { border-color:transparent; background:transparent; }
|
|
163
|
+
snap-button[state="disabled"], rp-button[state="disabled"], snap-button[disabled], rp-button[disabled] { opacity:.5; }
|
|
164
|
+
snap-button-group, rp-button-group { display:inline-flex; gap:0; width:fit-content; }
|
|
165
|
+
snap-button-group > snap-button, rp-button-group > rp-button { border-radius:0; margin-left:-1px; }
|
|
166
|
+
snap-button-group > :first-child { border-radius:8px 0 0 8px; margin-left:0; }
|
|
167
|
+
snap-button-group > :last-child { border-radius:0 8px 8px 0; }
|
|
168
|
+
snap-table, rp-table { display:table; border-collapse:collapse; width:fit-content; min-width:720px; max-width:980px; background:#fff; border:1px solid var(--rp-border); border-radius:8px; overflow:hidden; }
|
|
169
|
+
snap-viewport snap-table, rp-viewport rp-table { width:100%; max-width:none; }
|
|
170
|
+
.rp-table-row { display:table-row; }
|
|
171
|
+
.rp-table-cell { display:table-cell; padding:11px 12px; border-bottom:1px solid var(--rp-border); font-size:13px; vertical-align:middle; white-space:nowrap; }
|
|
172
|
+
.rp-table-head .rp-table-cell { background:#f9fafb; color:#6b7280; font-size:12px; font-weight:750; }
|
|
173
|
+
.rp-table-row:last-child .rp-table-cell { border-bottom:0; }
|
|
174
|
+
snap-table-row, rp-table-row { display:grid; grid-template-columns:44px 150px 240px 90px 90px; align-items:center; min-width:560px; border:1px solid var(--rp-border); border-radius:8px; overflow:hidden; background:#fff; }
|
|
175
|
+
snap-table-row > span, rp-table-row > span { padding:10px 12px; font-size:13px; }
|
|
176
|
+
snap-table-row[state="unread"], rp-table-row[state="unread"] { background:#eff6ff; font-weight:700; }
|
|
177
|
+
snap-table-row[state="selected"], rp-table-row[state="selected"] { outline:2px solid rgba(37,99,235,.35); background:#f8fbff; }
|
|
178
|
+
snap-table-row[state="highlighted"], rp-table-row[state="highlighted"] { background:#fffbeb; }
|
|
179
|
+
snap-table-row[state="disabled"], rp-table-row[state="disabled"] { opacity:.5; }
|
|
180
|
+
snap-bulk-action-bar, rp-bulk-action-bar { display:flex; align-items:center; gap:8px; width:fit-content; padding:8px 10px; margin:0 0 10px; border:1px solid #bfdbfe; background:#eff6ff; border-radius:8px; color:#1e40af; font-size:13px; font-weight:650; }
|
|
181
|
+
snap-empty, rp-empty { display:grid; justify-items:center; gap:8px; width:fit-content; min-width:240px; padding:24px; border:1px dashed var(--rp-border-strong); border-radius:10px; background:#fff; color:#6b7280; text-align:center; }
|
|
182
|
+
.rp-empty-title { color:#111827; font-weight:700; }
|
|
183
|
+
.rp-empty-desc { font-size:13px; }
|
|
184
|
+
snap-loading, rp-loading { display:grid; gap:8px; min-width:260px; color:var(--rp-primary); }
|
|
185
|
+
.rp-skeleton-line { height:14px; border-radius:999px; background:linear-gradient(90deg,#f3f4f6,#e5e7eb,#f3f4f6); }
|
|
186
|
+
.rp-spinner { display:inline-grid; place-items:center; width:32px; height:32px; }
|
|
187
|
+
snap-alert, rp-alert, snap-toast, rp-toast { display:flex; align-items:flex-start; gap:8px; width:fit-content; max-width:420px; padding:10px 12px; border:1px solid var(--rp-border); border-radius:8px; background:#fff; font-size:13px; }
|
|
188
|
+
snap-alert[type="info"], rp-alert[type="info"], snap-toast[type="info"], rp-toast[type="info"] { border-color:#bfdbfe; background:#eff6ff; color:#1e40af; }
|
|
189
|
+
snap-alert[type="success"], rp-alert[type="success"], snap-toast[type="success"], rp-toast[type="success"] { border-color:#bbf7d0; background:#f0fdf4; color:#166534; }
|
|
190
|
+
snap-alert[type="warning"], rp-alert[type="warning"], snap-toast[type="warning"], rp-toast[type="warning"] { border-color:#fde68a; background:#fffbeb; color:#92400e; }
|
|
191
|
+
snap-alert[type="error"], rp-alert[type="error"], snap-toast[type="error"], rp-toast[type="error"] { border-color:#fecaca; background:#fef2f2; color:#991b1b; }
|
|
192
|
+
snap-dropdown, rp-dropdown, snap-popover, rp-popover { display:block; width:var(--snap-width,300px); padding:8px; border:1px solid var(--rp-border); border-radius:10px; background:#fff; box-shadow:0 12px 24px rgba(15,23,42,.1); }
|
|
193
|
+
snap-tooltip, rp-tooltip { display:inline-block; width:fit-content; max-width:240px; padding:6px 8px; border-radius:6px; background:#111827; color:#fff; font-size:12px; }
|
|
194
|
+
.rp-overlay-title { margin:0 0 8px; color:#111827; font-size:14px; font-weight:750; }
|
|
195
|
+
snap-modal, rp-modal { display:block; width:min(var(--snap-width,480px), 100%); border:1px solid var(--rp-border); border-radius:12px; background:#fff; box-shadow:0 24px 48px rgba(15,23,42,.18); overflow:hidden; }
|
|
196
|
+
snap-drawer, rp-drawer { display:block; width:min(var(--snap-width,360px), 100%); min-height:320px; border:1px solid var(--rp-border); background:#fff; box-shadow:0 18px 40px rgba(15,23,42,.14); }
|
|
197
|
+
.rp-modal-head, .rp-drawer-head { display:flex; align-items:center; justify-content:space-between; padding:14px 16px; border-bottom:1px solid var(--rp-border); font-weight:750; }
|
|
198
|
+
.rp-modal-body, .rp-drawer-body { padding:16px; }
|
|
199
|
+
.rp-modal-footer { display:flex; justify-content:flex-end; gap:8px; padding:12px 16px; border-top:1px solid var(--rp-border); background:#f9fafb; }
|
|
200
|
+
snap-card, rp-card { display:block; width:auto; min-width:220px; padding:14px; border:1px solid var(--rp-border); border-radius:10px; background:#fff; }
|
|
201
|
+
.rp-card-image { display:grid; place-items:center; height:120px; margin:-14px -14px 12px; border-radius:10px 10px 0 0; background:#f3f4f6; color:#6b7280; }
|
|
202
|
+
.rp-card-title { display:block; color:#111827; font-weight:750; }
|
|
203
|
+
.rp-card-subtitle { display:block; margin-top:4px; color:#6b7280; font-size:13px; }
|
|
204
|
+
.rp-card-footer { margin:12px -14px -14px; padding:10px 14px; border-top:1px solid var(--rp-border); background:#f9fafb; }
|
|
205
|
+
snap-stat-card, rp-stat-card { display:grid; gap:6px; width:auto; min-width:0; padding:16px; border:1px solid var(--rp-border); border-radius:10px; background:#fff; }
|
|
206
|
+
.rp-stat-label { color:#6b7280; font-size:12px; font-weight:650; }
|
|
207
|
+
.rp-stat-value { color:#111827; font-size:26px; font-weight:800; }
|
|
208
|
+
.rp-stat-change { font-size:12px; font-weight:700; }
|
|
209
|
+
snap-stat-card[trend="up"] .rp-stat-change, rp-stat-card[trend="up"] .rp-stat-change { color:var(--rp-success); }
|
|
210
|
+
snap-stat-card[trend="down"] .rp-stat-change, rp-stat-card[trend="down"] .rp-stat-change { color:var(--rp-danger); }
|
|
211
|
+
snap-tag, rp-tag { display:inline-flex; align-items:center; gap:5px; height:24px; padding:0 8px; border-radius:999px; background:#eef2ff; color:#3730a3; font-size:12px; font-weight:650; }
|
|
212
|
+
snap-tag[color="green"], rp-tag[color="green"] { background:#dcfce7; color:#166534; }
|
|
213
|
+
snap-tag[color="orange"], rp-tag[color="orange"] { background:#ffedd5; color:#9a3412; }
|
|
214
|
+
snap-tag[color="red"], rp-tag[color="red"] { background:#fee2e2; color:#991b1b; }
|
|
215
|
+
snap-checkbox, rp-checkbox, snap-radio, rp-radio { display:inline-flex; align-items:center; gap:8px; font-size:13px; }
|
|
216
|
+
.rp-box { display:inline-grid; place-items:center; width:16px; height:16px; border:1px solid var(--rp-border-strong); border-radius:4px; color:#fff; }
|
|
217
|
+
snap-checkbox[state="checked"] .rp-box, rp-checkbox[state="checked"] .rp-box, snap-radio[state="checked"] .rp-box, rp-radio[state="checked"] .rp-box, snap-checkbox[state="indeterminate"] .rp-box, rp-checkbox[state="indeterminate"] .rp-box { background:var(--rp-primary); border-color:var(--rp-primary); }
|
|
218
|
+
snap-checkbox[state="disabled"], rp-checkbox[state="disabled"], snap-radio[state="disabled"], rp-radio[state="disabled"] { opacity:.5; }
|
|
219
|
+
snap-radio .rp-box, rp-radio .rp-box { border-radius:999px; }
|
|
220
|
+
snap-toggle, rp-toggle { display:inline-flex; align-items:center; gap:8px; font-size:13px; }
|
|
221
|
+
.rp-toggle-track { width:34px; height:20px; border-radius:999px; background:#d1d5db; padding:2px; }
|
|
222
|
+
.rp-toggle-dot { width:16px; height:16px; border-radius:999px; background:#fff; transition:none; }
|
|
223
|
+
snap-toggle[state="on"] .rp-toggle-track, rp-toggle[state="on"] .rp-toggle-track { background:var(--rp-primary); }
|
|
224
|
+
snap-toggle[state="on"] .rp-toggle-dot, rp-toggle[state="on"] .rp-toggle-dot { margin-left:14px; }
|
|
225
|
+
snap-toggle[state="disabled"], rp-toggle[state="disabled"] { opacity:.5; }
|
|
226
|
+
snap-form, rp-form { display:grid; gap:12px; width:fit-content; }
|
|
227
|
+
snap-form[layout="horizontal"], rp-form[layout="horizontal"] { grid-template-columns:max-content 1fr; align-items:start; }
|
|
228
|
+
snap-form-item, rp-form-item { display:grid; gap:6px; width:fit-content; }
|
|
229
|
+
.rp-form-label { color:#374151; font-size:12px; font-weight:700; }
|
|
230
|
+
.rp-form-label.required::after { content:" *"; color:var(--rp-danger); }
|
|
231
|
+
.rp-form-error { color:var(--rp-danger); font-size:12px; }
|
|
232
|
+
snap-upload, rp-upload { display:grid; justify-items:center; gap:8px; width:280px; padding:18px; border:1px dashed var(--rp-border-strong); border-radius:10px; background:#fff; color:#6b7280; text-align:center; font-size:13px; }
|
|
233
|
+
snap-upload[state="has-file"], rp-upload[state="has-file"] { justify-items:start; border-style:solid; color:#374151; }
|
|
234
|
+
snap-upload[state="uploading"], rp-upload[state="uploading"] { border-color:#bfdbfe; background:#eff6ff; color:#1e40af; }
|
|
235
|
+
snap-image-placeholder, rp-image-placeholder { display:grid; place-items:center; width:var(--snap-width,160px); height:var(--snap-height,100px); background:#f3f4f6; border:1px dashed var(--rp-border-strong); border-radius:8px; color:#6b7280; font-size:12px; }
|
|
236
|
+
snap-progress, rp-progress { display:block; width:180px; height:8px; border-radius:999px; background:#e5e7eb; overflow:hidden; }
|
|
237
|
+
snap-progress[kind="circle"], rp-progress[kind="circle"], snap-progress[style="circle"], rp-progress[style="circle"] { display:grid; place-items:center; width:52px; height:52px; border-radius:999px; background:conic-gradient(var(--rp-primary) var(--progress,40%), #e5e7eb 0); font-size:12px; font-weight:750; }
|
|
238
|
+
.rp-progress-bar { display:block; height:100%; width:var(--progress,40%); background:var(--rp-primary); }
|
|
239
|
+
snap-progress[status="success"] .rp-progress-bar, rp-progress[status="success"] .rp-progress-bar { background:var(--rp-success); }
|
|
240
|
+
snap-progress[status="error"] .rp-progress-bar, rp-progress[status="error"] .rp-progress-bar { background:var(--rp-danger); }
|
|
241
|
+
snap-pagination, rp-pagination { display:inline-flex; align-items:center; gap:6px; width:fit-content; font-size:13px; }
|
|
242
|
+
.rp-page-btn { display:inline-grid; place-items:center; min-width:30px; height:30px; padding:0 8px; border:1px solid var(--rp-border); border-radius:6px; background:#fff; color:#374151; }
|
|
243
|
+
.rp-page-btn.active { border-color:var(--rp-primary); background:var(--rp-primary); color:#fff; font-weight:750; }
|
|
244
|
+
snap-steps, rp-steps { display:flex; align-items:center; gap:8px; width:fit-content; }
|
|
245
|
+
.rp-step { display:inline-flex; align-items:center; gap:6px; color:#6b7280; font-size:13px; }
|
|
246
|
+
.rp-step-dot { display:inline-grid; place-items:center; width:22px; height:22px; border-radius:999px; border:1px solid var(--rp-border-strong); background:#fff; color:#6b7280; font-size:11px; font-weight:750; }
|
|
247
|
+
.rp-step.active { color:var(--rp-primary); font-weight:750; }
|
|
248
|
+
.rp-step.active .rp-step-dot { border-color:var(--rp-primary); background:var(--rp-primary); color:#fff; }
|
|
249
|
+
.rp-step.done .rp-step-dot { border-color:var(--rp-success); background:var(--rp-success); color:#fff; }
|
|
250
|
+
.rp-step-sep { width:28px; height:1px; background:var(--rp-border); }
|
|
251
|
+
snap-breadcrumb, rp-breadcrumb { display:inline-flex; align-items:center; gap:6px; color:#6b7280; font-size:13px; }
|
|
252
|
+
.rp-breadcrumb-current { color:#111827; font-weight:650; }
|
|
253
|
+
`;
|
|
254
|
+
function injectStyle() {
|
|
255
|
+
if (document.getElementById(RPUI_STYLE_ID)) return;
|
|
256
|
+
const el = document.createElement("style");
|
|
257
|
+
el.id = RPUI_STYLE_ID;
|
|
258
|
+
el.textContent = style;
|
|
259
|
+
document.head.appendChild(el);
|
|
260
|
+
}
|
|
261
|
+
class RpAnnotation extends HTMLElement {
|
|
262
|
+
connectedCallback() {
|
|
263
|
+
var _a;
|
|
264
|
+
injectStyle();
|
|
265
|
+
if (this.dataset.rpReady) return;
|
|
266
|
+
this.dataset.rpReady = "true";
|
|
267
|
+
const existing = Array.from(this.childNodes);
|
|
268
|
+
const depth = this.annotationDepth();
|
|
269
|
+
const id = attr(this, "id");
|
|
270
|
+
const label = attr(this, "label", id ? `Annotation ${id}` : "Annotation");
|
|
271
|
+
let sectionPath;
|
|
272
|
+
if (id) {
|
|
273
|
+
sectionPath = id;
|
|
274
|
+
} else {
|
|
275
|
+
const parentSection = ((_a = this.closest("[data-rp-section]")) == null ? void 0 : _a.dataset.rpSection) ?? "";
|
|
276
|
+
const siblings = this.parentElement ? Array.from(this.parentElement.children).filter(
|
|
277
|
+
(el) => el.tagName.toLowerCase() === "rp-annotation" || el.tagName.toLowerCase() === "proto-annotation"
|
|
278
|
+
) : [];
|
|
279
|
+
const idx = siblings.indexOf(this) + 1;
|
|
280
|
+
sectionPath = parentSection ? `${parentSection}-${idx}` : String(idx);
|
|
281
|
+
}
|
|
282
|
+
this.dataset.rpSection = sectionPath;
|
|
283
|
+
const marker = document.createElement("span");
|
|
284
|
+
const kind = id ? "drop" : depth <= 1 ? "circle" : "triangle";
|
|
285
|
+
marker.className = `rp-annotation-marker ${kind}`;
|
|
286
|
+
marker.innerHTML = kind === "drop" ? `<span>${escapeHtml(id)}</span>` : "";
|
|
287
|
+
const head = document.createElement("div");
|
|
288
|
+
head.className = "rp-annotation-head";
|
|
289
|
+
head.append(marker);
|
|
290
|
+
const title = document.createElement("span");
|
|
291
|
+
title.className = "rp-annotation-title";
|
|
292
|
+
title.textContent = label;
|
|
293
|
+
title.addEventListener("click", () => {
|
|
294
|
+
const url = new URL(location.href);
|
|
295
|
+
url.searchParams.set("section", sectionPath);
|
|
296
|
+
history.pushState(null, "", url);
|
|
297
|
+
window.dispatchEvent(new CustomEvent("rp-section", { detail: sectionPath }));
|
|
298
|
+
});
|
|
299
|
+
head.append(title);
|
|
300
|
+
const body = document.createElement("div");
|
|
301
|
+
body.className = "rp-annotation-body";
|
|
302
|
+
existing.forEach((n) => body.appendChild(n));
|
|
303
|
+
this.append(head, body);
|
|
304
|
+
}
|
|
305
|
+
annotationDepth() {
|
|
306
|
+
let d = 0;
|
|
307
|
+
let p = this.parentElement;
|
|
308
|
+
while (p) {
|
|
309
|
+
if (p.tagName.toLowerCase() === "rp-annotation" || p.tagName.toLowerCase() === "proto-annotation") d++;
|
|
310
|
+
p = p.parentElement;
|
|
311
|
+
}
|
|
312
|
+
return d;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
class RpEnum extends HTMLElement {
|
|
316
|
+
connectedCallback() {
|
|
317
|
+
injectStyle();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
class RpEnumItem extends HTMLElement {
|
|
321
|
+
connectedCallback() {
|
|
322
|
+
injectStyle();
|
|
323
|
+
if (this.dataset.rpReady) return;
|
|
324
|
+
this.dataset.rpReady = "true";
|
|
325
|
+
const children = Array.from(this.childNodes);
|
|
326
|
+
const parent = this.parentElement;
|
|
327
|
+
const siblings = parent ? Array.from(parent.children).filter(
|
|
328
|
+
(el) => el.tagName.toLowerCase() === "rp-enum-item" || el.tagName.toLowerCase() === "proto-enum-item"
|
|
329
|
+
) : [];
|
|
330
|
+
const idx = siblings.indexOf(this) + 1;
|
|
331
|
+
const labelEl = document.createElement("span");
|
|
332
|
+
labelEl.className = "rp-enum-label";
|
|
333
|
+
const idxBadge = document.createElement("span");
|
|
334
|
+
idxBadge.className = "rp-enum-index";
|
|
335
|
+
idxBadge.textContent = String(idx);
|
|
336
|
+
const labelText = document.createElement("span");
|
|
337
|
+
labelText.className = "rp-enum-label-text";
|
|
338
|
+
labelText.textContent = attr(this, "label", "State");
|
|
339
|
+
const description = attr(this, "description");
|
|
340
|
+
if (description) {
|
|
341
|
+
const desc = document.createElement("span");
|
|
342
|
+
desc.className = "rp-enum-description";
|
|
343
|
+
desc.textContent = description;
|
|
344
|
+
labelText.appendChild(desc);
|
|
345
|
+
}
|
|
346
|
+
labelEl.append(idxBadge, labelText);
|
|
347
|
+
const content = document.createElement("div");
|
|
348
|
+
content.className = "rp-enum-content";
|
|
349
|
+
children.forEach((n) => content.appendChild(n));
|
|
350
|
+
this.append(labelEl, content);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
class RpMainView extends HTMLElement {
|
|
354
|
+
constructor() {
|
|
355
|
+
super(...arguments);
|
|
356
|
+
__publicField(this, "ro");
|
|
357
|
+
__publicField(this, "frame", 0);
|
|
358
|
+
}
|
|
359
|
+
connectedCallback() {
|
|
360
|
+
injectStyle();
|
|
361
|
+
if (!this.dataset.rpReady) {
|
|
362
|
+
this.dataset.rpReady = "true";
|
|
363
|
+
const width = resolveWidth(this, 1440);
|
|
364
|
+
const height = resolveHeight(this, 900);
|
|
365
|
+
const autoHeight = usesAutoHeight(this);
|
|
366
|
+
const scale = Number(attr(this, "scale", "0.7")) || 0.7;
|
|
367
|
+
const children = Array.from(this.childNodes);
|
|
368
|
+
const shell = document.createElement("div");
|
|
369
|
+
shell.className = "rp-main-shell";
|
|
370
|
+
shell.style.width = `${width * scale}px`;
|
|
371
|
+
if (!autoHeight) shell.style.height = `${height * scale}px`;
|
|
372
|
+
const stage2 = document.createElement("div");
|
|
373
|
+
stage2.className = "rp-main-stage";
|
|
374
|
+
stage2.style.width = `${width}px`;
|
|
375
|
+
stage2.style.minHeight = autoHeight ? "0" : `${height}px`;
|
|
376
|
+
stage2.style.height = autoHeight ? "auto" : `${height}px`;
|
|
377
|
+
stage2.style.transform = `scale(${scale})`;
|
|
378
|
+
const clip = document.createElement("div");
|
|
379
|
+
clip.className = "rp-main-stage-clip";
|
|
380
|
+
children.forEach((n) => {
|
|
381
|
+
if (isViewportNode(n)) {
|
|
382
|
+
if (!n.hasAttribute("width") && !n.hasAttribute("device")) n.style.setProperty("--snap-width", `${width}px`);
|
|
383
|
+
if (!n.hasAttribute("height")) n.style.setProperty("--snap-height", autoHeight ? "auto" : `${height}px`);
|
|
384
|
+
}
|
|
385
|
+
stage2.appendChild(n);
|
|
386
|
+
});
|
|
387
|
+
clip.appendChild(stage2);
|
|
388
|
+
shell.appendChild(clip);
|
|
389
|
+
this.appendChild(shell);
|
|
390
|
+
}
|
|
391
|
+
this.scheduleRender();
|
|
392
|
+
this.ro = new ResizeObserver(() => this.scheduleRender());
|
|
393
|
+
this.ro.observe(this);
|
|
394
|
+
const stage = this.querySelector(".rp-main-stage");
|
|
395
|
+
if (stage) this.ro.observe(stage);
|
|
396
|
+
}
|
|
397
|
+
disconnectedCallback() {
|
|
398
|
+
var _a;
|
|
399
|
+
(_a = this.ro) == null ? void 0 : _a.disconnect();
|
|
400
|
+
if (this.frame) cancelAnimationFrame(this.frame);
|
|
401
|
+
}
|
|
402
|
+
scheduleRender() {
|
|
403
|
+
if (this.frame) return;
|
|
404
|
+
this.frame = requestAnimationFrame(() => {
|
|
405
|
+
this.frame = 0;
|
|
406
|
+
this.syncAutoHeight();
|
|
407
|
+
this.renderPins();
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
syncAutoHeight() {
|
|
411
|
+
if (!usesAutoHeight(this)) return;
|
|
412
|
+
const shell = this.querySelector(".rp-main-shell");
|
|
413
|
+
const stage = this.querySelector(".rp-main-stage");
|
|
414
|
+
if (!shell || !stage) return;
|
|
415
|
+
const scale = Number(attr(this, "scale", "0.7")) || 0.7;
|
|
416
|
+
const next = `${Math.ceil(stage.scrollHeight * scale)}px`;
|
|
417
|
+
if (shell.style.height !== next) shell.style.height = next;
|
|
418
|
+
}
|
|
419
|
+
renderPins() {
|
|
420
|
+
const shell = this.querySelector(".rp-main-shell");
|
|
421
|
+
const stage = this.querySelector(".rp-main-stage");
|
|
422
|
+
if (!shell || !stage) return;
|
|
423
|
+
shell.querySelectorAll(".rp-pin").forEach((p) => p.remove());
|
|
424
|
+
const shellRect = shell.getBoundingClientRect();
|
|
425
|
+
stage.querySelectorAll("[data-pin]").forEach((target) => {
|
|
426
|
+
const id = target.dataset.pin;
|
|
427
|
+
if (!id) return;
|
|
428
|
+
const r = target.getBoundingClientRect();
|
|
429
|
+
const pin = document.createElement("span");
|
|
430
|
+
pin.className = "rp-pin";
|
|
431
|
+
pin.style.left = `${r.left - shellRect.left}px`;
|
|
432
|
+
pin.style.top = `${r.top - shellRect.top}px`;
|
|
433
|
+
pin.innerHTML = `<span>${escapeHtml(id)}</span>`;
|
|
434
|
+
pin.addEventListener("click", () => {
|
|
435
|
+
const url = new URL(location.href);
|
|
436
|
+
url.searchParams.set("section", id);
|
|
437
|
+
history.pushState(null, "", url);
|
|
438
|
+
window.dispatchEvent(new CustomEvent("rp-section", { detail: id }));
|
|
439
|
+
});
|
|
440
|
+
shell.appendChild(pin);
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function activateSection(path, pane) {
|
|
445
|
+
document.querySelectorAll(".rp-section-focus").forEach((el) => el.classList.remove("rp-section-focus"));
|
|
446
|
+
const target = document.querySelector(`[data-rp-section="${CSS.escape(path)}"]`);
|
|
447
|
+
if (!target) return;
|
|
448
|
+
target.classList.add("rp-section-focus");
|
|
449
|
+
if (pane) {
|
|
450
|
+
const paneEl = pane;
|
|
451
|
+
const targetRect = target.getBoundingClientRect();
|
|
452
|
+
const paneRect = paneEl.getBoundingClientRect();
|
|
453
|
+
paneEl.scrollTo({ top: paneEl.scrollTop + targetRect.top - paneRect.top - 20, behavior: "smooth" });
|
|
454
|
+
}
|
|
455
|
+
setTimeout(() => target.classList.remove("rp-section-focus"), 3e3);
|
|
456
|
+
}
|
|
457
|
+
class RpPage extends HTMLElement {
|
|
458
|
+
connectedCallback() {
|
|
459
|
+
injectStyle();
|
|
460
|
+
if (this.dataset.rpReady) return;
|
|
461
|
+
this.dataset.rpReady = "true";
|
|
462
|
+
const pageTitle = attr(this, "title", "Untitled");
|
|
463
|
+
const route = attr(this, "route", "/");
|
|
464
|
+
const description = attr(this, "description", "");
|
|
465
|
+
this.removeAttribute("title");
|
|
466
|
+
const existing = Array.from(this.childNodes);
|
|
467
|
+
const header = document.createElement("div");
|
|
468
|
+
header.className = "rp-page-header";
|
|
469
|
+
header.innerHTML = `<div class="rp-page-title-row"><h1 class="rp-page-title">${escapeHtml(pageTitle)}</h1><span class="rp-page-route">${escapeHtml(route)}</span></div><p class="rp-page-description">${escapeHtml(description)}</p>`;
|
|
470
|
+
const body = document.createElement("div");
|
|
471
|
+
body.className = "rp-page-body";
|
|
472
|
+
const main = document.createElement("main");
|
|
473
|
+
main.className = "rp-page-main";
|
|
474
|
+
const pane = document.createElement("aside");
|
|
475
|
+
pane.className = "rp-annotation-pane";
|
|
476
|
+
pane.setAttribute("aria-label", "Annotations");
|
|
477
|
+
const paneInner = document.createElement("div");
|
|
478
|
+
paneInner.className = "rp-annotation-pane-inner";
|
|
479
|
+
existing.forEach((n) => (isTopAnnotation(n) ? paneInner : body).appendChild(n));
|
|
480
|
+
pane.appendChild(paneInner);
|
|
481
|
+
main.append(header, body);
|
|
482
|
+
const shell = document.createElement("div");
|
|
483
|
+
shell.className = "rp-page-shell";
|
|
484
|
+
shell.append(main, pane);
|
|
485
|
+
this.appendChild(shell);
|
|
486
|
+
requestAnimationFrame(() => {
|
|
487
|
+
const mv = body.querySelector("rp-main-view, proto-main-view");
|
|
488
|
+
if (mv) header.style.maxWidth = `${mv.offsetWidth}px`;
|
|
489
|
+
});
|
|
490
|
+
const go = () => {
|
|
491
|
+
const sec = new URLSearchParams(location.search).get("section");
|
|
492
|
+
if (sec) activateSection(sec, pane);
|
|
493
|
+
};
|
|
494
|
+
window.addEventListener("popstate", go);
|
|
495
|
+
window.addEventListener("rp-section", (e) => activateSection(e.detail, pane));
|
|
496
|
+
requestAnimationFrame(go);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
class GenericElement extends HTMLElement {
|
|
500
|
+
connectedCallback() {
|
|
501
|
+
injectStyle();
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
class ViewportElement extends HTMLElement {
|
|
505
|
+
connectedCallback() {
|
|
506
|
+
injectStyle();
|
|
507
|
+
if (this.hasAttribute("width") || this.hasAttribute("device")) this.style.setProperty("--snap-width", `${resolveWidth(this, 1440)}px`);
|
|
508
|
+
if (hasExplicitNumericHeight(this)) this.style.setProperty("--snap-height", `${resolveHeight(this, 900)}px`);
|
|
509
|
+
else if (usesAutoHeight(this)) this.style.setProperty("--snap-height", "auto");
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
class LayoutElement extends HTMLElement {
|
|
513
|
+
connectedCallback() {
|
|
514
|
+
injectStyle();
|
|
515
|
+
this.style.setProperty("--snap-columns", attr(this, "columns", "1fr"));
|
|
516
|
+
this.style.setProperty("--snap-rows", attr(this, "rows", "auto"));
|
|
517
|
+
if (this.hasAttribute("gap")) this.style.setProperty("--snap-gap", `${attr(this, "gap", "0")}px`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
class PanelElement extends HTMLElement {
|
|
521
|
+
connectedCallback() {
|
|
522
|
+
injectStyle();
|
|
523
|
+
this.style.setProperty("--snap-padding", `${attr(this, "padding", "16")}px`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
class NavbarElement extends HTMLElement {
|
|
527
|
+
connectedCallback() {
|
|
528
|
+
injectStyle();
|
|
529
|
+
this.style.setProperty("--snap-height", `${attr(this, "height", "64")}px`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
class SidebarElement extends HTMLElement {
|
|
533
|
+
connectedCallback() {
|
|
534
|
+
injectStyle();
|
|
535
|
+
this.style.setProperty("--snap-width", `${attr(this, "width", "260")}px`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
class LogoElement extends HTMLElement {
|
|
539
|
+
connectedCallback() {
|
|
540
|
+
injectStyle();
|
|
541
|
+
if (this.hasAttribute("size")) this.style.setProperty("--snap-size", `${attr(this, "size", "82")}px`);
|
|
542
|
+
if (!this.innerHTML.trim()) this.textContent = attr(this, "label", "LOGO");
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
const iconPaths = {
|
|
546
|
+
search: '<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>',
|
|
547
|
+
bell: '<path d="M10.3 21a1.9 1.9 0 0 0 3.4 0"/><path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9"/>',
|
|
548
|
+
user: '<path d="M20 21a8 8 0 0 0-16 0"/><circle cx="12" cy="7" r="4"/>',
|
|
549
|
+
inbox: '<polyline points="22 12 16 12 14 15 10 15 8 12 2 12"/><path d="M5.5 5h13L22 12v7a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-7z"/>',
|
|
550
|
+
archive: '<rect width="20" height="5" x="2" y="3" rx="1"/><path d="M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8"/><path d="M10 12h4"/>',
|
|
551
|
+
"at-sign": '<circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8"/>',
|
|
552
|
+
check: '<path d="M20 6 9 17l-5-5"/>',
|
|
553
|
+
"trash-2": '<path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/>',
|
|
554
|
+
x: '<path d="M18 6 6 18"/><path d="m6 6 12 12"/>',
|
|
555
|
+
loader: '<path d="M21 12a9 9 0 1 1-6.2-8.6"/>',
|
|
556
|
+
image: '<rect width="18" height="18" x="3" y="3" rx="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.1-3.1a2 2 0 0 0-2.8 0L6 21"/>',
|
|
557
|
+
"circle-alert": '<circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/>',
|
|
558
|
+
"chevron-down": '<path d="m6 9 6 6 6-6"/>',
|
|
559
|
+
"layout-dashboard": '<rect width="7" height="9" x="3" y="3" rx="1"/><rect width="7" height="5" x="14" y="3" rx="1"/><rect width="7" height="9" x="14" y="12" rx="1"/><rect width="7" height="5" x="3" y="16" rx="1"/>',
|
|
560
|
+
"message-square": '<path d="M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4z"/>',
|
|
561
|
+
settings: '<path d="M12.2 2h-.4l-1 3a7 7 0 0 0-1.6.7l-3-1.4-.3.3-2 3 .2.4 2.6 2a7 7 0 0 0 0 2l-2.6 2-.2.4 2 3 .3.3 3-1.4a7 7 0 0 0 1.6.7l1 3h.4l1-3a7 7 0 0 0 1.6-.7l3 1.4.3-.3 2-3-.2-.4-2.6-2a7 7 0 0 0 0-2l2.6-2 .2-.4-2-3-.3-.3-3 1.4a7 7 0 0 0-1.6-.7z"/><circle cx="12" cy="12" r="3"/>',
|
|
562
|
+
plus: '<path d="M5 12h14"/><path d="M12 5v14"/>',
|
|
563
|
+
file: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/>',
|
|
564
|
+
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.9"/><path d="M16 3.1a4 4 0 0 1 0 7.8"/>',
|
|
565
|
+
shield: '<path d="M20 13c0 5-3.5 7.5-8 9-4.5-1.5-8-4-8-9V5l8-3 8 3z"/>',
|
|
566
|
+
calendar: '<path d="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/>',
|
|
567
|
+
upload: '<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="m17 8-5-5-5 5"/><path d="M12 3v12"/>',
|
|
568
|
+
empty: '<path d="M4 7h16"/><path d="M5 7l1.5 13h11L19 7"/><path d="M9 11h6"/>',
|
|
569
|
+
"chevron-left": '<path d="m15 18-6-6 6-6"/>',
|
|
570
|
+
"chevron-right": '<path d="m9 18 6-6-6-6"/>',
|
|
571
|
+
minus: '<path d="M5 12h14"/>',
|
|
572
|
+
"alert-triangle": '<path d="m21.7 18-8-14a2 2 0 0 0-3.4 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.7-3Z"/><path d="M12 9v4"/><path d="M12 17h.01"/>',
|
|
573
|
+
info: '<circle cx="12" cy="12" r="10"/><path d="M12 16v-4"/><path d="M12 8h.01"/>',
|
|
574
|
+
"circle-check": '<circle cx="12" cy="12" r="10"/><path d="m9 12 2 2 4-4"/>',
|
|
575
|
+
circle: '<circle cx="12" cy="12" r="10"/>'
|
|
576
|
+
};
|
|
577
|
+
function icon(name, size = 16) {
|
|
578
|
+
const key = name || "file";
|
|
579
|
+
const paths = iconPaths[key] || iconPaths.file;
|
|
580
|
+
return `<svg class="rp-icon" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths}</svg>`;
|
|
581
|
+
}
|
|
582
|
+
class FieldElement extends HTMLElement {
|
|
583
|
+
connectedCallback() {
|
|
584
|
+
injectStyle();
|
|
585
|
+
if (this.dataset.rpReady) return;
|
|
586
|
+
this.dataset.rpReady = "true";
|
|
587
|
+
const value = attr(this, "value");
|
|
588
|
+
const placeholder = attr(this, "placeholder", "Search");
|
|
589
|
+
const label = attr(this, "label");
|
|
590
|
+
const error = attr(this, "error-message");
|
|
591
|
+
const showValue = value || attr(this, "state") === "filled";
|
|
592
|
+
const content = `${this.fieldIcon()}<span class="${showValue ? "rp-value" : "rp-placeholder"}">${escapeHtml(value || placeholder)}</span>${this.hasAttribute("has-clear-button") ? icon("x", 14) : ""}`;
|
|
593
|
+
this.innerHTML = label || error ? `<span class="rp-field-label">${escapeHtml(label)}</span><span class="rp-field-control">${content}</span>${error ? `<span class="rp-error-text">${escapeHtml(error)}</span>` : ""}` : content;
|
|
594
|
+
}
|
|
595
|
+
fieldIcon() {
|
|
596
|
+
return icon(this.tagName.toLowerCase().includes("date-picker") ? "calendar" : "search");
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
class TextareaElement extends HTMLElement {
|
|
600
|
+
connectedCallback() {
|
|
601
|
+
injectStyle();
|
|
602
|
+
if (this.dataset.rpReady) return;
|
|
603
|
+
this.dataset.rpReady = "true";
|
|
604
|
+
this.style.setProperty("--snap-rows", attr(this, "rows", "3"));
|
|
605
|
+
const value = attr(this, "value") || attr(this, "placeholder", "Textarea");
|
|
606
|
+
this.innerHTML = `<span class="${attr(this, "value") ? "rp-value" : "rp-placeholder"}">${escapeHtml(value)}</span>`;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
class SelectElement extends HTMLElement {
|
|
610
|
+
connectedCallback() {
|
|
611
|
+
injectStyle();
|
|
612
|
+
if (this.dataset.rpReady) return;
|
|
613
|
+
this.dataset.rpReady = "true";
|
|
614
|
+
const options = csv(this, "options", "选项 A,选项 B,选项 C");
|
|
615
|
+
const value = attr(this, "value", options[0] || "Select");
|
|
616
|
+
const label = attr(this, "label");
|
|
617
|
+
this.innerHTML = `${label ? `<span class="rp-field-label">${escapeHtml(label)}</span>` : ""}<span class="rp-select-control"><span class="rp-select-value">${escapeHtml(value)}</span>${icon("chevron-down")}</span><span class="rp-select-options">${options.map((o) => `<span class="rp-select-option${o === value ? " selected" : ""}">${escapeHtml(o)}</span>`).join("")}</span>`;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
class ButtonElement extends HTMLElement {
|
|
621
|
+
connectedCallback() {
|
|
622
|
+
var _a;
|
|
623
|
+
injectStyle();
|
|
624
|
+
if (this.dataset.rpReady) return;
|
|
625
|
+
this.dataset.rpReady = "true";
|
|
626
|
+
const label = attr(this, "label", ((_a = this.textContent) == null ? void 0 : _a.trim()) || "Button");
|
|
627
|
+
const ic = attr(this, "icon");
|
|
628
|
+
const loading = attr(this, "state") === "loading";
|
|
629
|
+
this.innerHTML = `${loading ? icon("loader") : ic ? icon(ic) : ""}<span>${escapeHtml(label)}</span>`;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
class CheckboxElement extends HTMLElement {
|
|
633
|
+
connectedCallback() {
|
|
634
|
+
injectStyle();
|
|
635
|
+
if (this.dataset.rpReady) return;
|
|
636
|
+
this.dataset.rpReady = "true";
|
|
637
|
+
const state = attr(this, "state");
|
|
638
|
+
const mark = state === "checked" ? icon("check", 12) : state === "indeterminate" ? icon("minus", 12) : "";
|
|
639
|
+
this.innerHTML = `<span class="rp-box">${mark}</span><span>${escapeHtml(attr(this, "label", ""))}</span>`;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
class RadioElement extends HTMLElement {
|
|
643
|
+
connectedCallback() {
|
|
644
|
+
injectStyle();
|
|
645
|
+
if (this.dataset.rpReady) return;
|
|
646
|
+
this.dataset.rpReady = "true";
|
|
647
|
+
const checked = attr(this, "state") === "checked";
|
|
648
|
+
this.innerHTML = `<span class="rp-box">${checked ? icon("circle", 8) : ""}</span><span>${escapeHtml(attr(this, "label", ""))}</span>`;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
class ToggleElement extends HTMLElement {
|
|
652
|
+
connectedCallback() {
|
|
653
|
+
injectStyle();
|
|
654
|
+
if (this.dataset.rpReady) return;
|
|
655
|
+
this.dataset.rpReady = "true";
|
|
656
|
+
this.innerHTML = `<span class="rp-toggle-track"><span class="rp-toggle-dot"></span></span><span>${escapeHtml(attr(this, "label", ""))}</span>`;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
class FormElement extends HTMLElement {
|
|
660
|
+
connectedCallback() {
|
|
661
|
+
injectStyle();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
class FormItemElement extends HTMLElement {
|
|
665
|
+
connectedCallback() {
|
|
666
|
+
injectStyle();
|
|
667
|
+
if (this.dataset.rpReady) return;
|
|
668
|
+
this.dataset.rpReady = "true";
|
|
669
|
+
const children = Array.from(this.childNodes);
|
|
670
|
+
const label = attr(this, "label");
|
|
671
|
+
const error = attr(this, "error");
|
|
672
|
+
this.innerHTML = `${label ? `<span class="rp-form-label${this.hasAttribute("required") ? " required" : ""}">${escapeHtml(label)}</span>` : ""}`;
|
|
673
|
+
children.forEach((n) => this.appendChild(n));
|
|
674
|
+
if (error) this.insertAdjacentHTML("beforeend", `<span class="rp-form-error">${escapeHtml(error)}</span>`);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
class DatePickerElement extends FieldElement {
|
|
678
|
+
fieldIcon() {
|
|
679
|
+
return icon("calendar");
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
class UploadElement extends HTMLElement {
|
|
683
|
+
connectedCallback() {
|
|
684
|
+
injectStyle();
|
|
685
|
+
if (this.dataset.rpReady) return;
|
|
686
|
+
this.dataset.rpReady = "true";
|
|
687
|
+
const state = attr(this, "state", "empty");
|
|
688
|
+
if (state === "has-file") this.innerHTML = `${icon("file")}<span>${escapeHtml(attr(this, "file", "document.pdf"))}</span>`;
|
|
689
|
+
else if (state === "uploading") this.innerHTML = `${icon("loader")}<span>上传中...</span><span class="rp-progress-bar" style="width:${escapeHtml(attr(this, "progress", "60"))}%"></span>`;
|
|
690
|
+
else this.innerHTML = `${icon("upload", 24)}<span>${escapeHtml(attr(this, "label", "点击或拖拽文件上传"))}</span>`;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
class ImagePlaceholderElement extends HTMLElement {
|
|
694
|
+
connectedCallback() {
|
|
695
|
+
injectStyle();
|
|
696
|
+
this.style.setProperty("--snap-width", `${attr(this, "width", "160")}px`);
|
|
697
|
+
this.style.setProperty("--snap-height", `${attr(this, "height", "100")}px`);
|
|
698
|
+
if (!this.innerHTML.trim()) this.innerHTML = `${icon("image")} ${escapeHtml(attr(this, "label", "Image"))}`;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
class ProgressElement extends HTMLElement {
|
|
702
|
+
connectedCallback() {
|
|
703
|
+
injectStyle();
|
|
704
|
+
if (this.dataset.rpReady) return;
|
|
705
|
+
this.dataset.rpReady = "true";
|
|
706
|
+
const value = attr(this, "value", "40");
|
|
707
|
+
this.style.setProperty("--progress", `${value}%`);
|
|
708
|
+
const kind = attr(this, "kind", attr(this, "style"));
|
|
709
|
+
this.innerHTML = kind === "circle" ? `${escapeHtml(value)}%` : '<span class="rp-progress-bar"></span>';
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
class BadgeElement extends HTMLElement {
|
|
713
|
+
connectedCallback() {
|
|
714
|
+
injectStyle();
|
|
715
|
+
const count = attr(this, "count", "0");
|
|
716
|
+
const max = intAttr(this, "max", 99);
|
|
717
|
+
const n = Number(count);
|
|
718
|
+
this.textContent = Number.isFinite(n) && n > max ? `${max}+` : count;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
class AvatarElement extends HTMLElement {
|
|
722
|
+
connectedCallback() {
|
|
723
|
+
var _a;
|
|
724
|
+
injectStyle();
|
|
725
|
+
const size = attr(this, "size", "32");
|
|
726
|
+
this.style.setProperty("--snap-size", `${size}px`);
|
|
727
|
+
if (!((_a = this.textContent) == null ? void 0 : _a.trim())) this.textContent = attr(this, "initials", "U");
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
class ListElement extends HTMLElement {
|
|
731
|
+
connectedCallback() {
|
|
732
|
+
injectStyle();
|
|
733
|
+
if (this.dataset.rpReady || this.children.length) return;
|
|
734
|
+
this.dataset.rpReady = "true";
|
|
735
|
+
const items = intAttr(this, "items", 3);
|
|
736
|
+
const state = attr(this, "state");
|
|
737
|
+
this.innerHTML = Array.from({ length: items }, (_, i) => `<snap-list-item label="${["全部", "未读", "@ 我", "已归档", "设置"][i] || `Item ${i + 1}`}" icon="${["inbox", "message-square", "at-sign", "archive", "settings"][i] || "file"}"${state === "first-selected" && i === 0 ? ' state="selected"' : ""}></snap-list-item>`).join("");
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
class ListItemElement extends HTMLElement {
|
|
741
|
+
connectedCallback() {
|
|
742
|
+
var _a;
|
|
743
|
+
injectStyle();
|
|
744
|
+
if (this.dataset.rpReady) return;
|
|
745
|
+
this.dataset.rpReady = "true";
|
|
746
|
+
const label = attr(this, "label", ((_a = this.textContent) == null ? void 0 : _a.trim()) || "Item");
|
|
747
|
+
const badge = attr(this, "badge");
|
|
748
|
+
const ic = attr(this, "icon");
|
|
749
|
+
this.innerHTML = `${ic ? icon(ic) : ""}<span class="rp-list-label">${escapeHtml(label)}</span>${badge ? `<span class="rp-list-badge">${escapeHtml(badge)}</span>` : ""}`;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
class TabsElement extends HTMLElement {
|
|
753
|
+
connectedCallback() {
|
|
754
|
+
injectStyle();
|
|
755
|
+
const active = attr(this, "active", "0");
|
|
756
|
+
const numeric = Number(active);
|
|
757
|
+
const children = Array.from(this.children);
|
|
758
|
+
children.forEach((child, i) => {
|
|
759
|
+
var _a;
|
|
760
|
+
const label = child.getAttribute("label") || ((_a = child.textContent) == null ? void 0 : _a.trim()) || "";
|
|
761
|
+
const isActive = Number.isFinite(numeric) ? i === numeric : label === active;
|
|
762
|
+
child.classList.toggle("rp-tab-active", isActive);
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
class TabElement extends HTMLElement {
|
|
767
|
+
connectedCallback() {
|
|
768
|
+
var _a;
|
|
769
|
+
injectStyle();
|
|
770
|
+
if (this.dataset.rpReady) return;
|
|
771
|
+
this.dataset.rpReady = "true";
|
|
772
|
+
const label = attr(this, "label", ((_a = this.textContent) == null ? void 0 : _a.trim()) || "Tab");
|
|
773
|
+
const badge = attr(this, "badge");
|
|
774
|
+
this.innerHTML = `<span>${escapeHtml(label)}</span>${badge ? `<span class="rp-list-badge">${escapeHtml(badge)}</span>` : ""}`;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
class PaginationElement extends HTMLElement {
|
|
778
|
+
connectedCallback() {
|
|
779
|
+
injectStyle();
|
|
780
|
+
if (this.dataset.rpReady) return;
|
|
781
|
+
this.dataset.rpReady = "true";
|
|
782
|
+
const total = intAttr(this, "total", 10);
|
|
783
|
+
const current = intAttr(this, "current", 1);
|
|
784
|
+
const pageSize = intAttr(this, "page-size", 10);
|
|
785
|
+
const pages = Math.max(1, Math.ceil(total / pageSize));
|
|
786
|
+
const visible = Array.from({ length: Math.min(pages, 5) }, (_, i) => i + 1);
|
|
787
|
+
this.innerHTML = `<span class="rp-page-btn">${icon("chevron-left", 14)}</span>${visible.map((p) => `<span class="rp-page-btn${p === current ? " active" : ""}">${p}</span>`).join("")}<span class="rp-page-btn">${icon("chevron-right", 14)}</span><span>共 ${total} 条</span>`;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
class StepsElement extends HTMLElement {
|
|
791
|
+
connectedCallback() {
|
|
792
|
+
injectStyle();
|
|
793
|
+
if (this.dataset.rpReady) return;
|
|
794
|
+
this.dataset.rpReady = "true";
|
|
795
|
+
const steps = csv(this, "steps", "步骤一,步骤二,步骤三");
|
|
796
|
+
const active = intAttr(this, "active", 0);
|
|
797
|
+
this.innerHTML = steps.map((s, i) => `<span class="rp-step ${i < active ? "done" : i === active ? "active" : ""}"><span class="rp-step-dot">${i < active ? icon("check", 12) : i + 1}</span>${escapeHtml(s)}</span>${i < steps.length - 1 ? '<span class="rp-step-sep"></span>' : ""}`).join("");
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
class BreadcrumbElement extends HTMLElement {
|
|
801
|
+
connectedCallback() {
|
|
802
|
+
injectStyle();
|
|
803
|
+
if (this.dataset.rpReady) return;
|
|
804
|
+
this.dataset.rpReady = "true";
|
|
805
|
+
const items = csv(this, "items", "首页,当前页");
|
|
806
|
+
this.innerHTML = items.map((item, i) => `<span class="${i === items.length - 1 ? "rp-breadcrumb-current" : ""}">${escapeHtml(item)}</span>${i < items.length - 1 ? "<span>/</span>" : ""}`).join("");
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function sampleCell(c, j, i) {
|
|
810
|
+
const lower = c.toLowerCase();
|
|
811
|
+
if (c.includes("发件") || lower.includes("name")) return ["张三", "李四", "系统通知", "运营助手", "王五", "安全团队"][i % 6];
|
|
812
|
+
if (c.includes("预览") || lower.includes("preview")) return ["请确认新的项目评审时间", "本周周报已发送", "你的账号存在新的登录", "活动报名已通过审核", "附件已更新", "安全策略变更提醒"][i % 6];
|
|
813
|
+
if (c.includes("时间") || lower.includes("time")) return ["09:12", "昨天", "周二", "5月30日", "5月28日", "5月20日"][i % 6];
|
|
814
|
+
if (c.includes("状态") || lower.includes("status")) return i % 2 ? "未读" : "已读";
|
|
815
|
+
return `Data ${i + 1}-${j + 1}`;
|
|
816
|
+
}
|
|
817
|
+
class TableElement extends HTMLElement {
|
|
818
|
+
connectedCallback() {
|
|
819
|
+
injectStyle();
|
|
820
|
+
if (this.dataset.rpReady) return;
|
|
821
|
+
this.dataset.rpReady = "true";
|
|
822
|
+
const cols = csv(this, "columns", "Name,Preview,Time,Status");
|
|
823
|
+
const rows = intAttr(this, "rows", 4);
|
|
824
|
+
const hasCheckbox = this.hasAttribute("has-checkbox");
|
|
825
|
+
const hasAction = this.hasAttribute("has-action");
|
|
826
|
+
const finalCols = hasAction ? [...cols, "操作"] : cols;
|
|
827
|
+
const headCells = `${hasCheckbox ? '<span class="rp-table-cell">✓</span>' : ""}${finalCols.map((c) => `<span class="rp-table-cell">${escapeHtml(c)}</span>`).join("")}`;
|
|
828
|
+
const body = Array.from({ length: rows }, (_, i) => `<div class="rp-table-row">${hasCheckbox ? `<span class="rp-table-cell"><span class="rp-box">${i === 1 ? icon("check", 12) : ""}</span></span>` : ""}${finalCols.map((c, j) => `<span class="rp-table-cell">${c === "操作" ? '<snap-button label="查看" variant="link"></snap-button>' : escapeHtml(sampleCell(c, j, i))}</span>`).join("")}</div>`).join("");
|
|
829
|
+
this.innerHTML = `<div class="rp-table-row rp-table-head">${headCells}</div>${body}`;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
class TableRowElement extends HTMLElement {
|
|
833
|
+
connectedCallback() {
|
|
834
|
+
injectStyle();
|
|
835
|
+
if (this.dataset.rpReady) return;
|
|
836
|
+
this.dataset.rpReady = "true";
|
|
837
|
+
this.innerHTML = `<span><span class="rp-box">${attr(this, "state") === "selected" ? icon("check", 12) : ""}</span></span><span>张三</span><span>消息内容预览文本</span><span>09:12</span><span>${escapeHtml(attr(this, "state", "default"))}</span>`;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
class BulkActionBarElement extends HTMLElement {
|
|
841
|
+
connectedCallback() {
|
|
842
|
+
injectStyle();
|
|
843
|
+
if (this.dataset.rpReady) return;
|
|
844
|
+
this.dataset.rpReady = "true";
|
|
845
|
+
const count = attr(this, "count", "1");
|
|
846
|
+
const actions = csv(this, "actions", "确认,取消");
|
|
847
|
+
this.innerHTML = `${icon("check")}<span>已选 ${escapeHtml(count)} 项</span>${actions.map((a) => `<snap-button label="${escapeHtml(a)}" variant="ghost"></snap-button>`).join("")}`;
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
class EmptyElement extends HTMLElement {
|
|
851
|
+
connectedCallback() {
|
|
852
|
+
injectStyle();
|
|
853
|
+
if (this.dataset.rpReady) return;
|
|
854
|
+
this.dataset.rpReady = "true";
|
|
855
|
+
this.innerHTML = `${icon("empty", 28)}<span class="rp-empty-title">${escapeHtml(attr(this, "label", "暂无数据"))}</span><span class="rp-empty-desc">${escapeHtml(attr(this, "description", ""))}</span>${this.hasAttribute("has-action") ? '<snap-button label="新建" variant="primary" icon="plus"></snap-button>' : ""}`;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
class LoadingElement extends HTMLElement {
|
|
859
|
+
connectedCallback() {
|
|
860
|
+
injectStyle();
|
|
861
|
+
if (this.dataset.rpReady) return;
|
|
862
|
+
this.dataset.rpReady = "true";
|
|
863
|
+
const rows = intAttr(this, "rows", 3);
|
|
864
|
+
this.innerHTML = attr(this, "kind") === "spinner" || attr(this, "style") === "spinner" ? `<span class="rp-spinner">${icon("loader", 24)}</span>` : Array.from({ length: rows }, (_, i) => `<span class="rp-skeleton-line" style="width:${220 - i * 24}px"></span>`).join("");
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
class AlertElement extends HTMLElement {
|
|
868
|
+
connectedCallback() {
|
|
869
|
+
injectStyle();
|
|
870
|
+
if (this.dataset.rpReady) return;
|
|
871
|
+
this.dataset.rpReady = "true";
|
|
872
|
+
const type = attr(this, "type", "info");
|
|
873
|
+
const title = attr(this, "title", type === "error" ? "错误" : "提示");
|
|
874
|
+
const message = attr(this, "message", "");
|
|
875
|
+
const ic = type === "error" ? "circle-alert" : type === "warning" ? "alert-triangle" : type === "success" ? "circle-check" : "info";
|
|
876
|
+
this.innerHTML = `${icon(ic)}<span><strong>${escapeHtml(title)}</strong>${message ? `<br>${escapeHtml(message)}` : ""}</span>${this.hasAttribute("closable") ? icon("x", 14) : ""}`;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
class OverlayElement extends HTMLElement {
|
|
880
|
+
connectedCallback() {
|
|
881
|
+
injectStyle();
|
|
882
|
+
if (this.dataset.rpReady) return;
|
|
883
|
+
this.dataset.rpReady = "true";
|
|
884
|
+
const children = Array.from(this.childNodes);
|
|
885
|
+
const title = attr(this, "title");
|
|
886
|
+
if (!title) return;
|
|
887
|
+
const head = document.createElement("div");
|
|
888
|
+
head.className = "rp-overlay-title";
|
|
889
|
+
head.textContent = title;
|
|
890
|
+
this.prepend(head);
|
|
891
|
+
children.forEach((n) => this.appendChild(n));
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
class TooltipElement extends HTMLElement {
|
|
895
|
+
connectedCallback() {
|
|
896
|
+
var _a;
|
|
897
|
+
injectStyle();
|
|
898
|
+
if (!((_a = this.textContent) == null ? void 0 : _a.trim())) this.textContent = attr(this, "text", "提示内容");
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
class ModalElement extends HTMLElement {
|
|
902
|
+
connectedCallback() {
|
|
903
|
+
injectStyle();
|
|
904
|
+
if (this.dataset.rpReady) return;
|
|
905
|
+
this.dataset.rpReady = "true";
|
|
906
|
+
this.style.setProperty("--snap-width", `${attr(this, "width", "480")}px`);
|
|
907
|
+
const children = Array.from(this.childNodes);
|
|
908
|
+
const body = document.createElement("div");
|
|
909
|
+
body.className = "rp-modal-body";
|
|
910
|
+
children.forEach((n) => body.appendChild(n));
|
|
911
|
+
this.innerHTML = `<div class="rp-modal-head"><span>${escapeHtml(attr(this, "title", "标题"))}</span>${icon("x", 14)}</div>`;
|
|
912
|
+
this.appendChild(body);
|
|
913
|
+
if (this.hasAttribute("has-footer")) this.insertAdjacentHTML("beforeend", '<div class="rp-modal-footer"><snap-button label="取消"></snap-button><snap-button label="确认" variant="primary"></snap-button></div>');
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
class DrawerElement extends HTMLElement {
|
|
917
|
+
connectedCallback() {
|
|
918
|
+
injectStyle();
|
|
919
|
+
if (this.dataset.rpReady) return;
|
|
920
|
+
this.dataset.rpReady = "true";
|
|
921
|
+
this.style.setProperty("--snap-width", `${attr(this, "width", "360")}px`);
|
|
922
|
+
const children = Array.from(this.childNodes);
|
|
923
|
+
const body = document.createElement("div");
|
|
924
|
+
body.className = "rp-drawer-body";
|
|
925
|
+
children.forEach((n) => body.appendChild(n));
|
|
926
|
+
this.innerHTML = `<div class="rp-drawer-head"><span>${escapeHtml(attr(this, "title", "抽屉"))}</span>${icon("x", 14)}</div>`;
|
|
927
|
+
this.appendChild(body);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
class CardElement extends HTMLElement {
|
|
931
|
+
connectedCallback() {
|
|
932
|
+
injectStyle();
|
|
933
|
+
if (this.dataset.rpReady) return;
|
|
934
|
+
this.dataset.rpReady = "true";
|
|
935
|
+
const children = Array.from(this.childNodes);
|
|
936
|
+
const title = attr(this, "title");
|
|
937
|
+
const subtitle = attr(this, "subtitle");
|
|
938
|
+
this.innerHTML = `${this.hasAttribute("has-image") ? `<span class="rp-card-image">${icon("image")} Image</span>` : ""}${title ? `<span class="rp-card-title">${escapeHtml(title)}</span>` : ""}${subtitle ? `<span class="rp-card-subtitle">${escapeHtml(subtitle)}</span>` : ""}`;
|
|
939
|
+
children.forEach((n) => this.appendChild(n));
|
|
940
|
+
if (this.hasAttribute("has-footer")) this.insertAdjacentHTML("beforeend", '<span class="rp-card-footer"><snap-button label="查看" variant="secondary"></snap-button></span>');
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
class StatCardElement extends HTMLElement {
|
|
944
|
+
connectedCallback() {
|
|
945
|
+
injectStyle();
|
|
946
|
+
if (this.dataset.rpReady) return;
|
|
947
|
+
this.dataset.rpReady = "true";
|
|
948
|
+
this.innerHTML = `<span class="rp-stat-label">${escapeHtml(attr(this, "label", "指标"))}</span><span class="rp-stat-value">${escapeHtml(attr(this, "value", "128"))}</span><span class="rp-stat-change">${escapeHtml(attr(this, "change", "0%"))}</span>`;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
class TagElement extends HTMLElement {
|
|
952
|
+
connectedCallback() {
|
|
953
|
+
var _a;
|
|
954
|
+
injectStyle();
|
|
955
|
+
if (this.dataset.rpReady) return;
|
|
956
|
+
this.dataset.rpReady = "true";
|
|
957
|
+
const label = attr(this, "label", ((_a = this.textContent) == null ? void 0 : _a.trim()) || "Tag");
|
|
958
|
+
this.innerHTML = `<span>${escapeHtml(label)}</span>${this.hasAttribute("closable") ? icon("x", 12) : ""}`;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
function registerAll() {
|
|
962
|
+
define("rp-page", RpPage);
|
|
963
|
+
define("proto-page", RpPage);
|
|
964
|
+
define("rp-main-view", RpMainView);
|
|
965
|
+
define("proto-main-view", RpMainView);
|
|
966
|
+
define("rp-annotation", RpAnnotation);
|
|
967
|
+
define("proto-annotation", RpAnnotation);
|
|
968
|
+
define("rp-enum", RpEnum);
|
|
969
|
+
define("proto-enum", RpEnum);
|
|
970
|
+
define("rp-enum-item", RpEnumItem);
|
|
971
|
+
define("proto-enum-item", RpEnumItem);
|
|
972
|
+
const pairs = [["viewport", ViewportElement], ["layout", LayoutElement], ["panel", PanelElement], ["navbar", NavbarElement], ["sidebar", SidebarElement], ["logo", LogoElement], ["search", FieldElement], ["input", FieldElement], ["textarea", TextareaElement], ["select", SelectElement], ["badge", BadgeElement], ["avatar", AvatarElement], ["list", ListElement], ["list-item", ListItemElement], ["tabs", TabsElement], ["tab", TabElement], ["button", ButtonElement], ["button-group", GenericElement], ["table", TableElement], ["table-row", TableRowElement], ["bulk-action-bar", BulkActionBarElement], ["empty", EmptyElement], ["loading", LoadingElement], ["alert", AlertElement], ["toast", AlertElement], ["dropdown", OverlayElement], ["popover", OverlayElement], ["tooltip", TooltipElement], ["modal", ModalElement], ["drawer", DrawerElement], ["card", CardElement], ["stat-card", StatCardElement], ["tag", TagElement], ["checkbox", CheckboxElement], ["radio", RadioElement], ["toggle", ToggleElement], ["form", FormElement], ["form-item", FormItemElement], ["date-picker", DatePickerElement], ["upload", UploadElement], ["image-placeholder", ImagePlaceholderElement], ["progress", ProgressElement], ["pagination", PaginationElement], ["steps", StepsElement], ["breadcrumb", BreadcrumbElement]];
|
|
973
|
+
for (const [suffix, ctor] of pairs) {
|
|
974
|
+
define(`snap-${suffix}`, ctor);
|
|
975
|
+
define(`rp-${suffix}`, ctor);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
registerAll();
|
|
979
|
+
export {
|
|
980
|
+
registerAll
|
|
981
|
+
};
|
|
982
|
+
//# sourceMappingURL=rpui.js.map
|