@scrawl-board/board 0.1.0-beta.0 → 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -23,6 +23,11 @@ var AssetResolutionError = class extends Error {
23
23
  var ASSET_CACHE_BYTES_DEFAULT = 256 * 1024 * 1024;
24
24
  var ASSET_CACHE_BYTES_MIN = 64 * 1024 * 1024;
25
25
  var ASSET_CACHE_BYTES_MAX = 512 * 1024 * 1024;
26
+ var SUPPORTED_ASSET_MEDIA_TYPES = [
27
+ "image/png",
28
+ "image/jpeg",
29
+ "image/webp"
30
+ ];
26
31
  function clampAssetCacheBytes(value) {
27
32
  if (value === void 0 || !Number.isFinite(value)) return ASSET_CACHE_BYTES_DEFAULT;
28
33
  return Math.min(ASSET_CACHE_BYTES_MAX, Math.max(ASSET_CACHE_BYTES_MIN, Math.floor(value)));
@@ -445,7 +450,6 @@ function measureTable(table) {
445
450
  height: table.rowHeights.reduce((sum, h) => sum + h, 0)
446
451
  };
447
452
  }
448
- var BOARD_COLOR = "#FFFFFF";
449
453
  var FOG_COLOR = "#FFFFFF";
450
454
  function cloneImage(img) {
451
455
  return { ...img };
@@ -1937,12 +1941,19 @@ var LIGHT = {
1937
1941
  var MARGIN = 4;
1938
1942
  var NOTE_FONT_RATIO = 44 / 512;
1939
1943
  var NOTE_PAD_RATIO = 40 / 512;
1944
+ /** Matches the theme system's light-preset `boardSurface` default (theme.ts) — kept in sync manually, since core-internal stays decoupled from the theme layer. */
1945
+ var DEFAULT_BACKGROUND_COLOR = "#f5f5f3";
1940
1946
  /**
1941
1947
  * `registry` is optional and only enables rendering Custom objects through
1942
1948
  * their own `describe()` — without it (or for an object whose extension
1943
1949
  * isn't in it), Custom objects still export via the standard fallback
1944
1950
  * placeholder (`fallback.bounds`/`label`), never silently dropped.
1945
1951
  *
1952
+ * `backgroundColor` should be the Host's actual resolved `boardTheme.surface`
1953
+ * so an export matches what was on screen; defaults to the theme system's
1954
+ * own light-preset default when the caller doesn't have one on hand. The
1955
+ * board's reference grid, if any, is a screen-only aid and never exported.
1956
+ *
1946
1957
  * `resolvedAssets` (ticket #23) maps an Asset reference to an already-
1947
1958
  * resolved `data:` URI — see `assetExport.ts`'s `exportDocumentSVGWithAssets`,
1948
1959
  * which is the only intended caller that ever passes one. Without it, every
@@ -1950,7 +1961,7 @@ var NOTE_PAD_RATIO = 40 / 512;
1950
1961
  * placeholder instead of guessing at a URL; a legacy `src`-backed image is
1951
1962
  * unaffected either way.
1952
1963
  */
1953
- function documentToSVG(doc, now = 0, registry, resolvedAssets) {
1964
+ function documentToSVG(doc, now = 0, registry, backgroundColor = DEFAULT_BACKGROUND_COLOR, resolvedAssets) {
1954
1965
  const notes = doc.notes ?? [];
1955
1966
  const texts = doc.textBlocks ?? [];
1956
1967
  const tables = doc.tables ?? [];
@@ -1963,7 +1974,7 @@ function documentToSVG(doc, now = 0, registry, resolvedAssets) {
1963
1974
  const highlights = doc.strokes.filter((s) => s.tool === "highlighter");
1964
1975
  const ink = doc.strokes.filter((s) => s.tool !== "highlighter");
1965
1976
  return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${view}">\n<defs>\n${defs}\n</defs>\n${[
1966
- `<rect x="${fmt(bounds.minX)}" y="${fmt(bounds.minY)}" width="${fmt(bounds.width)}" height="${fmt(bounds.height)}" fill="${BOARD_COLOR}"/>`,
1977
+ `<rect x="${fmt(bounds.minX)}" y="${fmt(bounds.minY)}" width="${fmt(bounds.width)}" height="${fmt(bounds.height)}" fill="${backgroundColor}"/>`,
1967
1978
  ...images.map((image) => imageToElement(image, resolvedAssets)),
1968
1979
  ...tables.map(tableToGroup),
1969
1980
  ...highlights.flatMap(strokeToPaths),
@@ -2879,7 +2890,7 @@ var SvgAssetExportError = class extends Error {
2879
2890
  this.name = "SvgAssetExportError";
2880
2891
  }
2881
2892
  };
2882
- async function exportDocumentSVGWithAssets(doc, now, registry, assetController, options) {
2893
+ async function exportDocumentSVGWithAssets(doc, now, registry, assetController, backgroundColor, options) {
2883
2894
  const refs = collectDocumentAssetRefs(doc, registry);
2884
2895
  const resolvedAssets = /* @__PURE__ */ new Map();
2885
2896
  const missingAssets = [];
@@ -2915,7 +2926,7 @@ async function exportDocumentSVGWithAssets(doc, now, registry, assetController,
2915
2926
  }
2916
2927
  if (missingAssets.length > 0 && options?.missingAssets !== "placeholder") throw new SvgAssetExportError(missingAssets);
2917
2928
  return {
2918
- svg: documentToSVG(doc, now, registry, resolvedAssets),
2929
+ svg: documentToSVG(doc, now, registry, backgroundColor, resolvedAssets),
2919
2930
  missingAssets
2920
2931
  };
2921
2932
  }
@@ -35836,6 +35847,21 @@ var FOG_GLSL = `
35836
35847
  `;
35837
35848
  //#endregion
35838
35849
  //#region ../../src/scrawl/engine/boardSurface.ts
35850
+ var GRID_MODE_CODE = {
35851
+ none: 0,
35852
+ line: 1,
35853
+ dot: 2
35854
+ };
35855
+ /** Used when a caller doesn't supply one (e.g. ScrawlEngine constructed without a Host theme). */
35856
+ var DEFAULT_BOARD_SURFACE_THEME = {
35857
+ color: "#f5f5f3",
35858
+ gridMode: "none",
35859
+ gridColor: "#deded8",
35860
+ gridSpacing: 5
35861
+ };
35862
+ /** Grid alpha fades out below this on-screen spacing (px) — otherwise it aliases into a solid wash when zoomed out. */
35863
+ var GRID_FADE_MIN_PX = 3;
35864
+ var GRID_FADE_MAX_PX = 8;
35839
35865
  var VERTEX$1 = `
35840
35866
  varying vec3 vWorldPos;
35841
35867
  void main() {
@@ -35849,6 +35875,11 @@ var FRAGMENT = `
35849
35875
  uniform vec3 uFogColor;
35850
35876
  uniform float uFogNear;
35851
35877
  uniform float uFogFar;
35878
+ uniform float uGridMode;
35879
+ uniform vec3 uGridColor;
35880
+ uniform float uGridSpacing;
35881
+ uniform float uGridLineWorld;
35882
+ uniform float uGridFade;
35852
35883
  varying vec3 vWorldPos;
35853
35884
 
35854
35885
  float hash(vec2 p) {
@@ -35867,6 +35898,22 @@ var FRAGMENT = `
35867
35898
 
35868
35899
  ${FOG_GLSL}
35869
35900
 
35901
+ // Distance from p's nearest axis-aligned grid line, in world units.
35902
+ float gridLineAlpha(vec2 p) {
35903
+ vec2 cell = mod(p, uGridSpacing);
35904
+ vec2 distToLine = min(cell, uGridSpacing - cell);
35905
+ vec2 lineAlpha2 = 1.0 - smoothstep(uGridLineWorld, uGridLineWorld * 2.0, distToLine);
35906
+ return max(lineAlpha2.x, lineAlpha2.y);
35907
+ }
35908
+
35909
+ // Distance from p's nearest grid intersection, in world units.
35910
+ float gridDotAlpha(vec2 p) {
35911
+ vec2 cell = mod(p, uGridSpacing) - uGridSpacing * 0.5;
35912
+ float dist = length(cell);
35913
+ float radius = uGridLineWorld * 1.5;
35914
+ return 1.0 - smoothstep(radius, radius * 2.0, dist);
35915
+ }
35916
+
35870
35917
  void main() {
35871
35918
  vec3 col = uColor;
35872
35919
 
@@ -35884,16 +35931,26 @@ var FRAGMENT = `
35884
35931
  float spec = pow(max(dot(N, H), 0.0), 90.0);
35885
35932
  col += (fres * 0.18 + spec * 0.06) * vec3(1.0);
35886
35933
 
35934
+ if (uGridMode > 0.5 && uGridFade > 0.001) {
35935
+ float gridAlpha = (uGridMode < 1.5 ? gridLineAlpha(vWorldPos.xy) : gridDotAlpha(vWorldPos.xy)) * uGridFade;
35936
+ col = mix(col, uGridColor, gridAlpha);
35937
+ }
35938
+
35887
35939
  col = applyBoardFog(col, vWorldPos);
35888
35940
  gl_FragColor = vec4(col, 1.0);
35889
35941
  }
35890
35942
  `;
35891
- function createBoardSurface(fog) {
35943
+ function createBoardSurface(fog, theme) {
35892
35944
  const material = new ShaderMaterial({
35893
35945
  vertexShader: VERTEX$1,
35894
35946
  fragmentShader: FRAGMENT,
35895
35947
  uniforms: {
35896
- uColor: { value: new Color(BOARD_COLOR) },
35948
+ uColor: { value: new Color(theme.color) },
35949
+ uGridMode: { value: GRID_MODE_CODE[theme.gridMode] },
35950
+ uGridColor: { value: new Color(theme.gridColor) },
35951
+ uGridSpacing: { value: Math.max(.001, theme.gridSpacing) },
35952
+ uGridLineWorld: { value: .05 },
35953
+ uGridFade: { value: 0 },
35897
35954
  ...fog
35898
35955
  }
35899
35956
  });
@@ -35901,11 +35958,32 @@ function createBoardSurface(fog) {
35901
35958
  mesh.name = "board-surface";
35902
35959
  return mesh;
35903
35960
  }
35904
- /** Keep the plane centered under the view and larger than the fog horizon. */
35905
- function updateBoardSurface(mesh, centerX, centerY, fogFar) {
35961
+ /** Applies a theme change (initial or live) — everything except the per-frame fade/line-width. */
35962
+ function setBoardSurfaceTheme(mesh, theme) {
35963
+ const uniforms = mesh.material.uniforms;
35964
+ uniforms.uColor.value.set(theme.color);
35965
+ uniforms.uGridMode.value = GRID_MODE_CODE[theme.gridMode];
35966
+ uniforms.uGridColor.value.set(theme.gridColor);
35967
+ uniforms.uGridSpacing.value = Math.max(.001, theme.gridSpacing);
35968
+ }
35969
+ /** Keep the plane centered under the view, larger than the fog horizon, and the grid's on-screen weight/fade current. */
35970
+ function updateBoardSurface(mesh, centerX, centerY, fogFar, worldPerPixel) {
35906
35971
  mesh.position.set(centerX, centerY, 0);
35907
35972
  const size = fogFar * 2.5;
35908
35973
  mesh.scale.set(size, size, 1);
35974
+ const uniforms = mesh.material.uniforms;
35975
+ uniforms.uGridLineWorld.value = worldPerPixel;
35976
+ const t = (uniforms.uGridSpacing.value / Math.max(1e-6, worldPerPixel) - GRID_FADE_MIN_PX) / (GRID_FADE_MAX_PX - GRID_FADE_MIN_PX);
35977
+ uniforms.uGridFade.value = MathUtils.clamp(t, 0, 1);
35978
+ }
35979
+ /** Temporarily zeroes the grid's contribution (for export snapshots) and returns a restore function. */
35980
+ function suppressBoardSurfaceGrid(mesh) {
35981
+ const uniforms = mesh.material.uniforms;
35982
+ const previous = uniforms.uGridFade.value;
35983
+ uniforms.uGridFade.value = 0;
35984
+ return () => {
35985
+ uniforms.uGridFade.value = previous;
35986
+ };
35909
35987
  }
35910
35988
  var MIN_HEIGHT = 40;
35911
35989
  var MAX_HEIGHT = 1500;
@@ -36069,7 +36147,7 @@ var CameraRig = class {
36069
36147
  //#endregion
36070
36148
  //#region ../../src/scrawl/engine/scene.ts
36071
36149
  var SceneRig = class {
36072
- constructor(canvas) {
36150
+ constructor(canvas, boardTheme) {
36073
36151
  this.renderer = new WebGLRenderer({
36074
36152
  canvas,
36075
36153
  antialias: true
@@ -36079,7 +36157,7 @@ var SceneRig = class {
36079
36157
  this.scene = new Scene();
36080
36158
  this.cameraRig = new CameraRig(canvas.clientWidth / Math.max(1, canvas.clientHeight));
36081
36159
  this.fog = createFogUniforms(FOG_COLOR);
36082
- this.board = createBoardSurface(this.fog);
36160
+ this.board = createBoardSurface(this.fog, boardTheme);
36083
36161
  this.scene.add(this.board);
36084
36162
  this.inkGroup = new Group();
36085
36163
  this.inkGroup.name = "ink";
@@ -36096,9 +36174,17 @@ var SceneRig = class {
36096
36174
  renderFrame(dtMs) {
36097
36175
  this.cameraRig.update(dtMs);
36098
36176
  updateFogForCamera(this.fog, this.cameraRig.height);
36099
- updateBoardSurface(this.board, this.cameraRig.center.x, this.cameraRig.center.y, this.fog.uFogFar.value);
36177
+ updateBoardSurface(this.board, this.cameraRig.center.x, this.cameraRig.center.y, this.fog.uFogFar.value, this.cameraRig.worldPerPixel());
36100
36178
  this.renderer.render(this.scene, this.cameraRig.camera);
36101
36179
  }
36180
+ /** Live theme update — the board controller's identity stays fixed across theme changes; this is how a new one reaches the render engine. */
36181
+ applyBoardTheme(theme) {
36182
+ setBoardSurfaceTheme(this.board, theme);
36183
+ }
36184
+ /** Zeroes the grid for one render pass (PNG export never bakes it in) and returns a restore function. */
36185
+ suppressGrid() {
36186
+ return suppressBoardSurfaceGrid(this.board);
36187
+ }
36102
36188
  dispose() {
36103
36189
  this.board.geometry.dispose();
36104
36190
  this.board.material.dispose();
@@ -46547,9 +46633,10 @@ function emptyExtensionRegistry() {
46547
46633
  * React never reaches past this class.
46548
46634
  */
46549
46635
  var ScrawlEngine = class {
46550
- constructor(canvas, documentId$1, extensionRegistry = emptyExtensionRegistry(), assetController = new AssetController(void 0)) {
46636
+ constructor(canvas, documentId$1, extensionRegistry = emptyExtensionRegistry(), assetController = new AssetController(void 0), boardTheme = DEFAULT_BOARD_SURFACE_THEME) {
46551
46637
  this.canvas = canvas;
46552
46638
  this.extensionRegistry = extensionRegistry;
46639
+ this.boardTheme = boardTheme;
46553
46640
  this.onToolChange = null;
46554
46641
  this.onZoomChange = null;
46555
46642
  this.onAuditEvent = null;
@@ -46596,7 +46683,7 @@ var ScrawlEngine = class {
46596
46683
  this.stampKind = "star";
46597
46684
  this.timerDurationMs = TIMER_DEFAULT_DURATION_MS;
46598
46685
  this.readOnly = false;
46599
- this.scene = new SceneRig(canvas);
46686
+ this.scene = new SceneRig(canvas, boardTheme);
46600
46687
  this.document = new BoardDocument(documentId(documentId$1));
46601
46688
  this.history = new History(this.document);
46602
46689
  this.history.onCommand = (command, kind) => {
@@ -46903,6 +46990,11 @@ var ScrawlEngine = class {
46903
46990
  height: rig.height
46904
46991
  };
46905
46992
  }
46993
+ /** Live update of the board surface color/grid — the engine's identity stays fixed across theme changes. */
46994
+ applyBoardTheme(theme) {
46995
+ this.boardTheme = theme;
46996
+ this.scene.applyBoardTheme(theme);
46997
+ }
46906
46998
  /**
46907
46999
  * Snap to a peer's camera. No-op while drawing so pointer-to-board
46908
47000
  * mapping does not warp the in-progress stroke.
@@ -46921,7 +47013,7 @@ var ScrawlEngine = class {
46921
47013
  }
46922
47014
  /** The saved document as standalone SVG — a pure walk of the wire format. */
46923
47015
  exportSVG() {
46924
- return documentToSVG(this.document.toJSON(), Date.now(), this.extensionRegistry);
47016
+ return documentToSVG(this.document.toJSON(), Date.now(), this.extensionRegistry, this.boardTheme.color);
46925
47017
  }
46926
47018
  /**
46927
47019
  * Content-framed PNG snapshot. Renders once offscreen-style with UI props
@@ -46957,6 +47049,7 @@ var ScrawlEngine = class {
46957
47049
  this.notesRenderer.setFocus(null);
46958
47050
  this.textsRenderer.setFocus(null);
46959
47051
  this.renderer.setGhostsVisible(false);
47052
+ const restoreGrid = this.scene.suppressGrid();
46960
47053
  try {
46961
47054
  rig.yaw = 0;
46962
47055
  rig.pitch = 0;
@@ -46967,6 +47060,7 @@ var ScrawlEngine = class {
46967
47060
  const dataUrl = this.scene.renderer.domElement.toDataURL("image/png");
46968
47061
  return await (await fetch(dataUrl)).blob();
46969
47062
  } finally {
47063
+ restoreGrid();
46970
47064
  rig.center.x = saved.x;
46971
47065
  rig.center.y = saved.y;
46972
47066
  rig.height = saved.height;
@@ -47976,7 +48070,13 @@ function createBoardControllerWithEngine(options, existingEngine) {
47976
48070
  }
47977
48071
  const extensionRegistry = registryResult.registry;
47978
48072
  const assetController = new AssetController(options.assetResolver, { cacheBytes: options.assetCacheBytes });
47979
- const engine = existingEngine ?? (options.canvas ? new ScrawlEngine(options.canvas, options.document.id, extensionRegistry, assetController) : null);
48073
+ let currentBoardTheme = {
48074
+ color: options.boardTheme?.surface ?? DEFAULT_BOARD_SURFACE_THEME.color,
48075
+ gridMode: options.boardTheme?.gridMode ?? DEFAULT_BOARD_SURFACE_THEME.gridMode,
48076
+ gridColor: options.boardTheme?.gridColor ?? DEFAULT_BOARD_SURFACE_THEME.gridColor,
48077
+ gridSpacing: options.boardTheme?.gridSpacing ?? DEFAULT_BOARD_SURFACE_THEME.gridSpacing
48078
+ };
48079
+ const engine = existingEngine ?? (options.canvas ? new ScrawlEngine(options.canvas, options.document.id, extensionRegistry, assetController, currentBoardTheme) : null);
47980
48080
  const document = engine?.document ?? new BoardDocument(documentId(options.document.id));
47981
48081
  const history = engine?.history ?? new History(document);
47982
48082
  const createId = options.createId ?? (() => crypto.randomUUID());
@@ -48460,6 +48560,15 @@ function createBoardControllerWithEngine(options, existingEngine) {
48460
48560
  changed();
48461
48561
  }
48462
48562
  },
48563
+ boardTheme: { set(theme) {
48564
+ currentBoardTheme = {
48565
+ color: theme.surface ?? currentBoardTheme.color,
48566
+ gridMode: theme.gridMode ?? currentBoardTheme.gridMode,
48567
+ gridColor: theme.gridColor ?? currentBoardTheme.gridColor,
48568
+ gridSpacing: theme.gridSpacing ?? currentBoardTheme.gridSpacing
48569
+ };
48570
+ engine?.applyBoardTheme(currentBoardTheme);
48571
+ } },
48463
48572
  view: {
48464
48573
  fit() {
48465
48574
  assertActive();
@@ -48764,10 +48873,10 @@ function createBoardControllerWithEngine(options, existingEngine) {
48764
48873
  gather: (nextView) => engine?.applyGatherView(nextView) ?? false
48765
48874
  },
48766
48875
  export: {
48767
- svg: () => engine ? engine.exportSVG() : documentToSVG(document.toJSON(), Date.now(), extensionRegistry),
48876
+ svg: () => engine ? engine.exportSVG() : documentToSVG(document.toJSON(), Date.now(), extensionRegistry, currentBoardTheme.color),
48768
48877
  png: (options) => engine ? engine.exportPNG(options?.maxSide, { awaitAssets: options?.awaitAssets }) : Promise.resolve(null),
48769
48878
  json: () => document.toJSON(),
48770
- svgAsync: (svgOptions) => exportDocumentSVGWithAssets(document.toJSON(), Date.now(), extensionRegistry, assetController, svgOptions)
48879
+ svgAsync: (svgOptions) => exportDocumentSVGWithAssets(document.toJSON(), Date.now(), extensionRegistry, assetController, currentBoardTheme.color, svgOptions)
48771
48880
  },
48772
48881
  assets: { async ingest(bytes, mediaType, name, signal) {
48773
48882
  assertActive();
@@ -49254,7 +49363,11 @@ var scrawlThemePresets = Object.freeze({
49254
49363
  elevationHigh: "0 8px 20px rgba(28, 28, 26, 0.18)",
49255
49364
  motionDuration: 140,
49256
49365
  motionEasing: "cubic-bezier(0.2, 0, 0, 1)",
49257
- density: "comfortable"
49366
+ density: "comfortable",
49367
+ boardSurface: "#f5f5f3",
49368
+ gridMode: "none",
49369
+ gridColor: "#deded8",
49370
+ gridSpacing: 5
49258
49371
  }),
49259
49372
  dark: Object.freeze({
49260
49373
  surface: "#171816",
@@ -49279,7 +49392,11 @@ var scrawlThemePresets = Object.freeze({
49279
49392
  elevationHigh: "0 8px 20px rgba(0, 0, 0, 0.38)",
49280
49393
  motionDuration: 140,
49281
49394
  motionEasing: "cubic-bezier(0.2, 0, 0, 1)",
49282
- density: "comfortable"
49395
+ density: "comfortable",
49396
+ boardSurface: "#232420",
49397
+ gridMode: "none",
49398
+ gridColor: "#33352f",
49399
+ gridSpacing: 5
49283
49400
  })
49284
49401
  });
49285
49402
  var variableNames = {
@@ -49305,7 +49422,11 @@ var variableNames = {
49305
49422
  elevationHigh: "--scrawl-elevation-high",
49306
49423
  motionDuration: "--scrawl-motion-duration",
49307
49424
  motionEasing: "--scrawl-motion-easing",
49308
- density: "--scrawl-density"
49425
+ density: "--scrawl-density",
49426
+ boardSurface: "--scrawl-board-surface",
49427
+ gridMode: "--scrawl-grid-mode",
49428
+ gridColor: "--scrawl-grid-color",
49429
+ gridSpacing: "--scrawl-grid-spacing"
49309
49430
  };
49310
49431
  var colorTokens = /* @__PURE__ */ new Set([
49311
49432
  "surface",
@@ -49318,7 +49439,9 @@ var colorTokens = /* @__PURE__ */ new Set([
49318
49439
  "selection",
49319
49440
  "danger",
49320
49441
  "warning",
49321
- "success"
49442
+ "success",
49443
+ "boardSurface",
49444
+ "gridColor"
49322
49445
  ]);
49323
49446
  var knownTokens = new Set(Object.keys(scrawlThemePresets.light));
49324
49447
  function validateScrawlTheme(theme) {
@@ -49355,6 +49478,14 @@ function validateScrawlTheme(theme) {
49355
49478
  token,
49356
49479
  message: "Expected comfortable or compact"
49357
49480
  });
49481
+ else if (token === "gridMode" && value !== "none" && value !== "line" && value !== "dot") diagnostics.push({
49482
+ token,
49483
+ message: "Expected none, line, or dot"
49484
+ });
49485
+ else if (token === "gridSpacing" && (!finiteNumber(value) || value < .5 || value > 50)) diagnostics.push({
49486
+ token,
49487
+ message: "Expected spacing 0.5-50 board units"
49488
+ });
49358
49489
  else if ((token.endsWith("Family") || token.startsWith("elevation") || token === "motionEasing") && (typeof value !== "string" || !value.trim() || /[;{}]/.test(value))) diagnostics.push({
49359
49490
  token,
49360
49491
  message: "Expected a safe CSS value"
@@ -50510,6 +50641,14 @@ function ScrawlProvider({ controller, children, preset = "light", theme, portalC
50510
50641
  style
50511
50642
  ]);
50512
50643
  useEffect(() => reportThemeDiagnostics(resolved.diagnostics, onThemeDiagnostic), [resolved, onThemeDiagnostic]);
50644
+ useEffect(() => {
50645
+ controller.boardTheme.set({
50646
+ surface: resolved.values.boardSurface,
50647
+ gridMode: resolved.values.gridMode,
50648
+ gridColor: resolved.values.gridColor,
50649
+ gridSpacing: resolved.values.gridSpacing
50650
+ });
50651
+ }, [controller, resolved]);
50513
50652
  useDeferredDisposal(controller, disposeOnUnmount);
50514
50653
  const value = useMemo(() => ({
50515
50654
  controller,
@@ -50557,8 +50696,16 @@ function Scrawl({ children, preset, theme, portalContainer, className, style, on
50557
50696
  try {
50558
50697
  if (!runtimeRef.current) {
50559
50698
  const canvas = suppliedCanvas === void 0 ? ownedCanvasRef.current : suppliedCanvas;
50699
+ const resolved = resolveScrawlTheme(preset, theme);
50700
+ const boardTheme = {
50701
+ surface: resolved.values.boardSurface,
50702
+ gridMode: resolved.values.gridMode,
50703
+ gridColor: resolved.values.gridColor,
50704
+ gridSpacing: resolved.values.gridSpacing
50705
+ };
50560
50706
  controller = createBoardController({
50561
50707
  ...options,
50708
+ boardTheme,
50562
50709
  ...canvas ? { canvas } : {}
50563
50710
  });
50564
50711
  runtimeRef.current = {
@@ -50794,4 +50941,4 @@ function ScrawlBoard({ documentId, initialDocument, onReady, className, style })
50794
50941
  });
50795
50942
  }
50796
50943
  //#endregion
50797
- export { DefaultBoardChrome, InlineEditors, MultiplayerCursors, Scrawl, ScrawlBoard, ScrawlCanvas, ScrawlDefaultUI, ScrawlPortal, ScrawlProvider, StyleShelf, resolveScrawlTheme, scrawlThemePresets, useScrawlController, useScrawlSnapshot, useScrawlTheme, validateScrawlTheme };
50944
+ export { AssetResolutionError, DefaultBoardChrome, InlineEditors, MultiplayerCursors, SUPPORTED_ASSET_MEDIA_TYPES, Scrawl, ScrawlBoard, ScrawlCanvas, ScrawlDefaultUI, ScrawlPortal, ScrawlProvider, StyleShelf, assetRef, clampAssetCacheBytes, cloneCustomObject, isAssetRef, resolveScrawlTheme, scrawlThemePresets, useScrawlController, useScrawlSnapshot, useScrawlTheme, validateScrawlTheme };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scrawl-board/board",
3
- "version": "0.1.0-beta.0",
3
+ "version": "0.1.0-beta.1",
4
4
  "description": "The Scrawl Board SDK: an embeddable, collaborative infinite-canvas whiteboard for React and vanilla JS/TS apps.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {