@xom11/whiteboard 0.24.2 → 0.25.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.
Files changed (84) hide show
  1. package/README.md +84 -11
  2. package/dist/ai.d.mts +422 -566
  3. package/dist/ai.d.ts +422 -566
  4. package/dist/ai.js +1527 -407
  5. package/dist/ai.js.map +1 -1
  6. package/dist/ai.mjs +1008 -512
  7. package/dist/ai.mjs.map +1 -1
  8. package/dist/catalog.json +4 -4
  9. package/dist/{chunk-BKSXPNPQ.mjs → chunk-AYSFWUPK.mjs} +4 -3
  10. package/dist/chunk-AYSFWUPK.mjs.map +1 -0
  11. package/dist/chunk-B4NJJZFR.mjs +18 -0
  12. package/dist/chunk-B4NJJZFR.mjs.map +1 -0
  13. package/dist/{chunk-LVNCYP4J.mjs → chunk-CJBLJUWG.mjs} +5 -5
  14. package/dist/{chunk-LVNCYP4J.mjs.map → chunk-CJBLJUWG.mjs.map} +1 -1
  15. package/dist/{chunk-7WQXXEVR.mjs → chunk-ESVPQWHX.mjs} +5 -5
  16. package/dist/{chunk-7WQXXEVR.mjs.map → chunk-ESVPQWHX.mjs.map} +1 -1
  17. package/dist/{chunk-KRC2XOIG.mjs → chunk-I24QOHPU.mjs} +3 -3
  18. package/dist/{chunk-KRC2XOIG.mjs.map → chunk-I24QOHPU.mjs.map} +1 -1
  19. package/dist/{chunk-ZBJBQKJ2.mjs → chunk-IHUFOV7L.mjs} +4 -19
  20. package/dist/chunk-IHUFOV7L.mjs.map +1 -0
  21. package/dist/{chunk-AZIARTGX.mjs → chunk-M42TGYT6.mjs} +3 -3
  22. package/dist/{chunk-AZIARTGX.mjs.map → chunk-M42TGYT6.mjs.map} +1 -1
  23. package/dist/{chunk-45CGKJ7S.mjs → chunk-NDEZJKNY.mjs} +4 -4
  24. package/dist/{chunk-45CGKJ7S.mjs.map → chunk-NDEZJKNY.mjs.map} +1 -1
  25. package/dist/{chunk-BEZSQKPY.mjs → chunk-ONBCUWVI.mjs} +5 -4
  26. package/dist/chunk-ONBCUWVI.mjs.map +1 -0
  27. package/dist/{chunk-WM2VDYQA.mjs → chunk-REIJZDVZ.mjs} +4 -3
  28. package/dist/chunk-REIJZDVZ.mjs.map +1 -0
  29. package/dist/{chunk-2WF6KIGF.mjs → chunk-TB4CL25L.mjs} +9 -8
  30. package/dist/chunk-TB4CL25L.mjs.map +1 -0
  31. package/dist/chunk-VNCCIV6O.mjs +938 -0
  32. package/dist/chunk-VNCCIV6O.mjs.map +1 -0
  33. package/dist/{chunk-CGZZO4BX.mjs → chunk-VRHWDZ66.mjs} +5 -5
  34. package/dist/{chunk-CGZZO4BX.mjs.map → chunk-VRHWDZ66.mjs.map} +1 -1
  35. package/dist/{chunk-4DS3MKID.mjs → chunk-YSJOVBCD.mjs} +4 -4
  36. package/dist/{chunk-4DS3MKID.mjs.map → chunk-YSJOVBCD.mjs.map} +1 -1
  37. package/dist/geometry-2d.d.mts +2 -2
  38. package/dist/geometry-2d.d.ts +2 -2
  39. package/dist/geometry-2d.js +1383 -23
  40. package/dist/geometry-2d.js.map +1 -1
  41. package/dist/geometry-2d.mjs +6 -5
  42. package/dist/geometry-3d.d.mts +2 -2
  43. package/dist/geometry-3d.d.ts +2 -2
  44. package/dist/geometry-3d.js +2 -2
  45. package/dist/geometry-3d.js.map +1 -1
  46. package/dist/geometry-3d.mjs +5 -4
  47. package/dist/graph-2d.d.mts +2 -2
  48. package/dist/graph-2d.d.ts +2 -2
  49. package/dist/graph-2d.js +2 -2
  50. package/dist/graph-2d.js.map +1 -1
  51. package/dist/graph-2d.mjs +8 -7
  52. package/dist/{host-ZIQ77W33.mjs → host-A64ITWVX.mjs} +7 -6
  53. package/dist/host-A64ITWVX.mjs.map +1 -0
  54. package/dist/{host-EPZCNFLH.mjs → host-L7FMFZUW.mjs} +226 -29
  55. package/dist/host-L7FMFZUW.mjs.map +1 -0
  56. package/dist/{host-LKCMYEAV.mjs → host-QK53UYMD.mjs} +11 -10
  57. package/dist/host-QK53UYMD.mjs.map +1 -0
  58. package/dist/index.d.mts +3 -3
  59. package/dist/index.d.ts +3 -3
  60. package/dist/index.js +1414 -54
  61. package/dist/index.js.map +1 -1
  62. package/dist/index.mjs +18 -17
  63. package/dist/index.mjs.map +1 -1
  64. package/dist/latex.d.mts +2 -2
  65. package/dist/latex.d.ts +2 -2
  66. package/dist/render-3WTY7NZB.mjs +9 -0
  67. package/dist/{render-SA4JTOW3.mjs.map → render-3WTY7NZB.mjs.map} +1 -1
  68. package/dist/serialize-SRJVKYUG.mjs +8 -0
  69. package/dist/{serialize-JAVOU22E.mjs.map → serialize-SRJVKYUG.mjs.map} +1 -1
  70. package/dist/{types-vtvyKGAA.d.mts → types-DWRyCa2m.d.mts} +187 -2
  71. package/dist/{types-Crbefnfe.d.ts → types-DWRyCa2m.d.ts} +187 -2
  72. package/package.json +1 -1
  73. package/dist/chunk-2WF6KIGF.mjs.map +0 -1
  74. package/dist/chunk-BEZSQKPY.mjs.map +0 -1
  75. package/dist/chunk-BKSXPNPQ.mjs.map +0 -1
  76. package/dist/chunk-WM2VDYQA.mjs.map +0 -1
  77. package/dist/chunk-ZBJBQKJ2.mjs.map +0 -1
  78. package/dist/host-EPZCNFLH.mjs.map +0 -1
  79. package/dist/host-LKCMYEAV.mjs.map +0 -1
  80. package/dist/host-ZIQ77W33.mjs.map +0 -1
  81. package/dist/render-SA4JTOW3.mjs +0 -8
  82. package/dist/serialize-JAVOU22E.mjs +0 -7
  83. package/dist/types-DxlMPh-6.d.mts +0 -49
  84. package/dist/types-DxlMPh-6.d.ts +0 -49
@@ -5,6 +5,7 @@ var immer = require('immer');
5
5
  var React = require('react');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
7
  var reactDom = require('react-dom');
8
+ var zod = require('zod');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -3266,11 +3267,11 @@ function formatMeasure(items) {
3266
3267
  return items.map((it) => `${it.label} = ${it.value.toFixed(2)}`).join(", ");
3267
3268
  }
3268
3269
  function ObjectRow(props) {
3269
- const { obj, state, selected, onSelect, onToggleVisible, onToggleLocked, onRename, onChangeColor, onDelete } = props;
3270
+ const { obj, state, selected, onSelect, onToggleVisible, onToggleLocked, onRename, onChangeColor, onDelete, describe } = props;
3270
3271
  const meta = getKindUiMeta(obj.kind);
3271
3272
  let title = "";
3272
3273
  try {
3273
- title = getKind(obj.kind).describe(obj, state);
3274
+ title = describe ? describe(obj, state) : getKind(obj.kind).describe(obj, state);
3274
3275
  } catch {
3275
3276
  title = `${meta.displayName} ${obj.label}`;
3276
3277
  }
@@ -7207,12 +7208,1122 @@ var init_Toast2 = __esm({
7207
7208
  init_useToast();
7208
7209
  }
7209
7210
  });
