@tsdraw/react 0.8.4 → 0.8.5

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/index.cjs CHANGED
@@ -303,7 +303,11 @@ var TAP_MOVE_TOLERANCE = 14;
303
303
  var PINCH_MODE_ZOOM_DISTANCE = 24;
304
304
  var PINCH_MODE_PAN_DISTANCE = 16;
305
305
  var PINCH_MODE_SWITCH_TO_ZOOM_DISTANCE = 64;
306
- function createTouchInteractionController(editor, canvas, handlers) {
306
+ function createTouchInteractionController(editor, canvas, handlers, touchOptions) {
307
+ const allowPinchZoom = touchOptions?.pinchToZoom !== false;
308
+ const allowFingerPan = touchOptions?.fingerPanInPenMode !== false;
309
+ const allowTapUndoRedo = touchOptions?.tapUndoRedo !== false;
310
+ const allowTrackpadGestures = touchOptions?.trackpadGestures !== false;
307
311
  const activeTouchPoints = /* @__PURE__ */ new Map();
308
312
  const touchTapState = {
309
313
  active: false,
@@ -345,7 +349,7 @@ function createTouchInteractionController(editor, canvas, handlers) {
345
349
  if (activeTouchPoints.size > 0) return;
346
350
  if (!touchTapState.active) return;
347
351
  const elapsed = performance.now() - touchTapState.startTime;
348
- if (!touchTapState.moved && elapsed <= TAP_MAX_DURATION_MS && (touchTapState.maxTouchCount === 2 || touchTapState.maxTouchCount === 3)) {
352
+ if (allowTapUndoRedo && !touchTapState.moved && elapsed <= TAP_MAX_DURATION_MS && (touchTapState.maxTouchCount === 2 || touchTapState.maxTouchCount === 3)) {
349
353
  const fingerCount = touchTapState.maxTouchCount;
350
354
  const now = performance.now();
351
355
  const previousTapTime = touchTapState.lastTapAtByCount[fingerCount] ?? 0;
@@ -393,9 +397,9 @@ function createTouchInteractionController(editor, canvas, handlers) {
393
397
  const touchDistance = Math.abs(distance - touchCameraState.initialDistance);
394
398
  const originDistance = Math.hypot(center.x - touchCameraState.initialCenter.x, center.y - touchCameraState.initialCenter.y);
395
399
  if (touchCameraState.mode === "not-sure") {
396
- if (touchDistance > PINCH_MODE_ZOOM_DISTANCE) touchCameraState.mode = "zooming";
400
+ if (allowPinchZoom && touchDistance > PINCH_MODE_ZOOM_DISTANCE) touchCameraState.mode = "zooming";
397
401
  else if (originDistance > PINCH_MODE_PAN_DISTANCE) touchCameraState.mode = "panning";
398
- } else if (touchCameraState.mode === "panning" && touchDistance > PINCH_MODE_SWITCH_TO_ZOOM_DISTANCE) touchCameraState.mode = "zooming";
402
+ } else if (allowPinchZoom && touchCameraState.mode === "panning" && touchDistance > PINCH_MODE_SWITCH_TO_ZOOM_DISTANCE) touchCameraState.mode = "zooming";
399
403
  const canvasRect = canvas.getBoundingClientRect();
400
404
  const centerOnCanvasX = center.x - canvasRect.left;
401
405
  const centerOnCanvasY = center.y - canvasRect.top;
@@ -436,7 +440,7 @@ function createTouchInteractionController(editor, canvas, handlers) {
436
440
  beginTouchCameraGesture();
437
441
  return true;
438
442
  }
439
- if (handlers.isPenModeActive() && activeTouchPoints.size === 1) {
443
+ if (allowFingerPan && handlers.isPenModeActive() && activeTouchPoints.size === 1) {
440
444
  handlers.cancelActivePointerInteraction();
441
445
  fingerPanPointerId = event.pointerId;
442
446
  fingerPanSession = core.beginCameraPan(editor.viewport, event.clientX, event.clientY);
@@ -471,11 +475,15 @@ function createTouchInteractionController(editor, canvas, handlers) {
471
475
  if (wasFingerPan) {
472
476
  endFingerPan();
473
477
  if (releasedPanSession) {
474
- fingerPanSlide = core.startCameraSlide(
475
- releasedPanSession,
476
- (dx, dy) => editor.panBy(dx, dy),
477
- () => handlers.refreshView()
478
- );
478
+ const slideConfig = handlers.getSlideOptions();
479
+ if (slideConfig.enabled) {
480
+ fingerPanSlide = core.startCameraSlide(
481
+ releasedPanSession,
482
+ (dx, dy) => editor.panBy(dx, dy),
483
+ () => handlers.refreshView(),
484
+ slideConfig.slideOptions
485
+ );
486
+ }
479
487
  }
480
488
  }
481
489
  maybeHandleTouchTapGesture();
@@ -486,6 +494,7 @@ function createTouchInteractionController(editor, canvas, handlers) {
486
494
  const handleGestureEvent = (event, container) => {
487
495
  if (!container.contains(event.target)) return;
488
496
  event.preventDefault();
497
+ if (!allowTrackpadGestures) return;
489
498
  const gestureEvent = event;
490
499
  if (gestureEvent.scale == null) return;
491
500
  if (event.type === "gesturestart") {
@@ -529,7 +538,7 @@ function createTouchInteractionController(editor, canvas, handlers) {
529
538
  }
530
539
 
531
540
  // src/canvas/keyboardShortcuts.ts
532
- var TOOL_SHORTCUTS = {
541
+ var DEFAULT_TOOL_SHORTCUTS = {
533
542
  v: "select",
534
543
  h: "hand",
535
544
  e: "eraser",
@@ -541,6 +550,11 @@ var TOOL_SHORTCUTS = {
541
550
  o: "circle",
542
551
  c: "circle"
543
552
  };
553
+ function resolveToolShortcuts(shortcutOptions) {
554
+ if (!shortcutOptions?.toolShortcuts) return DEFAULT_TOOL_SHORTCUTS;
555
+ if (shortcutOptions.overrideDefaults) return { ...shortcutOptions.toolShortcuts };
556
+ return { ...DEFAULT_TOOL_SHORTCUTS, ...shortcutOptions.toolShortcuts };
557
+ }
544
558
  function isEditableTarget(eventTarget) {
545
559
  const element = eventTarget;
546
560
  if (!element) return false;
@@ -548,7 +562,7 @@ function isEditableTarget(eventTarget) {
548
562
  const tagName = element.tagName;
549
563
  return tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT";
550
564
  }
551
- function handleKeyboardShortcutKeyDown(event, handlers) {
565
+ function handleKeyboardShortcutKeyDown(event, handlers, toolShortcutMap = DEFAULT_TOOL_SHORTCUTS) {
552
566
  if (isEditableTarget(event.target)) return;
553
567
  const loweredKey = event.key.toLowerCase();
554
568
  const isMetaPressed = event.metaKey || event.ctrlKey;
@@ -561,7 +575,7 @@ function handleKeyboardShortcutKeyDown(event, handlers) {
561
575
  }
562
576
  }
563
577
  if (!isMetaPressed && !event.altKey) {
564
- const nextToolId = TOOL_SHORTCUTS[loweredKey];
578
+ const nextToolId = toolShortcutMap[loweredKey];
565
579
  if (nextToolId && handlers.isToolAvailable(nextToolId)) {
566
580
  handlers.setToolFromShortcut(nextToolId);
567
581
  event.preventDefault();
@@ -736,8 +750,17 @@ function getHandlePagePoint(bounds, handle) {
736
750
  }
737
751
  }
738
752
  var ZOOM_WHEEL_CAP = 10;
753
+ var VIEW_ONLY_TOOLS = /* @__PURE__ */ new Set(["select", "hand"]);
739
754
  function useTsdrawCanvasController(options = {}) {
740
755
  const onMountRef = react.useRef(options.onMount);
756
+ const onChangeRef = react.useRef(options.onChange);
757
+ const onCameraChangeRef = react.useRef(options.onCameraChange);
758
+ const onToolChangeRef = react.useRef(options.onToolChange);
759
+ const cameraOptionsRef = react.useRef(options.cameraOptions);
760
+ const touchOptionsRef = react.useRef(options.touchOptions);
761
+ const keyboardShortcutsRef = react.useRef(options.keyboardShortcuts);
762
+ const penOptionsRef = react.useRef(options.penOptions);
763
+ const readOnlyRef = react.useRef(options.readOnly ?? false);
741
764
  const containerRef = react.useRef(null);
742
765
  const canvasRef = react.useRef(null);
743
766
  const editorRef = react.useRef(null);
@@ -797,6 +820,30 @@ function useTsdrawCanvasController(options = {}) {
797
820
  react.useEffect(() => {
798
821
  onMountRef.current = options.onMount;
799
822
  }, [options.onMount]);
823
+ react.useEffect(() => {
824
+ onChangeRef.current = options.onChange;
825
+ }, [options.onChange]);
826
+ react.useEffect(() => {
827
+ onCameraChangeRef.current = options.onCameraChange;
828
+ }, [options.onCameraChange]);
829
+ react.useEffect(() => {
830
+ onToolChangeRef.current = options.onToolChange;
831
+ }, [options.onToolChange]);
832
+ react.useEffect(() => {
833
+ cameraOptionsRef.current = options.cameraOptions;
834
+ }, [options.cameraOptions]);
835
+ react.useEffect(() => {
836
+ touchOptionsRef.current = options.touchOptions;
837
+ }, [options.touchOptions]);
838
+ react.useEffect(() => {
839
+ keyboardShortcutsRef.current = options.keyboardShortcuts;
840
+ }, [options.keyboardShortcuts]);
841
+ react.useEffect(() => {
842
+ penOptionsRef.current = options.penOptions;
843
+ }, [options.penOptions]);
844
+ react.useEffect(() => {
845
+ readOnlyRef.current = options.readOnly ?? false;
846
+ }, [options.readOnly]);
800
847
  react.useEffect(() => {
801
848
  selectedShapeIdsRef.current = selectedShapeIds;
802
849
  }, [selectedShapeIds]);
@@ -920,14 +967,21 @@ function useTsdrawCanvasController(options = {}) {
920
967
  const canvas = canvasRef.current;
921
968
  if (!container || !canvas) return;
922
969
  const initialTool = options.initialTool ?? "pen";
970
+ const cameraOpts = cameraOptionsRef.current;
971
+ const touchOpts = touchOptionsRef.current;
972
+ const toolShortcutMap = resolveToolShortcuts(keyboardShortcutsRef.current);
923
973
  const editor = new core.Editor({
924
974
  toolDefinitions: options.toolDefinitions,
925
- initialToolId: initialTool
975
+ initialToolId: initialTool,
976
+ zoomRange: cameraOpts?.zoomRange
926
977
  });
927
978
  editor.renderer.setTheme(options.theme ?? "light");
928
979
  if (!editor.tools.hasTool(initialTool)) {
929
980
  editor.setCurrentTool("pen");
930
981
  }
982
+ if (options.snapshot) {
983
+ editor.loadPersistenceSnapshot(options.snapshot);
984
+ }
931
985
  let disposed = false;
932
986
  let ignorePersistenceChanges = false;
933
987
  let disposeMount;
@@ -1094,16 +1148,24 @@ function useTsdrawCanvasController(options = {}) {
1094
1148
  render();
1095
1149
  refreshSelectionBounds(editor);
1096
1150
  };
1151
+ const emitCameraChange = () => {
1152
+ onCameraChangeRef.current?.({ ...editor.viewport });
1153
+ };
1097
1154
  const touchInteractions = createTouchInteractionController(editor, canvas, {
1098
1155
  cancelActivePointerInteraction,
1099
1156
  refreshView: () => {
1100
1157
  render();
1101
1158
  refreshSelectionBounds(editor);
1159
+ emitCameraChange();
1102
1160
  },
1103
1161
  runUndo: () => applyDocumentChangeResult(editor.undo()),
1104
1162
  runRedo: () => applyDocumentChangeResult(editor.redo()),
1105
- isPenModeActive: () => penModeRef.current
1106
- });
1163
+ isPenModeActive: () => penModeRef.current,
1164
+ getSlideOptions: () => ({
1165
+ enabled: cameraOptionsRef.current?.slideEnabled !== false,
1166
+ slideOptions: { friction: cameraOptionsRef.current?.slideFriction }
1167
+ })
1168
+ }, touchOpts);
1107
1169
  const hasRealPressure = (pressure) => pressure != null && pressure > 0 && pressure !== 0.5;
1108
1170
  const stopActiveSlide = () => {
1109
1171
  if (activeCameraSlideRef.current) {
@@ -1113,8 +1175,10 @@ function useTsdrawCanvasController(options = {}) {
1113
1175
  };
1114
1176
  const handlePointerDown = (e) => {
1115
1177
  if (!canvas.contains(e.target)) return;
1178
+ if (cameraOptionsRef.current?.locked && e.pointerType !== "pen") return;
1116
1179
  stopActiveSlide();
1117
- if (!penDetectedRef.current && (e.pointerType === "pen" || hasRealPressure(e.pressure))) {
1180
+ const penAutoDetect = penOptionsRef.current?.autoDetect !== false;
1181
+ if (penAutoDetect && !penDetectedRef.current && (e.pointerType === "pen" || hasRealPressure(e.pressure))) {
1118
1182
  penDetectedRef.current = true;
1119
1183
  penModeRef.current = true;
1120
1184
  }
@@ -1135,6 +1199,9 @@ function useTsdrawCanvasController(options = {}) {
1135
1199
  if (activePointerIdsRef.current.size > 1) {
1136
1200
  return;
1137
1201
  }
1202
+ if (readOnlyRef.current && !VIEW_ONLY_TOOLS.has(currentToolRef.current)) {
1203
+ return;
1204
+ }
1138
1205
  isPointerActiveRef.current = true;
1139
1206
  editor.beginHistoryEntry();
1140
1207
  canvas.setPointerCapture(e.pointerId);
@@ -1142,7 +1209,8 @@ function useTsdrawCanvasController(options = {}) {
1142
1209
  updatePointerPreview(e.clientX, e.clientY);
1143
1210
  const first = sampleEvents(e)[0];
1144
1211
  const { x, y } = getPagePoint(first);
1145
- const pressure = first.pressure ?? 0.5;
1212
+ const pressureSensitivity = penOptionsRef.current?.pressureSensitivity ?? 1;
1213
+ const pressure = (first.pressure ?? 0.5) * pressureSensitivity;
1146
1214
  const isPen = first.pointerType === "pen" || hasRealPressure(first.pressure);
1147
1215
  if (currentToolRef.current === "select") {
1148
1216
  const hit = core.getTopShapeAtPoint(editor, { x, y });
@@ -1189,7 +1257,8 @@ function useTsdrawCanvasController(options = {}) {
1189
1257
  refreshSelectionBounds(editor);
1190
1258
  };
1191
1259
  const handlePointerMove = (e) => {
1192
- if (!penDetectedRef.current && (e.pointerType === "pen" || hasRealPressure(e.pressure))) {
1260
+ const penAutoDetectOnMove = penOptionsRef.current?.autoDetect !== false;
1261
+ if (penAutoDetectOnMove && !penDetectedRef.current && (e.pointerType === "pen" || hasRealPressure(e.pressure))) {
1193
1262
  penDetectedRef.current = true;
1194
1263
  penModeRef.current = true;
1195
1264
  }
@@ -1204,9 +1273,10 @@ function useTsdrawCanvasController(options = {}) {
1204
1273
  const dx = prevClient ? e.clientX - prevClient.x : 0;
1205
1274
  const dy = prevClient ? e.clientY - prevClient.y : 0;
1206
1275
  lastPointerClientRef.current = { x: e.clientX, y: e.clientY };
1276
+ const movePressureSensitivity = penOptionsRef.current?.pressureSensitivity ?? 1;
1207
1277
  for (const sample of sampleEvents(e)) {
1208
1278
  const { x, y } = getPagePoint(sample);
1209
- const pressure = sample.pressure ?? 0.5;
1279
+ const pressure = (sample.pressure ?? 0.5) * movePressureSensitivity;
1210
1280
  const isPen = sample.pointerType === "pen" || hasRealPressure(sample.pressure);
1211
1281
  editor.input.pointerMove(x, y, pressure, isPen);
1212
1282
  }
@@ -1340,14 +1410,18 @@ function useTsdrawCanvasController(options = {}) {
1340
1410
  editor.tools.pointerUp();
1341
1411
  render();
1342
1412
  refreshSelectionBounds(editor);
1343
- if (handPanSession) {
1413
+ if (handPanSession && cameraOptionsRef.current?.slideEnabled !== false) {
1344
1414
  activeCameraSlideRef.current = core.startCameraSlide(
1345
1415
  handPanSession,
1346
- (slideDx, slideDy) => editor.panBy(slideDx, slideDy),
1416
+ (slideDx, slideDy) => {
1417
+ editor.panBy(slideDx, slideDy);
1418
+ emitCameraChange();
1419
+ },
1347
1420
  () => {
1348
1421
  render();
1349
1422
  refreshSelectionBounds(editor);
1350
- }
1423
+ },
1424
+ { friction: cameraOptionsRef.current?.slideFriction }
1351
1425
  );
1352
1426
  }
1353
1427
  if (pendingRemoteDocumentRef.current) {
@@ -1392,41 +1466,59 @@ function useTsdrawCanvasController(options = {}) {
1392
1466
  const handleWheel = (e) => {
1393
1467
  if (!container.contains(e.target)) return;
1394
1468
  e.preventDefault();
1469
+ const camOpts = cameraOptionsRef.current;
1470
+ if (camOpts?.locked) return;
1471
+ if (camOpts?.wheelBehavior === "none") return;
1395
1472
  if (touchInteractions.isTrackpadZoomActive()) return;
1396
1473
  const delta = normalizeWheelDelta(e);
1474
+ const panMultiplier = camOpts?.panSpeed ?? 1;
1475
+ const zoomMultiplier = camOpts?.zoomSpeed ?? 1;
1397
1476
  if (delta.z !== 0) {
1398
1477
  const rect = canvas.getBoundingClientRect();
1399
1478
  const pointX = e.clientX - rect.left;
1400
1479
  const pointY = e.clientY - rect.top;
1401
- editor.zoomAt(Math.exp(delta.z), pointX, pointY);
1480
+ editor.zoomAt(Math.exp(delta.z * zoomMultiplier), pointX, pointY);
1402
1481
  } else {
1403
- editor.panBy(delta.x, delta.y);
1482
+ editor.panBy(delta.x * panMultiplier, delta.y * panMultiplier);
1404
1483
  }
1405
1484
  render();
1406
1485
  refreshSelectionBounds(editor);
1486
+ emitCameraChange();
1407
1487
  };
1408
1488
  const handleGestureEvent = (e) => {
1409
1489
  touchInteractions.handleGestureEvent(e, container);
1410
1490
  };
1411
1491
  const handleKeyDown = (e) => {
1492
+ if (keyboardShortcutsRef.current?.enabled === false) return;
1493
+ const isReadOnly = readOnlyRef.current;
1412
1494
  handleKeyboardShortcutKeyDown(e, {
1413
- isToolAvailable: (tool) => editor.tools.hasTool(tool),
1495
+ isToolAvailable: (tool) => {
1496
+ if (isReadOnly && !VIEW_ONLY_TOOLS.has(tool)) return false;
1497
+ return editor.tools.hasTool(tool);
1498
+ },
1414
1499
  setToolFromShortcut: (tool) => {
1415
1500
  editor.setCurrentTool(tool);
1416
1501
  setCurrentToolState(tool);
1417
1502
  currentToolRef.current = tool;
1418
1503
  if (tool !== "select") resetSelectUi();
1419
1504
  render();
1505
+ onToolChangeRef.current?.(tool);
1506
+ },
1507
+ runHistoryShortcut: (shouldRedo) => {
1508
+ if (isReadOnly) return false;
1509
+ return applyDocumentChangeResult(shouldRedo ? editor.redo() : editor.undo());
1510
+ },
1511
+ deleteSelection: () => {
1512
+ if (isReadOnly) return false;
1513
+ return currentToolRef.current === "select" ? deleteCurrentSelection() : false;
1420
1514
  },
1421
- runHistoryShortcut: (shouldRedo) => applyDocumentChangeResult(shouldRedo ? editor.redo() : editor.undo()),
1422
- deleteSelection: () => currentToolRef.current === "select" ? deleteCurrentSelection() : false,
1423
1515
  dispatchKeyDown: (event) => {
1424
1516
  editor.input.setModifiers(event.shiftKey, event.ctrlKey, event.metaKey);
1425
1517
  editor.tools.keyDown({ key: event.key });
1426
1518
  render();
1427
1519
  },
1428
1520
  dispatchKeyUp: () => void 0
1429
- });
1521
+ }, toolShortcutMap);
1430
1522
  };
1431
1523
  const handleKeyUp = (e) => {
1432
1524
  handleKeyboardShortcutKeyUp(e, {
@@ -1507,6 +1599,7 @@ function useTsdrawCanvasController(options = {}) {
1507
1599
  const cleanupEditorListener = editor.listen(() => {
1508
1600
  if (ignorePersistenceChanges) return;
1509
1601
  schedulePersist();
1602
+ onChangeRef.current?.(editor.getDocumentSnapshot());
1510
1603
  });
1511
1604
  const cleanupHistoryListener = editor.listenHistory(() => {
1512
1605
  syncHistoryState();
@@ -1573,6 +1666,9 @@ function useTsdrawCanvasController(options = {}) {
1573
1666
  render();
1574
1667
  }
1575
1668
  });
1669
+ if (options.autoFocus !== false) {
1670
+ container.focus({ preventScroll: true });
1671
+ }
1576
1672
  return () => {
1577
1673
  disposed = true;
1578
1674
  schedulePersistRef.current = null;
@@ -1621,10 +1717,12 @@ function useTsdrawCanvasController(options = {}) {
1621
1717
  const editor = editorRef.current;
1622
1718
  if (!editor) return;
1623
1719
  if (!editor.tools.hasTool(tool)) return;
1720
+ if (readOnlyRef.current && !VIEW_ONLY_TOOLS.has(tool)) return;
1624
1721
  editor.setCurrentTool(tool);
1625
1722
  setCurrentToolState(tool);
1626
1723
  currentToolRef.current = tool;
1627
1724
  if (tool !== "select") resetSelectUi();
1725
+ onToolChangeRef.current?.(tool);
1628
1726
  },
1629
1727
  [resetSelectUi]
1630
1728
  );
@@ -1860,12 +1958,22 @@ function Tsdraw(props) {
1860
1958
  initialTool,
1861
1959
  theme: resolvedTheme,
1862
1960
  persistenceKey: props.persistenceKey,
1863
- onMount: props.onMount
1961
+ onMount: props.onMount,
1962
+ cameraOptions: props.cameraOptions,
1963
+ touchOptions: props.touchOptions,
1964
+ keyboardShortcuts: props.keyboardShortcuts,
1965
+ penOptions: props.penOptions,
1966
+ readOnly: props.readOnly,
1967
+ autoFocus: props.autoFocus,
1968
+ snapshot: props.snapshot,
1969
+ onChange: props.onChange,
1970
+ onCameraChange: props.onCameraChange,
1971
+ onToolChange: props.onToolChange
1864
1972
  });
1865
1973
  const toolbarPlacementStyle = resolvePlacementStyle(props.uiOptions?.toolbar?.placement, "bottom-center", 0, 14);
1866
1974
  const stylePanelPlacementStyle = resolvePlacementStyle(props.uiOptions?.stylePanel?.placement, "top-right", 8, 8);
1867
1975
  const isToolbarHidden = props.uiOptions?.toolbar?.hide === true;
1868
- const isStylePanelHidden = props.uiOptions?.stylePanel?.hide === true;
1976
+ const isStylePanelHidden = props.uiOptions?.stylePanel?.hide === true || props.readOnly === true;
1869
1977
  const canvasCursor = props.uiOptions?.cursor?.getCursor?.(cursorContext) ?? defaultCanvasCursor;
1870
1978
  const defaultToolOverlay = /* @__PURE__ */ jsxRuntime.jsx(
1871
1979
  ToolOverlay,
@@ -1954,12 +2062,14 @@ function Tsdraw(props) {
1954
2062
  "div",
1955
2063
  {
1956
2064
  ref: containerRef,
2065
+ tabIndex: 0,
1957
2066
  className: `tsdraw tsdraw-${resolvedTheme}mode ${props.className ?? ""}`,
1958
2067
  style: {
1959
2068
  width: props.width ?? "100%",
1960
2069
  height: props.height ?? "100%",
1961
2070
  position: "relative",
1962
2071
  overflow: "hidden",
2072
+ outline: "none",
1963
2073
  ...props.style
1964
2074
  },
1965
2075
  children: [