@archie/devtools 0.1.11 → 0.1.12
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/chunk-ZTJ6RQQF.mjs +2383 -0
- package/dist/client/client.js +1 -1
- package/dist/client/client.mjs +1 -1
- package/dist/collection-binding.js +1363 -1
- package/dist/collection-binding.mjs +1 -1
- package/dist/index.js +1367 -5
- package/dist/index.mjs +2 -2
- package/package.json +3 -2
- package/dist/chunk-ZG6HZFTJ.mjs +0 -1019
- /package/dist/{inspector.standalone@0.1.11.js → inspector.standalone@0.1.12.js} +0 -0
|
@@ -0,0 +1,2383 @@
|
|
|
1
|
+
// node_modules/tsup/assets/esm_shims.js
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
var getFilename = () => fileURLToPath(import.meta.url);
|
|
5
|
+
var getDirname = () => path.dirname(getFilename());
|
|
6
|
+
var __dirname = /* @__PURE__ */ getDirname();
|
|
7
|
+
|
|
8
|
+
// node_modules/@8base-archie/editor-protocol/dist/ids.js
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var VID_ATTR = "data-vid";
|
|
11
|
+
var VID_PATTERN = /^[a-z0-9]{6,8}$/;
|
|
12
|
+
var Vid = z.string().regex(VID_PATTERN);
|
|
13
|
+
|
|
14
|
+
// node_modules/@8base-archie/editor-protocol/dist/node-meta.js
|
|
15
|
+
import { z as z2 } from "zod";
|
|
16
|
+
var LockReasonSchema = z2.enum([
|
|
17
|
+
"KIT_INTERNAL",
|
|
18
|
+
"DYNAMIC_ARRAY",
|
|
19
|
+
"DYNAMIC_CONDITIONAL",
|
|
20
|
+
"CHROME_STRUCTURAL",
|
|
21
|
+
"DATA_TABLE",
|
|
22
|
+
"EXPRESSION_CONTAINER"
|
|
23
|
+
]);
|
|
24
|
+
var DynamicTypeSchema = z2.enum(["STATIC", "ARRAY", "CONDITIONAL"]);
|
|
25
|
+
var ContainerKindSchema = z2.enum(["plain", "expression", "none"]);
|
|
26
|
+
var NodeMetaSchema = z2.object({
|
|
27
|
+
vid: Vid,
|
|
28
|
+
file: z2.string().min(1),
|
|
29
|
+
component: z2.string().min(1).optional(),
|
|
30
|
+
dynamicType: DynamicTypeSchema,
|
|
31
|
+
isKitOrigin: z2.boolean(),
|
|
32
|
+
isChrome: z2.boolean(),
|
|
33
|
+
containerKind: ContainerKindSchema,
|
|
34
|
+
lockReason: LockReasonSchema.optional(),
|
|
35
|
+
usageVid: Vid.optional(),
|
|
36
|
+
usageFile: z2.string().min(1).optional()
|
|
37
|
+
}).strict();
|
|
38
|
+
|
|
39
|
+
// node_modules/@8base-archie/editor-protocol/dist/ops.js
|
|
40
|
+
import { z as z3 } from "zod";
|
|
41
|
+
var literalValue = z3.union([z3.string(), z3.number(), z3.boolean(), z3.null()]);
|
|
42
|
+
var opScopeSchema = z3.enum(["instance", "definition"]);
|
|
43
|
+
var setTextHintSchema = z3.object({
|
|
44
|
+
rowId: z3.string().min(1).optional(),
|
|
45
|
+
rendered: z3.string().optional()
|
|
46
|
+
}).strict();
|
|
47
|
+
var setTextTargetSchema = z3.enum(["auto", "data", "source"]);
|
|
48
|
+
var setTextOpSchema = z3.object({
|
|
49
|
+
kind: z3.literal("setText"),
|
|
50
|
+
vid: Vid,
|
|
51
|
+
text: z3.string(),
|
|
52
|
+
hint: setTextHintSchema.optional(),
|
|
53
|
+
scope: opScopeSchema.optional(),
|
|
54
|
+
target: setTextTargetSchema.optional()
|
|
55
|
+
}).strict();
|
|
56
|
+
var setClassNameOpSchema = z3.object({
|
|
57
|
+
kind: z3.literal("setClassName"),
|
|
58
|
+
vid: Vid,
|
|
59
|
+
add: z3.array(z3.string()),
|
|
60
|
+
remove: z3.array(z3.string()),
|
|
61
|
+
policy: z3.enum(["static", "cn"]),
|
|
62
|
+
scope: opScopeSchema.optional()
|
|
63
|
+
}).strict();
|
|
64
|
+
var setStyleOpSchema = z3.object({
|
|
65
|
+
kind: z3.literal("setStyle"),
|
|
66
|
+
vid: Vid,
|
|
67
|
+
decls: z3.record(z3.string(), z3.union([z3.string(), z3.null()])),
|
|
68
|
+
scope: opScopeSchema.optional(),
|
|
69
|
+
important: z3.boolean().optional()
|
|
70
|
+
}).strict();
|
|
71
|
+
var setAttributeOpSchema = z3.object({
|
|
72
|
+
kind: z3.literal("setAttribute"),
|
|
73
|
+
vid: Vid,
|
|
74
|
+
name: z3.string().min(1),
|
|
75
|
+
value: z3.union([z3.string(), z3.null()])
|
|
76
|
+
}).strict();
|
|
77
|
+
var setPropOpSchema = z3.object({
|
|
78
|
+
kind: z3.literal("setProp"),
|
|
79
|
+
vid: Vid,
|
|
80
|
+
name: z3.string().min(1),
|
|
81
|
+
literal: literalValue,
|
|
82
|
+
scope: opScopeSchema.optional()
|
|
83
|
+
}).strict();
|
|
84
|
+
var removeOpSchema = z3.object({
|
|
85
|
+
kind: z3.literal("remove"),
|
|
86
|
+
vid: Vid
|
|
87
|
+
}).strict();
|
|
88
|
+
var detachInstanceOpSchema = z3.object({
|
|
89
|
+
kind: z3.literal("detachInstance"),
|
|
90
|
+
vid: Vid
|
|
91
|
+
}).strict();
|
|
92
|
+
var setLocalConstOpSchema = z3.object({
|
|
93
|
+
kind: z3.literal("setLocalConst"),
|
|
94
|
+
file: z3.string().min(1),
|
|
95
|
+
name: z3.string().min(1),
|
|
96
|
+
literal: z3.string()
|
|
97
|
+
}).strict();
|
|
98
|
+
var screenRootTargetSchema = z3.object({ file: z3.string().min(1) }).strict();
|
|
99
|
+
var EXACTLY_ONE_TARGET_MESSAGE = "exactly one of containerVid or screenRoot is required";
|
|
100
|
+
function hasExactlyOneTarget(v) {
|
|
101
|
+
return v.containerVid != null !== (v.screenRoot != null);
|
|
102
|
+
}
|
|
103
|
+
var moveOpSchema = z3.object({
|
|
104
|
+
kind: z3.literal("move"),
|
|
105
|
+
targetVid: Vid,
|
|
106
|
+
containerVid: Vid.optional(),
|
|
107
|
+
screenRoot: screenRootTargetSchema.optional(),
|
|
108
|
+
index: z3.number().int().nonnegative()
|
|
109
|
+
}).strict();
|
|
110
|
+
var insertSourceSchema = z3.union([
|
|
111
|
+
z3.object({ paletteId: z3.string().min(1) }).strict(),
|
|
112
|
+
z3.object({ snippet: z3.string().min(1) }).strict()
|
|
113
|
+
]);
|
|
114
|
+
var insertOpSchema = z3.object({
|
|
115
|
+
kind: z3.literal("insert"),
|
|
116
|
+
containerVid: Vid.optional(),
|
|
117
|
+
screenRoot: screenRootTargetSchema.optional(),
|
|
118
|
+
index: z3.number().int().nonnegative(),
|
|
119
|
+
source: insertSourceSchema,
|
|
120
|
+
proposedVids: z3.array(Vid).optional()
|
|
121
|
+
}).strict();
|
|
122
|
+
var resizeOpSchema = z3.object({
|
|
123
|
+
kind: z3.literal("resize"),
|
|
124
|
+
vid: Vid,
|
|
125
|
+
width: z3.number().optional(),
|
|
126
|
+
height: z3.number().optional()
|
|
127
|
+
}).strict();
|
|
128
|
+
var shellConfigOpSchema = z3.object({
|
|
129
|
+
kind: z3.literal("shellConfig"),
|
|
130
|
+
patch: z3.record(z3.string(), z3.unknown())
|
|
131
|
+
}).strict();
|
|
132
|
+
var sliceCellOpSchema = z3.object({
|
|
133
|
+
kind: z3.literal("sliceCell"),
|
|
134
|
+
slug: z3.string().min(1),
|
|
135
|
+
entity: z3.string().min(1),
|
|
136
|
+
rowId: z3.string().min(1),
|
|
137
|
+
field: z3.string().min(1),
|
|
138
|
+
value: literalValue
|
|
139
|
+
}).strict();
|
|
140
|
+
var LUCIDE_ICON_NAME_RE = /^[A-Z][A-Za-z0-9]*$/;
|
|
141
|
+
var MAX_SVG_ICON_LENGTH = 2e4;
|
|
142
|
+
var SVG_SINGLE_ROOT_RE = /^<svg\b[^>]*(?:\/>|>[\s\S]*<\/svg>)\s*$/i;
|
|
143
|
+
function isSingleSvgRoot(svg) {
|
|
144
|
+
if (!SVG_SINGLE_ROOT_RE.test(svg))
|
|
145
|
+
return false;
|
|
146
|
+
const openCount = (svg.match(/<svg\b/gi) ?? []).length;
|
|
147
|
+
const closeCount = (svg.match(/<\/svg>/gi) ?? []).length;
|
|
148
|
+
return openCount === 1 && closeCount <= 1;
|
|
149
|
+
}
|
|
150
|
+
var SVG_FORBIDDEN_CHAR_RE = /[&%]/;
|
|
151
|
+
var SVG_FORBIDDEN_MARKUP_RE = /<!|<\?/;
|
|
152
|
+
var SVG_FORBIDDEN_ATTR_RE = /\b(?:href|xlink:href|src|style)\s*=|\bon[a-zA-Z-]+\s*=/i;
|
|
153
|
+
var SVG_FORBIDDEN_SCHEME_RE = /\b(?:data|javascript):|url\(/i;
|
|
154
|
+
var SVG_FORBIDDEN_TAG_RE = /<\/?\s*(?:script|style|foreignobject|iframe|object|embed|use|image|a|animate\w*|set)\b/i;
|
|
155
|
+
function isForbiddenSvg(svg) {
|
|
156
|
+
return SVG_FORBIDDEN_CHAR_RE.test(svg) || SVG_FORBIDDEN_MARKUP_RE.test(svg) || SVG_FORBIDDEN_ATTR_RE.test(svg) || SVG_FORBIDDEN_SCHEME_RE.test(svg) || SVG_FORBIDDEN_TAG_RE.test(svg);
|
|
157
|
+
}
|
|
158
|
+
var setIconValueSchema = z3.discriminatedUnion("kind", [
|
|
159
|
+
z3.object({
|
|
160
|
+
kind: z3.literal("lucide"),
|
|
161
|
+
name: z3.string().min(1).max(64).regex(LUCIDE_ICON_NAME_RE, "lucide icon name must be a PascalCase identifier")
|
|
162
|
+
}).strict(),
|
|
163
|
+
z3.object({
|
|
164
|
+
kind: z3.literal("svg"),
|
|
165
|
+
svg: z3.string().min(1).max(MAX_SVG_ICON_LENGTH).trim().refine((svg) => isSingleSvgRoot(svg), "svg must be a single <svg>\u2026</svg> (or self-closing <svg/>) root element").refine((svg) => !isForbiddenSvg(svg), "svg must not contain &, %, a comment/CDATA/DOCTYPE/processing instruction, an href/xlink:href/src/style attribute, an on* event handler, a data:/javascript: URL, a url(), or a script/style/foreignObject/iframe/object/embed/use/image/a/animate*/set element")
|
|
166
|
+
}).strict()
|
|
167
|
+
]);
|
|
168
|
+
var setIconOpSchema = z3.object({
|
|
169
|
+
kind: z3.literal("setIcon"),
|
|
170
|
+
vid: Vid,
|
|
171
|
+
icon: setIconValueSchema
|
|
172
|
+
}).strict();
|
|
173
|
+
var OpSchema = z3.discriminatedUnion("kind", [
|
|
174
|
+
setTextOpSchema,
|
|
175
|
+
setClassNameOpSchema,
|
|
176
|
+
setStyleOpSchema,
|
|
177
|
+
setAttributeOpSchema,
|
|
178
|
+
setPropOpSchema,
|
|
179
|
+
removeOpSchema,
|
|
180
|
+
setLocalConstOpSchema,
|
|
181
|
+
moveOpSchema,
|
|
182
|
+
insertOpSchema,
|
|
183
|
+
resizeOpSchema,
|
|
184
|
+
shellConfigOpSchema,
|
|
185
|
+
sliceCellOpSchema,
|
|
186
|
+
setIconOpSchema,
|
|
187
|
+
detachInstanceOpSchema
|
|
188
|
+
]).superRefine((op, ctx) => {
|
|
189
|
+
if ((op.kind === "move" || op.kind === "insert") && !hasExactlyOneTarget(op)) {
|
|
190
|
+
ctx.addIssue({ code: z3.ZodIssueCode.custom, message: EXACTLY_ONE_TARGET_MESSAGE, path: ["containerVid"] });
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
var OpLogSchema = z3.array(OpSchema).min(1);
|
|
194
|
+
|
|
195
|
+
// node_modules/@8base-archie/editor-protocol/dist/apply-ops.js
|
|
196
|
+
import { z as z4 } from "zod";
|
|
197
|
+
var RefusalCodeSchema = z4.enum([
|
|
198
|
+
"VID_NOT_FOUND",
|
|
199
|
+
"CONTAINER_NOT_PLAIN",
|
|
200
|
+
"KIT_INTERNAL",
|
|
201
|
+
"CHROME_STRUCTURAL",
|
|
202
|
+
"DYNAMIC_CHILD",
|
|
203
|
+
"STALE_BASE",
|
|
204
|
+
"GATE_REJECT",
|
|
205
|
+
"STYLE_UNMAPPABLE",
|
|
206
|
+
"DIALECT_UNSUPPORTED",
|
|
207
|
+
"COMPUTED_VALUE",
|
|
208
|
+
"PROP_BOUND",
|
|
209
|
+
"STATE_BOUND",
|
|
210
|
+
"ORIGIN_AMBIGUOUS",
|
|
211
|
+
"NOT_DETACHABLE"
|
|
212
|
+
]);
|
|
213
|
+
var TextTargetSchema = z4.discriminatedUnion("kind", [
|
|
214
|
+
z4.object({ kind: z4.literal("source") }).strict(),
|
|
215
|
+
z4.object({
|
|
216
|
+
kind: z4.literal("slice"),
|
|
217
|
+
entity: z4.string().min(1),
|
|
218
|
+
rowId: z4.string().min(1),
|
|
219
|
+
field: z4.string().min(1),
|
|
220
|
+
slugs: z4.array(z4.string().min(1)).min(1)
|
|
221
|
+
}).strict()
|
|
222
|
+
]);
|
|
223
|
+
var ApplyOpsFileRefSchema = z4.object({
|
|
224
|
+
path: z4.string().min(1),
|
|
225
|
+
baseSourceHash: z4.string().min(1)
|
|
226
|
+
}).strict();
|
|
227
|
+
var ApplyOpsRequestSchema = z4.object({
|
|
228
|
+
projectId: z4.string().min(1),
|
|
229
|
+
protocolVersion: z4.string().min(1),
|
|
230
|
+
dialect: z4.enum(["kit-d", "vite-tsx"]),
|
|
231
|
+
files: z4.array(ApplyOpsFileRefSchema).min(1),
|
|
232
|
+
baseRevisionId: z4.string().min(1),
|
|
233
|
+
ops: z4.array(OpSchema).min(1),
|
|
234
|
+
clientOpLogId: z4.string().min(1)
|
|
235
|
+
}).strict();
|
|
236
|
+
var ApplyOpsFileResultSchema = z4.object({
|
|
237
|
+
path: z4.string().min(1),
|
|
238
|
+
newSource: z4.string(),
|
|
239
|
+
sourceHash: z4.string().min(1)
|
|
240
|
+
}).strict();
|
|
241
|
+
var RefusedOpSchema = z4.object({
|
|
242
|
+
opIndex: z4.number().int().nonnegative(),
|
|
243
|
+
code: RefusalCodeSchema,
|
|
244
|
+
cause: z4.string(),
|
|
245
|
+
vid: Vid.optional()
|
|
246
|
+
}).strict();
|
|
247
|
+
var AppliedTargetSchema = z4.object({
|
|
248
|
+
opIndex: z4.number().int().nonnegative(),
|
|
249
|
+
target: TextTargetSchema
|
|
250
|
+
}).strict();
|
|
251
|
+
var PropagationFailureSchema = z4.object({
|
|
252
|
+
slug: z4.string().min(1),
|
|
253
|
+
code: RefusalCodeSchema,
|
|
254
|
+
cause: z4.string()
|
|
255
|
+
}).strict();
|
|
256
|
+
var DetachedComponentNodeSchema = z4.object({
|
|
257
|
+
vid: Vid,
|
|
258
|
+
templateVid: Vid.optional(),
|
|
259
|
+
slot: z4.string().min(1).optional()
|
|
260
|
+
}).strict();
|
|
261
|
+
var DetachedComponentSchema = z4.object({
|
|
262
|
+
vid: Vid,
|
|
263
|
+
component: z4.string().min(1),
|
|
264
|
+
nodes: z4.array(DetachedComponentNodeSchema)
|
|
265
|
+
}).strict();
|
|
266
|
+
var PropagationStatusSchema = z4.object({
|
|
267
|
+
jobId: z4.string().min(1),
|
|
268
|
+
status: z4.enum(["pending", "done", "failed"]),
|
|
269
|
+
slugs: z4.array(z4.string().min(1)),
|
|
270
|
+
failed: z4.array(PropagationFailureSchema).optional(),
|
|
271
|
+
revisionId: z4.string().min(1).optional()
|
|
272
|
+
}).strict();
|
|
273
|
+
var ApplyOpsPropagationSchema = z4.object({
|
|
274
|
+
status: z4.enum(["pending", "done", "failed"]),
|
|
275
|
+
jobId: z4.string().min(1),
|
|
276
|
+
slugs: z4.array(z4.string().min(1)),
|
|
277
|
+
failed: z4.array(PropagationFailureSchema).optional()
|
|
278
|
+
}).strict();
|
|
279
|
+
var ApplyOpsResponseSchema = z4.object({
|
|
280
|
+
revisionId: z4.string().min(1),
|
|
281
|
+
files: z4.array(ApplyOpsFileResultSchema),
|
|
282
|
+
vidMap: z4.record(z4.string(), z4.string()),
|
|
283
|
+
applied: z4.array(z4.number().int().nonnegative()),
|
|
284
|
+
refused: z4.array(RefusedOpSchema),
|
|
285
|
+
gateFindings: z4.array(z4.unknown()),
|
|
286
|
+
appliedTargets: z4.array(AppliedTargetSchema).optional(),
|
|
287
|
+
stylesheetChanged: z4.boolean().optional(),
|
|
288
|
+
propagation: ApplyOpsPropagationSchema.optional(),
|
|
289
|
+
detached: z4.array(DetachedComponentSchema).optional()
|
|
290
|
+
}).strict();
|
|
291
|
+
|
|
292
|
+
// node_modules/@8base-archie/editor-protocol/dist/capabilities.js
|
|
293
|
+
import { z as z5 } from "zod";
|
|
294
|
+
var CapabilitiesSchema = z5.object({
|
|
295
|
+
inspect: z5.boolean(),
|
|
296
|
+
dndMove: z5.boolean(),
|
|
297
|
+
dndResize: z5.boolean(),
|
|
298
|
+
vidIdentity: z5.boolean(),
|
|
299
|
+
nodeMeta: z5.boolean(),
|
|
300
|
+
hostControlledHistory: z5.boolean(),
|
|
301
|
+
refusals: z5.boolean(),
|
|
302
|
+
selectByVid: z5.boolean().optional()
|
|
303
|
+
}).strict();
|
|
304
|
+
|
|
305
|
+
// node_modules/@8base-archie/editor-protocol/dist/runtime-messages.js
|
|
306
|
+
import { z as z6 } from "zod";
|
|
307
|
+
var SourceSchema = z6.enum(["archie-devtools", "archie-app"]);
|
|
308
|
+
var RectSchema = z6.object({
|
|
309
|
+
x: z6.number(),
|
|
310
|
+
y: z6.number(),
|
|
311
|
+
width: z6.number(),
|
|
312
|
+
height: z6.number()
|
|
313
|
+
}).strict();
|
|
314
|
+
var helloMessageSchema = z6.object({
|
|
315
|
+
source: SourceSchema,
|
|
316
|
+
type: z6.literal("HELLO"),
|
|
317
|
+
protocolVersion: z6.string().min(1),
|
|
318
|
+
devtoolsVersion: z6.string().min(1),
|
|
319
|
+
capabilities: CapabilitiesSchema
|
|
320
|
+
}).strict();
|
|
321
|
+
var elementSelectedMessageSchema = z6.object({
|
|
322
|
+
source: SourceSchema,
|
|
323
|
+
type: z6.literal("ELEMENT_SELECTED"),
|
|
324
|
+
vid: Vid,
|
|
325
|
+
nodeMeta: NodeMetaSchema,
|
|
326
|
+
rect: RectSchema.optional()
|
|
327
|
+
}).strict();
|
|
328
|
+
var dragStartMessageSchema = z6.object({
|
|
329
|
+
source: SourceSchema,
|
|
330
|
+
type: z6.literal("DRAG_START"),
|
|
331
|
+
targetVid: Vid,
|
|
332
|
+
droppable: z6.array(Vid)
|
|
333
|
+
}).strict();
|
|
334
|
+
var dropMessageSchema = z6.object({
|
|
335
|
+
source: SourceSchema,
|
|
336
|
+
type: z6.literal("DROP"),
|
|
337
|
+
targetVid: Vid,
|
|
338
|
+
containerVid: Vid,
|
|
339
|
+
screenRootFile: z6.string().min(1).optional(),
|
|
340
|
+
index: z6.number().int().nonnegative()
|
|
341
|
+
}).strict();
|
|
342
|
+
var refusedMessageSchema = z6.object({
|
|
343
|
+
source: SourceSchema,
|
|
344
|
+
type: z6.literal("REFUSED"),
|
|
345
|
+
code: z6.union([RefusalCodeSchema, LockReasonSchema]),
|
|
346
|
+
cause: z6.string(),
|
|
347
|
+
vid: Vid.optional()
|
|
348
|
+
}).strict();
|
|
349
|
+
var RuntimeMessageSchema = z6.discriminatedUnion("type", [
|
|
350
|
+
helloMessageSchema,
|
|
351
|
+
elementSelectedMessageSchema,
|
|
352
|
+
dragStartMessageSchema,
|
|
353
|
+
dropMessageSchema,
|
|
354
|
+
refusedMessageSchema
|
|
355
|
+
]);
|
|
356
|
+
var selectMessageSchema = z6.object({
|
|
357
|
+
source: SourceSchema,
|
|
358
|
+
type: z6.literal("SELECT"),
|
|
359
|
+
vid: Vid
|
|
360
|
+
}).strict();
|
|
361
|
+
var previewOpMessageSchema = z6.object({
|
|
362
|
+
source: SourceSchema,
|
|
363
|
+
type: z6.literal("PREVIEW_OP"),
|
|
364
|
+
op: OpSchema
|
|
365
|
+
}).strict();
|
|
366
|
+
var setModeMessageSchema = z6.object({
|
|
367
|
+
source: SourceSchema,
|
|
368
|
+
type: z6.literal("SET_MODE"),
|
|
369
|
+
mode: z6.enum(["inspect", "design", "off"])
|
|
370
|
+
}).strict();
|
|
371
|
+
var HostMessageSchema = z6.discriminatedUnion("type", [
|
|
372
|
+
selectMessageSchema,
|
|
373
|
+
previewOpMessageSchema,
|
|
374
|
+
setModeMessageSchema
|
|
375
|
+
]);
|
|
376
|
+
|
|
377
|
+
// node_modules/@8base-archie/editor-protocol/dist/style-capabilities.js
|
|
378
|
+
function stripImportant(cls) {
|
|
379
|
+
if (cls.endsWith("!"))
|
|
380
|
+
return cls.slice(0, -1);
|
|
381
|
+
if (cls.startsWith("!"))
|
|
382
|
+
return cls.slice(1);
|
|
383
|
+
return cls;
|
|
384
|
+
}
|
|
385
|
+
var SPACING_PX_TO_UNIT = {
|
|
386
|
+
0: "0",
|
|
387
|
+
1: "px",
|
|
388
|
+
2: "0.5",
|
|
389
|
+
4: "1",
|
|
390
|
+
6: "1.5",
|
|
391
|
+
8: "2",
|
|
392
|
+
10: "2.5",
|
|
393
|
+
12: "3",
|
|
394
|
+
14: "3.5",
|
|
395
|
+
16: "4",
|
|
396
|
+
20: "5",
|
|
397
|
+
24: "6",
|
|
398
|
+
28: "7",
|
|
399
|
+
32: "8",
|
|
400
|
+
36: "9",
|
|
401
|
+
40: "10",
|
|
402
|
+
44: "11",
|
|
403
|
+
48: "12",
|
|
404
|
+
56: "14",
|
|
405
|
+
64: "16",
|
|
406
|
+
80: "20",
|
|
407
|
+
96: "24"
|
|
408
|
+
};
|
|
409
|
+
var FONT_SIZE_PX = {
|
|
410
|
+
12: "xs",
|
|
411
|
+
14: "sm",
|
|
412
|
+
16: "base",
|
|
413
|
+
18: "lg",
|
|
414
|
+
20: "xl",
|
|
415
|
+
24: "2xl",
|
|
416
|
+
30: "3xl",
|
|
417
|
+
36: "4xl",
|
|
418
|
+
48: "5xl"
|
|
419
|
+
};
|
|
420
|
+
var TEXT_SIZE_STEPS = /* @__PURE__ */ new Set(["xs", "sm", "base", "lg", "xl"]);
|
|
421
|
+
function isTextSizeClass(rawCls) {
|
|
422
|
+
const cls = stripImportant(rawCls);
|
|
423
|
+
if (!cls.startsWith("text-"))
|
|
424
|
+
return false;
|
|
425
|
+
const rest = cls.slice(5);
|
|
426
|
+
return TEXT_SIZE_STEPS.has(rest) || /^[0-9]+xl$/.test(rest) || /^\[[^\]]+px\]$/.test(rest);
|
|
427
|
+
}
|
|
428
|
+
var TEXT_ALIGN_STEPS = /* @__PURE__ */ new Set([
|
|
429
|
+
"left",
|
|
430
|
+
"center",
|
|
431
|
+
"right",
|
|
432
|
+
"justify",
|
|
433
|
+
"start",
|
|
434
|
+
"end"
|
|
435
|
+
]);
|
|
436
|
+
function isTextAlignClass(rawCls) {
|
|
437
|
+
const cls = stripImportant(rawCls);
|
|
438
|
+
return cls.startsWith("text-") && TEXT_ALIGN_STEPS.has(cls.slice(5));
|
|
439
|
+
}
|
|
440
|
+
var TEXT_OVERFLOW_STEPS = /* @__PURE__ */ new Set([
|
|
441
|
+
"ellipsis",
|
|
442
|
+
"clip",
|
|
443
|
+
"wrap",
|
|
444
|
+
"nowrap",
|
|
445
|
+
"balance",
|
|
446
|
+
"pretty"
|
|
447
|
+
]);
|
|
448
|
+
function isTextColorClass(rawCls) {
|
|
449
|
+
const cls = stripImportant(rawCls);
|
|
450
|
+
return cls.startsWith("text-") && !isTextSizeClass(cls) && !isTextAlignClass(cls) && !TEXT_OVERFLOW_STEPS.has(cls.slice(5));
|
|
451
|
+
}
|
|
452
|
+
var BG_UTILITY_VALUES = /* @__PURE__ */ new Set([
|
|
453
|
+
"cover",
|
|
454
|
+
"contain",
|
|
455
|
+
"auto",
|
|
456
|
+
"center",
|
|
457
|
+
"top",
|
|
458
|
+
"bottom",
|
|
459
|
+
"left",
|
|
460
|
+
"right",
|
|
461
|
+
"repeat",
|
|
462
|
+
"no-repeat",
|
|
463
|
+
"repeat-x",
|
|
464
|
+
"repeat-y",
|
|
465
|
+
"fixed",
|
|
466
|
+
"local",
|
|
467
|
+
"scroll",
|
|
468
|
+
"none",
|
|
469
|
+
"clip-border",
|
|
470
|
+
"clip-padding",
|
|
471
|
+
"clip-content",
|
|
472
|
+
"clip-text",
|
|
473
|
+
"origin-border",
|
|
474
|
+
"origin-padding",
|
|
475
|
+
"origin-content"
|
|
476
|
+
]);
|
|
477
|
+
function isBgUtilityClass(rawCls) {
|
|
478
|
+
const cls = stripImportant(rawCls);
|
|
479
|
+
return BG_UTILITY_VALUES.has(cls.slice(3)) || /^bg-\[url\(/.test(cls);
|
|
480
|
+
}
|
|
481
|
+
function isBgColorClass(rawCls) {
|
|
482
|
+
const cls = stripImportant(rawCls);
|
|
483
|
+
return cls.startsWith("bg-") && !isBgUtilityClass(cls);
|
|
484
|
+
}
|
|
485
|
+
var BORDER_STYLE_VALUES = /* @__PURE__ */ new Set(["solid", "dashed", "dotted", "double", "hidden", "none"]);
|
|
486
|
+
var BORDER_WIDTH_SIDE = /^([trblxy])(?:-(?:0|2|4|8))?$/;
|
|
487
|
+
function isBorderWidthClass(rawCls) {
|
|
488
|
+
const cls = stripImportant(rawCls);
|
|
489
|
+
if (!cls.startsWith("border-"))
|
|
490
|
+
return false;
|
|
491
|
+
const rest = cls.slice(7);
|
|
492
|
+
if (rest === "0" || rest === "2" || rest === "4" || rest === "8")
|
|
493
|
+
return true;
|
|
494
|
+
return BORDER_WIDTH_SIDE.test(rest);
|
|
495
|
+
}
|
|
496
|
+
function isBorderStyleClass(rawCls) {
|
|
497
|
+
const cls = stripImportant(rawCls);
|
|
498
|
+
return cls.startsWith("border-") && BORDER_STYLE_VALUES.has(cls.slice(7));
|
|
499
|
+
}
|
|
500
|
+
function isBorderColorClass(rawCls) {
|
|
501
|
+
const cls = stripImportant(rawCls);
|
|
502
|
+
return cls.startsWith("border-") && !isBorderWidthClass(cls) && !isBorderStyleClass(cls);
|
|
503
|
+
}
|
|
504
|
+
function prefixMatcher(prefix) {
|
|
505
|
+
return (cls) => stripImportant(cls).startsWith(prefix);
|
|
506
|
+
}
|
|
507
|
+
function exactMatcher(...values) {
|
|
508
|
+
const set = new Set(values);
|
|
509
|
+
return (cls) => set.has(stripImportant(cls));
|
|
510
|
+
}
|
|
511
|
+
function anyMatcher(...matchers) {
|
|
512
|
+
return (cls) => matchers.some((m) => m(cls));
|
|
513
|
+
}
|
|
514
|
+
var PROP_MATCHERS = {
|
|
515
|
+
color: isTextColorClass,
|
|
516
|
+
background: isBgColorClass,
|
|
517
|
+
backgroundColor: isBgColorClass,
|
|
518
|
+
padding: prefixMatcher("p-"),
|
|
519
|
+
paddingTop: prefixMatcher("pt-"),
|
|
520
|
+
paddingRight: prefixMatcher("pr-"),
|
|
521
|
+
paddingBottom: prefixMatcher("pb-"),
|
|
522
|
+
paddingLeft: prefixMatcher("pl-"),
|
|
523
|
+
// negative-margin classes are `-`-PREFIXED (`spacingClass` puts the sign
|
|
524
|
+
// ahead of the property, e.g. `-mt-4`), not `-`-suffixed on the property —
|
|
525
|
+
// a plain `prefixMatcher('mt-')` never matches `-mt-4`, so a subsequent
|
|
526
|
+
// clear left a dangling negative margin. Each margin matcher accepts both
|
|
527
|
+
// forms.
|
|
528
|
+
margin: anyMatcher(prefixMatcher("m-"), prefixMatcher("-m-")),
|
|
529
|
+
marginTop: anyMatcher(prefixMatcher("mt-"), prefixMatcher("-mt-")),
|
|
530
|
+
marginRight: anyMatcher(prefixMatcher("mr-"), prefixMatcher("-mr-")),
|
|
531
|
+
marginBottom: anyMatcher(prefixMatcher("mb-"), prefixMatcher("-mb-")),
|
|
532
|
+
marginLeft: anyMatcher(prefixMatcher("ml-"), prefixMatcher("-ml-")),
|
|
533
|
+
gap: prefixMatcher("gap-"),
|
|
534
|
+
width: prefixMatcher("w-"),
|
|
535
|
+
height: prefixMatcher("h-"),
|
|
536
|
+
fontSize: isTextSizeClass,
|
|
537
|
+
// exact, not prefix: `font-sans`/`font-serif`/`font-mono` share the same
|
|
538
|
+
// `font-` prefix for FAMILY, a property `mapStyleDeclToClass` never
|
|
539
|
+
// touches — a prefix match would sweep those off on a `fontWeight` clear.
|
|
540
|
+
fontWeight: exactMatcher("font-thin", "font-extralight", "font-light", "font-normal", "font-medium", "font-semibold", "font-bold", "font-extrabold", "font-black"),
|
|
541
|
+
borderColor: isBorderColorClass,
|
|
542
|
+
borderRadius: anyMatcher(exactMatcher("rounded"), prefixMatcher("rounded-")),
|
|
543
|
+
display: exactMatcher("block", "inline-block", "inline", "flex", "inline-flex", "grid", "hidden"),
|
|
544
|
+
flexDirection: exactMatcher("flex-col", "flex-row"),
|
|
545
|
+
alignItems: prefixMatcher("items-"),
|
|
546
|
+
justifyContent: prefixMatcher("justify-"),
|
|
547
|
+
textAlign: isTextAlignClass
|
|
548
|
+
};
|
|
549
|
+
var SPACING_PX_STEPS = Object.keys(SPACING_PX_TO_UNIT).map(Number).sort((a, b) => a - b);
|
|
550
|
+
var FONT_SIZE_PX_STEPS = Object.keys(FONT_SIZE_PX).map(Number).sort((a, b) => a - b);
|
|
551
|
+
|
|
552
|
+
// node_modules/@8base-archie/editor-protocol/dist/component-usages.js
|
|
553
|
+
import { z as z7 } from "zod";
|
|
554
|
+
var ComponentUsageSchema = z7.object({
|
|
555
|
+
slug: z7.string().min(1),
|
|
556
|
+
file: z7.string().min(1),
|
|
557
|
+
vid: Vid
|
|
558
|
+
}).strict();
|
|
559
|
+
var ComponentUsagesSchema = z7.object({
|
|
560
|
+
file: z7.string().min(1),
|
|
561
|
+
component: z7.string().min(1),
|
|
562
|
+
count: z7.number().int().nonnegative(),
|
|
563
|
+
usages: z7.array(ComponentUsageSchema)
|
|
564
|
+
}).strict();
|
|
565
|
+
|
|
566
|
+
// node_modules/@8base-archie/editor-protocol/dist/palette-catalog.js
|
|
567
|
+
var PALETTE_CATALOG = [
|
|
568
|
+
{
|
|
569
|
+
id: "button",
|
|
570
|
+
group: "common",
|
|
571
|
+
snippet: `<button className="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Button</button>`
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
id: "container",
|
|
575
|
+
group: "common",
|
|
576
|
+
snippet: `<div className="flex flex-col gap-4 p-4"></div>`
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
id: "heading-1",
|
|
580
|
+
group: "common",
|
|
581
|
+
snippet: `<h1 className="text-4xl font-bold tracking-tight text-foreground">Heading</h1>`
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
id: "heading-2",
|
|
585
|
+
group: "common",
|
|
586
|
+
snippet: `<h2 className="text-3xl font-semibold tracking-tight text-foreground">Heading</h2>`
|
|
587
|
+
},
|
|
588
|
+
{
|
|
589
|
+
id: "heading-3",
|
|
590
|
+
group: "common",
|
|
591
|
+
snippet: `<h3 className="text-2xl font-semibold text-foreground">Heading</h3>`
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
id: "paragraph",
|
|
595
|
+
group: "common",
|
|
596
|
+
snippet: `<p className="text-base leading-7 text-foreground">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>`
|
|
597
|
+
},
|
|
598
|
+
{
|
|
599
|
+
id: "typography",
|
|
600
|
+
group: "common",
|
|
601
|
+
snippet: `<span className="text-sm leading-6 text-foreground">Text content</span>`
|
|
602
|
+
},
|
|
603
|
+
{
|
|
604
|
+
id: "link",
|
|
605
|
+
group: "common",
|
|
606
|
+
snippet: `<a href="#" className="text-primary underline-offset-4 hover:underline">Link text</a>`
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
id: "image",
|
|
610
|
+
group: "common",
|
|
611
|
+
snippet: `<img src="https://placehold.co/600x400" alt="Placeholder" className="h-auto w-full rounded-lg" />`
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
id: "divider",
|
|
615
|
+
group: "common",
|
|
616
|
+
snippet: `<hr className="my-6 border-t border-border" />`
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
id: "list-unordered",
|
|
620
|
+
group: "common",
|
|
621
|
+
snippet: `<ul className="list-disc space-y-2 pl-6 text-foreground"><li>First item</li><li>Second item</li><li>Third item</li></ul>`
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
id: "list-ordered",
|
|
625
|
+
group: "common",
|
|
626
|
+
snippet: `<ol className="list-decimal space-y-2 pl-6 text-foreground"><li>First item</li><li>Second item</li><li>Third item</li></ol>`
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
id: "badge",
|
|
630
|
+
group: "common",
|
|
631
|
+
snippet: `<span className="inline-flex items-center rounded-md border border-transparent bg-primary px-2.5 py-0.5 text-xs font-semibold text-primary-foreground shadow">Badge</span>`
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
id: "code",
|
|
635
|
+
group: "common",
|
|
636
|
+
snippet: `<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-sm text-foreground">code</code>`
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
id: "blockquote",
|
|
640
|
+
group: "common",
|
|
641
|
+
snippet: `<blockquote className="border-l-4 border-border pl-4 italic text-muted-foreground">Quoted text goes here.</blockquote>`
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
id: "header",
|
|
645
|
+
group: "layout",
|
|
646
|
+
snippet: `<header className="flex items-center justify-between border-b border-border bg-background px-6 py-4">
|
|
647
|
+
<span className="text-lg font-bold text-foreground">Logo</span>
|
|
648
|
+
<nav className="flex gap-6 text-sm text-muted-foreground">
|
|
649
|
+
<a href="#" className="hover:text-foreground transition-colors">Home</a>
|
|
650
|
+
<a href="#" className="hover:text-foreground transition-colors">About</a>
|
|
651
|
+
</nav>
|
|
652
|
+
</header>`
|
|
653
|
+
},
|
|
654
|
+
{
|
|
655
|
+
id: "footer",
|
|
656
|
+
group: "layout",
|
|
657
|
+
snippet: `<footer className="border-t border-border bg-background px-6 py-12">
|
|
658
|
+
<div className="flex flex-col items-center gap-6 md:flex-row md:justify-between">
|
|
659
|
+
<p className="text-sm text-muted-foreground">\xA9 2025 Company Name. All rights reserved.</p>
|
|
660
|
+
<nav className="flex gap-6">
|
|
661
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Privacy</a>
|
|
662
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Terms</a>
|
|
663
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Contact</a>
|
|
664
|
+
</nav>
|
|
665
|
+
</div>
|
|
666
|
+
</footer>`
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
id: "card",
|
|
670
|
+
group: "layout",
|
|
671
|
+
snippet: `<div className="rounded-xl border border-border bg-card text-card-foreground shadow">
|
|
672
|
+
<div className="flex flex-col space-y-1.5 p-6">
|
|
673
|
+
<h3 className="text-lg font-semibold leading-none tracking-tight">Card Title</h3>
|
|
674
|
+
<p className="text-sm text-muted-foreground">Card description goes here.</p>
|
|
675
|
+
</div>
|
|
676
|
+
</div>`
|
|
677
|
+
},
|
|
678
|
+
{
|
|
679
|
+
id: "paper",
|
|
680
|
+
group: "layout",
|
|
681
|
+
snippet: `<div className="rounded-lg bg-muted/50 p-6 shadow-sm"></div>`
|
|
682
|
+
},
|
|
683
|
+
{
|
|
684
|
+
id: "menu",
|
|
685
|
+
group: "layout",
|
|
686
|
+
snippet: `<ul className="flex flex-col rounded-md border border-border bg-popover py-1 text-sm text-popover-foreground shadow-md">
|
|
687
|
+
<li className="px-3 py-2 hover:bg-accent hover:text-accent-foreground cursor-pointer transition-colors">Item one</li>
|
|
688
|
+
<li className="px-3 py-2 hover:bg-accent hover:text-accent-foreground cursor-pointer transition-colors">Item two</li>
|
|
689
|
+
<li className="px-3 py-2 hover:bg-accent hover:text-accent-foreground cursor-pointer transition-colors">Item three</li>
|
|
690
|
+
</ul>`
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
id: "popper",
|
|
694
|
+
group: "layout",
|
|
695
|
+
snippet: `<div className="w-64 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md">
|
|
696
|
+
<p className="text-sm font-medium">Popper title</p>
|
|
697
|
+
<p className="mt-1 text-xs text-muted-foreground">Floating content goes here.</p>
|
|
698
|
+
</div>`
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
id: "navbar",
|
|
702
|
+
group: "layout",
|
|
703
|
+
snippet: `<nav className="flex items-center justify-between border-b border-border bg-background px-6 py-4">
|
|
704
|
+
<span className="text-lg font-bold text-foreground">Logo</span>
|
|
705
|
+
<div className="flex items-center gap-6">
|
|
706
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Home</a>
|
|
707
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Features</a>
|
|
708
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Pricing</a>
|
|
709
|
+
<button className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Sign Up</button>
|
|
710
|
+
</div>
|
|
711
|
+
</nav>`
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
id: "grid-2",
|
|
715
|
+
group: "layout",
|
|
716
|
+
snippet: `<div className="grid grid-cols-1 gap-4 md:grid-cols-2"></div>`
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
id: "grid-3",
|
|
720
|
+
group: "layout",
|
|
721
|
+
snippet: `<div className="grid grid-cols-1 gap-4 md:grid-cols-3"></div>`
|
|
722
|
+
},
|
|
723
|
+
{
|
|
724
|
+
id: "table",
|
|
725
|
+
group: "layout",
|
|
726
|
+
snippet: `<table className="w-full border-collapse text-sm text-foreground">
|
|
727
|
+
<thead className="border-b border-border bg-muted/50">
|
|
728
|
+
<tr>
|
|
729
|
+
<th className="px-3 py-2 text-left font-medium text-muted-foreground">Name</th>
|
|
730
|
+
<th className="px-3 py-2 text-left font-medium text-muted-foreground">Status</th>
|
|
731
|
+
</tr>
|
|
732
|
+
</thead>
|
|
733
|
+
<tbody>
|
|
734
|
+
<tr className="border-b border-border">
|
|
735
|
+
<td className="px-3 py-2">Item one</td>
|
|
736
|
+
<td className="px-3 py-2 text-muted-foreground">Active</td>
|
|
737
|
+
</tr>
|
|
738
|
+
</tbody>
|
|
739
|
+
</table>`
|
|
740
|
+
},
|
|
741
|
+
{
|
|
742
|
+
id: "form-block",
|
|
743
|
+
group: "form",
|
|
744
|
+
snippet: `<form className="flex flex-col gap-4">
|
|
745
|
+
<div className="flex flex-col gap-1.5">
|
|
746
|
+
<label className="text-sm font-medium leading-none text-foreground">Label</label>
|
|
747
|
+
<input type="text" placeholder="Enter value" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />
|
|
748
|
+
</div>
|
|
749
|
+
<button type="submit" className="inline-flex h-9 items-center justify-center self-start rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Submit</button>
|
|
750
|
+
</form>`
|
|
751
|
+
},
|
|
752
|
+
{
|
|
753
|
+
id: "form-text-field",
|
|
754
|
+
group: "form",
|
|
755
|
+
snippet: `<input type="text" placeholder="Enter text..." className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />`
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
id: "form-textarea",
|
|
759
|
+
group: "form",
|
|
760
|
+
snippet: `<textarea placeholder="Enter text..." rows="4" className="flex w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"></textarea>`
|
|
761
|
+
},
|
|
762
|
+
{
|
|
763
|
+
id: "form-checkbox",
|
|
764
|
+
group: "form",
|
|
765
|
+
snippet: `<label className="inline-flex items-center gap-2 text-sm text-foreground">
|
|
766
|
+
<span className="peer flex h-4 w-4 shrink-0 items-center justify-center rounded-sm border border-primary bg-primary text-primary-foreground shadow"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round" className="h-3 w-3"><polyline points="20 6 9 17 4 12"></polyline></svg></span>
|
|
767
|
+
<span>Accept terms</span>
|
|
768
|
+
</label>`
|
|
769
|
+
},
|
|
770
|
+
{
|
|
771
|
+
id: "form-switch",
|
|
772
|
+
group: "form",
|
|
773
|
+
snippet: `<label className="inline-flex items-center gap-2 text-sm text-foreground">
|
|
774
|
+
<span className="peer inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent bg-primary shadow-sm transition-colors">
|
|
775
|
+
<span className="pointer-events-none block h-4 w-4 translate-x-4 rounded-full bg-background shadow-lg ring-0 transition-transform"></span>
|
|
776
|
+
</span>
|
|
777
|
+
<span>Enable</span>
|
|
778
|
+
</label>`
|
|
779
|
+
},
|
|
780
|
+
{
|
|
781
|
+
id: "form-radio-group",
|
|
782
|
+
group: "form",
|
|
783
|
+
snippet: `<div className="flex flex-col gap-2 text-sm text-foreground" role="radiogroup">
|
|
784
|
+
<label className="inline-flex items-center gap-2">
|
|
785
|
+
<span className="aspect-square h-4 w-4 rounded-full border border-primary bg-background text-primary shadow flex items-center justify-center"><span className="h-2 w-2 rounded-full bg-primary"></span></span>
|
|
786
|
+
<span>Option A</span>
|
|
787
|
+
</label>
|
|
788
|
+
<label className="inline-flex items-center gap-2">
|
|
789
|
+
<span className="aspect-square h-4 w-4 rounded-full border border-primary bg-background shadow"></span>
|
|
790
|
+
<span>Option B</span>
|
|
791
|
+
</label>
|
|
792
|
+
<label className="inline-flex items-center gap-2">
|
|
793
|
+
<span className="aspect-square h-4 w-4 rounded-full border border-primary bg-background shadow"></span>
|
|
794
|
+
<span>Option C</span>
|
|
795
|
+
</label>
|
|
796
|
+
</div>`
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
id: "form-select",
|
|
800
|
+
group: "form",
|
|
801
|
+
snippet: `<button type="button" className="flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm text-foreground shadow-sm focus:outline-none focus:ring-1 focus:ring-ring">
|
|
802
|
+
<span>Option one</span>
|
|
803
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-4 w-4 opacity-50"><path d="m6 9 6 6 6-6" /></svg>
|
|
804
|
+
</button>`
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
id: "form-slider",
|
|
808
|
+
group: "form",
|
|
809
|
+
snippet: `<span className="relative flex w-full touch-none select-none items-center">
|
|
810
|
+
<span className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
|
|
811
|
+
<span className="absolute h-full bg-primary" style={{ width: '50%' }}></span>
|
|
812
|
+
</span>
|
|
813
|
+
<span className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors" style={{ position: 'absolute', left: '50%', transform: 'translateX(-50%)' }}></span>
|
|
814
|
+
</span>`
|
|
815
|
+
},
|
|
816
|
+
{
|
|
817
|
+
id: "form-date-picker",
|
|
818
|
+
group: "form",
|
|
819
|
+
snippet: `<input type="date" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />`
|
|
820
|
+
},
|
|
821
|
+
{
|
|
822
|
+
id: "form-time-picker",
|
|
823
|
+
group: "form",
|
|
824
|
+
snippet: `<input type="time" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />`
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
id: "form-search",
|
|
828
|
+
group: "form",
|
|
829
|
+
snippet: `<input type="search" placeholder="Search..." className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring" />`
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
id: "form-file-upload",
|
|
833
|
+
group: "form",
|
|
834
|
+
snippet: `<input type="file" className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm text-foreground shadow-sm file:mr-3 file:rounded-md file:border-0 file:bg-secondary file:px-3 file:py-1 file:text-sm file:font-medium file:text-secondary-foreground" />`
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
id: "kit-hero",
|
|
838
|
+
group: "archie-kit",
|
|
839
|
+
snippet: `<section className="relative overflow-hidden rounded-2xl border border-border bg-card px-8 py-16 md:px-12 md:py-20 md:grid md:grid-cols-2 md:items-center md:gap-10">
|
|
840
|
+
<div>
|
|
841
|
+
<div className="mb-3 text-xs font-semibold uppercase tracking-[0.2em] text-primary">New Release</div>
|
|
842
|
+
<h1 className="text-4xl font-extrabold leading-[1.05] tracking-tight text-foreground md:text-6xl">Launch products your team will love</h1>
|
|
843
|
+
<p className="mt-5 max-w-xl text-lg leading-relaxed text-muted-foreground md:text-xl">A single workspace for planning, building, and shipping \u2014 without the busywork that usually gets in the way.</p>
|
|
844
|
+
<div className="mt-8 flex flex-wrap gap-3">
|
|
845
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">Get started</button>
|
|
846
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors border border-border bg-transparent hover:bg-muted">Book a demo</button>
|
|
847
|
+
</div>
|
|
848
|
+
</div>
|
|
849
|
+
<div className="mt-10 md:mt-0">
|
|
850
|
+
<figure className="">
|
|
851
|
+
<div className="relative overflow-hidden bg-muted rounded-lg" style={{ aspectRatio: '16/9', backgroundImage: 'linear-gradient(135deg, hsl(var(--chart-1) / 0.92), hsl(var(--chart-3) / 0.65))' }}></div>
|
|
852
|
+
</figure>
|
|
853
|
+
</div>
|
|
854
|
+
</section>`
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
id: "kit-page-header",
|
|
858
|
+
group: "archie-kit",
|
|
859
|
+
snippet: `<div className="flex items-end justify-between gap-4 mb-6">
|
|
860
|
+
<div>
|
|
861
|
+
<div className="text-xs font-medium uppercase tracking-wider text-muted-foreground">Projects</div>
|
|
862
|
+
<h1 className="text-3xl font-extrabold tracking-tight">Acme Onboarding</h1>
|
|
863
|
+
<p className="mt-1 text-muted-foreground">Track setup tasks and milestones for the Acme rollout.</p>
|
|
864
|
+
</div>
|
|
865
|
+
<div className="flex gap-2">
|
|
866
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors border border-border bg-transparent hover:bg-muted">Export</button>
|
|
867
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">New task</button>
|
|
868
|
+
</div>
|
|
869
|
+
</div>`
|
|
870
|
+
},
|
|
871
|
+
{
|
|
872
|
+
id: "kit-section",
|
|
873
|
+
group: "archie-kit",
|
|
874
|
+
snippet: `<div className="rounded-lg border border-border bg-card text-card-foreground shadow-sm mb-6">
|
|
875
|
+
<div className="flex flex-row items-center justify-between gap-1 px-5 pt-5 pb-3">
|
|
876
|
+
<div>
|
|
877
|
+
<h3 className="text-base font-semibold tracking-tight">Recent activity</h3>
|
|
878
|
+
<p className="text-sm text-muted-foreground">The latest updates across this project.</p>
|
|
879
|
+
</div>
|
|
880
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md h-7 px-2 text-xs font-medium transition-colors hover:bg-muted">View all</button>
|
|
881
|
+
</div>
|
|
882
|
+
<div className="px-5 pb-5">
|
|
883
|
+
<p className="text-sm text-muted-foreground">No activity has been logged in the last 24 hours.</p>
|
|
884
|
+
</div>
|
|
885
|
+
</div>`
|
|
886
|
+
},
|
|
887
|
+
{
|
|
888
|
+
id: "kit-card",
|
|
889
|
+
group: "archie-kit",
|
|
890
|
+
snippet: `<div className="rounded-lg border border-border bg-card text-card-foreground shadow-sm">
|
|
891
|
+
<div className="flex flex-col gap-1 px-5 pt-5 pb-3">
|
|
892
|
+
<h3 className="text-base font-semibold tracking-tight">Storage usage</h3>
|
|
893
|
+
<p className="text-sm text-muted-foreground">How much of your plan's storage is in use.</p>
|
|
894
|
+
</div>
|
|
895
|
+
<div className="px-5 pb-5">
|
|
896
|
+
<p className="text-sm">42.3 GB of 100 GB used across 3 workspaces.</p>
|
|
897
|
+
</div>
|
|
898
|
+
</div>`
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
id: "kit-status-badge",
|
|
902
|
+
group: "archie-kit",
|
|
903
|
+
snippet: `<span className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium bg-success/15 text-success">
|
|
904
|
+
<span className="h-1.5 w-1.5 rounded-full bg-current"></span>
|
|
905
|
+
Active
|
|
906
|
+
</span>`
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
id: "kit-data-table",
|
|
910
|
+
group: "archie-kit",
|
|
911
|
+
snippet: `<div>
|
|
912
|
+
<div className="mb-3 flex items-center justify-between gap-2">
|
|
913
|
+
<div className="relative">
|
|
914
|
+
<svg className="pointer-events-none absolute left-2.5 top-2.5 text-muted-foreground" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8"></circle><path d="m21 21-4.3-4.3"></path></svg>
|
|
915
|
+
<input value="" placeholder="Search\u2026" className="w-64 rounded-md border border-input bg-background py-1.5 pl-8 pr-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" />
|
|
916
|
+
</div>
|
|
917
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">
|
|
918
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14"></path><path d="M12 5v14"></path></svg>
|
|
919
|
+
New order
|
|
920
|
+
</button>
|
|
921
|
+
</div>
|
|
922
|
+
<div className="overflow-x-auto">
|
|
923
|
+
<table className="w-full text-sm">
|
|
924
|
+
<thead>
|
|
925
|
+
<tr className="border-b border-border text-left text-xs uppercase tracking-wider text-muted-foreground">
|
|
926
|
+
<th scope="col" className="pb-2 font-medium cursor-pointer select-none">Order</th>
|
|
927
|
+
<th scope="col" className="pb-2 font-medium cursor-pointer select-none">Customer</th>
|
|
928
|
+
<th scope="col" className="pb-2 font-medium cursor-pointer select-none">Status</th>
|
|
929
|
+
<th scope="col" className="pb-2 font-medium cursor-pointer select-none text-right">Amount</th>
|
|
930
|
+
<th scope="col" className="pb-2 font-medium text-right">Actions</th>
|
|
931
|
+
</tr>
|
|
932
|
+
</thead>
|
|
933
|
+
<tbody>
|
|
934
|
+
<tr className="border-b border-border/60 transition-colors hover:bg-muted/40">
|
|
935
|
+
<td className="py-3 font-mono tabular-nums">ORD-1044</td>
|
|
936
|
+
<td className="py-3">Acme Corp</td>
|
|
937
|
+
<td className="py-3"><span className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium bg-success/15 text-success"><span className="h-1.5 w-1.5 rounded-full bg-current"></span>Paid</span></td>
|
|
938
|
+
<td className="py-3 font-mono tabular-nums text-right">$1,240.00</td>
|
|
939
|
+
<td className="py-3 text-right"><div className="inline-flex gap-1"><button className="inline-flex items-center justify-center gap-2 rounded-md h-7 px-2 text-xs font-medium transition-colors hover:bg-muted">View</button></div></td>
|
|
940
|
+
</tr>
|
|
941
|
+
<tr className="border-b border-border/60 transition-colors hover:bg-muted/40">
|
|
942
|
+
<td className="py-3 font-mono tabular-nums">ORD-1043</td>
|
|
943
|
+
<td className="py-3">Globex Inc</td>
|
|
944
|
+
<td className="py-3"><span className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium bg-primary/15 text-primary"><span className="h-1.5 w-1.5 rounded-full bg-current"></span>Pending</span></td>
|
|
945
|
+
<td className="py-3 font-mono tabular-nums text-right">$860.00</td>
|
|
946
|
+
<td className="py-3 text-right"><div className="inline-flex gap-1"><button className="inline-flex items-center justify-center gap-2 rounded-md h-7 px-2 text-xs font-medium transition-colors hover:bg-muted">View</button></div></td>
|
|
947
|
+
</tr>
|
|
948
|
+
<tr className="border-b border-border/60 transition-colors hover:bg-muted/40">
|
|
949
|
+
<td className="py-3 font-mono tabular-nums">ORD-1042</td>
|
|
950
|
+
<td className="py-3">Initech</td>
|
|
951
|
+
<td className="py-3"><span className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium bg-destructive/15 text-destructive"><span className="h-1.5 w-1.5 rounded-full bg-current"></span>Overdue</span></td>
|
|
952
|
+
<td className="py-3 font-mono tabular-nums text-right">$2,150.00</td>
|
|
953
|
+
<td className="py-3 text-right"><div className="inline-flex gap-1"><button className="inline-flex items-center justify-center gap-2 rounded-md h-7 px-2 text-xs font-medium transition-colors hover:bg-muted">View</button></div></td>
|
|
954
|
+
</tr>
|
|
955
|
+
<tr className="border-b border-border/60 transition-colors hover:bg-muted/40">
|
|
956
|
+
<td className="py-3 font-mono tabular-nums">ORD-1041</td>
|
|
957
|
+
<td className="py-3">Umbrella LLC</td>
|
|
958
|
+
<td className="py-3"><span className="inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium bg-success/15 text-success"><span className="h-1.5 w-1.5 rounded-full bg-current"></span>Paid</span></td>
|
|
959
|
+
<td className="py-3 font-mono tabular-nums text-right">$430.00</td>
|
|
960
|
+
<td className="py-3 text-right"><div className="inline-flex gap-1"><button className="inline-flex items-center justify-center gap-2 rounded-md h-7 px-2 text-xs font-medium transition-colors hover:bg-muted">View</button></div></td>
|
|
961
|
+
</tr>
|
|
962
|
+
</tbody>
|
|
963
|
+
</table>
|
|
964
|
+
</div>
|
|
965
|
+
</div>`
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
id: "kit-spec-grid",
|
|
969
|
+
group: "archie-kit",
|
|
970
|
+
snippet: `<div className="rounded-lg border border-border bg-card text-card-foreground shadow-sm">
|
|
971
|
+
<div className="p-5">
|
|
972
|
+
<dl className="grid grid-cols-1 gap-x-6 gap-y-4 sm:grid-cols-2 lg:grid-cols-3">
|
|
973
|
+
<div>
|
|
974
|
+
<dt className="text-xs uppercase tracking-wider text-muted-foreground">Order ID</dt>
|
|
975
|
+
<dd className="mt-1 font-mono tabular-nums">ORD-1044</dd>
|
|
976
|
+
</div>
|
|
977
|
+
<div>
|
|
978
|
+
<dt className="text-xs uppercase tracking-wider text-muted-foreground">Customer</dt>
|
|
979
|
+
<dd className="mt-1 font-medium">Acme Corp</dd>
|
|
980
|
+
</div>
|
|
981
|
+
<div>
|
|
982
|
+
<dt className="text-xs uppercase tracking-wider text-muted-foreground">Amount</dt>
|
|
983
|
+
<dd className="mt-1 font-mono tabular-nums">$1,240.00</dd>
|
|
984
|
+
</div>
|
|
985
|
+
<div>
|
|
986
|
+
<dt className="text-xs uppercase tracking-wider text-muted-foreground">Placed on</dt>
|
|
987
|
+
<dd className="mt-1 font-medium">Mar 4, 2026</dd>
|
|
988
|
+
</div>
|
|
989
|
+
</dl>
|
|
990
|
+
</div>
|
|
991
|
+
</div>`
|
|
992
|
+
},
|
|
993
|
+
{
|
|
994
|
+
id: "kit-timeline",
|
|
995
|
+
group: "archie-kit",
|
|
996
|
+
snippet: `<div className="rounded-lg border border-border bg-card text-card-foreground shadow-sm">
|
|
997
|
+
<div className="p-5">
|
|
998
|
+
<ol className="space-y-4">
|
|
999
|
+
<li className="flex gap-3">
|
|
1000
|
+
<span className="mt-1.5 h-2 w-2 shrink-0 rounded-full bg-primary"></span>
|
|
1001
|
+
<div>
|
|
1002
|
+
<div className="text-xs text-muted-foreground">Mar 4, 2026 \xB7 Sarah Chen</div>
|
|
1003
|
+
<div className="text-sm">Marked the order as paid.</div>
|
|
1004
|
+
</div>
|
|
1005
|
+
</li>
|
|
1006
|
+
<li className="flex gap-3">
|
|
1007
|
+
<span className="mt-1.5 h-2 w-2 shrink-0 rounded-full bg-primary"></span>
|
|
1008
|
+
<div>
|
|
1009
|
+
<div className="text-xs text-muted-foreground">Mar 3, 2026 \xB7 System</div>
|
|
1010
|
+
<div className="text-sm">Invoice #4471 sent to customer.</div>
|
|
1011
|
+
</div>
|
|
1012
|
+
</li>
|
|
1013
|
+
<li className="flex gap-3">
|
|
1014
|
+
<span className="mt-1.5 h-2 w-2 shrink-0 rounded-full bg-primary"></span>
|
|
1015
|
+
<div>
|
|
1016
|
+
<div className="text-xs text-muted-foreground">Mar 1, 2026 \xB7 Diego Ramirez</div>
|
|
1017
|
+
<div className="text-sm">Order created from quote Q-2201.</div>
|
|
1018
|
+
</div>
|
|
1019
|
+
</li>
|
|
1020
|
+
</ol>
|
|
1021
|
+
</div>
|
|
1022
|
+
</div>`
|
|
1023
|
+
},
|
|
1024
|
+
{
|
|
1025
|
+
id: "kit-form-field",
|
|
1026
|
+
group: "archie-kit",
|
|
1027
|
+
snippet: `<label className="block text-sm">
|
|
1028
|
+
<span className="font-medium">Email address</span>
|
|
1029
|
+
<input type="email" placeholder="you@company.com" className="mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" />
|
|
1030
|
+
<span className="mt-1 block text-xs text-muted-foreground">We'll never share your email with anyone else.</span>
|
|
1031
|
+
</label>`
|
|
1032
|
+
},
|
|
1033
|
+
{
|
|
1034
|
+
id: "kit-dialog",
|
|
1035
|
+
group: "archie-kit",
|
|
1036
|
+
snippet: `<div className="fixed inset-0 z-[1050] flex items-center justify-center" role="dialog" aria-modal="true">
|
|
1037
|
+
<div className="absolute inset-0 bg-black/50"></div>
|
|
1038
|
+
<div className="relative w-full max-w-md rounded-lg border border-border bg-card shadow-lg p-6">
|
|
1039
|
+
<h2 className="text-lg font-semibold">Create contact</h2>
|
|
1040
|
+
<p className="mt-1 text-sm text-muted-foreground">Add a new contact to this project.</p>
|
|
1041
|
+
<div className="mt-4 space-y-3">
|
|
1042
|
+
<label className="block text-sm">
|
|
1043
|
+
<span className="font-medium">Full name</span>
|
|
1044
|
+
<input className="mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" value="" />
|
|
1045
|
+
</label>
|
|
1046
|
+
<label className="block text-sm">
|
|
1047
|
+
<span className="font-medium">Email</span>
|
|
1048
|
+
<input className="mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring" value="" />
|
|
1049
|
+
</label>
|
|
1050
|
+
</div>
|
|
1051
|
+
<div className="mt-5 flex justify-end gap-2">
|
|
1052
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors border border-border bg-transparent hover:bg-muted">Cancel</button>
|
|
1053
|
+
<button className="inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90">Create</button>
|
|
1054
|
+
</div>
|
|
1055
|
+
</div>
|
|
1056
|
+
</div>`
|
|
1057
|
+
},
|
|
1058
|
+
{
|
|
1059
|
+
id: "kit-figure",
|
|
1060
|
+
group: "archie-kit",
|
|
1061
|
+
snippet: `<figure>
|
|
1062
|
+
<div className="relative overflow-hidden bg-muted rounded-lg" style={{ aspectRatio: '16/9', backgroundImage: 'linear-gradient(135deg, hsl(var(--chart-2) / 0.92), hsl(var(--chart-4) / 0.65))' }}></div>
|
|
1063
|
+
<figcaption className="mt-2 text-sm text-muted-foreground">Product screenshot, dashboard overview.</figcaption>
|
|
1064
|
+
</figure>`
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
id: "kit-article",
|
|
1068
|
+
group: "archie-kit",
|
|
1069
|
+
snippet: `<article className="max-w-[65ch] text-[1.0625rem] leading-[1.75] text-foreground">
|
|
1070
|
+
<div className="mb-2 text-xs font-semibold uppercase tracking-[0.2em] text-primary">Engineering</div>
|
|
1071
|
+
<h1 className="mb-4 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl">Why we rebuilt our onboarding flow</h1>
|
|
1072
|
+
<p className="mb-6 text-xl leading-relaxed text-muted-foreground">A look at the research, the tradeoffs, and what shipped after three months of iteration.</p>
|
|
1073
|
+
|
|
1074
|
+
<p className="mb-5 first-letter:float-left first-letter:mr-3 first-letter:text-[3.4em] first-letter:font-bold first-letter:leading-[0.72] first-letter:text-primary">Onboarding is the first real conversation a new customer has with a product, and for years ours said the wrong things. Teams dropped off before ever seeing the value we'd promised them.</p>
|
|
1075
|
+
<p className="mb-5">We started by mapping every step a customer took in their first week, then cut anything that didn't lead directly to their first success moment.</p>
|
|
1076
|
+
|
|
1077
|
+
<h2 className="mt-8 mb-2 text-2xl font-bold tracking-tight text-foreground">What changed</h2>
|
|
1078
|
+
<p className="mb-5">The new flow leans on progressive disclosure: ask for less up front, and surface advanced options only once a team is ready for them.</p>
|
|
1079
|
+
<ul className="mb-5 list-disc pl-6">
|
|
1080
|
+
<li className="my-1.5">Reduced required setup fields from 12 to 4</li>
|
|
1081
|
+
<li className="my-1.5">Replaced the tour modal with inline, contextual tips</li>
|
|
1082
|
+
<li className="my-1.5">Added a visible progress indicator across every step</li>
|
|
1083
|
+
</ul>
|
|
1084
|
+
|
|
1085
|
+
<blockquote className="my-7 border-l-[3px] border-primary py-1 pl-5 text-[1.375rem] italic leading-normal text-foreground">
|
|
1086
|
+
The best onboarding doesn't feel like onboarding \u2014 it feels like the product already worked.
|
|
1087
|
+
<cite className="mt-2 block text-sm not-italic text-muted-foreground">\u2014 Head of Product</cite>
|
|
1088
|
+
</blockquote>
|
|
1089
|
+
</article>`
|
|
1090
|
+
},
|
|
1091
|
+
{
|
|
1092
|
+
id: "kit-empty-state",
|
|
1093
|
+
group: "archie-kit",
|
|
1094
|
+
snippet: `<div className="py-10 text-center">
|
|
1095
|
+
<div className="text-sm font-medium">No records</div>
|
|
1096
|
+
<div className="mt-1 text-sm text-muted-foreground">Nothing here yet \u2014 new items will show up as they're created.</div>
|
|
1097
|
+
</div>`
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
id: "kit-doc-nav",
|
|
1101
|
+
group: "archie-kit",
|
|
1102
|
+
snippet: `<nav aria-label="Documentation" className="text-sm">
|
|
1103
|
+
<div className="mb-3 px-2 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Documentation</div>
|
|
1104
|
+
<div className="mb-4">
|
|
1105
|
+
<div className="px-2 pb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Getting Started</div>
|
|
1106
|
+
<a href="#" aria-current="page" className="block rounded-md px-2 py-1.5 bg-primary/10 font-medium text-primary transition-colors">Introduction</a>
|
|
1107
|
+
<a href="#" className="block rounded-md px-2 py-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">Installation</a>
|
|
1108
|
+
<a href="#" className="block rounded-md px-2 py-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">Quick Start</a>
|
|
1109
|
+
</div>
|
|
1110
|
+
<div className="mb-4">
|
|
1111
|
+
<div className="px-2 pb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Guides</div>
|
|
1112
|
+
<a href="#" className="block rounded-md px-2 py-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">Authentication</a>
|
|
1113
|
+
<a href="#" className="block rounded-md px-2 py-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">Deployment</a>
|
|
1114
|
+
<a href="#" className="block rounded-md px-2 py-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">Webhooks</a>
|
|
1115
|
+
</div>
|
|
1116
|
+
</nav>`
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
id: "hero-section",
|
|
1120
|
+
group: "templates",
|
|
1121
|
+
snippet: `<section className="flex flex-col items-center justify-center gap-6 bg-background px-6 py-24 text-center">
|
|
1122
|
+
<h1 className="text-5xl font-bold tracking-tight text-foreground">Welcome to Our Platform</h1>
|
|
1123
|
+
<p className="max-w-2xl text-lg text-muted-foreground">A brief description of your product or service that captures attention and drives action.</p>
|
|
1124
|
+
<div className="flex gap-4">
|
|
1125
|
+
<button className="inline-flex h-11 items-center justify-center rounded-md bg-primary px-8 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Get Started</button>
|
|
1126
|
+
<button className="inline-flex h-11 items-center justify-center rounded-md border border-input bg-background px-8 text-sm font-medium text-foreground shadow-sm hover:bg-accent hover:text-accent-foreground transition-colors">Learn More</button>
|
|
1127
|
+
</div>
|
|
1128
|
+
</section>`
|
|
1129
|
+
},
|
|
1130
|
+
{
|
|
1131
|
+
id: "feature-card",
|
|
1132
|
+
group: "templates",
|
|
1133
|
+
snippet: `<div className="overflow-hidden rounded-xl border border-border bg-card text-card-foreground shadow-sm">
|
|
1134
|
+
<img src="https://placehold.co/400x200" alt="Card image" className="h-48 w-full object-cover" />
|
|
1135
|
+
<div className="p-6">
|
|
1136
|
+
<h3 className="text-lg font-semibold leading-none tracking-tight">Card Title</h3>
|
|
1137
|
+
<p className="mt-2 text-sm text-muted-foreground">A short description that provides context about this card's content.</p>
|
|
1138
|
+
</div>
|
|
1139
|
+
</div>`
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
id: "feature-grid",
|
|
1143
|
+
group: "templates",
|
|
1144
|
+
snippet: `<section className="bg-background px-6 py-16">
|
|
1145
|
+
<h2 className="mb-12 text-center text-3xl font-bold text-foreground">Features</h2>
|
|
1146
|
+
<div className="grid grid-cols-1 gap-8 md:grid-cols-3">
|
|
1147
|
+
<div className="flex flex-col items-center text-center">
|
|
1148
|
+
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">\u2726</div>
|
|
1149
|
+
<h3 className="text-lg font-semibold text-foreground">Feature One</h3>
|
|
1150
|
+
<p className="mt-2 text-sm text-muted-foreground">Brief description of this feature and its benefits.</p>
|
|
1151
|
+
</div>
|
|
1152
|
+
<div className="flex flex-col items-center text-center">
|
|
1153
|
+
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">\u2726</div>
|
|
1154
|
+
<h3 className="text-lg font-semibold text-foreground">Feature Two</h3>
|
|
1155
|
+
<p className="mt-2 text-sm text-muted-foreground">Brief description of this feature and its benefits.</p>
|
|
1156
|
+
</div>
|
|
1157
|
+
<div className="flex flex-col items-center text-center">
|
|
1158
|
+
<div className="mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 text-primary">\u2726</div>
|
|
1159
|
+
<h3 className="text-lg font-semibold text-foreground">Feature Three</h3>
|
|
1160
|
+
<p className="mt-2 text-sm text-muted-foreground">Brief description of this feature and its benefits.</p>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
</section>`
|
|
1164
|
+
},
|
|
1165
|
+
{
|
|
1166
|
+
id: "cta-banner",
|
|
1167
|
+
group: "templates",
|
|
1168
|
+
snippet: `<section className="rounded-2xl bg-primary px-6 py-16 text-center text-primary-foreground">
|
|
1169
|
+
<h2 className="text-3xl font-bold">Ready to Get Started?</h2>
|
|
1170
|
+
<p className="mx-auto mt-4 max-w-xl text-lg opacity-90">Join thousands of users who are already building amazing things.</p>
|
|
1171
|
+
<button className="mt-8 inline-flex h-11 items-center justify-center rounded-md bg-background px-8 text-sm font-medium text-foreground shadow hover:bg-background/90 transition-colors">Start Free Trial</button>
|
|
1172
|
+
</section>`
|
|
1173
|
+
},
|
|
1174
|
+
{
|
|
1175
|
+
id: "pricing-card",
|
|
1176
|
+
group: "templates",
|
|
1177
|
+
snippet: `<div className="rounded-xl border border-border bg-card p-8 text-card-foreground shadow-sm">
|
|
1178
|
+
<h3 className="text-lg font-semibold">Pro Plan</h3>
|
|
1179
|
+
<div className="mt-4 flex items-baseline gap-1">
|
|
1180
|
+
<span className="text-4xl font-bold text-foreground">$29</span>
|
|
1181
|
+
<span className="text-muted-foreground">/month</span>
|
|
1182
|
+
</div>
|
|
1183
|
+
<ul className="mt-6 space-y-3 text-sm text-muted-foreground">
|
|
1184
|
+
<li className="flex items-center gap-2"><span className="text-primary">\u2713</span> Unlimited projects</li>
|
|
1185
|
+
<li className="flex items-center gap-2"><span className="text-primary">\u2713</span> Priority support</li>
|
|
1186
|
+
<li className="flex items-center gap-2"><span className="text-primary">\u2713</span> Advanced analytics</li>
|
|
1187
|
+
<li className="flex items-center gap-2"><span className="text-primary">\u2713</span> Custom integrations</li>
|
|
1188
|
+
</ul>
|
|
1189
|
+
<button className="mt-8 inline-flex h-11 w-full items-center justify-center rounded-md bg-primary text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Choose Plan</button>
|
|
1190
|
+
</div>`
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
id: "testimonial",
|
|
1194
|
+
group: "templates",
|
|
1195
|
+
snippet: `<div className="rounded-xl border border-border bg-card p-8 text-card-foreground">
|
|
1196
|
+
<p className="italic text-foreground">"This product has completely transformed how we work. The team is more productive and our clients are happier."</p>
|
|
1197
|
+
<div className="mt-6 flex items-center gap-3">
|
|
1198
|
+
<div className="h-10 w-10 rounded-full bg-muted"></div>
|
|
1199
|
+
<div>
|
|
1200
|
+
<p className="text-sm font-semibold text-foreground">Jane Smith</p>
|
|
1201
|
+
<p className="text-xs text-muted-foreground">CEO, Acme Corp</p>
|
|
1202
|
+
</div>
|
|
1203
|
+
</div>
|
|
1204
|
+
</div>`
|
|
1205
|
+
},
|
|
1206
|
+
{
|
|
1207
|
+
id: "footer-template",
|
|
1208
|
+
group: "templates",
|
|
1209
|
+
snippet: `<footer className="border-t border-border bg-background px-6 py-12">
|
|
1210
|
+
<div className="flex flex-col items-center gap-6 md:flex-row md:justify-between">
|
|
1211
|
+
<p className="text-sm text-muted-foreground">\xA9 2025 Company Name. All rights reserved.</p>
|
|
1212
|
+
<nav className="flex gap-6">
|
|
1213
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Privacy</a>
|
|
1214
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Terms</a>
|
|
1215
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Contact</a>
|
|
1216
|
+
</nav>
|
|
1217
|
+
</div>
|
|
1218
|
+
</footer>`
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
id: "navbar-template",
|
|
1222
|
+
group: "templates",
|
|
1223
|
+
snippet: `<nav className="flex items-center justify-between border-b border-border bg-background px-6 py-4">
|
|
1224
|
+
<span className="text-lg font-bold text-foreground">Logo</span>
|
|
1225
|
+
<div className="flex items-center gap-6">
|
|
1226
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Home</a>
|
|
1227
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Features</a>
|
|
1228
|
+
<a href="#" className="text-sm text-muted-foreground hover:text-foreground transition-colors">Pricing</a>
|
|
1229
|
+
<button className="inline-flex h-9 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground shadow hover:bg-primary/90 transition-colors">Sign Up</button>
|
|
1230
|
+
</div>
|
|
1231
|
+
</nav>`
|
|
1232
|
+
},
|
|
1233
|
+
{
|
|
1234
|
+
id: "shadcn-button",
|
|
1235
|
+
group: "shadcn",
|
|
1236
|
+
snippet: "<Button>Button</Button>",
|
|
1237
|
+
importRequirements: [{ module: "@/components/ui/button", named: ["Button"] }]
|
|
1238
|
+
},
|
|
1239
|
+
{
|
|
1240
|
+
id: "shadcn-icon-button-delete",
|
|
1241
|
+
group: "shadcn",
|
|
1242
|
+
snippet: '<Button variant="outline" size="icon"><Trash2 className="h-4 w-4" /></Button>',
|
|
1243
|
+
importRequirements: [
|
|
1244
|
+
{ module: "@/components/ui/button", named: ["Button"] },
|
|
1245
|
+
{ module: "lucide-react", named: ["Trash2"] }
|
|
1246
|
+
]
|
|
1247
|
+
},
|
|
1248
|
+
{
|
|
1249
|
+
id: "shadcn-badge",
|
|
1250
|
+
group: "shadcn",
|
|
1251
|
+
snippet: `<Badge>Badge</Badge>`,
|
|
1252
|
+
importRequirements: [
|
|
1253
|
+
{ module: "@/components/ui/badge", named: ["Badge"] }
|
|
1254
|
+
]
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
id: "shadcn-card",
|
|
1258
|
+
group: "shadcn",
|
|
1259
|
+
snippet: `<Card>
|
|
1260
|
+
<CardHeader>
|
|
1261
|
+
<CardTitle>Card Title</CardTitle>
|
|
1262
|
+
<CardDescription>Card description goes here.</CardDescription>
|
|
1263
|
+
</CardHeader>
|
|
1264
|
+
</Card>`,
|
|
1265
|
+
importRequirements: [
|
|
1266
|
+
{ module: "@/components/ui/card", named: ["Card", "CardHeader", "CardTitle", "CardDescription"] }
|
|
1267
|
+
]
|
|
1268
|
+
},
|
|
1269
|
+
{
|
|
1270
|
+
id: "shadcn-form-text-field",
|
|
1271
|
+
group: "shadcn",
|
|
1272
|
+
snippet: `<Input type="text" placeholder="Enter text..." />`,
|
|
1273
|
+
importRequirements: [
|
|
1274
|
+
{ module: "@/components/ui/input", named: ["Input"] }
|
|
1275
|
+
]
|
|
1276
|
+
},
|
|
1277
|
+
{
|
|
1278
|
+
id: "shadcn-form-textarea",
|
|
1279
|
+
group: "shadcn",
|
|
1280
|
+
snippet: `<Textarea placeholder="Enter text..." rows={4} />`,
|
|
1281
|
+
importRequirements: [
|
|
1282
|
+
{ module: "@/components/ui/textarea", named: ["Textarea"] }
|
|
1283
|
+
]
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
id: "shadcn-form-checkbox",
|
|
1287
|
+
group: "shadcn",
|
|
1288
|
+
snippet: `<div className="flex items-center gap-2">
|
|
1289
|
+
<Checkbox id="terms" defaultChecked />
|
|
1290
|
+
<label htmlFor="terms" className="text-sm font-medium leading-none">Accept terms</label>
|
|
1291
|
+
</div>`,
|
|
1292
|
+
importRequirements: [
|
|
1293
|
+
{ module: "@/components/ui/checkbox", named: ["Checkbox"] }
|
|
1294
|
+
]
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
id: "shadcn-form-switch",
|
|
1298
|
+
group: "shadcn",
|
|
1299
|
+
snippet: `<div className="flex items-center gap-2">
|
|
1300
|
+
<Switch id="enable" defaultChecked />
|
|
1301
|
+
<label htmlFor="enable" className="text-sm font-medium leading-none">Enable</label>
|
|
1302
|
+
</div>`,
|
|
1303
|
+
importRequirements: [
|
|
1304
|
+
{ module: "@/components/ui/switch", named: ["Switch"] }
|
|
1305
|
+
]
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
id: "shadcn-form-radio-group",
|
|
1309
|
+
group: "shadcn",
|
|
1310
|
+
snippet: `<RadioGroup defaultValue="a" className="flex flex-col gap-2">
|
|
1311
|
+
<div className="flex items-center gap-2">
|
|
1312
|
+
<RadioGroupItem value="a" id="opt-a" />
|
|
1313
|
+
<label htmlFor="opt-a" className="text-sm font-medium leading-none">Option A</label>
|
|
1314
|
+
</div>
|
|
1315
|
+
<div className="flex items-center gap-2">
|
|
1316
|
+
<RadioGroupItem value="b" id="opt-b" />
|
|
1317
|
+
<label htmlFor="opt-b" className="text-sm font-medium leading-none">Option B</label>
|
|
1318
|
+
</div>
|
|
1319
|
+
<div className="flex items-center gap-2">
|
|
1320
|
+
<RadioGroupItem value="c" id="opt-c" />
|
|
1321
|
+
<label htmlFor="opt-c" className="text-sm font-medium leading-none">Option C</label>
|
|
1322
|
+
</div>
|
|
1323
|
+
</RadioGroup>`,
|
|
1324
|
+
importRequirements: [
|
|
1325
|
+
{ module: "@/components/ui/radio-group", named: ["RadioGroup", "RadioGroupItem"] }
|
|
1326
|
+
]
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
id: "shadcn-form-select",
|
|
1330
|
+
group: "shadcn",
|
|
1331
|
+
snippet: `<Select defaultValue="one">
|
|
1332
|
+
<SelectTrigger className="w-full">
|
|
1333
|
+
<SelectValue placeholder="Select an option" />
|
|
1334
|
+
</SelectTrigger>
|
|
1335
|
+
<SelectContent>
|
|
1336
|
+
<SelectItem value="one">Option one</SelectItem>
|
|
1337
|
+
<SelectItem value="two">Option two</SelectItem>
|
|
1338
|
+
<SelectItem value="three">Option three</SelectItem>
|
|
1339
|
+
</SelectContent>
|
|
1340
|
+
</Select>`,
|
|
1341
|
+
importRequirements: [
|
|
1342
|
+
{ module: "@/components/ui/select", named: ["Select", "SelectContent", "SelectItem", "SelectTrigger", "SelectValue"] }
|
|
1343
|
+
]
|
|
1344
|
+
},
|
|
1345
|
+
{
|
|
1346
|
+
id: "shadcn-form-slider",
|
|
1347
|
+
group: "shadcn",
|
|
1348
|
+
snippet: `<Slider defaultValue={[50]} max={100} step={1} />`,
|
|
1349
|
+
importRequirements: [
|
|
1350
|
+
{ module: "@/components/ui/slider", named: ["Slider"] }
|
|
1351
|
+
]
|
|
1352
|
+
},
|
|
1353
|
+
{
|
|
1354
|
+
id: "shadcn-form-search",
|
|
1355
|
+
group: "shadcn",
|
|
1356
|
+
snippet: `<Input type="search" placeholder="Search..." />`,
|
|
1357
|
+
importRequirements: [
|
|
1358
|
+
{ module: "@/components/ui/input", named: ["Input"] }
|
|
1359
|
+
]
|
|
1360
|
+
},
|
|
1361
|
+
{
|
|
1362
|
+
id: "shadcn-form-file-upload",
|
|
1363
|
+
group: "shadcn",
|
|
1364
|
+
snippet: `<Input type="file" />`,
|
|
1365
|
+
importRequirements: [
|
|
1366
|
+
{ module: "@/components/ui/input", named: ["Input"] }
|
|
1367
|
+
]
|
|
1368
|
+
}
|
|
1369
|
+
];
|
|
1370
|
+
var byId = new Map(PALETTE_CATALOG.map((e) => [e.id, e]));
|
|
1371
|
+
|
|
1372
|
+
// src/babel-plugin-editor-meta.ts
|
|
1373
|
+
import * as nodePath from "path";
|
|
1374
|
+
function meaningfulChildren(t, children) {
|
|
1375
|
+
return children.filter((child) => {
|
|
1376
|
+
if (t.isJSXText(child)) return child.value.trim() !== "";
|
|
1377
|
+
if (t.isJSXExpressionContainer(child)) return !t.isJSXEmptyExpression(child.expression);
|
|
1378
|
+
return true;
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
var KIT_SLOT_ATTR = "data-kit-slot";
|
|
1382
|
+
var MAX_SLOT_SEGMENTS = 4;
|
|
1383
|
+
var NON_BINDING_ATTRS = /* @__PURE__ */ new Set(["__editorMeta", "key", "ref", KIT_SLOT_ATTR]);
|
|
1384
|
+
var STRUCTURAL_ATTRS = /* @__PURE__ */ new Set([
|
|
1385
|
+
"id",
|
|
1386
|
+
"htmlFor",
|
|
1387
|
+
"slot",
|
|
1388
|
+
"name",
|
|
1389
|
+
"type",
|
|
1390
|
+
"role",
|
|
1391
|
+
// The camelCase carrier of the SAME durable key as `data-agent-id`: kit
|
|
1392
|
+
// components take `agentId` and render it as the data attribute. Found on the
|
|
1393
|
+
// real corpus (×4) — blocking only the dashed form would have left the prop
|
|
1394
|
+
// form routable, and a durable key with a string-literal usage value sails
|
|
1395
|
+
// straight through the usage-value law.
|
|
1396
|
+
"agentId"
|
|
1397
|
+
]);
|
|
1398
|
+
function isNonContentAttribute(name) {
|
|
1399
|
+
if (/^on[A-Z]/.test(name)) return true;
|
|
1400
|
+
if (name.startsWith("data-")) return true;
|
|
1401
|
+
return STRUCTURAL_ATTRS.has(name);
|
|
1402
|
+
}
|
|
1403
|
+
function normalizeSlot(raw) {
|
|
1404
|
+
const value = raw.trim();
|
|
1405
|
+
if (!value) return null;
|
|
1406
|
+
const segments = value.split("/");
|
|
1407
|
+
if (segments.length > MAX_SLOT_SEGMENTS) return null;
|
|
1408
|
+
if (segments.some((segment) => segment.trim() === "")) return null;
|
|
1409
|
+
return value;
|
|
1410
|
+
}
|
|
1411
|
+
function isPackageImport(src) {
|
|
1412
|
+
if (src.startsWith(".") || src.startsWith("/")) return false;
|
|
1413
|
+
if (src.startsWith("@")) {
|
|
1414
|
+
const slashIdx = src.indexOf("/");
|
|
1415
|
+
if (slashIdx === 1) return false;
|
|
1416
|
+
if (slashIdx > 1) return true;
|
|
1417
|
+
return true;
|
|
1418
|
+
}
|
|
1419
|
+
if (src.startsWith("~/") || src.startsWith("#/")) return false;
|
|
1420
|
+
return true;
|
|
1421
|
+
}
|
|
1422
|
+
function babelPluginEditorMeta({ types: t }, opts = {}) {
|
|
1423
|
+
const {
|
|
1424
|
+
fileExclude = /node_modules/,
|
|
1425
|
+
instrumentImported = true,
|
|
1426
|
+
includeHostSourceRef = false,
|
|
1427
|
+
origin = "screen",
|
|
1428
|
+
templateOrigin = false,
|
|
1429
|
+
allowLegacyIds = true,
|
|
1430
|
+
onMissingVid
|
|
1431
|
+
} = opts;
|
|
1432
|
+
let missingVidWarned = false;
|
|
1433
|
+
function getJSXTagName(el) {
|
|
1434
|
+
const { name } = el;
|
|
1435
|
+
if (t.isJSXIdentifier(name)) return name.name;
|
|
1436
|
+
if (t.isJSXMemberExpression(name)) {
|
|
1437
|
+
const parts = [];
|
|
1438
|
+
let current = name;
|
|
1439
|
+
while (t.isJSXMemberExpression(current)) {
|
|
1440
|
+
parts.unshift(current.property.name);
|
|
1441
|
+
current = current.object;
|
|
1442
|
+
}
|
|
1443
|
+
if (t.isJSXIdentifier(current)) parts.unshift(current.name);
|
|
1444
|
+
return parts.join(".");
|
|
1445
|
+
}
|
|
1446
|
+
return "";
|
|
1447
|
+
}
|
|
1448
|
+
function isIntrinsicTagName(name) {
|
|
1449
|
+
return t.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
|
|
1450
|
+
}
|
|
1451
|
+
function isHostLikeMemberExpressionName(name) {
|
|
1452
|
+
if (!t.isJSXMemberExpression(name)) return false;
|
|
1453
|
+
const propertyName = name.property.name;
|
|
1454
|
+
return propertyName[0] === propertyName[0].toLowerCase();
|
|
1455
|
+
}
|
|
1456
|
+
function isStaticNamespaceDestructure(binding) {
|
|
1457
|
+
const bp = binding.path;
|
|
1458
|
+
if (!bp.isVariableDeclarator()) return false;
|
|
1459
|
+
if (!t.isObjectPattern(bp.node.id)) return false;
|
|
1460
|
+
if (!binding.constant) return false;
|
|
1461
|
+
const decl = bp.parentPath;
|
|
1462
|
+
if (decl?.isVariableDeclaration() && decl.node.kind !== "const") return false;
|
|
1463
|
+
let init = bp.node.init;
|
|
1464
|
+
while (init && (t.isTSAsExpression(init) || t.isTSNonNullExpression(init) || t.isTypeCastExpression(init))) {
|
|
1465
|
+
init = init.expression;
|
|
1466
|
+
}
|
|
1467
|
+
while (init && t.isMemberExpression(init) && !init.computed) {
|
|
1468
|
+
init = init.object;
|
|
1469
|
+
}
|
|
1470
|
+
if (!init || !t.isIdentifier(init)) return false;
|
|
1471
|
+
const rootBinding = bp.scope.getBinding(init.name);
|
|
1472
|
+
if (!rootBinding) return true;
|
|
1473
|
+
if (!rootBinding.constant) return false;
|
|
1474
|
+
return rootBinding.scope === rootBinding.scope.getProgramParent();
|
|
1475
|
+
}
|
|
1476
|
+
function computeNodeId(file, line, col, componentName) {
|
|
1477
|
+
return `${file}:${line}:${col}:${componentName}`;
|
|
1478
|
+
}
|
|
1479
|
+
function readVidAttr(attrs) {
|
|
1480
|
+
for (const attr of attrs) {
|
|
1481
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
1482
|
+
if (!t.isJSXIdentifier(attr.name, { name: VID_ATTR })) continue;
|
|
1483
|
+
const { value } = attr;
|
|
1484
|
+
let raw = null;
|
|
1485
|
+
if (t.isStringLiteral(value)) {
|
|
1486
|
+
raw = value.value;
|
|
1487
|
+
} else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) {
|
|
1488
|
+
raw = value.expression.value;
|
|
1489
|
+
}
|
|
1490
|
+
if (raw !== null && VID_PATTERN.test(raw)) return raw;
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
return null;
|
|
1494
|
+
}
|
|
1495
|
+
function computeDynamicType(path2) {
|
|
1496
|
+
let current = path2.parentPath;
|
|
1497
|
+
while (current) {
|
|
1498
|
+
if (current.isJSXExpressionContainer()) {
|
|
1499
|
+
const expr = current.node.expression;
|
|
1500
|
+
if (t.isConditionalExpression(expr) || t.isLogicalExpression(expr)) {
|
|
1501
|
+
return "CONDITIONAL";
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
if (current.isArrowFunctionExpression() || current.isFunctionExpression()) {
|
|
1505
|
+
const call = current.parentPath;
|
|
1506
|
+
if (call?.isCallExpression()) {
|
|
1507
|
+
const callee = call.node.callee;
|
|
1508
|
+
if (t.isMemberExpression(callee) && !callee.computed && t.isIdentifier(callee.property) && /^(map|flatMap|forEach)$/.test(callee.property.name)) {
|
|
1509
|
+
return "ARRAY";
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
break;
|
|
1513
|
+
}
|
|
1514
|
+
if (current.isFunctionDeclaration()) break;
|
|
1515
|
+
current = current.parentPath;
|
|
1516
|
+
}
|
|
1517
|
+
return "STATIC";
|
|
1518
|
+
}
|
|
1519
|
+
const SHELL_FILE_RE = /(^|\/)shell\.(jsx|tsx)$/;
|
|
1520
|
+
const SHELL_DIR_RE = /(^|\/)components\/shell\//;
|
|
1521
|
+
const SHELL_BASENAME_RE = /shell/i;
|
|
1522
|
+
const CHROME_ANCESTOR_TAGS = /* @__PURE__ */ new Set(["nav", "aside", "header"]);
|
|
1523
|
+
function isChromeFilePath(file) {
|
|
1524
|
+
if (SHELL_FILE_RE.test(file) || SHELL_DIR_RE.test(file)) return true;
|
|
1525
|
+
const base = file.split("/").pop() ?? file;
|
|
1526
|
+
return SHELL_BASENAME_RE.test(base);
|
|
1527
|
+
}
|
|
1528
|
+
function computeIsChrome(file, path2) {
|
|
1529
|
+
if (isChromeFilePath(file)) return true;
|
|
1530
|
+
let current = path2.parentPath;
|
|
1531
|
+
while (current) {
|
|
1532
|
+
if (current.isJSXElement()) {
|
|
1533
|
+
const tag = getJSXTagName(current.node.openingElement);
|
|
1534
|
+
if (CHROME_ANCESTOR_TAGS.has(tag)) return true;
|
|
1535
|
+
}
|
|
1536
|
+
current = current.parentPath;
|
|
1537
|
+
}
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
function computeContainerKind(path2) {
|
|
1541
|
+
const elPath = path2.parentPath;
|
|
1542
|
+
if (!elPath?.isJSXElement()) return "none";
|
|
1543
|
+
if (!elPath.node.closingElement) return "none";
|
|
1544
|
+
const children = elPath.node.children;
|
|
1545
|
+
const allPlain = children.every((c) => {
|
|
1546
|
+
if (t.isJSXElement(c)) return true;
|
|
1547
|
+
if (t.isJSXText(c)) return c.value.trim() === "";
|
|
1548
|
+
if (t.isJSXExpressionContainer(c) && t.isJSXEmptyExpression(c.expression)) return true;
|
|
1549
|
+
return false;
|
|
1550
|
+
});
|
|
1551
|
+
return allPlain ? "plain" : "expression";
|
|
1552
|
+
}
|
|
1553
|
+
const kitBoundNamesCache = /* @__PURE__ */ new WeakMap();
|
|
1554
|
+
function computeKitBoundNames(programPath) {
|
|
1555
|
+
const cached = kitBoundNamesCache.get(programPath.node);
|
|
1556
|
+
if (cached) return cached;
|
|
1557
|
+
const names = /* @__PURE__ */ new Set();
|
|
1558
|
+
for (const stmt of programPath.node.body) {
|
|
1559
|
+
if (!t.isVariableDeclaration(stmt)) continue;
|
|
1560
|
+
for (const decl of stmt.declarations) {
|
|
1561
|
+
if (!t.isObjectPattern(decl.id)) continue;
|
|
1562
|
+
if (!decl.init || !t.isIdentifier(decl.init) || decl.init.name !== "Kit") continue;
|
|
1563
|
+
for (const prop of decl.id.properties) {
|
|
1564
|
+
if (!t.isObjectProperty(prop)) continue;
|
|
1565
|
+
const value = t.isIdentifier(prop.value) ? prop.value : t.isIdentifier(prop.key) ? prop.key : null;
|
|
1566
|
+
if (value) names.add(value.name);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
kitBoundNamesCache.set(programPath.node, names);
|
|
1571
|
+
return names;
|
|
1572
|
+
}
|
|
1573
|
+
function isKitComponentTagName(path2) {
|
|
1574
|
+
const name = path2.node.name;
|
|
1575
|
+
let head = null;
|
|
1576
|
+
if (t.isJSXIdentifier(name)) {
|
|
1577
|
+
head = name.name;
|
|
1578
|
+
} else if (t.isJSXMemberExpression(name)) {
|
|
1579
|
+
let cur = name;
|
|
1580
|
+
while (t.isJSXMemberExpression(cur)) cur = cur.object;
|
|
1581
|
+
if (t.isJSXIdentifier(cur)) head = cur.name;
|
|
1582
|
+
}
|
|
1583
|
+
if (!head || !/^[A-Z]/.test(head)) return false;
|
|
1584
|
+
if (head === "Kit") return true;
|
|
1585
|
+
const programPath = path2.scope.getProgramParent().path;
|
|
1586
|
+
if (programPath.isProgram() && computeKitBoundNames(programPath).has(head)) return true;
|
|
1587
|
+
const binding = path2.scope.getBinding(head);
|
|
1588
|
+
if (binding) {
|
|
1589
|
+
const bp = binding.path;
|
|
1590
|
+
const isImport = bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier();
|
|
1591
|
+
if (isImport) {
|
|
1592
|
+
const decl = bp.parentPath;
|
|
1593
|
+
if (decl?.isImportDeclaration() && /kit-runtime/.test(decl.node.source.value)) return true;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
return false;
|
|
1597
|
+
}
|
|
1598
|
+
function computeLockReason(isKitOrigin, isChrome, dynamicType) {
|
|
1599
|
+
if (isKitOrigin) return "KIT_INTERNAL";
|
|
1600
|
+
if (isChrome) return "CHROME_STRUCTURAL";
|
|
1601
|
+
if (dynamicType === "ARRAY") return "DYNAMIC_ARRAY";
|
|
1602
|
+
if (dynamicType === "CONDITIONAL") return "DYNAMIC_CONDITIONAL";
|
|
1603
|
+
return void 0;
|
|
1604
|
+
}
|
|
1605
|
+
function isMovable(path2) {
|
|
1606
|
+
const elPath = path2.parentPath;
|
|
1607
|
+
if (!elPath) return false;
|
|
1608
|
+
const parentEl = elPath.parentPath;
|
|
1609
|
+
if (!parentEl || !parentEl.isJSXElement()) return false;
|
|
1610
|
+
const siblings = parentEl.node.children.filter(
|
|
1611
|
+
(c) => t.isJSXElement(c)
|
|
1612
|
+
);
|
|
1613
|
+
return siblings.length >= 2;
|
|
1614
|
+
}
|
|
1615
|
+
function getParentNodeId(path2, file) {
|
|
1616
|
+
const elPath = path2.parentPath;
|
|
1617
|
+
if (!elPath) return null;
|
|
1618
|
+
let ancestor = elPath.parentPath;
|
|
1619
|
+
while (ancestor) {
|
|
1620
|
+
if (ancestor.isJSXElement()) {
|
|
1621
|
+
const opening = ancestor.node.openingElement;
|
|
1622
|
+
const parentVid = readVidAttr(opening.attributes);
|
|
1623
|
+
if (parentVid) return parentVid;
|
|
1624
|
+
if (!allowLegacyIds) return null;
|
|
1625
|
+
const loc = opening.loc?.start;
|
|
1626
|
+
if (loc) {
|
|
1627
|
+
const tag = getJSXTagName(opening);
|
|
1628
|
+
return computeNodeId(file, loc.line, loc.column + 1, tag);
|
|
1629
|
+
}
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
ancestor = ancestor.parentPath;
|
|
1633
|
+
}
|
|
1634
|
+
return null;
|
|
1635
|
+
}
|
|
1636
|
+
function extractStaticProps(attrs) {
|
|
1637
|
+
const props = [];
|
|
1638
|
+
let hasAny = false;
|
|
1639
|
+
for (const attr of attrs) {
|
|
1640
|
+
if (t.isJSXSpreadAttribute(attr)) continue;
|
|
1641
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
1642
|
+
const keyName = t.isJSXIdentifier(attr.name) ? attr.name.name : attr.name.name.name;
|
|
1643
|
+
if (keyName === "__editorMeta") continue;
|
|
1644
|
+
let value;
|
|
1645
|
+
if (attr.value === null || attr.value === void 0) {
|
|
1646
|
+
value = t.booleanLiteral(true);
|
|
1647
|
+
} else if (t.isStringLiteral(attr.value)) {
|
|
1648
|
+
value = attr.value;
|
|
1649
|
+
} else if (t.isJSXExpressionContainer(attr.value)) {
|
|
1650
|
+
const expr = attr.value.expression;
|
|
1651
|
+
if (t.isNumericLiteral(expr)) {
|
|
1652
|
+
value = expr;
|
|
1653
|
+
} else if (t.isBooleanLiteral(expr)) {
|
|
1654
|
+
value = expr;
|
|
1655
|
+
} else if (t.isNullLiteral(expr)) {
|
|
1656
|
+
value = expr;
|
|
1657
|
+
} else if (t.isStringLiteral(expr)) {
|
|
1658
|
+
value = expr;
|
|
1659
|
+
} else {
|
|
1660
|
+
value = t.stringLiteral("__dynamic__");
|
|
1661
|
+
}
|
|
1662
|
+
} else {
|
|
1663
|
+
continue;
|
|
1664
|
+
}
|
|
1665
|
+
props.push(t.objectProperty(t.stringLiteral(keyName), value));
|
|
1666
|
+
hasAny = true;
|
|
1667
|
+
}
|
|
1668
|
+
return hasAny ? t.objectExpression(props) : null;
|
|
1669
|
+
}
|
|
1670
|
+
function describeChildrenText(opening) {
|
|
1671
|
+
const elementPath = opening.parentPath;
|
|
1672
|
+
if (!elementPath || !elementPath.isJSXElement()) return null;
|
|
1673
|
+
const element = elementPath.node;
|
|
1674
|
+
if (!element.closingElement) return null;
|
|
1675
|
+
const children = element.children;
|
|
1676
|
+
if (children.length === 0) return "";
|
|
1677
|
+
if (children.length !== 1) return "__dynamic__";
|
|
1678
|
+
const [only] = children;
|
|
1679
|
+
if (!t.isJSXText(only)) return "__dynamic__";
|
|
1680
|
+
return only.value.trim();
|
|
1681
|
+
}
|
|
1682
|
+
function literalInitText(init) {
|
|
1683
|
+
if (t.isStringLiteral(init)) return init.value;
|
|
1684
|
+
if (t.isTemplateLiteral(init) && init.expressions.length === 0) {
|
|
1685
|
+
const [quasi] = init.quasis;
|
|
1686
|
+
if (!quasi) return null;
|
|
1687
|
+
return quasi.value.cooked ?? quasi.value.raw;
|
|
1688
|
+
}
|
|
1689
|
+
return null;
|
|
1690
|
+
}
|
|
1691
|
+
function describeLocalConstSource(name, binding) {
|
|
1692
|
+
const declarator = binding.path;
|
|
1693
|
+
if (!declarator.isVariableDeclarator()) return null;
|
|
1694
|
+
const declaration = declarator.parentPath;
|
|
1695
|
+
if (!declaration?.isVariableDeclaration()) return null;
|
|
1696
|
+
if (declaration.node.kind !== "const" && declaration.node.kind !== "let") return null;
|
|
1697
|
+
const init = declarator.node.init;
|
|
1698
|
+
if (!init) return null;
|
|
1699
|
+
const literal = literalInitText(init);
|
|
1700
|
+
if (literal === null) return null;
|
|
1701
|
+
const loc = init.loc?.start;
|
|
1702
|
+
if (!loc) return null;
|
|
1703
|
+
return {
|
|
1704
|
+
kind: "local-const",
|
|
1705
|
+
name,
|
|
1706
|
+
// The init lives in the SAME file being transformed by construction —
|
|
1707
|
+
// `scope.getBinding` never crosses a file boundary — so the caller's
|
|
1708
|
+
// own `file` (computed once per visited node) is correct here too.
|
|
1709
|
+
file: currentFile,
|
|
1710
|
+
line: loc.line,
|
|
1711
|
+
col: loc.column + 1,
|
|
1712
|
+
literal,
|
|
1713
|
+
// FE MINOR-5: how many places in the FILE read this const — every
|
|
1714
|
+
// reference, not only the one this call is describing. `refs > 1`
|
|
1715
|
+
// means one initializer feeds more than one rendered element, so a
|
|
1716
|
+
// consumer must warn/refuse rather than treat a rewrite as scoped to
|
|
1717
|
+
// just this usage (see `PropSource`'s docstring for the full contract).
|
|
1718
|
+
refs: binding.referencePaths.length
|
|
1719
|
+
};
|
|
1720
|
+
}
|
|
1721
|
+
function resolvableSameFileBinding(name, scope) {
|
|
1722
|
+
const binding = scope.getBinding(name);
|
|
1723
|
+
if (!binding) return null;
|
|
1724
|
+
if (!binding.constant) return null;
|
|
1725
|
+
const bp = binding.path;
|
|
1726
|
+
if (bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier()) {
|
|
1727
|
+
return null;
|
|
1728
|
+
}
|
|
1729
|
+
return binding;
|
|
1730
|
+
}
|
|
1731
|
+
function memberChain(expr) {
|
|
1732
|
+
const path2 = [];
|
|
1733
|
+
let current = expr;
|
|
1734
|
+
while (t.isMemberExpression(current)) {
|
|
1735
|
+
if (current.computed) return null;
|
|
1736
|
+
if (!t.isIdentifier(current.property)) return null;
|
|
1737
|
+
path2.unshift(current.property.name);
|
|
1738
|
+
current = current.object;
|
|
1739
|
+
}
|
|
1740
|
+
if (!t.isIdentifier(current)) return null;
|
|
1741
|
+
return { root: current.name, path: path2 };
|
|
1742
|
+
}
|
|
1743
|
+
let currentFile = "";
|
|
1744
|
+
function describeSource(expr, scope) {
|
|
1745
|
+
if (t.isIdentifier(expr)) {
|
|
1746
|
+
const binding = resolvableSameFileBinding(expr.name, scope);
|
|
1747
|
+
if (!binding) return { kind: "other" };
|
|
1748
|
+
const local = describeLocalConstSource(expr.name, binding);
|
|
1749
|
+
if (local) return local;
|
|
1750
|
+
return { kind: "identifier", name: expr.name };
|
|
1751
|
+
}
|
|
1752
|
+
if (t.isMemberExpression(expr) && !expr.computed) {
|
|
1753
|
+
const chain = memberChain(expr);
|
|
1754
|
+
if (chain && resolvableSameFileBinding(chain.root, scope)) {
|
|
1755
|
+
return { kind: "member", root: chain.root, path: chain.path };
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
return { kind: "other" };
|
|
1759
|
+
}
|
|
1760
|
+
function isStaticPropsLiteral(expr) {
|
|
1761
|
+
return t.isStringLiteral(expr) || t.isNumericLiteral(expr) || t.isBooleanLiteral(expr) || t.isNullLiteral(expr);
|
|
1762
|
+
}
|
|
1763
|
+
function describeChildrenSource(opening) {
|
|
1764
|
+
const elementPath = opening.parentPath;
|
|
1765
|
+
if (!elementPath || !elementPath.isJSXElement()) return null;
|
|
1766
|
+
const children = elementPath.node.children;
|
|
1767
|
+
if (children.length !== 1) return null;
|
|
1768
|
+
const [only] = children;
|
|
1769
|
+
if (!t.isJSXExpressionContainer(only)) return null;
|
|
1770
|
+
if (t.isJSXEmptyExpression(only.expression)) return null;
|
|
1771
|
+
return describeSource(only.expression, opening.scope);
|
|
1772
|
+
}
|
|
1773
|
+
function collectPropSources(attrs, scope) {
|
|
1774
|
+
const entries = [];
|
|
1775
|
+
for (const attr of attrs) {
|
|
1776
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
1777
|
+
const name = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
1778
|
+
if (NON_BINDING_ATTRS.has(name)) continue;
|
|
1779
|
+
const value = attr.value;
|
|
1780
|
+
if (!t.isJSXExpressionContainer(value)) continue;
|
|
1781
|
+
const expression = value.expression;
|
|
1782
|
+
if (t.isJSXEmptyExpression(expression)) continue;
|
|
1783
|
+
if (isStaticPropsLiteral(expression)) continue;
|
|
1784
|
+
entries.push([name, describeSource(expression, scope)]);
|
|
1785
|
+
}
|
|
1786
|
+
return entries;
|
|
1787
|
+
}
|
|
1788
|
+
function propSourceToAst(source) {
|
|
1789
|
+
switch (source.kind) {
|
|
1790
|
+
case "identifier":
|
|
1791
|
+
return t.objectExpression([
|
|
1792
|
+
t.objectProperty(t.identifier("kind"), t.stringLiteral("identifier")),
|
|
1793
|
+
t.objectProperty(t.identifier("name"), t.stringLiteral(source.name))
|
|
1794
|
+
]);
|
|
1795
|
+
case "local-const":
|
|
1796
|
+
return t.objectExpression([
|
|
1797
|
+
t.objectProperty(t.identifier("kind"), t.stringLiteral("local-const")),
|
|
1798
|
+
t.objectProperty(t.identifier("name"), t.stringLiteral(source.name)),
|
|
1799
|
+
t.objectProperty(t.identifier("file"), t.stringLiteral(source.file)),
|
|
1800
|
+
t.objectProperty(t.identifier("line"), t.numericLiteral(source.line)),
|
|
1801
|
+
t.objectProperty(t.identifier("col"), t.numericLiteral(source.col)),
|
|
1802
|
+
t.objectProperty(
|
|
1803
|
+
t.identifier("literal"),
|
|
1804
|
+
source.literal === null ? t.nullLiteral() : t.stringLiteral(source.literal)
|
|
1805
|
+
),
|
|
1806
|
+
t.objectProperty(t.identifier("refs"), t.numericLiteral(source.refs))
|
|
1807
|
+
]);
|
|
1808
|
+
case "member":
|
|
1809
|
+
return t.objectExpression([
|
|
1810
|
+
t.objectProperty(t.identifier("kind"), t.stringLiteral("member")),
|
|
1811
|
+
t.objectProperty(t.identifier("root"), t.stringLiteral(source.root)),
|
|
1812
|
+
t.objectProperty(
|
|
1813
|
+
t.identifier("path"),
|
|
1814
|
+
t.arrayExpression(source.path.map((segment) => t.stringLiteral(segment)))
|
|
1815
|
+
)
|
|
1816
|
+
]);
|
|
1817
|
+
case "other":
|
|
1818
|
+
default:
|
|
1819
|
+
return t.objectExpression([t.objectProperty(t.identifier("kind"), t.stringLiteral("other"))]);
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
function isMetaStripSpreadExpression(arg) {
|
|
1823
|
+
if (!t.isCallExpression(arg)) return false;
|
|
1824
|
+
if (!t.isArrowFunctionExpression(arg.callee)) return false;
|
|
1825
|
+
const [firstParam] = arg.callee.params;
|
|
1826
|
+
if (!firstParam || !t.isObjectPattern(firstParam)) return false;
|
|
1827
|
+
return firstParam.properties.some((prop) => {
|
|
1828
|
+
if (!t.isObjectProperty(prop)) return false;
|
|
1829
|
+
if (!t.isIdentifier(prop.key)) return false;
|
|
1830
|
+
return prop.key.name === "__editorMeta";
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
function hasTruthyAsChildProp(attrs) {
|
|
1834
|
+
for (const attr of attrs) {
|
|
1835
|
+
if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name, { name: "asChild" })) {
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
if (attr.value == null) return true;
|
|
1839
|
+
if (t.isJSXExpressionContainer(attr.value)) {
|
|
1840
|
+
const expr = attr.value.expression;
|
|
1841
|
+
if (t.isBooleanLiteral(expr)) return expr.value;
|
|
1842
|
+
}
|
|
1843
|
+
if (t.isStringLiteral(attr.value)) return attr.value.value !== "false";
|
|
1844
|
+
return true;
|
|
1845
|
+
}
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
function buildPayloadFilter(payload) {
|
|
1849
|
+
return t.callExpression(
|
|
1850
|
+
t.arrowFunctionExpression(
|
|
1851
|
+
[
|
|
1852
|
+
t.objectPattern([
|
|
1853
|
+
t.objectProperty(
|
|
1854
|
+
t.identifier("__editorMeta"),
|
|
1855
|
+
t.identifier("_$em"),
|
|
1856
|
+
false,
|
|
1857
|
+
false
|
|
1858
|
+
),
|
|
1859
|
+
t.objectProperty(
|
|
1860
|
+
t.stringLiteral(KIT_SLOT_ATTR),
|
|
1861
|
+
t.identifier("_$ks"),
|
|
1862
|
+
false,
|
|
1863
|
+
false
|
|
1864
|
+
),
|
|
1865
|
+
t.restElement(t.identifier("_$r"))
|
|
1866
|
+
])
|
|
1867
|
+
],
|
|
1868
|
+
t.identifier("_$r")
|
|
1869
|
+
),
|
|
1870
|
+
[t.objectExpression([t.spreadElement(payload)])]
|
|
1871
|
+
);
|
|
1872
|
+
}
|
|
1873
|
+
function sanitizeSpreadAttributes(attrs) {
|
|
1874
|
+
for (const attr of attrs) {
|
|
1875
|
+
if (!t.isJSXSpreadAttribute(attr)) continue;
|
|
1876
|
+
if (isMetaStripSpreadExpression(attr.argument)) continue;
|
|
1877
|
+
attr.argument = buildPayloadFilter(attr.argument);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
function consumeKitSlot(attrs) {
|
|
1881
|
+
let slot = null;
|
|
1882
|
+
let found = false;
|
|
1883
|
+
for (const attr of attrs) {
|
|
1884
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
1885
|
+
if (!t.isJSXIdentifier(attr.name, { name: KIT_SLOT_ATTR })) continue;
|
|
1886
|
+
found = true;
|
|
1887
|
+
if (slot !== null) continue;
|
|
1888
|
+
const { value } = attr;
|
|
1889
|
+
if (t.isStringLiteral(value)) {
|
|
1890
|
+
slot = normalizeSlot(value.value);
|
|
1891
|
+
} else if (t.isJSXExpressionContainer(value) && t.isStringLiteral(value.expression)) {
|
|
1892
|
+
slot = normalizeSlot(value.expression.value);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
if (!found) return { slot: null, found: false, attrs };
|
|
1896
|
+
return {
|
|
1897
|
+
slot,
|
|
1898
|
+
found: true,
|
|
1899
|
+
attrs: attrs.filter(
|
|
1900
|
+
(attr) => !(t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: KIT_SLOT_ATTR }))
|
|
1901
|
+
)
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
function getFunctionName(fn) {
|
|
1905
|
+
const node = fn.node;
|
|
1906
|
+
if (t.isFunctionDeclaration(node) && node.id) return node.id.name;
|
|
1907
|
+
if (t.isFunctionExpression(node) && node.id) return node.id.name;
|
|
1908
|
+
const parent = fn.parentPath;
|
|
1909
|
+
if (parent?.isVariableDeclarator() && t.isIdentifier(parent.node.id)) {
|
|
1910
|
+
return parent.node.id.name;
|
|
1911
|
+
}
|
|
1912
|
+
return null;
|
|
1913
|
+
}
|
|
1914
|
+
function buildPropMap(pattern) {
|
|
1915
|
+
const map = /* @__PURE__ */ new Map();
|
|
1916
|
+
for (const prop of pattern.properties) {
|
|
1917
|
+
if (!t.isObjectProperty(prop) || prop.computed) continue;
|
|
1918
|
+
const key = t.isIdentifier(prop.key) ? prop.key.name : t.isStringLiteral(prop.key) ? prop.key.value : null;
|
|
1919
|
+
if (!key) continue;
|
|
1920
|
+
const value = prop.value;
|
|
1921
|
+
if (t.isIdentifier(value)) {
|
|
1922
|
+
map.set(value.name, key);
|
|
1923
|
+
} else if (t.isAssignmentPattern(value) && t.isIdentifier(value.left)) {
|
|
1924
|
+
map.set(value.left.name, key);
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
return map;
|
|
1928
|
+
}
|
|
1929
|
+
function restParamName(pattern) {
|
|
1930
|
+
for (const prop of pattern.properties) {
|
|
1931
|
+
if (!t.isRestElement(prop)) continue;
|
|
1932
|
+
if (t.isIdentifier(prop.argument)) return prop.argument.name;
|
|
1933
|
+
return null;
|
|
1934
|
+
}
|
|
1935
|
+
return null;
|
|
1936
|
+
}
|
|
1937
|
+
function resolvePropContext(path2) {
|
|
1938
|
+
let fn = path2.getFunctionParent();
|
|
1939
|
+
while (fn) {
|
|
1940
|
+
const [first] = fn.node.params;
|
|
1941
|
+
if (first && t.isObjectPattern(first) && fn.scope.parent === fn.scope.getProgramParent()) {
|
|
1942
|
+
return {
|
|
1943
|
+
componentScope: fn.scope,
|
|
1944
|
+
propMap: buildPropMap(first),
|
|
1945
|
+
componentName: getFunctionName(fn),
|
|
1946
|
+
restParam: restParamName(first),
|
|
1947
|
+
componentPath: fn
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
fn = fn.getFunctionParent();
|
|
1951
|
+
}
|
|
1952
|
+
return null;
|
|
1953
|
+
}
|
|
1954
|
+
function resolveProp(name, scope, ctx) {
|
|
1955
|
+
const prop = ctx.propMap.get(name);
|
|
1956
|
+
if (!prop) return null;
|
|
1957
|
+
const binding = scope.getBinding(name);
|
|
1958
|
+
if (!binding) return null;
|
|
1959
|
+
if (binding.scope !== ctx.componentScope) return null;
|
|
1960
|
+
if (!binding.constant) return null;
|
|
1961
|
+
return prop;
|
|
1962
|
+
}
|
|
1963
|
+
function isScopeWithinComponent(scope, ctx) {
|
|
1964
|
+
let current = scope;
|
|
1965
|
+
while (current) {
|
|
1966
|
+
if (current === ctx.componentScope) return true;
|
|
1967
|
+
current = current.parent;
|
|
1968
|
+
}
|
|
1969
|
+
return false;
|
|
1970
|
+
}
|
|
1971
|
+
function resolveLocalConstInit(name, scope, ctx) {
|
|
1972
|
+
const binding = scope.getBinding(name);
|
|
1973
|
+
if (!binding) return null;
|
|
1974
|
+
if (!binding.constant) return null;
|
|
1975
|
+
const declarator = binding.path;
|
|
1976
|
+
if (!declarator.isVariableDeclarator()) return null;
|
|
1977
|
+
if (!isScopeWithinComponent(binding.scope, ctx)) return null;
|
|
1978
|
+
const init = declarator.node.init;
|
|
1979
|
+
if (!init || !t.isExpression(init)) return null;
|
|
1980
|
+
return { init, scope: declarator.scope };
|
|
1981
|
+
}
|
|
1982
|
+
function isStaticStringLiteral(node) {
|
|
1983
|
+
if (t.isStringLiteral(node)) return true;
|
|
1984
|
+
return t.isTemplateLiteral(node) && node.expressions.length === 0;
|
|
1985
|
+
}
|
|
1986
|
+
function collectPropIdentifiers(node, scope, ctx, out = []) {
|
|
1987
|
+
if (!node) return out;
|
|
1988
|
+
const visit = (child) => collectPropIdentifiers(child, scope, ctx, out);
|
|
1989
|
+
if (t.isIdentifier(node)) {
|
|
1990
|
+
const prop = resolveProp(node.name, scope, ctx);
|
|
1991
|
+
if (prop && !out.includes(prop)) out.push(prop);
|
|
1992
|
+
return out;
|
|
1993
|
+
}
|
|
1994
|
+
if (t.isMemberExpression(node) || t.isOptionalMemberExpression(node)) {
|
|
1995
|
+
visit(node.object);
|
|
1996
|
+
if (node.computed) visit(node.property);
|
|
1997
|
+
return out;
|
|
1998
|
+
}
|
|
1999
|
+
if (t.isCallExpression(node) || t.isOptionalCallExpression(node)) {
|
|
2000
|
+
visit(node.callee);
|
|
2001
|
+
node.arguments.forEach((arg) => visit(arg));
|
|
2002
|
+
return out;
|
|
2003
|
+
}
|
|
2004
|
+
if (t.isTemplateLiteral(node)) {
|
|
2005
|
+
node.expressions.forEach((expr) => visit(expr));
|
|
2006
|
+
return out;
|
|
2007
|
+
}
|
|
2008
|
+
if (t.isConditionalExpression(node)) {
|
|
2009
|
+
visit(node.test);
|
|
2010
|
+
visit(node.consequent);
|
|
2011
|
+
visit(node.alternate);
|
|
2012
|
+
return out;
|
|
2013
|
+
}
|
|
2014
|
+
if (t.isLogicalExpression(node) || t.isBinaryExpression(node)) {
|
|
2015
|
+
visit(node.left);
|
|
2016
|
+
visit(node.right);
|
|
2017
|
+
return out;
|
|
2018
|
+
}
|
|
2019
|
+
if (t.isUnaryExpression(node) || t.isAwaitExpression(node)) {
|
|
2020
|
+
visit(node.argument);
|
|
2021
|
+
return out;
|
|
2022
|
+
}
|
|
2023
|
+
if (t.isArrayExpression(node)) {
|
|
2024
|
+
node.elements.forEach((el) => visit(el));
|
|
2025
|
+
return out;
|
|
2026
|
+
}
|
|
2027
|
+
if (t.isObjectExpression(node)) {
|
|
2028
|
+
for (const prop of node.properties) {
|
|
2029
|
+
if (t.isObjectProperty(prop)) {
|
|
2030
|
+
if (prop.computed) visit(prop.key);
|
|
2031
|
+
visit(prop.value);
|
|
2032
|
+
} else if (t.isSpreadElement(prop)) {
|
|
2033
|
+
visit(prop.argument);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
return out;
|
|
2037
|
+
}
|
|
2038
|
+
if (t.isSpreadElement(node)) {
|
|
2039
|
+
visit(node.argument);
|
|
2040
|
+
return out;
|
|
2041
|
+
}
|
|
2042
|
+
if (t.isTSAsExpression(node) || t.isTSNonNullExpression(node) || t.isTypeCastExpression(node)) {
|
|
2043
|
+
visit(node.expression);
|
|
2044
|
+
return out;
|
|
2045
|
+
}
|
|
2046
|
+
return out;
|
|
2047
|
+
}
|
|
2048
|
+
function classifyExpression(expr, scope, ctx, hop) {
|
|
2049
|
+
if (t.isIdentifier(expr)) {
|
|
2050
|
+
const prop = resolveProp(expr.name, scope, ctx);
|
|
2051
|
+
if (prop) return { kind: "direct", prop };
|
|
2052
|
+
if (hop > 0) return null;
|
|
2053
|
+
const local = resolveLocalConstInit(expr.name, scope, ctx);
|
|
2054
|
+
if (!local) return null;
|
|
2055
|
+
const inner = classifyExpression(local.init, local.scope, ctx, hop + 1);
|
|
2056
|
+
if (!inner) return null;
|
|
2057
|
+
return { kind: inner.kind === "formatted" ? "formatted" : "derived", prop: inner.prop };
|
|
2058
|
+
}
|
|
2059
|
+
if (t.isLogicalExpression(expr) && (expr.operator === "||" || expr.operator === "??") && isStaticStringLiteral(expr.right)) {
|
|
2060
|
+
const left = classifyExpression(expr.left, scope, ctx, hop);
|
|
2061
|
+
if (!left) return null;
|
|
2062
|
+
return { kind: left.kind === "formatted" ? "formatted" : "derived", prop: left.prop };
|
|
2063
|
+
}
|
|
2064
|
+
const props = collectPropIdentifiers(expr, scope, ctx);
|
|
2065
|
+
return props.length > 0 ? { kind: "formatted", prop: props[0] } : null;
|
|
2066
|
+
}
|
|
2067
|
+
function unwrapSanitizedSpread(arg) {
|
|
2068
|
+
if (!t.isCallExpression(arg)) return arg;
|
|
2069
|
+
if (!isMetaStripSpreadExpression(arg)) return arg;
|
|
2070
|
+
if (arg.arguments.length !== 1) return arg;
|
|
2071
|
+
const [payload] = arg.arguments;
|
|
2072
|
+
if (!t.isObjectExpression(payload) || payload.properties.length !== 1) return arg;
|
|
2073
|
+
const [only] = payload.properties;
|
|
2074
|
+
if (!t.isSpreadElement(only)) return arg;
|
|
2075
|
+
return only.argument;
|
|
2076
|
+
}
|
|
2077
|
+
function forwardsOwnerRestChildren(opening, ctx) {
|
|
2078
|
+
if (ctx.restParam === null) return false;
|
|
2079
|
+
const elementPath = opening.parentPath;
|
|
2080
|
+
if (!elementPath || !elementPath.isJSXElement()) return false;
|
|
2081
|
+
if (meaningfulChildren(t, elementPath.node.children).length > 0) return false;
|
|
2082
|
+
let spreadsRest = 0;
|
|
2083
|
+
for (const attr of opening.node.attributes) {
|
|
2084
|
+
if (t.isJSXAttribute(attr)) {
|
|
2085
|
+
if (t.isJSXIdentifier(attr.name, { name: "children" })) return false;
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
if (!t.isJSXSpreadAttribute(attr)) continue;
|
|
2089
|
+
const payload = unwrapSanitizedSpread(attr.argument);
|
|
2090
|
+
if (!t.isIdentifier(payload, { name: ctx.restParam })) return false;
|
|
2091
|
+
spreadsRest += 1;
|
|
2092
|
+
}
|
|
2093
|
+
if (spreadsRest !== 1) return false;
|
|
2094
|
+
const binding = opening.scope.getBinding(ctx.restParam);
|
|
2095
|
+
if (!binding) return false;
|
|
2096
|
+
if (binding.scope !== ctx.componentScope) return false;
|
|
2097
|
+
return binding.constant;
|
|
2098
|
+
}
|
|
2099
|
+
const restForwarderCounts = /* @__PURE__ */ new WeakMap();
|
|
2100
|
+
function countRestForwarders(ctx) {
|
|
2101
|
+
const cached = restForwarderCounts.get(ctx.componentPath.node);
|
|
2102
|
+
if (cached !== void 0) return cached;
|
|
2103
|
+
let count = 0;
|
|
2104
|
+
ctx.componentPath.traverse({
|
|
2105
|
+
JSXOpeningElement(inner) {
|
|
2106
|
+
if (forwardsOwnerRestChildren(inner, ctx)) count += 1;
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
2109
|
+
restForwarderCounts.set(ctx.componentPath.node, count);
|
|
2110
|
+
return count;
|
|
2111
|
+
}
|
|
2112
|
+
function collectPropBindings(path2, attrs) {
|
|
2113
|
+
const ctx = resolvePropContext(path2);
|
|
2114
|
+
if (!ctx || ctx.propMap.size === 0 && ctx.restParam === null) {
|
|
2115
|
+
return { bindings: [], owner: null };
|
|
2116
|
+
}
|
|
2117
|
+
if (ctx.componentName === null) return { bindings: [], owner: null };
|
|
2118
|
+
const scope = path2.scope;
|
|
2119
|
+
const bindings = [];
|
|
2120
|
+
if (forwardsOwnerRestChildren(path2, ctx) && countRestForwarders(ctx) === 1) {
|
|
2121
|
+
bindings.push({ target: "children", prop: "children", kind: "direct" });
|
|
2122
|
+
}
|
|
2123
|
+
const elementPath = path2.parentPath;
|
|
2124
|
+
if (elementPath && elementPath.isJSXElement()) {
|
|
2125
|
+
const children = meaningfulChildren(t, elementPath.node.children);
|
|
2126
|
+
const isSoleChild = children.length === 1;
|
|
2127
|
+
for (const child of children) {
|
|
2128
|
+
if (!t.isJSXExpressionContainer(child)) continue;
|
|
2129
|
+
const expression = child.expression;
|
|
2130
|
+
if (t.isJSXEmptyExpression(expression)) continue;
|
|
2131
|
+
const verdict = classifyExpression(expression, scope, ctx, 0);
|
|
2132
|
+
if (!verdict) continue;
|
|
2133
|
+
bindings.push({
|
|
2134
|
+
target: "children",
|
|
2135
|
+
prop: verdict.prop,
|
|
2136
|
+
kind: isSoleChild ? verdict.kind : "formatted"
|
|
2137
|
+
});
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
for (const attr of attrs) {
|
|
2141
|
+
if (!t.isJSXAttribute(attr)) continue;
|
|
2142
|
+
const name = t.isJSXIdentifier(attr.name) ? attr.name.name : `${attr.name.namespace.name}:${attr.name.name.name}`;
|
|
2143
|
+
if (NON_BINDING_ATTRS.has(name)) continue;
|
|
2144
|
+
const value = attr.value;
|
|
2145
|
+
if (!t.isJSXExpressionContainer(value)) continue;
|
|
2146
|
+
const expression = value.expression;
|
|
2147
|
+
if (t.isJSXEmptyExpression(expression)) continue;
|
|
2148
|
+
const verdict = classifyExpression(expression, scope, ctx, 0);
|
|
2149
|
+
if (!verdict) continue;
|
|
2150
|
+
bindings.push({
|
|
2151
|
+
target: `attr:${name}`,
|
|
2152
|
+
prop: verdict.prop,
|
|
2153
|
+
// M2b: machine-contract attributes are reported, never offered.
|
|
2154
|
+
kind: isNonContentAttribute(name) ? "formatted" : verdict.kind
|
|
2155
|
+
});
|
|
2156
|
+
}
|
|
2157
|
+
return { bindings, owner: bindings.length > 0 ? ctx.componentName : null };
|
|
2158
|
+
}
|
|
2159
|
+
function propBindingsToAst(bindings) {
|
|
2160
|
+
return t.arrayExpression(
|
|
2161
|
+
bindings.map(
|
|
2162
|
+
(binding) => t.objectExpression([
|
|
2163
|
+
t.objectProperty(t.identifier("target"), t.stringLiteral(binding.target)),
|
|
2164
|
+
t.objectProperty(t.identifier("prop"), t.stringLiteral(binding.prop)),
|
|
2165
|
+
t.objectProperty(t.identifier("kind"), t.stringLiteral(binding.kind))
|
|
2166
|
+
])
|
|
2167
|
+
)
|
|
2168
|
+
);
|
|
2169
|
+
}
|
|
2170
|
+
return {
|
|
2171
|
+
name: "babel-plugin-editor-meta",
|
|
2172
|
+
visitor: {
|
|
2173
|
+
CallExpression(path2, state) {
|
|
2174
|
+
const filename = state.filename ?? "";
|
|
2175
|
+
if (fileExclude.test(filename)) return;
|
|
2176
|
+
const callee = path2.node.callee;
|
|
2177
|
+
let isCreateElement = false;
|
|
2178
|
+
let isCloneElement = false;
|
|
2179
|
+
if (t.isIdentifier(callee, { name: "createElement" })) {
|
|
2180
|
+
isCreateElement = true;
|
|
2181
|
+
} else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "createElement" })) {
|
|
2182
|
+
isCreateElement = true;
|
|
2183
|
+
} else if (t.isIdentifier(callee, { name: "cloneElement" })) {
|
|
2184
|
+
isCloneElement = true;
|
|
2185
|
+
} else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "cloneElement" })) {
|
|
2186
|
+
isCloneElement = true;
|
|
2187
|
+
}
|
|
2188
|
+
if (!isCreateElement && !isCloneElement) return;
|
|
2189
|
+
const args = path2.node.arguments;
|
|
2190
|
+
if (args.length < 2) return;
|
|
2191
|
+
if (isCreateElement && !t.isStringLiteral(args[0])) return;
|
|
2192
|
+
const propsArg = args[1];
|
|
2193
|
+
if (!propsArg || t.isNullLiteral(propsArg)) return;
|
|
2194
|
+
if (!t.isExpression(propsArg)) return;
|
|
2195
|
+
if (isMetaStripSpreadExpression(propsArg)) return;
|
|
2196
|
+
args[1] = buildPayloadFilter(propsArg);
|
|
2197
|
+
},
|
|
2198
|
+
JSXOpeningElement(path2, state) {
|
|
2199
|
+
const consumed = consumeKitSlot(path2.node.attributes);
|
|
2200
|
+
path2.node.attributes = consumed.attrs;
|
|
2201
|
+
const slot = consumed.slot;
|
|
2202
|
+
const hasSlotAttr = consumed.found;
|
|
2203
|
+
const filename = state.filename ?? "";
|
|
2204
|
+
if (fileExclude.test(filename)) return;
|
|
2205
|
+
const existing = path2.node.attributes.find(
|
|
2206
|
+
(a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: "__editorMeta" })
|
|
2207
|
+
);
|
|
2208
|
+
if (existing) return;
|
|
2209
|
+
const loc = path2.node.loc?.start;
|
|
2210
|
+
if (!loc) return;
|
|
2211
|
+
const root = state.file.opts.root ?? "";
|
|
2212
|
+
const file = root ? nodePath.relative(root, filename) : filename;
|
|
2213
|
+
currentFile = file;
|
|
2214
|
+
const line = loc.line;
|
|
2215
|
+
const col = loc.column + 1;
|
|
2216
|
+
const componentName = getJSXTagName(path2.node);
|
|
2217
|
+
if (!componentName) return;
|
|
2218
|
+
const isHostLikeMemberExpression = isHostLikeMemberExpressionName(path2.node.name);
|
|
2219
|
+
const isHostElement = componentName[0] === componentName[0].toLowerCase();
|
|
2220
|
+
sanitizeSpreadAttributes(path2.node.attributes);
|
|
2221
|
+
if (hasTruthyAsChildProp(path2.node.attributes)) {
|
|
2222
|
+
return;
|
|
2223
|
+
}
|
|
2224
|
+
let rootName = null;
|
|
2225
|
+
if (isIntrinsicTagName(path2.node.name)) {
|
|
2226
|
+
rootName = null;
|
|
2227
|
+
} else if (t.isJSXIdentifier(path2.node.name)) {
|
|
2228
|
+
rootName = path2.node.name.name;
|
|
2229
|
+
} else if (t.isJSXMemberExpression(path2.node.name)) {
|
|
2230
|
+
let cur = path2.node.name;
|
|
2231
|
+
while (t.isJSXMemberExpression(cur)) cur = cur.object;
|
|
2232
|
+
if (t.isJSXIdentifier(cur)) rootName = cur.name;
|
|
2233
|
+
}
|
|
2234
|
+
if (rootName) {
|
|
2235
|
+
const binding = path2.scope.getBinding(rootName);
|
|
2236
|
+
if (binding) {
|
|
2237
|
+
const bp = binding.path;
|
|
2238
|
+
if (bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier()) {
|
|
2239
|
+
if (!instrumentImported) return;
|
|
2240
|
+
const decl = bp.parentPath;
|
|
2241
|
+
if (decl?.isImportDeclaration()) {
|
|
2242
|
+
const src = decl.node.source.value;
|
|
2243
|
+
if (isPackageImport(src) && !isHostLikeMemberExpression) return;
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
const programScope = path2.scope.getProgramParent();
|
|
2247
|
+
if (binding.scope !== programScope && !isStaticNamespaceDestructure(binding))
|
|
2248
|
+
return;
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
const vid = readVidAttr(path2.node.attributes);
|
|
2252
|
+
if (!vid && onMissingVid && !missingVidWarned) {
|
|
2253
|
+
missingVidWarned = true;
|
|
2254
|
+
onMissingVid({ file, line, col, componentName, instrumented: allowLegacyIds });
|
|
2255
|
+
}
|
|
2256
|
+
if (!vid && !allowLegacyIds) return;
|
|
2257
|
+
const nodeId = vid ?? computeNodeId(file, line, col, componentName);
|
|
2258
|
+
const isKitOrigin = origin === "kit" || hasSlotAttr;
|
|
2259
|
+
const movable = isKitOrigin ? false : isMovable(path2);
|
|
2260
|
+
const parentNodeId = getParentNodeId(path2, file);
|
|
2261
|
+
const staticPropsObj = extractStaticProps(path2.node.attributes);
|
|
2262
|
+
const { bindings, owner } = collectPropBindings(path2, path2.node.attributes);
|
|
2263
|
+
const metaObj = t.objectExpression([
|
|
2264
|
+
t.objectProperty(t.identifier("nodeId"), t.stringLiteral(nodeId)),
|
|
2265
|
+
t.objectProperty(t.identifier("file"), t.stringLiteral(file)),
|
|
2266
|
+
t.objectProperty(t.identifier("line"), t.numericLiteral(line)),
|
|
2267
|
+
t.objectProperty(t.identifier("col"), t.numericLiteral(col)),
|
|
2268
|
+
t.objectProperty(t.identifier("componentName"), t.stringLiteral(componentName)),
|
|
2269
|
+
t.objectProperty(
|
|
2270
|
+
t.identifier("staticProps"),
|
|
2271
|
+
staticPropsObj ?? t.nullLiteral()
|
|
2272
|
+
),
|
|
2273
|
+
t.objectProperty(t.identifier("movable"), t.booleanLiteral(movable)),
|
|
2274
|
+
t.objectProperty(
|
|
2275
|
+
t.identifier("parentNodeId"),
|
|
2276
|
+
parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
|
|
2277
|
+
)
|
|
2278
|
+
]);
|
|
2279
|
+
if (vid) {
|
|
2280
|
+
const dynamicType = computeDynamicType(path2);
|
|
2281
|
+
const isChrome = computeIsChrome(file, path2);
|
|
2282
|
+
const containerKind = computeContainerKind(path2);
|
|
2283
|
+
const isKitComponentContainer = isKitComponentTagName(path2);
|
|
2284
|
+
const lockReason = computeLockReason(isKitOrigin, isChrome, dynamicType);
|
|
2285
|
+
metaObj.properties.push(
|
|
2286
|
+
t.objectProperty(t.identifier("vid"), t.stringLiteral(vid)),
|
|
2287
|
+
t.objectProperty(t.identifier("isKitOrigin"), t.booleanLiteral(isKitOrigin)),
|
|
2288
|
+
t.objectProperty(t.identifier("dynamicType"), t.stringLiteral(dynamicType)),
|
|
2289
|
+
t.objectProperty(t.identifier("isChrome"), t.booleanLiteral(isChrome)),
|
|
2290
|
+
t.objectProperty(t.identifier("containerKind"), t.stringLiteral(containerKind))
|
|
2291
|
+
);
|
|
2292
|
+
if (isKitComponentContainer) {
|
|
2293
|
+
metaObj.properties.push(
|
|
2294
|
+
t.objectProperty(t.identifier("isKitContainer"), t.booleanLiteral(true))
|
|
2295
|
+
);
|
|
2296
|
+
}
|
|
2297
|
+
if (lockReason) {
|
|
2298
|
+
metaObj.properties.push(
|
|
2299
|
+
t.objectProperty(t.identifier("lockReason"), t.stringLiteral(lockReason))
|
|
2300
|
+
);
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
if (isKitOrigin) {
|
|
2304
|
+
if (templateOrigin) {
|
|
2305
|
+
metaObj.properties.push(
|
|
2306
|
+
t.objectProperty(t.identifier("template"), t.booleanLiteral(true))
|
|
2307
|
+
);
|
|
2308
|
+
} else {
|
|
2309
|
+
metaObj.properties.push(
|
|
2310
|
+
t.objectProperty(t.identifier("origin"), t.stringLiteral("kit"))
|
|
2311
|
+
);
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
if (slot !== null) {
|
|
2315
|
+
metaObj.properties.push(
|
|
2316
|
+
t.objectProperty(t.identifier("slot"), t.stringLiteral(slot))
|
|
2317
|
+
);
|
|
2318
|
+
}
|
|
2319
|
+
if (!isHostElement) {
|
|
2320
|
+
const childrenText = describeChildrenText(path2);
|
|
2321
|
+
metaObj.properties.push(
|
|
2322
|
+
t.objectProperty(
|
|
2323
|
+
t.identifier("childrenText"),
|
|
2324
|
+
childrenText === null ? t.nullLiteral() : t.stringLiteral(childrenText)
|
|
2325
|
+
)
|
|
2326
|
+
);
|
|
2327
|
+
const childrenSource = describeChildrenSource(path2);
|
|
2328
|
+
if (childrenSource) {
|
|
2329
|
+
metaObj.properties.push(
|
|
2330
|
+
t.objectProperty(t.identifier("childrenSource"), propSourceToAst(childrenSource))
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
}
|
|
2334
|
+
if (bindings.length > 0) {
|
|
2335
|
+
metaObj.properties.push(
|
|
2336
|
+
t.objectProperty(t.identifier("propBindings"), propBindingsToAst(bindings))
|
|
2337
|
+
);
|
|
2338
|
+
metaObj.properties.push(
|
|
2339
|
+
t.objectProperty(
|
|
2340
|
+
t.identifier("propOwner"),
|
|
2341
|
+
owner ? t.stringLiteral(owner) : t.nullLiteral()
|
|
2342
|
+
)
|
|
2343
|
+
);
|
|
2344
|
+
}
|
|
2345
|
+
const propSourceEntries = collectPropSources(path2.node.attributes, path2.scope);
|
|
2346
|
+
if (propSourceEntries.length > 0) {
|
|
2347
|
+
metaObj.properties.push(
|
|
2348
|
+
t.objectProperty(
|
|
2349
|
+
t.identifier("propSources"),
|
|
2350
|
+
t.objectExpression(
|
|
2351
|
+
propSourceEntries.map(
|
|
2352
|
+
([name, source]) => t.objectProperty(t.stringLiteral(name), propSourceToAst(source))
|
|
2353
|
+
)
|
|
2354
|
+
)
|
|
2355
|
+
)
|
|
2356
|
+
);
|
|
2357
|
+
}
|
|
2358
|
+
if (isHostElement && includeHostSourceRef) {
|
|
2359
|
+
path2.node.attributes.push(
|
|
2360
|
+
t.jsxAttribute(
|
|
2361
|
+
t.jsxIdentifier("data-archie-source-ref"),
|
|
2362
|
+
t.stringLiteral(`${file}::${line}::${col}`)
|
|
2363
|
+
)
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2366
|
+
const metaThunk = t.arrowFunctionExpression([], metaObj);
|
|
2367
|
+
path2.node.attributes.push(
|
|
2368
|
+
t.jsxAttribute(
|
|
2369
|
+
t.jsxIdentifier("__editorMeta"),
|
|
2370
|
+
t.jsxExpressionContainer(metaThunk)
|
|
2371
|
+
)
|
|
2372
|
+
);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
export {
|
|
2379
|
+
__dirname,
|
|
2380
|
+
VID_ATTR,
|
|
2381
|
+
meaningfulChildren,
|
|
2382
|
+
babelPluginEditorMeta
|
|
2383
|
+
};
|