@proto-labs-inc/wire 0.1.0 → 0.1.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/dist/index.d.ts CHANGED
@@ -57,18 +57,28 @@ export interface ReferenceDef {
57
57
  variant?: string;
58
58
  }
59
59
  export interface VariantSetDef {
60
- /** component id the variants belong to (matches the rig's registration) */
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
- /** variant id the prototype's code defaults to */
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;
@@ -85,9 +95,31 @@ export interface Manifest {
85
95
  states: StateDef[];
86
96
  variantSets: VariantSetDef[];
87
97
  prPlan?: PrPlanDef;
98
+ /** The width (and height) the page was copied at, when the copy only
99
+ * lays out right there (a frozen page): the Frame draws it at this
100
+ * width and scales it down when the area is narrower. */
101
+ viewport?: {
102
+ width: number;
103
+ height: number;
104
+ /** the narrowest width it still lays out at without spilling sideways:
105
+ * the Frame re-flows it down to here and scales it only below */
106
+ minWidth?: number;
107
+ };
88
108
  }
89
109
  export declare const STATE_PARAM = "state";
90
110
  export declare const variantParam: (component: string) => string;
111
+ /** Required ancestors, outermost first. Invalid references and cycles fail closed. */
112
+ export declare function variantSetRequirements(sets: VariantSetDef[], component: string): Array<{
113
+ component: string;
114
+ variant: string;
115
+ }> | null;
116
+ export declare function isVariantSetApplicable(sets: VariantSetDef[], component: string, params: URLSearchParams): boolean;
117
+ /** Apply a selection and its ancestors together, preserving dormant child choices. */
118
+ export declare function applyVariantSelection(sets: VariantSetDef[], params: URLSearchParams, component: string, variant: string): boolean;
119
+ /** CSS properties exposed by the annotation inspector. */
120
+ 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"];
121
+ export type ElementStyleProperty = typeof ELEMENT_STYLE_PROPERTIES[number];
122
+ export type ElementStyles = Partial<Record<ElementStyleProperty, string>>;
91
123
  export type FrameToRig = {
92
124
  type: "set-state";
93
125
  id: string;
@@ -116,6 +148,13 @@ export type FrameToRig = {
116
148
  } | {
117
149
  type: "set-element-picker";
118
150
  on: boolean;
151
+ } | {
152
+ type: "preview-element-styles";
153
+ selectionId: string;
154
+ styles: ElementStyles;
155
+ } | {
156
+ type: "release-element";
157
+ selectionId: string;
119
158
  };
120
159
  export interface CommentAnchor {
121
160
  /** Bounds of the selected component in the prototype viewport. */
@@ -177,6 +216,10 @@ export type RigToFrame = {
177
216
  type: "variant-set-picker-exited";
178
217
  } | {
179
218
  type: "element-target-picked";
219
+ inspection?: {
220
+ selectionId: string;
221
+ styles: ElementStyles;
222
+ };
180
223
  /** A CSS selector scoped as narrowly as possible to a registered ancestor. */
181
224
  selector: string;
182
225
  tagName: string;
@@ -186,6 +229,10 @@ export type RigToFrame = {
186
229
  anchor: CommentAnchor;
187
230
  } | {
188
231
  type: "element-picker-exited";
232
+ } | {
233
+ type: "element-preview-bounds";
234
+ selectionId: string;
235
+ anchor: CommentAnchor | null;
189
236
  };
190
237
  export declare function isFrameToRig(d: unknown): d is FrameToRig;
191
238
  export declare function isRigToFrame(d: unknown): d is RigToFrame;
package/dist/index.js CHANGED
@@ -2,11 +2,66 @@ export const PROTOCOL_VERSION = 2;
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" &&
@@ -33,6 +88,7 @@ export function isRigToFrame(d) {
33
88
  t === "target-measured" ||
34
89
  t === "variant-set-target-picked" ||
35
90
  t === "variant-set-picker-exited" ||
91
+ t === "element-preview-bounds" ||
36
92
  t === "element-target-picked" ||
37
93
  t === "element-picker-exited");
38
94
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proto-labs-inc/wire",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "The typed contract between Proto's Frame and the rig inside a prototype: bridge messages and the prototype.json schema.",
5
5
  "license": "MIT",
6
6
  "repository": {