7210
- function useAiFigure(generator) {
7211
+ var NameZ;
7212
+ var init_names = __esm({
7213
+ "src/stamps/geometry-2d/dsl/names.ts"() {
7214
+ NameZ = zod.z.string().regex(/^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/);
7215
+ }
7216
+ });
7217
+
7218
+ // src/stamps/geometry-2d/dsl/kinds/_types.ts
7219
+ function defineModule(m) {
7220
+ return m;
7221
+ }
7222
+ var init_types4 = __esm({
7223
+ "src/stamps/geometry-2d/dsl/kinds/_types.ts"() {
7224
+ }
7225
+ });
7226
+
7227
+ // src/stamps/geometry-2d/dsl/kinds/_shared.ts
7228
+ function emitPointObject(id, name, constraint) {
7229
+ return {
7230
+ id,
7231
+ kind: "point",
7232
+ label: name,
7233
+ ...POINT_BASE_FIELDS,
7234
+ attrs: { constraint }
7235
+ };
7236
+ }
7237
+ function resolveTriangleVertices(ctx, vertices) {
7238
+ return [ctx.resolveId(vertices[0]), ctx.resolveId(vertices[1]), ctx.resolveId(vertices[2])];
7239
+ }
7240
+ var POINT_BASE_FIELDS, SHAPE_BASE_FIELDS;
7241
+ var init_shared = __esm({
7242
+ "src/stamps/geometry-2d/dsl/kinds/_shared.ts"() {
7243
+ POINT_BASE_FIELDS = {
7244
+ visible: true,
7245
+ locked: false,
7246
+ layer: "default",
7247
+ schemaVersion: 1
7248
+ };
7249
+ SHAPE_BASE_FIELDS = {
7250
+ visible: true,
7251
+ locked: false,
7252
+ layer: "default",
7253
+ schemaVersion: 1
7254
+ };
7255
+ }
7256
+ });
7257
+ var freeModule;
7258
+ var init_free = __esm({
7259
+ "src/stamps/geometry-2d/dsl/kinds/points/free.ts"() {
7260
+ init_names();
7261
+ init_types4();
7262
+ init_shared();
7263
+ freeModule = defineModule({
7264
+ kind: "free",
7265
+ role: "point",
7266
+ category: "points",
7267
+ prefix: "p",
7268
+ schema: zod.z.object({
7269
+ name: NameZ,
7270
+ kind: zod.z.literal("free"),
7271
+ x: zod.z.number().finite(),
7272
+ y: zod.z.number().finite()
7273
+ }),
7274
+ collectRefs: () => [],
7275
+ emit: (e, ctx) => [{
7276
+ role: "primary",
7277
+ object: emitPointObject(ctx.resolveId(e.name), e.name, { kind: "free", x: e.x, y: e.y })
7278
+ }]
7279
+ });
7280
+ }
7281
+ });
7282
+ var midpointModule;
7283
+ var init_midpoint = __esm({
7284
+ "src/stamps/geometry-2d/dsl/kinds/points/midpoint.ts"() {
7285
+ init_names();
7286
+ init_types4();
7287
+ init_shared();
7288
+ midpointModule = defineModule({
7289
+ kind: "midpoint",
7290
+ role: "point",
7291
+ category: "points",
7292
+ prefix: "p",
7293
+ schema: zod.z.object({
7294
+ name: NameZ,
7295
+ kind: zod.z.literal("midpoint"),
7296
+ p1: NameZ,
7297
+ p2: NameZ
7298
+ }),
7299
+ collectRefs: (e) => [e.p1, e.p2],
7300
+ emit: (e, ctx) => [{
7301
+ role: "primary",
7302
+ object: emitPointObject(
7303
+ ctx.resolveId(e.name),
7304
+ e.name,
7305
+ { kind: "midpoint", p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7306
+ )
7307
+ }]
7308
+ });
7309
+ }
7310
+ });
7311
+ var onSegmentModule;
7312
+ var init_onSegment = __esm({
7313
+ "src/stamps/geometry-2d/dsl/kinds/points/onSegment.ts"() {
7314
+ init_names();
7315
+ init_types4();
7316
+ init_shared();
7317
+ onSegmentModule = defineModule({
7318
+ kind: "onSegment",
7319
+ role: "point",
7320
+ category: "points",
7321
+ prefix: "p",
7322
+ schema: zod.z.object({
7323
+ name: NameZ,
7324
+ kind: zod.z.literal("onSegment"),
7325
+ segmentId: NameZ,
7326
+ t: zod.z.number().min(0).max(1)
7327
+ }),
7328
+ collectRefs: (e) => [e.segmentId],
7329
+ emit: (e, ctx) => [{
7330
+ role: "primary",
7331
+ object: emitPointObject(
7332
+ ctx.resolveId(e.name),
7333
+ e.name,
7334
+ { kind: "onSegment", segmentId: ctx.resolveId(e.segmentId), t: e.t }
7335
+ )
7336
+ }]
7337
+ });
7338
+ }
7339
+ });
7340
+ var onLineModule;
7341
+ var init_onLine = __esm({
7342
+ "src/stamps/geometry-2d/dsl/kinds/points/onLine.ts"() {
7343
+ init_names();
7344
+ init_types4();
7345
+ init_shared();
7346
+ onLineModule = defineModule({
7347
+ kind: "onLine",
7348
+ role: "point",
7349
+ category: "points",
7350
+ prefix: "p",
7351
+ schema: zod.z.object({
7352
+ name: NameZ,
7353
+ kind: zod.z.literal("onLine"),
7354
+ lineId: NameZ,
7355
+ t: zod.z.number().finite()
7356
+ }),
7357
+ collectRefs: (e) => [e.lineId],
7358
+ emit: (e, ctx) => [{
7359
+ role: "primary",
7360
+ object: emitPointObject(
7361
+ ctx.resolveId(e.name),
7362
+ e.name,
7363
+ { kind: "onLine", lineId: ctx.resolveId(e.lineId), t: e.t }
7364
+ )
7365
+ }]
7366
+ });
7367
+ }
7368
+ });
7369
+ var onCircleModule;
7370
+ var init_onCircle = __esm({
7371
+ "src/stamps/geometry-2d/dsl/kinds/points/onCircle.ts"() {
7372
+ init_names();
7373
+ init_types4();
7374
+ init_shared();
7375
+ onCircleModule = defineModule({
7376
+ kind: "onCircle",
7377
+ role: "point",
7378
+ category: "points",
7379
+ prefix: "p",
7380
+ schema: zod.z.object({
7381
+ name: NameZ,
7382
+ kind: zod.z.literal("onCircle"),
7383
+ circleId: NameZ,
7384
+ theta: zod.z.number().finite()
7385
+ }),
7386
+ collectRefs: (e) => [e.circleId],
7387
+ emit: (e, ctx) => [{
7388
+ role: "primary",
7389
+ object: emitPointObject(
7390
+ ctx.resolveId(e.name),
7391
+ e.name,
7392
+ { kind: "onCircle", circleId: ctx.resolveId(e.circleId), theta: e.theta }
7393
+ )
7394
+ }]
7395
+ });
7396
+ }
7397
+ });
7398
+ var perpFootModule;
7399
+ var init_perpFoot = __esm({
7400
+ "src/stamps/geometry-2d/dsl/kinds/points/perpFoot.ts"() {
7401
+ init_names();
7402
+ init_types4();
7403
+ init_shared();
7404
+ perpFootModule = defineModule({
7405
+ kind: "perpFoot",
7406
+ role: "point",
7407
+ category: "points",
7408
+ prefix: "p",
7409
+ schema: zod.z.object({
7410
+ name: NameZ,
7411
+ kind: zod.z.literal("perpFoot"),
7412
+ from: NameZ,
7413
+ onLine: NameZ
7414
+ }),
7415
+ collectRefs: (e) => [e.from, e.onLine],
7416
+ emit: (e, ctx) => [{
7417
+ role: "primary",
7418
+ object: emitPointObject(
7419
+ ctx.resolveId(e.name),
7420
+ e.name,
7421
+ { kind: "perpFoot", from: ctx.resolveId(e.from), onLine: ctx.resolveId(e.onLine) }
7422
+ )
7423
+ }]
7424
+ });
7425
+ }
7426
+ });
7427
+ var circumcenterModule;
7428
+ var init_circumcenter = __esm({
7429
+ "src/stamps/geometry-2d/dsl/kinds/points/circumcenter.ts"() {
7430
+ init_names();
7431
+ init_types4();
7432
+ init_shared();
7433
+ circumcenterModule = defineModule({
7434
+ kind: "circumcenter",
7435
+ role: "point",
7436
+ category: "points",
7437
+ prefix: "p",
7438
+ schema: zod.z.object({
7439
+ name: NameZ,
7440
+ kind: zod.z.literal("circumcenter"),
7441
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7442
+ }),
7443
+ collectRefs: (e) => [...e.vertices],
7444
+ emit: (e, ctx) => [{
7445
+ role: "primary",
7446
+ object: emitPointObject(
7447
+ ctx.resolveId(e.name),
7448
+ e.name,
7449
+ { kind: "circumcenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7450
+ )
7451
+ }]
7452
+ });
7453
+ }
7454
+ });
7455
+ var incenterModule;
7456
+ var init_incenter = __esm({
7457
+ "src/stamps/geometry-2d/dsl/kinds/points/incenter.ts"() {
7458
+ init_names();
7459
+ init_types4();
7460
+ init_shared();
7461
+ incenterModule = defineModule({
7462
+ kind: "incenter",
7463
+ role: "point",
7464
+ category: "points",
7465
+ prefix: "p",
7466
+ schema: zod.z.object({
7467
+ name: NameZ,
7468
+ kind: zod.z.literal("incenter"),
7469
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7470
+ }),
7471
+ collectRefs: (e) => [...e.vertices],
7472
+ emit: (e, ctx) => [{
7473
+ role: "primary",
7474
+ object: emitPointObject(
7475
+ ctx.resolveId(e.name),
7476
+ e.name,
7477
+ { kind: "incenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7478
+ )
7479
+ }]
7480
+ });
7481
+ }
7482
+ });
7483
+ var centroidModule;
7484
+ var init_centroid = __esm({
7485
+ "src/stamps/geometry-2d/dsl/kinds/points/centroid.ts"() {
7486
+ init_names();
7487
+ init_types4();
7488
+ init_shared();
7489
+ centroidModule = defineModule({
7490
+ kind: "centroid",
7491
+ role: "point",
7492
+ category: "points",
7493
+ prefix: "p",
7494
+ schema: zod.z.object({
7495
+ name: NameZ,
7496
+ kind: zod.z.literal("centroid"),
7497
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7498
+ }),
7499
+ collectRefs: (e) => [...e.vertices],
7500
+ emit: (e, ctx) => [{
7501
+ role: "primary",
7502
+ object: emitPointObject(
7503
+ ctx.resolveId(e.name),
7504
+ e.name,
7505
+ { kind: "centroid", vertices: resolveTriangleVertices(ctx, e.vertices) }
7506
+ )
7507
+ }]
7508
+ });
7509
+ }
7510
+ });
7511
+ var orthocenterModule;
7512
+ var init_orthocenter = __esm({
7513
+ "src/stamps/geometry-2d/dsl/kinds/points/orthocenter.ts"() {
7514
+ init_names();
7515
+ init_types4();
7516
+ init_shared();
7517
+ orthocenterModule = defineModule({
7518
+ kind: "orthocenter",
7519
+ role: "point",
7520
+ category: "points",
7521
+ prefix: "p",
7522
+ schema: zod.z.object({
7523
+ name: NameZ,
7524
+ kind: zod.z.literal("orthocenter"),
7525
+ vertices: zod.z.tuple([NameZ, NameZ, NameZ])
7526
+ }),
7527
+ collectRefs: (e) => [...e.vertices],
7528
+ emit: (e, ctx) => [{
7529
+ role: "primary",
7530
+ object: emitPointObject(
7531
+ ctx.resolveId(e.name),
7532
+ e.name,
7533
+ { kind: "orthocenter", vertices: resolveTriangleVertices(ctx, e.vertices) }
7534
+ )
7535
+ }]
7536
+ });
7537
+ }
7538
+ });
7539
+ var intersectionModule;
7540
+ var init_intersection2 = __esm({
7541
+ "src/stamps/geometry-2d/dsl/kinds/points/intersection.ts"() {
7542
+ init_names();
7543
+ init_types4();
7544
+ init_shared();
7545
+ intersectionModule = defineModule({
7546
+ kind: "intersection",
7547
+ role: "point",
7548
+ category: "points",
7549
+ prefix: "i",
7550
+ schema: zod.z.object({
7551
+ name: NameZ,
7552
+ kind: zod.z.literal("intersection"),
7553
+ ref1: NameZ,
7554
+ ref2: NameZ,
7555
+ branch: zod.z.union([zod.z.literal(0), zod.z.literal(1)]).optional()
7556
+ }),
7557
+ collectRefs: (e) => [e.ref1, e.ref2],
7558
+ emit: (e, ctx) => {
7559
+ const r1IsCircle = ctx.hintOf(e.ref1) === "circle";
7560
+ const r2IsCircle = ctx.hintOf(e.ref2) === "circle";
7561
+ let intersectKind;
7562
+ if (r1IsCircle && r2IsCircle) intersectKind = "circleCircle";
7563
+ else if (r1IsCircle || r2IsCircle) intersectKind = "lineCircle";
7564
+ else intersectKind = "lineLine";
7565
+ const attrs = {
7566
+ kind: intersectKind,
7567
+ ref1: ctx.resolveId(e.ref1),
7568
+ ref2: ctx.resolveId(e.ref2)
7569
+ };
7570
+ if (intersectKind !== "lineLine") {
7571
+ attrs.branch = e.branch ?? 0;
7572
+ }
7573
+ return [{
7574
+ role: "primary",
7575
+ object: {
7576
+ id: ctx.resolveId(e.name),
7577
+ kind: "intersection",
7578
+ label: e.name,
7579
+ ...POINT_BASE_FIELDS,
7580
+ attrs
7581
+ }
7582
+ }];
7583
+ }
7584
+ });
7585
+ }
7586
+ });
7587
+ var segmentModule;
7588
+ var init_segment2 = __esm({
7589
+ "src/stamps/geometry-2d/dsl/kinds/lines/segment.ts"() {
7590
+ init_names();
7591
+ init_types4();
7592
+ init_shared();
7593
+ segmentModule = defineModule({
7594
+ kind: "segment",
7595
+ role: "segment",
7596
+ category: "lines",
7597
+ prefix: "s",
7598
+ schema: zod.z.object({
7599
+ name: NameZ,
7600
+ kind: zod.z.literal("segment"),
7601
+ p1: NameZ,
7602
+ p2: NameZ
7603
+ }),
7604
+ collectRefs: (e) => [e.p1, e.p2],
7605
+ emit: (e, ctx) => [{
7606
+ role: "primary",
7607
+ object: {
7608
+ id: ctx.resolveId(e.name),
7609
+ kind: "segment",
7610
+ label: e.name,
7611
+ ...SHAPE_BASE_FIELDS,
7612
+ attrs: { p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7613
+ }
7614
+ }]
7615
+ });
7616
+ }
7617
+ });
7618
+ var lineModule;
7619
+ var init_line2 = __esm({
7620
+ "src/stamps/geometry-2d/dsl/kinds/lines/line.ts"() {
7621
+ init_names();
7622
+ init_types4();
7623
+ init_shared();
7624
+ lineModule = defineModule({
7625
+ kind: "line",
7626
+ role: "line",
7627
+ category: "lines",
7628
+ prefix: "l",
7629
+ schema: zod.z.object({
7630
+ name: NameZ,
7631
+ kind: zod.z.literal("line"),
7632
+ p1: NameZ,
7633
+ p2: NameZ
7634
+ }),
7635
+ collectRefs: (e) => [e.p1, e.p2],
7636
+ emit: (e, ctx) => [{
7637
+ role: "primary",
7638
+ object: {
7639
+ id: ctx.resolveId(e.name),
7640
+ kind: "line",
7641
+ label: e.name,
7642
+ ...SHAPE_BASE_FIELDS,
7643
+ attrs: { p1: ctx.resolveId(e.p1), p2: ctx.resolveId(e.p2) }
7644
+ }
7645
+ }]
7646
+ });
7647
+ }
7648
+ });
7649
+ var rayModule;
7650
+ var init_ray2 = __esm({
7651
+ "src/stamps/geometry-2d/dsl/kinds/lines/ray.ts"() {
7652
+ init_names();
7653
+ init_types4();
7654
+ init_shared();
7655
+ rayModule = defineModule({
7656
+ kind: "ray",
7657
+ role: "ray",
7658
+ category: "lines",
7659
+ prefix: "r",
7660
+ schema: zod.z.object({
7661
+ name: NameZ,
7662
+ kind: zod.z.literal("ray"),
7663
+ origin: NameZ,
7664
+ through: NameZ
7665
+ }),
7666
+ collectRefs: (e) => [e.origin, e.through],
7667
+ emit: (e, ctx) => [{
7668
+ role: "primary",
7669
+ object: {
7670
+ id: ctx.resolveId(e.name),
7671
+ kind: "ray",
7672
+ label: e.name,
7673
+ ...SHAPE_BASE_FIELDS,
7674
+ attrs: { origin: ctx.resolveId(e.origin), through: ctx.resolveId(e.through) }
7675
+ }
7676
+ }]
7677
+ });
7678
+ }
7679
+ });
7680
+ var perpendicularModule;
7681
+ var init_perpendicular = __esm({
7682
+ "src/stamps/geometry-2d/dsl/kinds/lines/perpendicular.ts"() {
7683
+ init_names();
7684
+ init_types4();
7685
+ init_shared();
7686
+ perpendicularModule = defineModule({
7687
+ kind: "perpendicular",
7688
+ role: "lineConstruction",
7689
+ category: "lines",
7690
+ prefix: "l",
7691
+ schema: zod.z.object({
7692
+ name: NameZ,
7693
+ kind: zod.z.literal("perpendicular"),
7694
+ throughPoint: NameZ,
7695
+ toLine: NameZ
7696
+ }),
7697
+ collectRefs: (e) => [e.throughPoint, e.toLine],
7698
+ emit: (e, ctx) => [{
7699
+ role: "primary",
7700
+ object: {
7701
+ id: ctx.resolveId(e.name),
7702
+ kind: "line",
7703
+ label: e.name,
7704
+ ...SHAPE_BASE_FIELDS,
7705
+ attrs: {
7706
+ construction: {
7707
+ kind: "perpendicular",
7708
+ throughPoint: ctx.resolveId(e.throughPoint),
7709
+ toLine: ctx.resolveId(e.toLine)
7710
+ }
7711
+ }
7712
+ }
7713
+ }]
7714
+ });
7715
+ }
7716
+ });
7717
+ var parallelModule;
7718
+ var init_parallel = __esm({
7719
+ "src/stamps/geometry-2d/dsl/kinds/lines/parallel.ts"() {
7720
+ init_names();
7721
+ init_types4();
7722
+ init_shared();
7723
+ parallelModule = defineModule({
7724
+ kind: "parallel",
7725
+ role: "lineConstruction",
7726
+ category: "lines",
7727
+ prefix: "l",
7728
+ schema: zod.z.object({
7729
+ name: NameZ,
7730
+ kind: zod.z.literal("parallel"),
7731
+ throughPoint: NameZ,
7732
+ toLine: NameZ
7733
+ }),
7734
+ collectRefs: (e) => [e.throughPoint, e.toLine],
7735
+ emit: (e, ctx) => [{
7736
+ role: "primary",
7737
+ object: {
7738
+ id: ctx.resolveId(e.name),
7739
+ kind: "line",
7740
+ label: e.name,
7741
+ ...SHAPE_BASE_FIELDS,
7742
+ attrs: {
7743
+ construction: {
7744
+ kind: "parallel",
7745
+ throughPoint: ctx.resolveId(e.throughPoint),
7746
+ toLine: ctx.resolveId(e.toLine)
7747
+ }
7748
+ }
7749
+ }
7750
+ }]
7751
+ });
7752
+ }
7753
+ });
7754
+ var perpBisectorModule;
7755
+ var init_perpBisector = __esm({
7756
+ "src/stamps/geometry-2d/dsl/kinds/lines/perpBisector.ts"() {
7757
+ init_names();
7758
+ init_types4();
7759
+ init_shared();
7760
+ perpBisectorModule = defineModule({
7761
+ kind: "perpBisector",
7762
+ role: "lineConstruction",
7763
+ category: "lines",
7764
+ prefix: "l",
7765
+ schema: zod.z.object({
7766
+ name: NameZ,
7767
+ kind: zod.z.literal("perpBisector"),
7768
+ p1: NameZ,
7769
+ p2: NameZ
7770
+ }),
7771
+ collectRefs: (e) => [e.p1, e.p2],
7772
+ emit: (e, ctx) => [{
7773
+ role: "primary",
7774
+ object: {
7775
+ id: ctx.resolveId(e.name),
7776
+ kind: "line",
7777
+ label: e.name,
7778
+ ...SHAPE_BASE_FIELDS,
7779
+ attrs: {
7780
+ construction: {
7781
+ kind: "perpBisector",
7782
+ p1: ctx.resolveId(e.p1),
7783
+ p2: ctx.resolveId(e.p2)
7784
+ }
7785
+ }
7786
+ }
7787
+ }]
7788
+ });
7789
+ }
7790
+ });
7791
+ var angleBisectorModule;
7792
+ var init_angleBisector = __esm({
7793
+ "src/stamps/geometry-2d/dsl/kinds/lines/angleBisector.ts"() {
7794
+ init_names();
7795
+ init_types4();
7796
+ init_shared();
7797
+ angleBisectorModule = defineModule({
7798
+ kind: "angleBisector",
7799
+ role: "lineConstruction",
7800
+ category: "lines",
7801
+ prefix: "l",
7802
+ schema: zod.z.object({
7803
+ name: NameZ,
7804
+ kind: zod.z.literal("angleBisector"),
7805
+ p1: NameZ,
7806
+ vertex: NameZ,
7807
+ p2: NameZ
7808
+ }),
7809
+ collectRefs: (e) => [e.p1, e.vertex, e.p2],
7810
+ emit: (e, ctx) => [{
7811
+ role: "primary",
7812
+ object: {
7813
+ id: ctx.resolveId(e.name),
7814
+ kind: "line",
7815
+ label: e.name,
7816
+ ...SHAPE_BASE_FIELDS,
7817
+ attrs: {
7818
+ construction: {
7819
+ kind: "angleBisector",
7820
+ p1: ctx.resolveId(e.p1),
7821
+ vertex: ctx.resolveId(e.vertex),
7822
+ p2: ctx.resolveId(e.p2)
7823
+ }
7824
+ }
7825
+ }
7826
+ }]
7827
+ });
7828
+ }
7829
+ });
7830
+ var tangentModule;
7831
+ var init_tangent = __esm({
7832
+ "src/stamps/geometry-2d/dsl/kinds/lines/tangent.ts"() {
7833
+ init_names();
7834
+ init_types4();
7835
+ init_shared();
7836
+ tangentModule = defineModule({
7837
+ kind: "tangent",
7838
+ role: "lineConstruction",
7839
+ category: "lines",
7840
+ prefix: "l",
7841
+ schema: zod.z.object({
7842
+ name: NameZ,
7843
+ kind: zod.z.literal("tangent"),
7844
+ throughPoint: NameZ,
7845
+ toCircle: NameZ,
7846
+ branch: zod.z.union([zod.z.literal(0), zod.z.literal(1), zod.z.literal("on")]).optional()
7847
+ }),
7848
+ collectRefs: (e) => [e.throughPoint, e.toCircle],
7849
+ emit: (e, ctx) => {
7850
+ const construction = {
7851
+ kind: "tangent",
7852
+ throughPoint: ctx.resolveId(e.throughPoint),
7853
+ toCircle: ctx.resolveId(e.toCircle)
7854
+ };
7855
+ if (e.branch !== void 0) construction.branch = e.branch;
7856
+ return [{
7857
+ role: "primary",
7858
+ object: {
7859
+ id: ctx.resolveId(e.name),
7860
+ kind: "line",
7861
+ label: e.name,
7862
+ ...SHAPE_BASE_FIELDS,
7863
+ attrs: { construction }
7864
+ }
7865
+ }];
7866
+ }
7867
+ });
7868
+ }
7869
+ });
7870
+ var polygonModule;
7871
+ var init_polygon3 = __esm({
7872
+ "src/stamps/geometry-2d/dsl/kinds/polygons/polygon.ts"() {
7873
+ init_names();
7874
+ init_types4();
7875
+ init_shared();
7876
+ polygonModule = defineModule({
7877
+ kind: "polygon",
7878
+ role: "polygon",
7879
+ category: "polygons",
7880
+ prefix: "poly",
7881
+ schema: zod.z.object({
7882
+ name: NameZ,
7883
+ kind: zod.z.literal("polygon"),
7884
+ vertices: zod.z.array(NameZ).min(3)
7885
+ }),
7886
+ collectRefs: (e) => [...e.vertices],
7887
+ emit: (e, ctx) => [{
7888
+ role: "primary",
7889
+ object: {
7890
+ id: ctx.resolveId(e.name),
7891
+ kind: "polygon",
7892
+ label: e.name,
7893
+ ...SHAPE_BASE_FIELDS,
7894
+ attrs: { vertices: e.vertices.map((v) => ctx.resolveId(v)) }
7895
+ }
7896
+ }]
7897
+ });
7898
+ }
7899
+ });
7900
+ var circleCPModule;
7901
+ var init_circleCP = __esm({
7902
+ "src/stamps/geometry-2d/dsl/kinds/circles/circleCP.ts"() {
7903
+ init_names();
7904
+ init_types4();
7905
+ init_shared();
7906
+ circleCPModule = defineModule({
7907
+ kind: "circleCP",
7908
+ role: "circle",
7909
+ category: "circles",
7910
+ prefix: "c",
7911
+ schema: zod.z.object({
7912
+ name: NameZ,
7913
+ kind: zod.z.literal("circleCP"),
7914
+ center: NameZ,
7915
+ surfacePoint: NameZ
7916
+ }),
7917
+ collectRefs: (e) => [e.center, e.surfacePoint],
7918
+ emit: (e, ctx) => [{
7919
+ role: "primary",
7920
+ object: {
7921
+ id: ctx.resolveId(e.name),
7922
+ kind: "circle",
7923
+ label: e.name,
7924
+ ...SHAPE_BASE_FIELDS,
7925
+ attrs: { center: ctx.resolveId(e.center), surfacePoint: ctx.resolveId(e.surfacePoint) }
7926
+ }
7927
+ }]
7928
+ });
7929
+ }
7930
+ });
7931
+ var circle3Module;
7932
+ var init_circle3 = __esm({
7933
+ "src/stamps/geometry-2d/dsl/kinds/circles/circle3.ts"() {
7934
+ init_names();
7935
+ init_types4();
7936
+ init_shared();
7937
+ circle3Module = defineModule({
7938
+ kind: "circle3",
7939
+ role: "circle",
7940
+ category: "circles",
7941
+ prefix: "c",
7942
+ schema: zod.z.object({
7943
+ name: NameZ,
7944
+ kind: zod.z.literal("circle3"),
7945
+ p1: NameZ,
7946
+ p2: NameZ,
7947
+ p3: NameZ
7948
+ }),
7949
+ collectRefs: (e) => [e.p1, e.p2, e.p3],
7950
+ emit: (e, ctx) => [{
7951
+ role: "primary",
7952
+ object: {
7953
+ id: ctx.resolveId(e.name),
7954
+ kind: "circle",
7955
+ label: e.name,
7956
+ ...SHAPE_BASE_FIELDS,
7957
+ attrs: {
7958
+ construction: {
7959
+ kind: "circumscribed",
7960
+ p1: ctx.resolveId(e.p1),
7961
+ p2: ctx.resolveId(e.p2),
7962
+ p3: ctx.resolveId(e.p3)
7963
+ }
7964
+ }
7965
+ }
7966
+ }]
7967
+ });
7968
+ }
7969
+ });
7970
+ var ALL_MODULES, POINT_KINDS;
7971
+ var init_registry2 = __esm({
7972
+ "src/stamps/geometry-2d/dsl/registry.ts"() {
7973
+ init_free();
7974
+ init_midpoint();
7975
+ init_onSegment();
7976
+ init_onLine();
7977
+ init_onCircle();
7978
+ init_perpFoot();
7979
+ init_circumcenter();
7980
+ init_incenter();
7981
+ init_centroid();
7982
+ init_orthocenter();
7983
+ init_intersection2();
7984
+ init_segment2();
7985
+ init_line2();
7986
+ init_ray2();
7987
+ init_perpendicular();
7988
+ init_parallel();
7989
+ init_perpBisector();
7990
+ init_angleBisector();
7991
+ init_tangent();
7992
+ init_polygon3();
7993
+ init_circleCP();
7994
+ init_circle3();
7995
+ ALL_MODULES = [
7996
+ freeModule,
7997
+ midpointModule,
7998
+ onSegmentModule,
7999
+ onLineModule,
8000
+ onCircleModule,
8001
+ perpFootModule,
8002
+ circumcenterModule,
8003
+ incenterModule,
8004
+ centroidModule,
8005
+ orthocenterModule,
8006
+ intersectionModule,
8007
+ segmentModule,
8008
+ lineModule,
8009
+ rayModule,
8010
+ perpendicularModule,
8011
+ parallelModule,
8012
+ perpBisectorModule,
8013
+ angleBisectorModule,
8014
+ tangentModule,
8015
+ polygonModule,
8016
+ circleCPModule,
8017
+ circle3Module
8018
+ ];
8019
+ new Map(ALL_MODULES.map((m) => [m.kind, m]));
8020
+ POINT_KINDS = new Set(
8021
+ ALL_MODULES.filter((m) => m.role === "point").map((m) => m.kind)
8022
+ );
8023
+ new Set(
8024
+ ALL_MODULES.filter(
8025
+ (m) => m.role === "segment" || m.role === "line" || m.role === "ray" || m.role === "lineConstruction"
8026
+ ).map((m) => m.kind)
8027
+ );
8028
+ new Set(
8029
+ ALL_MODULES.filter((m) => m.role === "circle").map((m) => m.kind)
8030
+ );
8031
+ zod.z.discriminatedUnion(
8032
+ "kind",
8033
+ ALL_MODULES.map((m) => m.schema)
8034
+ );
8035
+ }
8036
+ });
8037
+
8038
+ // src/stamps/geometry-2d/dsl/serialize.ts
8039
+ function isValidName(s) {
8040
+ return NAME_REGEX.test(s);
8041
+ }
8042
+ function labelOf2(id, state) {
8043
+ const obj = state.objects[id];
8044
+ return obj ? obj.label : null;
8045
+ }
8046
+ function resolveRefs(ids, state) {
8047
+ const out = [];
8048
+ for (const id of ids) {
8049
+ const lab = labelOf2(id, state);
8050
+ if (lab == null || !isValidName(lab)) return null;
8051
+ out.push(lab);
8052
+ }
8053
+ return out;
8054
+ }
8055
+ function fail(reason, detail) {
8056
+ return { ok: false, reason, detail };
8057
+ }
8058
+ function serializePoint(obj, state) {
8059
+ const c = obj.attrs?.constraint;
8060
+ if (!c) return fail("unsupported-constraint", "missing");
8061
+ switch (c.kind) {
8062
+ case "free":
8063
+ return { ok: true, entity: { name: obj.label, kind: "free", x: c.x, y: c.y } };
8064
+ case "midpoint": {
8065
+ const refs = resolveRefs([c.p1, c.p2], state);
8066
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2}`);
8067
+ return { ok: true, entity: { name: obj.label, kind: "midpoint", p1: refs[0], p2: refs[1] } };
8068
+ }
8069
+ case "onSegment": {
8070
+ const refs = resolveRefs([c.segmentId], state);
8071
+ if (!refs) return fail("unresolved-ref", c.segmentId);
8072
+ return { ok: true, entity: { name: obj.label, kind: "onSegment", segmentId: refs[0], t: c.t } };
8073
+ }
8074
+ case "onLine": {
8075
+ const refs = resolveRefs([c.lineId], state);
8076
+ if (!refs) return fail("unresolved-ref", c.lineId);
8077
+ return { ok: true, entity: { name: obj.label, kind: "onLine", lineId: refs[0], t: c.t } };
8078
+ }
8079
+ case "onCircle": {
8080
+ const refs = resolveRefs([c.circleId], state);
8081
+ if (!refs) return fail("unresolved-ref", c.circleId);
8082
+ return { ok: true, entity: { name: obj.label, kind: "onCircle", circleId: refs[0], theta: c.theta } };
8083
+ }
8084
+ case "perpFoot": {
8085
+ const refs = resolveRefs([c.from, c.onLine], state);
8086
+ if (!refs) return fail("unresolved-ref", `${c.from},${c.onLine}`);
8087
+ return { ok: true, entity: { name: obj.label, kind: "perpFoot", from: refs[0], onLine: refs[1] } };
8088
+ }
8089
+ case "circumcenter":
8090
+ case "incenter":
8091
+ case "centroid":
8092
+ case "orthocenter": {
8093
+ const refs = resolveRefs(c.vertices, state);
8094
+ if (!refs || refs.length !== 3) return fail("unresolved-ref", c.vertices.join(","));
8095
+ return {
8096
+ ok: true,
8097
+ entity: {
8098
+ name: obj.label,
8099
+ kind: c.kind,
8100
+ vertices: [refs[0], refs[1], refs[2]]
8101
+ }
8102
+ };
8103
+ }
8104
+ // Out of DSL v1:
8105
+ case "onAxis":
8106
+ case "onPolygon":
8107
+ case "transformed":
8108
+ return fail("unsupported-constraint", c.kind);
8109
+ default: {
8110
+ return fail("unsupported-constraint");
8111
+ }
8112
+ }
8113
+ }
8114
+ function serializeIntersection(obj, state) {
8115
+ const a = obj.attrs;
8116
+ const refs = resolveRefs([a.ref1, a.ref2], state);
8117
+ if (!refs) return fail("unresolved-ref", `${a.ref1},${a.ref2}`);
8118
+ if (a.kind === "lineLine") {
8119
+ return { ok: true, entity: { name: obj.label, kind: "intersection", ref1: refs[0], ref2: refs[1] } };
8120
+ }
8121
+ return {
8122
+ ok: true,
8123
+ entity: {
8124
+ name: obj.label,
8125
+ kind: "intersection",
8126
+ ref1: refs[0],
8127
+ ref2: refs[1],
8128
+ branch: a.branch
8129
+ }
8130
+ };
8131
+ }
8132
+ function serializeSegment(obj, state) {
8133
+ const refs = resolveRefs([obj.attrs.p1, obj.attrs.p2], state);
8134
+ if (!refs) return fail("unresolved-ref", `${obj.attrs.p1},${obj.attrs.p2}`);
8135
+ return { ok: true, entity: { name: obj.label, kind: "segment", p1: refs[0], p2: refs[1] } };
8136
+ }
8137
+ function serializeRay(obj, state) {
8138
+ const refs = resolveRefs([obj.attrs.origin, obj.attrs.through], state);
8139
+ if (!refs) return fail("unresolved-ref", `${obj.attrs.origin},${obj.attrs.through}`);
8140
+ return { ok: true, entity: { name: obj.label, kind: "ray", origin: refs[0], through: refs[1] } };
8141
+ }
8142
+ function serializeLine(obj, state) {
8143
+ const a = obj.attrs;
8144
+ const c = a.construction;
8145
+ if (!c) {
8146
+ if (!a.p1 || !a.p2) return fail("unsupported-construction", "missing p1/p2");
8147
+ const refs = resolveRefs([a.p1, a.p2], state);
8148
+ if (!refs) return fail("unresolved-ref", `${a.p1},${a.p2}`);
8149
+ return { ok: true, entity: { name: obj.label, kind: "line", p1: refs[0], p2: refs[1] } };
8150
+ }
8151
+ switch (c.kind) {
8152
+ case "perpendicular":
8153
+ case "parallel": {
8154
+ const refs = resolveRefs([c.throughPoint, c.toLine], state);
8155
+ if (!refs) return fail("unresolved-ref", `${c.throughPoint},${c.toLine}`);
8156
+ return {
8157
+ ok: true,
8158
+ entity: { name: obj.label, kind: c.kind, throughPoint: refs[0], toLine: refs[1] }
8159
+ };
8160
+ }
8161
+ case "perpBisector": {
8162
+ const refs = resolveRefs([c.p1, c.p2], state);
8163
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2}`);
8164
+ return { ok: true, entity: { name: obj.label, kind: "perpBisector", p1: refs[0], p2: refs[1] } };
8165
+ }
8166
+ case "angleBisector": {
8167
+ const refs = resolveRefs([c.p1, c.vertex, c.p2], state);
8168
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.vertex},${c.p2}`);
8169
+ return {
8170
+ ok: true,
8171
+ entity: {
8172
+ name: obj.label,
8173
+ kind: "angleBisector",
8174
+ p1: refs[0],
8175
+ vertex: refs[1],
8176
+ p2: refs[2]
8177
+ }
8178
+ };
8179
+ }
8180
+ case "tangent": {
8181
+ const refs = resolveRefs([c.throughPoint, c.toCircle], state);
8182
+ if (!refs) return fail("unresolved-ref", `${c.throughPoint},${c.toCircle}`);
8183
+ const entity = c.branch !== void 0 ? {
8184
+ name: obj.label,
8185
+ kind: "tangent",
8186
+ throughPoint: refs[0],
8187
+ toCircle: refs[1],
8188
+ branch: c.branch
8189
+ } : { name: obj.label, kind: "tangent", throughPoint: refs[0], toCircle: refs[1] };
8190
+ return { ok: true, entity };
8191
+ }
8192
+ case "angleBisectorLines":
8193
+ return fail("unsupported-construction", "angleBisectorLines");
8194
+ default: {
8195
+ return fail("unsupported-construction");
8196
+ }
8197
+ }
8198
+ }
8199
+ function serializePolygon(obj, state) {
8200
+ const a = obj.attrs;
8201
+ if (a.construction) return fail("unsupported-construction", a.construction.kind);
8202
+ if (!Array.isArray(a.vertices) || a.vertices.length < 3) {
8203
+ return fail("unsupported-construction", "missing vertices");
8204
+ }
8205
+ const refs = resolveRefs(a.vertices, state);
8206
+ if (!refs) return fail("unresolved-ref", a.vertices.join(","));
8207
+ return { ok: true, entity: { name: obj.label, kind: "polygon", vertices: refs } };
8208
+ }
8209
+ function serializeCircle(obj, state) {
8210
+ const a = obj.attrs;
8211
+ const c = a.construction;
8212
+ if (!c) {
8213
+ if (!a.center || !a.surfacePoint) {
8214
+ return fail("unsupported-construction", "missing center/surfacePoint");
8215
+ }
8216
+ const refs = resolveRefs([a.center, a.surfacePoint], state);
8217
+ if (!refs) return fail("unresolved-ref", `${a.center},${a.surfacePoint}`);
8218
+ return {
8219
+ ok: true,
8220
+ entity: { name: obj.label, kind: "circleCP", center: refs[0], surfacePoint: refs[1] }
8221
+ };
8222
+ }
8223
+ if (c.kind === "circumscribed") {
8224
+ const refs = resolveRefs([c.p1, c.p2, c.p3], state);
8225
+ if (!refs) return fail("unresolved-ref", `${c.p1},${c.p2},${c.p3}`);
8226
+ return {
8227
+ ok: true,
8228
+ entity: { name: obj.label, kind: "circle3", p1: refs[0], p2: refs[1], p3: refs[2] }
8229
+ };
8230
+ }
8231
+ return fail("unsupported-construction");
8232
+ }
8233
+ function serializeObject(obj, state) {
8234
+ if (!isValidName(obj.label)) {
8235
+ return fail("invalid-label", obj.label);
8236
+ }
8237
+ switch (obj.kind) {
8238
+ case "point":
8239
+ return serializePoint(obj, state);
8240
+ case "segment":
8241
+ return serializeSegment(obj, state);
8242
+ case "ray":
8243
+ return serializeRay(obj, state);
8244
+ case "line":
8245
+ return serializeLine(obj, state);
8246
+ case "polygon":
8247
+ return serializePolygon(obj, state);
8248
+ case "circle":
8249
+ return serializeCircle(obj, state);
8250
+ case "intersection":
8251
+ return serializeIntersection(obj, state);
8252
+ default:
8253
+ return fail("unsupported-kind", obj.kind);
8254
+ }
8255
+ }
8256
+ function serializeState(state) {
8257
+ const points = [];
8258
+ const shapes = [];
8259
+ const unsupported = [];
8260
+ for (const id of state.order) {
8261
+ const obj = state.objects[id];
8262
+ if (!obj) continue;
8263
+ const r = serializeObject(obj, state);
8264
+ if (!r.ok) {
8265
+ unsupported.push({
8266
+ id: obj.id,
8267
+ label: obj.label,
8268
+ kind: obj.kind,
8269
+ reason: r.reason,
8270
+ detail: r.detail
8271
+ });
8272
+ continue;
8273
+ }
8274
+ if (POINT_KINDS.has(r.entity.kind)) {
8275
+ points.push(r.entity);
8276
+ } else {
8277
+ shapes.push(r.entity);
8278
+ }
8279
+ }
8280
+ return {
8281
+ dsl: { version: 1, points, shapes },
8282
+ unsupported
8283
+ };
8284
+ }
8285
+ var NAME_REGEX;
8286
+ var init_serialize2 = __esm({
8287
+ "src/stamps/geometry-2d/dsl/serialize.ts"() {
8288
+ init_registry2();
8289
+ NAME_REGEX = /^[A-Za-z][A-Za-z0-9_'₀-₉]{0,11}$/;
8290
+ }
8291
+ });
8292
+ function useAiFigure(generator, options = {}) {
8293
+ const { currentState } = options;
7211
8294
  const [prompt, setPrompt] = React.useState("");
7212
8295
  const [isLoading, setIsLoading] = React.useState(false);
7213
8296
  const [error, setError] = React.useState(null);
8297
+ const [tokens, setTokens] = React.useState(0);
7214
8298
  const abortRef = React.useRef(null);
7215
8299
  const requestIdRef = React.useRef(0);
8300
+ const { dsl: currentDsl, unsupported, entityCount, hasContent } = React.useMemo(() => {
8301
+ if (!currentState || currentState.order.length === 0) {
8302
+ return {
8303
+ dsl: null,
8304
+ unsupported: [],
8305
+ entityCount: { points: 0, shapes: 0 },
8306
+ hasContent: false
8307
+ };
8308
+ }
8309
+ const { dsl, unsupported: unsupported2 } = serializeState(currentState);
8310
+ return {
8311
+ dsl,
8312
+ unsupported: unsupported2,
8313
+ entityCount: { points: dsl.points.length, shapes: dsl.shapes.length },
8314
+ hasContent: true
8315
+ };
8316
+ }, [currentState]);
8317
+ const hasUnsupported = unsupported.length > 0;
8318
+ const initialMode = hasContent && !hasUnsupported ? "refine" : "build";
8319
+ const [mode, setModeInternal] = React.useState(initialMode);
8320
+ React.useEffect(() => {
8321
+ if (!hasContent && mode === "refine") setModeInternal("build");
8322
+ if (hasUnsupported && mode === "refine") setModeInternal("build");
8323
+ }, [hasContent, hasUnsupported, mode]);
8324
+ const setMode = React.useCallback((next) => {
8325
+ setModeInternal(next);
8326
+ }, []);
7216
8327
  React.useEffect(() => () => abortRef.current?.abort(), []);
7217
8328
  const submit = React.useCallback(async () => {
7218
8329
  const problem = prompt.trim();
@@ -7230,8 +8341,15 @@ function useAiFigure(generator) {
7230
8341
  abortRef.current = controller;
7231
8342
  setIsLoading(true);
7232
8343
  setError(null);
8344
+ setTokens(0);
7233
8345
  try {
7234
- const generated = await generator(problem, { signal: controller.signal });
8346
+ const generated = await generator(problem, {
8347
+ signal: controller.signal,
8348
+ onProgress: (info) => {
8349
+ if (requestId === requestIdRef.current) setTokens(info.tokens);
8350
+ },
8351
+ ...mode === "refine" && currentDsl ? { currentDsl } : {}
8352
+ });
7235
8353
  if (controller.signal.aborted || requestId !== requestIdRef.current) return null;
7236
8354
  if (!generated.ok) {
7237
8355
  setError(generated.message);
@@ -7243,7 +8361,9 @@ function useAiFigure(generator) {
7243
8361
  return null;
7244
8362
  }
7245
8363
  if (requestId === requestIdRef.current) {
7246
- setError(caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI.");
8364
+ setError(
8365
+ caught instanceof Error && caught.message ? caught.message : "Kh\xF4ng th\u1EC3 d\u1EF1ng h\xECnh b\u1EB1ng AI."
8366
+ );
7247
8367
  }
7248
8368
  return null;
7249
8369
  } finally {
@@ -7252,27 +8372,75 @@ function useAiFigure(generator) {
7252
8372
  setIsLoading(false);
7253
8373
  }
7254
8374
  }
7255
- }, [generator, prompt]);
7256
- return { prompt, setPrompt, isLoading, error, submit };
8375
+ }, [generator, prompt, mode, currentDsl]);
8376
+ const cancel = React.useCallback(() => {
8377
+ abortRef.current?.abort();
8378
+ }, []);
8379
+ return {
8380
+ prompt,
8381
+ setPrompt,
8382
+ isLoading,
8383
+ error,
8384
+ submit,
8385
+ cancel,
8386
+ tokens,
8387
+ mode,
8388
+ setMode,
8389
+ entityCount,
8390
+ hasUnsupported
8391
+ };
7257
8392
  }
7258
8393
  var init_useAiFigure = __esm({
7259
8394
  "src/stamps/geometry-2d/editor/useAiFigure.ts"() {
7260
8395
  "use client";
8396
+ init_serialize2();
7261
8397
  }
7262
8398
  });
7263
- function AiFigurePrompt({ generator, onGenerated }) {
8399
+ function AiFigurePrompt({ generator, onGenerated, currentState }) {
7264
8400
  const {
7265
8401
  prompt,
7266
8402
  setPrompt,
7267
8403
  isLoading,
7268
8404
  error,
7269
- submit
7270
- } = useAiFigure(generator);
7271
- const handleSubmit = React.useCallback(async (event) => {
7272
- event.preventDefault();
7273
- const generated = await submit();
7274
- if (generated) onGenerated(generated);
7275
- }, [onGenerated, submit]);
8405
+ submit,
8406
+ cancel,
8407
+ tokens,
8408
+ mode,
8409
+ setMode,
8410
+ entityCount,
8411
+ hasUnsupported
8412
+ } = useAiFigure(generator, { currentState });
8413
+ const [elapsed, setElapsed] = React.useState(0);
8414
+ React.useEffect(() => {
8415
+ if (!isLoading) {
8416
+ setElapsed(0);
8417
+ return;
8418
+ }
8419
+ setElapsed(0);
8420
+ const id = setInterval(() => setElapsed((s) => s + 1), 1e3);
8421
+ return () => clearInterval(id);
8422
+ }, [isLoading]);
8423
+ const handleSubmit = React.useCallback(
8424
+ async (event) => {
8425
+ event.preventDefault();
8426
+ const generated = await submit();
8427
+ if (generated) onGenerated(generated);
8428
+ },
8429
+ [onGenerated, submit]
8430
+ );
8431
+ const handleSwitchToBuild = React.useCallback(() => {
8432
+ if (currentState && currentState.order.length > 0) {
8433
+ const ok = window.confirm(
8434
+ "D\u1EF1ng m\u1EDBi s\u1EBD thay to\xE0n b\u1ED9 h\xECnh hi\u1EC7n t\u1EA1i b\u1EB1ng h\xECnh m\u1EDBi t\u1EEB AI. Ti\u1EBFp t\u1EE5c?"
8435
+ );
8436
+ if (!ok) return;
8437
+ }
8438
+ setMode("build");
8439
+ }, [currentState, setMode]);
8440
+ const primaryLabel = isLoading ? tokens > 0 ? `\u0110ang d\u1EF1ng ${tokens}tok / ${elapsed}s \u2014 Hu\u1EF7` : `\u0110ang d\u1EF1ng... ${elapsed}s \u2014 Hu\u1EF7` : "D\u1EF1ng b\u1EB1ng AI";
8441
+ const hasContent = currentState != null && currentState.order.length > 0;
8442
+ const examples = mode === "refine" ? REFINE_EXAMPLES : BUILD_EXAMPLES;
8443
+ const refineChipLabel = entityCount.points + entityCount.shapes > 0 ? `Th\xEAm v\xE0o \xB7 ${entityCount.points}\u0111, ${entityCount.shapes}\u0111o\u1EA1n` : "Th\xEAm v\xE0o";
7276
8444
  return /* @__PURE__ */ jsxRuntime.jsxs(
7277
8445
  "form",
7278
8446
  {
@@ -7282,7 +8450,47 @@ function AiFigurePrompt({ generator, onGenerated }) {
7282
8450
  },
7283
8451
  className: "border-b border-slate-200 bg-slate-50 px-3 py-2",
7284
8452
  children: [
7285
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: "geometry-ai-prompt", className: "mb-1 block text-xs font-medium text-slate-600", children: "D\u1EF1ng h\xECnh b\u1EB1ng AI" }),
8453
+ /* @__PURE__ */ jsxRuntime.jsx(
8454
+ "label",
8455
+ {
8456
+ htmlFor: "geometry-ai-prompt",
8457
+ className: "mb-1 block text-xs font-medium text-slate-600",
8458
+ children: "D\u1EF1ng h\xECnh b\u1EB1ng AI"
8459
+ }
8460
+ ),
8461
+ hasContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-center gap-2", children: [
8462
+ /* @__PURE__ */ jsxRuntime.jsx(
8463
+ "button",
8464
+ {
8465
+ type: "button",
8466
+ "data-testid": "geometry-ai-mode-refine",
8467
+ onClick: () => setMode("refine"),
8468
+ disabled: isLoading || hasUnsupported,
8469
+ className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "refine" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"} ${hasUnsupported ? "cursor-not-allowed opacity-50" : ""}`,
8470
+ title: hasUnsupported ? "H\xECnh hi\u1EC7n t\u1EA1i c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL \u2014 ch\u1EC9 d\u1EF1ng m\u1EDBi \u0111\u01B0\u1EE3c" : refineChipLabel,
8471
+ children: refineChipLabel
8472
+ }
8473
+ ),
8474
+ /* @__PURE__ */ jsxRuntime.jsx(
8475
+ "button",
8476
+ {
8477
+ type: "button",
8478
+ "data-testid": "geometry-ai-mode-build",
8479
+ onClick: handleSwitchToBuild,
8480
+ disabled: isLoading,
8481
+ className: `rounded-full border px-2 py-0.5 text-[11px] transition ${mode === "build" ? "border-emerald-600 bg-emerald-100 text-emerald-800" : "border-slate-300 bg-white text-slate-600 hover:border-emerald-400"}`,
8482
+ children: "D\u1EF1ng m\u1EDBi"
8483
+ }
8484
+ ),
8485
+ hasUnsupported && /* @__PURE__ */ jsxRuntime.jsx(
8486
+ "span",
8487
+ {
8488
+ className: "text-[10px] text-amber-700",
8489
+ "data-testid": "geometry-ai-unsupported-warning",
8490
+ children: "H\xECnh c\xF3 \u0111\u1ED1i t\u01B0\u1EE3ng ngo\xE0i DSL"
8491
+ }
8492
+ )
8493
+ ] }),
7286
8494
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
7287
8495
  /* @__PURE__ */ jsxRuntime.jsx(
7288
8496
  "textarea",
@@ -7293,29 +8501,63 @@ function AiFigurePrompt({ generator, onGenerated }) {
7293
8501
  onChange: (event) => setPrompt(event.target.value),
7294
8502
  disabled: isLoading,
7295
8503
  rows: 2,
7296
- placeholder: "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
8504
+ placeholder: mode === "refine" ? "V\xED d\u1EE5: th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC" : "V\xED d\u1EE5: Cho tam gi\xE1c ABC, d\u1EF1ng \u0111\u01B0\u1EDDng cao AH.",
7297
8505
  className: "min-h-12 flex-1 resize-none rounded border border-slate-300 bg-white px-2 py-1.5 text-xs text-slate-800 outline-none focus:border-emerald-500 disabled:opacity-60"
7298
8506
  }
7299
8507
  ),
