react-cheminfo 0.38.0 → 0.39.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/lib/chart/ui/Axes.d.ts +19 -0
- package/lib/chart/ui/Axes.d.ts.map +1 -1
- package/lib/chart/ui/Axes.js +25 -5
- package/lib/chart/ui/Axes.js.map +1 -1
- package/lib/chrome/ui/NavMenuButton.d.ts.map +1 -1
- package/lib/chrome/ui/NavMenuButton.js +41 -11
- package/lib/chrome/ui/NavMenuButton.js.map +1 -1
- package/lib/chrome/ui/SiteHeader.js +24 -1
- package/lib/chrome/ui/SiteHeader.js.map +1 -1
- package/lib/chrome/ui/navItem.d.ts +7 -0
- package/lib/chrome/ui/navItem.d.ts.map +1 -1
- package/lib/chrome/ui/navItem.js.map +1 -1
- package/lib/citation/ui/entries.d.ts.map +1 -1
- package/lib/citation/ui/entries.js +6 -1
- package/lib/citation/ui/entries.js.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.d.ts +11 -0
- package/lib/clipboard/ui/ClickToCopy.d.ts.map +1 -1
- package/lib/clipboard/ui/ClickToCopy.js +28 -10
- package/lib/clipboard/ui/ClickToCopy.js.map +1 -1
- package/lib/clipboard/ui/CopyButton.d.ts +2 -1
- package/lib/clipboard/ui/CopyButton.d.ts.map +1 -1
- package/lib/clipboard/ui/CopyButton.js +2 -1
- package/lib/clipboard/ui/CopyButton.js.map +1 -1
- package/lib/clipboard/ui/CopyableValue.d.ts +24 -4
- package/lib/clipboard/ui/CopyableValue.d.ts.map +1 -1
- package/lib/clipboard/ui/CopyableValue.js +35 -3
- package/lib/clipboard/ui/CopyableValue.js.map +1 -1
- package/lib/clipboard/ui/index.d.ts +1 -1
- package/lib/clipboard/ui/index.d.ts.map +1 -1
- package/lib/clipboard/ui/index.js.map +1 -1
- package/lib/confirm/ui/ConfirmButton.d.ts.map +1 -1
- package/lib/confirm/ui/ConfirmButton.js +2 -1
- package/lib/confirm/ui/ConfirmButton.js.map +1 -1
- package/lib/delimited/ui/TableDataButton.d.ts.map +1 -1
- package/lib/delimited/ui/TableDataButton.js +2 -1
- package/lib/delimited/ui/TableDataButton.js.map +1 -1
- package/lib/download/core/figureSvg.d.ts.map +1 -1
- package/lib/download/core/figureSvg.js +37 -12
- package/lib/download/core/figureSvg.js.map +1 -1
- package/lib/help/ui/HelpToolbarButton.d.ts.map +1 -1
- package/lib/help/ui/HelpToolbarButton.js +2 -1
- package/lib/help/ui/HelpToolbarButton.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/locales/de.json +39 -4
- package/lib/locales/en.json +39 -4
- package/lib/locales/es.json +39 -4
- package/lib/locales/fr.json +39 -4
- package/lib/locales/it.json +39 -4
- package/lib/number/ui/NumberInput.js +1 -1
- package/lib/number/ui/NumberInput.js.map +1 -1
- package/lib/overlay/ui/OverlayIconButton.d.ts.map +1 -1
- package/lib/overlay/ui/OverlayIconButton.js +1 -1
- package/lib/overlay/ui/OverlayIconButton.js.map +1 -1
- package/lib/panel/ui/ClearButton.d.ts.map +1 -1
- package/lib/panel/ui/ClearButton.js +1 -1
- package/lib/panel/ui/ClearButton.js.map +1 -1
- package/lib/pedagogy/core/inlineMarks.d.ts +9 -5
- package/lib/pedagogy/core/inlineMarks.d.ts.map +1 -1
- package/lib/pedagogy/core/inlineMarks.js +14 -6
- package/lib/pedagogy/core/inlineMarks.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryDefinition.d.ts +4 -10
- package/lib/pedagogy/ui/GlossaryDefinition.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryDefinition.js +7 -7
- package/lib/pedagogy/ui/GlossaryDefinition.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.js +1 -1
- package/lib/pedagogy/ui/GlossaryIndex.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryProvider.d.ts +7 -0
- package/lib/pedagogy/ui/GlossaryProvider.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryProvider.js +3 -2
- package/lib/pedagogy/ui/GlossaryProvider.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryText.d.ts +7 -2
- package/lib/pedagogy/ui/GlossaryText.d.ts.map +1 -1
- package/lib/pedagogy/ui/GlossaryText.js +3 -2
- package/lib/pedagogy/ui/GlossaryText.js.map +1 -1
- package/lib/pedagogy/ui/InlineText.d.ts +8 -2
- package/lib/pedagogy/ui/InlineText.d.ts.map +1 -1
- package/lib/pedagogy/ui/InlineText.js +7 -2
- package/lib/pedagogy/ui/InlineText.js.map +1 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts +4 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.d.ts.map +1 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.js +2 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.js.map +1 -1
- package/lib/pedagogy/ui/SyntaxTooltip.d.ts.map +1 -1
- package/lib/pedagogy/ui/SyntaxTooltip.js +11 -10
- package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
- package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
- package/lib/pedagogy/ui/TutorialStepStrip.js +18 -4
- package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
- package/lib/pedagogy/ui/glossaryContext.d.ts +7 -0
- package/lib/pedagogy/ui/glossaryContext.d.ts.map +1 -1
- package/lib/pedagogy/ui/glossaryContext.js.map +1 -1
- package/lib/pedagogy/ui/index.d.ts +1 -1
- package/lib/pedagogy/ui/index.d.ts.map +1 -1
- package/lib/pedagogy/ui/inlineSegments.d.ts +5 -0
- package/lib/pedagogy/ui/inlineSegments.d.ts.map +1 -1
- package/lib/pedagogy/ui/inlineSegments.js +2 -0
- package/lib/pedagogy/ui/inlineSegments.js.map +1 -1
- package/lib/pedagogy/ui/pedagogyStyle.d.ts +8 -9
- package/lib/pedagogy/ui/pedagogyStyle.d.ts.map +1 -1
- package/lib/pedagogy/ui/pedagogyStyle.js +10 -18
- package/lib/pedagogy/ui/pedagogyStyle.js.map +1 -1
- package/lib/seo/core/plainDescription.d.ts +2 -2
- package/lib/seo/core/plainDescription.js +5 -2
- package/lib/seo/core/plainDescription.js.map +1 -1
- package/lib/share/core/devices.d.ts +41 -0
- package/lib/share/core/devices.d.ts.map +1 -0
- package/lib/share/core/devices.js +58 -0
- package/lib/share/core/devices.js.map +1 -0
- package/lib/share/core/index.d.ts +4 -0
- package/lib/share/core/index.d.ts.map +1 -1
- package/lib/share/core/index.js +2 -0
- package/lib/share/core/index.js.map +1 -1
- package/lib/share/core/regions.d.ts +43 -0
- package/lib/share/core/regions.d.ts.map +1 -0
- package/lib/share/core/regions.js +71 -0
- package/lib/share/core/regions.js.map +1 -0
- package/lib/share/ui/HiddenPartsProvider.d.ts.map +1 -1
- package/lib/share/ui/HiddenPartsProvider.js +4 -1
- package/lib/share/ui/HiddenPartsProvider.js.map +1 -1
- package/lib/share/ui/PagePart.d.ts.map +1 -1
- package/lib/share/ui/PagePart.js +10 -1
- package/lib/share/ui/PagePart.js.map +1 -1
- package/lib/share/ui/ShareButton.d.ts.map +1 -1
- package/lib/share/ui/ShareButton.js +3 -4
- package/lib/share/ui/ShareButton.js.map +1 -1
- package/lib/share/ui/ShareConfigOptions.d.ts +6 -1
- package/lib/share/ui/ShareConfigOptions.d.ts.map +1 -1
- package/lib/share/ui/ShareConfigOptions.js +6 -13
- package/lib/share/ui/ShareConfigOptions.js.map +1 -1
- package/lib/share/ui/ShareDialog.d.ts +14 -0
- package/lib/share/ui/ShareDialog.d.ts.map +1 -1
- package/lib/share/ui/ShareDialog.js +3 -3
- package/lib/share/ui/ShareDialog.js.map +1 -1
- package/lib/share/ui/ShareDialogContent.d.ts +2 -2
- package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
- package/lib/share/ui/ShareDialogContent.js +36 -30
- package/lib/share/ui/ShareDialogContent.js.map +1 -1
- package/lib/share/ui/ShareLinkBar.d.ts +21 -0
- package/lib/share/ui/ShareLinkBar.d.ts.map +1 -0
- package/lib/share/ui/ShareLinkBar.js +32 -0
- package/lib/share/ui/ShareLinkBar.js.map +1 -0
- package/lib/share/ui/SharePanes.d.ts +17 -0
- package/lib/share/ui/SharePanes.d.ts.map +1 -0
- package/lib/share/ui/SharePanes.js +27 -0
- package/lib/share/ui/SharePanes.js.map +1 -0
- package/lib/share/ui/SharePartOptions.d.ts +9 -3
- package/lib/share/ui/SharePartOptions.d.ts.map +1 -1
- package/lib/share/ui/SharePartOptions.js +12 -16
- package/lib/share/ui/SharePartOptions.js.map +1 -1
- package/lib/share/ui/SharePartRow.d.ts +37 -0
- package/lib/share/ui/SharePartRow.d.ts.map +1 -0
- package/lib/share/ui/SharePartRow.js +25 -0
- package/lib/share/ui/SharePartRow.js.map +1 -0
- package/lib/share/ui/SharePresetTabs.d.ts +10 -7
- package/lib/share/ui/SharePresetTabs.d.ts.map +1 -1
- package/lib/share/ui/SharePresetTabs.js +17 -17
- package/lib/share/ui/SharePresetTabs.js.map +1 -1
- package/lib/share/ui/SharePreview.d.ts +32 -0
- package/lib/share/ui/SharePreview.d.ts.map +1 -0
- package/lib/share/ui/SharePreview.js +104 -0
- package/lib/share/ui/SharePreview.js.map +1 -0
- package/lib/share/ui/SharePreviewDevices.d.ts +20 -0
- package/lib/share/ui/SharePreviewDevices.d.ts.map +1 -0
- package/lib/share/ui/SharePreviewDevices.js +40 -0
- package/lib/share/ui/SharePreviewDevices.js.map +1 -0
- package/lib/share/ui/index.d.ts +1 -0
- package/lib/share/ui/index.d.ts.map +1 -1
- package/lib/share/ui/index.js.map +1 -1
- package/lib/share/ui/shareMarking.d.ts +14 -0
- package/lib/share/ui/shareMarking.d.ts.map +1 -0
- package/lib/share/ui/shareMarking.js +17 -0
- package/lib/share/ui/shareMarking.js.map +1 -0
- package/lib/share/ui/useShareRegionReports.d.ts +12 -0
- package/lib/share/ui/useShareRegionReports.d.ts.map +1 -0
- package/lib/share/ui/useShareRegionReports.js +73 -0
- package/lib/share/ui/useShareRegionReports.js.map +1 -0
- package/lib/shared/ui/ActionTooltip.d.ts +42 -0
- package/lib/shared/ui/ActionTooltip.d.ts.map +1 -0
- package/lib/shared/ui/ActionTooltip.js +21 -0
- package/lib/shared/ui/ActionTooltip.js.map +1 -0
- package/lib/shared/ui/index.d.ts +4 -0
- package/lib/shared/ui/index.d.ts.map +1 -1
- package/lib/shared/ui/index.js +2 -0
- package/lib/shared/ui/index.js.map +1 -1
- package/lib/shared/ui/useActionTooltip.d.ts +48 -0
- package/lib/shared/ui/useActionTooltip.d.ts.map +1 -0
- package/lib/shared/ui/useActionTooltip.js +78 -0
- package/lib/shared/ui/useActionTooltip.js.map +1 -0
- package/lib/structure/core/index.d.ts +2 -0
- package/lib/structure/core/index.d.ts.map +1 -1
- package/lib/structure/core/index.js +1 -0
- package/lib/structure/core/index.js.map +1 -1
- package/lib/structure/core/sourceMolecule.d.ts +18 -0
- package/lib/structure/core/sourceMolecule.d.ts.map +1 -0
- package/lib/structure/core/sourceMolecule.js +26 -0
- package/lib/structure/core/sourceMolecule.js.map +1 -0
- package/lib/structure/core/structureNotations.d.ts +57 -0
- package/lib/structure/core/structureNotations.d.ts.map +1 -0
- package/lib/structure/core/structureNotations.js +74 -0
- package/lib/structure/core/structureNotations.js.map +1 -0
- package/lib/structure/core/structurePicture.d.ts +49 -0
- package/lib/structure/core/structurePicture.d.ts.map +1 -0
- package/lib/structure/core/structurePicture.js +83 -0
- package/lib/structure/core/structurePicture.js.map +1 -0
- package/lib/structure/ui/EditorExportButton.d.ts +23 -0
- package/lib/structure/ui/EditorExportButton.d.ts.map +1 -0
- package/lib/structure/ui/EditorExportButton.js +23 -0
- package/lib/structure/ui/EditorExportButton.js.map +1 -0
- package/lib/structure/ui/EditorHelpButton.d.ts +5 -2
- package/lib/structure/ui/EditorHelpButton.d.ts.map +1 -1
- package/lib/structure/ui/EditorHelpButton.js +8 -9
- package/lib/structure/ui/EditorHelpButton.js.map +1 -1
- package/lib/structure/ui/StructureEditor.d.ts +8 -0
- package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
- package/lib/structure/ui/StructureEditor.js +26 -3
- package/lib/structure/ui/StructureEditor.js.map +1 -1
- package/lib/structure/ui/StructureExportDialog.d.ts +34 -0
- package/lib/structure/ui/StructureExportDialog.d.ts.map +1 -0
- package/lib/structure/ui/StructureExportDialog.js +43 -0
- package/lib/structure/ui/StructureExportDialog.js.map +1 -0
- package/lib/structure/ui/StructureExportPanel.d.ts +37 -0
- package/lib/structure/ui/StructureExportPanel.d.ts.map +1 -0
- package/lib/structure/ui/StructureExportPanel.js +75 -0
- package/lib/structure/ui/StructureExportPanel.js.map +1 -0
- package/lib/structure/ui/StructureNotationRow.d.ts +22 -0
- package/lib/structure/ui/StructureNotationRow.d.ts.map +1 -0
- package/lib/structure/ui/StructureNotationRow.js +34 -0
- package/lib/structure/ui/StructureNotationRow.js.map +1 -0
- package/lib/structure/ui/StructurePicturePane.d.ts +23 -0
- package/lib/structure/ui/StructurePicturePane.d.ts.map +1 -0
- package/lib/structure/ui/StructurePicturePane.js +113 -0
- package/lib/structure/ui/StructurePicturePane.js.map +1 -0
- package/lib/structure/ui/StructureSvg.d.ts.map +1 -1
- package/lib/structure/ui/StructureSvg.js +2 -18
- package/lib/structure/ui/StructureSvg.js.map +1 -1
- package/lib/structure/ui/ToolbarTooltip.d.ts.map +1 -1
- package/lib/structure/ui/ToolbarTooltip.js +1 -2
- package/lib/structure/ui/ToolbarTooltip.js.map +1 -1
- package/lib/structure/ui/index.d.ts +7 -3
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js +5 -3
- package/lib/structure/ui/index.js.map +1 -1
- package/lib/structure/ui/structureNotationText.d.ts +23 -0
- package/lib/structure/ui/structureNotationText.d.ts.map +1 -0
- package/lib/structure/ui/structureNotationText.js +42 -0
- package/lib/structure/ui/structureNotationText.js.map +1 -0
- package/lib/structure/ui/useEditorStructure.d.ts +37 -0
- package/lib/structure/ui/useEditorStructure.d.ts.map +1 -0
- package/lib/structure/ui/useEditorStructure.js +70 -0
- package/lib/structure/ui/useEditorStructure.js.map +1 -0
- package/package.json +1 -1
- package/src/chart/ui/Axes.tsx +53 -5
- package/src/chrome/ui/NavMenuButton.tsx +61 -18
- package/src/chrome/ui/SiteHeader.tsx +37 -1
- package/src/chrome/ui/navItem.ts +7 -0
- package/src/citation/ui/entries.tsx +10 -2
- package/src/clipboard/ui/ClickToCopy.tsx +47 -13
- package/src/clipboard/ui/CopyButton.tsx +4 -2
- package/src/clipboard/ui/CopyableValue.tsx +88 -13
- package/src/clipboard/ui/index.ts +5 -1
- package/src/confirm/ui/ConfirmButton.tsx +2 -0
- package/src/delimited/ui/TableDataButton.tsx +2 -1
- package/src/download/core/figureSvg.ts +42 -10
- package/src/help/ui/HelpToolbarButton.tsx +2 -1
- package/src/locales/de.json +39 -4
- package/src/locales/en.json +39 -4
- package/src/locales/es.json +39 -4
- package/src/locales/fr.json +39 -4
- package/src/locales/it.json +39 -4
- package/src/number/ui/NumberInput.tsx +1 -1
- package/src/overlay/ui/OverlayIconButton.tsx +1 -0
- package/src/panel/ui/ClearButton.tsx +1 -0
- package/src/pedagogy/core/inlineMarks.ts +15 -7
- package/src/pedagogy/ui/GlossaryDefinition.tsx +8 -18
- package/src/pedagogy/ui/GlossaryIndex.tsx +0 -1
- package/src/pedagogy/ui/GlossaryProvider.tsx +10 -2
- package/src/pedagogy/ui/GlossaryText.tsx +10 -2
- package/src/pedagogy/ui/InlineText.tsx +21 -4
- package/src/pedagogy/ui/ReferenceSectionBlock.tsx +8 -2
- package/src/pedagogy/ui/SyntaxTooltip.tsx +11 -9
- package/src/pedagogy/ui/TutorialStepStrip.tsx +50 -18
- package/src/pedagogy/ui/glossaryContext.ts +7 -0
- package/src/pedagogy/ui/index.ts +1 -1
- package/src/pedagogy/ui/inlineSegments.tsx +7 -0
- package/src/pedagogy/ui/pedagogyStyle.ts +12 -24
- package/src/seo/core/plainDescription.ts +4 -2
- package/src/share/core/devices.ts +80 -0
- package/src/share/core/index.ts +14 -0
- package/src/share/core/regions.ts +87 -0
- package/src/share/ui/HiddenPartsProvider.tsx +6 -1
- package/src/share/ui/PagePart.tsx +12 -1
- package/src/share/ui/ShareButton.tsx +3 -6
- package/src/share/ui/ShareConfigOptions.tsx +25 -16
- package/src/share/ui/ShareDialog.tsx +17 -3
- package/src/share/ui/ShareDialogContent.tsx +80 -77
- package/src/share/ui/ShareLinkBar.tsx +70 -0
- package/src/share/ui/SharePanes.tsx +62 -0
- package/src/share/ui/SharePartOptions.tsx +25 -26
- package/src/share/ui/SharePartRow.tsx +78 -0
- package/src/share/ui/SharePresetTabs.tsx +36 -43
- package/src/share/ui/SharePreview.tsx +204 -0
- package/src/share/ui/SharePreviewDevices.tsx +70 -0
- package/src/share/ui/index.ts +1 -0
- package/src/share/ui/shareMarking.ts +18 -0
- package/src/share/ui/useShareRegionReports.ts +84 -0
- package/src/shared/ui/ActionTooltip.tsx +70 -0
- package/src/shared/ui/index.ts +7 -0
- package/src/shared/ui/useActionTooltip.ts +103 -0
- package/src/structure/core/index.ts +5 -0
- package/src/structure/core/sourceMolecule.ts +26 -0
- package/src/structure/core/structureNotations.ts +125 -0
- package/src/structure/core/structurePicture.ts +119 -0
- package/src/structure/ui/EditorExportButton.tsx +62 -0
- package/src/structure/ui/EditorHelpButton.tsx +26 -30
- package/src/structure/ui/StructureEditor.tsx +51 -5
- package/src/structure/ui/StructureExportDialog.tsx +90 -0
- package/src/structure/ui/StructureExportPanel.tsx +156 -0
- package/src/structure/ui/StructureNotationRow.tsx +74 -0
- package/src/structure/ui/StructurePicturePane.tsx +208 -0
- package/src/structure/ui/StructureSvg.tsx +3 -12
- package/src/structure/ui/ToolbarTooltip.tsx +1 -1
- package/src/structure/ui/index.ts +7 -3
- package/src/structure/ui/structureNotationText.ts +56 -0
- package/src/structure/ui/useEditorStructure.ts +119 -0
- package/styles/chrome.css +414 -14
|
@@ -16,8 +16,8 @@ import { HOVER_OPEN_DELAY } from './pedagogyStyle.ts';
|
|
|
16
16
|
export interface GlossaryTextProps<TExample = GlossaryExample> {
|
|
17
17
|
/**
|
|
18
18
|
* Authored prose. Every `[[term]]` — or `[[term|displayed text]]` — the
|
|
19
|
-
* glossary knows becomes a hoverable chip, and `` `code` ``,
|
|
20
|
-
* and `*emphasis*` are drawn as such.
|
|
19
|
+
* glossary knows becomes a hoverable chip, and `` `code` ``, `{{C6H6O}}`,
|
|
20
|
+
* `**strong**` and `*emphasis*` are drawn as such.
|
|
21
21
|
*/
|
|
22
22
|
text: string;
|
|
23
23
|
/**
|
|
@@ -47,6 +47,11 @@ export interface GlossaryTextProps<TExample = GlossaryExample> {
|
|
|
47
47
|
* @default the surrounding provider's, and otherwise a plain `<code>`
|
|
48
48
|
*/
|
|
49
49
|
renderCode?: (code: string) => ReactNode;
|
|
50
|
+
/**
|
|
51
|
+
* Draws a `{{C6H6O}}` of the prose.
|
|
52
|
+
* @default the surrounding provider's, and otherwise the formula as typed
|
|
53
|
+
*/
|
|
54
|
+
renderMf?: (mf: string) => ReactNode;
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
/**
|
|
@@ -69,6 +74,7 @@ export function GlossaryText<TExample = GlossaryExample>(
|
|
|
69
74
|
className = 'glossary-term',
|
|
70
75
|
renderExample,
|
|
71
76
|
renderCode,
|
|
77
|
+
renderMf,
|
|
72
78
|
} = props;
|
|
73
79
|
const context = useGlossary();
|
|
74
80
|
const terms: Glossary<unknown> = glossary ?? context.glossary;
|
|
@@ -78,6 +84,7 @@ export function GlossaryText<TExample = GlossaryExample>(
|
|
|
78
84
|
<>
|
|
79
85
|
{renderInlineSegments(segments, {
|
|
80
86
|
code: renderCode ?? context.renderCode ?? plainCode,
|
|
87
|
+
mf: renderMf ?? context.renderMf,
|
|
81
88
|
term: (term, shown) => {
|
|
82
89
|
const entry = lookupGlossaryTerm(terms, term);
|
|
83
90
|
if (entry === undefined) return shown;
|
|
@@ -94,6 +101,7 @@ export function GlossaryText<TExample = GlossaryExample>(
|
|
|
94
101
|
}
|
|
95
102
|
hoverOpenDelay={HOVER_OPEN_DELAY}
|
|
96
103
|
placement={placement}
|
|
104
|
+
popoverClassName="help-tooltip"
|
|
97
105
|
>
|
|
98
106
|
<span className={className} style={TERM_STYLE}>
|
|
99
107
|
{shown}
|
|
@@ -2,13 +2,14 @@ import type { ReactElement, ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import { parseInlineMarks } from '../core/inlineMarks.ts';
|
|
4
4
|
|
|
5
|
+
import { useGlossary } from './glossaryContext.ts';
|
|
5
6
|
import { plainCode, renderInlineSegments } from './inlineSegments.tsx';
|
|
6
7
|
|
|
7
8
|
/** Props of {@link InlineText}. */
|
|
8
9
|
export interface InlineTextProps {
|
|
9
10
|
/**
|
|
10
|
-
* Authored prose: `` `code` ``, `**strong**` and `*emphasis*`.
|
|
11
|
-
* `[[markers]]` included, is shown as typed.
|
|
11
|
+
* Authored prose: `` `code` ``, `{{C6H6O}}`, `**strong**` and `*emphasis*`.
|
|
12
|
+
* Anything else, `[[markers]]` included, is shown as typed.
|
|
12
13
|
*/
|
|
13
14
|
text: string;
|
|
14
15
|
/**
|
|
@@ -17,6 +18,12 @@ export interface InlineTextProps {
|
|
|
17
18
|
* @default a plain `<code>`
|
|
18
19
|
*/
|
|
19
20
|
renderCode?: (code: string) => ReactNode;
|
|
21
|
+
/**
|
|
22
|
+
* Draws a `{{C6H6O}}`: as a formula, with `react-mf`.
|
|
23
|
+
* @default the surrounding `GlossaryProvider`'s, and otherwise the formula
|
|
24
|
+
* as typed
|
|
25
|
+
*/
|
|
26
|
+
renderMf?: (mf: string) => ReactNode;
|
|
20
27
|
}
|
|
21
28
|
|
|
22
29
|
/**
|
|
@@ -31,9 +38,19 @@ export interface InlineTextProps {
|
|
|
31
38
|
* @returns The prose, with its marks drawn.
|
|
32
39
|
*/
|
|
33
40
|
export function InlineText(props: InlineTextProps): ReactElement {
|
|
34
|
-
const
|
|
41
|
+
const context = useGlossary();
|
|
42
|
+
const {
|
|
43
|
+
text,
|
|
44
|
+
renderCode = context.renderCode ?? plainCode,
|
|
45
|
+
renderMf = context.renderMf,
|
|
46
|
+
} = props;
|
|
35
47
|
|
|
36
48
|
return (
|
|
37
|
-
<>
|
|
49
|
+
<>
|
|
50
|
+
{renderInlineSegments(parseInlineMarks(text), {
|
|
51
|
+
code: renderCode,
|
|
52
|
+
mf: renderMf,
|
|
53
|
+
})}
|
|
54
|
+
</>
|
|
38
55
|
);
|
|
39
56
|
}
|
|
@@ -4,6 +4,7 @@ import { ClickToCopy } from '../../clipboard/ui/ClickToCopy.tsx';
|
|
|
4
4
|
import { joinClassNames } from '../../shared/ui/joinClassNames.ts';
|
|
5
5
|
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
6
6
|
|
|
7
|
+
import { InlineText } from './InlineText.tsx';
|
|
7
8
|
import type { SyntaxTooltipContent } from './SyntaxTooltip.tsx';
|
|
8
9
|
import { SyntaxTooltip } from './SyntaxTooltip.tsx';
|
|
9
10
|
import { MONOSPACE } from './pedagogyStyle.ts';
|
|
@@ -12,7 +13,10 @@ import { MONOSPACE } from './pedagogyStyle.ts';
|
|
|
12
13
|
export interface ReferenceRow {
|
|
13
14
|
/** The construct itself, set in monospace. */
|
|
14
15
|
syntax: string;
|
|
15
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* What it does, in one line — short enough to read on paper. Authored prose,
|
|
18
|
+
* so a `{{C6H6O}}` in it is drawn as a formula and a `` `code` `` as code.
|
|
19
|
+
*/
|
|
16
20
|
description: string;
|
|
17
21
|
/**
|
|
18
22
|
* The longer story, opened by hovering the row. A sparse section is meant to
|
|
@@ -118,7 +122,9 @@ function ReferenceRowLine(props: {
|
|
|
118
122
|
{row.syntax}
|
|
119
123
|
</ClickToCopy>
|
|
120
124
|
</span>
|
|
121
|
-
<span style={DESCRIPTION_STYLE}>
|
|
125
|
+
<span style={DESCRIPTION_STYLE}>
|
|
126
|
+
<InlineText text={row.description} />
|
|
127
|
+
</span>
|
|
122
128
|
</span>
|
|
123
129
|
);
|
|
124
130
|
if (row.tooltip === undefined) return line;
|
|
@@ -3,6 +3,7 @@ import { Tooltip } from '@blueprintjs/core';
|
|
|
3
3
|
import type { CSSProperties, ReactElement, ReactNode } from 'react';
|
|
4
4
|
|
|
5
5
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
6
7
|
import type { GlossaryExample } from '../core/glossary.ts';
|
|
7
8
|
|
|
8
9
|
import { HOVER_OPEN_DELAY, MONOSPACE, PROSE_INK } from './pedagogyStyle.ts';
|
|
@@ -98,6 +99,7 @@ export function SyntaxTooltip(props: SyntaxTooltipProps): ReactElement {
|
|
|
98
99
|
hoverOpenDelay={HOVER_OPEN_DELAY}
|
|
99
100
|
placement={placement}
|
|
100
101
|
isOpen={isOpen}
|
|
102
|
+
popoverClassName="help-tooltip"
|
|
101
103
|
>
|
|
102
104
|
{children}
|
|
103
105
|
</Tooltip>
|
|
@@ -164,7 +166,6 @@ const BODY_STYLE: CSSProperties = {
|
|
|
164
166
|
display: 'flex',
|
|
165
167
|
flexDirection: 'column',
|
|
166
168
|
gap: 6,
|
|
167
|
-
maxWidth: 360,
|
|
168
169
|
};
|
|
169
170
|
|
|
170
171
|
const HEADER_STYLE: CSSProperties = {
|
|
@@ -175,9 +176,10 @@ const HEADER_STYLE: CSSProperties = {
|
|
|
175
176
|
};
|
|
176
177
|
|
|
177
178
|
const SYNTAX_STYLE: CSSProperties = {
|
|
178
|
-
background:
|
|
179
|
+
background: TOKEN.surfaceSunken,
|
|
180
|
+
border: `1px solid ${PROSE_INK.rule}`,
|
|
179
181
|
borderRadius: 3,
|
|
180
|
-
color:
|
|
182
|
+
color: PROSE_INK.code,
|
|
181
183
|
fontFamily: MONOSPACE,
|
|
182
184
|
fontSize: 14,
|
|
183
185
|
fontWeight: 600,
|
|
@@ -187,20 +189,20 @@ const SYNTAX_STYLE: CSSProperties = {
|
|
|
187
189
|
const NAME_STYLE: CSSProperties = { fontWeight: 600, fontSize: 13 };
|
|
188
190
|
|
|
189
191
|
const TAG_STYLE: CSSProperties = {
|
|
190
|
-
color: PROSE_INK.
|
|
192
|
+
color: PROSE_INK.muted,
|
|
191
193
|
fontSize: 11,
|
|
192
194
|
};
|
|
193
195
|
|
|
194
196
|
const SUMMARY_STYLE: CSSProperties = { fontSize: 12, lineHeight: 1.4 };
|
|
195
197
|
|
|
196
198
|
const DETAIL_STYLE: CSSProperties = {
|
|
197
|
-
color: PROSE_INK.
|
|
199
|
+
color: PROSE_INK.text,
|
|
198
200
|
fontSize: 12,
|
|
199
201
|
lineHeight: 1.45,
|
|
200
202
|
};
|
|
201
203
|
|
|
202
204
|
const EXAMPLE_STYLE: CSSProperties = {
|
|
203
|
-
borderTop: `1px solid ${PROSE_INK.
|
|
205
|
+
borderTop: `1px solid ${PROSE_INK.rule}`,
|
|
204
206
|
display: 'flex',
|
|
205
207
|
flexDirection: 'column',
|
|
206
208
|
gap: 2,
|
|
@@ -210,18 +212,18 @@ const EXAMPLE_STYLE: CSSProperties = {
|
|
|
210
212
|
const ROW_STYLE: CSSProperties = { display: 'flex', gap: 6, fontSize: 12 };
|
|
211
213
|
|
|
212
214
|
const LABEL_STYLE: CSSProperties = {
|
|
213
|
-
color: PROSE_INK.
|
|
215
|
+
color: PROSE_INK.muted,
|
|
214
216
|
flex: '0 0 68px',
|
|
215
217
|
};
|
|
216
218
|
|
|
217
219
|
const VALUE_STYLE: CSSProperties = {
|
|
218
|
-
color: PROSE_INK.
|
|
220
|
+
color: PROSE_INK.text,
|
|
219
221
|
fontFamily: MONOSPACE,
|
|
220
222
|
overflowWrap: 'anywhere',
|
|
221
223
|
};
|
|
222
224
|
|
|
223
225
|
const NOTE_STYLE: CSSProperties = {
|
|
224
|
-
color: PROSE_INK.
|
|
226
|
+
color: PROSE_INK.muted,
|
|
225
227
|
fontSize: 12,
|
|
226
228
|
fontStyle: 'italic',
|
|
227
229
|
marginTop: 2,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { Button, Tag
|
|
1
|
+
import { Button, Tag } from '@blueprintjs/core';
|
|
2
2
|
import type { CSSProperties, ReactElement, ReactNode } from 'react';
|
|
3
3
|
|
|
4
4
|
import { clamp } from '../../format/core/clamp.ts';
|
|
5
5
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
6
|
+
import { ActionTooltip } from '../../shared/ui/ActionTooltip.tsx';
|
|
6
7
|
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
7
8
|
import type { ExerciseLevel } from '../core/types.ts';
|
|
8
9
|
|
|
@@ -150,24 +151,14 @@ function LevelStrip(props: LevelStripProps): ReactElement {
|
|
|
150
151
|
const step = steps[position] as TutorialStripStep;
|
|
151
152
|
const active = position === activeIndex;
|
|
152
153
|
buttons.push(
|
|
153
|
-
<
|
|
154
|
+
<StepButton
|
|
154
155
|
key={step.id ?? position}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
aria-label={`Step ${position + 1}: ${step.title}`}
|
|
162
|
-
aria-current={active ? 'step' : undefined}
|
|
163
|
-
style={numberStyle(colours, active)}
|
|
164
|
-
onClick={() => {
|
|
165
|
-
onSelect(position);
|
|
166
|
-
}}
|
|
167
|
-
>
|
|
168
|
-
{position + 1}
|
|
169
|
-
</button>
|
|
170
|
-
</Tooltip>,
|
|
156
|
+
step={step}
|
|
157
|
+
position={position}
|
|
158
|
+
colours={colours}
|
|
159
|
+
active={active}
|
|
160
|
+
onSelect={onSelect}
|
|
161
|
+
/>,
|
|
171
162
|
);
|
|
172
163
|
}
|
|
173
164
|
|
|
@@ -179,6 +170,47 @@ function LevelStrip(props: LevelStripProps): ReactElement {
|
|
|
179
170
|
);
|
|
180
171
|
}
|
|
181
172
|
|
|
173
|
+
interface StepButtonProps {
|
|
174
|
+
step: TutorialStripStep;
|
|
175
|
+
position: number;
|
|
176
|
+
colours: TutorialLevelColours;
|
|
177
|
+
active: boolean;
|
|
178
|
+
onSelect: (index: number) => void;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* One numbered step, naming itself on hover.
|
|
183
|
+
*
|
|
184
|
+
* The name is held by {@link ActionTooltip} rather than by Blueprint: pressing
|
|
185
|
+
* a number within the hover delay would otherwise open the card afterwards,
|
|
186
|
+
* over the step it has just walked away from.
|
|
187
|
+
* @param props - The step, where it sits, and what picking it does.
|
|
188
|
+
* @returns The button.
|
|
189
|
+
*/
|
|
190
|
+
function StepButton(props: StepButtonProps): ReactElement {
|
|
191
|
+
const { step, position, colours, active, onSelect } = props;
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<ActionTooltip
|
|
195
|
+
content={step.title}
|
|
196
|
+
delay={HOVER_OPEN_DELAY}
|
|
197
|
+
placement="bottom"
|
|
198
|
+
>
|
|
199
|
+
<button
|
|
200
|
+
type="button"
|
|
201
|
+
aria-label={`Step ${position + 1}: ${step.title}`}
|
|
202
|
+
aria-current={active ? 'step' : undefined}
|
|
203
|
+
style={numberStyle(colours, active)}
|
|
204
|
+
onClick={() => {
|
|
205
|
+
onSelect(position);
|
|
206
|
+
}}
|
|
207
|
+
>
|
|
208
|
+
{position + 1}
|
|
209
|
+
</button>
|
|
210
|
+
</ActionTooltip>
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
182
214
|
function positionsOfLevel(
|
|
183
215
|
steps: readonly TutorialStripStep[],
|
|
184
216
|
level: ExerciseLevel,
|
|
@@ -26,6 +26,13 @@ export interface GlossaryContextValue {
|
|
|
26
26
|
* @default undefined — a plain `<code>`
|
|
27
27
|
*/
|
|
28
28
|
renderCode?: (code: string) => ReactNode;
|
|
29
|
+
/**
|
|
30
|
+
* Draws a `{{C6H6O}}` of the prose. A chemistry site passes
|
|
31
|
+
* `(mf) => <MF mf={mf} />` from `react-mf` here, once, so that every formula
|
|
32
|
+
* below reads as a formula rather than as a line of digits.
|
|
33
|
+
* @default undefined — the formula as typed
|
|
34
|
+
*/
|
|
35
|
+
renderMf?: (mf: string) => ReactNode;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
/**
|
package/src/pedagogy/ui/index.ts
CHANGED
|
@@ -41,7 +41,7 @@ export type {
|
|
|
41
41
|
SyntaxTooltipProps,
|
|
42
42
|
} from './SyntaxTooltip.tsx';
|
|
43
43
|
export { SyntaxTooltip } from './SyntaxTooltip.tsx';
|
|
44
|
-
export type {
|
|
44
|
+
export type { ProseInk } from './pedagogyStyle.ts';
|
|
45
45
|
export type { TestCaseListProps } from './TestCaseList.tsx';
|
|
46
46
|
export { TestCaseList } from './TestCaseList.tsx';
|
|
47
47
|
export type {
|
|
@@ -7,6 +7,11 @@ import type { InlineSegment } from '../core/inlineMarks.ts';
|
|
|
7
7
|
interface InlineRenderers {
|
|
8
8
|
/** Draws a code span, from the text between its backticks. */
|
|
9
9
|
code: (code: string) => ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* Draws a molecular formula, from the text between its braces.
|
|
12
|
+
* @default undefined — the formula as typed, which no chemistry site wants
|
|
13
|
+
*/
|
|
14
|
+
mf?: (mf: string) => ReactNode;
|
|
10
15
|
/**
|
|
11
16
|
* Draws a glossary marker, from its lowercased term and the text to show.
|
|
12
17
|
* @default undefined — the text, as plain prose
|
|
@@ -53,6 +58,8 @@ function renderSegment(
|
|
|
53
58
|
return segment.text;
|
|
54
59
|
case 'code':
|
|
55
60
|
return renderers.code(segment.text);
|
|
61
|
+
case 'mf':
|
|
62
|
+
return renderers.mf === undefined ? segment.mf : renderers.mf(segment.mf);
|
|
56
63
|
case 'term':
|
|
57
64
|
return renderers.term === undefined
|
|
58
65
|
? segment.text
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What the pedagogy components share about how they look: how long a pointer
|
|
3
3
|
* rests before a definition opens, the monospace stack, and the ink prose is
|
|
4
|
-
* set in
|
|
4
|
+
* set in.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { Colors } from '@blueprintjs/core';
|
|
8
|
-
|
|
9
7
|
import { TOKEN } from '../../tokens/core/familyTokens.ts';
|
|
10
8
|
|
|
11
9
|
/** Long enough that the pointer can cross a chip or a row without opening it. */
|
|
@@ -15,10 +13,7 @@ export const HOVER_OPEN_DELAY = 150;
|
|
|
15
13
|
export const MONOSPACE =
|
|
16
14
|
'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace';
|
|
17
15
|
|
|
18
|
-
/**
|
|
19
|
-
export type ProseTone = 'tooltip' | 'page';
|
|
20
|
-
|
|
21
|
-
/** The colours prose is set in on one ground. */
|
|
16
|
+
/** The colours prose is set in. */
|
|
22
17
|
export interface ProseInk {
|
|
23
18
|
/** The body of a paragraph. */
|
|
24
19
|
text: string;
|
|
@@ -31,23 +26,16 @@ export interface ProseInk {
|
|
|
31
26
|
}
|
|
32
27
|
|
|
33
28
|
/**
|
|
34
|
-
* The ink
|
|
29
|
+
* The one ink, because there is one ground.
|
|
35
30
|
*
|
|
36
|
-
* A
|
|
37
|
-
*
|
|
38
|
-
*
|
|
31
|
+
* A definition, a documented construct and a help card are the same job, and
|
|
32
|
+
* the family answers it with one card: `help-tooltip` in `chrome.css`, light,
|
|
33
|
+
* on a border and a shadow. So the prose here is the family's tokens wherever
|
|
34
|
+
* it is read — on a page, or on that card.
|
|
39
35
|
*/
|
|
40
|
-
export const PROSE_INK:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
rule: 'rgb(255 255 255 / 15%)',
|
|
46
|
-
},
|
|
47
|
-
page: {
|
|
48
|
-
text: TOKEN.text,
|
|
49
|
-
muted: TOKEN.textMuted,
|
|
50
|
-
code: TOKEN.text,
|
|
51
|
-
rule: TOKEN.border,
|
|
52
|
-
},
|
|
36
|
+
export const PROSE_INK: ProseInk = {
|
|
37
|
+
text: TOKEN.text,
|
|
38
|
+
muted: TOKEN.textMuted,
|
|
39
|
+
code: TOKEN.text,
|
|
40
|
+
rule: TOKEN.border,
|
|
53
41
|
};
|
|
@@ -44,8 +44,8 @@ export function plainDescription(
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
|
-
* Authored prose as plain text: glossary markers, code spans, strong
|
|
48
|
-
* emphasis resolved to the words they show, and the whitespace collapsed.
|
|
47
|
+
* Authored prose as plain text: glossary markers, code spans, formulas, strong
|
|
48
|
+
* and emphasis resolved to the words they show, and the whitespace collapsed.
|
|
49
49
|
* @param prose - The prose, markup and all.
|
|
50
50
|
* @returns The same words, unmarked.
|
|
51
51
|
*/
|
|
@@ -66,6 +66,8 @@ function textOf(segments: readonly InlineSegment[]): string {
|
|
|
66
66
|
for (const segment of segments) {
|
|
67
67
|
if ('children' in segment) {
|
|
68
68
|
text += textOf(segment.children);
|
|
69
|
+
} else if (segment.kind === 'mf') {
|
|
70
|
+
text += segment.mf;
|
|
69
71
|
} else {
|
|
70
72
|
text += segment.text;
|
|
71
73
|
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** The screens a link can be looked at on, before it is handed out. */
|
|
2
|
+
export type SharePreviewDeviceKey = 'window' | 'mobile' | 'laptop' | 'hd';
|
|
3
|
+
|
|
4
|
+
/** A screen the preview lays the page out at. */
|
|
5
|
+
export interface SharePreviewSize {
|
|
6
|
+
/** Width in CSS pixels. */
|
|
7
|
+
width: number;
|
|
8
|
+
/** Height in CSS pixels. */
|
|
9
|
+
height: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The screens offered, in the order the capsules read. `window` is the
|
|
14
|
+
* reader's own, and is resolved against the browser rather than written here.
|
|
15
|
+
*/
|
|
16
|
+
export const SHARE_PREVIEW_DEVICES: readonly SharePreviewDeviceKey[] = [
|
|
17
|
+
'window',
|
|
18
|
+
'mobile',
|
|
19
|
+
'laptop',
|
|
20
|
+
'hd',
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
const FIXED_SIZES: Record<
|
|
24
|
+
Exclude<SharePreviewDeviceKey, 'window'>,
|
|
25
|
+
SharePreviewSize
|
|
26
|
+
> = {
|
|
27
|
+
mobile: { width: 390, height: 844 },
|
|
28
|
+
laptop: { width: 1280, height: 800 },
|
|
29
|
+
hd: { width: 1920, height: 1080 },
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** What the preview falls back to where there is no window to measure. */
|
|
33
|
+
const FALLBACK_WINDOW: SharePreviewSize = { width: 1280, height: 800 };
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The page size a device lays the preview out at.
|
|
37
|
+
* @param key - The device picked.
|
|
38
|
+
* @param window - The reader's own window, for the `window` device.
|
|
39
|
+
* @returns Its width and height in CSS pixels.
|
|
40
|
+
*/
|
|
41
|
+
export function sharePreviewSize(
|
|
42
|
+
key: SharePreviewDeviceKey,
|
|
43
|
+
window?: Partial<SharePreviewSize>,
|
|
44
|
+
): SharePreviewSize {
|
|
45
|
+
if (key !== 'window') return FIXED_SIZES[key];
|
|
46
|
+
const width = window?.width ?? 0;
|
|
47
|
+
const height = window?.height ?? 0;
|
|
48
|
+
return width > 0 && height > 0 ? { width, height } : FALLBACK_WINDOW;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* How far the page is shrunk to fit the pane it is previewed in.
|
|
53
|
+
*
|
|
54
|
+
* It is never enlarged: a phone shown bigger than a phone is not what the
|
|
55
|
+
* reader is checking.
|
|
56
|
+
* @param pane - The room the preview pane has.
|
|
57
|
+
* @param page - The size the page is laid out at.
|
|
58
|
+
* @returns The scale, between 0 and 1.
|
|
59
|
+
*/
|
|
60
|
+
export function sharePreviewScale(
|
|
61
|
+
pane: Partial<SharePreviewSize>,
|
|
62
|
+
page: SharePreviewSize,
|
|
63
|
+
): number {
|
|
64
|
+
const width = pane.width ?? 0;
|
|
65
|
+
const height = pane.height ?? 0;
|
|
66
|
+
if (width <= 0 || height <= 0) return 1;
|
|
67
|
+
return Math.min(1, width / page.width, height / page.height);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The address as the preview's own bar writes it, without its scheme.
|
|
72
|
+
*
|
|
73
|
+
* What a reader checks there is the site and the query the link carries, and a
|
|
74
|
+
* bar as wide as a phone has no room for `https://`.
|
|
75
|
+
* @param url - The link the preview loads.
|
|
76
|
+
* @returns The address, scheme dropped.
|
|
77
|
+
*/
|
|
78
|
+
export function sharePreviewAddress(url: string): string {
|
|
79
|
+
return url.replace(/^[a-z][\w+.-]*:\/\//i, '');
|
|
80
|
+
}
|
package/src/share/core/index.ts
CHANGED
|
@@ -9,7 +9,21 @@ export {
|
|
|
9
9
|
suggestedShareConfig,
|
|
10
10
|
visibleShareParts,
|
|
11
11
|
} from './config.ts';
|
|
12
|
+
export type { SharePreviewDeviceKey, SharePreviewSize } from './devices.ts';
|
|
13
|
+
export {
|
|
14
|
+
SHARE_PREVIEW_DEVICES,
|
|
15
|
+
sharePreviewAddress,
|
|
16
|
+
sharePreviewScale,
|
|
17
|
+
sharePreviewSize,
|
|
18
|
+
} from './devices.ts';
|
|
12
19
|
export { escapeAttribute, escapeText } from './escape.ts';
|
|
20
|
+
export type { ShareRegion } from './regions.ts';
|
|
21
|
+
export {
|
|
22
|
+
SHARE_REGIONS_MESSAGE,
|
|
23
|
+
SHARE_REGIONS_REQUEST,
|
|
24
|
+
isShareRegionsRequest,
|
|
25
|
+
readShareRegions,
|
|
26
|
+
} from './regions.ts';
|
|
13
27
|
export type {
|
|
14
28
|
BooleanParamOptions,
|
|
15
29
|
IntegerParamOptions,
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where each part of a page sits, so a share dialog can show which region of
|
|
3
|
+
* the preview a row of its list names.
|
|
4
|
+
*
|
|
5
|
+
* The two sides are different documents — the dialog and the framed page — so
|
|
6
|
+
* they speak by message. Everything that arrives is somebody else's input: a
|
|
7
|
+
* framed page is messaged by whatever page frames it, and a dialog by whatever
|
|
8
|
+
* it frames, so both ends read rather than trust.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Asks a framed page to report where its parts are, and to keep reporting. */
|
|
12
|
+
export const SHARE_REGIONS_REQUEST = 'cheminfo:share-regions-request';
|
|
13
|
+
|
|
14
|
+
/** Carries the answer back to the dialog. */
|
|
15
|
+
export const SHARE_REGIONS_MESSAGE = 'cheminfo:share-regions';
|
|
16
|
+
|
|
17
|
+
/** The box one part of the page occupies, in the page's own coordinates. */
|
|
18
|
+
export interface ShareRegion {
|
|
19
|
+
/** The name the part takes in `?hide=`. */
|
|
20
|
+
part: string;
|
|
21
|
+
/** Distance from the left edge of the page, in CSS pixels. */
|
|
22
|
+
x: number;
|
|
23
|
+
/** Distance from the top edge of the page, in CSS pixels. */
|
|
24
|
+
y: number;
|
|
25
|
+
/** Width of the box, in CSS pixels. */
|
|
26
|
+
width: number;
|
|
27
|
+
/** Height of the box, in CSS pixels. */
|
|
28
|
+
height: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether a message asks this page to report where its parts are.
|
|
33
|
+
* @param data - What arrived on the message event.
|
|
34
|
+
* @returns Whether it is the request.
|
|
35
|
+
*/
|
|
36
|
+
export function isShareRegionsRequest(data: unknown): boolean {
|
|
37
|
+
return messageType(data) === SHARE_REGIONS_REQUEST;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The regions a framed page reported, or `null` for anything else that arrived.
|
|
42
|
+
*
|
|
43
|
+
* A region with a name that is not a string, or a side that is not a finite
|
|
44
|
+
* number, is dropped rather than taken: a dialog drawing a box from a number it
|
|
45
|
+
* did not check draws it across the whole screen.
|
|
46
|
+
* @param data - What arrived on the message event.
|
|
47
|
+
* @returns The regions, or `null` when the message is not one.
|
|
48
|
+
*/
|
|
49
|
+
export function readShareRegions(data: unknown): ShareRegion[] | null {
|
|
50
|
+
if (messageType(data) !== SHARE_REGIONS_MESSAGE) return null;
|
|
51
|
+
const { regions } = data as { regions?: unknown };
|
|
52
|
+
if (!Array.isArray(regions)) return null;
|
|
53
|
+
|
|
54
|
+
const read: ShareRegion[] = [];
|
|
55
|
+
for (const candidate of regions) {
|
|
56
|
+
const region = readRegion(candidate);
|
|
57
|
+
if (region !== null) read.push(region);
|
|
58
|
+
}
|
|
59
|
+
return read;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function readRegion(candidate: unknown): ShareRegion | null {
|
|
63
|
+
if (typeof candidate !== 'object' || candidate === null) return null;
|
|
64
|
+
const { part, x, y, width, height } = candidate as Record<string, unknown>;
|
|
65
|
+
if (typeof part !== 'string' || part === '') return null;
|
|
66
|
+
if (
|
|
67
|
+
!Number.isFinite(x) ||
|
|
68
|
+
!Number.isFinite(y) ||
|
|
69
|
+
!Number.isFinite(width) ||
|
|
70
|
+
!Number.isFinite(height)
|
|
71
|
+
) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
part,
|
|
76
|
+
x: x as number,
|
|
77
|
+
y: y as number,
|
|
78
|
+
width: width as number,
|
|
79
|
+
height: height as number,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function messageType(data: unknown): string | null {
|
|
84
|
+
if (typeof data !== 'object' || data === null) return null;
|
|
85
|
+
const { type } = data as { type?: unknown };
|
|
86
|
+
return typeof type === 'string' ? type : null;
|
|
87
|
+
}
|
|
@@ -2,6 +2,8 @@ import type { ReactElement, ReactNode } from 'react';
|
|
|
2
2
|
import { useMemo } from 'react';
|
|
3
3
|
|
|
4
4
|
import { HiddenPartsContext } from './hiddenParts.ts';
|
|
5
|
+
import { ShareMarkingContext } from './shareMarking.ts';
|
|
6
|
+
import { useShareRegionReports } from './useShareRegionReports.ts';
|
|
5
7
|
|
|
6
8
|
export interface HiddenPartsProviderProps {
|
|
7
9
|
/**
|
|
@@ -25,10 +27,13 @@ export function HiddenPartsProvider(
|
|
|
25
27
|
): ReactElement {
|
|
26
28
|
const { hidden, children } = props;
|
|
27
29
|
const parts = useMemo(() => new Set(hidden), [hidden]);
|
|
30
|
+
const marking = useShareRegionReports(parts);
|
|
28
31
|
|
|
29
32
|
return (
|
|
30
33
|
<HiddenPartsContext.Provider value={parts}>
|
|
31
|
-
{
|
|
34
|
+
<ShareMarkingContext.Provider value={marking}>
|
|
35
|
+
{children}
|
|
36
|
+
</ShareMarkingContext.Provider>
|
|
32
37
|
</HiddenPartsContext.Provider>
|
|
33
38
|
);
|
|
34
39
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useIsHidden } from './hiddenParts.ts';
|
|
4
|
+
import { useShareMarking } from './shareMarking.ts';
|
|
4
5
|
|
|
5
6
|
export interface PagePartProps {
|
|
6
7
|
/** The name this region takes in `?hide=`. */
|
|
@@ -21,6 +22,16 @@ export interface PagePartProps {
|
|
|
21
22
|
export function PagePart(props: PagePartProps): ReactNode {
|
|
22
23
|
const { part, children } = props;
|
|
23
24
|
const isHidden = useIsHidden();
|
|
25
|
+
const marking = useShareMarking();
|
|
24
26
|
|
|
25
|
-
|
|
27
|
+
if (isHidden(part)) return null;
|
|
28
|
+
if (!marking) return children;
|
|
29
|
+
|
|
30
|
+
// `display: contents` so the marker is only a name the dialog can find, and
|
|
31
|
+
// never a box between the page and the part it holds.
|
|
32
|
+
return (
|
|
33
|
+
<div data-share-part={part} style={{ display: 'contents' }}>
|
|
34
|
+
{children}
|
|
35
|
+
</div>
|
|
36
|
+
);
|
|
26
37
|
}
|