tsquare 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,17 @@
1
1
  import {
2
+ ACCENTS,
3
+ PRIMARY_PROP,
4
+ bareWords,
5
+ boardLayout,
2
6
  compileWireframe,
7
+ componentDefinitions,
3
8
  componentDocs,
4
9
  formatIssues,
10
+ iconNames,
5
11
  renderWireframePng,
6
12
  renderWireframeSvg,
7
13
  wireframePrompt
8
- } from "../chunks/chunk-L6GTIZQH.js";
14
+ } from "../chunks/chunk-46MGJLGB.js";
9
15
 
10
16
  // src/playground/index.ts
11
17
  import { createServer } from "node:http";
@@ -13,6 +19,56 @@ import { readFile, readdir } from "node:fs/promises";
13
19
  import path from "node:path";
14
20
  import { fileURLToPath } from "node:url";
15
21
 
22
+ // src/playground/language-data.ts
23
+ function unwrap(t) {
24
+ let cur = t;
25
+ while (cur && ["optional", "nullable", "default"].includes(cur.def?.type)) cur = cur.def.innerType;
26
+ return cur;
27
+ }
28
+ function describe(name, schema) {
29
+ const s = unwrap(schema);
30
+ const description = schema.description ?? s?.description;
31
+ const iconish = /Lucide icon|Icon names/i.test(description ?? "");
32
+ switch (s?.def?.type) {
33
+ case "enum":
34
+ return { name, kind: "enum", values: s.options, description };
35
+ case "boolean":
36
+ return { name, kind: "boolean", values: ["true", "false"], description };
37
+ case "number":
38
+ return { name, kind: "number", description };
39
+ case "array": {
40
+ const el = unwrap(s.def.element);
41
+ const hasIcon = el?.def?.type === "object" && "icon" in el.shape;
42
+ return { name, kind: "list", icon: iconish || hasIcon, description };
43
+ }
44
+ case "object":
45
+ return { name, kind: "object", description };
46
+ default:
47
+ return { name, kind: "string", icon: iconish || void 0, accent: name === "accent" || void 0, description };
48
+ }
49
+ }
50
+ var cache = null;
51
+ function languageData() {
52
+ if (cache) return cache;
53
+ const components = Object.entries(componentDefinitions).map(([type, def]) => {
54
+ const shape = def.props.shape;
55
+ const props = Object.entries(shape).map(([name, schema]) => describe(name, schema));
56
+ if (type === "Icon") props.find((p) => p.name === "name").icon = true;
57
+ const words = bareWords(type);
58
+ const off = words.booleans.flatMap((b) => b === "on" ? ["off"] : b === "checked" ? ["unchecked"] : [`no-${b}`]);
59
+ return {
60
+ name: type.toLowerCase(),
61
+ description: def.description,
62
+ main: PRIMARY_PROP[type],
63
+ children: def.slots.length > 0,
64
+ props,
65
+ words: [...words.options.map((o) => o.value), ...words.booleans, ...off]
66
+ };
67
+ });
68
+ cache = { components, icons: [...new Set(iconNames)].sort(), accents: Object.keys(ACCENTS) };
69
+ return cache;
70
+ }
71
+
16
72
  // src/playground/reference.ts
17
73
  var GROUPS = [
18
74
  { name: "Canvas", components: ["Board", "Screen", "Note"] },
@@ -166,7 +222,9 @@ var EXAMPLES = {
166
222
  button primary sm "Small"
167
223
  button primary "Medium"
168
224
  button primary lg "Large"
169
- button secondary "With icon" icon=download
225
+ stack row gap=8 align=center
226
+ button secondary "Back" leadingIcon=chevron-left
227
+ button primary "Next" trailingIcon=chevron-right
170
228
  button primary "Full width" fullWidth
171
229
  text "With a board accent, primary buttons fill with it and ghost buttons use it for text." sm muted`,
172
230
  Input: `board
@@ -225,11 +283,11 @@ var EXAMPLES = {
225
283
  ListItem: `board
226
284
  screen custom width=400 height=440
227
285
  list
228
- listitem "leading=icon" subtitle="trailing=chevron" leading=icon icon=settings trailing=chevron
286
+ listitem "leadingIcon=settings" subtitle="trailing=chevron" leadingIcon=settings trailing=chevron
229
287
  listitem "leading=avatar" subtitle="trailing=text" leading=avatar trailing=text trailingText="9:41"
230
288
  listitem "leading=image" subtitle="trailing=badge" leading=image trailing=badge trailingText="3"
231
289
  listitem "leading=checkbox" leading=checkbox trailing=toggle
232
- listitem "trailing=icon" trailing=icon trailingIcon=trash-2
290
+ listitem "trailingIcon=trash-2" trailingIcon=trash-2
233
291
  listitem leading=image trailing=chevron`,
234
292
  Table: `board
235
293
  screen custom width=520 height=400
@@ -252,15 +310,15 @@ var EXAMPLES = {
252
310
  drawer left size=260
253
311
  heading "Menu" level=3
254
312
  list dividers=false
255
- listitem "Inbox" leading=icon icon=inbox
256
- listitem "Sent" leading=icon icon=send
313
+ listitem "Inbox" leadingIcon=inbox
314
+ listitem "Sent" leadingIcon=send
257
315
  screen phone "side=bottom"
258
316
  navbar "Photo" leading=back
259
317
  image height=300
260
318
  drawer bottom "Share" size=280
261
319
  list dividers=false
262
- listitem "Copy link" leading=icon icon=link
263
- listitem "Message" leading=icon icon=message-circle`
320
+ listitem "Copy link" leadingIcon=link
321
+ listitem "Message" leadingIcon=message-circle`
264
322
  };
265
323
 
266
324
  // src/playground/index.ts
@@ -280,6 +338,28 @@ ${formatIssues(issues)}`);
280
338
  }
281
339
  return problems;
282
340
  }
