@doenet/doenetml-iframe 0.7.20-dev.323 → 0.7.20-dev.326

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/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import * as React__default from "react";
2
- import React__default__default, { createContext, useMemo, useCallback, useLayoutEffect, useEffect, useRef, useState, useContext, isValidElement } from "react";
1
+ import * as React from "react";
2
+ import React__default, { createContext, useMemo, useCallback, useLayoutEffect, useEffect, useRef, useState, useContext, isValidElement } from "react";
3
3
  import { MathJaxBaseContext, MathJax } from "better-react-mathjax";
4
4
  import { createRoot } from "react-dom/client";
5
5
  import { createPortal } from "react-dom";
@@ -337,7 +337,7 @@ var DefaultContext = {
337
337
  style: void 0,
338
338
  attr: void 0
339
339
  };
340
- var IconContext = React__default__default.createContext && /* @__PURE__ */ React__default__default.createContext(DefaultContext);
340
+ var IconContext = React__default.createContext && /* @__PURE__ */ React__default.createContext(DefaultContext);
341
341
  var _excluded = ["attr", "size", "title"];
342
342
  function _objectWithoutProperties(e2, t4) {
343
343
  if (null == e2) return {};
@@ -405,12 +405,12 @@ function _toPrimitive(t4, r2) {
405
405
  return ("string" === r2 ? String : Number)(t4);
406
406
  }
407
407
  function Tree2Element(tree) {
408
- return tree && tree.map((node, i2) => /* @__PURE__ */ React__default__default.createElement(node.tag, _objectSpread$5({
408
+ return tree && tree.map((node, i2) => /* @__PURE__ */ React__default.createElement(node.tag, _objectSpread$5({
409
409
  key: i2
410
410
  }, node.attr), Tree2Element(node.child)));
411
411
  }
412
412
  function GenIcon(data) {
413
- return (props) => /* @__PURE__ */ React__default__default.createElement(IconBase, _extends$2({
413
+ return (props) => /* @__PURE__ */ React__default.createElement(IconBase, _extends$2({
414
414
  attr: _objectSpread$5({}, data.attr)
415
415
  }, props), Tree2Element(data.child));
416
416
  }
@@ -421,7 +421,7 @@ function IconBase(props) {
421
421
  var className;
422
422
  if (conf.className) className = conf.className;
423
423
  if (props.className) className = (className ? className + " " : "") + props.className;
424
- return /* @__PURE__ */ React__default__default.createElement("svg", _extends$2({
424
+ return /* @__PURE__ */ React__default.createElement("svg", _extends$2({
425
425
  stroke: "currentColor",
426
426
  fill: "currentColor",
427
427
  strokeWidth: "0"
@@ -433,9 +433,9 @@ function IconBase(props) {
433
433
  height: computedSize,
434
434
  width: computedSize,
435
435
  xmlns: "http://www.w3.org/2000/svg"
436
- }), title && /* @__PURE__ */ React__default__default.createElement("title", null, title), props.children);
436
+ }), title && /* @__PURE__ */ React__default.createElement("title", null, title), props.children);
437
437
  };
438
- return IconContext !== void 0 ? /* @__PURE__ */ React__default__default.createElement(IconContext.Consumer, null, (conf) => elem(conf)) : elem(DefaultContext);
438
+ return IconContext !== void 0 ? /* @__PURE__ */ React__default.createElement(IconContext.Consumer, null, (conf) => elem(conf)) : elem(DefaultContext);
439
439
  }
440
440
  function MdError(props) {
441
441
  return GenIcon({ "attr": { "viewBox": "0 0 24 24" }, "child": [{ "tag": "path", "attr": { "fill": "none", "d": "M0 0h24v24H0z" }, "child": [] }, { "tag": "path", "attr": { "d": "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m1 15h-2v-2h2zm0-4h-2V7h2z" }, "child": [] }] })(props);
@@ -20232,10 +20232,10 @@ var astToFiniteField$1$1 = class astToFiniteField$12 {
20232
20232
  convert(t4, n2, r2 = PRIME$1) {
20233
20233
  return finite_field_evaluate_ast$1(t4, n2, r2);
20234
20234
  }
20235
- }, evaluation_exports$1 = __exportAll$1({ evaluate: () => evaluate$1, evaluate_to_constant: () => evaluate_to_constant$1, f: () => f$2, finite_field_evaluate: () => finite_field_evaluate$1 }), astToMathjs$1$1 = new astToMathjs$2$1({ mathjs: mathjs_default$1 }), astToFiniteField$2 = new astToFiniteField$1$1(), f$2 = function(t4) {
20235
+ }, evaluation_exports$1 = __exportAll$1({ evaluate: () => evaluate$2, evaluate_to_constant: () => evaluate_to_constant$1, f: () => f$2, finite_field_evaluate: () => finite_field_evaluate$1 }), astToMathjs$1$1 = new astToMathjs$2$1({ mathjs: mathjs_default$1 }), astToFiniteField$2 = new astToFiniteField$1$1(), f$2 = function(t4) {
20236
20236
  var n2 = get_tree$1(t4), r2 = factorial_to_gamma_function$1(astToMathjs$1$1.convert(log_subscript_to_two_arg_log$1(normalize_function_names$1(normalize_applied_functions$1(n2)))));
20237
20237
  return r2.evaluate.bind(r2);
20238
- }, evaluate$1 = function(t4, n2) {
20238
+ }, evaluate$2 = function(t4, n2) {
20239
20239
  return f$2(t4)(n2);
20240
20240
  }, finite_field_evaluate$1 = function(t4, n2, r2) {
20241
20241
  return astToFiniteField$2.convert(t4.tree, n2, r2);
@@ -25618,7 +25618,7 @@ function requireCssesc$1() {
25618
25618
  return cssesc_1$1;
25619
25619
  }
25620
25620
  requireCssesc$1();
25621
- const viewerIframeJsSource = '(function() {\n "use strict";\n async function waitForStandaloneBundle(timeoutMs) {\n if (typeof window.renderDoenetViewerToContainer === "function") {\n return true;\n }\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n if (typeof window.renderDoenetViewerToContainer === "function") {\n return true;\n }\n }\n return false;\n }\n ComlinkViewer.expose(\n { renderViewerWithFunctionProps },\n ComlinkViewer.windowEndpoint(globalThis.parent)\n );\n function renderViewerWithFunctionProps(...args) {\n const augmentedDoenetViewerProps = { ...doenetViewerProps };\n augmentedDoenetViewerProps.externalVirtualKeyboardProvided = true;\n for (const propName of doenetViewerPropsSpecified) {\n if (!(propName in doenetViewerProps)) {\n const idx = args.indexOf(propName);\n if (idx !== -1) {\n augmentedDoenetViewerProps[propName] = args[idx + 1];\n }\n }\n }\n if (!doenetViewerPropsSpecified.includes("requestScrollTo")) {\n augmentedDoenetViewerProps.requestScrollTo = (offset) => {\n messageParentFromViewer({ type: "scrollTo", offset });\n };\n }\n window.renderDoenetViewerToContainer(\n document.getElementById("root"),\n void 0,\n augmentedDoenetViewerProps\n );\n }\n function installSharedCorePortProvider() {\n let coreCounter = 0;\n window.doenetGlobalConfig.createExternalCoreWorkerPort = () => {\n const coreId = `${viewerId}-core-${++coreCounter}`;\n const channel = new MessageChannel();\n window.parent.postMessage(\n { origin: viewerId, data: { type: "createSharedCore", coreId } },\n window.parent.origin,\n [channel.port2]\n );\n return {\n port: channel.port1,\n destroy: (suspectWedge) => {\n messageParentFromViewer({\n type: "destroySharedCore",\n coreId,\n suspectWedge: Boolean(suspectWedge)\n });\n }\n };\n };\n }\n (async () => {\n if (await waitForStandaloneBundle(6e4)) {\n if (typeof doenetSharedCoreWorker !== "undefined" && doenetSharedCoreWorker) {\n installSharedCorePortProvider();\n }\n messageParentFromViewer({ iframeReady: true });\n } else {\n messageParentFromViewer({\n error: "Invalid DoenetML version or DoenetML package not found"\n });\n }\n })().catch((err) => {\n console.error(\n "iframe DoenetViewer: unexpected failure while signalling iframeReady",\n err\n );\n try {\n messageParentFromViewer({\n error: "iframe viewer failed to initialize"\n });\n } catch {\n }\n });\n function messageParentFromViewer(data) {\n window.parent.postMessage(\n {\n origin: viewerId,\n data\n },\n window.parent.origin\n );\n }\n})();\n';
25621
+ const viewerIframeJsSource = '(function() {\n "use strict";\n let lastAugmentedProps = null;\n let currentFunctionProps = {};\n const functionPropDispatchers = {};\n function getFunctionPropDispatcher(key) {\n let dispatcher = functionPropDispatchers[key];\n if (!dispatcher) {\n dispatcher = (...callArgs) => currentFunctionProps[key]?.(...callArgs);\n functionPropDispatchers[key] = dispatcher;\n }\n return dispatcher;\n }\n function functionPropArgsToMap(args) {\n const map = {};\n for (let i = 0; i < args.length; i += 2) {\n const key = args[i];\n const fn = args[i + 1];\n if (typeof key === "string" && typeof fn === "function") {\n map[key] = fn;\n }\n }\n return map;\n }\n function releaseFunctionProxy(fn) {\n try {\n fn?.[ComlinkViewer.releaseProxy]?.();\n } catch (e) {\n console.warn(\n "iframe DoenetViewer: failed to release stale Comlink proxy",\n e\n );\n }\n }\n function setCurrentFunctionProps(incoming) {\n for (const [key, fn] of Object.entries(currentFunctionProps)) {\n if (incoming[key] !== fn) {\n releaseFunctionProxy(fn);\n }\n }\n currentFunctionProps = incoming;\n }\n function defaultRequestScrollTo(offset) {\n messageParentFromViewer({ type: "scrollTo", offset });\n }\n function syncAugmentedFunctionProps() {\n if (!lastAugmentedProps) {\n return;\n }\n const next = {};\n for (const [key, val] of Object.entries(lastAugmentedProps)) {\n if (typeof val !== "function") {\n next[key] = val;\n }\n }\n for (const key of Object.keys(currentFunctionProps)) {\n next[key] = getFunctionPropDispatcher(key);\n }\n if (!("requestScrollTo" in next)) {\n next.requestScrollTo = defaultRequestScrollTo;\n }\n lastAugmentedProps = next;\n }\n let currentDoenetMLSource = null;\n function resolveDoenetMLSource(root) {\n if (currentDoenetMLSource !== null) {\n return currentDoenetMLSource;\n }\n const scriptTag = root.querySelector(\'script[type="text/doenetml"]\');\n currentDoenetMLSource = scriptTag?.innerHTML ?? "";\n return currentDoenetMLSource;\n }\n async function waitForStandaloneBundle(timeoutMs) {\n if (typeof window.renderDoenetViewerToContainer === "function") {\n return true;\n }\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n await new Promise((resolve) => setTimeout(resolve, 50));\n if (typeof window.renderDoenetViewerToContainer === "function") {\n return true;\n }\n }\n return false;\n }\n ComlinkViewer.expose(\n {\n renderViewerWithFunctionProps,\n updateViewerProps(updatedSerializableProps) {\n if (!lastAugmentedProps) {\n console.warn(\n "iframe DoenetViewer: updateViewerProps arrived before renderViewerWithFunctionProps completed — likely a bug in the iframe wrapper\'s queue/replay sequencing."\n );\n return;\n }\n const { doenetML, ...rest } = updatedSerializableProps;\n if (typeof doenetML === "string") {\n currentDoenetMLSource = doenetML;\n }\n lastAugmentedProps = {\n ...lastAugmentedProps,\n ...rest\n };\n renderWithLastAugmentedProps();\n },\n updateViewerFunctionProps(...args) {\n if (!lastAugmentedProps) {\n console.warn(\n "iframe DoenetViewer: updateViewerFunctionProps arrived before renderViewerWithFunctionProps completed — likely a bug in the iframe wrapper\'s queue/replay sequencing."\n );\n return;\n }\n const incoming = functionPropArgsToMap(args);\n const prevKeys = Object.keys(currentFunctionProps).sort();\n const nextKeys = Object.keys(incoming).sort();\n const keysChanged = prevKeys.length !== nextKeys.length || prevKeys.some((key, i) => key !== nextKeys[i]);\n setCurrentFunctionProps(incoming);\n if (keysChanged) {\n syncAugmentedFunctionProps();\n renderWithLastAugmentedProps();\n }\n }\n },\n ComlinkViewer.windowEndpoint(globalThis.parent)\n );\n function renderViewerWithFunctionProps(...args) {\n setCurrentFunctionProps(functionPropArgsToMap(args));\n const augmentedDoenetViewerProps = { ...doenetViewerProps };\n augmentedDoenetViewerProps.externalVirtualKeyboardProvided = true;\n for (const propName of doenetViewerPropsSpecified) {\n if (!(propName in doenetViewerProps) && propName in currentFunctionProps) {\n augmentedDoenetViewerProps[propName] = getFunctionPropDispatcher(propName);\n }\n }\n if (!doenetViewerPropsSpecified.includes("requestScrollTo")) {\n augmentedDoenetViewerProps.requestScrollTo = defaultRequestScrollTo;\n }\n lastAugmentedProps = augmentedDoenetViewerProps;\n renderWithLastAugmentedProps();\n }\n function renderWithLastAugmentedProps() {\n const root = document.getElementById("root");\n window.renderDoenetViewerToContainer(\n root,\n resolveDoenetMLSource(root),\n lastAugmentedProps\n );\n }\n function installSharedCorePortProvider() {\n let coreCounter = 0;\n window.doenetGlobalConfig.createExternalCoreWorkerPort = () => {\n const coreId = `${viewerId}-core-${++coreCounter}`;\n const channel = new MessageChannel();\n window.parent.postMessage(\n { origin: viewerId, data: { type: "createSharedCore", coreId } },\n window.parent.origin,\n [channel.port2]\n );\n return {\n port: channel.port1,\n destroy: (suspectWedge) => {\n messageParentFromViewer({\n type: "destroySharedCore",\n coreId,\n suspectWedge: Boolean(suspectWedge)\n });\n }\n };\n };\n }\n (async () => {\n if (await waitForStandaloneBundle(6e4)) {\n if (typeof doenetSharedCoreWorker !== "undefined" && doenetSharedCoreWorker) {\n installSharedCorePortProvider();\n }\n messageParentFromViewer({ iframeReady: true });\n } else {\n messageParentFromViewer({\n error: "Invalid DoenetML version or DoenetML package not found"\n });\n }\n })().catch((err) => {\n console.error(\n "iframe DoenetViewer: unexpected failure while signalling iframeReady",\n err\n );\n try {\n messageParentFromViewer({\n error: "iframe viewer failed to initialize"\n });\n } catch {\n }\n });\n function messageParentFromViewer(data) {\n window.parent.postMessage(\n {\n origin: viewerId,\n data\n },\n window.parent.origin\n );\n }\n})();\n';
25622
25622
  const editorIframeJsSource = `(function() {
25623
25623
  "use strict";
25624
25624
  let editorControlHandle = null;
@@ -26026,6 +26026,140 @@ function destroySharedCoresForViewer(viewerId) {
26026
26026
  }
26027
26027
  }
26028
26028
  }
26029
+ const DEFAULT_MAX_LIVE_VIEWERS = 3;
26030
+ const DEFAULT_VISIBLE_MARGIN = "1000px";
26031
+ const DEFAULT_FLUSH_TIMEOUT_MS = 5e3;
26032
+ const DEFAULT_PARK_DELAY_MS = 2e3;
26033
+ const records = /* @__PURE__ */ new Map();
26034
+ let visibleOrderCounter = 0;
26035
+ let effectiveMaxLive = null;
26036
+ let warnedMixedBudgets = false;
26037
+ let evaluateTimerId = null;
26038
+ let evaluateTimerAt = Infinity;
26039
+ function registerWindowedViewer({
26040
+ id: id2,
26041
+ maxLiveViewers,
26042
+ parkDelayMs,
26043
+ canPark,
26044
+ requestPark
26045
+ }) {
26046
+ if (effectiveMaxLive !== null && effectiveMaxLive !== maxLiveViewers && !warnedMixedBudgets) {
26047
+ warnedMixedBudgets = true;
26048
+ console.warn(
26049
+ `DoenetViewer mountPolicy: viewers on this page specify different maxLiveViewers (${effectiveMaxLive} and ${maxLiveViewers}); using the smaller value.`
26050
+ );
26051
+ }
26052
+ effectiveMaxLive = effectiveMaxLive === null ? maxLiveViewers : Math.min(effectiveMaxLive, maxLiveViewers);
26053
+ records.set(id2, {
26054
+ id: id2,
26055
+ state: "live",
26056
+ visible: false,
26057
+ lastVisibleOrder: 0,
26058
+ invisibleSince: Date.now(),
26059
+ parkDelayMs,
26060
+ canPark,
26061
+ requestPark
26062
+ });
26063
+ scheduleEvaluate(parkDelayMs);
26064
+ return () => {
26065
+ records.delete(id2);
26066
+ scheduleEvaluate(0);
26067
+ };
26068
+ }
26069
+ function setViewerVisibility(id2, visible) {
26070
+ const record = records.get(id2);
26071
+ if (!record || record.visible === visible) {
26072
+ return;
26073
+ }
26074
+ record.visible = visible;
26075
+ if (visible) {
26076
+ record.lastVisibleOrder = ++visibleOrderCounter;
26077
+ scheduleEvaluate(0);
26078
+ } else {
26079
+ record.invisibleSince = Date.now();
26080
+ scheduleEvaluate(record.parkDelayMs);
26081
+ }
26082
+ }
26083
+ function notifyViewerState(id2, state) {
26084
+ const record = records.get(id2);
26085
+ if (!record || record.state === state) {
26086
+ return;
26087
+ }
26088
+ record.state = state;
26089
+ scheduleEvaluate(0);
26090
+ }
26091
+ function getViewerLifecycleStats() {
26092
+ let live = 0, parking = 0, parked = 0;
26093
+ for (const record of records.values()) {
26094
+ if (record.state === "live") {
26095
+ live++;
26096
+ } else if (record.state === "parking") {
26097
+ parking++;
26098
+ } else {
26099
+ parked++;
26100
+ }
26101
+ }
26102
+ return { registered: records.size, live, parking, parked };
26103
+ }
26104
+ function scheduleEvaluate(delayMs) {
26105
+ const at = Date.now() + delayMs;
26106
+ if (evaluateTimerId !== null) {
26107
+ if (at >= evaluateTimerAt) {
26108
+ return;
26109
+ }
26110
+ clearTimeout(evaluateTimerId);
26111
+ }
26112
+ evaluateTimerAt = at;
26113
+ evaluateTimerId = setTimeout(() => {
26114
+ evaluateTimerId = null;
26115
+ evaluateTimerAt = Infinity;
26116
+ evaluate$1();
26117
+ }, delayMs);
26118
+ }
26119
+ function evaluate$1() {
26120
+ if (effectiveMaxLive === null) {
26121
+ return;
26122
+ }
26123
+ const now = Date.now();
26124
+ let live = 0;
26125
+ for (const record of records.values()) {
26126
+ if (record.state === "live") {
26127
+ live++;
26128
+ }
26129
+ }
26130
+ let excess = live - effectiveMaxLive;
26131
+ if (excess <= 0) {
26132
+ return;
26133
+ }
26134
+ const candidates = [];
26135
+ let nextDebounceExpiry = Infinity;
26136
+ for (const record of records.values()) {
26137
+ if (record.state !== "live" || record.visible) {
26138
+ continue;
26139
+ }
26140
+ const eligibleAt = record.invisibleSince + record.parkDelayMs;
26141
+ if (eligibleAt > now) {
26142
+ nextDebounceExpiry = Math.min(nextDebounceExpiry, eligibleAt);
26143
+ continue;
26144
+ }
26145
+ if (!record.canPark()) {
26146
+ continue;
26147
+ }
26148
+ candidates.push(record);
26149
+ }
26150
+ candidates.sort((a2, b2) => a2.lastVisibleOrder - b2.lastVisibleOrder);
26151
+ for (const record of candidates) {
26152
+ if (excess <= 0) {
26153
+ break;
26154
+ }
26155
+ record.state = "parking";
26156
+ excess--;
26157
+ record.requestPark();
26158
+ }
26159
+ if (excess > 0 && nextDebounceExpiry < Infinity) {
26160
+ scheduleEvaluate(Math.max(0, nextDebounceExpiry - now));
26161
+ }
26162
+ }
26029
26163
  function findNodesWithPositionInfo(nodes) {
26030
26164
  if (typeof nodes !== "object" || nodes === null) {
26031
26165
  return [];
@@ -34639,7 +34773,7 @@ for (const key of [
34639
34773
  ]) {
34640
34774
  key.isMath = true;
34641
34775
  }
34642
- const BackspaceIcon = /* @__PURE__ */ React__default__default.createElement(
34776
+ const BackspaceIcon = /* @__PURE__ */ React__default.createElement(
34643
34777
  "svg",
34644
34778
  {
34645
34779
  "aria-hidden": "true",
@@ -34651,7 +34785,7 @@ const BackspaceIcon = /* @__PURE__ */ React__default__default.createElement(
34651
34785
  xmlns: "http://www.w3.org/2000/svg",
34652
34786
  viewBox: "0 0 576 512"
34653
34787
  },
34654
- /* @__PURE__ */ React__default__default.createElement(
34788
+ /* @__PURE__ */ React__default.createElement(
34655
34789
  "path",
34656
34790
  {
34657
34791
  fill: "currentColor",
@@ -34665,19 +34799,19 @@ function Keyboard({
34665
34799
  }) {
34666
34800
  switch (style) {
34667
34801
  case "alpha_lower":
34668
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard alpha" }, /* @__PURE__ */ React__default__default.createElement(Qwerty, { type: "lower", onClick }));
34802
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard alpha" }, /* @__PURE__ */ React__default.createElement(Qwerty, { type: "lower", onClick }));
34669
34803
  case "alpha_upper":
34670
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard alpha" }, /* @__PURE__ */ React__default__default.createElement(Qwerty, { type: "upper", onClick }));
34804
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard alpha" }, /* @__PURE__ */ React__default.createElement(Qwerty, { type: "upper", onClick }));
34671
34805
  case "numeric":
34672
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard numeric" }, /* @__PURE__ */ React__default__default.createElement(Numeric, { onClick }));
34806
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard numeric" }, /* @__PURE__ */ React__default.createElement(Numeric, { onClick }));
34673
34807
  case "greek_lower":
34674
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard greek" }, /* @__PURE__ */ React__default__default.createElement(Greek, { type: "lower", onClick }));
34808
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard greek" }, /* @__PURE__ */ React__default.createElement(Greek, { type: "lower", onClick }));
34675
34809
  case "greek_upper":
34676
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard greek" }, /* @__PURE__ */ React__default__default.createElement(Greek, { type: "upper", onClick }));
34810
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard greek" }, /* @__PURE__ */ React__default.createElement(Greek, { type: "upper", onClick }));
34677
34811
  case "symbol":
34678
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard symbol" }, /* @__PURE__ */ React__default__default.createElement(Symbol$1, { onClick }));
34812
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard symbol" }, /* @__PURE__ */ React__default.createElement(Symbol$1, { onClick }));
34679
34813
  case "function":
34680
- return /* @__PURE__ */ React__default__default.createElement("div", { className: "virtual-keyboard composite" }, /* @__PURE__ */ React__default__default.createElement(Composite, { onClick }));
34814
+ return /* @__PURE__ */ React__default.createElement("div", { className: "virtual-keyboard composite" }, /* @__PURE__ */ React__default.createElement(Composite, { onClick }));
34681
34815
  }
34682
34816
  }
34683
34817
  function Key({
@@ -34686,12 +34820,12 @@ function Key({
34686
34820
  }) {
34687
34821
  let content = keyInfo.displayName;
34688
34822
  if (keyInfo.isMath) {
34689
- content = /* @__PURE__ */ React__default__default.createElement("div", { style: { pointerEvents: "none" } }, /* @__PURE__ */ React__default__default.createElement(MathJax, null, "\\(" + content + "\\)"));
34823
+ content = /* @__PURE__ */ React__default.createElement("div", { style: { pointerEvents: "none" } }, /* @__PURE__ */ React__default.createElement(MathJax, null, "\\(" + content + "\\)"));
34690
34824
  }
34691
34825
  if (keyInfo.name === "backspace") {
34692
34826
  content = BackspaceIcon;
34693
34827
  }
34694
- return /* @__PURE__ */ React__default__default.createElement(
34828
+ return /* @__PURE__ */ React__default.createElement(
34695
34829
  "button",
34696
34830
  {
34697
34831
  className: `key key-${keyInfo.name} ${keyInfo.isMath ? "math" : ""}`,
@@ -34723,7 +34857,7 @@ function Qwerty({
34723
34857
  SPECIAL_KEYS.right,
34724
34858
  SPECIAL_KEYS.enter
34725
34859
  ];
34726
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name })))));
34860
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name })))));
34727
34861
  }
34728
34862
  function Numeric({ onClick }) {
34729
34863
  const row1 = [
@@ -34747,7 +34881,7 @@ function Numeric({ onClick }) {
34747
34881
  SPECIAL_KEYS.right,
34748
34882
  SPECIAL_KEYS.enter
34749
34883
  ];
34750
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-region" }, Object.values(VAR_KEYS).map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default__default.createElement("div", { className: "sub-keyboard" }, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default__default.createElement(
34884
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-region" }, Object.values(VAR_KEYS).map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default.createElement("div", { className: "sub-keyboard" }, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default.createElement(
34751
34885
  Key,
34752
34886
  {
34753
34887
  keyInfo: key,
@@ -34757,12 +34891,12 @@ function Numeric({ onClick }) {
34757
34891
  ))))));
34758
34892
  }
34759
34893
  function Symbol$1({ onClick }) {
34760
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-region" }, Object.values(SYMBOL_KEYS).map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-region" }, Object.values(OTHER_SYMBOLS).map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name })), [
34894
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-region" }, Object.values(SYMBOL_KEYS).map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-region" }, Object.values(OTHER_SYMBOLS).map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name })), [
34761
34895
  SPECIAL_KEYS.left,
34762
34896
  SPECIAL_KEYS.right,
34763
34897
  SPECIAL_KEYS.backspace,
34764
34898
  SPECIAL_KEYS.enter
34765
- ].map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))));
34899
+ ].map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))));
34766
34900
  }
34767
34901
  function Greek({
34768
34902
  type,
@@ -34783,15 +34917,15 @@ function Greek({
34783
34917
  SPECIAL_KEYS.right,
34784
34918
  SPECIAL_KEYS.enter
34785
34919
  ];
34786
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name })))));
34920
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, [row1, row2, row3, row4].map((row, i2) => /* @__PURE__ */ React__default.createElement("div", { key: i2, className: "row" }, row.map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name })))));
34787
34921
  }
34788
34922
  function Composite({ onClick }) {
34789
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-region" }, Object.values(TRIG_KEYS).map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-region" }, Object.values(FUNCTION_KEYS).map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name })), [
34923
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-region" }, Object.values(TRIG_KEYS).map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))), /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-region" }, Object.values(FUNCTION_KEYS).map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name })), [
34790
34924
  SPECIAL_KEYS.backspace,
34791
34925
  SPECIAL_KEYS.left,
34792
34926
  SPECIAL_KEYS.right,
34793
34927
  SPECIAL_KEYS.enter
34794
- ].map((key) => /* @__PURE__ */ React__default__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))));
34928
+ ].map((key) => /* @__PURE__ */ React__default.createElement(Key, { keyInfo: key, onClick, key: key.name }))));
34795
34929
  }
34796
34930
  const FocusableContext = createContext(true);
34797
34931
  function flatten2DArray(array) {
@@ -35235,7 +35369,7 @@ function mergeProps(base, overrides2) {
35235
35369
  }
35236
35370
  return props;
35237
35371
  }
35238
- const _React = { ...React__default };
35372
+ const _React = { ...React };
35239
35373
  const useReactId = _React.useId;
35240
35374
  const useReactInsertionEffect = _React.useInsertionEffect;
35241
35375
  const useSafeLayoutEffect = canUseDOM ? useLayoutEffect : useEffect;
@@ -35352,7 +35486,7 @@ function useMetadataProps(props, key, value) {
35352
35486
  return [parent?.[key], { onLoadedMetadataCapture }];
35353
35487
  }
35354
35488
  function forwardRef(render) {
35355
- const Role = React__default.forwardRef((props, ref) => render({
35489
+ const Role = React.forwardRef((props, ref) => render({
35356
35490
  ...props,
35357
35491
  ref
35358
35492
  }));
@@ -35360,18 +35494,18 @@ function forwardRef(render) {
35360
35494
  return Role;
35361
35495
  }
35362
35496
  function memo(Component, propsAreEqual) {
35363
- return React__default.memo(Component, propsAreEqual);
35497
+ return React.memo(Component, propsAreEqual);
35364
35498
  }
35365
35499
  function createElement(Type, props) {
35366
35500
  const { wrapElement, render, ...rest2 } = props;
35367
35501
  const mergedRef = useMergeRefs(props.ref, getRefProperty(render));
35368
35502
  let element;
35369
- if (React__default.isValidElement(render)) {
35503
+ if (React.isValidElement(render)) {
35370
35504
  const renderProps = {
35371
35505
  ...render.props,
35372
35506
  ref: mergedRef
35373
35507
  };
35374
- element = React__default.cloneElement(render, mergeProps(rest2, renderProps));
35508
+ element = React.cloneElement(render, mergeProps(rest2, renderProps));
35375
35509
  } else if (render) element = render(rest2);
35376
35510
  else element = /* @__PURE__ */ jsxRuntimeExports.jsx(Type, { ...rest2 });
35377
35511
  if (wrapElement) return wrapElement(element);
@@ -35385,17 +35519,17 @@ function createHook(useProps) {
35385
35519
  return useRole;
35386
35520
  }
35387
35521
  function createStoreContext(providers = [], scopedProviders = []) {
35388
- const context = React__default.createContext(void 0);
35389
- const scopedContext = React__default.createContext(void 0);
35390
- const useContext2 = () => React__default.useContext(context);
35522
+ const context = React.createContext(void 0);
35523
+ const scopedContext = React.createContext(void 0);
35524
+ const useContext2 = () => React.useContext(context);
35391
35525
  const useScopedContext = (onlyScoped = false) => {
35392
- const scoped = React__default.useContext(scopedContext);
35526
+ const scoped = React.useContext(scopedContext);
35393
35527
  const store = useContext2();
35394
35528
  if (onlyScoped) return scoped;
35395
35529
  return scoped || store;
35396
35530
  };
35397
35531
  const useProviderContext = () => {
35398
- const scoped = React__default.useContext(scopedContext);
35532
+ const scoped = React.useContext(scopedContext);
35399
35533
  const store = useContext2();
35400
35534
  if (scoped && scoped === store) return;
35401
35535
  return store;
@@ -36649,7 +36783,7 @@ var hasRequiredUseSyncExternalStoreShim_production;
36649
36783
  function requireUseSyncExternalStoreShim_production() {
36650
36784
  if (hasRequiredUseSyncExternalStoreShim_production) return useSyncExternalStoreShim_production;
36651
36785
  hasRequiredUseSyncExternalStoreShim_production = 1;
36652
- var React2 = React__default__default;
36786
+ var React2 = React__default;
36653
36787
  function is(x2, y2) {
36654
36788
  return x2 === y2 && (0 !== x2 || 1 / x2 === 1 / y2) || x2 !== x2 && y2 !== y2;
36655
36789
  }
@@ -36706,7 +36840,7 @@ var shimExports = requireShim();
36706
36840
  const noopSubscribe = () => () => {
36707
36841
  };
36708
36842
  function useStoreState(store, keyOrSelector = identity$1) {
36709
- const storeSubscribe = React__default.useCallback((callback) => {
36843
+ const storeSubscribe = React.useCallback((callback) => {
36710
36844
  if (!store) return noopSubscribe();
36711
36845
  return subscribe(store, null, callback);
36712
36846
  }, [store]);
@@ -36723,8 +36857,8 @@ function useStoreState(store, keyOrSelector = identity$1) {
36723
36857
  return shimExports.useSyncExternalStore(storeSubscribe, getSnapshot, getSnapshot);
36724
36858
  }
36725
36859
  function useStoreStateObject(store, object2) {
36726
- const objRef = React__default.useRef({});
36727
- const storeSubscribe = React__default.useCallback((callback) => {
36860
+ const objRef = React.useRef({});
36861
+ const storeSubscribe = React.useCallback((callback) => {
36728
36862
  if (!store) return noopSubscribe();
36729
36863
  return subscribe(store, null, callback);
36730
36864
  }, [store]);
@@ -36781,10 +36915,10 @@ function useStoreProps(store, props, key, setKey) {
36781
36915
  });
36782
36916
  }
36783
36917
  function useStore(createStore2, props) {
36784
- const [store, setStore] = React__default.useState(() => createStore2(props));
36918
+ const [store, setStore] = React.useState(() => createStore2(props));
36785
36919
  useSafeLayoutEffect(() => init(store), [store]);
36786
- const useState2 = React__default.useCallback((keyOrSelector) => useStoreState(store, keyOrSelector), [store]);
36787
- return [React__default.useMemo(() => ({
36920
+ const useState2 = React.useCallback((keyOrSelector) => useStoreState(store, keyOrSelector), [store]);
36921
+ return [React.useMemo(() => ({
36788
36922
  ...store,
36789
36923
  useState: useState2
36790
36924
  }), [store, useState2]), useEvent(() => {
@@ -37626,10 +37760,10 @@ function TabProvider(props = {}) {
37626
37760
  });
37627
37761
  }
37628
37762
  function ManagedKeyboard({ onClick }) {
37629
- const [style, setStyle] = React__default__default.useState("numeric");
37763
+ const [style, setStyle] = React__default.useState("numeric");
37630
37764
  const store = useTabStore();
37631
37765
  const storeState = store.useState();
37632
- React__default__default.useEffect(() => {
37766
+ React__default.useEffect(() => {
37633
37767
  if (!storeState.activeId) {
37634
37768
  return;
37635
37769
  }
@@ -37643,7 +37777,7 @@ function ManagedKeyboard({ onClick }) {
37643
37777
  setStyle(storeState.activeId);
37644
37778
  }
37645
37779
  }, [storeState, style]);
37646
- const wrappedOnClick = React__default__default.useCallback(
37780
+ const wrappedOnClick = React__default.useCallback(
37647
37781
  (e2) => {
37648
37782
  const firstPress = e2[0];
37649
37783
  if (!firstPress) {
@@ -37670,7 +37804,7 @@ function ManagedKeyboard({ onClick }) {
37670
37804
  },
37671
37805
  [style]
37672
37806
  );
37673
- return /* @__PURE__ */ React__default__default.createElement(TabProvider, null, /* @__PURE__ */ React__default__default.createElement(TabList, { className: "virtual-keyboard-tab-list" }, /* @__PURE__ */ React__default__default.createElement(Tab, { store, id: "numeric" }, "123"), /* @__PURE__ */ React__default__default.createElement(Tab, { store, id: "function" }, "f(x)"), /* @__PURE__ */ React__default__default.createElement(Tab, { store, id: "alpha_lower" }, "ABC"), /* @__PURE__ */ React__default__default.createElement(Tab, { store, id: "greek_lower" }, "αβγ"), /* @__PURE__ */ React__default__default.createElement(Tab, { store, id: "symbol" }, "$%∞")), /* @__PURE__ */ React__default__default.createElement(Keyboard, { style, onClick: wrappedOnClick }));
37807
+ return /* @__PURE__ */ React__default.createElement(TabProvider, null, /* @__PURE__ */ React__default.createElement(TabList, { className: "virtual-keyboard-tab-list" }, /* @__PURE__ */ React__default.createElement(Tab, { store, id: "numeric" }, "123"), /* @__PURE__ */ React__default.createElement(Tab, { store, id: "function" }, "f(x)"), /* @__PURE__ */ React__default.createElement(Tab, { store, id: "alpha_lower" }, "ABC"), /* @__PURE__ */ React__default.createElement(Tab, { store, id: "greek_lower" }, "αβγ"), /* @__PURE__ */ React__default.createElement(Tab, { store, id: "symbol" }, "$%∞")), /* @__PURE__ */ React__default.createElement(Keyboard, { style, onClick: wrappedOnClick }));
37674
37808
  }
37675
37809
  var classnames = { exports: {} };
37676
37810
  var hasRequiredClassnames;
@@ -37732,7 +37866,7 @@ function requireClassnames() {
37732
37866
  }
37733
37867
  var classnamesExports = requireClassnames();
37734
37868
  const classNames = /* @__PURE__ */ getDefaultExportFromCjs$1(classnamesExports);
37735
- const KeyboardIcon = () => /* @__PURE__ */ React__default__default.createElement(
37869
+ const KeyboardIcon = () => /* @__PURE__ */ React__default.createElement(
37736
37870
  "svg",
37737
37871
  {
37738
37872
  stroke: "currentColor",
@@ -37745,15 +37879,15 @@ const KeyboardIcon = () => /* @__PURE__ */ React__default__default.createElement
37745
37879
  width: "1em",
37746
37880
  xmlns: "http://www.w3.org/2000/svg"
37747
37881
  },
37748
- /* @__PURE__ */ React__default__default.createElement("path", { d: "M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z" })
37882
+ /* @__PURE__ */ React__default.createElement("path", { d: "M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z" })
37749
37883
  );
37750
37884
  function KeyboardTray({
37751
37885
  onClick,
37752
37886
  theme
37753
37887
  }) {
37754
- const [open, setOpen] = React__default__default.useState(false);
37888
+ const [open, setOpen] = React__default.useState(false);
37755
37889
  return createPortal(
37756
- /* @__PURE__ */ React__default__default.createElement(
37890
+ /* @__PURE__ */ React__default.createElement(
37757
37891
  "div",
37758
37892
  {
37759
37893
  id: "virtual-keyboard-tray",
@@ -37770,7 +37904,7 @@ function KeyboardTray({
37770
37904
  ]);
37771
37905
  }
37772
37906
  },
37773
- /* @__PURE__ */ React__default__default.createElement(
37907
+ /* @__PURE__ */ React__default.createElement(
37774
37908
  "button",
37775
37909
  {
37776
37910
  className: "open-keyboard-button",
@@ -37778,9 +37912,9 @@ function KeyboardTray({
37778
37912
  title: open ? "Close Keyboard" : "Open Keyboard",
37779
37913
  "aria-label": open ? "Close Keyboard" : "Open Keyboard"
37780
37914
  },
37781
- /* @__PURE__ */ React__default__default.createElement(KeyboardIcon, null)
37915
+ /* @__PURE__ */ React__default.createElement(KeyboardIcon, null)
37782
37916
  ),
37783
- /* @__PURE__ */ React__default__default.createElement("div", { className: "keyboard-container" }, /* @__PURE__ */ React__default__default.createElement(
37917
+ /* @__PURE__ */ React__default.createElement("div", { className: "keyboard-container" }, /* @__PURE__ */ React__default.createElement(
37784
37918
  "button",
37785
37919
  {
37786
37920
  className: "close-keyboard-button",
@@ -37789,7 +37923,7 @@ function KeyboardTray({
37789
37923
  "aria-label": "Close Keyboard"
37790
37924
  },
37791
37925
  "×"
37792
- ), /* @__PURE__ */ React__default__default.createElement(ManagedKeyboard, { onClick }))
37926
+ ), /* @__PURE__ */ React__default.createElement(ManagedKeyboard, { onClick }))
37793
37927
  ),
37794
37928
  document.body
37795
37929
  );
@@ -37905,7 +38039,7 @@ function MathJaxContext({
37905
38039
  });
37906
38040
  return { version: version2, promise };
37907
38041
  }, [config2, src, useExistingMathJax, timeoutMs, version2]);
37908
- return /* @__PURE__ */ React__default__default.createElement(MathJaxBaseContext.Provider, { value }, children);
38042
+ return /* @__PURE__ */ React__default.createElement(MathJaxBaseContext.Provider, { value }, children);
37909
38043
  }
37910
38044
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
37911
38045
  function getDefaultExportFromCjs(x2) {
@@ -63053,7 +63187,7 @@ function rerenderTray() {
63053
63187
  virtualKeyboardState.keyboardReactRoot?.render(renderTray(theme));
63054
63188
  }
63055
63189
  function renderTray(theme) {
63056
- return /* @__PURE__ */ React__default__default.createElement(MathJaxContext, { config: mathjaxConfig, version: 4 }, /* @__PURE__ */ React__default__default.createElement(
63190
+ return /* @__PURE__ */ React__default.createElement(MathJaxContext, { config: mathjaxConfig, version: 4 }, /* @__PURE__ */ React__default.createElement(
63057
63191
  KeyboardTray,
63058
63192
  {
63059
63193
  theme,
@@ -63068,12 +63202,12 @@ function UniqueKeyboardTray({
63068
63202
  theme,
63069
63203
  ownerRef
63070
63204
  }) {
63071
- const [id2] = React__default__default.useState(() => {
63205
+ const [id2] = React__default.useState(() => {
63072
63206
  const next = virtualKeyboardState.nextRegistrationId;
63073
63207
  virtualKeyboardState.nextRegistrationId += 1;
63074
63208
  return next;
63075
63209
  });
63076
- React__default__default.useEffect(() => {
63210
+ React__default.useEffect(() => {
63077
63211
  if (virtualKeyboardState.count === 0) {
63078
63212
  const keyboardDomNode = document.createElement("footer");
63079
63213
  keyboardDomNode.id = "virtual-keyboard-dummy";
@@ -63132,7 +63266,7 @@ function UniqueKeyboardTray({
63132
63266
  }
63133
63267
  };
63134
63268
  }, []);
63135
- React__default__default.useEffect(() => {
63269
+ React__default.useEffect(() => {
63136
63270
  const registration = getRegistrationById(id2);
63137
63271
  if (registration) {
63138
63272
  registration.onClick = onClick;
@@ -63147,7 +63281,7 @@ function ExternalVirtualKeyboard({
63147
63281
  theme,
63148
63282
  ownerRef
63149
63283
  }) {
63150
- return /* @__PURE__ */ React__default__default.createElement(
63284
+ return /* @__PURE__ */ React__default.createElement(
63151
63285
  UniqueKeyboardTray,
63152
63286
  {
63153
63287
  ownerRef,
@@ -63172,7 +63306,7 @@ function ExternalVirtualKeyboard({
63172
63306
  }
63173
63307
  );
63174
63308
  }
63175
- const version = "0.7.20-dev.323";
63309
+ const version = "0.7.20-dev.326";
63176
63310
  const latestDoenetmlVersion = version;
63177
63311
  function subscribeToPinnedTheme() {
63178
63312
  return () => {
@@ -63180,13 +63314,32 @@ function subscribeToPinnedTheme() {
63180
63314
  }
63181
63315
  function useResolvedTheme(setting) {
63182
63316
  const subscribe2 = setting === "system" ? subscribeToSystemTheme : subscribeToPinnedTheme;
63183
- const systemTheme = React__default__default.useSyncExternalStore(
63317
+ const systemTheme = React__default.useSyncExternalStore(
63184
63318
  subscribe2,
63185
63319
  getSystemTheme,
63186
63320
  () => "light"
63187
63321
  );
63188
63322
  return setting === "system" ? systemTheme : setting;
63189
63323
  }
63324
+ const LIVE_UPDATE_MIN_VERSION = [0, 7, 18];
63325
+ function versionSupportsLiveUpdates(version2) {
63326
+ const match2 = version2.replace(/^v/, "").match(/^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
63327
+ if (!match2) {
63328
+ return true;
63329
+ }
63330
+ const parts = [match2[1], match2[2], match2[3]].map(
63331
+ (p2) => p2 === void 0 ? Infinity : parseInt(p2, 10)
63332
+ );
63333
+ for (let i2 = 0; i2 < 3; i2++) {
63334
+ if (parts[i2] > LIVE_UPDATE_MIN_VERSION[i2]) {
63335
+ return true;
63336
+ }
63337
+ if (parts[i2] < LIVE_UPDATE_MIN_VERSION[i2]) {
63338
+ return false;
63339
+ }
63340
+ }
63341
+ return true;
63342
+ }
63190
63343
  function DoenetViewer({
63191
63344
  doenetML,
63192
63345
  standaloneUrl: specifiedStandaloneUrl,
@@ -63194,16 +63347,53 @@ function DoenetViewer({
63194
63347
  doenetmlVersion: specifiedDoenetmlVersion,
63195
63348
  autodetectVersion = true,
63196
63349
  useSharedCoreWorker = false,
63350
+ mountPolicy,
63197
63351
  ...doenetViewerProps
63198
63352
  }) {
63199
- const [id2, _2] = React__default__default.useState(() => Math.random().toString(36).slice(2));
63200
- const ref = React__default__default.useRef(null);
63201
- const [height, setHeight] = React__default__default.useState("500px");
63202
- const [inErrorState, setInErrorState] = React__default__default.useState(null);
63203
- const [ignoreDetectedVersion, setIgnoreDetectedVersion] = React__default__default.useState(false);
63353
+ const [id2, _2] = React__default.useState(() => Math.random().toString(36).slice(2));
63354
+ const ref = React__default.useRef(null);
63355
+ const viewerIframeRef = React__default.useRef(null);
63356
+ const pendingActions = React__default.useRef([]);
63357
+ const lastSentPropsSnapshotRef = React__default.useRef(null);
63358
+ const lastSentFunctionPropsRef = React__default.useRef(null);
63359
+ const doenetViewerPropsRef = React__default.useRef(doenetViewerProps);
63360
+ doenetViewerPropsRef.current = doenetViewerProps;
63361
+ const doenetMLRef = React__default.useRef(doenetML);
63362
+ doenetMLRef.current = doenetML;
63363
+ const windowed = mountPolicy?.mode === "windowed";
63364
+ const [parked, setParked] = React__default.useState(false);
63365
+ const [parkGeneration, setParkGeneration] = React__default.useState(0);
63366
+ const parkedRef = React__default.useRef(false);
63367
+ const parkingRef = React__default.useRef(false);
63368
+ const visibleRef = React__default.useRef(false);
63369
+ const containerRef = React__default.useRef(null);
63370
+ const parkFlushCounterRef = React__default.useRef(0);
63371
+ const parkFlushIdRef = React__default.useRef(null);
63372
+ const parkFlushCleanupRef = React__default.useRef(null);
63373
+ const lastCapturedReportRef = React__default.useRef(null);
63374
+ const parkedSnapshotRef = React__default.useRef(
63375
+ void 0
63376
+ );
63377
+ const everHadStateRef = React__default.useRef(false);
63378
+ const pinnedVariantIndexRef = React__default.useRef(null);
63379
+ if (windowed && pinnedVariantIndexRef.current === null) {
63380
+ pinnedVariantIndexRef.current = doenetViewerProps.requestedVariantIndex ?? Math.floor(Math.random() * 1e6) + 1;
63381
+ }
63382
+ const [height, setHeight] = React__default.useState("500px");
63383
+ const [inErrorState, setInErrorState] = React__default.useState(null);
63384
+ const [ignoreDetectedVersion, setIgnoreDetectedVersion] = React__default.useState(false);
63204
63385
  const resolvedTheme = useResolvedTheme(
63205
63386
  doenetViewerProps.darkMode ?? "system"
63206
63387
  );
63388
+ function syncIframeBodyBackground() {
63389
+ const body = ref.current?.contentDocument?.body;
63390
+ if (body) {
63391
+ setIframeBodyBackground(
63392
+ body,
63393
+ doenetViewerPropsRef.current.darkMode
63394
+ );
63395
+ }
63396
+ }
63207
63397
  let standaloneUrl, cssUrl;
63208
63398
  let foundAutoVersion = false;
63209
63399
  let detectedVersion;
@@ -63226,22 +63416,80 @@ function DoenetViewer({
63226
63416
  } else {
63227
63417
  cssUrl = `https://cdn.jsdelivr.net/npm/@doenet/standalone@${selectedDoenetmlVersion}/style.css`;
63228
63418
  }
63229
- const standaloneUrlRef = React__default__default.useRef(standaloneUrl);
63419
+ const usingCustomStandaloneUrl = Boolean(
63420
+ specifiedStandaloneUrl && !foundAutoVersion
63421
+ );
63422
+ const liveUpdatesSupported = usingCustomStandaloneUrl || versionSupportsLiveUpdates(selectedDoenetmlVersion);
63423
+ const standaloneUrlRef = React__default.useRef(standaloneUrl);
63230
63424
  standaloneUrlRef.current = standaloneUrl;
63231
- React__default__default.useEffect(() => {
63232
- if (!useSharedCoreWorker) {
63233
- return;
63425
+ const propsSnapshotStr = serializePropsSnapshot(
63426
+ { doenetML },
63427
+ doenetViewerProps
63428
+ );
63429
+ const legacyReloadKey = liveUpdatesSupported ? "" : propsSnapshotStr;
63430
+ const srcDoc = React__default.useMemo(() => {
63431
+ let bakedProps = doenetViewerPropsRef.current;
63432
+ if (windowed) {
63433
+ bakedProps = { ...bakedProps };
63434
+ if (bakedProps.requestedVariantIndex === void 0) {
63435
+ bakedProps.requestedVariantIndex = pinnedVariantIndexRef.current;
63436
+ }
63437
+ if (parkedSnapshotRef.current !== void 0) {
63438
+ bakedProps.initialState = parkedSnapshotRef.current;
63439
+ bakedProps.flags = {
63440
+ ...bakedProps.flags ?? {},
63441
+ allowLoadState: true
63442
+ };
63443
+ }
63234
63444
  }
63445
+ return createHtmlForDoenetViewer(
63446
+ id2,
63447
+ doenetMLRef.current,
63448
+ bakedProps,
63449
+ standaloneUrl,
63450
+ cssUrl,
63451
+ useSharedCoreWorker
63452
+ );
63453
+ }, [
63454
+ id2,
63455
+ standaloneUrl,
63456
+ cssUrl,
63457
+ useSharedCoreWorker,
63458
+ legacyReloadKey,
63459
+ parkGeneration
63460
+ ]);
63461
+ React__default.useEffect(() => {
63235
63462
  return () => {
63236
63463
  destroySharedCoresForViewer(id2);
63237
63464
  };
63238
63465
  }, []);
63239
- React__default__default.useEffect(() => {
63466
+ React__default.useLayoutEffect(() => {
63467
+ viewerIframeRef.current = null;
63468
+ destroySharedCoresForViewer(id2);
63469
+ lastSentPropsSnapshotRef.current = serializePropsSnapshot(
63470
+ { doenetML: doenetMLRef.current },
63471
+ doenetViewerPropsRef.current
63472
+ );
63473
+ lastSentFunctionPropsRef.current = null;
63474
+ }, [srcDoc]);
63475
+ React__default.useEffect(() => {
63240
63476
  const listener = (event) => {
63241
63477
  if (event.origin !== window.location.origin) {
63242
63478
  return;
63243
63479
  }
63244
- if (event.data.subject === "SPLICE.getState.response" || event.data.subject === "SPLICE.requestSolutionView.response" || event.data.subject == "SPLICE.submitAllAnswers") {
63480
+ if (windowed && parkedRef.current && event.data.subject === "SPLICE.flushState") {
63481
+ const currentProps = doenetViewerPropsRef.current;
63482
+ window.postMessage({
63483
+ subject: "SPLICE.flushState.response",
63484
+ activity_id: currentProps.activityId ?? "a",
63485
+ doc_id: currentProps.docId ?? "1",
63486
+ message_id: event.data.message_id,
63487
+ success: true,
63488
+ hadState: everHadStateRef.current
63489
+ });
63490
+ return;
63491
+ }
63492
+ if (event.data.subject === "SPLICE.getState.response" || event.data.subject === "SPLICE.requestSolutionView.response" || event.data.subject == "SPLICE.submitAllAnswers" || event.data.subject === "SPLICE.flushState") {
63245
63493
  ref.current?.contentWindow?.postMessage(event.data);
63246
63494
  return;
63247
63495
  }
@@ -63253,6 +63501,16 @@ function DoenetViewer({
63253
63501
  setHeight(event.data.height + "px");
63254
63502
  }
63255
63503
  }
63504
+ if (windowed) {
63505
+ if (event.data.subject === "SPLICE.reportScoreAndState") {
63506
+ lastCapturedReportRef.current = event.data;
63507
+ return;
63508
+ }
63509
+ if (event.data.subject === "SPLICE.flushState.response" && event.data.message_id === parkFlushIdRef.current) {
63510
+ completeParkFlush(event.data);
63511
+ return;
63512
+ }
63513
+ }
63256
63514
  if (event.data?.origin !== id2) {
63257
63515
  return;
63258
63516
  }
@@ -63288,18 +63546,29 @@ function DoenetViewer({
63288
63546
  const viewerIframe = wrap$3(
63289
63547
  windowEndpoint(ref.current.contentWindow)
63290
63548
  );
63549
+ const latestProps = doenetViewerPropsRef.current;
63291
63550
  const proxiedFunctions = [];
63292
- for (const [key, prop] of Object.entries(
63293
- doenetViewerProps
63294
- )) {
63551
+ const registeredFunctions = {};
63552
+ for (const [key, prop] of Object.entries(latestProps)) {
63295
63553
  if (typeof prop === "function") {
63554
+ registeredFunctions[key] = prop;
63296
63555
  proxiedFunctions.push(key);
63297
63556
  proxiedFunctions.push(proxy(prop));
63298
63557
  }
63299
63558
  }
63300
- viewerIframe?.renderViewerWithFunctionProps(
63301
- ...proxiedFunctions
63559
+ viewerIframe.renderViewerWithFunctionProps(...proxiedFunctions).catch(
63560
+ logComlinkError(
63561
+ "DoenetViewer",
63562
+ "renderViewerWithFunctionProps"
63563
+ )
63302
63564
  );
63565
+ lastSentFunctionPropsRef.current = registeredFunctions;
63566
+ viewerIframeRef.current = viewerIframe;
63567
+ const queued = pendingActions.current.splice(0);
63568
+ for (const action of queued) {
63569
+ action(viewerIframe);
63570
+ }
63571
+ syncIframeBodyBackground();
63303
63572
  }
63304
63573
  }
63305
63574
  };
@@ -63310,13 +63579,208 @@ function DoenetViewer({
63310
63579
  window.removeEventListener("message", listener);
63311
63580
  };
63312
63581
  }, []);
63582
+ React__default.useEffect(() => {
63583
+ if (!liveUpdatesSupported) {
63584
+ return;
63585
+ }
63586
+ if (lastSentPropsSnapshotRef.current === propsSnapshotStr) {
63587
+ return;
63588
+ }
63589
+ lastSentPropsSnapshotRef.current = propsSnapshotStr;
63590
+ const snapshot = JSON.parse(propsSnapshotStr);
63591
+ const action = (remote) => {
63592
+ remote.updateViewerProps(snapshot).catch(logComlinkError("DoenetViewer", "updateViewerProps"));
63593
+ };
63594
+ if (viewerIframeRef.current) {
63595
+ action(viewerIframeRef.current);
63596
+ } else {
63597
+ pendingActions.current.push(action);
63598
+ }
63599
+ }, [propsSnapshotStr, srcDoc, liveUpdatesSupported]);
63600
+ React__default.useEffect(() => {
63601
+ syncIframeBodyBackground();
63602
+ }, [doenetViewerProps.darkMode]);
63603
+ React__default.useEffect(() => {
63604
+ if (!liveUpdatesSupported) {
63605
+ return;
63606
+ }
63607
+ const prev = lastSentFunctionPropsRef.current;
63608
+ if (prev === null) {
63609
+ return;
63610
+ }
63611
+ const current = {};
63612
+ for (const [key, val] of Object.entries(doenetViewerPropsRef.current)) {
63613
+ if (typeof val === "function") {
63614
+ current[key] = val;
63615
+ }
63616
+ }
63617
+ const prevKeys = Object.keys(prev);
63618
+ const currKeys = Object.keys(current);
63619
+ let changed = prevKeys.length !== currKeys.length;
63620
+ if (!changed) {
63621
+ for (const k2 of currKeys) {
63622
+ if (prev[k2] !== current[k2]) {
63623
+ changed = true;
63624
+ break;
63625
+ }
63626
+ }
63627
+ }
63628
+ if (!changed) {
63629
+ return;
63630
+ }
63631
+ lastSentFunctionPropsRef.current = current;
63632
+ const proxiedFunctions = [];
63633
+ for (const [key, val] of Object.entries(current)) {
63634
+ proxiedFunctions.push(key);
63635
+ proxiedFunctions.push(proxy(val));
63636
+ }
63637
+ const action = (remote) => {
63638
+ remote.updateViewerFunctionProps(...proxiedFunctions).catch(
63639
+ logComlinkError(
63640
+ "DoenetViewer",
63641
+ "updateViewerFunctionProps"
63642
+ )
63643
+ );
63644
+ };
63645
+ if (viewerIframeRef.current) {
63646
+ action(viewerIframeRef.current);
63647
+ } else {
63648
+ pendingActions.current.push(action);
63649
+ }
63650
+ });
63651
+ function hasPersistencePath() {
63652
+ const flags = doenetViewerPropsRef.current.flags;
63653
+ return Boolean(flags?.allowSaveState || flags?.allowLocalState);
63654
+ }
63655
+ function canPark() {
63656
+ return hasPersistencePath() && Boolean(ref.current?.contentWindow);
63657
+ }
63658
+ function beginPark() {
63659
+ if (parkedRef.current || parkingRef.current) {
63660
+ return;
63661
+ }
63662
+ if (!ref.current?.contentWindow) {
63663
+ notifyViewerState(id2, "live");
63664
+ return;
63665
+ }
63666
+ parkingRef.current = true;
63667
+ const flushId = `__doenetParkFlush-${id2}-${++parkFlushCounterRef.current}`;
63668
+ parkFlushIdRef.current = flushId;
63669
+ const post = () => {
63670
+ ref.current?.contentWindow?.postMessage({
63671
+ subject: "SPLICE.flushState",
63672
+ message_id: flushId
63673
+ });
63674
+ };
63675
+ const retryTimer = setInterval(post, 500);
63676
+ const timeoutTimer = setTimeout(() => {
63677
+ onParkFlushTimeout();
63678
+ }, mountPolicy?.flushTimeoutMs ?? DEFAULT_FLUSH_TIMEOUT_MS);
63679
+ parkFlushCleanupRef.current = () => {
63680
+ clearInterval(retryTimer);
63681
+ clearTimeout(timeoutTimer);
63682
+ parkFlushCleanupRef.current = null;
63683
+ };
63684
+ post();
63685
+ }
63686
+ function endParkFlush() {
63687
+ if (!parkingRef.current) {
63688
+ return false;
63689
+ }
63690
+ parkFlushCleanupRef.current?.();
63691
+ parkFlushIdRef.current = null;
63692
+ parkingRef.current = false;
63693
+ if (visibleRef.current) {
63694
+ notifyViewerState(id2, "live");
63695
+ return false;
63696
+ }
63697
+ return true;
63698
+ }
63699
+ function completeParkFlush(ack) {
63700
+ if (!endParkFlush()) {
63701
+ return;
63702
+ }
63703
+ if (ack.hadState) {
63704
+ everHadStateRef.current = true;
63705
+ if (lastCapturedReportRef.current?.state) {
63706
+ parkedSnapshotRef.current = lastCapturedReportRef.current.state;
63707
+ }
63708
+ }
63709
+ finishPark();
63710
+ }
63711
+ function onParkFlushTimeout() {
63712
+ if (!endParkFlush()) {
63713
+ return;
63714
+ }
63715
+ finishPark();
63716
+ }
63717
+ function finishPark() {
63718
+ viewerIframeRef.current = null;
63719
+ destroySharedCoresForViewer(id2);
63720
+ parkedRef.current = true;
63721
+ setParked(true);
63722
+ notifyViewerState(id2, "parked");
63723
+ }
63724
+ function unpark() {
63725
+ if (!parkedRef.current) {
63726
+ return;
63727
+ }
63728
+ parkedRef.current = false;
63729
+ setParked(false);
63730
+ setParkGeneration((generation) => generation + 1);
63731
+ notifyViewerState(id2, "live");
63732
+ }
63733
+ React__default.useEffect(() => {
63734
+ if (!windowed || !containerRef.current) {
63735
+ return;
63736
+ }
63737
+ const observer = new IntersectionObserver(
63738
+ (entries) => {
63739
+ for (const entry of entries) {
63740
+ visibleRef.current = entry.isIntersecting;
63741
+ setViewerVisibility(id2, entry.isIntersecting);
63742
+ if (entry.isIntersecting && parkedRef.current) {
63743
+ unpark();
63744
+ }
63745
+ }
63746
+ },
63747
+ {
63748
+ rootMargin: mountPolicy?.visibleMargin ?? DEFAULT_VISIBLE_MARGIN
63749
+ }
63750
+ );
63751
+ observer.observe(containerRef.current);
63752
+ return () => {
63753
+ observer.disconnect();
63754
+ };
63755
+ }, [windowed]);
63756
+ React__default.useEffect(() => {
63757
+ if (!windowed) {
63758
+ return;
63759
+ }
63760
+ if (!hasPersistencePath()) {
63761
+ console.warn(
63762
+ "DoenetViewer mountPolicy: windowed mounting is enabled but neither flags.allowSaveState nor flags.allowLocalState is set, so parking would lose student work. This viewer will always stay live."
63763
+ );
63764
+ }
63765
+ const unregister = registerWindowedViewer({
63766
+ id: id2,
63767
+ maxLiveViewers: mountPolicy?.maxLiveViewers ?? DEFAULT_MAX_LIVE_VIEWERS,
63768
+ parkDelayMs: mountPolicy?.parkDelayMs ?? DEFAULT_PARK_DELAY_MS,
63769
+ canPark,
63770
+ requestPark: beginPark
63771
+ });
63772
+ return () => {
63773
+ parkFlushCleanupRef.current?.();
63774
+ unregister();
63775
+ };
63776
+ }, [windowed]);
63313
63777
  if (inErrorState) {
63314
63778
  if (foundAutoVersion) {
63315
63779
  setIgnoreDetectedVersion(true);
63316
63780
  setInErrorState("");
63317
63781
  return null;
63318
63782
  }
63319
- let errorIcon = /* @__PURE__ */ React__default__default.createElement(
63783
+ let errorIcon = /* @__PURE__ */ React__default.createElement(
63320
63784
  MdError,
63321
63785
  {
63322
63786
  fontSize: "24pt",
@@ -63324,7 +63788,7 @@ function DoenetViewer({
63324
63788
  style: { verticalAlign: "middle" }
63325
63789
  }
63326
63790
  );
63327
- return /* @__PURE__ */ React__default__default.createElement(
63791
+ return /* @__PURE__ */ React__default.createElement(
63328
63792
  "div",
63329
63793
  {
63330
63794
  style: {
@@ -63344,19 +63808,28 @@ function DoenetViewer({
63344
63808
  inErrorState
63345
63809
  );
63346
63810
  }
63347
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, addVirtualKeyboard ? /* @__PURE__ */ React__default__default.createElement(ExternalVirtualKeyboard, { ownerRef: ref, theme: resolvedTheme }) : null, /* @__PURE__ */ React__default__default.createElement(
63811
+ const viewerContent = parked ? (
63812
+ // Fixed-height placeholder holding a parked viewer's place in the
63813
+ // layout (the last height the iframe reported survives in state, so
63814
+ // parking does not shift the page).
63815
+ /* @__PURE__ */ React__default.createElement(
63816
+ "div",
63817
+ {
63818
+ "data-doenet-parked-viewer": "true",
63819
+ style: {
63820
+ width: "100%",
63821
+ boxSizing: "border-box",
63822
+ height,
63823
+ minHeight: 50
63824
+ }
63825
+ }
63826
+ )
63827
+ ) : /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, addVirtualKeyboard ? /* @__PURE__ */ React__default.createElement(ExternalVirtualKeyboard, { ownerRef: ref, theme: resolvedTheme }) : null, /* @__PURE__ */ React__default.createElement(
63348
63828
  "iframe",
63349
63829
  {
63350
63830
  title: "Doenet document",
63351
63831
  ref,
63352
- srcDoc: createHtmlForDoenetViewer(
63353
- id2,
63354
- doenetML,
63355
- doenetViewerProps,
63356
- standaloneUrl,
63357
- cssUrl,
63358
- useSharedCoreWorker
63359
- ),
63832
+ srcDoc,
63360
63833
  style: {
63361
63834
  width: "100%",
63362
63835
  boxSizing: "border-box",
@@ -63367,13 +63840,26 @@ function DoenetViewer({
63367
63840
  height
63368
63841
  }
63369
63842
  ));
63843
+ if (!windowed) {
63844
+ return viewerContent;
63845
+ }
63846
+ return /* @__PURE__ */ React__default.createElement("div", { ref: containerRef, style: { width: "100%" } }, viewerContent);
63847
+ }
63848
+ function serializePropsSnapshot(seed, props) {
63849
+ const snapshot = { ...seed };
63850
+ for (const [key, val] of Object.entries(props)) {
63851
+ if (typeof val !== "function") {
63852
+ snapshot[key] = val;
63853
+ }
63854
+ }
63855
+ return JSON.stringify(snapshot);
63370
63856
  }
63371
- function logComlinkError(method) {
63857
+ function logComlinkError(component, method) {
63372
63858
  return (err) => {
63373
- console.warn(`iframe DoenetEditor: ${method} failed`, err);
63859
+ console.warn(`iframe ${component}: ${method} failed`, err);
63374
63860
  };
63375
63861
  }
63376
- const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63862
+ const DoenetEditor = React__default.forwardRef(function DoenetEditor2({
63377
63863
  doenetML,
63378
63864
  standaloneUrl: specifiedStandaloneUrl,
63379
63865
  cssUrl: specifiedCssUrl,
@@ -63383,17 +63869,17 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63383
63869
  autodetectVersion = true,
63384
63870
  ...doenetEditorProps
63385
63871
  }, forwardedRef) {
63386
- const [id2, _2] = React__default__default.useState(() => Math.random().toString(36).slice(2));
63387
- const ref = React__default__default.useRef(null);
63388
- const editorIframeRef = React__default__default.useRef(null);
63389
- const pendingActions = React__default__default.useRef([]);
63390
- const lastSentPropsSnapshotRef = React__default__default.useRef(null);
63391
- const lastSentFunctionPropsRef = React__default__default.useRef(null);
63392
- const doenetEditorPropsRef = React__default__default.useRef(doenetEditorProps);
63872
+ const [id2, _2] = React__default.useState(() => Math.random().toString(36).slice(2));
63873
+ const ref = React__default.useRef(null);
63874
+ const editorIframeRef = React__default.useRef(null);
63875
+ const pendingActions = React__default.useRef([]);
63876
+ const lastSentPropsSnapshotRef = React__default.useRef(null);
63877
+ const lastSentFunctionPropsRef = React__default.useRef(null);
63878
+ const doenetEditorPropsRef = React__default.useRef(doenetEditorProps);
63393
63879
  doenetEditorPropsRef.current = doenetEditorProps;
63394
- const [inErrorState, setInErrorState] = React__default__default.useState(null);
63395
- const [ignoreDetectedVersion, setIgnoreDetectedVersion] = React__default__default.useState(false);
63396
- const [initialDiagnostics, setInitialDiagnostics] = React__default__default.useState([]);
63880
+ const [inErrorState, setInErrorState] = React__default.useState(null);
63881
+ const [ignoreDetectedVersion, setIgnoreDetectedVersion] = React__default.useState(false);
63882
+ const [initialDiagnostics, setInitialDiagnostics] = React__default.useState([]);
63397
63883
  const resolvedTheme = useResolvedTheme(
63398
63884
  doenetEditorProps.darkMode ?? "system"
63399
63885
  );
@@ -63406,12 +63892,17 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63406
63892
  );
63407
63893
  }
63408
63894
  }
63409
- React__default__default.useImperativeHandle(
63895
+ React__default.useImperativeHandle(
63410
63896
  forwardedRef,
63411
63897
  () => ({
63412
63898
  openDiagnosticsTab(tabId) {
63413
63899
  const action = (remote) => {
63414
- remote.openDiagnosticsTab(tabId).catch(logComlinkError("openDiagnosticsTab"));
63900
+ remote.openDiagnosticsTab(tabId).catch(
63901
+ logComlinkError(
63902
+ "DoenetEditor",
63903
+ "openDiagnosticsTab"
63904
+ )
63905
+ );
63415
63906
  };
63416
63907
  if (editorIframeRef.current) {
63417
63908
  action(editorIframeRef.current);
@@ -63421,7 +63912,12 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63421
63912
  },
63422
63913
  closeDiagnosticsPanel() {
63423
63914
  const action = (remote) => {
63424
- remote.closeDiagnosticsPanel().catch(logComlinkError("closeDiagnosticsPanel"));
63915
+ remote.closeDiagnosticsPanel().catch(
63916
+ logComlinkError(
63917
+ "DoenetEditor",
63918
+ "closeDiagnosticsPanel"
63919
+ )
63920
+ );
63425
63921
  };
63426
63922
  if (editorIframeRef.current) {
63427
63923
  action(editorIframeRef.current);
@@ -63431,7 +63927,12 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63431
63927
  },
63432
63928
  updateRenderedView() {
63433
63929
  const action = (remote) => {
63434
- remote.updateRenderedView().catch(logComlinkError("updateRenderedView"));
63930
+ remote.updateRenderedView().catch(
63931
+ logComlinkError(
63932
+ "DoenetEditor",
63933
+ "updateRenderedView"
63934
+ )
63935
+ );
63435
63936
  };
63436
63937
  if (editorIframeRef.current) {
63437
63938
  action(editorIframeRef.current);
@@ -63442,7 +63943,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63442
63943
  }),
63443
63944
  []
63444
63945
  );
63445
- const initialIframePropsRef = React__default__default.useRef(null);
63946
+ const initialIframePropsRef = React__default.useRef(null);
63446
63947
  if (initialIframePropsRef.current === null) {
63447
63948
  initialIframePropsRef.current = {
63448
63949
  doenetML,
@@ -63473,7 +63974,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63473
63974
  } else {
63474
63975
  cssUrl = `https://cdn.jsdelivr.net/npm/@doenet/standalone@${selectedDoenetmlVersion}/style.css`;
63475
63976
  }
63476
- React__default__default.useEffect(() => {
63977
+ React__default.useEffect(() => {
63477
63978
  const listener = (event) => {
63478
63979
  if (event.origin !== window.location.origin || event.data?.origin !== id2) {
63479
63980
  return;
@@ -63497,7 +63998,10 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63497
63998
  }
63498
63999
  }
63499
64000
  editorIframe?.renderEditorWithFunctionProps(...proxiedFunctions).catch(
63500
- logComlinkError("renderEditorWithFunctionProps")
64001
+ logComlinkError(
64002
+ "DoenetEditor",
64003
+ "renderEditorWithFunctionProps"
64004
+ )
63501
64005
  );
63502
64006
  lastSentFunctionPropsRef.current = registeredFunctions;
63503
64007
  editorIframeRef.current = editorIframe;
@@ -63516,7 +64020,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63516
64020
  window.removeEventListener("message", listener);
63517
64021
  };
63518
64022
  }, []);
63519
- const srcDoc = React__default__default.useMemo(() => {
64023
+ const srcDoc = React__default.useMemo(() => {
63520
64024
  const baseProps = {
63521
64025
  ...initialIframePropsRef.current.doenetEditorProps
63522
64026
  };
@@ -63537,36 +64041,26 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63537
64041
  cssUrl
63538
64042
  );
63539
64043
  }, [id2, standaloneUrl, cssUrl, initialDiagnostics]);
63540
- const propsForUpdate = { width };
63541
- for (const [key, val] of Object.entries(doenetEditorProps)) {
63542
- if (typeof val !== "function") {
63543
- propsForUpdate[key] = val;
63544
- }
63545
- }
63546
- const propsSnapshotStr = JSON.stringify(propsForUpdate);
63547
- React__default__default.useLayoutEffect(() => {
64044
+ const propsSnapshotStr = serializePropsSnapshot(
64045
+ { width },
64046
+ doenetEditorProps
64047
+ );
64048
+ React__default.useLayoutEffect(() => {
63548
64049
  editorIframeRef.current = null;
63549
- const baselineProps = {
63550
- width: initialIframePropsRef.current.width
63551
- };
63552
- for (const [key, val] of Object.entries(
64050
+ lastSentPropsSnapshotRef.current = serializePropsSnapshot(
64051
+ { width: initialIframePropsRef.current.width },
63553
64052
  initialIframePropsRef.current.doenetEditorProps
63554
- )) {
63555
- if (typeof val !== "function") {
63556
- baselineProps[key] = val;
63557
- }
63558
- }
63559
- lastSentPropsSnapshotRef.current = JSON.stringify(baselineProps);
64053
+ );
63560
64054
  lastSentFunctionPropsRef.current = null;
63561
64055
  }, [srcDoc]);
63562
- React__default__default.useEffect(() => {
64056
+ React__default.useEffect(() => {
63563
64057
  if (lastSentPropsSnapshotRef.current === propsSnapshotStr) {
63564
64058
  return;
63565
64059
  }
63566
64060
  lastSentPropsSnapshotRef.current = propsSnapshotStr;
63567
64061
  const snapshot = JSON.parse(propsSnapshotStr);
63568
64062
  const action = (remote) => {
63569
- remote.updateEditorProps(snapshot).catch(logComlinkError("updateEditorProps"));
64063
+ remote.updateEditorProps(snapshot).catch(logComlinkError("DoenetEditor", "updateEditorProps"));
63570
64064
  };
63571
64065
  if (editorIframeRef.current) {
63572
64066
  action(editorIframeRef.current);
@@ -63574,10 +64068,10 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63574
64068
  pendingActions.current.push(action);
63575
64069
  }
63576
64070
  }, [propsSnapshotStr, srcDoc]);
63577
- React__default__default.useEffect(() => {
64071
+ React__default.useEffect(() => {
63578
64072
  syncIframeBodyBackground();
63579
64073
  }, [doenetEditorProps.darkMode]);
63580
- React__default__default.useEffect(() => {
64074
+ React__default.useEffect(() => {
63581
64075
  const prev = lastSentFunctionPropsRef.current;
63582
64076
  if (prev === null) {
63583
64077
  return;
@@ -63609,7 +64103,12 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63609
64103
  proxiedFunctions.push(proxy(val));
63610
64104
  }
63611
64105
  const action = (remote) => {
63612
- remote.updateEditorFunctionProps(...proxiedFunctions).catch(logComlinkError("updateEditorFunctionProps"));
64106
+ remote.updateEditorFunctionProps(...proxiedFunctions).catch(
64107
+ logComlinkError(
64108
+ "DoenetEditor",
64109
+ "updateEditorFunctionProps"
64110
+ )
64111
+ );
63613
64112
  };
63614
64113
  if (editorIframeRef.current) {
63615
64114
  action(editorIframeRef.current);
@@ -63635,7 +64134,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63635
64134
  ]);
63636
64135
  return null;
63637
64136
  }
63638
- let errorIcon = /* @__PURE__ */ React__default__default.createElement(
64137
+ let errorIcon = /* @__PURE__ */ React__default.createElement(
63639
64138
  MdError,
63640
64139
  {
63641
64140
  fontSize: "24pt",
@@ -63643,7 +64142,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63643
64142
  style: { verticalAlign: "middle", marginRight: "5px" }
63644
64143
  }
63645
64144
  );
63646
- return /* @__PURE__ */ React__default__default.createElement(
64145
+ return /* @__PURE__ */ React__default.createElement(
63647
64146
  "div",
63648
64147
  {
63649
64148
  style: {
@@ -63663,7 +64162,7 @@ const DoenetEditor = React__default__default.forwardRef(function DoenetEditor2({
63663
64162
  inErrorState
63664
64163
  );
63665
64164
  }
63666
- return /* @__PURE__ */ React__default__default.createElement(React__default__default.Fragment, null, addVirtualKeyboard ? /* @__PURE__ */ React__default__default.createElement(ExternalVirtualKeyboard, { ownerRef: ref, theme: resolvedTheme }) : null, /* @__PURE__ */ React__default__default.createElement(
64165
+ return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, addVirtualKeyboard ? /* @__PURE__ */ React__default.createElement(ExternalVirtualKeyboard, { ownerRef: ref, theme: resolvedTheme }) : null, /* @__PURE__ */ React__default.createElement(
63667
64166
  "iframe",
63668
64167
  {
63669
64168
  title: "Doenet Editor",
@@ -63686,6 +64185,7 @@ export {
63686
64185
  defaultCreativeCommonsVersion$1 as defaultCreativeCommonsVersion,
63687
64186
  getMediaLicenseDisplay,
63688
64187
  getMediaLicenseInfo,
64188
+ getViewerLifecycleStats,
63689
64189
  mathjaxConfig$1 as mathjaxConfig,
63690
64190
  mediaLicenses$1 as mediaLicenses,
63691
64191
  version