7300
- /* @__PURE__ */ jsxRuntime.jsx(
8508
+ isLoading ? /* @__PURE__ */ jsxRuntime.jsx(
8509
+ "button",
8510
+ {
8511
+ type: "button",
8512
+ onClick: cancel,
8513
+ className: "rounded bg-amber-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-amber-700",
8514
+ children: primaryLabel
8515
+ }
8516
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
7301
8517
  "button",
7302
8518
  {
7303
8519
  type: "submit",
7304
- disabled: isLoading || !prompt.trim(),
8520
+ disabled: !prompt.trim(),
7305
8521
  className: "rounded bg-emerald-600 px-3 py-2 text-xs font-medium text-white transition hover:bg-emerald-700 disabled:opacity-50",
7306
- children: isLoading ? "\u0110ang d\u1EF1ng..." : "D\u1EF1ng b\u1EB1ng AI"
8522
+ children: primaryLabel
7307
8523
  }
7308
8524
  )
7309
8525
  ] }),
7310
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error })
8526
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "mt-1 text-xs text-red-600", children: error }),
8527
+ !isLoading && !prompt.trim() && !error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-1", children: [
8528
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-slate-500", children: "G\u1EE3i \xFD:" }),
8529
+ examples.map((ex) => /* @__PURE__ */ jsxRuntime.jsx(
8530
+ "button",
8531
+ {
8532
+ type: "button",
8533
+ onClick: () => setPrompt(ex),
8534
+ className: "rounded-full border border-slate-300 bg-white px-2 py-0.5 text-[10px] text-slate-600 transition hover:border-emerald-400 hover:bg-emerald-50 hover:text-emerald-700",
8535
+ children: ex
8536
+ },
8537
+ ex
8538
+ ))
8539
+ ] })
7311
8540
  ]