341
+ var scriptCache = null;
342
+ function playgroundScript() {
343
+ scriptCache ??= (async () => {
344
+ const built = path.join(here, "playground.js");
345
+ try {
346
+ return await readFile(built, "utf8");
347
+ } catch {
348
+ const { build } = await import("esbuild");
349
+ const out = await build({ ...PLAYGROUND_BUNDLE, entryPoints: [path.join(here, "app.ts")], write: false });
350
+ return out.outputFiles[0].text;
351
+ }
352
+ })();
353
+ return scriptCache;
354
+ }
355
+ var PLAYGROUND_BUNDLE = {
356
+ bundle: true,
357
+ format: "esm",
358
+ platform: "browser",
359
+ target: "es2022",
360
+ minify: true,
361
+ legalComments: "eof"
362
+ };
283
363
  var referenceCache = null;
284
364
  function reference() {
285
365
  referenceCache ??= Promise.all(
@@ -290,9 +370,11 @@ function reference() {
290
370
  ).then((components) => ({ groups: GROUPS, components }));
291
371
  return referenceCache;
292
372
  }
373
+ var EXAMPLE_ORDER = ["sign-in", "dashboard", "checkout", "states", "notes-mobile", "notes-web"];
374
+ var rank = (name) => EXAMPLE_ORDER.indexOf(name) + 1 || EXAMPLE_ORDER.length + 1;
293
375
  async function examples() {
294
376
  const dir = path.join(packageRoot, "examples");
295
- const files = (await readdir(dir)).filter((f) => f.endsWith(".tsq")).sort();
377
+ const files = (await readdir(dir)).filter((f) => f.endsWith(".tsq")).sort((a, b) => rank(a.slice(0, -4)) - rank(b.slice(0, -4)) || a.localeCompare(b));
296
378
  return Promise.all(files.map(async (f) => ({ name: f.replace(/\.tsq$/, ""), source: await readFile(path.join(dir, f), "utf8") })));
297
379
  }
298
380
  function readBody(req) {
@@ -321,6 +403,12 @@ function createPlaygroundHandler() {
321
403
  res.end(await readFile(path.join(here, "index.html")));
322
404
  return true;
323
405
  }
406
+ if (req.method === "GET" && url.pathname === "/playground.js") {
407
+ res.writeHead(200, { "content-type": "text/javascript; charset=utf-8" });
408
+ res.end(await playgroundScript());
409
+ return true;
410
+ }
411
+ if (req.method === "GET" && url.pathname === "/api/language") return json(res, 200, languageData());
324
412
  if (req.method === "GET" && url.pathname === "/mark.png") {
325
413
  res.writeHead(200, { "content-type": "image/png", "cache-control": "max-age=3600" });
326
414
  res.end(await readFile(path.join(packageRoot, "assets", "mark.png")));
@@ -337,7 +425,8 @@ function createPlaygroundHandler() {
337
425
  const { spec, issues } = compileWireframe(await readBody(req));
338
426
  if (url.pathname === "/api/render") {
339
427
  if (!spec || issues.length) return json(res, 200, { issues });
340
- return json(res, 200, { issues, svg: await renderWireframeSvg(spec, { skipValidation: true }) });
428
+ const { width, height, items } = boardLayout(spec);
429
+ return json(res, 200, { issues, svg: await renderWireframeSvg(spec, { skipValidation: true }), width, height, items });
341
430
  }
342
431
  if (!spec || issues.length) return json(res, 400, { issues });
343
432
  const scale = Math.min(4, Math.max(1, Number(url.searchParams.get("scale") ?? 2)));
@@ -370,6 +459,7 @@ ${problems.join("\n")}`);
370
459
  return server;
371
460
  }
372
461
  export {
462
+ PLAYGROUND_BUNDLE,
373
463
  checkReferenceExamples,
374
464
  createPlaygroundHandler,
375
465
  startPlayground
@@ -0,0 +1,28 @@
1
+ export interface PropInfo {
2
+ name: string;
3
+ kind: "string" | "number" | "boolean" | "enum" | "list" | "object";
4
+ /** Allowed values for enums (and booleans: true/false). */
5
+ values?: string[];
6
+ /** The value is a Lucide icon name (or a list of them). */
7
+ icon?: boolean;
8
+ /** The value is an accent color. */
9
+ accent?: boolean;
10
+ description?: string;
11
+ }
12
+ export interface ComponentInfo {
13
+ /** Lowercase, as written: "listitem". */
14
+ name: string;
15
+ description: string;
16
+ /** The prop a quoted string fills, if any. */
17
+ main?: string;
18
+ children: boolean;
19
+ props: PropInfo[];
20
+ /** Bare words this component accepts: option values, switch names and their off forms. */
21
+ words: string[];
22
+ }
23
+ export interface LanguageData {
24
+ components: ComponentInfo[];
25
+ icons: string[];
26
+ accents: string[];
27
+ }
28
+ export declare function languageData(): LanguageData;