react-cheminfo 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1229,9 +1229,11 @@ A prerendered site can also be deployed as a server, with its API and its MCP
1229
1229
  tools beside the pages. `staticSite` from `react-cheminfo/server` serves the
1230
1230
  build by the rules the static hosts follow: `/titration` is `titration.html`
1231
1231
  with no redirect, an unknown address is `404.html` and never the home page,
1232
- pages are revalidated on every visit and `assets/` is kept for a year, the
1233
- `TRACKING_SCRIPT` snippet is in every page, and `/health` answers the deploy
1234
- script. Only a file the build wrote is ever served.
1232
+ pages are revalidated on every visit and `assets/` is kept for a year, every
1233
+ answer carries `Access-Control-Allow-Origin: *` (a page framed by a chat's
1234
+ sandboxed view fetches all its files cross-origin), the `TRACKING_SCRIPT`
1235
+ snippet is in every page, and `/health` answers the deploy script. Only a file
1236
+ the build wrote is ever served.
1235
1237
 
1236
1238
  ```ts
1237
1239
  import { fastify } from 'fastify';
@@ -1 +1 @@
1
- {"version":3,"file":"FigureDownloadPanel.d.ts","sourceRoot":"","sources":["../../../src/download/ui/FigureDownloadPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,sDAAsD;AACtD,MAAM,WAAW,wBAAwB;IACvC,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,YAAY,CAAC;IACrB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,wEAAwE;IACxE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,mEAAmE;IACnE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/C,4CAA4C;IAC5C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mCAAmC;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;OAGG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,YAAY,CAqEd"}
1
+ {"version":3,"file":"FigureDownloadPanel.d.ts","sourceRoot":"","sources":["../../../src/download/ui/FigureDownloadPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAO1C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAQ3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAIzD,sDAAsD;AACtD,MAAM,WAAW,wBAAwB;IACvC,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,EAAE,YAAY,CAAC;IACrB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,wEAAwE;IACxE,IAAI,EAAE,YAAY,GAAG,IAAI,CAAC;IAC1B,mEAAmE;IACnE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;OAIG;IACH,MAAM,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,2DAA2D;IAC3D,MAAM,EAAE,OAAO,CAAC;IAChB,gDAAgD;IAChD,cAAc,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,CAAC;IAC/C,4CAA4C;IAC5C,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mCAAmC;IACnC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;OAGG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,wBAAwB,GAC9B,YAAY,CAuEd"}
@@ -36,7 +36,7 @@ export function FigureDownloadPanel(props) {
36
36
  ? size
37
37
  : figureLayoutSize(sizing.layout, size, sizing.custom ?? size);
38
38
  const painted = format === 'png' || rasterSvg;
39
- return (_jsxs(OverlayPanel, { title: title, width: PANEL_WIDTH, hint: hintOf({ format, size: drawn, scale, failure, notice, rasterSvg }, t), actions: _jsxs(_Fragment, { children: [_jsx(OverlayAction, { text: t('download.save'), icon: "download", intent: "primary", disabled: saving || size === null, onClick: onSave }), _jsx(OverlayAction, { text: t('clipboard.copy'), icon: "clipboard", disabled: saving || size === null, onClick: onCopy })] }), children: [_jsx(OverlaySegmented, { label: t('download.format'), help: {
39
+ return (_jsxs(OverlayPanel, { title: title, width: PANEL_WIDTH, hint: hintOf({ format, size: drawn, scale, failure, notice, rasterSvg }, t), actions: _jsxs(_Fragment, { children: [_jsx(OverlayAction, { text: t('download.save'), icon: "download", intent: "primary", disabled: size === null, busy: saving, onClick: onSave }), _jsx(OverlayAction, { text: t('clipboard.copy'), icon: "clipboard", disabled: size === null, busy: saving, onClick: onCopy })] }), children: [_jsx(OverlaySegmented, { label: t('download.format'), help: {
40
40
  title: t('download.format'),
41
41
  body: t('download.formatHelp'),
42
42
  }, value: format, options: FORMAT_CHOICES, onChange: onFormatChange }), sizing === undefined ? null : (_jsx(FigureSizeRows, { sizing: sizing, size: size })), _jsx(OverlaySegmented, { label: t('download.resolution'), help: {
@@ -1 +1 @@
1
- {"version":3,"file":"FigureDownloadPanel.js","sourceRoot":"","sources":["../../../src/download/ui/FigureDownloadPanel.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FigureDownloadPanel.js","sourceRoot":"","sources":["../../../src/download/ui/FigureDownloadPanel.tsx"],"names":[],"mappings":"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"}
@@ -12,8 +12,16 @@ import type { CSSProperties, ReactElement, ReactNode } from 'react';
12
12
  import type { Molecule3DFullscreen } from './Molecule3DToolbar.tsx';
13
13
  /** Props of {@link Molecule3DStage}. */
14
14
  export interface Molecule3DStageProps {
15
- /** Style of the box. */
16
- style: CSSProperties;
15
+ /**
16
+ * Style of the box, or a function handed whether the box fills the screen,
17
+ * for a box shaped differently while it does.
18
+ */
19
+ style: CSSProperties | ((fillsScreen: boolean) => CSSProperties);
20
+ /**
21
+ * Called with the box once it is mounted, and with `null` once it is gone.
22
+ * @default undefined
23
+ */
24
+ onStage?: (element: HTMLDivElement | null) => void;
17
25
  /**
18
26
  * What is drawn in the box, handed whether it fills the screen and the
19
27
  * toggle, or `undefined` where the browser cannot fill the screen.
@@ -1 +1 @@
1
- {"version":3,"file":"Molecule3DStage.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/Molecule3DStage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,wCAAwC;AACxC,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB;;;OAGG;IACH,QAAQ,EAAE,CAAC,UAAU,EAAE,oBAAoB,GAAG,SAAS,KAAK,SAAS,CAAC;CACvE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,CAMzE"}
1
+ {"version":3,"file":"Molecule3DStage.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/Molecule3DStage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,wCAAwC;AACxC,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,KAAK,EAAE,aAAa,GAAG,CAAC,CAAC,WAAW,EAAE,OAAO,KAAK,aAAa,CAAC,CAAC;IACjE;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,KAAK,IAAI,CAAC;IACnD;;;OAGG;IACH,QAAQ,EAAE,CAAC,UAAU,EAAE,oBAAoB,GAAG,SAAS,KAAK,SAAS,CAAC;CACvE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,oBAAoB,GAAG,YAAY,CAMzE"}
@@ -21,7 +21,7 @@ export function Molecule3DStage(props) {
21
21
  return (_jsx(FullScreenProvider, { children: (fullscreenRef) => _jsx(Stage, { ...props, fullscreenRef: fullscreenRef }) }));
22
22
  }
23
23
  function Stage(props) {
24
- const { style, children, fullscreenRef } = props;
24
+ const { style, onStage, children, fullscreenRef } = props;
25
25
  const { isFullScreen, toggle } = useFullscreen();
26
26
  const portal = useContext(PortalContext);
27
27
  const [canFillScreen] = useState(isFullscreenEnabled);
@@ -29,10 +29,11 @@ function Stage(props) {
29
29
  const stageRef = useCallback((element) => {
30
30
  fullscreenRef.current = element;
31
31
  setStage(element);
32
- }, [fullscreenRef]);
32
+ onStage?.(element);
33
+ }, [fullscreenRef, onStage]);
33
34
  // The provider is always there, so entering full screen changes a value
34
35
  // rather than the tree, and the canvas inside is never mounted again.
35
- return (_jsx("div", { ref: stageRef, style: style, children: _jsx(PortalProvider, { portalClassName: portal.portalClassName, portalContainer: isFullScreen && stage !== null ? stage : portal.portalContainer, children: children(canFillScreen ? { active: isFullScreen, toggle } : undefined) }) }));
36
+ return (_jsx("div", { ref: stageRef, style: typeof style === 'function' ? style(isFullScreen) : style, children: _jsx(PortalProvider, { portalClassName: portal.portalClassName, portalContainer: isFullScreen && stage !== null ? stage : portal.portalContainer, children: children(canFillScreen ? { active: isFullScreen, toggle } : undefined) }) }));
36
37
  }
37
38
  function isFullscreenEnabled() {
38
39
  return typeof document !== 'undefined' && document.fullscreenEnabled;
@@ -1 +1 @@
1
- {"version":3,"file":"Molecule3DStage.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/Molecule3DStage.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAerE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,OAAO,CACL,KAAC,kBAAkB,cAChB,CAAC,aAAa,EAAE,EAAE,CAAC,KAAC,KAAK,OAAK,KAAK,EAAE,aAAa,EAAE,aAAa,GAAI,GACnD,CACtB,CAAC;AACJ,CAAC;AAOD,SAAS,KAAK,CAAC,KAAiB;IAC9B,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IACjD,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,MAAM,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,OAA8B,EAAE,EAAE;QACjC,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC;QAChC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACpB,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF,wEAAwE;IACxE,sEAAsE;IACtE,OAAO,CACL,cAAK,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,YAC9B,KAAC,cAAc,IACb,eAAe,EAAE,MAAM,CAAC,eAAe,EACvC,eAAe,EACb,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,YAGhE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GACxD,GACb,CACP,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,iBAAiB,CAAC;AACvE,CAAC"}
1
+ {"version":3,"file":"Molecule3DStage.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/Molecule3DStage.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAElE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAuBrE;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAA2B;IACzD,OAAO,CACL,KAAC,kBAAkB,cAChB,CAAC,aAAa,EAAE,EAAE,CAAC,KAAC,KAAK,OAAK,KAAK,EAAE,aAAa,EAAE,aAAa,GAAI,GACnD,CACtB,CAAC;AACJ,CAAC;AAOD,SAAS,KAAK,CAAC,KAAiB;IAC9B,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,GAAG,KAAK,CAAC;IAC1D,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,aAAa,EAAE,CAAC;IACjD,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,MAAM,CAAC,aAAa,CAAC,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC;IACtD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,OAA8B,EAAE,EAAE;QACjC,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC;QAChC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAClB,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IACrB,CAAC,EACD,CAAC,aAAa,EAAE,OAAO,CAAC,CACzB,CAAC;IAEF,wEAAwE;IACxE,sEAAsE;IACtE,OAAO,CACL,cACE,GAAG,EAAE,QAAQ,EACb,KAAK,EAAE,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,YAEhE,KAAC,cAAc,IACb,eAAe,EAAE,MAAM,CAAC,eAAe,EACvC,eAAe,EACb,YAAY,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,YAGhE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,GACxD,GACb,CACP,CAAC;AACJ,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,iBAAiB,CAAC;AACvE,CAAC"}
@@ -9,6 +9,8 @@
9
9
  export { Molecule3DExport } from './Molecule3DExport.tsx';
10
10
  export type { Molecule3DExportProps } from './Molecule3DExport.tsx';
11
11
  export { Molecule3DHelp } from './Molecule3DHelp.tsx';
12
+ export { Molecule3DStage } from './Molecule3DStage.tsx';
13
+ export type { Molecule3DStageProps } from './Molecule3DStage.tsx';
12
14
  export { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
13
15
  export type { Molecule3DFullscreen, Molecule3DToolbarProps, } from './Molecule3DToolbar.tsx';
14
16
  export type { MoleculeImageRequest, SceneCapture, } from './exportMoleculeImage.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,oBAAoB,EACpB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/molecule3d/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,YAAY,EACV,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,YAAY,EACV,oBAAoB,EACpB,YAAY,GACb,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC"}
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export { Molecule3DExport } from "./Molecule3DExport.js";
10
10
  export { Molecule3DHelp } from "./Molecule3DHelp.js";
11
+ export { Molecule3DStage } from "./Molecule3DStage.js";
11
12
  export { Molecule3DToolbar } from "./Molecule3DToolbar.js";
12
13
  export { exportMoleculeImage } from "./exportMoleculeImage.js";
13
14
  export { useImageExport } from "./useImageExport.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAwB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAsB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAyB,CAAC;AAS5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/molecule3d/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAwB,CAAC;AAE1D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAuB,CAAC;AAExD,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAyB,CAAC;AAS5D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAwB,CAAC"}
@@ -18,6 +18,13 @@ export interface OverlayActionProps extends Omit<OverlayControlProps, 'label' |
18
18
  * @default 'none'
19
19
  */
20
20
  intent?: Intent;
21
+ /**
22
+ * Whether what it started is still running. A busy button ignores a press
23
+ * but keeps the focus, so the card around it keeps its keys: a disabled one
24
+ * drops the focus to the page, and Escape no longer closes the card.
25
+ * @default false
26
+ */
27
+ busy?: boolean;
21
28
  }
22
29
  /**
23
30
  * The one control here that does something rather than changing something.
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayAction.d.ts","sourceRoot":"","sources":["../../../src/overlay/ui/OverlayAction.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAI5D,wCAAwC;AACxC,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAC9C,mBAAmB,EACnB,OAAO,GAAG,WAAW,CACtB;IACC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,CA0BrE"}
1
+ {"version":3,"file":"OverlayAction.d.ts","sourceRoot":"","sources":["../../../src/overlay/ui/OverlayAction.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAI5D,wCAAwC;AACxC,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAC9C,mBAAmB,EACnB,OAAO,GAAG,WAAW,CACtB;IACC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,YAAY,CA4BrE"}
@@ -12,8 +12,8 @@ import { useOverlaySurface } from "./overlaySurface.js";
12
12
  * @returns The button, with its help.
13
13
  */
14
14
  export function OverlayAction(props) {
15
- const { text, onClick, icon, intent = 'none', help, disabled = false, testId, } = props;
15
+ const { text, onClick, icon, intent = 'none', help, disabled = false, busy = false, testId, } = props;
16
16
  const { metrics } = useOverlaySurface();
17
- return (_jsx(OverlayRow, { label: text, help: help, hideLabel: true, disabled: disabled, children: _jsx(Button, { variant: "minimal", size: metrics.blueprintSize, intent: intent, icon: icon, text: text, disabled: disabled, "data-testid": testId, onClick: onClick }) }));
17
+ return (_jsx(OverlayRow, { label: text, help: help, hideLabel: true, disabled: disabled, children: _jsx(Button, { variant: "minimal", size: metrics.blueprintSize, intent: intent, icon: icon, text: text, disabled: disabled, "aria-disabled": busy || undefined, "data-testid": testId, onClick: busy ? undefined : onClick }) }));
18
18
  }
19
19
  //# sourceMappingURL=OverlayAction.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"OverlayAction.js","sourceRoot":"","sources":["../../../src/overlay/ui/OverlayAction.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAwBxD;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,MAAM,EACJ,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,GAAG,MAAM,EACf,IAAI,EACJ,QAAQ,GAAG,KAAK,EAChB,MAAM,GACP,GAAG,KAAK,CAAC;IACV,MAAM,EAAE,OAAO,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAExC,OAAO,CACL,KAAC,UAAU,IAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,QAAC,QAAQ,EAAE,QAAQ,YAC/D,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAE,OAAO,CAAC,aAAa,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,iBACL,MAAM,EACnB,OAAO,EAAE,OAAO,GAChB,GACS,CACd,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"OverlayAction.js","sourceRoot":"","sources":["../../../src/overlay/ui/OverlayAction.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAG1C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AA+BxD;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,MAAM,EACJ,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,MAAM,GAAG,MAAM,EACf,IAAI,EACJ,QAAQ,GAAG,KAAK,EAChB,IAAI,GAAG,KAAK,EACZ,MAAM,GACP,GAAG,KAAK,CAAC;IACV,MAAM,EAAE,OAAO,EAAE,GAAG,iBAAiB,EAAE,CAAC;IAExC,OAAO,CACL,KAAC,UAAU,IAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,QAAC,QAAQ,EAAE,QAAQ,YAC/D,KAAC,MAAM,IACL,OAAO,EAAC,SAAS,EACjB,IAAI,EAAE,OAAO,CAAC,aAAa,EAC3B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,mBACH,IAAI,IAAI,SAAS,iBACnB,MAAM,EACnB,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,GACnC,GACS,CACd,CAAC;AACJ,CAAC"}
@@ -28,8 +28,9 @@ export interface StaticSiteOptions {
28
28
  * family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
29
29
  * file per address and no fallback page, `/titration` answered without a
30
30
  * redirect, pages checked on every visit and hashed bundles kept for a year,
31
- * the analytics snippet in every page, `404.html` for an address the site does
32
- * not have, and `/health` for the deploy script.
31
+ * every response open to any origin, the analytics snippet in every page,
32
+ * `404.html` for an address the site does not have, and `/health` for the
33
+ * deploy script.
33
34
  *
34
35
  * Register it next to the API; a build missing (a server started before the
35
36
  * frontend was built) leaves the API alone:
@@ -1 +1 @@
1
- {"version":3,"file":"staticSite.d.ts","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAC;AAMjB,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAiBD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CA4Df"}
1
+ {"version":3,"file":"staticSite.d.ts","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAC;AAMjB,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAyDf"}
@@ -6,6 +6,12 @@ import { isHashedBundle, listSiteFiles, resolveAddress } from "./siteFiles.js";
6
6
  const PAGE_CACHE = 'no-cache';
7
7
  /** A bundle is named by its content, so it never changes under its name. */
8
8
  const BUNDLE_CACHE = 'public, max-age=31536000, immutable';
9
+ /**
10
+ * Every file of a build is public, and a page framed by a sandboxed view runs
11
+ * under an opaque origin, where everything it fetches from its own site is
12
+ * cross-origin: the static hosts open every response, and so does this server.
13
+ */
14
+ const ALLOW_ORIGIN = 'access-control-allow-origin';
9
15
  /** Kept out of the API's documentation (`@fastify/swagger` reads `hide`). */
10
16
  const HIDDEN = { hide: true };
11
17
  /**
@@ -13,8 +19,9 @@ const HIDDEN = { hide: true };
13
19
  * family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
14
20
  * file per address and no fallback page, `/titration` answered without a
15
21
  * redirect, pages checked on every visit and hashed bundles kept for a year,
16
- * the analytics snippet in every page, `404.html` for an address the site does
17
- * not have, and `/health` for the deploy script.
22
+ * every response open to any origin, the analytics snippet in every page,
23
+ * `404.html` for an address the site does not have, and `/health` for the
24
+ * deploy script.
18
25
  *
19
26
  * Register it next to the API; a build missing (a server started before the
20
27
  * frontend was built) leaves the API alone:
@@ -26,7 +33,7 @@ const HIDDEN = { hide: true };
26
33
  export async function staticSite(fastify, options) {
27
34
  const { trackingScript, redirects = {}, reserved = ['/v1/'] } = options;
28
35
  const root = resolve(options.root);
29
- fastify.get('/health', { logLevel: 'silent', schema: HIDDEN }, (_request, reply) => reply.send({ status: 'ok' }));
36
+ fastify.get('/health', { logLevel: 'silent', schema: HIDDEN }, (_request, reply) => reply.header(ALLOW_ORIGIN, '*').send({ status: 'ok' }));
30
37
  const files = await listSiteFiles(root);
31
38
  if (files === undefined) {
32
39
  fastify.log.warn({ root }, 'no built site: serving the API alone');
@@ -42,15 +49,7 @@ export async function staticSite(fastify, options) {
42
49
  cacheControl: false,
43
50
  setHeaders: (reply, path) => {
44
51
  const file = relative(root, path).split(sep).join('/');
45
- if (isHashedBundle(file)) {
46
- reply.header('cache-control', BUNDLE_CACHE);
47
- // A page framed by a sandboxed view may run under an opaque origin,
48
- // and a module bundle is then fetched cross-origin.
49
- reply.header('access-control-allow-origin', '*');
50
- }
51
- else {
52
- reply.header('cache-control', PAGE_CACHE);
53
- }
52
+ reply.header('cache-control', isHashedBundle(file) ? BUNDLE_CACHE : PAGE_CACHE);
54
53
  },
55
54
  });
56
55
  const answer = (request, reply) => {
@@ -59,6 +58,7 @@ export async function staticSite(fastify, options) {
59
58
  if (reserved.some((prefix) => pathname.startsWith(prefix))) {
60
59
  return reply.callNotFound();
61
60
  }
61
+ reply.header(ALLOW_ORIGIN, '*');
62
62
  const destination = redirects[pathname] ?? redirects[pathname.replace(/\/$/, '')];
63
63
  if (destination !== undefined) {
64
64
  return reply.redirect(`${destination}${search}`, 301);
@@ -1 +1 @@
1
- {"version":3,"file":"staticSite.js","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"staticSite.js","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-cheminfo",
3
- "version": "0.61.0",
3
+ "version": "0.63.0",
4
4
  "license": "MIT",
5
5
  "description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
6
6
  "author": "Luc Patiny",
@@ -118,13 +118,15 @@ export function FigureDownloadPanel(
118
118
  text={t('download.save')}
119
119
  icon="download"
120
120
  intent="primary"
121
- disabled={saving || size === null}
121
+ disabled={size === null}
122
+ busy={saving}
122
123
  onClick={onSave}
123
124
  />
124
125
  <OverlayAction
125
126
  text={t('clipboard.copy')}
126
127
  icon="clipboard"
127
- disabled={saving || size === null}
128
+ disabled={size === null}
129
+ busy={saving}
128
130
  onClick={onCopy}
129
131
  />
130
132
  </>
@@ -18,8 +18,16 @@ import type { Molecule3DFullscreen } from './Molecule3DToolbar.tsx';
18
18
 
19
19
  /** Props of {@link Molecule3DStage}. */
20
20
  export interface Molecule3DStageProps {
21
- /** Style of the box. */
22
- style: CSSProperties;
21
+ /**
22
+ * Style of the box, or a function handed whether the box fills the screen,
23
+ * for a box shaped differently while it does.
24
+ */
25
+ style: CSSProperties | ((fillsScreen: boolean) => CSSProperties);
26
+ /**
27
+ * Called with the box once it is mounted, and with `null` once it is gone.
28
+ * @default undefined
29
+ */
30
+ onStage?: (element: HTMLDivElement | null) => void;
23
31
  /**
24
32
  * What is drawn in the box, handed whether it fills the screen and the
25
33
  * toggle, or `undefined` where the browser cannot fill the screen.
@@ -46,7 +54,7 @@ interface StageProps extends Molecule3DStageProps {
46
54
  }
47
55
 
48
56
  function Stage(props: StageProps): ReactElement {
49
- const { style, children, fullscreenRef } = props;
57
+ const { style, onStage, children, fullscreenRef } = props;
50
58
  const { isFullScreen, toggle } = useFullscreen();
51
59
  const portal = useContext(PortalContext);
52
60
  const [canFillScreen] = useState(isFullscreenEnabled);
@@ -55,14 +63,18 @@ function Stage(props: StageProps): ReactElement {
55
63
  (element: HTMLDivElement | null) => {
56
64
  fullscreenRef.current = element;
57
65
  setStage(element);
66
+ onStage?.(element);
58
67
  },
59
- [fullscreenRef],
68
+ [fullscreenRef, onStage],
60
69
  );
61
70
 
62
71
  // The provider is always there, so entering full screen changes a value
63
72
  // rather than the tree, and the canvas inside is never mounted again.
64
73
  return (
65
- <div ref={stageRef} style={style}>
74
+ <div
75
+ ref={stageRef}
76
+ style={typeof style === 'function' ? style(isFullScreen) : style}
77
+ >
66
78
  <PortalProvider
67
79
  portalClassName={portal.portalClassName}
68
80
  portalContainer={
@@ -10,6 +10,8 @@
10
10
  export { Molecule3DExport } from './Molecule3DExport.tsx';
11
11
  export type { Molecule3DExportProps } from './Molecule3DExport.tsx';
12
12
  export { Molecule3DHelp } from './Molecule3DHelp.tsx';
13
+ export { Molecule3DStage } from './Molecule3DStage.tsx';
14
+ export type { Molecule3DStageProps } from './Molecule3DStage.tsx';
13
15
  export { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
14
16
  export type {
15
17
  Molecule3DFullscreen,
@@ -26,6 +26,13 @@ export interface OverlayActionProps extends Omit<
26
26
  * @default 'none'
27
27
  */
28
28
  intent?: Intent;
29
+ /**
30
+ * Whether what it started is still running. A busy button ignores a press
31
+ * but keeps the focus, so the card around it keeps its keys: a disabled one
32
+ * drops the focus to the page, and Escape no longer closes the card.
33
+ * @default false
34
+ */
35
+ busy?: boolean;
29
36
  }
30
37
 
31
38
  /**
@@ -45,6 +52,7 @@ export function OverlayAction(props: OverlayActionProps): ReactElement {
45
52
  intent = 'none',
46
53
  help,
47
54
  disabled = false,
55
+ busy = false,
48
56
  testId,
49
57
  } = props;
50
58
  const { metrics } = useOverlaySurface();
@@ -58,8 +66,9 @@ export function OverlayAction(props: OverlayActionProps): ReactElement {
58
66
  icon={icon}
59
67
  text={text}
60
68
  disabled={disabled}
69
+ aria-disabled={busy || undefined}
61
70
  data-testid={testId}
62
- onClick={onClick}
71
+ onClick={busy ? undefined : onClick}
63
72
  />
64
73
  </OverlayRow>
65
74
  );
@@ -49,6 +49,13 @@ const PAGE_CACHE = 'no-cache';
49
49
  /** A bundle is named by its content, so it never changes under its name. */
50
50
  const BUNDLE_CACHE = 'public, max-age=31536000, immutable';
51
51
 
52
+ /**
53
+ * Every file of a build is public, and a page framed by a sandboxed view runs
54
+ * under an opaque origin, where everything it fetches from its own site is
55
+ * cross-origin: the static hosts open every response, and so does this server.
56
+ */
57
+ const ALLOW_ORIGIN = 'access-control-allow-origin';
58
+
52
59
  /** Kept out of the API's documentation (`@fastify/swagger` reads `hide`). */
53
60
  const HIDDEN: FastifySchema & { hide: boolean } = { hide: true };
54
61
 
@@ -57,8 +64,9 @@ const HIDDEN: FastifySchema & { hide: boolean } = { hide: true };
57
64
  * family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
58
65
  * file per address and no fallback page, `/titration` answered without a
59
66
  * redirect, pages checked on every visit and hashed bundles kept for a year,
60
- * the analytics snippet in every page, `404.html` for an address the site does
61
- * not have, and `/health` for the deploy script.
67
+ * every response open to any origin, the analytics snippet in every page,
68
+ * `404.html` for an address the site does not have, and `/health` for the
69
+ * deploy script.
62
70
  *
63
71
  * Register it next to the API; a build missing (a server started before the
64
72
  * frontend was built) leaves the API alone:
@@ -77,7 +85,7 @@ export async function staticSite(
77
85
  fastify.get(
78
86
  '/health',
79
87
  { logLevel: 'silent', schema: HIDDEN },
80
- (_request, reply) => reply.send({ status: 'ok' }),
88
+ (_request, reply) => reply.header(ALLOW_ORIGIN, '*').send({ status: 'ok' }),
81
89
  );
82
90
 
83
91
  const files = await listSiteFiles(root);
@@ -96,14 +104,10 @@ export async function staticSite(
96
104
  cacheControl: false,
97
105
  setHeaders: (reply, path) => {
98
106
  const file = relative(root, path).split(sep).join('/');
99
- if (isHashedBundle(file)) {
100
- reply.header('cache-control', BUNDLE_CACHE);
101
- // A page framed by a sandboxed view may run under an opaque origin,
102
- // and a module bundle is then fetched cross-origin.
103
- reply.header('access-control-allow-origin', '*');
104
- } else {
105
- reply.header('cache-control', PAGE_CACHE);
106
- }
107
+ reply.header(
108
+ 'cache-control',
109
+ isHashedBundle(file) ? BUNDLE_CACHE : PAGE_CACHE,
110
+ );
107
111
  },
108
112
  });
109
113
 
@@ -113,6 +117,7 @@ export async function staticSite(
113
117
  if (reserved.some((prefix) => pathname.startsWith(prefix))) {
114
118
  return reply.callNotFound();
115
119
  }
120
+ reply.header(ALLOW_ORIGIN, '*');
116
121
  const destination =
117
122
  redirects[pathname] ?? redirects[pathname.replace(/\/$/, '')];
118
123
  if (destination !== undefined) {