7312
8541
  }
7313
8542
  );
7314
8543
  }
8544
+ var BUILD_EXAMPLES, REFINE_EXAMPLES;
7315
8545
  var init_AiFigurePrompt = __esm({
7316
8546
  "src/stamps/geometry-2d/editor/AiFigurePrompt.tsx"() {
7317
8547
  "use client";
7318
8548
  init_useAiFigure();
8549
+ BUILD_EXAMPLES = [
8550
+ "Tam gi\xE1c ABC, d\u1EF1ng trung \u0111i\u1EC3m M c\u1EE7a BC",
8551
+ "Tam gi\xE1c ABC vu\xF4ng t\u1EA1i A, AH l\xE0 \u0111\u01B0\u1EDDng cao xu\u1ED1ng BC",
8552
+ "H\xECnh thoi ABCD, hai \u0111\u01B0\u1EDDng ch\xE9o c\u1EAFt nhau t\u1EA1i O",
8553
+ "T\u1EEB \u0111i\u1EC3m M ngo\xE0i \u0111\u01B0\u1EDDng tr\xF2n (O), k\u1EBB hai ti\u1EBFp tuy\u1EBFn"
8554
+ ];
8555
+ REFINE_EXAMPLES = [
8556
+ "Th\xEAm trung \u0111i\u1EC3m M c\u1EE7a BC",
8557
+ "D\u1EF1ng \u0111\u01B0\u1EDDng cao AH xu\u1ED1ng BC",
8558
+ "V\u1EBD \u0111\u01B0\u1EDDng tr\xF2n ngo\u1EA1i ti\u1EBFp",
8559
+ "Th\xEAm ti\u1EBFp tuy\u1EBFn t\u1EA1i A"
8560
+ ];
7319
8561
  }
7320
8562
  });
