@proto-labs-inc/wire 0.1.0 → 0.2.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/dist/index.d.ts +64 -12
- package/dist/index.js +66 -9
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const PROTOCOL_VERSION =
|
|
1
|
+
export declare const PROTOCOL_VERSION = 3;
|
|
2
2
|
export type ResolvedPreviewTheme = "light" | "dark";
|
|
3
3
|
export interface StateDef {
|
|
4
4
|
id: string;
|
|
@@ -57,18 +57,28 @@ export interface ReferenceDef {
|
|
|
57
57
|
variant?: string;
|
|
58
58
|
}
|
|
59
59
|
export interface VariantSetDef {
|
|
60
|
-
/**
|
|
60
|
+
/** Stable identity for this creation. Older manifests use component as their identity. */
|
|
61
|
+
id?: string;
|
|
62
|
+
/** Unique set address used by the rig, independent of the display title and selected element. */
|
|
61
63
|
component: string;
|
|
64
|
+
/** This set applies only while this variant in another set is active. */
|
|
65
|
+
requires?: {
|
|
66
|
+
component: string;
|
|
67
|
+
variant: string;
|
|
68
|
+
};
|
|
62
69
|
title?: string;
|
|
63
70
|
/** temporary lifecycle state while an agent is creating the variant set */
|
|
64
71
|
status?: "building";
|
|
65
72
|
variants: VariantDef[];
|
|
66
|
-
/**
|
|
73
|
+
/** Variant id the prototype's code defaults to; empty for a references-only set. */
|
|
67
74
|
default: string;
|
|
68
75
|
/** preview-state id that showcases this variant set (used by previews) */
|
|
69
76
|
state?: string;
|
|
70
77
|
/** variant id that is the pre-variant-set original — pinned last, badged ORIGINAL */
|
|
71
78
|
baseline?: string;
|
|
79
|
+
/** Marked page regions the set changes, independent of its rig address.
|
|
80
|
+
* A decision across the top bar and a notice is one set. */
|
|
81
|
+
regions?: string[];
|
|
72
82
|
/** overview copy shown at the bottom of the variants panel */
|
|
73
83
|
overview?: {
|
|
74
84
|
title?: string;
|
|
@@ -78,6 +88,8 @@ export interface VariantSetDef {
|
|
|
78
88
|
}
|
|
79
89
|
export interface Manifest {
|
|
80
90
|
schemaVersion: 2;
|
|
91
|
+
/** Trusted Frame app origin, configured by the workspace owner. */
|
|
92
|
+
frameOrigin?: string;
|
|
81
93
|
/** the slug */
|
|
82
94
|
name: string;
|
|
83
95
|
port: number;
|
|
@@ -85,9 +97,31 @@ export interface Manifest {
|
|
|
85
97
|
states: StateDef[];
|
|
86
98
|
variantSets: VariantSetDef[];
|
|
87
99
|
prPlan?: PrPlanDef;
|
|
100
|
+
/** The width (and height) the page was copied at, when the copy only
|
|
101
|
+
* lays out right there (a frozen page): the Frame draws it at this
|
|
102
|
+
* width and scales it down when the area is narrower. */
|
|
103
|
+
viewport?: {
|
|
104
|
+
width: number;
|
|
105
|
+
height: number;
|
|
106
|
+
/** the narrowest width it still lays out at without spilling sideways:
|
|
107
|
+
* the Frame re-flows it down to here and scales it only below */
|
|
108
|
+
minWidth?: number;
|
|
109
|
+
};
|
|
88
110
|
}
|
|
89
111
|
export declare const STATE_PARAM = "state";
|
|
90
112
|
export declare const variantParam: (component: string) => string;
|
|
113
|
+
/** Required ancestors, outermost first. Invalid references and cycles fail closed. */
|
|
114
|
+
export declare function variantSetRequirements(sets: VariantSetDef[], component: string): Array<{
|
|
115
|
+
component: string;
|
|
116
|
+
variant: string;
|
|
117
|
+
}> | null;
|
|
118
|
+
export declare function isVariantSetApplicable(sets: VariantSetDef[], component: string, params: URLSearchParams): boolean;
|
|
119
|
+
/** Apply a selection and its ancestors together, preserving dormant child choices. */
|
|
120
|
+
export declare function applyVariantSelection(sets: VariantSetDef[], params: URLSearchParams, component: string, variant: string): boolean;
|
|
121
|
+
/** CSS properties exposed by the annotation inspector. */
|
|
122
|
+
export declare const ELEMENT_STYLE_PROPERTIES: readonly ["color", "background-color", "opacity", "font-family", "font-size", "font-weight", "line-height", "letter-spacing", "padding-top", "padding-right", "padding-bottom", "padding-left", "border-radius", "gap"];
|
|
123
|
+
export type ElementStyleProperty = typeof ELEMENT_STYLE_PROPERTIES[number];
|
|
124
|
+
export type ElementStyles = Partial<Record<ElementStyleProperty, string>>;
|
|
91
125
|
export type FrameToRig = {
|
|
92
126
|
type: "set-state";
|
|
93
127
|
id: string;
|
|
@@ -100,10 +134,10 @@ export type FrameToRig = {
|
|
|
100
134
|
variant: string;
|
|
101
135
|
} | {
|
|
102
136
|
type: "focus-target";
|
|
103
|
-
|
|
137
|
+
selector: string | null;
|
|
104
138
|
} | {
|
|
105
139
|
type: "measure-target";
|
|
106
|
-
|
|
140
|
+
selector: string;
|
|
107
141
|
} | {
|
|
108
142
|
type: "set-comment-mode";
|
|
109
143
|
on: boolean;
|
|
@@ -116,6 +150,13 @@ export type FrameToRig = {
|
|
|
116
150
|
} | {
|
|
117
151
|
type: "set-element-picker";
|
|
118
152
|
on: boolean;
|
|
153
|
+
} | {
|
|
154
|
+
type: "preview-element-styles";
|
|
155
|
+
selectionId: string;
|
|
156
|
+
styles: ElementStyles;
|
|
157
|
+
} | {
|
|
158
|
+
type: "release-element";
|
|
159
|
+
selectionId: string;
|
|
119
160
|
};
|
|
120
161
|
export interface CommentAnchor {
|
|
121
162
|
/** Bounds of the selected component in the prototype viewport. */
|
|
@@ -125,6 +166,9 @@ export interface CommentAnchor {
|
|
|
125
166
|
height: number;
|
|
126
167
|
}
|
|
127
168
|
export type RigToFrame = {
|
|
169
|
+
type: "frame-tools-status";
|
|
170
|
+
status: "loading" | "ready" | "unavailable";
|
|
171
|
+
} | {
|
|
128
172
|
type: "hello";
|
|
129
173
|
protocolVersion: number;
|
|
130
174
|
rigVersion: string;
|
|
@@ -136,14 +180,14 @@ export type RigToFrame = {
|
|
|
136
180
|
search: string;
|
|
137
181
|
} | {
|
|
138
182
|
type: "comment-target-picked";
|
|
139
|
-
/**
|
|
140
|
-
|
|
183
|
+
/** CSS selector for the exact selected element. */
|
|
184
|
+
selector: string;
|
|
141
185
|
/** Used by the Frame to place the composer beside the selection. */
|
|
142
186
|
anchor: CommentAnchor;
|
|
143
187
|
} | {
|
|
144
188
|
type: "comment-capture";
|
|
145
|
-
/**
|
|
146
|
-
|
|
189
|
+
/** CSS selector for the exact selected element. */
|
|
190
|
+
selector: string;
|
|
147
191
|
/** PNG data URL with the highlight composited in; null if capture failed
|
|
148
192
|
(e.g. modern-screenshot not installed) — the comment still works */
|
|
149
193
|
image: string | null;
|
|
@@ -165,18 +209,22 @@ export type RigToFrame = {
|
|
|
165
209
|
type: "target-focus-dismissed";
|
|
166
210
|
} | {
|
|
167
211
|
type: "target-measured";
|
|
168
|
-
|
|
169
|
-
/** Null when no matching
|
|
212
|
+
selector: string;
|
|
213
|
+
/** Null when no matching element exists in the current state. */
|
|
170
214
|
anchor: CommentAnchor | null;
|
|
171
215
|
} | {
|
|
172
216
|
type: "variant-set-target-picked";
|
|
173
|
-
|
|
217
|
+
selector: string;
|
|
174
218
|
/** Used by the Frame to place the variant-set brief beside the selection. */
|
|
175
219
|
anchor: CommentAnchor;
|
|
176
220
|
} | {
|
|
177
221
|
type: "variant-set-picker-exited";
|
|
178
222
|
} | {
|
|
179
223
|
type: "element-target-picked";
|
|
224
|
+
inspection?: {
|
|
225
|
+
selectionId: string;
|
|
226
|
+
styles: ElementStyles;
|
|
227
|
+
};
|
|
180
228
|
/** A CSS selector scoped as narrowly as possible to a registered ancestor. */
|
|
181
229
|
selector: string;
|
|
182
230
|
tagName: string;
|
|
@@ -186,6 +234,10 @@ export type RigToFrame = {
|
|
|
186
234
|
anchor: CommentAnchor;
|
|
187
235
|
} | {
|
|
188
236
|
type: "element-picker-exited";
|
|
237
|
+
} | {
|
|
238
|
+
type: "element-preview-bounds";
|
|
239
|
+
selectionId: string;
|
|
240
|
+
anchor: CommentAnchor | null;
|
|
189
241
|
};
|
|
190
242
|
export declare function isFrameToRig(d: unknown): d is FrameToRig;
|
|
191
243
|
export declare function isRigToFrame(d: unknown): d is RigToFrame;
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,74 @@
|
|
|
1
|
-
export const PROTOCOL_VERSION =
|
|
1
|
+
export const PROTOCOL_VERSION = 3;
|
|
2
2
|
// ─── URL param conventions ─────────────────────────────────────────
|
|
3
3
|
export const STATE_PARAM = "state";
|
|
4
4
|
export const variantParam = (component) => `v.${component}`;
|
|
5
|
+
/** Required ancestors, outermost first. Invalid references and cycles fail closed. */
|
|
6
|
+
export function variantSetRequirements(sets, component) {
|
|
7
|
+
const visited = new Set();
|
|
8
|
+
const requirements = [];
|
|
9
|
+
let set = sets.find((candidate) => candidate.component === component);
|
|
10
|
+
if (!set)
|
|
11
|
+
return null;
|
|
12
|
+
while (set) {
|
|
13
|
+
if (visited.has(set.component))
|
|
14
|
+
return null;
|
|
15
|
+
visited.add(set.component);
|
|
16
|
+
const requirement = set.requires;
|
|
17
|
+
if (!requirement)
|
|
18
|
+
break;
|
|
19
|
+
const parent = sets.find((candidate) => candidate.component === requirement.component);
|
|
20
|
+
if (!parent?.variants.some((variant) => variant.id === requirement.variant))
|
|
21
|
+
return null;
|
|
22
|
+
requirements.unshift(requirement);
|
|
23
|
+
set = parent;
|
|
24
|
+
}
|
|
25
|
+
return requirements;
|
|
26
|
+
}
|
|
27
|
+
export function isVariantSetApplicable(sets, component, params) {
|
|
28
|
+
const requirements = variantSetRequirements(sets, component);
|
|
29
|
+
return requirements !== null && requirements.every((requirement) => {
|
|
30
|
+
const parent = sets.find((set) => set.component === requirement.component);
|
|
31
|
+
return (params.get(variantParam(parent.component)) ?? parent.default) === requirement.variant;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** Apply a selection and its ancestors together, preserving dormant child choices. */
|
|
35
|
+
export function applyVariantSelection(sets, params, component, variant) {
|
|
36
|
+
const requirements = variantSetRequirements(sets, component);
|
|
37
|
+
const set = sets.find((candidate) => candidate.component === component);
|
|
38
|
+
if (!requirements || !set?.variants.some((candidate) => candidate.id === variant))
|
|
39
|
+
return false;
|
|
40
|
+
for (const requirement of requirements) {
|
|
41
|
+
params.set(variantParam(requirement.component), requirement.variant);
|
|
42
|
+
}
|
|
43
|
+
params.set(variantParam(component), variant);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
/** CSS properties exposed by the annotation inspector. */
|
|
47
|
+
export const ELEMENT_STYLE_PROPERTIES = [
|
|
48
|
+
"color", "background-color", "opacity", "font-family", "font-size",
|
|
49
|
+
"font-weight", "line-height", "letter-spacing",
|
|
50
|
+
"padding-top", "padding-right", "padding-bottom", "padding-left",
|
|
51
|
+
"border-radius", "gap",
|
|
52
|
+
];
|
|
5
53
|
// ─── guards (tolerant: unknown message types are ignored, never errors) ──
|
|
6
54
|
export function isFrameToRig(d) {
|
|
7
55
|
if (typeof d !== "object" || d === null)
|
|
8
56
|
return false;
|
|
9
57
|
const message = d;
|
|
58
|
+
if (message.type === "release-element")
|
|
59
|
+
return typeof message.selectionId === "string";
|
|
60
|
+
if (message.type === "preview-element-styles") {
|
|
61
|
+
return typeof message.selectionId === "string" && typeof message.styles === "object" &&
|
|
62
|
+
message.styles !== null && !Array.isArray(message.styles) &&
|
|
63
|
+
Object.entries(message.styles).every(([property, value]) => ELEMENT_STYLE_PROPERTIES.includes(property) && typeof value === "string");
|
|
64
|
+
}
|
|
10
65
|
const t = message.type;
|
|
11
66
|
return (t === "set-state" ||
|
|
12
67
|
(t === "set-theme" &&
|
|
13
68
|
(message.theme === "light" || message.theme === "dark")) ||
|
|
14
69
|
t === "set-variant" ||
|
|
15
|
-
t === "focus-target" ||
|
|
16
|
-
t === "measure-target" ||
|
|
70
|
+
(t === "focus-target" && (message.selector === null || typeof message.selector === "string")) ||
|
|
71
|
+
(t === "measure-target" && typeof message.selector === "string") ||
|
|
17
72
|
t === "set-comment-mode" ||
|
|
18
73
|
t === "capture-comment" ||
|
|
19
74
|
t === "set-variant-set-picker" ||
|
|
@@ -22,17 +77,19 @@ export function isFrameToRig(d) {
|
|
|
22
77
|
export function isRigToFrame(d) {
|
|
23
78
|
if (typeof d !== "object" || d === null)
|
|
24
79
|
return false;
|
|
25
|
-
const
|
|
26
|
-
|
|
80
|
+
const message = d;
|
|
81
|
+
const t = message.type;
|
|
82
|
+
if (["comment-target-picked", "comment-capture", "variant-set-target-picked", "target-measured"].includes(t)) {
|
|
83
|
+
return typeof message.selector === "string";
|
|
84
|
+
}
|
|
85
|
+
return ((t === "frame-tools-status" && ["loading", "ready", "unavailable"].includes(message.status)) ||
|
|
86
|
+
t === "hello" ||
|
|
27
87
|
t === "state-changed" ||
|
|
28
|
-
t === "comment-target-picked" ||
|
|
29
|
-
t === "comment-capture" ||
|
|
30
88
|
t === "thumbnail-capture" ||
|
|
31
89
|
t === "comment-mode-exited" ||
|
|
32
90
|
t === "target-focus-dismissed" ||
|
|
33
|
-
t === "target-measured" ||
|
|
34
|
-
t === "variant-set-target-picked" ||
|
|
35
91
|
t === "variant-set-picker-exited" ||
|
|
92
|
+
t === "element-preview-bounds" ||
|
|
36
93
|
t === "element-target-picked" ||
|
|
37
94
|
t === "element-picker-exited");
|
|
38
95
|
}
|
package/package.json
CHANGED