react-cheminfo 0.64.1 → 0.66.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 +293 -6
- package/lib/card/core/cardAddress.d.ts +70 -0
- package/lib/card/core/cardAddress.d.ts.map +1 -0
- package/lib/card/core/cardAddress.js +59 -0
- package/lib/card/core/cardAddress.js.map +1 -0
- package/lib/card/core/cardPageUrl.d.ts +49 -0
- package/lib/card/core/cardPageUrl.d.ts.map +1 -0
- package/lib/card/core/cardPageUrl.js +59 -0
- package/lib/card/core/cardPageUrl.js.map +1 -0
- package/lib/card/core/index.d.ts +7 -0
- package/lib/card/core/index.d.ts.map +1 -0
- package/lib/card/core/index.js +4 -0
- package/lib/card/core/index.js.map +1 -0
- package/lib/card/core/panelRoom.d.ts +40 -0
- package/lib/card/core/panelRoom.d.ts.map +1 -0
- package/lib/card/core/panelRoom.js +40 -0
- package/lib/card/core/panelRoom.js.map +1 -0
- package/lib/card/ui/CardDetailsButton.d.ts +38 -0
- package/lib/card/ui/CardDetailsButton.d.ts.map +1 -0
- package/lib/card/ui/CardDetailsButton.js +50 -0
- package/lib/card/ui/CardDetailsButton.js.map +1 -0
- package/lib/card/ui/CardFigure.d.ts +51 -0
- package/lib/card/ui/CardFigure.d.ts.map +1 -0
- package/lib/card/ui/CardFigure.js +27 -0
- package/lib/card/ui/CardFigure.js.map +1 -0
- package/lib/card/ui/CardFrame.d.ts +30 -0
- package/lib/card/ui/CardFrame.d.ts.map +1 -0
- package/lib/card/ui/CardFrame.js +20 -0
- package/lib/card/ui/CardFrame.js.map +1 -0
- package/lib/card/ui/CopyTableButton.d.ts +37 -0
- package/lib/card/ui/CopyTableButton.d.ts.map +1 -0
- package/lib/card/ui/CopyTableButton.js +19 -0
- package/lib/card/ui/CopyTableButton.js.map +1 -0
- package/lib/card/ui/cardTooltip.d.ts +14 -0
- package/lib/card/ui/cardTooltip.d.ts.map +1 -0
- package/lib/card/ui/cardTooltip.js +15 -0
- package/lib/card/ui/cardTooltip.js.map +1 -0
- package/lib/card/ui/embed.d.ts +15 -0
- package/lib/card/ui/embed.d.ts.map +1 -0
- package/lib/card/ui/embed.js +24 -0
- package/lib/card/ui/embed.js.map +1 -0
- package/lib/card/ui/fitCardToFrame.d.ts +31 -0
- package/lib/card/ui/fitCardToFrame.d.ts.map +1 -0
- package/lib/card/ui/fitCardToFrame.js +66 -0
- package/lib/card/ui/fitCardToFrame.js.map +1 -0
- package/lib/card/ui/holdRoomForPanels.d.ts +16 -0
- package/lib/card/ui/holdRoomForPanels.d.ts.map +1 -0
- package/lib/card/ui/holdRoomForPanels.js +76 -0
- package/lib/card/ui/holdRoomForPanels.js.map +1 -0
- package/lib/card/ui/index.d.ts +11 -0
- package/lib/card/ui/index.d.ts.map +1 -0
- package/lib/card/ui/index.js +7 -0
- package/lib/card/ui/index.js.map +1 -0
- package/lib/card/ui/openPanels.d.ts +25 -0
- package/lib/card/ui/openPanels.d.ts.map +1 -0
- package/lib/card/ui/openPanels.js +85 -0
- package/lib/card/ui/openPanels.js.map +1 -0
- package/lib/card.d.ts +13 -0
- package/lib/card.d.ts.map +1 -0
- package/lib/card.js +13 -0
- package/lib/card.js.map +1 -0
- package/lib/conformers.d.ts +1 -0
- package/lib/conformers.d.ts.map +1 -1
- package/lib/conformers.js +1 -0
- package/lib/conformers.js.map +1 -1
- package/lib/core.d.ts +4 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +5 -0
- package/lib/core.js.map +1 -1
- package/lib/fetch/core/apiError.d.ts +56 -0
- package/lib/fetch/core/apiError.d.ts.map +1 -0
- package/lib/fetch/core/apiError.js +43 -0
- package/lib/fetch/core/apiError.js.map +1 -0
- package/lib/fetch/core/fetchJson.d.ts +47 -0
- package/lib/fetch/core/fetchJson.d.ts.map +1 -0
- package/lib/fetch/core/fetchJson.js +109 -0
- package/lib/fetch/core/fetchJson.js.map +1 -0
- package/lib/fetch/core/index.d.ts +5 -0
- package/lib/fetch/core/index.d.ts.map +1 -0
- package/lib/fetch/core/index.js +3 -0
- package/lib/fetch/core/index.js.map +1 -0
- package/lib/formula/core/formulaText.d.ts +46 -0
- package/lib/formula/core/formulaText.d.ts.map +1 -0
- package/lib/formula/core/formulaText.js +74 -0
- package/lib/formula/core/formulaText.js.map +1 -0
- package/lib/formula/core/index.d.ts +6 -0
- package/lib/formula/core/index.d.ts.map +1 -0
- package/lib/formula/core/index.js +4 -0
- package/lib/formula/core/index.js.map +1 -0
- package/lib/formula/core/normalizeFormula.d.ts +22 -0
- package/lib/formula/core/normalizeFormula.d.ts.map +1 -0
- package/lib/formula/core/normalizeFormula.js +46 -0
- package/lib/formula/core/normalizeFormula.js.map +1 -0
- package/lib/formula/core/readFormula.d.ts +73 -0
- package/lib/formula/core/readFormula.d.ts.map +1 -0
- package/lib/formula/core/readFormula.js +132 -0
- package/lib/formula/core/readFormula.js.map +1 -0
- package/lib/formula/ui/CopyableFormula.d.ts +31 -0
- package/lib/formula/ui/CopyableFormula.d.ts.map +1 -0
- package/lib/formula/ui/CopyableFormula.js +19 -0
- package/lib/formula/ui/CopyableFormula.js.map +1 -0
- package/lib/formula/ui/FormulaInput.d.ts +29 -0
- package/lib/formula/ui/FormulaInput.d.ts.map +1 -0
- package/lib/formula/ui/FormulaInput.js +16 -0
- package/lib/formula/ui/FormulaInput.js.map +1 -0
- package/lib/formula/ui/QuestionFormula.d.ts +14 -0
- package/lib/formula/ui/QuestionFormula.d.ts.map +1 -0
- package/lib/formula/ui/QuestionFormula.js +13 -0
- package/lib/formula/ui/QuestionFormula.js.map +1 -0
- package/lib/formula/ui/index.d.ts +7 -0
- package/lib/formula/ui/index.d.ts.map +1 -0
- package/lib/formula/ui/index.js +4 -0
- package/lib/formula/ui/index.js.map +1 -0
- package/lib/formula.d.ts +11 -0
- package/lib/formula.d.ts.map +1 -0
- package/lib/formula.js +11 -0
- package/lib/formula.js.map +1 -0
- package/lib/hooks/ui/index.d.ts +1 -0
- package/lib/hooks/ui/index.d.ts.map +1 -1
- package/lib/hooks/ui/index.js.map +1 -1
- package/lib/hooks/ui/keyTargets.d.ts +4 -2
- package/lib/hooks/ui/keyTargets.d.ts.map +1 -1
- package/lib/hooks/ui/keyTargets.js +5 -3
- package/lib/hooks/ui/keyTargets.js.map +1 -1
- package/lib/hooks/ui/useAsync.d.ts +20 -5
- package/lib/hooks/ui/useAsync.d.ts.map +1 -1
- package/lib/hooks/ui/useAsync.js +29 -14
- package/lib/hooks/ui/useAsync.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/ir/core/analysisSpectra.d.ts +23 -6
- package/lib/ir/core/analysisSpectra.d.ts.map +1 -1
- package/lib/ir/core/analysisSpectra.js.map +1 -1
- package/lib/ir/core/bandLabelPlan.d.ts.map +1 -1
- package/lib/ir/core/bandLabelPlan.js +11 -6
- package/lib/ir/core/bandLabelPlan.js.map +1 -1
- package/lib/ir/core/index.d.ts +13 -9
- package/lib/ir/core/index.d.ts.map +1 -1
- package/lib/ir/core/index.js +9 -6
- package/lib/ir/core/index.js.map +1 -1
- package/lib/ir/core/irBand.d.ts +45 -14
- package/lib/ir/core/irBand.d.ts.map +1 -1
- package/lib/ir/core/irBand.js +28 -6
- package/lib/ir/core/irBand.js.map +1 -1
- package/lib/ir/core/irCommands.d.ts +11 -0
- package/lib/ir/core/irCommands.d.ts.map +1 -1
- package/lib/ir/core/irCommands.js +11 -1
- package/lib/ir/core/irCommands.js.map +1 -1
- package/lib/ir/core/irDomain.d.ts +4 -3
- package/lib/ir/core/irDomain.d.ts.map +1 -1
- package/lib/ir/core/irDomain.js +10 -7
- package/lib/ir/core/irDomain.js.map +1 -1
- package/lib/ir/core/irFormat.d.ts +14 -2
- package/lib/ir/core/irFormat.d.ts.map +1 -1
- package/lib/ir/core/irFormat.js +33 -4
- package/lib/ir/core/irFormat.js.map +1 -1
- package/lib/ir/core/irMode.d.ts +35 -8
- package/lib/ir/core/irMode.d.ts.map +1 -1
- package/lib/ir/core/irMode.js +38 -10
- package/lib/ir/core/irMode.js.map +1 -1
- package/lib/ir/core/irReducer.d.ts +0 -28
- package/lib/ir/core/irReducer.d.ts.map +1 -1
- package/lib/ir/core/irReducer.js +1 -24
- package/lib/ir/core/irReducer.js.map +1 -1
- package/lib/ir/core/irSpectrum.d.ts +52 -26
- package/lib/ir/core/irSpectrum.d.ts.map +1 -1
- package/lib/ir/core/irSpectrum.js +21 -15
- package/lib/ir/core/irSpectrum.js.map +1 -1
- package/lib/ir/core/irState.d.ts +40 -2
- package/lib/ir/core/irState.d.ts.map +1 -1
- package/lib/ir/core/irState.js +38 -1
- package/lib/ir/core/irState.js.map +1 -1
- package/lib/ir/core/irTechnique.d.ts +94 -0
- package/lib/ir/core/irTechnique.d.ts.map +1 -0
- package/lib/ir/core/irTechnique.js +87 -0
- package/lib/ir/core/irTechnique.js.map +1 -0
- package/lib/ir/core/irTechniqueCommands.d.ts +26 -0
- package/lib/ir/core/irTechniqueCommands.d.ts.map +1 -0
- package/lib/ir/core/irTechniqueCommands.js +68 -0
- package/lib/ir/core/irTechniqueCommands.js.map +1 -0
- package/lib/ir/core/pickBands.d.ts +6 -5
- package/lib/ir/core/pickBands.d.ts.map +1 -1
- package/lib/ir/core/pickBands.js +49 -26
- package/lib/ir/core/pickBands.js.map +1 -1
- package/lib/ir/core/ramanBands.d.ts +30 -0
- package/lib/ir/core/ramanBands.d.ts.map +1 -0
- package/lib/ir/core/ramanBands.js +83 -0
- package/lib/ir/core/ramanBands.js.map +1 -0
- package/lib/ir/core/spectrumJcamp.d.ts +10 -5
- package/lib/ir/core/spectrumJcamp.d.ts.map +1 -1
- package/lib/ir/core/spectrumJcamp.js +63 -15
- package/lib/ir/core/spectrumJcamp.js.map +1 -1
- package/lib/ir/core/toIrSpectrum.d.ts.map +1 -1
- package/lib/ir/core/toIrSpectrum.js +17 -2
- package/lib/ir/core/toIrSpectrum.js.map +1 -1
- package/lib/ir/ui/BandRow.d.ts +30 -0
- package/lib/ir/ui/BandRow.d.ts.map +1 -0
- package/lib/ir/ui/BandRow.js +42 -0
- package/lib/ir/ui/BandRow.js.map +1 -0
- package/lib/ir/ui/BandsPanel.d.ts +4 -0
- package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
- package/lib/ir/ui/BandsPanel.js +14 -59
- package/lib/ir/ui/BandsPanel.js.map +1 -1
- package/lib/ir/ui/IrAboutDialog.d.ts +7 -0
- package/lib/ir/ui/IrAboutDialog.d.ts.map +1 -1
- package/lib/ir/ui/IrAboutDialog.js +16 -3
- package/lib/ir/ui/IrAboutDialog.js.map +1 -1
- package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
- package/lib/ir/ui/IrCanvas.js +2 -2
- package/lib/ir/ui/IrCanvas.js.map +1 -1
- package/lib/ir/ui/IrChart.d.ts +2 -1
- package/lib/ir/ui/IrChart.d.ts.map +1 -1
- package/lib/ir/ui/IrChart.js +18 -21
- package/lib/ir/ui/IrChart.js.map +1 -1
- package/lib/ir/ui/IrCommandProvider.d.ts +7 -0
- package/lib/ir/ui/IrCommandProvider.d.ts.map +1 -1
- package/lib/ir/ui/IrCommandProvider.js +2 -2
- package/lib/ir/ui/IrCommandProvider.js.map +1 -1
- package/lib/ir/ui/IrCommandTooltip.d.ts +7 -0
- package/lib/ir/ui/IrCommandTooltip.d.ts.map +1 -1
- package/lib/ir/ui/IrCommandTooltip.js +3 -2
- package/lib/ir/ui/IrCommandTooltip.js.map +1 -1
- package/lib/ir/ui/IrDocumentationDialog.d.ts +8 -1
- package/lib/ir/ui/IrDocumentationDialog.d.ts.map +1 -1
- package/lib/ir/ui/IrDocumentationDialog.js +30 -7
- package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
- package/lib/ir/ui/IrEditor.d.ts +3 -1
- package/lib/ir/ui/IrEditor.d.ts.map +1 -1
- package/lib/ir/ui/IrEditor.js +3 -20
- package/lib/ir/ui/IrEditor.js.map +1 -1
- package/lib/ir/ui/IrHeader.d.ts.map +1 -1
- package/lib/ir/ui/IrHeader.js +5 -1
- package/lib/ir/ui/IrHeader.js.map +1 -1
- package/lib/ir/ui/IrLogo.d.ts +11 -3
- package/lib/ir/ui/IrLogo.d.ts.map +1 -1
- package/lib/ir/ui/IrLogo.js +14 -5
- package/lib/ir/ui/IrLogo.js.map +1 -1
- package/lib/ir/ui/IrShell.d.ts.map +1 -1
- package/lib/ir/ui/IrShell.js +23 -56
- package/lib/ir/ui/IrShell.js.map +1 -1
- package/lib/ir/ui/IrStatusBar.d.ts +3 -2
- package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
- package/lib/ir/ui/IrStatusBar.js +14 -9
- package/lib/ir/ui/IrStatusBar.js.map +1 -1
- package/lib/ir/ui/IrToolbar.d.ts +3 -0
- package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
- package/lib/ir/ui/IrToolbar.js +10 -3
- package/lib/ir/ui/IrToolbar.js.map +1 -1
- package/lib/ir/ui/IrTraces.d.ts +4 -1
- package/lib/ir/ui/IrTraces.d.ts.map +1 -1
- package/lib/ir/ui/IrTraces.js +2 -0
- package/lib/ir/ui/IrTraces.js.map +1 -1
- package/lib/ir/ui/RamanEditor.d.ts +46 -0
- package/lib/ir/ui/RamanEditor.d.ts.map +1 -0
- package/lib/ir/ui/RamanEditor.js +17 -0
- package/lib/ir/ui/RamanEditor.js.map +1 -0
- package/lib/ir/ui/SpectraPanel.d.ts.map +1 -1
- package/lib/ir/ui/SpectraPanel.js +2 -2
- package/lib/ir/ui/SpectraPanel.js.map +1 -1
- package/lib/ir/ui/SpectrumRow.d.ts +7 -0
- package/lib/ir/ui/SpectrumRow.d.ts.map +1 -1
- package/lib/ir/ui/SpectrumRow.js +4 -5
- package/lib/ir/ui/SpectrumRow.js.map +1 -1
- package/lib/ir/ui/VibrationalEditor.d.ts +48 -0
- package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -0
- package/lib/ir/ui/VibrationalEditor.js +31 -0
- package/lib/ir/ui/VibrationalEditor.js.map +1 -0
- package/lib/ir/ui/bandsTsv.d.ts +19 -0
- package/lib/ir/ui/bandsTsv.d.ts.map +1 -0
- package/lib/ir/ui/bandsTsv.js +38 -0
- package/lib/ir/ui/bandsTsv.js.map +1 -0
- package/lib/ir/ui/irChartProps.d.ts +14 -4
- package/lib/ir/ui/irChartProps.d.ts.map +1 -1
- package/lib/ir/ui/irChartProps.js +3 -2
- package/lib/ir/ui/irChartProps.js.map +1 -1
- package/lib/ir/ui/irCommandContext.d.ts +8 -0
- package/lib/ir/ui/irCommandContext.d.ts.map +1 -1
- package/lib/ir/ui/irCommandContext.js +14 -3
- package/lib/ir/ui/irCommandContext.js.map +1 -1
- package/lib/ir/ui/useIrEditor.d.ts +3 -3
- package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
- package/lib/ir/ui/useIrEditor.js +13 -4
- package/lib/ir/ui/useIrEditor.js.map +1 -1
- package/lib/ir/ui/useIrHandle.d.ts +14 -0
- package/lib/ir/ui/useIrHandle.d.ts.map +1 -0
- package/lib/ir/ui/useIrHandle.js +39 -0
- package/lib/ir/ui/useIrHandle.js.map +1 -0
- package/lib/ir/ui/useIrText.d.ts +40 -0
- package/lib/ir/ui/useIrText.d.ts.map +1 -0
- package/lib/ir/ui/useIrText.js +118 -0
- package/lib/ir/ui/useIrText.js.map +1 -0
- package/lib/ir/ui/useIrZoom.d.ts +7 -0
- package/lib/ir/ui/useIrZoom.d.ts.map +1 -1
- package/lib/ir/ui/useIrZoom.js +5 -4
- package/lib/ir/ui/useIrZoom.js.map +1 -1
- package/lib/ir/ui/useValueAxisZoom.d.ts +20 -0
- package/lib/ir/ui/useValueAxisZoom.d.ts.map +1 -0
- package/lib/ir/ui/useValueAxisZoom.js +54 -0
- package/lib/ir/ui/useValueAxisZoom.js.map +1 -0
- package/lib/ir.d.ts +3 -0
- package/lib/ir.d.ts.map +1 -1
- package/lib/ir.js +3 -0
- package/lib/ir.js.map +1 -1
- package/lib/locales/de.json +57 -1
- package/lib/locales/en.json +57 -1
- package/lib/locales/es.json +57 -1
- package/lib/locales/fr.json +57 -1
- package/lib/locales/it.json +57 -1
- package/lib/moleculesClient/core/index.d.ts +5 -0
- package/lib/moleculesClient/core/index.d.ts.map +1 -0
- package/lib/moleculesClient/core/index.js +3 -0
- package/lib/moleculesClient/core/index.js.map +1 -0
- package/lib/moleculesClient/core/moleculesClient.d.ts +12 -0
- package/lib/moleculesClient/core/moleculesClient.d.ts.map +1 -0
- package/lib/moleculesClient/core/moleculesClient.js +105 -0
- package/lib/moleculesClient/core/moleculesClient.js.map +1 -0
- package/lib/moleculesClient/core/moleculesClientApi.d.ts +100 -0
- package/lib/moleculesClient/core/moleculesClientApi.d.ts.map +1 -0
- package/lib/moleculesClient/core/moleculesClientApi.js +20 -0
- package/lib/moleculesClient/core/moleculesClientApi.js.map +1 -0
- package/lib/moleculesClient/core/moleculesTypes.d.ts +154 -0
- package/lib/moleculesClient/core/moleculesTypes.d.ts.map +1 -0
- package/lib/moleculesClient/core/moleculesTypes.js +2 -0
- package/lib/moleculesClient/core/moleculesTypes.js.map +1 -0
- package/lib/moleculesClient/core/requestRetry.d.ts +50 -0
- package/lib/moleculesClient/core/requestRetry.d.ts.map +1 -0
- package/lib/moleculesClient/core/requestRetry.js +108 -0
- package/lib/moleculesClient/core/requestRetry.js.map +1 -0
- package/lib/molstar/core/camera.d.ts +2 -1
- package/lib/molstar/core/camera.d.ts.map +1 -1
- package/lib/molstar/core/camera.js +3 -2
- package/lib/molstar/core/camera.js.map +1 -1
- package/lib/molstar/core/framing.d.ts +102 -0
- package/lib/molstar/core/framing.d.ts.map +1 -0
- package/lib/molstar/core/framing.js +120 -0
- package/lib/molstar/core/framing.js.map +1 -0
- package/lib/molstar/core/hover.d.ts +16 -0
- package/lib/molstar/core/hover.d.ts.map +1 -1
- package/lib/molstar/core/hover.js +14 -0
- package/lib/molstar/core/hover.js.map +1 -1
- package/lib/molstar/core/index.d.ts +4 -1
- package/lib/molstar/core/index.d.ts.map +1 -1
- package/lib/molstar/core/index.js +2 -1
- package/lib/molstar/core/index.js.map +1 -1
- package/lib/pedagogy/core/answers.d.ts +46 -0
- package/lib/pedagogy/core/answers.d.ts.map +1 -0
- package/lib/pedagogy/core/answers.js +77 -0
- package/lib/pedagogy/core/answers.js.map +1 -0
- package/lib/pedagogy/core/attempts.d.ts +86 -0
- package/lib/pedagogy/core/attempts.d.ts.map +1 -0
- package/lib/pedagogy/core/attempts.js +117 -0
- package/lib/pedagogy/core/attempts.js.map +1 -0
- package/lib/pedagogy/core/index.d.ts +8 -0
- package/lib/pedagogy/core/index.d.ts.map +1 -1
- package/lib/pedagogy/core/index.js +4 -0
- package/lib/pedagogy/core/index.js.map +1 -1
- package/lib/pedagogy/core/progressController.d.ts +64 -0
- package/lib/pedagogy/core/progressController.d.ts.map +1 -0
- package/lib/pedagogy/core/progressController.js +56 -0
- package/lib/pedagogy/core/progressController.js.map +1 -0
- package/lib/pedagogy/core/seed.d.ts +96 -0
- package/lib/pedagogy/core/seed.d.ts.map +1 -0
- package/lib/pedagogy/core/seed.js +128 -0
- package/lib/pedagogy/core/seed.js.map +1 -0
- package/lib/pedagogy/core/series.d.ts +77 -0
- package/lib/pedagogy/core/series.d.ts.map +1 -0
- package/lib/pedagogy/core/series.js +10 -0
- package/lib/pedagogy/core/series.js.map +1 -0
- package/lib/pedagogy/ui/AnswerFields.d.ts +21 -0
- package/lib/pedagogy/ui/AnswerFields.d.ts.map +1 -0
- package/lib/pedagogy/ui/AnswerFields.js +24 -0
- package/lib/pedagogy/ui/AnswerFields.js.map +1 -0
- package/lib/pedagogy/ui/ExerciseList.d.ts +82 -0
- package/lib/pedagogy/ui/ExerciseList.d.ts.map +1 -0
- package/lib/pedagogy/ui/ExerciseList.js +53 -0
- package/lib/pedagogy/ui/ExerciseList.js.map +1 -0
- package/lib/pedagogy/ui/ExerciseSeries.d.ts +95 -0
- package/lib/pedagogy/ui/ExerciseSeries.d.ts.map +1 -0
- package/lib/pedagogy/ui/ExerciseSeries.js +74 -0
- package/lib/pedagogy/ui/ExerciseSeries.js.map +1 -0
- package/lib/pedagogy/ui/QuestionCard.d.ts +64 -0
- package/lib/pedagogy/ui/QuestionCard.d.ts.map +1 -0
- package/lib/pedagogy/ui/QuestionCard.js +73 -0
- package/lib/pedagogy/ui/QuestionCard.js.map +1 -0
- package/lib/pedagogy/ui/index.d.ts +10 -0
- package/lib/pedagogy/ui/index.d.ts.map +1 -1
- package/lib/pedagogy/ui/index.js +6 -0
- package/lib/pedagogy/ui/index.js.map +1 -1
- package/lib/pedagogy/ui/seriesCounts.d.ts +17 -0
- package/lib/pedagogy/ui/seriesCounts.d.ts.map +1 -0
- package/lib/pedagogy/ui/seriesCounts.js +27 -0
- package/lib/pedagogy/ui/seriesCounts.js.map +1 -0
- package/lib/pedagogy/ui/seriesParts.d.ts +55 -0
- package/lib/pedagogy/ui/seriesParts.d.ts.map +1 -0
- package/lib/pedagogy/ui/seriesParts.js +38 -0
- package/lib/pedagogy/ui/seriesParts.js.map +1 -0
- package/lib/pedagogy/ui/useAttemptRecords.d.ts +10 -0
- package/lib/pedagogy/ui/useAttemptRecords.d.ts.map +1 -0
- package/lib/pedagogy/ui/useAttemptRecords.js +11 -0
- package/lib/pedagogy/ui/useAttemptRecords.js.map +1 -0
- package/lib/periodic/ui/PeriodicTable.d.ts.map +1 -1
- package/lib/periodic/ui/PeriodicTable.js +6 -3
- package/lib/periodic/ui/PeriodicTable.js.map +1 -1
- package/lib/property/core/copyableText.d.ts +14 -0
- package/lib/property/core/copyableText.d.ts.map +1 -0
- package/lib/property/core/copyableText.js +21 -0
- package/lib/property/core/copyableText.js.map +1 -0
- package/lib/property/core/index.d.ts +2 -0
- package/lib/property/core/index.d.ts.map +1 -0
- package/lib/property/core/index.js +2 -0
- package/lib/property/core/index.js.map +1 -0
- package/lib/property/ui/PropertyTable.d.ts +43 -0
- package/lib/property/ui/PropertyTable.d.ts.map +1 -0
- package/lib/property/ui/PropertyTable.js +19 -0
- package/lib/property/ui/PropertyTable.js.map +1 -0
- package/lib/property/ui/index.d.ts +3 -0
- package/lib/property/ui/index.d.ts.map +1 -0
- package/lib/property/ui/index.js +2 -0
- package/lib/property/ui/index.js.map +1 -0
- package/lib/raman.d.ts +16 -0
- package/lib/raman.d.ts.map +1 -0
- package/lib/raman.js +12 -0
- package/lib/raman.js.map +1 -0
- package/lib/router/core/history.d.ts +24 -3
- package/lib/router/core/history.d.ts.map +1 -1
- package/lib/router/core/history.js +55 -7
- package/lib/router/core/history.js.map +1 -1
- package/lib/router/core/index.d.ts +3 -3
- package/lib/router/core/index.d.ts.map +1 -1
- package/lib/router/core/index.js +2 -2
- package/lib/router/core/index.js.map +1 -1
- package/lib/router/core/languageRoute.d.ts +61 -0
- package/lib/router/core/languageRoute.d.ts.map +1 -0
- package/lib/router/core/languageRoute.js +96 -0
- package/lib/router/core/languageRoute.js.map +1 -0
- package/lib/router/core/siteAddresses.d.ts +23 -0
- package/lib/router/core/siteAddresses.d.ts.map +1 -1
- package/lib/router/core/siteAddresses.js +26 -0
- package/lib/router/core/siteAddresses.js.map +1 -1
- package/lib/router/core/tabRouter.d.ts +2 -108
- package/lib/router/core/tabRouter.d.ts.map +1 -1
- package/lib/router/core/tabRouter.js +38 -5
- package/lib/router/core/tabRouter.js.map +1 -1
- package/lib/router/core/tabRouterTypes.d.ts +154 -0
- package/lib/router/core/tabRouterTypes.d.ts.map +1 -0
- package/lib/router/core/tabRouterTypes.js +2 -0
- package/lib/router/core/tabRouterTypes.js.map +1 -0
- package/lib/seo/core/fitDescription.d.ts +40 -0
- package/lib/seo/core/fitDescription.d.ts.map +1 -0
- package/lib/seo/core/fitDescription.js +45 -0
- package/lib/seo/core/fitDescription.js.map +1 -0
- package/lib/seo/core/index.d.ts +7 -0
- package/lib/seo/core/index.d.ts.map +1 -1
- package/lib/seo/core/index.js +4 -0
- package/lib/seo/core/index.js.map +1 -1
- package/lib/seo/core/limits.d.ts +24 -0
- package/lib/seo/core/limits.d.ts.map +1 -0
- package/lib/seo/core/limits.js +24 -0
- package/lib/seo/core/limits.js.map +1 -0
- package/lib/seo/core/pageContent.d.ts +25 -0
- package/lib/seo/core/pageContent.d.ts.map +1 -0
- package/lib/seo/core/pageContent.js +25 -0
- package/lib/seo/core/pageContent.js.map +1 -0
- package/lib/seo/core/plainDescription.d.ts.map +1 -1
- package/lib/seo/core/plainDescription.js +3 -2
- package/lib/seo/core/plainDescription.js.map +1 -1
- package/lib/seo/core/routeProblems.d.ts.map +1 -1
- package/lib/seo/core/routeProblems.js +1 -6
- package/lib/seo/core/routeProblems.js.map +1 -1
- package/lib/seo/core/routeTable.d.ts +31 -0
- package/lib/seo/core/routeTable.d.ts.map +1 -0
- package/lib/seo/core/routeTable.js +96 -0
- package/lib/seo/core/routeTable.js.map +1 -0
- package/lib/seo/vite/index.d.ts +2 -0
- package/lib/seo/vite/index.d.ts.map +1 -1
- package/lib/seo/vite/index.js +1 -0
- package/lib/seo/vite/index.js.map +1 -1
- package/lib/seo/vite/prerender.d.ts +10 -0
- package/lib/seo/vite/prerender.d.ts.map +1 -1
- package/lib/seo/vite/prerender.js +12 -1
- package/lib/seo/vite/prerender.js.map +1 -1
- package/lib/seo/vite/routeTable.d.ts +40 -0
- package/lib/seo/vite/routeTable.d.ts.map +1 -0
- package/lib/seo/vite/routeTable.js +44 -0
- package/lib/seo/vite/routeTable.js.map +1 -0
- package/lib/server/answerAddresses.d.ts +51 -0
- package/lib/server/answerAddresses.d.ts.map +1 -0
- package/lib/server/answerAddresses.js +72 -0
- package/lib/server/answerAddresses.js.map +1 -0
- package/lib/server/cardMeta.d.ts +57 -0
- package/lib/server/cardMeta.d.ts.map +1 -0
- package/lib/server/cardMeta.js +52 -0
- package/lib/server/cardMeta.js.map +1 -0
- package/lib/server/config.d.ts +72 -0
- package/lib/server/config.d.ts.map +1 -0
- package/lib/server/config.js +67 -0
- package/lib/server/config.js.map +1 -0
- package/lib/server/envNumber.d.ts +35 -0
- package/lib/server/envNumber.d.ts.map +1 -0
- package/lib/server/envNumber.js +42 -0
- package/lib/server/envNumber.js.map +1 -0
- package/lib/server/healthRoute.d.ts +26 -0
- package/lib/server/healthRoute.d.ts.map +1 -0
- package/lib/server/healthRoute.js +22 -0
- package/lib/server/healthRoute.js.map +1 -0
- package/lib/server/listenSite.d.ts +38 -0
- package/lib/server/listenSite.d.ts.map +1 -0
- package/lib/server/listenSite.js +60 -0
- package/lib/server/listenSite.js.map +1 -0
- package/lib/server/mcpServer.d.ts +8 -0
- package/lib/server/mcpServer.d.ts.map +1 -0
- package/lib/server/mcpServer.js +11 -0
- package/lib/server/mcpServer.js.map +1 -0
- package/lib/server/repositoryVersion.d.ts +16 -0
- package/lib/server/repositoryVersion.d.ts.map +1 -0
- package/lib/server/repositoryVersion.js +33 -0
- package/lib/server/repositoryVersion.js.map +1 -0
- package/lib/server/routeOptions.d.ts +23 -0
- package/lib/server/routeOptions.d.ts.map +1 -0
- package/lib/server/routeOptions.js +20 -0
- package/lib/server/routeOptions.js.map +1 -0
- package/lib/server/routeTable.d.ts +14 -0
- package/lib/server/routeTable.d.ts.map +1 -0
- package/lib/server/routeTable.js +32 -0
- package/lib/server/routeTable.js.map +1 -0
- package/lib/server/siteView.d.ts +29 -0
- package/lib/server/siteView.d.ts.map +1 -0
- package/lib/server/siteView.js +21 -0
- package/lib/server/siteView.js.map +1 -0
- package/lib/server/spaPages.d.ts +32 -0
- package/lib/server/spaPages.d.ts.map +1 -0
- package/lib/server/spaPages.js +126 -0
- package/lib/server/spaPages.js.map +1 -0
- package/lib/server/spaSite.d.ts +30 -0
- package/lib/server/spaSite.d.ts.map +1 -0
- package/lib/server/spaSite.js +170 -0
- package/lib/server/spaSite.js.map +1 -0
- package/lib/server/spaSiteOptions.d.ts +126 -0
- package/lib/server/spaSiteOptions.d.ts.map +1 -0
- package/lib/server/spaSiteOptions.js +2 -0
- package/lib/server/spaSiteOptions.js.map +1 -0
- package/lib/server/staticSite.d.ts +9 -0
- package/lib/server/staticSite.d.ts.map +1 -1
- package/lib/server/staticSite.js +41 -19
- package/lib/server/staticSite.js.map +1 -1
- package/lib/server/toolSiteServer.d.ts +77 -0
- package/lib/server/toolSiteServer.d.ts.map +1 -0
- package/lib/server/toolSiteServer.js +58 -0
- package/lib/server/toolSiteServer.js.map +1 -0
- package/lib/server/trustProxy.d.ts +20 -0
- package/lib/server/trustProxy.d.ts.map +1 -0
- package/lib/server/trustProxy.js +32 -0
- package/lib/server/trustProxy.js.map +1 -0
- package/lib/server/types.d.ts +13 -0
- package/lib/server/types.d.ts.map +1 -0
- package/lib/server/types.js +2 -0
- package/lib/server/types.js.map +1 -0
- package/lib/server.d.ts +22 -0
- package/lib/server.d.ts.map +1 -1
- package/lib/server.js +12 -0
- package/lib/server.js.map +1 -1
- package/lib/share/core/config.d.ts +18 -0
- package/lib/share/core/config.d.ts.map +1 -1
- package/lib/share/core/config.js +33 -2
- package/lib/share/core/config.js.map +1 -1
- package/lib/share/core/index.d.ts +3 -1
- package/lib/share/core/index.d.ts.map +1 -1
- package/lib/share/core/index.js +2 -1
- package/lib/share/core/index.js.map +1 -1
- package/lib/share/core/keySetParam.d.ts +40 -0
- package/lib/share/core/keySetParam.d.ts.map +1 -0
- package/lib/share/core/keySetParam.js +60 -0
- package/lib/share/core/keySetParam.js.map +1 -0
- package/lib/share/core/vocabulary.d.ts +8 -0
- package/lib/share/core/vocabulary.d.ts.map +1 -1
- package/lib/shell/ui/ShareControl.d.ts +75 -0
- package/lib/shell/ui/ShareControl.d.ts.map +1 -0
- package/lib/shell/ui/ShareControl.js +40 -0
- package/lib/shell/ui/ShareControl.js.map +1 -0
- package/lib/shell/ui/ShellFrame.d.ts +14 -0
- package/lib/shell/ui/ShellFrame.d.ts.map +1 -0
- package/lib/shell/ui/ShellFrame.js +45 -0
- package/lib/shell/ui/ShellFrame.js.map +1 -0
- package/lib/shell/ui/SiteShell.d.ts +251 -0
- package/lib/shell/ui/SiteShell.d.ts.map +1 -0
- package/lib/shell/ui/SiteShell.js +39 -0
- package/lib/shell/ui/SiteShell.js.map +1 -0
- package/lib/shell/ui/index.d.ts +5 -0
- package/lib/shell/ui/index.d.ts.map +1 -0
- package/lib/shell/ui/index.js +3 -0
- package/lib/shell/ui/index.js.map +1 -0
- package/lib/state/core/index.d.ts +1 -0
- package/lib/state/core/index.d.ts.map +1 -1
- package/lib/state/core/index.js.map +1 -1
- package/lib/state/core/legacyEntries.d.ts +30 -0
- package/lib/state/core/legacyEntries.d.ts.map +1 -0
- package/lib/state/core/legacyEntries.js +51 -0
- package/lib/state/core/legacyEntries.js.map +1 -0
- package/lib/state/core/persistBucket.d.ts +26 -2
- package/lib/state/core/persistBucket.d.ts.map +1 -1
- package/lib/state/core/persistBucket.js +26 -9
- package/lib/state/core/persistBucket.js.map +1 -1
- package/lib/state/core/persistSignalBucket.d.ts +26 -0
- package/lib/state/core/persistSignalBucket.d.ts.map +1 -1
- package/lib/state/core/persistSignalBucket.js +31 -0
- package/lib/state/core/persistSignalBucket.js.map +1 -1
- package/lib/state/core/storageEntry.d.ts +15 -0
- package/lib/state/core/storageEntry.d.ts.map +1 -1
- package/lib/state/core/storageEntry.js +33 -0
- package/lib/state/core/storageEntry.js.map +1 -1
- package/lib/structure/ui/StructureExportButton.d.ts +27 -0
- package/lib/structure/ui/StructureExportButton.d.ts.map +1 -0
- package/lib/structure/ui/StructureExportButton.js +21 -0
- package/lib/structure/ui/StructureExportButton.js.map +1 -0
- package/lib/structure/ui/index.d.ts +4 -0
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js +2 -0
- package/lib/structure/ui/index.js.map +1 -1
- package/lib/structure/ui/useStructureDraft.d.ts +32 -0
- package/lib/structure/ui/useStructureDraft.d.ts.map +1 -0
- package/lib/structure/ui/useStructureDraft.js +20 -0
- package/lib/structure/ui/useStructureDraft.js.map +1 -0
- package/lib/ui.d.ts +2 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +2 -0
- package/lib/ui.js.map +1 -1
- package/lib/worker/core/index.d.ts +1 -1
- package/lib/worker/core/index.d.ts.map +1 -1
- package/lib/worker/core/messages.d.ts +4 -2
- package/lib/worker/core/messages.d.ts.map +1 -1
- package/lib/worker/core/messages.js.map +1 -1
- package/lib/worker/core/oclResourcesUrl.d.ts +16 -0
- package/lib/worker/core/oclResourcesUrl.d.ts.map +1 -0
- package/lib/worker/core/oclResourcesUrl.js +19 -0
- package/lib/worker/core/oclResourcesUrl.js.map +1 -0
- package/lib/worker/core/serveWorkerRequests.d.ts +8 -0
- package/lib/worker/core/serveWorkerRequests.d.ts.map +1 -1
- package/lib/worker/core/serveWorkerRequests.js +15 -2
- package/lib/worker/core/serveWorkerRequests.js.map +1 -1
- package/lib/worker/core/workerChannel.d.ts +3 -4
- package/lib/worker/core/workerChannel.d.ts.map +1 -1
- package/lib/worker/core/workerChannel.js +72 -67
- package/lib/worker/core/workerChannel.js.map +1 -1
- package/lib/worker/core/workerChannelParts.d.ts +17 -6
- package/lib/worker/core/workerChannelParts.d.ts.map +1 -1
- package/lib/worker/core/workerChannelParts.js +20 -4
- package/lib/worker/core/workerChannelParts.js.map +1 -1
- package/lib/worker/core/workerChannelTypes.d.ts +46 -2
- package/lib/worker/core/workerChannelTypes.d.ts.map +1 -1
- package/lib/worker/core/workerSlot.d.ts +66 -0
- package/lib/worker/core/workerSlot.d.ts.map +1 -0
- package/lib/worker/core/workerSlot.js +107 -0
- package/lib/worker/core/workerSlot.js.map +1 -0
- package/package.json +17 -1
- package/src/card/core/cardAddress.ts +100 -0
- package/src/card/core/cardPageUrl.ts +97 -0
- package/src/card/core/index.ts +6 -0
- package/src/card/core/panelRoom.ts +66 -0
- package/src/card/ui/CardDetailsButton.tsx +104 -0
- package/src/card/ui/CardFigure.tsx +86 -0
- package/src/card/ui/CardFrame.tsx +46 -0
- package/src/card/ui/CopyTableButton.tsx +81 -0
- package/src/card/ui/cardTooltip.ts +18 -0
- package/src/card/ui/embed.ts +27 -0
- package/src/card/ui/fitCardToFrame.ts +76 -0
- package/src/card/ui/holdRoomForPanels.ts +83 -0
- package/src/card/ui/index.ts +14 -0
- package/src/card/ui/openPanels.ts +106 -0
- package/src/card.ts +13 -0
- package/src/conformers.ts +4 -0
- package/src/core.ts +5 -0
- package/src/fetch/core/apiError.ts +65 -0
- package/src/fetch/core/fetchJson.ts +129 -0
- package/src/fetch/core/index.ts +4 -0
- package/src/formula/core/formulaText.ts +96 -0
- package/src/formula/core/index.ts +20 -0
- package/src/formula/core/normalizeFormula.ts +50 -0
- package/src/formula/core/readFormula.ts +211 -0
- package/src/formula/ui/CopyableFormula.tsx +51 -0
- package/src/formula/ui/FormulaInput.tsx +50 -0
- package/src/formula/ui/QuestionFormula.tsx +20 -0
- package/src/formula/ui/index.ts +6 -0
- package/src/formula.ts +11 -0
- package/src/hooks/ui/index.ts +1 -0
- package/src/hooks/ui/keyTargets.ts +5 -3
- package/src/hooks/ui/useAsync.ts +50 -14
- package/src/ir/core/analysisSpectra.ts +26 -10
- package/src/ir/core/bandLabelPlan.ts +21 -10
- package/src/ir/core/index.ts +25 -5
- package/src/ir/core/irBand.ts +52 -14
- package/src/ir/core/irCommands.ts +15 -1
- package/src/ir/core/irDomain.ts +9 -7
- package/src/ir/core/irFormat.ts +39 -6
- package/src/ir/core/irMode.ts +42 -10
- package/src/ir/core/irReducer.ts +1 -49
- package/src/ir/core/irSpectrum.ts +59 -30
- package/src/ir/core/irState.ts +67 -2
- package/src/ir/core/irTechnique.ts +115 -0
- package/src/ir/core/irTechniqueCommands.ts +82 -0
- package/src/ir/core/pickBands.ts +63 -28
- package/src/ir/core/ramanBands.ts +105 -0
- package/src/ir/core/spectrumJcamp.ts +65 -16
- package/src/ir/core/toIrSpectrum.ts +20 -2
- package/src/ir/ui/BandRow.tsx +107 -0
- package/src/ir/ui/BandsPanel.tsx +32 -125
- package/src/ir/ui/IrAboutDialog.tsx +69 -28
- package/src/ir/ui/IrCanvas.tsx +2 -1
- package/src/ir/ui/IrChart.tsx +20 -24
- package/src/ir/ui/IrCommandProvider.tsx +10 -3
- package/src/ir/ui/IrCommandTooltip.tsx +11 -2
- package/src/ir/ui/IrDocumentationDialog.tsx +99 -55
- package/src/ir/ui/IrEditor.tsx +5 -36
- package/src/ir/ui/IrHeader.tsx +10 -3
- package/src/ir/ui/IrLogo.tsx +28 -9
- package/src/ir/ui/IrShell.tsx +27 -75
- package/src/ir/ui/IrStatusBar.tsx +17 -12
- package/src/ir/ui/IrToolbar.tsx +26 -15
- package/src/ir/ui/IrTraces.tsx +5 -1
- package/src/ir/ui/RamanEditor.tsx +53 -0
- package/src/ir/ui/SpectraPanel.tsx +2 -1
- package/src/ir/ui/SpectrumRow.tsx +14 -5
- package/src/ir/ui/VibrationalEditor.tsx +94 -0
- package/src/ir/ui/bandsTsv.ts +46 -0
- package/src/ir/ui/irChartProps.ts +14 -4
- package/src/ir/ui/irCommandContext.tsx +18 -3
- package/src/ir/ui/useIrEditor.ts +20 -8
- package/src/ir/ui/useIrHandle.ts +51 -0
- package/src/ir/ui/useIrText.ts +170 -0
- package/src/ir/ui/useIrZoom.ts +12 -3
- package/src/ir/ui/useValueAxisZoom.ts +67 -0
- package/src/ir.ts +3 -0
- package/src/locales/de.json +57 -1
- package/src/locales/en.json +57 -1
- package/src/locales/es.json +57 -1
- package/src/locales/fr.json +57 -1
- package/src/locales/it.json +57 -1
- package/src/moleculesClient/core/index.ts +19 -0
- package/src/moleculesClient/core/moleculesClient.ts +175 -0
- package/src/moleculesClient/core/moleculesClientApi.ts +120 -0
- package/src/moleculesClient/core/moleculesTypes.ts +163 -0
- package/src/moleculesClient/core/requestRetry.ts +118 -0
- package/src/molstar/core/camera.ts +3 -2
- package/src/molstar/core/framing.ts +200 -0
- package/src/molstar/core/hover.ts +26 -0
- package/src/molstar/core/index.ts +21 -1
- package/src/pedagogy/core/answers.ts +94 -0
- package/src/pedagogy/core/attempts.ts +205 -0
- package/src/pedagogy/core/index.ts +36 -0
- package/src/pedagogy/core/progressController.ts +116 -0
- package/src/pedagogy/core/seed.ts +177 -0
- package/src/pedagogy/core/series.ts +82 -0
- package/src/pedagogy/ui/AnswerFields.tsx +63 -0
- package/src/pedagogy/ui/ExerciseList.tsx +202 -0
- package/src/pedagogy/ui/ExerciseSeries.tsx +250 -0
- package/src/pedagogy/ui/QuestionCard.tsx +231 -0
- package/src/pedagogy/ui/index.ts +18 -0
- package/src/pedagogy/ui/seriesCounts.ts +34 -0
- package/src/pedagogy/ui/seriesParts.tsx +127 -0
- package/src/pedagogy/ui/useAttemptRecords.ts +16 -0
- package/src/periodic/ui/PeriodicTable.tsx +6 -3
- package/src/property/core/copyableText.ts +20 -0
- package/src/property/core/index.ts +1 -0
- package/src/property/ui/PropertyTable.tsx +83 -0
- package/src/property/ui/index.ts +2 -0
- package/src/raman.ts +19 -0
- package/src/router/core/history.ts +61 -7
- package/src/router/core/index.ts +3 -2
- package/src/router/core/languageRoute.ts +136 -0
- package/src/router/core/siteAddresses.ts +38 -0
- package/src/router/core/tabRouter.ts +59 -117
- package/src/router/core/tabRouterTypes.ts +158 -0
- package/src/seo/core/fitDescription.ts +74 -0
- package/src/seo/core/index.ts +17 -0
- package/src/seo/core/limits.ts +27 -0
- package/src/seo/core/pageContent.ts +42 -0
- package/src/seo/core/plainDescription.ts +4 -2
- package/src/seo/core/routeProblems.ts +1 -7
- package/src/seo/core/routeTable.ts +103 -0
- package/src/seo/vite/index.ts +2 -0
- package/src/seo/vite/prerender.ts +26 -1
- package/src/seo/vite/routeTable.ts +79 -0
- package/src/server/answerAddresses.ts +92 -0
- package/src/server/cardMeta.ts +88 -0
- package/src/server/config.ts +125 -0
- package/src/server/envNumber.ts +65 -0
- package/src/server/healthRoute.ts +42 -0
- package/src/server/listenSite.ts +90 -0
- package/src/server/mcpServer.ts +14 -0
- package/src/server/repositoryVersion.ts +33 -0
- package/src/server/routeOptions.ts +26 -0
- package/src/server/routeTable.ts +35 -0
- package/src/server/siteView.ts +42 -0
- package/src/server/spaPages.ts +179 -0
- package/src/server/spaSite.ts +216 -0
- package/src/server/spaSiteOptions.ts +133 -0
- package/src/server/staticSite.ts +65 -35
- package/src/server/toolSiteServer.ts +127 -0
- package/src/server/trustProxy.ts +32 -0
- package/src/server/types.ts +25 -0
- package/src/server.ts +40 -0
- package/src/share/core/config.ts +45 -2
- package/src/share/core/index.ts +4 -0
- package/src/share/core/keySetParam.ts +92 -0
- package/src/share/core/vocabulary.ts +8 -0
- package/src/shell/ui/ShareControl.tsx +150 -0
- package/src/shell/ui/ShellFrame.tsx +180 -0
- package/src/shell/ui/SiteShell.tsx +297 -0
- package/src/shell/ui/index.ts +9 -0
- package/src/state/core/index.ts +1 -0
- package/src/state/core/legacyEntries.ts +76 -0
- package/src/state/core/persistBucket.ts +50 -10
- package/src/state/core/persistSignalBucket.ts +52 -0
- package/src/state/core/storageEntry.ts +32 -0
- package/src/structure/ui/StructureExportButton.tsx +57 -0
- package/src/structure/ui/index.ts +4 -0
- package/src/structure/ui/useStructureDraft.ts +47 -0
- package/src/ui.ts +2 -0
- package/src/worker/core/index.ts +1 -0
- package/src/worker/core/messages.ts +4 -3
- package/src/worker/core/oclResourcesUrl.ts +21 -0
- package/src/worker/core/serveWorkerRequests.ts +30 -2
- package/src/worker/core/workerChannel.ts +74 -74
- package/src/worker/core/workerChannelParts.ts +33 -13
- package/src/worker/core/workerChannelTypes.ts +47 -2
- package/src/worker/core/workerSlot.ts +181 -0
- package/styles/card.css +145 -0
- package/styles/chrome.css +248 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
2
|
+
import { useEffect, useEffectEvent, useMemo, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
import { useDocumentListNavigation } from '../../hooks/ui/useDocumentListNavigation.ts';
|
|
5
|
+
import type { SplitRange } from '../../split/core/split.ts';
|
|
6
|
+
import { clampSplit } from '../../split/core/split.ts';
|
|
7
|
+
import { SplitRow } from '../../split/ui/SplitRow.tsx';
|
|
8
|
+
import type { AttemptStore } from '../core/attempts.ts';
|
|
9
|
+
import { attemptKey } from '../core/attempts.ts';
|
|
10
|
+
import { progressSummary } from '../core/progress.ts';
|
|
11
|
+
import type { PickSeededOptions, SeedRange } from '../core/seed.ts';
|
|
12
|
+
import { freshSeed, pickSeeded } from '../core/seed.ts';
|
|
13
|
+
import type { SeriesTool } from '../core/series.ts';
|
|
14
|
+
|
|
15
|
+
import { ExerciseProgressHeader } from './ExerciseProgressHeader.tsx';
|
|
16
|
+
import type { QuestionRendering } from './QuestionCard.tsx';
|
|
17
|
+
import { QuestionCard } from './QuestionCard.tsx';
|
|
18
|
+
import { SeriesHead, SeriesQuestionList } from './seriesParts.tsx';
|
|
19
|
+
import { useAttemptRecords } from './useAttemptRecords.ts';
|
|
20
|
+
|
|
21
|
+
/** What {@link ExerciseSeries} needs. */
|
|
22
|
+
export interface ExerciseSeriesProps<
|
|
23
|
+
Question,
|
|
24
|
+
> extends QuestionRendering<Question> {
|
|
25
|
+
/** The tool the series is drawn from. */
|
|
26
|
+
tool: SeriesTool<Question>;
|
|
27
|
+
/** Where the attempts, and the series each tool was last on, are kept. */
|
|
28
|
+
store: AttemptStore;
|
|
29
|
+
/** How a question is named in the list beside the card. */
|
|
30
|
+
label: (question: Question) => ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* The seed the address names, read with `parseSeed`, or `null` when it names
|
|
33
|
+
* none — the series this browser was last on is then written into it.
|
|
34
|
+
*/
|
|
35
|
+
seed: number | null;
|
|
36
|
+
/**
|
|
37
|
+
* Write a seed into the address: `replace` when the page adopts one it was
|
|
38
|
+
* opened without, `push` when the student draws a new series, so Back
|
|
39
|
+
* returns to the previous one.
|
|
40
|
+
*/
|
|
41
|
+
onSeed: (seed: number, history: 'replace' | 'push') => void;
|
|
42
|
+
/** How many questions the student asked for; the pool caps it. */
|
|
43
|
+
count: number;
|
|
44
|
+
/** Change how many questions the series holds. */
|
|
45
|
+
onCount: (count: number) => void;
|
|
46
|
+
/**
|
|
47
|
+
* The lengths offered, beside the whole pool.
|
|
48
|
+
* @default [5, 10, 15, 20]
|
|
49
|
+
*/
|
|
50
|
+
counts?: readonly number[];
|
|
51
|
+
/**
|
|
52
|
+
* The share of the row the list takes, as the address names it, or `null`
|
|
53
|
+
* for {@link ExerciseSeriesProps.defaultSplit}.
|
|
54
|
+
*/
|
|
55
|
+
split: number | null;
|
|
56
|
+
/** Write the share a drag came to rest at, or `null` for the default. */
|
|
57
|
+
onSplit: (split: number | null) => void;
|
|
58
|
+
/**
|
|
59
|
+
* The share the list opens at: the card is the figure, so the list opens
|
|
60
|
+
* narrow.
|
|
61
|
+
* @default 22
|
|
62
|
+
*/
|
|
63
|
+
defaultSplit?: number;
|
|
64
|
+
/**
|
|
65
|
+
* How far the list may be dragged, measured on the labels of the pool.
|
|
66
|
+
* @default { min: 15, max: 26 }
|
|
67
|
+
*/
|
|
68
|
+
splitRange?: SplitRange;
|
|
69
|
+
/**
|
|
70
|
+
* The narrowest row still divided, in pixels; under it the list stacks under
|
|
71
|
+
* the card's row, as on a tablet held upright.
|
|
72
|
+
* @default SplitRow's own, 860
|
|
73
|
+
*/
|
|
74
|
+
stackBelow?: number;
|
|
75
|
+
/**
|
|
76
|
+
* How the series is drawn from the pool, for a site whose links were written
|
|
77
|
+
* with the other generator call.
|
|
78
|
+
* @default { draw: 'getFloat', wrap: false }
|
|
79
|
+
*/
|
|
80
|
+
pick?: PickSeededOptions;
|
|
81
|
+
/**
|
|
82
|
+
* The seeds a new series is drawn from.
|
|
83
|
+
* @default every unsigned 32-bit integer
|
|
84
|
+
*/
|
|
85
|
+
seedRange?: SeedRange;
|
|
86
|
+
/**
|
|
87
|
+
* The heading over the series.
|
|
88
|
+
* @default the chrome's own word for it, in the language of the page
|
|
89
|
+
*/
|
|
90
|
+
title?: ReactNode;
|
|
91
|
+
/**
|
|
92
|
+
* Id of the heading, for a section labelled by it.
|
|
93
|
+
* @default 'questions-heading'
|
|
94
|
+
*/
|
|
95
|
+
headingId?: string;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const DEFAULT_RANGE: SplitRange = { min: 15, max: 26 };
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* A graded series drawn from a tool's pool: the list of its questions, the one
|
|
102
|
+
* open, and the progress over the series.
|
|
103
|
+
*
|
|
104
|
+
* The series is its seed, and the seed is in the address, so the link on
|
|
105
|
+
* screen reopens the same questions for anyone — a teacher hands one series to
|
|
106
|
+
* a whole class. How the row is divided between the list and the open question
|
|
107
|
+
* travels in the address too. The component reads neither: the page hands it
|
|
108
|
+
* the seed, the length and the share, and is told when one changes.
|
|
109
|
+
* @param props - The tool, where its attempts are kept, the address values,
|
|
110
|
+
* and how to draw a question.
|
|
111
|
+
* @returns The series.
|
|
112
|
+
*/
|
|
113
|
+
export function ExerciseSeries<Question>(
|
|
114
|
+
props: ExerciseSeriesProps<Question>,
|
|
115
|
+
): ReactElement {
|
|
116
|
+
const {
|
|
117
|
+
tool,
|
|
118
|
+
store,
|
|
119
|
+
label,
|
|
120
|
+
seed: addressSeed,
|
|
121
|
+
onSeed,
|
|
122
|
+
count: wanted,
|
|
123
|
+
onCount,
|
|
124
|
+
counts,
|
|
125
|
+
split,
|
|
126
|
+
onSplit,
|
|
127
|
+
defaultSplit = 22,
|
|
128
|
+
splitRange = DEFAULT_RANGE,
|
|
129
|
+
stackBelow,
|
|
130
|
+
pick,
|
|
131
|
+
seedRange,
|
|
132
|
+
title,
|
|
133
|
+
headingId = 'questions-heading',
|
|
134
|
+
...rendering
|
|
135
|
+
} = props;
|
|
136
|
+
const records = useAttemptRecords(store);
|
|
137
|
+
const [fallbackSeed] = useState(
|
|
138
|
+
() => store.storedSeed(tool.id) ?? freshSeed(seedRange),
|
|
139
|
+
);
|
|
140
|
+
const seed = addressSeed ?? fallbackSeed;
|
|
141
|
+
const poolSize = tool.maxCount ?? tool.pool.length;
|
|
142
|
+
const count = Math.min(wanted, poolSize);
|
|
143
|
+
|
|
144
|
+
// The address is what the series is read from and handed out as, so a page
|
|
145
|
+
// opened without a seed writes the one it fell back on into it; and the
|
|
146
|
+
// series on screen is the one this tool reopens on the next visit.
|
|
147
|
+
const followSeed = useEffectEvent((): void => {
|
|
148
|
+
if (addressSeed === null) onSeed(fallbackSeed, 'replace');
|
|
149
|
+
store.storeSeed(tool.id, addressSeed ?? fallbackSeed);
|
|
150
|
+
});
|
|
151
|
+
useEffect(() => {
|
|
152
|
+
followSeed();
|
|
153
|
+
}, [seed, addressSeed, tool.id]);
|
|
154
|
+
|
|
155
|
+
const series = useMemo(
|
|
156
|
+
() =>
|
|
157
|
+
tool.draw === undefined
|
|
158
|
+
? pickSeeded(tool.pool, count, seed, pick)
|
|
159
|
+
: tool.draw(count, seed),
|
|
160
|
+
[tool, count, seed, pick],
|
|
161
|
+
);
|
|
162
|
+
const keys = useMemo(
|
|
163
|
+
() =>
|
|
164
|
+
series.map((question) => attemptKey(tool.id, seed, tool.key(question))),
|
|
165
|
+
[series, tool, seed],
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const [opened, setOpened] = useState({ seed, index: 0 });
|
|
169
|
+
const index =
|
|
170
|
+
opened.seed === seed ? Math.min(opened.index, series.length - 1) : 0;
|
|
171
|
+
function open(next: number): void {
|
|
172
|
+
setOpened({ seed, index: next });
|
|
173
|
+
}
|
|
174
|
+
const listRef = useDocumentListNavigation<HTMLElement>({
|
|
175
|
+
length: series.length,
|
|
176
|
+
selectedIndex: index,
|
|
177
|
+
onSelect: open,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const summary = progressSummary(records, keys);
|
|
181
|
+
const question = series[index];
|
|
182
|
+
const storageKey = keys[index];
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
<div className="exercise-series">
|
|
186
|
+
<SeriesHead
|
|
187
|
+
title={title}
|
|
188
|
+
headingId={headingId}
|
|
189
|
+
count={count}
|
|
190
|
+
poolSize={poolSize}
|
|
191
|
+
counts={counts}
|
|
192
|
+
onCount={onCount}
|
|
193
|
+
onNewSeries={() => {
|
|
194
|
+
const next = freshSeed(seedRange);
|
|
195
|
+
store.forgetOtherSeries(tool.id, next);
|
|
196
|
+
onSeed(next, 'push');
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
|
|
200
|
+
<ExerciseProgressHeader
|
|
201
|
+
summary={summary}
|
|
202
|
+
onClearAll={() => {
|
|
203
|
+
store.clearAttempts(keys);
|
|
204
|
+
}}
|
|
205
|
+
clearDisabled={!keys.some((key) => records[key] !== undefined)}
|
|
206
|
+
/>
|
|
207
|
+
|
|
208
|
+
<SplitRow
|
|
209
|
+
ratio={split === null ? null : clampSplit(split, splitRange)}
|
|
210
|
+
defaultRatio={defaultSplit}
|
|
211
|
+
min={splitRange.min}
|
|
212
|
+
max={splitRange.max}
|
|
213
|
+
stackBelow={stackBelow}
|
|
214
|
+
onRatio={onSplit}
|
|
215
|
+
start={
|
|
216
|
+
<SeriesQuestionList
|
|
217
|
+
series={series}
|
|
218
|
+
keys={keys}
|
|
219
|
+
records={records}
|
|
220
|
+
index={index}
|
|
221
|
+
onOpen={open}
|
|
222
|
+
label={label}
|
|
223
|
+
listRef={listRef}
|
|
224
|
+
/>
|
|
225
|
+
}
|
|
226
|
+
end={
|
|
227
|
+
question === undefined || storageKey === undefined ? null : (
|
|
228
|
+
<QuestionCard
|
|
229
|
+
key={storageKey}
|
|
230
|
+
tool={tool}
|
|
231
|
+
question={question}
|
|
232
|
+
store={store}
|
|
233
|
+
storageKey={storageKey}
|
|
234
|
+
number={index + 1}
|
|
235
|
+
total={series.length}
|
|
236
|
+
onNext={
|
|
237
|
+
index + 1 < series.length
|
|
238
|
+
? () => {
|
|
239
|
+
open(index + 1);
|
|
240
|
+
}
|
|
241
|
+
: undefined
|
|
242
|
+
}
|
|
243
|
+
{...rendering}
|
|
244
|
+
/>
|
|
245
|
+
)
|
|
246
|
+
}
|
|
247
|
+
/>
|
|
248
|
+
</div>
|
|
249
|
+
);
|
|
250
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { Button, Callout, Tag } from '@blueprintjs/core';
|
|
2
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { useIsHidden } from '../../share/ui/hiddenParts.ts';
|
|
7
|
+
import type { AttemptStore } from '../core/attempts.ts';
|
|
8
|
+
import { emptyAttempt } from '../core/attempts.ts';
|
|
9
|
+
import type { Answers, FieldCase, SeriesTool } from '../core/series.ts';
|
|
10
|
+
|
|
11
|
+
import { AnswerFields } from './AnswerFields.tsx';
|
|
12
|
+
import { ExerciseActions } from './ExerciseActions.tsx';
|
|
13
|
+
import { GlossaryText } from './GlossaryText.tsx';
|
|
14
|
+
import { HintLadder } from './HintLadder.tsx';
|
|
15
|
+
import { TestCaseList } from './TestCaseList.tsx';
|
|
16
|
+
import { LEVEL_INTENT } from './exerciseMeta.ts';
|
|
17
|
+
import { useAttemptRecords } from './useAttemptRecords.ts';
|
|
18
|
+
|
|
19
|
+
/** What a tool's own answer input is handed. */
|
|
20
|
+
export interface AnswerInputProps<Question> {
|
|
21
|
+
/** The question being answered. */
|
|
22
|
+
question: Question;
|
|
23
|
+
/** What is typed so far, field by field. */
|
|
24
|
+
answers: Answers;
|
|
25
|
+
/** Change one field. */
|
|
26
|
+
onChange: (key: string, value: string) => void;
|
|
27
|
+
/** Check the answer, as Enter does in a box. */
|
|
28
|
+
onSubmit: () => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** How one tool draws the parts of a question the card does not know. */
|
|
32
|
+
export interface QuestionRendering<Question> {
|
|
33
|
+
/** The statement of the question. */
|
|
34
|
+
prompt: (question: Question) => ReactNode;
|
|
35
|
+
/**
|
|
36
|
+
* An input of the tool's own — a drawing canvas, a reaction to balance — in
|
|
37
|
+
* place of the typed boxes.
|
|
38
|
+
* @default undefined — one box per field of the tool
|
|
39
|
+
*/
|
|
40
|
+
answer?: (props: AnswerInputProps<Question>) => ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* What the solution shows beyond its text, such as a drawn structure.
|
|
43
|
+
* @default undefined
|
|
44
|
+
*/
|
|
45
|
+
solution?: (question: Question) => ReactNode;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** What {@link QuestionCard} needs. */
|
|
49
|
+
export interface QuestionCardProps<
|
|
50
|
+
Question,
|
|
51
|
+
> extends QuestionRendering<Question> {
|
|
52
|
+
/** The tool the question belongs to. */
|
|
53
|
+
tool: SeriesTool<Question>;
|
|
54
|
+
/** The question on the card. */
|
|
55
|
+
question: Question;
|
|
56
|
+
/** Where the attempts are kept. */
|
|
57
|
+
store: AttemptStore;
|
|
58
|
+
/** The key this question's attempt is kept under, from `attemptKey`. */
|
|
59
|
+
storageKey: string;
|
|
60
|
+
/** Its position in the series, counted from 1. */
|
|
61
|
+
number: number;
|
|
62
|
+
/** How many questions the series holds. */
|
|
63
|
+
total: number;
|
|
64
|
+
/**
|
|
65
|
+
* Open the next question; left out on the last one.
|
|
66
|
+
* @default undefined
|
|
67
|
+
*/
|
|
68
|
+
onNext?: () => void;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* One question: its statement, the answer, the four actions, and — once
|
|
73
|
+
* checked — the verdict case by case, the hints taken and the solution.
|
|
74
|
+
*
|
|
75
|
+
* The answer is graded on every change, but the verdict is shown only for the
|
|
76
|
+
* answer as it was checked: a numeric answer that turned green as it was typed
|
|
77
|
+
* could be found by trying numbers. A link that hides the `solutions` part
|
|
78
|
+
* takes the solution button away.
|
|
79
|
+
* @param props - The tool, the question, where its attempt is kept, and how to
|
|
80
|
+
* draw it.
|
|
81
|
+
* @returns The card.
|
|
82
|
+
*/
|
|
83
|
+
export function QuestionCard<Question>(
|
|
84
|
+
props: QuestionCardProps<Question>,
|
|
85
|
+
): ReactElement {
|
|
86
|
+
const {
|
|
87
|
+
tool,
|
|
88
|
+
question,
|
|
89
|
+
store,
|
|
90
|
+
storageKey,
|
|
91
|
+
number,
|
|
92
|
+
total,
|
|
93
|
+
onNext,
|
|
94
|
+
prompt,
|
|
95
|
+
answer,
|
|
96
|
+
solution,
|
|
97
|
+
} = props;
|
|
98
|
+
const t = useChromeT();
|
|
99
|
+
const isHidden = useIsHidden();
|
|
100
|
+
const records = useAttemptRecords(store);
|
|
101
|
+
const {
|
|
102
|
+
answers,
|
|
103
|
+
checked: checkedAnswers,
|
|
104
|
+
hintsRevealed,
|
|
105
|
+
showSolution,
|
|
106
|
+
} = records[storageKey] ?? emptyAttempt();
|
|
107
|
+
const check = useMemo(
|
|
108
|
+
() => tool.grade(question, answers),
|
|
109
|
+
[tool, question, answers],
|
|
110
|
+
);
|
|
111
|
+
const hints = useMemo(() => tool.hints(question), [tool, question]);
|
|
112
|
+
const snapshot = JSON.stringify(answers);
|
|
113
|
+
const checked = checkedAnswers === snapshot;
|
|
114
|
+
const solutionsHidden = isHidden('solutions');
|
|
115
|
+
const level = tool.level?.(question);
|
|
116
|
+
|
|
117
|
+
function setAnswer(key: string, value: string): void {
|
|
118
|
+
store.updateAttempt(storageKey, { answers: { ...answers, [key]: value } });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function commit(): void {
|
|
122
|
+
store.updateAttempt(storageKey, {
|
|
123
|
+
status: check.passed ? 'solved' : 'attempted',
|
|
124
|
+
checked: snapshot,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<article
|
|
130
|
+
className="series-question"
|
|
131
|
+
aria-label={t('pedagogy.questionNumber', { number })}
|
|
132
|
+
>
|
|
133
|
+
<div className="series-question__meta">
|
|
134
|
+
<span>{t('pedagogy.questionOf', { number, total })}</span>
|
|
135
|
+
{level === undefined ? null : (
|
|
136
|
+
<Tag minimal intent={LEVEL_INTENT[level]}>
|
|
137
|
+
{level}
|
|
138
|
+
</Tag>
|
|
139
|
+
)}
|
|
140
|
+
</div>
|
|
141
|
+
<div className="series-question__prompt">{prompt(question)}</div>
|
|
142
|
+
|
|
143
|
+
{answer ? (
|
|
144
|
+
answer({ question, answers, onChange: setAnswer, onSubmit: commit })
|
|
145
|
+
) : (
|
|
146
|
+
<AnswerFields
|
|
147
|
+
fields={tool.fields(question)}
|
|
148
|
+
answers={answers}
|
|
149
|
+
onChange={setAnswer}
|
|
150
|
+
onSubmit={commit}
|
|
151
|
+
/>
|
|
152
|
+
)}
|
|
153
|
+
|
|
154
|
+
<ExerciseActions
|
|
155
|
+
onCheck={commit}
|
|
156
|
+
checkDisabled={isBlank(answers)}
|
|
157
|
+
onRevealHint={() => {
|
|
158
|
+
store.updateAttempt(storageKey, {
|
|
159
|
+
hintsRevealed: Math.min(hintsRevealed + 1, hints.length),
|
|
160
|
+
});
|
|
161
|
+
}}
|
|
162
|
+
hintsRevealed={hintsRevealed}
|
|
163
|
+
hintCount={hints.length}
|
|
164
|
+
onToggleSolution={
|
|
165
|
+
solutionsHidden
|
|
166
|
+
? undefined
|
|
167
|
+
: () => {
|
|
168
|
+
store.updateAttempt(storageKey, {
|
|
169
|
+
showSolution: !showSolution,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
showSolution={showSolution}
|
|
174
|
+
onReset={() => {
|
|
175
|
+
store.updateAttempt(storageKey, emptyAttempt());
|
|
176
|
+
}}
|
|
177
|
+
/>
|
|
178
|
+
|
|
179
|
+
{checked ? (
|
|
180
|
+
<TestCaseList<FieldCase>
|
|
181
|
+
results={check.cases}
|
|
182
|
+
label={(verdict) => verdict.label}
|
|
183
|
+
/>
|
|
184
|
+
) : null}
|
|
185
|
+
|
|
186
|
+
{checked && check.passed ? (
|
|
187
|
+
<Callout
|
|
188
|
+
intent="success"
|
|
189
|
+
icon="tick-circle"
|
|
190
|
+
title={t('pedagogy.solved')}
|
|
191
|
+
>
|
|
192
|
+
{hintsRevealed > 0
|
|
193
|
+
? t('pedagogy.solvedWithHintsOf', {
|
|
194
|
+
revealed: hintsRevealed,
|
|
195
|
+
total: hints.length,
|
|
196
|
+
})
|
|
197
|
+
: t('pedagogy.solvedWithoutHint')}
|
|
198
|
+
{onNext ? (
|
|
199
|
+
<Button
|
|
200
|
+
className="series-question__next"
|
|
201
|
+
intent="success"
|
|
202
|
+
endIcon="arrow-right"
|
|
203
|
+
text={t('pedagogy.nextQuestion')}
|
|
204
|
+
onClick={onNext}
|
|
205
|
+
/>
|
|
206
|
+
) : null}
|
|
207
|
+
</Callout>
|
|
208
|
+
) : null}
|
|
209
|
+
|
|
210
|
+
{hintsRevealed > 0 ? (
|
|
211
|
+
<HintLadder hints={hints} revealed={hintsRevealed} />
|
|
212
|
+
) : null}
|
|
213
|
+
|
|
214
|
+
{showSolution && !solutionsHidden ? (
|
|
215
|
+
<Callout intent="warning" icon="key" title={t('pedagogy.solution')}>
|
|
216
|
+
<p className="series-question__solution">
|
|
217
|
+
<GlossaryText text={tool.solution(question)} />
|
|
218
|
+
</p>
|
|
219
|
+
{solution?.(question)}
|
|
220
|
+
</Callout>
|
|
221
|
+
) : null}
|
|
222
|
+
</article>
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function isBlank(answers: Answers): boolean {
|
|
227
|
+
for (const value of Object.values(answers)) {
|
|
228
|
+
if (value.trim() !== '') return false;
|
|
229
|
+
}
|
|
230
|
+
return true;
|
|
231
|
+
}
|
package/src/pedagogy/ui/index.ts
CHANGED
|
@@ -51,3 +51,21 @@ export type {
|
|
|
51
51
|
export { TutorialStepStrip } from './TutorialStepStrip.tsx';
|
|
52
52
|
export type { TutorialLevelColours } from './tutorialLevels.ts';
|
|
53
53
|
export { TUTORIAL_LEVEL_COLOURS } from './tutorialLevels.ts';
|
|
54
|
+
export type { AnswerFieldsProps } from './AnswerFields.tsx';
|
|
55
|
+
export { AnswerFields } from './AnswerFields.tsx';
|
|
56
|
+
export type {
|
|
57
|
+
ExerciseListEntry,
|
|
58
|
+
ExerciseListProgress,
|
|
59
|
+
ExerciseListProps,
|
|
60
|
+
} from './ExerciseList.tsx';
|
|
61
|
+
export { ExerciseList } from './ExerciseList.tsx';
|
|
62
|
+
export type { ExerciseSeriesProps } from './ExerciseSeries.tsx';
|
|
63
|
+
export { ExerciseSeries } from './ExerciseSeries.tsx';
|
|
64
|
+
export type {
|
|
65
|
+
AnswerInputProps,
|
|
66
|
+
QuestionCardProps,
|
|
67
|
+
QuestionRendering,
|
|
68
|
+
} from './QuestionCard.tsx';
|
|
69
|
+
export { QuestionCard } from './QuestionCard.tsx';
|
|
70
|
+
export { SERIES_COUNTS } from './seriesCounts.ts';
|
|
71
|
+
export { useAttemptRecords } from './useAttemptRecords.ts';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ChromeKey } from '../../i18n/core/chromeCatalog.ts';
|
|
2
|
+
import type { Translate } from '../../i18n/core/translate.ts';
|
|
3
|
+
|
|
4
|
+
/** The series lengths offered when a page names none. */
|
|
5
|
+
export const SERIES_COUNTS: readonly number[] = [5, 10, 15, 20];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The series lengths a pool can fill, and the whole pool last, so a pool
|
|
9
|
+
* smaller than the longest length is offered whole rather than overpromised.
|
|
10
|
+
* @param poolSize - How many questions the pool holds.
|
|
11
|
+
* @param counts - The lengths offered, or the family's when none.
|
|
12
|
+
* @param t - The chrome's formatter.
|
|
13
|
+
* @returns The options of the picker.
|
|
14
|
+
*/
|
|
15
|
+
export function seriesCountOptions(
|
|
16
|
+
poolSize: number,
|
|
17
|
+
counts: readonly number[] | undefined,
|
|
18
|
+
t: Translate<ChromeKey>,
|
|
19
|
+
): Array<{ value: number; label: string }> {
|
|
20
|
+
const options: Array<{ value: number; label: string }> = [];
|
|
21
|
+
for (const count of counts ?? SERIES_COUNTS) {
|
|
22
|
+
if (count < poolSize) {
|
|
23
|
+
options.push({
|
|
24
|
+
value: count,
|
|
25
|
+
label: t('pedagogy.questionCount', { count }),
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
options.push({
|
|
30
|
+
value: poolSize,
|
|
31
|
+
label: t('pedagogy.allQuestions', { count: poolSize }),
|
|
32
|
+
});
|
|
33
|
+
return options;
|
|
34
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two pieces of `ExerciseSeries` that are only layout: the heading row
|
|
3
|
+
* with the length picker and the new-series button, and the numbered list of
|
|
4
|
+
* questions.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Button, HTMLSelect } from '@blueprintjs/core';
|
|
8
|
+
import type { ReactElement, ReactNode, RefObject } from 'react';
|
|
9
|
+
|
|
10
|
+
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
11
|
+
import type { Attempt } from '../core/attempts.ts';
|
|
12
|
+
import type { ProgressRecords } from '../core/progress.ts';
|
|
13
|
+
|
|
14
|
+
import { ExerciseStatusIcon } from './ExerciseTags.tsx';
|
|
15
|
+
import { seriesCountOptions } from './seriesCounts.ts';
|
|
16
|
+
|
|
17
|
+
/** What {@link SeriesHead} needs. */
|
|
18
|
+
export interface SeriesHeadProps {
|
|
19
|
+
/** The heading, or the chrome's word for it. */
|
|
20
|
+
title: ReactNode | undefined;
|
|
21
|
+
/** Id of the heading. */
|
|
22
|
+
headingId: string;
|
|
23
|
+
/** The length on screen. */
|
|
24
|
+
count: number;
|
|
25
|
+
/** The largest length the tool serves. */
|
|
26
|
+
poolSize: number;
|
|
27
|
+
/** The lengths offered beside the whole pool. */
|
|
28
|
+
counts: readonly number[] | undefined;
|
|
29
|
+
/** Change the length. */
|
|
30
|
+
onCount: (count: number) => void;
|
|
31
|
+
/** Draw another series. */
|
|
32
|
+
onNewSeries: () => void;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The heading row of a series.
|
|
37
|
+
* @param props - See {@link SeriesHeadProps}.
|
|
38
|
+
* @returns The row.
|
|
39
|
+
*/
|
|
40
|
+
export function SeriesHead(props: SeriesHeadProps): ReactElement {
|
|
41
|
+
const { title, headingId, count, poolSize, counts, onCount, onNewSeries } =
|
|
42
|
+
props;
|
|
43
|
+
const t = useChromeT();
|
|
44
|
+
return (
|
|
45
|
+
<div className="exercise-series__head">
|
|
46
|
+
<h2 className="exercise-series__title" id={headingId}>
|
|
47
|
+
{title ?? t('pedagogy.questions')}
|
|
48
|
+
</h2>
|
|
49
|
+
<div className="exercise-series__controls">
|
|
50
|
+
<HTMLSelect
|
|
51
|
+
aria-label={t('pedagogy.questionsInSeries')}
|
|
52
|
+
value={count}
|
|
53
|
+
onChange={(event) => {
|
|
54
|
+
onCount(Number(event.currentTarget.value));
|
|
55
|
+
}}
|
|
56
|
+
options={seriesCountOptions(poolSize, counts, t)}
|
|
57
|
+
/>
|
|
58
|
+
<Button
|
|
59
|
+
icon="refresh"
|
|
60
|
+
text={t('pedagogy.newSeries')}
|
|
61
|
+
title={t('pedagogy.newSeriesTitle')}
|
|
62
|
+
onClick={onNewSeries}
|
|
63
|
+
/>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** What {@link SeriesQuestionList} needs. */
|
|
70
|
+
export interface SeriesQuestionListProps<Question> {
|
|
71
|
+
/** The questions of the series, in order. */
|
|
72
|
+
series: readonly Question[];
|
|
73
|
+
/** The attempt key of each, in the same order. */
|
|
74
|
+
keys: readonly string[];
|
|
75
|
+
/** Every attempt kept. */
|
|
76
|
+
records: ProgressRecords<Attempt>;
|
|
77
|
+
/** The open one. */
|
|
78
|
+
index: number;
|
|
79
|
+
/** Open one. */
|
|
80
|
+
onOpen: (index: number) => void;
|
|
81
|
+
/** How a question is named. */
|
|
82
|
+
label: (question: Question) => ReactNode;
|
|
83
|
+
/** The ref the arrow keys scroll inside. */
|
|
84
|
+
listRef: RefObject<HTMLElement | null>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The numbered list of a series, each question with its status.
|
|
89
|
+
* @param props - See {@link SeriesQuestionListProps}.
|
|
90
|
+
* @returns The list.
|
|
91
|
+
*/
|
|
92
|
+
export function SeriesQuestionList<Question>(
|
|
93
|
+
props: SeriesQuestionListProps<Question>,
|
|
94
|
+
): ReactElement {
|
|
95
|
+
const { series, keys, records, index, onOpen, label, listRef } = props;
|
|
96
|
+
const t = useChromeT();
|
|
97
|
+
return (
|
|
98
|
+
<nav
|
|
99
|
+
ref={listRef}
|
|
100
|
+
className="exercise-series__list"
|
|
101
|
+
aria-label={t('pedagogy.seriesQuestions')}
|
|
102
|
+
>
|
|
103
|
+
{series.map((entry, position) => {
|
|
104
|
+
const key = keys[position] ?? '';
|
|
105
|
+
return (
|
|
106
|
+
<Button
|
|
107
|
+
key={key}
|
|
108
|
+
variant="minimal"
|
|
109
|
+
alignText="start"
|
|
110
|
+
fill
|
|
111
|
+
active={position === index}
|
|
112
|
+
data-selected={position === index ? 'true' : undefined}
|
|
113
|
+
icon={
|
|
114
|
+
<ExerciseStatusIcon status={records[key]?.status ?? 'idle'} />
|
|
115
|
+
}
|
|
116
|
+
onClick={() => {
|
|
117
|
+
onOpen(position);
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
<span className="exercise-series__number">{position + 1}.</span>{' '}
|
|
121
|
+
{label(entry)}
|
|
122
|
+
</Button>
|
|
123
|
+
);
|
|
124
|
+
})}
|
|
125
|
+
</nav>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { Attempt, AttemptStore } from '../core/attempts.ts';
|
|
4
|
+
import type { ProgressRecords } from '../core/progress.ts';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Every attempt a store holds, re-rendering the component whenever one
|
|
8
|
+
* changes.
|
|
9
|
+
* @param store - The site's attempt store.
|
|
10
|
+
* @returns The records, keyed by attempt key.
|
|
11
|
+
*/
|
|
12
|
+
export function useAttemptRecords(
|
|
13
|
+
store: AttemptStore,
|
|
14
|
+
): ProgressRecords<Attempt> {
|
|
15
|
+
return useSyncExternalStore(store.subscribe, store.records, store.records);
|
|
16
|
+
}
|
|
@@ -77,10 +77,13 @@ export function PeriodicTable(props: PeriodicTableProps): ReactElement {
|
|
|
77
77
|
// otherwise re-render all 118 cells per frame, and the engine recomputes
|
|
78
78
|
// every length from the custom property on its own. A width of zero is a
|
|
79
79
|
// table in a tab nobody has opened; the last measurement stands until it is
|
|
80
|
-
// shown, and the observer fires again then.
|
|
80
|
+
// shown, and the observer fires again then. `data-measured` says the cells
|
|
81
|
+
// now follow a measured width rather than the `1cqw` fallback.
|
|
81
82
|
useResizeObserver(rootRef, ({ width }) => {
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
const root = rootRef.current;
|
|
84
|
+
if (width === 0 || root === null) return;
|
|
85
|
+
root.style.setProperty(UNIT_PROPERTY, unitValue(width));
|
|
86
|
+
root.dataset.measured = '';
|
|
84
87
|
});
|
|
85
88
|
|
|
86
89
|
useEffect(() => {
|