7321
8563
  var GeometryEditorPanelInner, GeometryEditorPanel;
@@ -7366,6 +8608,11 @@ var init_EditorPanel = __esm({
7366
8608
  onSelectionChangeRef.current = onSelectionChange;
7367
8609
  }, [onSelectionChange]);
7368
8610
  useEditorState({ store, onHistoryChange });
8611
+ const currentSceneState = React.useSyncExternalStore(
8612
+ (cb) => store.subscribe(cb),
8613
+ () => store.getState(),
8614
+ () => store.getState()
8615
+ );
7369
8616
  React.useEffect(() => {
7370
8617
  const sync = () => setHasContent(Object.keys(store.getState().objects).length > 0);
7371
8618
  sync();
@@ -7559,7 +8806,7 @@ var init_EditorPanel = __esm({
7559
8806
  /* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" })
7560
8807
  ] }) })
7561
8808
  ] }),
7562
- generateGeometryFigure && /* @__PURE__ */ jsxRuntime.jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure }),
8809
+ generateGeometryFigure && /* @__PURE__ */ jsxRuntime.jsx(AiFigurePrompt, { generator: generateGeometryFigure, onGenerated: loadAiFigure, currentState: currentSceneState }),
7563
8810
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex min-h-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsx(
7564
8811
  MiniBoard2D,
7565
8812
  {
@@ -7850,6 +9097,116 @@ var init_useStampStore = __esm({
7850
9097
  }
7851
9098
  });
7852
9099
 
9100
+ // src/stamps/geometry-2d/dsl/describeDsl.ts
9101
+ function describeEntity(e) {
9102
+ switch (e.kind) {
9103
+ case "free":
9104
+ return `${e.name} = (${e.x}, ${e.y})`;
9105
+ case "midpoint":
9106
+ return `${e.name} = trung \u0111i\u1EC3m ${e.p1}${e.p2}`;
9107
+ case "onSegment":
9108
+ return `${e.name} \u2208 \u0111o\u1EA1n ${e.segmentId} (t = ${e.t})`;
9109
+ case "onLine":
9110
+ return `${e.name} \u2208 \u0111\u01B0\u1EDDng ${e.lineId} (t = ${e.t})`;
9111
+ case "onCircle":
9112
+ return `${e.name} \u2208 \u0111\u01B0\u1EDDng tr\xF2n ${e.circleId} (\u03B8 = ${e.theta})`;
9113
+ case "perpFoot":
9114
+ return `${e.name} = ch\xE2n vu\xF4ng g\xF3c t\u1EEB ${e.from} xu\u1ED1ng ${e.onLine}`;
9115
+ case "circumcenter":
9116
+ return `${e.name} = t\xE2m ngo\u1EA1i ti\u1EBFp ${e.vertices.join("")}`;
9117
+ case "incenter":
9118
+ return `${e.name} = t\xE2m n\u1ED9i ti\u1EBFp ${e.vertices.join("")}`;
9119
+ case "centroid":
9120
+ return `${e.name} = tr\u1ECDng t\xE2m ${e.vertices.join("")}`;
9121
+ case "orthocenter":
9122
+ return `${e.name} = tr\u1EF1c t\xE2m ${e.vertices.join("")}`;
9123
+ case "intersection": {
9124
+ const branch = "branch" in e && e.branch !== void 0 ? ` (nh\xE1nh ${e.branch})` : "";
9125
+ return `${e.name} = ${e.ref1} \u2229 ${e.ref2}${branch}`;
9126
+ }
9127
+ case "segment":
9128
+ return `${e.name} = \u0111o\u1EA1n ${e.p1}${e.p2}`;
9129
+ case "line":
9130
+ return `${e.name} = \u0111\u01B0\u1EDDng th\u1EB3ng ${e.p1}${e.p2}`;
9131
+ case "ray":
9132
+ return `${e.name} = tia ${e.origin}${e.through}`;
9133
+ case "polygon":
9134
+ return `${e.name} = \u0111a gi\xE1c ${e.vertices.join("")}`;
9135
+ case "perpendicular":
9136
+ return `${e.name} \u27C2 ${e.toLine} qua ${e.throughPoint}`;
9137
+ case "parallel":
9138
+ return `${e.name} \u2225 ${e.toLine} qua ${e.throughPoint}`;
9139
+ case "perpBisector":
9140
+ return `${e.name} = trung tr\u1EF1c ${e.p1}${e.p2}`;
9141
+ case "angleBisector":
9142
+ return `${e.name} = ph\xE2n gi\xE1c \u2220${e.p1}${e.vertex}${e.p2}`;
9143
+ case "tangent": {
9144
+ const branch = "branch" in e && e.branch !== void 0 ? ` (nh\xE1nh ${e.branch})` : "";
9145
+ return `${e.name} = ti\u1EBFp tuy\u1EBFn ${e.toCircle} qua ${e.throughPoint}${branch}`;
9146
+ }
9147
+ case "circleCP":
9148
+ return `${e.name} = (${e.center}; ${e.center}${e.surfacePoint})`;
9149
+ case "circle3":
9150
+ return `${e.name} = \u0111\u01B0\u1EDDng tr\xF2n qua ${e.p1}${e.p2}${e.p3}`;
9151
+ default: {
9152
+ return "";
9153
+ }
9154
+ }
9155
+ }
9156
+ function describeDsl(obj, state) {
9157
+ const r = serializeObject(obj, state);
9158
+ if (r.ok) return describeEntity(r.entity);
9159
+ let base;
9160
+ try {
9161
+ base = getKind(obj.kind).describe(obj, state);
9162
+ } catch {
9163
+ base = `${obj.kind} ${obj.label}`;
9164
+ }
9165
+ return `${base} (kh\xF4ng h\u1ED7 tr\u1EE3 DSL)`;
9166
+ }
9167
+ var init_describeDsl = __esm({
9168
+ "src/stamps/geometry-2d/dsl/describeDsl.ts"() {
9169
+ init_registry();
9170
+ init_serialize2();
9171
+ }
9172
+ });
9173
+ function makeDslRenderRow(store) {
9174
+ return function renderDslRow(obj, defaults) {
9175
+ const state = store.getState();
9176
+ const noop = () => {
9177
+ };
9178
+ return /* @__PURE__ */ jsxRuntime.jsx(
9179
+ ObjectRow,
9180
+ {
9181
+ obj,
9182
+ state,
9183
+ selected: defaults.selected,
9184
+ onSelect: defaults.onClick,
9185
+ onToggleVisible: (id) => {
9186
+ const o = state.objects[id];
9187
+ if (!o) return;
9188
+ store.dispatch({ type: "UPDATE", payload: { id, patch: { visible: !o.visible } } });
9189
+ },
9190
+ onToggleLocked: (id) => {
9191
+ const o = state.objects[id];
9192
+ if (!o) return;
9193
+ store.dispatch({ type: "UPDATE", payload: { id, patch: { locked: !o.locked } } });
9194
+ },
9195
+ onRename: noop,
9196
+ onChangeColor: noop,
9197
+ onDelete: (id) => store.dispatch({ type: "DELETE", payload: { id } }),
9198
+ describe: describeDsl
9199
+ }
9200
+ );
9201
+ };
9202
+ }
9203
+ var init_dslRenderRow = __esm({
9204
+ "src/stamps/geometry-2d/editor/dslRenderRow.tsx"() {
9205
+ init_ObjectRow();
9206
+ init_describeDsl();
9207
+ }
9208
+ });
9209
+
7853
9210
  // src/stamps/geometry-2d/host.tsx
7854
9211
  var host_exports = {};
7855
9212
  __export(host_exports, {
@@ -7874,6 +9231,7 @@ var init_host = __esm({
7874
9231
  init_scene();
7875
9232
  init_useIsMobile();
7876
9233
  init_useStampStore();
9234
+ init_dslRenderRow();
7877
9235
  GeometryStampHost = React.forwardRef(
7878
9236
  function GeometryStampHost2({ api, editingElement, onClose, isDark, generateGeometryFigure }, ref) {
7879
9237
  const panelRef = React.useRef(null);
@@ -7900,6 +9258,7 @@ var init_host = __esm({
7900
9258
  onSelect: (key) => setSelectedTool(key),
7901
9259
  enabled: !isMobile
7902
9260
  });
9261
+ const renderRow = React.useMemo(() => makeDslRenderRow(sceneStore), [sceneStore]);
7903
9262
  const handleInsert = React.useCallback(
7904
9263
  async (jsonState, svgString) => {
7905
9264
  if (!api) return;
@@ -7961,7 +9320,8 @@ var init_host = __esm({
7961
9320
  onObjectSelect: (id) => {
7962
9321
  setSelectedObjectId(id ?? void 0);
7963
9322
  panelRef.current?.selectObject(id);
7964
- }
9323
+ },
9324
+ renderRow
7965
9325
  },
7966
9326
  isMobile,
7967
9327
  drawerOpen,