ducjs 2.2.3 → 2.4.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 (39) hide show
  1. package/dist/flatbuffers/duc/document-grid-align-items.d.ts +5 -0
  2. package/dist/flatbuffers/duc/document-grid-align-items.js +8 -0
  3. package/dist/flatbuffers/duc/document-grid-config.d.ts +24 -0
  4. package/dist/flatbuffers/duc/document-grid-config.js +81 -0
  5. package/dist/flatbuffers/duc/duc-doc-element.d.ts +6 -0
  6. package/dist/flatbuffers/duc/duc-doc-element.js +16 -1
  7. package/dist/flatbuffers/duc/duc-model-element.d.ts +26 -0
  8. package/dist/flatbuffers/duc/duc-model-element.js +79 -0
  9. package/dist/flatbuffers/duc/duc-pdf-element.d.ts +3 -1
  10. package/dist/flatbuffers/duc/duc-pdf-element.js +9 -7
  11. package/dist/flatbuffers/duc/element.d.ts +5 -3
  12. package/dist/flatbuffers/duc/element.js +4 -0
  13. package/dist/flatbuffers/duc.d.ts +3 -0
  14. package/dist/flatbuffers/duc.js +3 -0
  15. package/dist/index.d.ts +4 -3
  16. package/dist/index.js +4 -3
  17. package/dist/lazy-files.d.ts +84 -0
  18. package/dist/lazy-files.js +207 -0
  19. package/dist/parse.d.ts +35 -2
  20. package/dist/parse.js +244 -14
  21. package/dist/restore/restoreDataState.d.ts +1 -6
  22. package/dist/restore/restoreDataState.js +4 -11
  23. package/dist/restore/restoreElements.js +51 -26
  24. package/dist/serialize.js +56 -27
  25. package/dist/types/elements/index.d.ts +32 -31
  26. package/dist/types/elements/typeChecks.d.ts +4 -1
  27. package/dist/types/elements/typeChecks.js +7 -1
  28. package/dist/types/index.d.ts +3 -3
  29. package/dist/types/index.js +1 -1
  30. package/dist/utils/constants.d.ts +18 -14
  31. package/dist/utils/constants.js +28 -15
  32. package/dist/utils/elements/freedrawElement.d.ts +6 -0
  33. package/dist/utils/elements/freedrawElement.js +28 -11
  34. package/dist/utils/elements/newElement.d.ts +2 -2
  35. package/dist/utils/elements/newElement.js +14 -5
  36. package/dist/utils/elements/textElement.d.ts +3 -3
  37. package/dist/utils/elements/textElement.js +43 -16
  38. package/dist/utils/state/index.js +1 -1
  39. package/package.json +1 -1
@@ -3,7 +3,7 @@ isValidColor, isValidDucHead, isValidEnumValue, isValidFunction, isValidImageSca
3
3
  import { getPrecisionValueFromRaw, getPrecisionValueFromScoped, getScaledZoomValueForScope, getScopedBezierPointFromDucPoint, getScopedZoomValue, NEUTRAL_SCOPE, ScaleFactors, } from "../technical/scopes";
4
4
  import { isElbowArrow, isLinearElement, isTextElement, } from "../types";
5
5
  import { arrayToMap, bumpVersion, DEFAULT_ELEMENT_PROPS, DEFAULT_ELLIPSE_ELEMENT, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_FREEDRAW_ELEMENT, detectLineHeight, FONT_FAMILY, getContainerElement, getDefaultLocalState, getDefaultTableData, getNormalizedDimensions, getNormalizedPoints, getNormalizedZoom, getSizeFromPoints, getUpdatedTimestamp, isFiniteNumber, isInvisiblySmallElement, LINE_CONFIRM_THRESHOLD, mergeOverlappingPoints, migratePoints, normalizeFixedPoint, normalizeLink, randomId, refreshTextDimensions, validateClosedPath, } from "../utils";
6
- import { AXIS, BLOCK_ATTACHMENT, COLUMN_TYPE, DATUM_BRACKET_STYLE, DIMENSION_FIT_RULE, DIMENSION_TEXT_PLACEMENT, DIMENSION_TYPE, GDT_SYMBOL, LEADER_CONTENT_TYPE, LINE_SPACING_TYPE, MARK_ELLIPSE_CENTER, MATERIAL_CONDITION, PARAMETRIC_SOURCE_TYPE, STACKED_TEXT_ALIGN, TABLE_CELL_ALIGNMENT, TABLE_FLOW_DIRECTION, TEXT_FLOW_DIRECTION, TOLERANCE_DISPLAY, TOLERANCE_ZONE_TYPE, VERTICAL_ALIGN, VIEWPORT_SHADE_PLOT, } from "../flatbuffers/duc";
6
+ import { AXIS, BLOCK_ATTACHMENT, COLUMN_TYPE, DATUM_BRACKET_STYLE, DIMENSION_FIT_RULE, DIMENSION_TEXT_PLACEMENT, DIMENSION_TYPE, GDT_SYMBOL, LEADER_CONTENT_TYPE, LINE_SPACING_TYPE, MARK_ELLIPSE_CENTER, MATERIAL_CONDITION, STACKED_TEXT_ALIGN, TABLE_CELL_ALIGNMENT, TABLE_FLOW_DIRECTION, TEXT_FLOW_DIRECTION, TOLERANCE_DISPLAY, TOLERANCE_ZONE_TYPE, VERTICAL_ALIGN, VIEWPORT_SHADE_PLOT, } from "../flatbuffers/duc";
7
7
  import tinycolor from "tinycolor2";
8
8
  const restoreElementWithProperties = (element, extra, localState, globalState) => {
9
9
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
@@ -80,7 +80,7 @@ const restoreElementWithProperties = (element, extra, localState, globalState) =
80
80
  return Object.assign(Object.assign(Object.assign(Object.assign({}, _element), base), normalized), { type: _element.type });
81
81
  };
