@dumiflex/wp-kit 0.6.0 → 0.7.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/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/src/BundlePreview.vue +255 -0
- package/src/CombinePreview.vue +151 -0
- package/src/ConstraintMatrixPreview.vue +6 -22
- package/src/ConstraintPreview.vue +260 -0
- package/src/DerivationCondition.vue +68 -0
- package/src/DerivationPreview.vue +346 -0
- package/src/FixedValuesPreview.vue +185 -0
- package/src/IconPicker.vue +31 -102
- package/src/IconPickerPanel.vue +132 -0
- package/src/LoadingMark.vue +6 -61
- package/src/PayloadPreview.vue +155 -0
- package/src/PostDetailSkeleton.vue +65 -0
- package/src/PostGridSkeleton.vue +61 -0
- package/src/PreviewGroup.vue +75 -0
- package/src/ProfileSkeleton.vue +73 -0
- package/src/RichText.vue +61 -0
- package/src/SelectionBar.vue +101 -0
- package/src/SettingGroup.vue +57 -0
- package/src/SettingRow.vue +127 -0
- package/src/WildcardPreview.vue +608 -0
- package/src/WorkingLine.vue +38 -124
- package/src/canvas-motion.ts +251 -0
- package/src/kind-colour.ts +24 -1
- package/src/linkify.ts +142 -0
- package/src/loading-mark-motion.ts +12 -155
- package/src/matrix-axis.ts +28 -0
- package/src/pi-icons.ts +51 -0
- package/src/preview-readers.ts +401 -0
- package/src/preview.css +197 -0
- package/src/tokens.ts +8 -2
- package/src/working-line-motion.ts +135 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defensive readers + parsers for published payloads. Pure (no Vue), shared
|
|
3
|
+
* by the per-type previews, the post header's feature pills and the bundle
|
|
4
|
+
* summary. A published payload is untrusted JSON, so every read tolerates a
|
|
5
|
+
* missing or mistyped field.
|
|
6
|
+
*/
|
|
7
|
+
import { tokenizeRich, type RichToken } from "./rich-tokenize";
|
|
8
|
+
|
|
9
|
+
export type Obj = Record<string, unknown>;
|
|
10
|
+
|
|
11
|
+
export function readString(obj: unknown, key: string): string | null {
|
|
12
|
+
if (!obj || typeof obj !== "object") return null;
|
|
13
|
+
const v = (obj as Obj)[key];
|
|
14
|
+
return typeof v === "string" ? v : null;
|
|
15
|
+
}
|
|
16
|
+
export function readNumber(obj: unknown, key: string): number | null {
|
|
17
|
+
if (!obj || typeof obj !== "object") return null;
|
|
18
|
+
const v = (obj as Obj)[key];
|
|
19
|
+
return typeof v === "number" ? v : null;
|
|
20
|
+
}
|
|
21
|
+
export function readArray(obj: unknown, key: string): unknown[] {
|
|
22
|
+
if (!obj || typeof obj !== "object") return [];
|
|
23
|
+
const v = (obj as Obj)[key];
|
|
24
|
+
return Array.isArray(v) ? v : [];
|
|
25
|
+
}
|
|
26
|
+
export function readObject(obj: unknown, key: string): Obj | null {
|
|
27
|
+
if (!obj || typeof obj !== "object") return null;
|
|
28
|
+
const v = (obj as Obj)[key];
|
|
29
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return null;
|
|
30
|
+
return v as Obj;
|
|
31
|
+
}
|
|
32
|
+
export function readStrings(obj: unknown, key: string): string[] {
|
|
33
|
+
return readArray(obj, key).filter((s): s is string => typeof s === "string");
|
|
34
|
+
}
|
|
35
|
+
/** Coerce a payload field into an axis map (`{axis: tag[]}`), keeping only
|
|
36
|
+
* string members. Null when absent or empty. */
|
|
37
|
+
export function readGroups(obj: unknown, key: string): Record<string, string[]> | null {
|
|
38
|
+
const raw = readObject(obj, key);
|
|
39
|
+
if (!raw) return null;
|
|
40
|
+
const out: Record<string, string[]> = {};
|
|
41
|
+
for (const [axis, members] of Object.entries(raw)) {
|
|
42
|
+
if (Array.isArray(members)) {
|
|
43
|
+
const tags = members.filter((m): m is string => typeof m === "string");
|
|
44
|
+
if (tags.length) out[axis] = tags;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return Object.keys(out).length ? out : null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Engine rows nest type fields under `payload`; older flat seeds don't. */
|
|
51
|
+
export function innerOf(payload: unknown): Obj | null {
|
|
52
|
+
return readObject(payload, "payload") ?? (payload && typeof payload === "object" ? (payload as Obj) : null);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Module type, or "bundle" for a bundle row (no `type`, has `children`). */
|
|
56
|
+
export function payloadKind(payload: unknown): string | null {
|
|
57
|
+
return readString(payload, "type") ?? (readArray(payload, "children").length ? "bundle" : null);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ─────────── grammar scanning ───────────
|
|
61
|
+
|
|
62
|
+
/** Every token in `text`, brace/multi arms included (depth-first). */
|
|
63
|
+
function allTokens(text: string): RichToken[] {
|
|
64
|
+
const out: RichToken[] = [];
|
|
65
|
+
const walk = (s: string): void => {
|
|
66
|
+
for (const t of tokenizeRich(s)) {
|
|
67
|
+
out.push(t);
|
|
68
|
+
for (const b of t.meta?.branches ?? []) walk(b);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
walk(text);
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
export interface TextScan {
|
|
75
|
+
vars: string[];
|
|
76
|
+
negVars: string[];
|
|
77
|
+
refs: number;
|
|
78
|
+
picks: number;
|
|
79
|
+
}
|
|
80
|
+
export function scanText(text: string): TextScan {
|
|
81
|
+
const vars: string[] = [];
|
|
82
|
+
const negVars: string[] = [];
|
|
83
|
+
let refs = 0;
|
|
84
|
+
let picks = 0;
|
|
85
|
+
for (const t of allTokens(text)) {
|
|
86
|
+
if (t.kind === "var" && t.meta?.name) {
|
|
87
|
+
(t.meta.neg ? negVars : vars).push(t.meta.name);
|
|
88
|
+
} else if (t.kind === "ref") refs++;
|
|
89
|
+
else if (t.kind === "dp-brace" || t.kind === "dp-multi") picks++;
|
|
90
|
+
}
|
|
91
|
+
return { vars, negVars, refs, picks };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ─────────── wildcard ───────────
|
|
95
|
+
|
|
96
|
+
export interface WildcardOption {
|
|
97
|
+
value: string;
|
|
98
|
+
weight: number;
|
|
99
|
+
/** Plural tag list (a legacy singular `sub_category` folds in). */
|
|
100
|
+
tags: string[];
|
|
101
|
+
negative: string;
|
|
102
|
+
/** Schema v9: rolls normally, and is also used when nothing else is left to pick. */
|
|
103
|
+
fallback: boolean;
|
|
104
|
+
}
|
|
105
|
+
export interface WildcardAxis {
|
|
106
|
+
name: string;
|
|
107
|
+
tags: string[];
|
|
108
|
+
}
|
|
109
|
+
export function wildcardOptions(inner: unknown): WildcardOption[] {
|
|
110
|
+
return readArray(inner, "options")
|
|
111
|
+
.map((r) => {
|
|
112
|
+
const tags = readStrings(r, "sub_categories");
|
|
113
|
+
const singular = readString(r, "sub_category");
|
|
114
|
+
return {
|
|
115
|
+
value: readString(r, "value") ?? "",
|
|
116
|
+
weight: readNumber(r, "weight") ?? 1,
|
|
117
|
+
tags: tags.length ? tags : singular ? [singular] : [],
|
|
118
|
+
negative: readString(r, "negative") ?? "",
|
|
119
|
+
fallback: !!r && typeof r === "object" && (r as Obj).fallback === true,
|
|
120
|
+
};
|
|
121
|
+
})
|
|
122
|
+
.filter((o) => o.value);
|
|
123
|
+
}
|
|
124
|
+
/** Axes from `tag_groups`; without them, one flat axis over the
|
|
125
|
+
* `sub_categories` registry (or none at all). */
|
|
126
|
+
export function wildcardAxes(inner: unknown): WildcardAxis[] {
|
|
127
|
+
const groups = readGroups(inner, "tag_groups");
|
|
128
|
+
if (groups) return Object.entries(groups).map(([name, tags]) => ({ name, tags }));
|
|
129
|
+
const flat = readStrings(inner, "sub_categories");
|
|
130
|
+
return flat.length ? [{ name: "tag", tags: flat }] : [];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ─────────── fixed values / combine ───────────
|
|
134
|
+
|
|
135
|
+
export interface FixedValue {
|
|
136
|
+
name: string;
|
|
137
|
+
value: string;
|
|
138
|
+
negative: string;
|
|
139
|
+
}
|
|
140
|
+
export function fixedValues(inner: unknown): FixedValue[] {
|
|
141
|
+
// Engine shape is `values: [{id, name, value}]`; `entries/variable_name`
|
|
142
|
+
// was a stale community guess kept only for old published data.
|
|
143
|
+
const rows = readArray(inner, "values").length ? readArray(inner, "values") : readArray(inner, "entries");
|
|
144
|
+
return rows.map((r) => ({
|
|
145
|
+
name: readString(r, "name") ?? readString(r, "variable_name") ?? "",
|
|
146
|
+
value: readString(r, "value") ?? "",
|
|
147
|
+
negative: readString(r, "negative") ?? "",
|
|
148
|
+
}));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// ─────────── derivation ───────────
|
|
152
|
+
|
|
153
|
+
export type ActionOp = "set" | "append" | "prepend" | "neg_add" | "neg_replace" | "other";
|
|
154
|
+
export interface DerivationAction {
|
|
155
|
+
target: string;
|
|
156
|
+
op: ActionOp;
|
|
157
|
+
/** Raw mode string, shown when the op is unknown. */
|
|
158
|
+
mode: string;
|
|
159
|
+
value: string;
|
|
160
|
+
}
|
|
161
|
+
export interface CondTest {
|
|
162
|
+
kind: "test";
|
|
163
|
+
var: string;
|
|
164
|
+
op: string;
|
|
165
|
+
value: string | null;
|
|
166
|
+
}
|
|
167
|
+
export interface CondGroup {
|
|
168
|
+
kind: "group";
|
|
169
|
+
match: "all" | "any";
|
|
170
|
+
conditions: Condition[];
|
|
171
|
+
}
|
|
172
|
+
export type Condition = CondTest | CondGroup;
|
|
173
|
+
export interface DerivationBranch {
|
|
174
|
+
condition: Condition | null;
|
|
175
|
+
actions: DerivationAction[];
|
|
176
|
+
}
|
|
177
|
+
export interface DerivationRule {
|
|
178
|
+
branches: DerivationBranch[];
|
|
179
|
+
fallback: DerivationAction[] | null;
|
|
180
|
+
}
|
|
181
|
+
/** Presence checks carry no value. */
|
|
182
|
+
const VALUELESS_OPS = new Set(["exists", "not_exists", "is_empty", "is_not_empty"]);
|
|
183
|
+
|
|
184
|
+
export function parseCondition(cond: unknown): Condition | null {
|
|
185
|
+
if (!cond || typeof cond !== "object") return null;
|
|
186
|
+
if ("conditions" in cond) {
|
|
187
|
+
const kids = readArray(cond, "conditions")
|
|
188
|
+
.map(parseCondition)
|
|
189
|
+
.filter((c): c is Condition => c !== null);
|
|
190
|
+
if (!kids.length) return null;
|
|
191
|
+
return { kind: "group", match: readString(cond, "match") === "any" ? "any" : "all", conditions: kids };
|
|
192
|
+
}
|
|
193
|
+
const op = readString(cond, "op") ?? "?";
|
|
194
|
+
const raw = (cond as Obj)["value"];
|
|
195
|
+
return {
|
|
196
|
+
kind: "test",
|
|
197
|
+
var: readString(cond, "var") ?? "?",
|
|
198
|
+
op,
|
|
199
|
+
value: VALUELESS_OPS.has(op) ? null : typeof raw === "string" ? raw : JSON.stringify(raw ?? ""),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function parseAction(action: unknown): DerivationAction {
|
|
203
|
+
const mode = readString(action, "mode") ?? "?";
|
|
204
|
+
const raw = (action as Obj | null)?.["value"];
|
|
205
|
+
const op: ActionOp =
|
|
206
|
+
mode === "replace"
|
|
207
|
+
? "set"
|
|
208
|
+
: mode === "append"
|
|
209
|
+
? "append"
|
|
210
|
+
: mode === "prepend"
|
|
211
|
+
? "prepend"
|
|
212
|
+
: mode === "negative"
|
|
213
|
+
? "neg_add"
|
|
214
|
+
: mode === "negative_replace"
|
|
215
|
+
? "neg_replace"
|
|
216
|
+
: "other";
|
|
217
|
+
return {
|
|
218
|
+
target: readString(action, "target_var") ?? "?",
|
|
219
|
+
op,
|
|
220
|
+
mode,
|
|
221
|
+
value: typeof raw === "string" ? raw : JSON.stringify(raw ?? ""),
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
/** `action` then every `extra_actions` entry, in order (schema v8). Mirrors
|
|
225
|
+
* the engine's `clause_actions`; never read `.action` alone. */
|
|
226
|
+
export function clauseActions(clause: unknown): DerivationAction[] {
|
|
227
|
+
const out: DerivationAction[] = [];
|
|
228
|
+
const first = readObject(clause, "action");
|
|
229
|
+
if (first) out.push(parseAction(first));
|
|
230
|
+
for (const extra of readArray(clause, "extra_actions")) {
|
|
231
|
+
if (extra && typeof extra === "object") out.push(parseAction(extra));
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
export function derivationRules(inner: unknown): DerivationRule[] {
|
|
236
|
+
return readArray(inner, "rules").map((rule) => {
|
|
237
|
+
const elseClause = readObject(rule, "else");
|
|
238
|
+
return {
|
|
239
|
+
branches: readArray(rule, "branches").map((b) => ({
|
|
240
|
+
condition: parseCondition(readObject(b, "condition")),
|
|
241
|
+
actions: clauseActions(b),
|
|
242
|
+
})),
|
|
243
|
+
fallback: elseClause ? clauseActions(elseClause) : null,
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
export function conditionVars(c: Condition | null, out: string[] = []): string[] {
|
|
248
|
+
if (!c) return out;
|
|
249
|
+
if (c.kind === "test") out.push(c.var);
|
|
250
|
+
else for (const k of c.conditions) conditionVars(k, out);
|
|
251
|
+
return out;
|
|
252
|
+
}
|
|
253
|
+
export function hasGroups(c: Condition | null): boolean {
|
|
254
|
+
return c?.kind === "group";
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ─────────── variables in / out ───────────
|
|
258
|
+
|
|
259
|
+
export interface VarFlow {
|
|
260
|
+
/** Variables this payload sets (value writes). */
|
|
261
|
+
sets: string[];
|
|
262
|
+
/** Variables it reads. */
|
|
263
|
+
reads: string[];
|
|
264
|
+
/** Variables whose negatives it touches. */
|
|
265
|
+
negatives: string[];
|
|
266
|
+
}
|
|
267
|
+
function uniq(xs: string[]): string[] {
|
|
268
|
+
return [...new Set(xs.filter(Boolean))];
|
|
269
|
+
}
|
|
270
|
+
/** What one module sets / reads. Bundles fold their children. */
|
|
271
|
+
export function varFlow(payload: unknown): VarFlow {
|
|
272
|
+
const kind = payloadKind(payload);
|
|
273
|
+
if (kind === "bundle") {
|
|
274
|
+
const flows = readArray(payload, "children")
|
|
275
|
+
.filter((c) => (c as Obj | null)?.["enabled"] !== false)
|
|
276
|
+
.map(varFlow);
|
|
277
|
+
return {
|
|
278
|
+
sets: uniq(flows.flatMap((f) => f.sets)),
|
|
279
|
+
reads: uniq(flows.flatMap((f) => f.reads)),
|
|
280
|
+
negatives: uniq(flows.flatMap((f) => f.negatives)),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
const inner = innerOf(payload);
|
|
284
|
+
const sets: string[] = [];
|
|
285
|
+
const reads: string[] = [];
|
|
286
|
+
const negatives: string[] = [];
|
|
287
|
+
const readText = (t: string): void => {
|
|
288
|
+
const s = scanText(t);
|
|
289
|
+
reads.push(...s.vars, ...s.negVars);
|
|
290
|
+
};
|
|
291
|
+
if (kind === "wildcard") {
|
|
292
|
+
const b = readString(inner, "var_binding");
|
|
293
|
+
if (b) sets.push(b);
|
|
294
|
+
for (const o of wildcardOptions(inner)) {
|
|
295
|
+
readText(o.value);
|
|
296
|
+
if (o.negative) {
|
|
297
|
+
readText(o.negative);
|
|
298
|
+
if (b) negatives.push(b);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} else if (kind === "fixed_values") {
|
|
302
|
+
for (const v of fixedValues(inner)) {
|
|
303
|
+
sets.push(v.name);
|
|
304
|
+
readText(v.value);
|
|
305
|
+
if (v.negative) negatives.push(v.name);
|
|
306
|
+
}
|
|
307
|
+
} else if (kind === "combine") {
|
|
308
|
+
const out = readString(inner, "output_var");
|
|
309
|
+
if (out) sets.push(out);
|
|
310
|
+
reads.push(...readStrings(inner, "input_vars"));
|
|
311
|
+
readText(readString(inner, "template") ?? "");
|
|
312
|
+
const neg = readString(inner, "negative") ?? "";
|
|
313
|
+
if (neg) {
|
|
314
|
+
readText(neg);
|
|
315
|
+
if (out) negatives.push(out);
|
|
316
|
+
}
|
|
317
|
+
} else if (kind === "derivation") {
|
|
318
|
+
for (const r of derivationRules(inner)) {
|
|
319
|
+
const clauses = [...r.branches.map((b) => b.actions), ...(r.fallback ? [r.fallback] : [])];
|
|
320
|
+
for (const b of r.branches) reads.push(...conditionVars(b.condition));
|
|
321
|
+
for (const a of clauses.flat()) {
|
|
322
|
+
readText(a.value);
|
|
323
|
+
if (a.op === "neg_add" || a.op === "neg_replace") negatives.push(a.target);
|
|
324
|
+
else sets.push(a.target);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return { sets: uniq(sets), reads: uniq(reads), negatives: uniq(negatives) };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ─────────── feature pills ───────────
|
|
332
|
+
|
|
333
|
+
/** Short labels for the notable features a payload uses, shown as pills in
|
|
334
|
+
* the post header. Order is stable (most notable first). */
|
|
335
|
+
export function payloadFeatures(payload: unknown): string[] {
|
|
336
|
+
const kind = payloadKind(payload);
|
|
337
|
+
const found = new Set<string>();
|
|
338
|
+
const addText = (t: string): void => {
|
|
339
|
+
const s = scanText(t);
|
|
340
|
+
if (s.refs) found.add("@refs");
|
|
341
|
+
if (s.picks) found.add("picks");
|
|
342
|
+
if (s.negVars.length) found.add("$var.neg");
|
|
343
|
+
};
|
|
344
|
+
const visit = (p: unknown): void => {
|
|
345
|
+
const k = payloadKind(p);
|
|
346
|
+
const inner = innerOf(p);
|
|
347
|
+
if (k === "wildcard") {
|
|
348
|
+
if (readGroups(inner, "tag_groups")) found.add("tag axes");
|
|
349
|
+
for (const o of wildcardOptions(inner)) {
|
|
350
|
+
addText(o.value);
|
|
351
|
+
if (o.weight !== 1) found.add("weights");
|
|
352
|
+
if (o.negative) {
|
|
353
|
+
found.add("negatives");
|
|
354
|
+
addText(o.negative);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
} else if (k === "fixed_values") {
|
|
358
|
+
for (const v of fixedValues(inner)) {
|
|
359
|
+
addText(v.value);
|
|
360
|
+
if (v.negative) found.add("negatives");
|
|
361
|
+
}
|
|
362
|
+
} else if (k === "combine") {
|
|
363
|
+
addText(readString(inner, "template") ?? "");
|
|
364
|
+
const neg = readString(inner, "negative");
|
|
365
|
+
if (neg) {
|
|
366
|
+
found.add("negatives");
|
|
367
|
+
addText(neg);
|
|
368
|
+
}
|
|
369
|
+
} else if (k === "derivation") {
|
|
370
|
+
for (const r of derivationRules(inner)) {
|
|
371
|
+
const clauses = [...r.branches.map((b) => b.actions), ...(r.fallback ? [r.fallback] : [])];
|
|
372
|
+
if (r.branches.some((b) => hasGroups(b.condition))) found.add("AND / OR");
|
|
373
|
+
if (clauses.some((c) => c.length > 1)) found.add("multi-action");
|
|
374
|
+
for (const a of clauses.flat()) {
|
|
375
|
+
addText(a.value);
|
|
376
|
+
if (a.op === "neg_add" || a.op === "neg_replace") found.add("negatives");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
} else if (k === "constraint") {
|
|
380
|
+
const matrix = readObject(inner, "matrix") ?? {};
|
|
381
|
+
const onlyUsed =
|
|
382
|
+
Object.values(matrix).some((row) =>
|
|
383
|
+
Object.values((row as Obj) ?? {}).some((c) => readString(c, "mode") === "only"),
|
|
384
|
+
) || readArray(inner, "exceptions").some((e) => readString(e, "mode") === "only");
|
|
385
|
+
if (onlyUsed) found.add("only rule");
|
|
386
|
+
const sel = readObject(inner, "target_select");
|
|
387
|
+
const mode = readString(sel, "mode");
|
|
388
|
+
if (mode && mode !== "all") {
|
|
389
|
+
const count = readNumber(sel, "count");
|
|
390
|
+
found.add(`reach: ${mode}${count !== null ? ` ${count}` : ""}`);
|
|
391
|
+
}
|
|
392
|
+
} else if (k === "bundle") {
|
|
393
|
+
for (const c of readArray(p, "children")) visit(c);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
visit(payload);
|
|
397
|
+
const order = ["tag axes", "weights", "negatives", "$var.neg", "AND / OR", "multi-action", "only rule", "@refs", "picks"];
|
|
398
|
+
const sorted = order.filter((f) => found.has(f));
|
|
399
|
+
for (const f of found) if (!order.includes(f)) sorted.push(f);
|
|
400
|
+
return kind ? sorted : [];
|
|
401
|
+
}
|
package/src/preview.css
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/* Shared chrome for the per-type payload previews (stats strip, toolbar,
|
|
2
|
+
row tables, section labels). Every preview imports it from its script
|
|
3
|
+
(`import "./preview.css"`), so a page carries ONE copy however many
|
|
4
|
+
previews it shows; pulled in scoped, each piece got its own copy (seven in
|
|
5
|
+
the community embed). Every selector is `.wp-pv-*`, so it is safe global.
|
|
6
|
+
Unlayered like button.css and menu.css: in @layer wp-extension a host's
|
|
7
|
+
unlayered reset (Tailwind's preflight) would strip its borders. */
|
|
8
|
+
|
|
9
|
+
.wp-pv {
|
|
10
|
+
container-type: inline-size;
|
|
11
|
+
min-width: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* ── stats strip ─────────────────────────────────────────────── */
|
|
15
|
+
.wp-pv-stats {
|
|
16
|
+
display: flex;
|
|
17
|
+
flex-wrap: wrap;
|
|
18
|
+
border-bottom: 1px solid var(--wp-border);
|
|
19
|
+
}
|
|
20
|
+
.wp-pv-stat {
|
|
21
|
+
padding: 12px 18px;
|
|
22
|
+
border-right: 1px solid var(--wp-border);
|
|
23
|
+
min-width: 0;
|
|
24
|
+
}
|
|
25
|
+
.wp-pv-stat b {
|
|
26
|
+
display: block;
|
|
27
|
+
font-size: 17px;
|
|
28
|
+
font-weight: 600;
|
|
29
|
+
color: var(--wp-text);
|
|
30
|
+
font-variant-numeric: tabular-nums;
|
|
31
|
+
white-space: nowrap;
|
|
32
|
+
}
|
|
33
|
+
.wp-pv-stat span {
|
|
34
|
+
font-size: 11.5px;
|
|
35
|
+
color: var(--wp-text-muted);
|
|
36
|
+
white-space: nowrap;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ── toolbar ─────────────────────────────────────────────────── */
|
|
40
|
+
.wp-pv-tool {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
flex-wrap: wrap;
|
|
44
|
+
gap: 8px 10px;
|
|
45
|
+
padding: 12px 16px;
|
|
46
|
+
border-bottom: 1px solid var(--wp-border);
|
|
47
|
+
}
|
|
48
|
+
.wp-pv-search {
|
|
49
|
+
width: 220px;
|
|
50
|
+
max-width: 100%;
|
|
51
|
+
}
|
|
52
|
+
.wp-pv-label {
|
|
53
|
+
font-size: 10.5px;
|
|
54
|
+
color: var(--wp-text-dim);
|
|
55
|
+
text-transform: uppercase;
|
|
56
|
+
letter-spacing: 0.05em;
|
|
57
|
+
}
|
|
58
|
+
.wp-pv-tool__end {
|
|
59
|
+
margin-left: auto;
|
|
60
|
+
}
|
|
61
|
+
.wp-pv-count {
|
|
62
|
+
font-size: 12px;
|
|
63
|
+
color: var(--wp-text-muted);
|
|
64
|
+
font-variant-numeric: tabular-nums;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* ── row tables ──────────────────────────────────────────────── */
|
|
68
|
+
.wp-pv-table {
|
|
69
|
+
width: 100%;
|
|
70
|
+
border-collapse: collapse;
|
|
71
|
+
table-layout: fixed;
|
|
72
|
+
}
|
|
73
|
+
.wp-pv-table th,
|
|
74
|
+
.wp-pv-table td {
|
|
75
|
+
padding: 7px 12px;
|
|
76
|
+
border-bottom: 1px solid var(--wp-border);
|
|
77
|
+
text-align: left;
|
|
78
|
+
vertical-align: top;
|
|
79
|
+
}
|
|
80
|
+
.wp-pv-table th {
|
|
81
|
+
font-size: 10.5px;
|
|
82
|
+
font-weight: 500;
|
|
83
|
+
color: var(--wp-text-dim);
|
|
84
|
+
text-transform: uppercase;
|
|
85
|
+
letter-spacing: 0.05em;
|
|
86
|
+
padding-top: 8px;
|
|
87
|
+
padding-bottom: 6px;
|
|
88
|
+
}
|
|
89
|
+
.wp-pv-table td {
|
|
90
|
+
font-size: 13px;
|
|
91
|
+
color: var(--wp-text);
|
|
92
|
+
line-height: 1.5;
|
|
93
|
+
overflow-wrap: anywhere;
|
|
94
|
+
}
|
|
95
|
+
.wp-pv-col-n {
|
|
96
|
+
width: 40px;
|
|
97
|
+
}
|
|
98
|
+
.wp-pv-table .wp-pv-n {
|
|
99
|
+
width: 40px;
|
|
100
|
+
text-align: right;
|
|
101
|
+
color: var(--wp-text-dim);
|
|
102
|
+
font-family: var(--wp-font-mono);
|
|
103
|
+
font-size: 11px;
|
|
104
|
+
}
|
|
105
|
+
.wp-pv-table .wp-pv-var {
|
|
106
|
+
font-family: var(--wp-font-mono);
|
|
107
|
+
font-size: 12px;
|
|
108
|
+
color: var(--wp-success);
|
|
109
|
+
}
|
|
110
|
+
.wp-pv-neg-cell {
|
|
111
|
+
color: var(--wp-danger-text, var(--wp-danger));
|
|
112
|
+
font-size: 12px;
|
|
113
|
+
}
|
|
114
|
+
.wp-pv-clamp {
|
|
115
|
+
display: -webkit-box;
|
|
116
|
+
-webkit-line-clamp: 2;
|
|
117
|
+
-webkit-box-orient: vertical;
|
|
118
|
+
overflow: hidden;
|
|
119
|
+
}
|
|
120
|
+
.wp-pv-more {
|
|
121
|
+
padding: 4px 12px;
|
|
122
|
+
border-bottom: 1px solid var(--wp-border);
|
|
123
|
+
}
|
|
124
|
+
.wp-pv-empty {
|
|
125
|
+
margin: 0;
|
|
126
|
+
padding: 18px 16px;
|
|
127
|
+
color: var(--wp-text-muted);
|
|
128
|
+
font-size: 13px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/* Wildcard fallback option (schema v9): rolls normally, also stands in. */
|
|
132
|
+
.wp-pv-fbtag {
|
|
133
|
+
font-family: var(--wp-font-mono);
|
|
134
|
+
font-size: 10px;
|
|
135
|
+
font-weight: 700;
|
|
136
|
+
letter-spacing: 0.04em;
|
|
137
|
+
padding: 1px 6px;
|
|
138
|
+
border-radius: min(3px, var(--wp-radius-cap, 999px));
|
|
139
|
+
background: color-mix(in oklab, var(--wp-accent-500) 18%, transparent);
|
|
140
|
+
color: var(--wp-accent-text);
|
|
141
|
+
white-space: nowrap;
|
|
142
|
+
}
|
|
143
|
+
/* NEG tag, shared by every negative cell / block. */
|
|
144
|
+
.wp-pv-negtag {
|
|
145
|
+
font-family: var(--wp-font-mono);
|
|
146
|
+
font-size: 9px;
|
|
147
|
+
font-weight: 700;
|
|
148
|
+
letter-spacing: 0.06em;
|
|
149
|
+
padding: 0 4px;
|
|
150
|
+
margin-right: 5px;
|
|
151
|
+
border-radius: min(3px, var(--wp-radius-cap, 999px));
|
|
152
|
+
background: color-mix(in oklab, var(--wp-danger) 18%, transparent);
|
|
153
|
+
color: var(--wp-danger-text, var(--wp-danger));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* ── section label + text block ──────────────────────────────── */
|
|
157
|
+
.wp-pv-sec {
|
|
158
|
+
padding: 14px 16px 6px;
|
|
159
|
+
font-size: 10.5px;
|
|
160
|
+
color: var(--wp-text-dim);
|
|
161
|
+
text-transform: uppercase;
|
|
162
|
+
letter-spacing: 0.05em;
|
|
163
|
+
}
|
|
164
|
+
.wp-pv-block {
|
|
165
|
+
margin: 0 16px 4px;
|
|
166
|
+
padding: 12px 14px;
|
|
167
|
+
background: var(--wp-bg-2);
|
|
168
|
+
border: 1px solid var(--wp-border);
|
|
169
|
+
border-radius: min(10px, var(--wp-radius-cap, 999px));
|
|
170
|
+
font-family: var(--wp-font-mono);
|
|
171
|
+
font-size: 13px;
|
|
172
|
+
line-height: 1.9;
|
|
173
|
+
color: var(--wp-text);
|
|
174
|
+
overflow-wrap: anywhere;
|
|
175
|
+
}
|
|
176
|
+
.wp-pv-block--neg {
|
|
177
|
+
border-color: color-mix(in oklab, var(--wp-danger) 28%, transparent);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Narrow hosts (embed, phones): drop secondary columns. */
|
|
181
|
+
@container (max-width: 640px) {
|
|
182
|
+
.wp-pv-hide-narrow {
|
|
183
|
+
display: none;
|
|
184
|
+
}
|
|
185
|
+
.wp-pv-stat {
|
|
186
|
+
padding: 10px 12px;
|
|
187
|
+
}
|
|
188
|
+
.wp-pv-table td,
|
|
189
|
+
.wp-pv-table th {
|
|
190
|
+
padding-left: 8px;
|
|
191
|
+
padding-right: 8px;
|
|
192
|
+
}
|
|
193
|
+
.wp-pv-col-n,
|
|
194
|
+
.wp-pv-table .wp-pv-n {
|
|
195
|
+
width: 28px;
|
|
196
|
+
}
|
|
197
|
+
}
|
package/src/tokens.ts
CHANGED
|
@@ -50,12 +50,18 @@ export const LOCAL_TOKENS = ["--wp-hsv-hue", "--wp-lm-o", "--wp-select-line-h",
|
|
|
50
50
|
"--wp-wl-t", "--wp-wl-k", "--wp-wl-x", "--wp-wl-f", "--wp-wl-r", "--wp-wl-s", "--wp-wl-o", "--wp-wl-wo", "--wp-wl-wb",
|
|
51
51
|
"--wp-wl-dx", "--wp-wl-dy", "--wp-wl-big", "--wp-wl-a", "--wp-wl-b",
|
|
52
52
|
// motion.css entrances.
|
|
53
|
-
"--wp-enter-o", "--wp-enter-s", "--wp-enter-y", "--wp-enter-x"
|
|
53
|
+
"--wp-enter-o", "--wp-enter-s", "--wp-enter-y", "--wp-enter-x",
|
|
54
|
+
// SelectionBar: where a sticky bar stops under a fixed header.
|
|
55
|
+
"--wp-selection-bar-top"] as const;
|
|
54
56
|
|
|
55
57
|
/** Pieces that need a page with src/theme/ loaded (not the canvas). */
|
|
56
58
|
export const PAGE_PIECES = [
|
|
57
59
|
"axis-color.ts", "kind-colour.ts", "matrix-axis.ts", "BundleMeta.vue", "ConstraintMatrixPreview.vue", "PostCard.vue", "TokenizedValue.vue",
|
|
58
60
|
"Card.vue", "Chip.vue", "ChoiceCards.vue",
|
|
59
|
-
"DataTable.vue", "Drawer.vue", "EmptyState.vue", "Field.vue", "Icon.vue", "
|
|
61
|
+
"DataTable.vue", "Drawer.vue", "EmptyState.vue", "Field.vue", "Icon.vue", "Input.vue",
|
|
60
62
|
"ListFilter.vue", "RelativeDate.vue", "Select.vue", "Textarea.vue", "ToastHost.vue",
|
|
63
|
+
// The payload previews and post loading shapes (community post pages).
|
|
64
|
+
"PayloadPreview.vue", "WildcardPreview.vue", "FixedValuesPreview.vue", "CombinePreview.vue", "DerivationPreview.vue",
|
|
65
|
+
"DerivationCondition.vue", "ConstraintPreview.vue", "BundlePreview.vue", "PreviewGroup.vue", "preview.css", "RichText.vue",
|
|
66
|
+
"PostGridSkeleton.vue", "PostDetailSkeleton.vue", "ProfileSkeleton.vue",
|
|
61
67
|
] as const;
|