@tldraw/editor 4.6.0-next.793daa9fe264 → 4.6.0-next.a31a8a6b83f2

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 (110) hide show
  1. package/dist-cjs/index.d.ts +376 -98
  2. package/dist-cjs/index.js +12 -3
  3. package/dist-cjs/index.js.map +3 -3
  4. package/dist-cjs/lib/TldrawEditor.js +55 -12
  5. package/dist-cjs/lib/TldrawEditor.js.map +3 -3
  6. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +3 -3
  7. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
  8. package/dist-cjs/lib/config/createTLStore.js +7 -0
  9. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  10. package/dist-cjs/lib/config/defaultAssets.js +36 -0
  11. package/dist-cjs/lib/config/defaultAssets.js.map +7 -0
  12. package/dist-cjs/lib/editor/Editor.js +200 -5
  13. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  14. package/dist-cjs/lib/editor/assets/AssetUtil.js +66 -0
  15. package/dist-cjs/lib/editor/assets/AssetUtil.js.map +7 -0
  16. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  17. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +106 -0
  18. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +7 -0
  19. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +586 -0
  20. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +7 -0
  21. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +6 -4
  22. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +9 -0
  24. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/editor/types/SvgExportContext.js.map +2 -2
  26. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  27. package/dist-cjs/lib/exports/getSvgJsx.js +12 -7
  28. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  29. package/dist-cjs/lib/globals/environment.js +18 -1
  30. package/dist-cjs/lib/globals/environment.js.map +2 -2
  31. package/dist-cjs/lib/hooks/{useIsDarkMode.js → useColorMode.js} +14 -10
  32. package/dist-cjs/lib/hooks/useColorMode.js.map +7 -0
  33. package/dist-cjs/lib/hooks/useCursor.js +3 -7
  34. package/dist-cjs/lib/hooks/useCursor.js.map +2 -2
  35. package/dist-cjs/lib/hooks/useDarkMode.js +4 -4
  36. package/dist-cjs/lib/hooks/useDarkMode.js.map +2 -2
  37. package/dist-cjs/lib/utils/reparenting.js +2 -1
  38. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  39. package/dist-cjs/lib/utils/richText.js.map +2 -2
  40. package/dist-cjs/version.js +3 -3
  41. package/dist-cjs/version.js.map +1 -1
  42. package/dist-esm/index.d.mts +376 -98
  43. package/dist-esm/index.mjs +13 -6
  44. package/dist-esm/index.mjs.map +2 -2
  45. package/dist-esm/lib/TldrawEditor.mjs +58 -12
  46. package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
  47. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +3 -3
  48. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
  49. package/dist-esm/lib/config/createTLStore.mjs +10 -1
  50. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  51. package/dist-esm/lib/config/defaultAssets.mjs +16 -0
  52. package/dist-esm/lib/config/defaultAssets.mjs.map +7 -0
  53. package/dist-esm/lib/editor/Editor.mjs +200 -5
  54. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  55. package/dist-esm/lib/editor/assets/AssetUtil.mjs +46 -0
  56. package/dist-esm/lib/editor/assets/AssetUtil.mjs.map +7 -0
  57. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  58. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +88 -0
  59. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +7 -0
  60. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +568 -0
  61. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +7 -0
  62. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +6 -4
  63. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  64. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +9 -0
  65. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  66. package/dist-esm/lib/editor/types/SvgExportContext.mjs.map +2 -2
  67. package/dist-esm/lib/exports/getSvgJsx.mjs +12 -10
  68. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  69. package/dist-esm/lib/globals/environment.mjs +18 -1
  70. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  71. package/dist-esm/lib/hooks/useColorMode.mjs +19 -0
  72. package/dist-esm/lib/hooks/useColorMode.mjs.map +7 -0
  73. package/dist-esm/lib/hooks/useCursor.mjs +3 -7
  74. package/dist-esm/lib/hooks/useCursor.mjs.map +2 -2
  75. package/dist-esm/lib/hooks/useDarkMode.mjs +4 -4
  76. package/dist-esm/lib/hooks/useDarkMode.mjs.map +2 -2
  77. package/dist-esm/lib/utils/reparenting.mjs +2 -1
  78. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  79. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  80. package/dist-esm/version.mjs +3 -3
  81. package/dist-esm/version.mjs.map +1 -1
  82. package/editor.css +0 -33
  83. package/package.json +7 -7
  84. package/src/index.ts +8 -6
  85. package/src/lib/TldrawEditor.tsx +90 -13
  86. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +3 -3
  87. package/src/lib/config/createTLStore.ts +22 -1
  88. package/src/lib/config/defaultAssets.ts +19 -0
  89. package/src/lib/editor/Editor.ts +285 -27
  90. package/src/lib/editor/assets/AssetUtil.ts +85 -0
  91. package/src/lib/editor/managers/FontManager/FontManager.test.ts +9 -2
  92. package/src/lib/editor/managers/FontManager/FontManager.ts +1 -67
  93. package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +116 -0
  94. package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +605 -0
  95. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +23 -29
  96. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +5 -3
  97. package/src/lib/editor/shapes/ShapeUtil.ts +26 -1
  98. package/src/lib/editor/types/SvgExportContext.tsx +5 -0
  99. package/src/lib/editor/types/external-content.ts +1 -0
  100. package/src/lib/exports/getSvgJsx.tsx +21 -15
  101. package/src/lib/globals/environment.ts +18 -0
  102. package/src/lib/hooks/{useIsDarkMode.ts → useColorMode.ts} +9 -5
  103. package/src/lib/hooks/useCursor.ts +3 -7
  104. package/src/lib/hooks/useDarkMode.ts +4 -4
  105. package/src/lib/utils/reparenting.ts +6 -2
  106. package/src/lib/utils/richText.ts +1 -1
  107. package/src/version.ts +3 -3
  108. package/dist-cjs/lib/hooks/useIsDarkMode.js.map +0 -7
  109. package/dist-esm/lib/hooks/useIsDarkMode.mjs +0 -15
  110. package/dist-esm/lib/hooks/useIsDarkMode.mjs.map +0 -7
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var AssetUtil_exports = {};
20
+ __export(AssetUtil_exports, {
21
+ AssetUtil: () => AssetUtil
22
+ });
23
+ module.exports = __toCommonJS(AssetUtil_exports);
24
+ class AssetUtil {
25
+ constructor(editor) {
26
+ this.editor = editor;
27
+ }
28
+ /** Configure this asset util's {@link AssetUtil.options | `options`}. */
29
+ static configure(options) {
30
+ return class extends this {
31
+ // @ts-expect-error
32
+ options = { ...this.options, ...options };
33
+ };
34
+ }
35
+ /**
36
+ * Options for this asset util. Override this to provide customization options for your asset.
37
+ * Use {@link AssetUtil.configure} to customize existing asset utils.
38
+ */
39
+ options = {};
40
+ static props;
41
+ static migrations;
42
+ /**
43
+ * The type of the asset util, which should match the asset's type.
44
+ */
45
+ static type;
46
+ /**
47
+ * Get the MIME types that this asset type supports.
48
+ * Return an empty array if this asset type doesn't support files (e.g. bookmarks).
49
+ */
50
+ getSupportedMimeTypes() {
51
+ return [];
52
+ }
53
+ /**
54
+ * Check whether this asset type accepts a given MIME type.
55
+ */
56
+ acceptsMimeType(mimeType) {
57
+ return this.getSupportedMimeTypes().includes(mimeType);
58
+ }
59
+ /**
60
+ * Create an asset from a file. Return null if this asset type can't handle the file.
61
+ */
62
+ async getAssetFromFile(_file, _assetId) {
63
+ return null;
64
+ }
65
+ }
66
+ //# sourceMappingURL=AssetUtil.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/lib/editor/assets/AssetUtil.ts"],
4
+ "sourcesContent": ["import { LegacyMigrations, MigrationSequence } from '@tldraw/store'\nimport {\n\tRecordProps,\n\tTLAsset,\n\tTLAssetId,\n\tTLPropsMigrations,\n\tTLUnknownAsset,\n} from '@tldraw/tlschema'\nimport type { Editor } from '../Editor'\n\n/** @public */\nexport interface TLAssetUtilConstructor<\n\tT extends TLAsset = TLAsset,\n\tU extends AssetUtil<T> = AssetUtil<T>,\n> {\n\tnew (editor: Editor): U\n\ttype: T['type']\n\tprops?: RecordProps<T>\n\tmigrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence\n}\n\n/**\n * Abstract base class for defining asset-type-specific behavior.\n *\n * Each asset type (image, video, bookmark, etc.) has a corresponding AssetUtil that handles\n * type-specific operations like determining supported MIME types and creating assets from files.\n *\n * @public\n */\nexport abstract class AssetUtil<Asset extends TLAsset = TLAsset> {\n\t/** Configure this asset util's {@link AssetUtil.options | `options`}. */\n\tstatic configure<T extends TLAssetUtilConstructor<any, any>>(\n\t\tthis: T,\n\t\toptions: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never\n\t): T {\n\t\t// @ts-expect-error -- typescript has no idea what's going on here but it's fine\n\t\treturn class extends this {\n\t\t\t// @ts-expect-error\n\t\t\toptions = { ...this.options, ...options }\n\t\t}\n\t}\n\n\tconstructor(public editor: Editor) {}\n\n\t/**\n\t * Options for this asset util. Override this to provide customization options for your asset.\n\t * Use {@link AssetUtil.configure} to customize existing asset utils.\n\t */\n\toptions = {}\n\n\tstatic props?: RecordProps<TLUnknownAsset>\n\tstatic migrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence\n\n\t/**\n\t * The type of the asset util, which should match the asset's type.\n\t */\n\tstatic type: string\n\n\t/**\n\t * Get the default props for an asset of this type.\n\t */\n\tabstract getDefaultProps(): Asset['props']\n\n\t/**\n\t * Get the MIME types that this asset type supports.\n\t * Return an empty array if this asset type doesn't support files (e.g. bookmarks).\n\t */\n\tgetSupportedMimeTypes(): readonly string[] {\n\t\treturn []\n\t}\n\n\t/**\n\t * Check whether this asset type accepts a given MIME type.\n\t */\n\tacceptsMimeType(mimeType: string): boolean {\n\t\treturn this.getSupportedMimeTypes().includes(mimeType)\n\t}\n\n\t/**\n\t * Create an asset from a file. Return null if this asset type can't handle the file.\n\t */\n\tasync getAssetFromFile(_file: File, _assetId: TLAssetId): Promise<Asset | null> {\n\t\treturn null\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6BO,MAAe,UAA2C;AAAA,EAahE,YAAmB,QAAgB;AAAhB;AAAA,EAAiB;AAAA;AAAA,EAXpC,OAAO,UAEN,SACI;AAEJ,WAAO,cAAc,KAAK;AAAA;AAAA,MAEzB,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AAAA,IACzC;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,CAAC;AAAA,EAEX,OAAO;AAAA,EACP,OAAO;AAAA;AAAA;AAAA;AAAA,EAKP,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAWP,wBAA2C;AAC1C,WAAO,CAAC;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,UAA2B;AAC1C,WAAO,KAAK,sBAAsB,EAAE,SAAS,QAAQ;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,OAAa,UAA4C;AAC/E,WAAO;AAAA,EACR;AACD;",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/FontManager/FontManager.ts"],
4
- "sourcesContent": ["import { computed, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport { AtomMap } from '@tldraw/store'\nimport { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport {\n\tareArraysShallowEqual,\n\tcompact,\n\tFileHelpers,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n} from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * Represents the `src` property of a {@link TLFontFace}.\n * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`} for details of the properties here.\n * @public\n */\nexport interface TLFontFaceSource {\n\t/**\n\t * A URL from which to load the font. If the value here is a key in\n\t * {@link tldraw#TLEditorAssetUrls.fonts}, the value from there will be used instead.\n\t */\n\turl: string\n\tformat?: string\n\ttech?: string\n}\n\n/**\n * A font face that can be used in the editor. The properties of this are largely the same as the\n * ones in the\n * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face | css `@font-face` rule}.\n * @public\n */\nexport interface TLFontFace {\n\t/**\n\t * How this font can be referred to in CSS.\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family | `font-family`}.\n\t */\n\treadonly family: string\n\t/**\n\t * The source of the font. This\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`}.\n\t */\n\treadonly src: TLFontFaceSource\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/ascent-override | `ascent-override`}.\n\t */\n\treadonly ascentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/descent-override | `descent-override`}.\n\t */\n\treadonly descentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch | `font-stretch`}.\n\t */\n\treadonly stretch?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-style | `font-style`}.\n\t */\n\treadonly style?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-weight | `font-weight`}.\n\t */\n\treadonly weight?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings | `font-feature-settings`}.\n\t */\n\treadonly featureSettings?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/line-gap-override | `line-gap-override`}.\n\t */\n\treadonly lineGapOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range | `unicode-range`}.\n\t */\n\treadonly unicodeRange?: string\n}\n\ninterface FontState {\n\treadonly state: 'loading' | 'ready' | 'error'\n\treadonly instance: FontFace\n\treadonly loadingPromise: Promise<void>\n}\n\n/** @public */\nexport class FontManager {\n\tconstructor(\n\t\tprivate readonly editor: Editor,\n\t\tprivate readonly assetUrls?: { [key: string]: string | undefined }\n\t) {\n\t\tthis.shapeFontFacesCache = editor.store.createComputedCache(\n\t\t\t'shape font faces',\n\t\t\t(shape: TLShape) => {\n\t\t\t\tconst shapeUtil = this.editor.getShapeUtil(shape)\n\t\t\t\treturn shapeUtil.getFontFaces(shape)\n\t\t\t},\n\t\t\t{\n\t\t\t\tareResultsEqual: areArraysShallowEqual,\n\t\t\t\tareRecordsEqual: (a, b) => a.props === b.props && a.meta === b.meta,\n\t\t\t}\n\t\t)\n\n\t\tthis.shapeFontLoadStateCache = editor.store.createCache<(FontState | null)[], TLShape>(\n\t\t\t(id: TLShapeId) => {\n\t\t\t\tconst fontFacesComputed = computed('font faces', () => this.getShapeFontFaces(id))\n\t\t\t\treturn computed(\n\t\t\t\t\t'font load state',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst states = fontFacesComputed.get().map((face) => this.getFontState(face))\n\t\t\t\t\t\treturn states\n\t\t\t\t\t},\n\t\t\t\t\t{ isEqual: areArraysShallowEqual }\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate readonly shapeFontFacesCache\n\tprivate readonly shapeFontLoadStateCache\n\n\tgetShapeFontFaces(shape: TLShape | TLShapeId): TLFontFace[] {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\treturn this.shapeFontFacesCache.get(shapeId) ?? EMPTY_ARRAY\n\t}\n\n\ttrackFontsForShape(shape: TLShape | TLShapeId) {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\tthis.shapeFontLoadStateCache.get(shapeId)\n\t}\n\n\tasync loadRequiredFontsForCurrentPage(limit = Infinity) {\n\t\tconst neededFonts = new Set<TLFontFace>()\n\t\tfor (const shapeId of this.editor.getCurrentPageShapeIds()) {\n\t\t\tfor (const font of this.getShapeFontFaces(this.editor.getShape(shapeId)!)) {\n\t\t\t\tneededFonts.add(font)\n\t\t\t}\n\t\t}\n\n\t\tif (neededFonts.size > limit) {\n\t\t\treturn\n\t\t}\n\n\t\tconst promises = Array.from(neededFonts, (font) => this.ensureFontIsLoaded(font))\n\t\tawait Promise.all(promises)\n\t}\n\n\tprivate readonly fontStates = new AtomMap<TLFontFace, FontState>('font states')\n\tprivate getFontState(font: TLFontFace): FontState | null {\n\t\treturn this.fontStates.get(font) ?? null\n\t}\n\n\tensureFontIsLoaded(font: TLFontFace): Promise<void> {\n\t\tconst existingState = this.getFontState(font)\n\t\tif (existingState) return existingState.loadingPromise\n\n\t\tconst instance = this.findOrCreateFontFace(font)\n\t\tconst state: FontState = {\n\t\t\tstate: 'loading',\n\t\t\tinstance,\n\t\t\tloadingPromise: instance\n\t\t\t\t.load()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.editor.getContainerDocument().fonts.add(instance)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'ready' }))\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(err)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'error' }))\n\t\t\t\t}),\n\t\t}\n\n\t\tthis.fontStates.set(font, state)\n\t\treturn state.loadingPromise\n\t}\n\n\tprivate fontsToLoad = new Set<TLFontFace>()\n\trequestFonts(fonts: TLFontFace[]) {\n\t\tif (!this.fontsToLoad.size) {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (this.editor.isDisposed) return\n\t\t\t\tconst toLoad = this.fontsToLoad\n\t\t\t\tthis.fontsToLoad = new Set()\n\t\t\t\ttransact(() => {\n\t\t\t\t\tfor (const font of toLoad) {\n\t\t\t\t\t\tthis.ensureFontIsLoaded(font)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t\tfor (const font of fonts) {\n\t\t\tthis.fontsToLoad.add(font)\n\t\t}\n\t}\n\n\tprivate findOrCreateFontFace(font: TLFontFace) {\n\t\tconst fonts = this.editor.getContainerDocument().fonts\n\t\tfor (const existing of fonts) {\n\t\t\tif (\n\t\t\t\texisting.family === font.family &&\n\t\t\t\tobjectMapEntries(defaultFontFaceDescriptors).every(\n\t\t\t\t\t([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn existing\n\t\t\t}\n\t\t}\n\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst instance = new FontFace(font.family, `url(${JSON.stringify(url)})`, {\n\t\t\t...mapObjectMapValues(defaultFontFaceDescriptors, (key) => font[key]),\n\t\t\tdisplay: 'swap',\n\t\t})\n\n\t\tfonts.add(instance)\n\n\t\treturn instance\n\t}\n\n\tasync toEmbeddedCssDeclaration(font: TLFontFace) {\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst dataUrl = await FileHelpers.urlToDataUrl(url)\n\n\t\tconst src = compact([\n\t\t\t`url(\"${dataUrl}\")`,\n\t\t\tfont.src.format ? `format(${font.src.format})` : null,\n\t\t\tfont.src.tech ? `tech(${font.src.tech})` : null,\n\t\t]).join(' ')\n\t\treturn compact([\n\t\t\t`@font-face {`,\n\t\t\t` font-family: \"${font.family}\";`,\n\t\t\tfont.ascentOverride ? ` ascent-override: ${font.ascentOverride};` : null,\n\t\t\tfont.descentOverride ? ` descent-override: ${font.descentOverride};` : null,\n\t\t\tfont.stretch ? ` font-stretch: ${font.stretch};` : null,\n\t\t\tfont.style ? ` font-style: ${font.style};` : null,\n\t\t\tfont.weight ? ` font-weight: ${font.weight};` : null,\n\t\t\tfont.featureSettings ? ` font-feature-settings: ${font.featureSettings};` : null,\n\t\t\tfont.lineGapOverride ? ` line-gap-override: ${font.lineGapOverride};` : null,\n\t\t\tfont.unicodeRange ? ` unicode-range: ${font.unicodeRange};` : null,\n\t\t\t` src: ${src};`,\n\t\t\t`}`,\n\t\t]).join('\\n')\n\t}\n}\n\n// From https://drafts.csswg.org/css-font-loading/#fontface-interface\nconst defaultFontFaceDescriptors = {\n\tstyle: 'normal',\n\tweight: 'normal',\n\tstretch: 'normal',\n\tunicodeRange: 'U+0-10FFFF',\n\tfeatureSettings: 'normal',\n\tascentOverride: 'normal',\n\tdescentOverride: 'normal',\n\tlineGapOverride: 'normal',\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { computed, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport { AtomMap } from '@tldraw/store'\nimport { TLFontFace, TLShape, TLShapeId } from '@tldraw/tlschema'\nimport {\n\tareArraysShallowEqual,\n\tcompact,\n\tFileHelpers,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n} from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\ninterface FontState {\n\treadonly state: 'loading' | 'ready' | 'error'\n\treadonly instance: FontFace\n\treadonly loadingPromise: Promise<void>\n}\n\n/** @public */\nexport class FontManager {\n\tconstructor(\n\t\tprivate readonly editor: Editor,\n\t\tprivate readonly assetUrls?: { [key: string]: string | undefined }\n\t) {\n\t\tthis.shapeFontFacesCache = editor.store.createComputedCache(\n\t\t\t'shape font faces',\n\t\t\t(shape: TLShape) => {\n\t\t\t\tconst shapeUtil = this.editor.getShapeUtil(shape)\n\t\t\t\treturn shapeUtil.getFontFaces(shape)\n\t\t\t},\n\t\t\t{\n\t\t\t\tareResultsEqual: areArraysShallowEqual,\n\t\t\t\tareRecordsEqual: (a, b) => a.props === b.props && a.meta === b.meta,\n\t\t\t}\n\t\t)\n\n\t\tthis.shapeFontLoadStateCache = editor.store.createCache<(FontState | null)[], TLShape>(\n\t\t\t(id: TLShapeId) => {\n\t\t\t\tconst fontFacesComputed = computed('font faces', () => this.getShapeFontFaces(id))\n\t\t\t\treturn computed(\n\t\t\t\t\t'font load state',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst states = fontFacesComputed.get().map((face) => this.getFontState(face))\n\t\t\t\t\t\treturn states\n\t\t\t\t\t},\n\t\t\t\t\t{ isEqual: areArraysShallowEqual }\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate readonly shapeFontFacesCache\n\tprivate readonly shapeFontLoadStateCache\n\n\tgetShapeFontFaces(shape: TLShape | TLShapeId): TLFontFace[] {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\treturn this.shapeFontFacesCache.get(shapeId) ?? EMPTY_ARRAY\n\t}\n\n\ttrackFontsForShape(shape: TLShape | TLShapeId) {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\tthis.shapeFontLoadStateCache.get(shapeId)\n\t}\n\n\tasync loadRequiredFontsForCurrentPage(limit = Infinity) {\n\t\tconst neededFonts = new Set<TLFontFace>()\n\t\tfor (const shapeId of this.editor.getCurrentPageShapeIds()) {\n\t\t\tfor (const font of this.getShapeFontFaces(this.editor.getShape(shapeId)!)) {\n\t\t\t\tneededFonts.add(font)\n\t\t\t}\n\t\t}\n\n\t\tif (neededFonts.size > limit) {\n\t\t\treturn\n\t\t}\n\n\t\tconst promises = Array.from(neededFonts, (font) => this.ensureFontIsLoaded(font))\n\t\tawait Promise.all(promises)\n\t}\n\n\tprivate readonly fontStates = new AtomMap<TLFontFace, FontState>('font states')\n\tprivate getFontState(font: TLFontFace): FontState | null {\n\t\treturn this.fontStates.get(font) ?? null\n\t}\n\n\tensureFontIsLoaded(font: TLFontFace): Promise<void> {\n\t\tconst existingState = this.getFontState(font)\n\t\tif (existingState) return existingState.loadingPromise\n\n\t\tconst instance = this.findOrCreateFontFace(font)\n\t\tconst state: FontState = {\n\t\t\tstate: 'loading',\n\t\t\tinstance,\n\t\t\tloadingPromise: instance\n\t\t\t\t.load()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.editor.getContainerDocument().fonts.add(instance)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'ready' }))\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(err)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'error' }))\n\t\t\t\t}),\n\t\t}\n\n\t\tthis.fontStates.set(font, state)\n\t\treturn state.loadingPromise\n\t}\n\n\tprivate fontsToLoad = new Set<TLFontFace>()\n\trequestFonts(fonts: TLFontFace[]) {\n\t\tif (!this.fontsToLoad.size) {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (this.editor.isDisposed) return\n\t\t\t\tconst toLoad = this.fontsToLoad\n\t\t\t\tthis.fontsToLoad = new Set()\n\t\t\t\ttransact(() => {\n\t\t\t\t\tfor (const font of toLoad) {\n\t\t\t\t\t\tthis.ensureFontIsLoaded(font)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t\tfor (const font of fonts) {\n\t\t\tthis.fontsToLoad.add(font)\n\t\t}\n\t}\n\n\tprivate findOrCreateFontFace(font: TLFontFace) {\n\t\tconst fonts = this.editor.getContainerDocument().fonts\n\t\tfor (const existing of fonts) {\n\t\t\tif (\n\t\t\t\texisting.family === font.family &&\n\t\t\t\tobjectMapEntries(defaultFontFaceDescriptors).every(\n\t\t\t\t\t([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn existing\n\t\t\t}\n\t\t}\n\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst instance = new FontFace(font.family, `url(${JSON.stringify(url)})`, {\n\t\t\t...mapObjectMapValues(defaultFontFaceDescriptors, (key) => font[key]),\n\t\t\tdisplay: 'swap',\n\t\t})\n\n\t\tfonts.add(instance)\n\n\t\treturn instance\n\t}\n\n\tasync toEmbeddedCssDeclaration(font: TLFontFace) {\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst dataUrl = await FileHelpers.urlToDataUrl(url)\n\n\t\tconst src = compact([\n\t\t\t`url(\"${dataUrl}\")`,\n\t\t\tfont.src.format ? `format(${font.src.format})` : null,\n\t\t\tfont.src.tech ? `tech(${font.src.tech})` : null,\n\t\t]).join(' ')\n\t\treturn compact([\n\t\t\t`@font-face {`,\n\t\t\t` font-family: \"${font.family}\";`,\n\t\t\tfont.ascentOverride ? ` ascent-override: ${font.ascentOverride};` : null,\n\t\t\tfont.descentOverride ? ` descent-override: ${font.descentOverride};` : null,\n\t\t\tfont.stretch ? ` font-stretch: ${font.stretch};` : null,\n\t\t\tfont.style ? ` font-style: ${font.style};` : null,\n\t\t\tfont.weight ? ` font-weight: ${font.weight};` : null,\n\t\t\tfont.featureSettings ? ` font-feature-settings: ${font.featureSettings};` : null,\n\t\t\tfont.lineGapOverride ? ` line-gap-override: ${font.lineGapOverride};` : null,\n\t\t\tfont.unicodeRange ? ` unicode-range: ${font.unicodeRange};` : null,\n\t\t\t` src: ${src};`,\n\t\t\t`}`,\n\t\t]).join('\\n')\n\t}\n}\n\n// From https://drafts.csswg.org/css-font-loading/#fontface-interface\nconst defaultFontFaceDescriptors = {\n\tstyle: 'normal',\n\tweight: 'normal',\n\tstretch: 'normal',\n\tunicodeRange: 'U+0-10FFFF',\n\tfeatureSettings: 'normal',\n\tascentOverride: 'normal',\n\tdescentOverride: 'normal',\n\tlineGapOverride: 'normal',\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+ var ThemeManager_exports = {};
28
+ __export(ThemeManager_exports, {
29
+ ThemeManager: () => ThemeManager,
30
+ resolveThemes: () => resolveThemes
31
+ });
32
+ module.exports = __toCommonJS(ThemeManager_exports);
33
+ var import_state = require("@tldraw/state");
34
+ var import_utils = require("@tldraw/utils");
35
+ var import_defaultThemes = require("./defaultThemes");
36
+ function resolveThemes(themes) {
37
+ return { default: import_defaultThemes.DEFAULT_THEME, ...themes };
38
+ }
39
+ class ThemeManager {
40
+ constructor(editor, options) {
41
+ this.editor = editor;
42
+ this._themes = (0, import_state.atom)("ThemeManager._definitions", options.themes);
43
+ this._currentThemeId = (0, import_state.atom)("ThemeManager._currentThemeName", options.initial);
44
+ }
45
+ _themes;
46
+ _currentThemeId;
47
+ getColorMode() {
48
+ return this.editor.user.getIsDarkMode() ? "dark" : "light";
49
+ }
50
+ /** Get all registered theme definitions. */
51
+ getThemes() {
52
+ return this._themes.get();
53
+ }
54
+ /** Get a single theme definition by id. */
55
+ getTheme(id) {
56
+ return this._themes.get()[id];
57
+ }
58
+ /** Get the id of the current theme. */
59
+ getCurrentThemeId() {
60
+ return this._currentThemeId.get();
61
+ }
62
+ getCurrentTheme() {
63
+ return this._themes.get()[this.getCurrentThemeId()];
64
+ }
65
+ /** Set the current theme by id. The theme must have been previously registered. */
66
+ setCurrentTheme(id) {
67
+ if (process.env.NODE_ENV !== "production") {
68
+ if (!(id in this._themes.get())) {
69
+ console.warn(
70
+ `Theme '${id}' not found. Available themes: ${Object.keys(this._themes.get()).join(", ")}`
71
+ );
72
+ }
73
+ }
74
+ this._currentThemeId.set(id);
75
+ }
76
+ /** Replace all theme definitions, or update them via a callback that receives a deep copy. */
77
+ updateThemes(themes) {
78
+ this._themes.update((prev) => {
79
+ const next = typeof themes === "function" ? themes((0, import_utils.structuredClone)(prev)) : themes;
80
+ if (process.env.NODE_ENV !== "production") {
81
+ if (!("default" in next)) {
82
+ console.warn("The 'default' theme cannot be removed.");
83
+ return prev;
84
+ }
85
+ }
86
+ if (!(this._currentThemeId.get() in next)) {
87
+ this._currentThemeId.set("default");
88
+ }
89
+ return next;
90
+ });
91
+ }
92
+ /** Register or update a named theme definition. */
93
+ updateTheme(theme) {
94
+ this._themes.update((prev) => ({
95
+ ...prev,
96
+ [theme.id]: theme
97
+ }));
98
+ }
99
+ /** Clean up any resources held by the manager. */
100
+ dispose() {
101
+ }
102
+ }
103
+ __decorateClass([
104
+ import_state.computed
105
+ ], ThemeManager.prototype, "getColorMode", 1);
106
+ //# sourceMappingURL=ThemeManager.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../src/lib/editor/managers/ThemeManager/ThemeManager.ts"],
4
+ "sourcesContent": ["import { Atom, atom, computed } from '@tldraw/state'\nimport { TLTheme, TLThemeId, TLThemes } from '@tldraw/tlschema'\nimport { structuredClone } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\nimport { DEFAULT_THEME } from './defaultThemes'\n\n/**\n * Resolve a partial set of user-provided themes into a complete `TLThemes`\n * record by merging with `DEFAULT_THEME`. The result is suitable for passing to\n * `registerColorsFromThemes`, `registerFontsFromThemes`, and the\n * `ThemeManager` constructor.\n *\n * @public\n */\nexport function resolveThemes(themes?: Partial<TLThemes>): TLThemes {\n\treturn { default: DEFAULT_THEME, ...themes } as TLThemes\n}\n\n/**\n * Manages the editor's color themes.\n *\n * Stores named theme definitions (each containing light and dark color palettes\n * alongside shared properties like font size). The current theme is resolved by\n * combining the current theme name with the user's color mode preference.\n *\n * **Terminology:**\n * - **Theme** (`TLTheme`): A named set of colors and typographic values for both light and dark modes.\n * - **Color mode** (`'light' | 'dark'`): The resolved appearance mode, derived from the user's\n * `colorScheme` preference (`'light' | 'dark' | 'system'`). Access via `getColorMode()`.\n *\n * @public\n */\nexport class ThemeManager {\n\tprivate readonly _themes: Atom<TLThemes>\n\tprivate readonly _currentThemeId: Atom<TLThemeId>\n\n\tconstructor(\n\t\tprivate readonly editor: Editor,\n\t\toptions: {\n\t\t\tthemes: TLThemes\n\t\t\tinitial: TLThemeId\n\t\t}\n\t) {\n\t\tthis._themes = atom('ThemeManager._definitions', options.themes)\n\t\tthis._currentThemeId = atom('ThemeManager._currentThemeName', options.initial)\n\t}\n\n\t/** Get the current color mode based on the user's dark mode preference. */\n\t@computed getColorMode(): 'light' | 'dark' {\n\t\treturn this.editor.user.getIsDarkMode() ? 'dark' : 'light'\n\t}\n\n\t/** Get all registered theme definitions. */\n\tgetThemes(): TLThemes {\n\t\treturn this._themes.get()\n\t}\n\n\t/** Get a single theme definition by id. */\n\tgetTheme(id: TLThemeId): TLTheme | undefined {\n\t\treturn this._themes.get()[id]\n\t}\n\n\t/** Get the id of the current theme. */\n\tgetCurrentThemeId(): TLThemeId {\n\t\treturn this._currentThemeId.get()\n\t}\n\n\tgetCurrentTheme(): TLTheme {\n\t\treturn this._themes.get()[this.getCurrentThemeId()]!\n\t}\n\n\t/** Set the current theme by id. The theme must have been previously registered. */\n\tsetCurrentTheme(id: TLThemeId): void {\n\t\tif (process.env.NODE_ENV !== 'production') {\n\t\t\tif (!(id in this._themes.get())) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Theme '${id}' not found. Available themes: ${Object.keys(this._themes.get()).join(', ')}`\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\n\t\tthis._currentThemeId.set(id)\n\t}\n\n\t/** Replace all theme definitions, or update them via a callback that receives a deep copy. */\n\tupdateThemes(themes: TLThemes | ((themes: TLThemes) => TLThemes)): void {\n\t\tthis._themes.update((prev) => {\n\t\t\tconst next = typeof themes === 'function' ? themes(structuredClone(prev)) : themes\n\t\t\tif (process.env.NODE_ENV !== 'production') {\n\t\t\t\tif (!('default' in next)) {\n\t\t\t\t\tconsole.warn(\"The 'default' theme cannot be removed.\")\n\t\t\t\t\treturn prev\n\t\t\t\t}\n\t\t\t}\n\t\t\t// If the current theme was removed, fall back to 'default'\n\t\t\tif (!(this._currentThemeId.get() in next)) {\n\t\t\t\tthis._currentThemeId.set('default')\n\t\t\t}\n\t\t\treturn next\n\t\t})\n\t}\n\n\t/** Register or update a named theme definition. */\n\tupdateTheme(theme: TLTheme): void {\n\t\tthis._themes.update((prev) => ({\n\t\t\t...prev,\n\t\t\t[theme.id]: theme,\n\t\t}))\n\t}\n\n\t/** Clean up any resources held by the manager. */\n\tdispose() {\n\t\t// currently no subscriptions to tear down, but here for consistency\n\t\t// with the manager pattern and for future use\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqC;AAErC,mBAAgC;AAEhC,2BAA8B;AAUvB,SAAS,cAAc,QAAsC;AACnE,SAAO,EAAE,SAAS,oCAAe,GAAG,OAAO;AAC5C;AAgBO,MAAM,aAAa;AAAA,EAIzB,YACkB,QACjB,SAIC;AALgB;AAMjB,SAAK,cAAU,mBAAK,6BAA6B,QAAQ,MAAM;AAC/D,SAAK,sBAAkB,mBAAK,kCAAkC,QAAQ,OAAO;AAAA,EAC9E;AAAA,EAZiB;AAAA,EACA;AAAA,EAcP,eAAiC;AAC1C,WAAO,KAAK,OAAO,KAAK,cAAc,IAAI,SAAS;AAAA,EACpD;AAAA;AAAA,EAGA,YAAsB;AACrB,WAAO,KAAK,QAAQ,IAAI;AAAA,EACzB;AAAA;AAAA,EAGA,SAAS,IAAoC;AAC5C,WAAO,KAAK,QAAQ,IAAI,EAAE,EAAE;AAAA,EAC7B;AAAA;AAAA,EAGA,oBAA+B;AAC9B,WAAO,KAAK,gBAAgB,IAAI;AAAA,EACjC;AAAA,EAEA,kBAA2B;AAC1B,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAK,kBAAkB,CAAC;AAAA,EACnD;AAAA;AAAA,EAGA,gBAAgB,IAAqB;AACpC,QAAI,QAAQ,IAAI,aAAa,cAAc;AAC1C,UAAI,EAAE,MAAM,KAAK,QAAQ,IAAI,IAAI;AAChC,gBAAQ;AAAA,UACP,UAAU,EAAE,kCAAkC,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,QACzF;AAAA,MACD;AAAA,IACD;AAEA,SAAK,gBAAgB,IAAI,EAAE;AAAA,EAC5B;AAAA;AAAA,EAGA,aAAa,QAA2D;AACvE,SAAK,QAAQ,OAAO,CAAC,SAAS;AAC7B,YAAM,OAAO,OAAO,WAAW,aAAa,WAAO,8BAAgB,IAAI,CAAC,IAAI;AAC5E,UAAI,QAAQ,IAAI,aAAa,cAAc;AAC1C,YAAI,EAAE,aAAa,OAAO;AACzB,kBAAQ,KAAK,wCAAwC;AACrD,iBAAO;AAAA,QACR;AAAA,MACD;AAEA,UAAI,EAAE,KAAK,gBAAgB,IAAI,KAAK,OAAO;AAC1C,aAAK,gBAAgB,IAAI,SAAS;AAAA,MACnC;AACA,aAAO;AAAA,IACR,CAAC;AAAA,EACF;AAAA;AAAA,EAGA,YAAY,OAAsB;AACjC,SAAK,QAAQ,OAAO,CAAC,UAAU;AAAA,MAC9B,GAAG;AAAA,MACH,CAAC,MAAM,EAAE,GAAG;AAAA,IACb,EAAE;AAAA,EACH;AAAA;AAAA,EAGA,UAAU;AAAA,EAGV;AACD;AAnEW;AAAA,EAAT;AAAA,GAhBW,aAgBF;",
6
+ "names": []
7
+ }