82
82
  const restoreElement = (element, currentScope, restoredBlocks, localState, globalState) => {
83
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
83
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
84
84
  // Migration: convert deprecated 'diamond' to 'polygon' with 4 sides
85
85
  if (element.type === "diamond") {
86
86
  const migrated = Object.assign(Object.assign({}, element), { type: "polygon", sides: 4 });
@@ -90,6 +90,10 @@ const restoreElement = (element, currentScope, restoredBlocks, localState, globa
90
90
  case "text": {
91
91
  let fontSize = element.fontSize;
92
92
  let fontFamily = element.fontFamily;
93
+ // Restore condition: if font family is "10", change to DEFAULT_FONT_FAMILY
94
+ if (fontFamily === "10") {
95
+ fontFamily = DEFAULT_FONT_FAMILY;
96
+ }
93
97
  if ("font" in element) {
94
98
  try {
95
99
  const fontParts = String(element.font).split(" ");
@@ -343,7 +347,10 @@ const restoreElement = (element, currentScope, restoredBlocks, localState, globa
343
347
  }
344
348
  // Other elements
345
349
  case "pdf":
346
- return restoreElementWithProperties(element, { fileId: isValidString(element.fileId) || null }, localState);
350
+ return restoreElementWithProperties(element, {
351
+ fileId: isValidString(element.fileId) || null,
352
+ gridConfig: restoreDocumentGridConfig(element.gridConfig),
353
+ }, localState);
347
354
  case "mermaid":
348
355
  return restoreElementWithProperties(element, {
349
356
  source: isValidString(element.source),
@@ -381,7 +388,7 @@ const restoreElement = (element, currentScope, restoredBlocks, localState, globa
381
388
  const docElement = element;
382
389
  return restoreElementWithProperties(element, Object.assign(Object.assign({}, restoreDocStyleProperties(docElement, currentScope)), { text: isValidString(docElement.text), dynamic: restoreTextDynamicParts(docElement.dynamic), flowDirection: (Object.values(TEXT_FLOW_DIRECTION)).includes(docElement.flowDirection)
383
390
  ? docElement.flowDirection
384
- : TEXT_FLOW_DIRECTION.TOP_TO_BOTTOM, columns: restoreTextColumns(docElement.columns, currentScope), autoResize: isValidBooleanValue(docElement.autoResize, true) }), localState);
391
+ : TEXT_FLOW_DIRECTION.TOP_TO_BOTTOM, columns: restoreTextColumns(docElement.columns, currentScope), autoResize: isValidBooleanValue(docElement.autoResize, true), fileId: isValidString(docElement.fileId) || null, gridConfig: restoreDocumentGridConfig(docElement.gridConfig) }), localState);
385
392
  }
386
393
  case "xray": {
387
394
  const xrayElement = element;
@@ -393,22 +400,13 @@ const restoreElement = (element, currentScope, restoredBlocks, localState, globa
393
400
  color: isValidColor(xrayElement.color, "#FF00FF"),
394
401
  }, localState, globalState);
395
402
  }
396
- case "parametric": {
397
- const parametricElement = element;
398
- let source;
399
- if (((_s = parametricElement.source) === null || _s === void 0 ? void 0 : _s.type) === PARAMETRIC_SOURCE_TYPE.FILE) {
400
- source = {
401
- type: PARAMETRIC_SOURCE_TYPE.FILE,
402
- fileId: isValidString((_t = parametricElement.source) === null || _t === void 0 ? void 0 : _t.fileId),
403
- };
404
- }
405
- else {
406
- source = {
407
- type: PARAMETRIC_SOURCE_TYPE.CODE,
408
- code: isValidString((_u = parametricElement.source) === null || _u === void 0 ? void 0 : _u.code),
409
- };
410
- }
411
- return restoreElementWithProperties(parametricElement, { source }, localState, globalState);
403
+ case "model": {
404
+ const modelElement = element;
405
+ return restoreElementWithProperties(modelElement, {
406
+ source: isValidString(modelElement.source),
407
+ fileIds: modelElement.fileIds || [],
408
+ svgPath: modelElement.svgPath || null,
409
+ }, localState, globalState);
412
410
  }
413
411
  case "featurecontrolframe": {
414
412
  const fcfElement = element;
@@ -417,15 +415,15 @@ const restoreElement = (element, currentScope, restoredBlocks, localState, globa
417
415
  // Restore style properties
418
416
  textStyle: restoreTextStyle(fcfElement.textStyle, currentScope),
419
417
  layout: {
420
- padding: restorePrecisionValue((_v = fcfElement.layout) === null || _v === void 0 ? void 0 : _v.padding, elementScope, currentScope, 2),
421
- segmentSpacing: restorePrecisionValue((_w = fcfElement.layout) === null || _w === void 0 ? void 0 : _w.segmentSpacing, elementScope, currentScope, 2),
422
- rowSpacing: restorePrecisionValue((_x = fcfElement.layout) === null || _x === void 0 ? void 0 : _x.rowSpacing, elementScope, currentScope, 2),
418
+ padding: restorePrecisionValue((_s = fcfElement.layout) === null || _s === void 0 ? void 0 : _s.padding, elementScope, currentScope, 2),
419
+ segmentSpacing: restorePrecisionValue((_t = fcfElement.layout) === null || _t === void 0 ? void 0 : _t.segmentSpacing, elementScope, currentScope, 2),
420
+ rowSpacing: restorePrecisionValue((_u = fcfElement.layout) === null || _u === void 0 ? void 0 : _u.rowSpacing, elementScope, currentScope, 2),
423
421
  },
424
422
  symbols: {
425
- scale: (_z = (_y = fcfElement.symbols) === null || _y === void 0 ? void 0 : _y.scale) !== null && _z !== void 0 ? _z : 1,
423
+ scale: (_w = (_v = fcfElement.symbols) === null || _v === void 0 ? void 0 : _v.scale) !== null && _w !== void 0 ? _w : 1,
426
424
  },
427
425
  datumStyle: {
428
- bracketStyle: isValidEnumValue((_0 = fcfElement.datumStyle) === null || _0 === void 0 ? void 0 : _0.bracketStyle, DATUM_BRACKET_STYLE, DATUM_BRACKET_STYLE.SQUARE),
426
+ bracketStyle: isValidEnumValue((_x = fcfElement.datumStyle) === null || _x === void 0 ? void 0 : _x.bracketStyle, DATUM_BRACKET_STYLE, DATUM_BRACKET_STYLE.SQUARE),
429
427
  },
430
428
  // Restore data properties
431
429
  rows: restoreFcfRows(fcfElement.rows),
@@ -973,6 +971,28 @@ const restoreTextColumns = (columns, currentScope) => {
973
971
  autoHeight: isValidBooleanValue(columns.autoHeight, true),
974
972
  };
975
973
  };
974
+ const restoreDocumentGridConfig = (gridConfig) => {
975
+ if (!gridConfig || typeof gridConfig !== "object") {
976
+ return {
977
+ columns: 1,
978
+ gapX: 0,
979
+ gapY: 0,
980
+ alignItems: "start",
981
+ firstPageAlone: false,
982
+ scale: 1,
983
+ };
984
+ }
985
+ return {
986
+ columns: typeof gridConfig.columns === "number" ? gridConfig.columns : 1,
987
+ gapX: typeof gridConfig.gapX === "number" ? gridConfig.gapX : 0,
988
+ gapY: typeof gridConfig.gapY === "number" ? gridConfig.gapY : 0,
989
+ alignItems: (typeof gridConfig.alignItems === "string" && ["start", "center", "end"].includes(gridConfig.alignItems))
990
+ ? gridConfig.alignItems
991
+ : "start",
992
+ firstPageAlone: typeof gridConfig.firstPageAlone === "boolean" ? gridConfig.firstPageAlone : false,
993
+ scale: typeof gridConfig.scale === "number" ? gridConfig.scale : 1,
994
+ };
995
+ };
976
996
  const getFontFamilyByName = (fontFamilyName) => {
977
997
  if (Object.keys(FONT_FAMILY).includes(fontFamilyName)) {
978
998
  return FONT_FAMILY[fontFamilyName];
@@ -1258,10 +1278,15 @@ const restoreFcfDatumDefinition = (def, elementScope, currentScope, restoredBloc
1258
1278
  const restoreTextStyle = (style, currentScope) => {
1259
1279
  var _a, _b, _c;
1260
1280
  const defaultLineHeight = 1.15;
1281
+ // Restore condition: if font family is "10", change to DEFAULT_FONT_FAMILY
1282
+ let fontFamily = style === null || style === void 0 ? void 0 : style.fontFamily;
1283
+ if (fontFamily === "10") {
1284
+ fontFamily = DEFAULT_FONT_FAMILY;
1285
+ }
1261
1286
  return {
1262
1287
  // Text-specific styles
1263
1288
  isLtr: isValidBoolean(style === null || style === void 0 ? void 0 : style.isLtr, true),
1264
- fontFamily: getFontFamilyByName(style === null || style === void 0 ? void 0 : style.fontFamily),
1289
+ fontFamily: getFontFamilyByName(fontFamily),
1265
1290
  bigFontFamily: isValidString(style === null || style === void 0 ? void 0 : style.bigFontFamily, "sans-serif"),
1266
1291
  textAlign: isValidTextAlignValue(style === null || style === void 0 ? void 0 : style.textAlign),
1267
1292
  verticalAlign: isValidVerticalAlignValue(style === null || style === void 0 ? void 0 : style.verticalAlign),
package/dist/serialize.js CHANGED
@@ -740,6 +740,25 @@ function writeColumnLayout(b, c, usv) {
740
740
  Duc.ColumnLayout.addAutoHeight(b, c.autoHeight);
741
741
  return Duc.ColumnLayout.endColumnLayout(b);
742
742
  }
743
+ function writeDocumentGridConfig(b, config, usv) {
744
+ Duc.DocumentGridConfig.startDocumentGridConfig(b);
745
+ Duc.DocumentGridConfig.addColumns(b, config.columns);
746
+ Duc.DocumentGridConfig.addGapX(b, config.gapX);
747
+ Duc.DocumentGridConfig.addGapY(b, config.gapY);
748
+ const alignItems = (() => {
749
+ if (config.alignItems === 'start')
750
+ return Duc.DOCUMENT_GRID_ALIGN_ITEMS.START;
751
+ if (config.alignItems === 'center')
752
+ return Duc.DOCUMENT_GRID_ALIGN_ITEMS.CENTER;
753
+ if (config.alignItems === 'end')
754
+ return Duc.DOCUMENT_GRID_ALIGN_ITEMS.END;
755
+ return Duc.DOCUMENT_GRID_ALIGN_ITEMS.START;
756
+ })();
757
+ Duc.DocumentGridConfig.addAlignItems(b, alignItems);
758
+ Duc.DocumentGridConfig.addFirstPageAlone(b, config.firstPageAlone);
759
+ Duc.DocumentGridConfig.addScale(b, config.scale);
760
+ return Duc.DocumentGridConfig.endDocumentGridConfig(b);
761
+ }
743
762
  function writeText(b, e, usv) {
744
763
  var _a;
745
764
  const base = writeElementBase(b, e, usv);
@@ -836,8 +855,14 @@ function writeBlockInstance(b, i, usv) {
836
855
  Duc.DucBlockDuplicationArray.startDucBlockDuplicationArray(b);
837
856
  Duc.DucBlockDuplicationArray.addRows(b, i.duplicationArray.rows);
838
857
  Duc.DucBlockDuplicationArray.addCols(b, i.duplicationArray.cols);
839
- Duc.DucBlockDuplicationArray.addRowSpacing(b, getPrecisionValue(i.duplicationArray.rowSpacing, usv));
840
- Duc.DucBlockDuplicationArray.addColSpacing(b, getPrecisionValue(i.duplicationArray.colSpacing, usv));
858
+ const rSpacing = typeof i.duplicationArray.rowSpacing === 'number'
859
+ ? i.duplicationArray.rowSpacing
860
+ : getPrecisionValue(i.duplicationArray.rowSpacing, usv);
861
+ const cSpacing = typeof i.duplicationArray.colSpacing === 'number'
862
+ ? i.duplicationArray.colSpacing
863
+ : getPrecisionValue(i.duplicationArray.colSpacing, usv);
864
+ Duc.DucBlockDuplicationArray.addRowSpacing(b, rSpacing);
865
+ Duc.DucBlockDuplicationArray.addColSpacing(b, cSpacing);
841
866
  return Duc.DucBlockDuplicationArray.endDucBlockDuplicationArray(b);
842
867
  })()
843
868
  : undefined;
@@ -1378,6 +1403,8 @@ function writeDoc(b, e, usv) {
1378
1403
  Duc.ColumnLayout.addAutoHeight(b, col.autoHeight);
1379
1404
  return Duc.ColumnLayout.endColumnLayout(b);
1380
1405
  })();
1406
+ const fileId = e.fileId ? b.createString(e.fileId) : undefined;
1407
+ const gridConfig = writeDocumentGridConfig(b, e.gridConfig, usv);
1381
1408
  Duc.DucDocElement.startDucDocElement(b);
1382
1409
  Duc.DucDocElement.addBase(b, base);
1383
1410
  Duc.DucDocElement.addStyle(b, style);
@@ -1386,36 +1413,23 @@ function writeDoc(b, e, usv) {
1386
1413
  Duc.DucDocElement.addFlowDirection(b, e.flowDirection);
1387
1414
  Duc.DucDocElement.addColumns(b, columns);
1388
1415
  Duc.DucDocElement.addAutoResize(b, e.autoResize);
1416
+ if (fileId)
1417
+ Duc.DucDocElement.addFileId(b, fileId);
1418
+ Duc.DucDocElement.addGridConfig(b, gridConfig);
1389
1419
  return Duc.DucDocElement.endDucDocElement(b);
1390
1420
  }
1391
1421
  /**
1392
- * Parametric, PDF, Mermaid, Embeddable
1422
+ * PDF, Mermaid, Embeddable
1393
1423
  */
1394
- function writeParametricSource(b, s, usv) {
1395
- Duc.ParametricSource.startParametricSource(b);
1396
- Duc.ParametricSource.addType(b, s.type);
1397
- if (s.type === Duc.PARAMETRIC_SOURCE_TYPE.CODE) {
1398
- Duc.ParametricSource.addCode(b, b.createString(s.code));
1399
- }
1400
- else {
1401
- Duc.ParametricSource.addFileId(b, b.createString(s.fileId));
1402
- }
1403
- return Duc.ParametricSource.endParametricSource(b);
1404
- }
1405
- function writeParametric(b, e, usv) {
1406
- const base = writeElementBase(b, e, usv);
1407
- const src = writeParametricSource(b, e.source, usv);
1408
- Duc.DucParametricElement.startDucParametricElement(b);
1409
- Duc.DucParametricElement.addBase(b, base);
1410
- Duc.DucParametricElement.addSource(b, src);
1411
- return Duc.DucParametricElement.endDucParametricElement(b);
1412
- }
1413
1424
  function writePdf(b, e, usv) {
1414
1425
  const base = writeElementBase(b, e, usv);
1415
- const fileId = b.createString(e.fileId);
1426
+ const fileId = e.fileId ? b.createString(e.fileId) : undefined;
1427
+ const gridConfig = writeDocumentGridConfig(b, e.gridConfig, usv);
1416
1428
  Duc.DucPdfElement.startDucPdfElement(b);
1417
1429
  Duc.DucPdfElement.addBase(b, base);
1418
- Duc.DucPdfElement.addFileId(b, fileId);
1430
+ if (fileId)
1431
+ Duc.DucPdfElement.addFileId(b, fileId);
1432
+ Duc.DucPdfElement.addGridConfig(b, gridConfig);
1419
1433
  return Duc.DucPdfElement.endDucPdfElement(b);
1420
1434
  }
1421
1435
  function writeMermaid(b, e, usv) {
@@ -1432,6 +1446,21 @@ function writeMermaid(b, e, usv) {
1432
1446
  Duc.DucMermaidElement.addSvgPath(b, svg);
1433
1447
  return Duc.DucMermaidElement.endDucMermaidElement(b);
1434
1448
  }
1449
+ function writeModel(b, e, usv) {
1450
+ var _a;
1451
+ const base = writeElementBase(b, e, usv);
1452
+ const src = b.createString(e.source);
1453
+ const svg = e.svgPath ? b.createString(e.svgPath) : undefined;
1454
+ const fileIds = ((_a = e.fileIds) === null || _a === void 0 ? void 0 : _a.length) ? Duc.DucModelElement.createFileIdsVector(b, e.fileIds.map((id) => b.createString(id))) : undefined;
1455
+ Duc.DucModelElement.startDucModelElement(b);
1456
+ Duc.DucModelElement.addBase(b, base);
1457
+ Duc.DucModelElement.addSource(b, src);
1458
+ if (svg)
1459
+ Duc.DucModelElement.addSvgPath(b, svg);
1460
+ if (fileIds)
1461
+ Duc.DucModelElement.addFileIds(b, fileIds);
1462
+ return Duc.DucModelElement.endDucModelElement(b);
1463
+ }
1435
1464
  function writeEmbeddable(b, e, usv) {
1436
1465
  const base = writeElementBase(b, e, usv);
1437
1466
  Duc.DucEmbeddableElement.startDucEmbeddableElement(b);
@@ -1633,9 +1662,9 @@ function writeElementWrapper(b, e, usv) {
1633
1662
  type = Duc.Element.DucDocElement;
1634
1663
  elem = writeDoc(b, e, usv);
1635
1664
  break;
1636
- case "parametric":
1637
- type = Duc.Element.DucParametricElement;
1638
- elem = writeParametric(b, e, usv);
1665
+ case "model":
1666
+ type = Duc.Element.DucModelElement;
1667
+ elem = writeModel(b, e, usv);
1639
1668
  break;
1640
1669
  case "embeddable":
1641
1670
  type = Duc.Element.DucEmbeddableElement;
@@ -1,6 +1,6 @@
1
1
  export * from "./typeChecks";
2
2
  import { DucView, PrecisionValue, Scope } from "..";
3
- import { BEZIER_MIRRORING, BLENDING, BLOCK_ATTACHMENT, BOOLEAN_OPERATION, COLUMN_TYPE, DATUM_BRACKET_STYLE, DATUM_TARGET_TYPE, DIMENSION_FIT_RULE, DIMENSION_TEXT_PLACEMENT, DIMENSION_TYPE, ELEMENT_CONTENT_PREFERENCE, FEATURE_MODIFIER, GDT_SYMBOL, HATCH_STYLE, IMAGE_STATUS, LINE_HEAD, LINE_SPACING_TYPE, MARK_ELLIPSE_CENTER, MATERIAL_CONDITION, PARAMETRIC_SOURCE_TYPE, STACKED_TEXT_ALIGN, STROKE_CAP, STROKE_JOIN, STROKE_PLACEMENT, STROKE_PREFERENCE, STROKE_SIDE_PREFERENCE, TABLE_CELL_ALIGNMENT, TABLE_FLOW_DIRECTION, TEXT_ALIGN, TEXT_FIELD_SOURCE_PROPERTY, TEXT_FIELD_SOURCE_TYPE, TEXT_FLOW_DIRECTION, TOLERANCE_DISPLAY, TOLERANCE_TYPE, TOLERANCE_ZONE_TYPE, VERTICAL_ALIGN, VIEWPORT_SHADE_PLOT } from "../../flatbuffers/duc";
3
+ import { BEZIER_MIRRORING, BLENDING, BLOCK_ATTACHMENT, BOOLEAN_OPERATION, COLUMN_TYPE, DATUM_BRACKET_STYLE, DATUM_TARGET_TYPE, DIMENSION_FIT_RULE, DIMENSION_TEXT_PLACEMENT, DIMENSION_TYPE, ELEMENT_CONTENT_PREFERENCE, FEATURE_MODIFIER, GDT_SYMBOL, HATCH_STYLE, IMAGE_STATUS, LINE_HEAD, LINE_SPACING_TYPE, MARK_ELLIPSE_CENTER, MATERIAL_CONDITION, STACKED_TEXT_ALIGN, STROKE_CAP, STROKE_JOIN, STROKE_PLACEMENT, STROKE_PREFERENCE, STROKE_SIDE_PREFERENCE, TABLE_CELL_ALIGNMENT, TABLE_FLOW_DIRECTION, TEXT_ALIGN, TEXT_FIELD_SOURCE_PROPERTY, TEXT_FIELD_SOURCE_TYPE, TEXT_FLOW_DIRECTION, TOLERANCE_DISPLAY, TOLERANCE_TYPE, TOLERANCE_ZONE_TYPE, VERTICAL_ALIGN, VIEWPORT_SHADE_PLOT } from "../../flatbuffers/duc";
4
4
  import { Standard, StandardUnits } from "../../technical/standards";
5
5
  import { FONT_FAMILY, FREEDRAW_EASINGS } from "../../utils/constants";
6
6
  import { Axis, GeometricPoint, Percentage, Radian, ScaleFactor } from "../geometryTypes";
@@ -134,7 +134,7 @@ export type DucGenericElement = DucSelectionElement | DucRectangleElement;
134
134
  * no computed data. The list of all DucElements should be shareable
135
135
  * between peers and contain no state local to the peer.
136
136
  */
137
- export type DucElement = DucGenericElement | DucTextElement | DucLinearElement | DucFreeDrawElement | DucArrowElement | DucImageElement | DucFrameElement | DucEmbeddableElement | DucTableElement | DucDocElement | DucEllipseElement | DucPolygonElement | DucParametricElement | DucFeatureControlFrameElement | DucLeaderElement | DucDimensionElement | DucViewportElement | DucPlotElement | DucXRayElement | DucPdfElement | DucMermaidElement;
137
+ export type DucElement = DucGenericElement | DucTextElement | DucLinearElement | DucFreeDrawElement | DucArrowElement | DucImageElement | DucFrameElement | DucEmbeddableElement | DucTableElement | DucDocElement | DucEllipseElement | DucPolygonElement | DucModelElement | DucFeatureControlFrameElement | DucLeaderElement | DucDimensionElement | DucViewportElement | DucPlotElement | DucXRayElement | DucPdfElement | DucMermaidElement;
138
138
  export type DucElementTypes = DucElement["type"];
139
139
  export type NonDeleted<TElement extends DucElement> = TElement & {
140
140
  isDeleted: boolean;
@@ -316,9 +316,22 @@ export type DucEllipseElement = _DucElementBase & {
316
316
  export type DucEmbeddableElement = _DucElementBase & {
317
317
  type: "embeddable";
318
318
  };
319
+ /**
320
+ * Configuration for PDF grid layout
321
+ */
322
+ export type DocumentGridConfig = {
323
+ columns: number;
324
+ gapX: number;
325
+ gapY: number;
326
+ alignItems: 'start' | 'center' | 'end';
327
+ firstPageAlone: boolean;
328
+ scale: number;
329
+ };
319
330
  export type DucPdfElement = _DucElementBase & {
320
331
  type: "pdf";
321
332
  fileId: ExternalFileId | null;
333
+ /** Configuration for rendering the document in a grid layout */
334
+ gridConfig: DocumentGridConfig;
322
335
  };
323
336
  export type DucMermaidElement = _DucElementBase & {
324
337
  type: "mermaid";
@@ -458,9 +471,8 @@ export type DucImageElement = _DucElementBase & {
458
471
  export type InitializedDucImageElement = MarkNonNullable<DucImageElement, "fileId">;
459
472
  export type FontFamilyKeys = keyof typeof FONT_FAMILY;
460
473
  export type FontFamilyValues = typeof FONT_FAMILY[FontFamilyKeys];
461
- export type FontString = string & {
462
- _brand: "fontString";
463
- };
474
+ /** Font family identifier — any valid CSS font-family string (Google Font name, system font, etc.) */
475
+ export type FontString = string;
464
476
  export type TextAlign = ValueOf<typeof TEXT_ALIGN>;
465
477
  export type VerticalAlign = ValueOf<typeof VERTICAL_ALIGN>;
466
478
  export type LineSpacingType = ValueOf<typeof LINE_SPACING_TYPE>;
@@ -474,7 +486,7 @@ export type DucTextStyle = {
474
486
  /**
475
487
  * The primary font family to use for the text
476
488
  */
477
- fontFamily: FontFamilyValues;
489
+ fontFamily: FontString;
478
490
  /**
479
491
  * Fallback font family for broader compatibility across all systems and languages
480
492
  * Useful for emojis, non-latin characters, etc.
@@ -1357,10 +1369,8 @@ export type TextColumn = {
1357
1369
  export type DucDocElement = _DucElementBase & DucDocStyle & {
1358
1370
  type: "doc";
1359
1371
  /**
1360
- * The content of the document, stored as a Markdown string.
1361
- * This approach allows a rich text editor (like Tiptap) to manage the complex
1362
- * inline formatting (bold, italic, colors, hyperlinks, etc.) while keeping the
1363
- * core data structure simple and clean.
1372
+ * The content of the document, stored as a code string.
1373
+ * This approach allows to use a rich text editor that can compile to PDF using Typst code
1364
1374
  *
1365
1375
  * It can also contain wildcards like `{@fieldname}` for dynamic data insertion.
1366
1376
  * Example: "This is **bold text** and this is a {color:red}red word{/color}."
@@ -1369,6 +1379,9 @@ export type DucDocElement = _DucElementBase & DucDocStyle & {
1369
1379
  * Example: "This document was last saved on {{SaveDate}} by {{Author}}."
1370
1380
  */
1371
1381
  text: string;
1382
+ fileId: ExternalFileId | null;
1383
+ /** Configuration for rendering the document in a grid layout */
1384
+ gridConfig: DocumentGridConfig;
1372
1385
  /**
1373
1386
  * An array of metadata objects that define the behavior of the placeholders
1374
1387
  * found in the `text` property. If this is empty, the text is treated
@@ -1401,27 +1414,15 @@ export type DucDocElement = _DucElementBase & DucDocStyle & {
1401
1414
  autoResize: boolean;
1402
1415
  };
1403
1416
  /**
1404
- * Defines the source of the 3D geometry for a Parametric Element.
1405
- * The geometry is either generated from live code or loaded from an external file.
1406
- */
1407
- export type ParametricElementSource = {
1408
- /** The geometry is defined by executable Replicad code. */
1409
- type: PARAMETRIC_SOURCE_TYPE.CODE;
1410
- /** The JavaScript code that generates the Replicad model. */
1411
- code: string;
1412
- } | {
1413
- /** The geometry is loaded from a static 3D file. */
1414
- type: PARAMETRIC_SOURCE_TYPE.FILE;
1415
- /** A reference to the imported file in the DucExternalFiles collection. */
1416
- fileId: ExternalFileId;
1417
- };
1418
- /**
1419
- * An element that embeds a 3D model on the 2D canvas, defined either by
1420
- * parametric Replicad code or by an imported 3D file (e.g., STEP, STL).
1417
+ * An element that embeds a 3D model on the 2D canvas, defined by build123d python code.
1421
1418
  * It includes its own 3D view and display controls.
1422
1419
  */
1423
- export type DucParametricElement = _DucElementBase & {
1424
- type: "parametric";
1425
- /** Defines the source of the 3D geometry (either from code or a file). */
1426
- source: ParametricElementSource;
1420
+ export type DucModelElement = _DucElementBase & {
1421
+ type: "model";
1422
+ /** Defines the source of the model using build123d python code */
1423
+ source: string;
1424
+ /** The last known SVG path representation of the 3D model for quick rendering on the canvas */
1425
+ svgPath: string | null;
1426
+ /** Possibly connected external files, such as STEP, STL or other reference models */
1427
+ fileIds: ExternalFileId[];
1427
1428
  };
@@ -1,9 +1,12 @@
1
1
  import type { ElementOrToolType } from "..";
2
2
  import type { MarkNonNullable } from "../utility-types";
3
3
  import { Bounds, LineSegment, TuplePoint } from "../geometryTypes";
4
- import type { DucArrowElement, DucBindableElement, DucElbowArrowElement, DucElement, DucElementType, DucEmbeddableElement, DucFlowchartNodeElement, DucFrameElement, DucFrameLikeElement, DucFreeDrawElement, DucImageElement, DucLinearElement, DucPlotElement, DucTableElement, DucPointBinding, DucTextContainer, DucTextElement, DucTextElementWithContainer, FixedPointBinding, InitializedDucImageElement, DucNonSelectionElement, DucEllipseElement, DucPolygonElement, NonDeleted, DucIframeLikeElement } from "./";
4
+ import type { DucArrowElement, DucBindableElement, DucDocElement, DucElbowArrowElement, DucElement, DucElementType, DucEmbeddableElement, DucFlowchartNodeElement, DucFrameElement, DucFrameLikeElement, DucFreeDrawElement, DucImageElement, DucLinearElement, DucPdfElement, DucPlotElement, DucTableElement, DucPointBinding, DucTextContainer, DucTextElement, DucTextElementWithContainer, FixedPointBinding, InitializedDucImageElement, DucNonSelectionElement, DucEllipseElement, DucPolygonElement, NonDeleted, DucIframeLikeElement } from "./";
5
5
  export declare const isInitializedImageElement: (element: DucElement | null) => element is InitializedDucImageElement;
6
6
  export declare const isImageElement: (element: DucElement | null) => element is DucImageElement;
7
+ export declare const isPdfElement: (element: DucElement | null) => element is DucPdfElement;
8
+ export type DucPdfLikeElement = DucPdfElement | DucDocElement;
9
+ export declare const isPdfLikeElement: (element: DucElement | null) => element is DucPdfLikeElement;
7
10
  export declare const isEmbeddableElement: (element: DucElement | null | undefined) => element is DucEmbeddableElement;
8
11
  export declare const isTableElement: (element: DucElement | null) => element is DucTableElement;
9
12
  export declare const isIframeLikeElement: (element: DucElement | null) => element is DucIframeLikeElement;
@@ -5,6 +5,12 @@ export const isInitializedImageElement = (element) => {
5
5
  export const isImageElement = (element) => {
6
6
  return !!element && element.type === "image";
7
7
  };
8
+ export const isPdfElement = (element) => {
9
+ return !!element && element.type === "pdf";
10
+ };
11
+ export const isPdfLikeElement = (element) => {
12
+ return !!element && (element.type === "pdf" || element.type === "doc");
13
+ };
8
14
  export const isEmbeddableElement = (element) => {
9
15
  return !!element && element.type === "embeddable";
10
16
  };
@@ -133,7 +139,7 @@ export const isDucElement = (element) => {
133
139
  case "leader":
134
140
  case "doc":
135
141
  case "selection":
136
- case "parametric":
142
+ case "model":
137
143
  case "featurecontrolframe":
138
144
  case "viewport":
139
145
  case "plot":
@@ -1,14 +1,14 @@
1
1
  export * from "./elements";
2
2
  export * from "./geometryTypes";
3
- export * from "./utility-types";
4
3
  export * from "./typeChecks";
4
+ export * from "./utility-types";
5
5
  import { OBJECT_SNAP_MODE, PRUNING_LEVEL } from "../flatbuffers/duc";
6
6
  import { SupportedMeasures } from "../technical/scopes";
7
7
  import { Standard } from "../technical/standards";
8
+ import type { GRID_DISPLAY_TYPE, GRID_TYPE, SNAP_MARKER_SHAPE, SNAP_MODE, SNAP_OVERRIDE_BEHAVIOR } from "../utils/constants";
8
9
  import { DucBindableElement, DucBlock, DucBlockCollection, DucBlockInstance, DucElement, DucElementType, DucGroup, DucIframeLikeElement, DucLayer, DucLinearElement, DucPoint, DucRegion, DucTextElement, ElementBackground, ElementStroke, ExternalFileId, FontFamilyValues, LineHead, NonDeleted, TextAlign } from "./elements";
9
10
  import { GeometricPoint, Percentage, Radian, ScaleFactor } from "./geometryTypes";
10
11
  import { MakeBrand, MarkOptional, MaybePromise, ValueOf } from "./utility-types";
11
- import type { GRID_DISPLAY_TYPE, GRID_TYPE, SNAP_MARKER_SHAPE, SNAP_MODE, SNAP_OVERRIDE_BEHAVIOR } from "../utils/constants";
12
12
  /**
13
13
  * Root data structure for the stored data state
14
14
  */
@@ -112,7 +112,7 @@ export type SuggestedPointBinding = [
112
112
  "start" | "end" | "both",
113
113
  NonDeleted<DucBindableElement>
114
114
  ];
115
- export type ToolType = "selection" | "rectangle" | "polygon" | "ellipse" | "line" | "freedraw" | "text" | "image" | "eraser" | "hand" | "frame" | "plot" | "embeddable" | "ruler" | "lasso" | "laser" | "table";
115
+ export type ToolType = "selection" | "rectangle" | "polygon" | "ellipse" | "line" | "freedraw" | "text" | "image" | "eraser" | "hand" | "frame" | "plot" | "embeddable" | "ruler" | "lasso" | "laser" | "table" | "doc" | "pdf";
116
116
  export type ElementOrToolType = DucElementType | ToolType | "custom";
117
117
  /**
118
118
  * Defines the global, persistent settings for the drawing. These are fundamental
@@ -1,4 +1,4 @@
1
1
  export * from "./elements";
2
2
  export * from "./geometryTypes";
3
- export * from "./utility-types";
4
3
  export * from "./typeChecks";
4
+ export * from "./utility-types";
@@ -89,24 +89,28 @@ export declare const HIDE_FRAME_NAME_ZOOM_THRESHOLD = 0.18;
89
89
  export declare const DEFAULT_PROPORTIONAL_RADIUS = 0.25;
90
90
  export declare const DEFAULT_ADAPTIVE_RADIUS = 32;
91
91
  /**
92
- * // TODO: shouldn't be really `const`, likely neither have integers as values, due to value for the custom fonts, which should likely be some hash.
92
+ * Font family identifiers. Values are the actual CSS font-family names
93
+ * so they can be passed directly to Google Fonts / Canvas2D.
93
94
  *
94
- * Let's think this through and consider:
95
- * - https://developer.mozilla.org/en-US/docs/Web/CSS/generic-family
96
- * - https://drafts.csswg.org/css-fonts-4/#font-family-prop
97
- * - https://learn.microsoft.com/en-us/typography/opentype/spec/ibmfc
95
+ * For backward compatibility with old files that stored numeric IDs,
96
+ * use `LEGACY_FONT_ID_TO_NAME` to resolve them.
98
97
  */
99
98
  export declare const FONT_FAMILY: {
100
- Virgil: number;
101
- Helvetica: number;
102
- Cascadia: number;
103
- Excalifont: number;
104
- Nunito: number;
105
- "Lilita One": number;
106
- "Comic Shanns": number;
107
- "Liberation Sans": number;
108
- "Roboto Mono": number;
99
+ readonly Virgil: "Virgil";
100
+ readonly Helvetica: "Helvetica";
101
+ readonly Cascadia: "Cascadia";
102
+ readonly Excalifont: "Excalifont";
103
+ readonly Nunito: "Nunito";
104
+ readonly "Lilita One": "Lilita One";
105
+ readonly "Comic Shanns": "Comic Shanns";
106
+ readonly "Liberation Sans": "Liberation Sans";
107
+ readonly "Roboto Mono": "Roboto Mono";
109
108
  };
109
+ /**
110
+ * Reverse mapping from legacy numeric font IDs to font family names.
111
+ * Used when loading old .duc files that encoded fontFamily as a number.
112
+ */
113
+ export declare const LEGACY_FONT_ID_TO_NAME: Record<number, string>;
110
114
  export declare const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
111
115
  export declare const DEFAULT_VERSION = "{version}";
112
116
  export declare const MIN_FONT_SIZE = 1;
@@ -87,24 +87,37 @@ export const DEFAULT_PROPORTIONAL_RADIUS = 0.25;
87
87
  // Fixed radius for the ADAPTIVE_RADIUS algorithm. In pixels.
88
88
  export const DEFAULT_ADAPTIVE_RADIUS = 32;
89
89
  /**
90
- * // TODO: shouldn't be really `const`, likely neither have integers as values, due to value for the custom fonts, which should likely be some hash.
90
+ * Font family identifiers. Values are the actual CSS font-family names
91
+ * so they can be passed directly to Google Fonts / Canvas2D.
91
92
  *
92
- * Let's think this through and consider:
93
- * - https://developer.mozilla.org/en-US/docs/Web/CSS/generic-family
94
- * - https://drafts.csswg.org/css-fonts-4/#font-family-prop
95
- * - https://learn.microsoft.com/en-us/typography/opentype/spec/ibmfc
93
+ * For backward compatibility with old files that stored numeric IDs,
94
+ * use `LEGACY_FONT_ID_TO_NAME` to resolve them.
96
95
  */
97
96
  export const FONT_FAMILY = {
98
- Virgil: 1,
99
- Helvetica: 2,
100
- Cascadia: 3,
101
- // leave 4 unused as it was historically used for Assistant (which we don't use anymore) or custom font (Obsidian)
102
- Excalifont: 5,
103
- Nunito: 6,
104
- "Lilita One": 7,
105
- "Comic Shanns": 8,
106
- "Liberation Sans": 9,
107
- "Roboto Mono": 10,
97
+ Virgil: "Virgil",
98
+ Helvetica: "Helvetica",
99
+ Cascadia: "Cascadia",
100
+ Excalifont: "Excalifont",
101
+ Nunito: "Nunito",
102
+ "Lilita One": "Lilita One",
103
+ "Comic Shanns": "Comic Shanns",
104
+ "Liberation Sans": "Liberation Sans",
105
+ "Roboto Mono": "Roboto Mono",
106
+ };
107
+ /**
108
+ * Reverse mapping from legacy numeric font IDs to font family names.
109
+ * Used when loading old .duc files that encoded fontFamily as a number.
110
+ */
111
+ export const LEGACY_FONT_ID_TO_NAME = {
112
+ 1: "Virgil",
113
+ 2: "Helvetica",
114
+ 3: "Cascadia",
115
+ 5: "Excalifont",
116
+ 6: "Nunito",
117
+ 7: "Lilita One",
118
+ 8: "Comic Shanns",
119
+ 9: "Liberation Sans",
120
+ 10: "Roboto Mono",
108
121
  };
109
122
  export const WINDOWS_EMOJI_FALLBACK_FONT = "Segoe UI Emoji";
110
123
  export const DEFAULT_VERSION = "{version}";
@@ -1,2 +1,8 @@
1
1
  import { DucFreeDrawElement } from "../../types/elements";
2
2
  export declare function getFreeDrawSvgPath(element: DucFreeDrawElement): string;
3
+ /**
4
+ * Returns the raw outline polygon points from perfect-freehand.
5
+ * Each point is [x, y]. The result forms a closed polygon that
6
+ * represents the visual shape of the freedraw stroke.
7
+ */
8
+ export declare function getFreeDrawStrokePoints(element: DucFreeDrawElement): number[][];
@@ -22,16 +22,8 @@ function getSvgPathFromStroke(points) {
22
22
  .join(" ")
23
23
  .replace(TO_FIXED_PRECISION, "$1");
24
24
  }
25
- export function getFreeDrawSvgPath(element) {
26
- // If input points are empty (should they ever be?) return a dot
27
- if (element.points.length === 0) {
28
- return "";
29
- }
30
- const inputPoints = element.simulatePressure
31
- ? element.points.map(({ x, y }, i) => [x.scoped, y.scoped, element.pressures[i]])
32
- : element.points.map(({ x, y }) => [x.scoped, y.scoped]);
33
- // Consider changing the options for simulated pressure vs real pressure
34
- const options = {
25
+ function buildStrokeOptions(element) {
26
+ return {
35
27
  size: element.size.scoped,
36
28
  simulatePressure: element.simulatePressure,
37
29
  thinning: element.thinning,
@@ -40,7 +32,32 @@ export function getFreeDrawSvgPath(element) {
40
32
  easing: element.easing,
41
33
  start: element.start || undefined,
42
34
  end: element.end || undefined,
43
- last: !!element.lastCommittedPoint, // LastCommittedPoint is added on pointerup
35
+ last: !!element.lastCommittedPoint,
44
36
  };
37
+ }
38
+ function buildInputPoints(element) {
39
+ return element.simulatePressure
40
+ ? element.points.map(({ x, y }, i) => [x.scoped, y.scoped, element.pressures[i]])
41
+ : element.points.map(({ x, y }) => [x.scoped, y.scoped]);
42
+ }
43
+ export function getFreeDrawSvgPath(element) {
44
+ if (element.points.length === 0) {
45
+ return "";
46
+ }
47
+ const inputPoints = buildInputPoints(element);
48
+ const options = buildStrokeOptions(element);
45
49
  return getSvgPathFromStroke(getStroke(inputPoints, options));
46
50
  }
51
+ /**
52
+ * Returns the raw outline polygon points from perfect-freehand.
53
+ * Each point is [x, y]. The result forms a closed polygon that
54
+ * represents the visual shape of the freedraw stroke.
55
+ */
56
+ export function getFreeDrawStrokePoints(element) {
57
+ if (element.points.length === 0) {
58
+ return [];
59
+ }
60
+ const inputPoints = buildInputPoints(element);
61
+ const options = buildStrokeOptions(element);
62
+ return getStroke(inputPoints, options);
63
+ }