@miliastry/quasar 1.0.6 → 1.1.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/dist/Visuals/lyne.css +117 -6
- package/dist/Visuals/osu.css +36 -5
- package/dist/index.js +9664 -3282
- package/dist/index.mjs +9535 -3283
- package/dist/types/Analysis/Contracts/AnalysisReport.d.ts +22 -0
- package/dist/types/Analysis/Contracts/Contribution.d.ts +68 -0
- package/dist/types/Analysis/Contracts/Pass.d.ts +59 -0
- package/dist/types/Analysis/Contracts/PipelineContext.d.ts +34 -0
- package/dist/types/Analysis/Passes/Analysis/ColorUsageAnalyzer.d.ts +56 -0
- package/dist/types/Analysis/Passes/Analysis/GradientAnalyzer.d.ts +111 -0
- package/dist/types/Analysis/Passes/Analysis/MergeableColorAnalyzer.d.ts +26 -0
- package/dist/types/Analysis/Passes/Analysis/RainbowAnalyzer.d.ts +47 -0
- package/dist/types/Analysis/Passes/Analysis/SymbolAnalyzer.d.ts +89 -0
- package/dist/types/Analysis/Passes/Analysis/WaveAnalyzer.d.ts +44 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Decision/DefaultDecision.d.ts +30 -0
- package/dist/types/Analysis/Passes/Decision/PaletteRemapDecision.d.ts +169 -0
- package/dist/types/Analysis/Passes/Decision/__tests__/DefaultDecision.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Transform/CollapseGradientTransform.d.ts +37 -0
- package/dist/types/Analysis/Passes/Transform/MergeColorsTransform.d.ts +28 -0
- package/dist/types/Analysis/Passes/Transform/RainbowCollapseTransform.d.ts +19 -0
- package/dist/types/Analysis/Passes/Transform/WaveCollapseTransform.d.ts +20 -0
- package/dist/types/Analysis/Passes/Utility/CharacterCountAnalyzer.d.ts +19 -0
- package/dist/types/Analysis/Pipeline/Pipeline.d.ts +69 -0
- package/dist/types/Analysis/Pipeline/PipelineBuilder.d.ts +31 -0
- package/dist/types/Analysis/Pipeline/PipelineStage.d.ts +17 -0
- package/dist/types/Analysis/Utils/color-utils.d.ts +60 -0
- package/dist/types/Analysis/__tests__/Integration.test.d.ts +8 -0
- package/dist/types/Analysis/__tests__/PaletteRemap.test.d.ts +14 -0
- package/dist/types/Analysis/__tests__/Pipeline.test.d.ts +10 -0
- package/dist/types/Analysis/__tests__/RoundTrip.test.d.ts +30 -0
- package/dist/types/Analysis/__tests__/SymbolAnalyzer.test.d.ts +11 -0
- package/dist/types/Analysis/index.d.ts +40 -0
- package/dist/types/BBCode/BBCodeDocumentModel.d.ts +92 -0
- package/dist/types/BBCode/BBCodeToGreenNode.d.ts +111 -0
- package/dist/types/BBCode/Parser.d.ts +78 -0
- package/dist/types/BBCode/index.d.ts +4 -0
- package/dist/types/Collab/positions.d.ts +55 -0
- package/dist/types/Commands/Command.d.ts +37 -0
- package/dist/types/Commands/CommandRegistry.d.ts +48 -0
- package/dist/types/Commands/DeleteNode.d.ts +7 -0
- package/dist/types/Commands/InsertText.d.ts +8 -0
- package/dist/types/Commands/SplitMerge.d.ts +9 -0
- package/dist/types/Commands/WrapInTag.d.ts +8 -0
- package/dist/types/Commands/index.d.ts +6 -0
- package/dist/types/Diff/TreeDiffer.d.ts +52 -0
- package/dist/types/Diff/__tests__/TreeDiffer.test.d.ts +1 -0
- package/dist/types/Diff/index.d.ts +2 -0
- package/dist/types/Edits/EditPlan.d.ts +144 -0
- package/dist/types/Edits/Optimizer.d.ts +78 -0
- package/dist/types/Edits/Rules/Rule.d.ts +91 -0
- package/dist/types/Edits/Rules/dropEmptyTags.d.ts +40 -0
- package/dist/types/Edits/Rules/dropRedundantNesting.d.ts +59 -0
- package/dist/types/Edits/Rules/index.d.ts +9 -0
- package/dist/types/Edits/Rules/mergeAdjacent.d.ts +93 -0
- package/dist/types/Edits/Rules/reorderWrappers.d.ts +42 -0
- package/dist/types/Edits/Rules/shortenHex.d.ts +30 -0
- package/dist/types/Edits/Rules/tagValue.d.ts +56 -0
- package/dist/types/Edits/Rules/unwrapInvisibleColor.d.ts +47 -0
- package/dist/types/Edits/applyEdits.d.ts +36 -0
- package/dist/types/Edits/index.d.ts +6 -0
- package/dist/types/Events/EventBus.d.ts +103 -0
- package/dist/types/Events/index.d.ts +2 -0
- package/dist/types/Formatter/Formatter.d.ts +32 -0
- package/dist/types/Formatter/index.d.ts +2 -0
- package/dist/types/HTML/HTMLDocumentModel.d.ts +13 -0
- package/dist/types/HTML/HTMLToGreenNode.d.ts +4 -0
- package/dist/types/Incremental/BracketIndex.d.ts +101 -0
- package/dist/types/Incremental/ChangeTracker.d.ts +69 -0
- package/dist/types/Incremental/IncrementalParser.d.ts +246 -0
- package/dist/types/Incremental/__tests__/BracketIndex.test.d.ts +1 -0
- package/dist/types/Incremental/__tests__/IncrementalParser.test.d.ts +1 -0
- package/dist/types/Incremental/index.d.ts +4 -0
- package/dist/types/Lexer/BBCodeLexer.d.ts +74 -0
- package/dist/types/Lexer/Lexer.d.ts +54 -0
- package/dist/types/Lexer/index.d.ts +4 -0
- package/dist/types/Linter/Linter.d.ts +58 -0
- package/dist/types/Linter/index.d.ts +2 -0
- package/dist/types/Markdown/MarkdownAST.d.ts +122 -0
- package/dist/types/Markdown/MarkdownDocumentModel.d.ts +15 -0
- package/dist/types/Markdown/MarkdownLexer.d.ts +155 -0
- package/dist/types/Markdown/MarkdownParser.d.ts +42 -0
- package/dist/types/Markdown/MarkdownToGreenNode.d.ts +6 -0
- package/dist/types/MilHibri/MilHibriDocumentModel.d.ts +21 -0
- package/dist/types/Model/DocumentModel.d.ts +318 -0
- package/dist/types/Model/NodeFactory.d.ts +29 -0
- package/dist/types/Model/TagRegistry.d.ts +165 -0
- package/dist/types/Model/index.d.ts +5 -0
- package/dist/types/Plugins/PluginAPI.d.ts +44 -0
- package/dist/types/Plugins/PluginRegistry.d.ts +81 -0
- package/dist/types/Plugins/index.d.ts +3 -0
- package/dist/types/Queries/QueryEngine.d.ts +32 -0
- package/dist/types/Queries/index.d.ts +1 -0
- package/dist/types/Reconciler/SurgicalReconciler.d.ts +23 -0
- package/dist/types/RenderPipeline/RenderPipeline.d.ts +46 -0
- package/dist/types/RenderPipeline/RenderTree.d.ts +55 -0
- package/dist/types/RenderPipeline/index.d.ts +4 -0
- package/dist/types/Repair/NestingRepair.d.ts +48 -0
- package/dist/types/Repair/index.d.ts +1 -0
- package/dist/types/Semantic/SemanticAnalyzer.d.ts +321 -0
- package/dist/types/Semantic/index.d.ts +2 -0
- package/dist/types/Symbols/SymbolTable.d.ts +47 -0
- package/dist/types/Symbols/index.d.ts +1 -0
- package/dist/types/Syntax/GreenNode.d.ts +154 -0
- package/dist/types/Syntax/GreenNodePool.d.ts +134 -0
- package/dist/types/Syntax/NodeMatcher.d.ts +75 -0
- package/dist/types/Syntax/RedNode.d.ts +280 -0
- package/dist/types/Syntax/RedNodeStore.d.ts +116 -0
- package/dist/types/Syntax/TreeBuilder.d.ts +54 -0
- package/dist/types/Syntax/__tests__/GreenNode.test.d.ts +1 -0
- package/dist/types/Syntax/__tests__/RedNode.test.d.ts +1 -0
- package/dist/types/Syntax/__tests__/RedNodeStore.test.d.ts +1 -0
- package/dist/types/Syntax/greenEdit.d.ts +64 -0
- package/dist/types/Syntax/hash.d.ts +17 -0
- package/dist/types/Syntax/index.d.ts +8 -0
- package/dist/types/Syntax/nodeAttr.d.ts +63 -0
- package/dist/types/Syntax/partition.d.ts +67 -0
- package/dist/types/Syntax/preserveNodeIds.d.ts +47 -0
- package/dist/types/Tokens/TokenResolver.d.ts +25 -0
- package/dist/types/Tokens/index.d.ts +1 -0
- package/dist/types/Transactions/Transaction.d.ts +36 -0
- package/dist/types/Transactions/UndoManager.d.ts +63 -0
- package/dist/types/Transactions/index.d.ts +3 -0
- package/dist/types/Transformers/ASTOptimizer.d.ts +34 -0
- package/dist/types/Transformers/GradientTransformer.d.ts +18 -0
- package/dist/types/Transformers/GrowTransformer.d.ts +16 -0
- package/dist/types/Transformers/RainbowTransformer.d.ts +17 -0
- package/dist/types/Transformers/SineWaveTransformer.d.ts +17 -0
- package/dist/types/Transformers/Transformer.d.ts +17 -0
- package/dist/types/Types/core.d.ts +104 -0
- package/dist/types/Types/diagnostics.d.ts +85 -0
- package/dist/types/Types/index.d.ts +11 -0
- package/dist/types/Types/operations.d.ts +109 -0
- package/dist/types/Types/queries.d.ts +67 -0
- package/dist/types/Types/symbols.d.ts +42 -0
- package/dist/types/Types/tokens.d.ts +75 -0
- package/dist/types/Utils/BBCodeGenerator.d.ts +21 -0
- package/dist/types/Utils/ColorMath.d.ts +92 -0
- package/dist/types/Utils/EffectMath.d.ts +643 -0
- package/dist/types/Utils/TagVocabulary.d.ts +104 -0
- package/dist/types/Utils/TagVocabulary.test.d.ts +1 -0
- package/dist/types/Utils/color.d.ts +29 -0
- package/dist/types/Utils/dom-to-svg.d.ts +28 -0
- package/dist/types/Utils/dom-to-svg.test.d.ts +1 -0
- package/dist/types/Utils/treeTransformers.d.ts +160 -0
- package/dist/types/Visitors/BBBlocksExporter.d.ts +27 -0
- package/dist/types/Visitors/BBCodeExporter.d.ts +90 -0
- package/dist/types/Visitors/BlockPatcher.d.ts +91 -0
- package/dist/types/Visitors/DOMMorpher.d.ts +13 -0
- package/dist/types/Visitors/HTMLRenderer.d.ts +380 -0
- package/dist/types/Visitors/JSONExporter.d.ts +42 -0
- package/dist/types/Visitors/MarkdownExporter.d.ts +28 -0
- package/dist/types/Visitors/SVGRenderer.d.ts +16 -0
- package/dist/types/Visitors/TiptapExporter.d.ts +40 -0
- package/dist/types/Visitors/Visitor.d.ts +35 -0
- package/dist/types/Visitors/index.d.ts +9 -0
- package/dist/types/Visuals/BoxDrawer.d.ts +49 -0
- package/dist/types/Visuals/index.d.ts +38 -0
- package/dist/types/index.d.ts +154 -0
- package/package.json +14 -10
- package/src/Analysis/Passes/Analysis/ColorUsageAnalyzer.ts +103 -0
- package/src/Analysis/Passes/Analysis/GradientAnalyzer.ts +294 -20
- package/src/Analysis/Passes/Analysis/SymbolAnalyzer.ts +257 -0
- package/src/Analysis/Passes/Decision/PaletteRemapDecision.ts +425 -0
- package/src/Analysis/Pipeline/Pipeline.ts +15 -2
- package/src/Analysis/index.ts +8 -2
- package/src/BBCode/BBCodeDocumentModel.ts +3 -0
- package/src/BBCode/BBCodeToGreenNode.ts +18 -12
- package/src/BBCode/Parser.ts +38 -1
- package/src/Edits/EditPlan.ts +290 -0
- package/src/Edits/Optimizer.ts +185 -0
- package/src/Edits/Rules/Rule.ts +145 -0
- package/src/Edits/Rules/dropEmptyTags.ts +110 -0
- package/src/Edits/Rules/dropRedundantNesting.ts +120 -0
- package/src/Edits/Rules/index.ts +28 -0
- package/src/Edits/Rules/mergeAdjacent.ts +224 -0
- package/src/Edits/Rules/reorderWrappers.ts +154 -0
- package/src/Edits/Rules/shortenHex.ts +79 -0
- package/src/Edits/Rules/tagValue.ts +105 -0
- package/src/Edits/Rules/unwrapInvisibleColor.ts +93 -0
- package/src/Edits/applyEdits.ts +54 -0
- package/src/Edits/index.ts +22 -0
- package/src/Events/EventBus.ts +18 -0
- package/src/HTML/HTMLToGreenNode.ts +185 -37
- package/src/Incremental/BracketIndex.ts +249 -0
- package/src/Incremental/IncrementalParser.ts +464 -41
- package/src/Lexer/BBCodeLexer.ts +25 -3
- package/src/Lexer/index.ts +1 -1
- package/src/Markdown/MarkdownAST.ts +65 -2
- package/src/Markdown/MarkdownLexer.ts +69 -14
- package/src/Markdown/MarkdownParser.ts +749 -62
- package/src/Markdown/MarkdownToGreenNode.ts +148 -27
- package/src/MilHibri/MilHibriDocumentModel.ts +56 -0
- package/src/Model/DocumentModel.ts +138 -5
- package/src/Model/TagRegistry.ts +129 -134
- package/src/Reconciler/SurgicalReconciler.ts +460 -0
- package/src/Repair/NestingRepair.ts +116 -0
- package/src/Repair/index.ts +1 -0
- package/src/Semantic/SemanticAnalyzer.ts +1802 -65
- package/src/Syntax/GreenNodePool.ts +12 -12
- package/src/Syntax/RedNode.ts +17 -3
- package/src/Syntax/RedNodeStore.ts +9 -1
- package/src/Syntax/nodeAttr.ts +172 -0
- package/src/Tokens/TokenResolver.ts +55 -0
- package/src/Tokens/index.ts +1 -0
- package/src/Types/core.ts +15 -0
- package/src/Utils/ColorMath.ts +276 -55
- package/src/Utils/EffectMath.ts +2462 -0
- package/src/Utils/TagVocabulary.ts +141 -0
- package/src/Utils/dom-to-svg.ts +28 -12
- package/src/Visitors/BBBlocksExporter.ts +15 -1
- package/src/Visitors/BBCodeExporter.ts +319 -32
- package/src/Visitors/BlockPatcher.ts +87 -11
- package/src/Visitors/DOMMorpher.ts +15 -5
- package/src/Visitors/HTMLRenderer.ts +374 -151
- package/src/Visitors/MarkdownExporter.ts +98 -41
- package/src/Visitors/TiptapExporter.ts +1 -0
- package/src/Visuals/index.ts +7 -4
- package/src/Visuals/lyne.css +117 -6
- package/src/Visuals/osu.css +36 -5
- package/src/index.ts +172 -5
- package/dist/index.d.mts +0 -4612
- package/dist/index.d.ts +0 -4612
- package/src/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.ts +0 -135
- package/src/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.ts +0 -84
- package/src/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.ts +0 -99
- package/src/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.ts +0 -119
- package/src/Analysis/Passes/Decision/__tests__/DefaultDecision.test.ts +0 -179
- package/src/Analysis/__tests__/Integration.test.ts +0 -162
- package/src/Analysis/__tests__/Pipeline.test.ts +0 -133
- package/src/Diff/__tests__/TreeDiffer.test.ts +0 -65
- package/src/Incremental/__tests__/IncrementalParser.test.ts +0 -164
- package/src/Syntax/__tests__/GreenNode.test.ts +0 -33
- package/src/Syntax/__tests__/RedNode.test.ts +0 -81
- package/src/Syntax/__tests__/RedNodeStore.test.ts +0 -104
- package/src/Tests/ASTOptimizerIdempotence.test.ts +0 -77
- package/src/Tests/BlockPatcher.test.ts +0 -437
- package/src/Tests/BlockPatcherWindowed.test.ts +0 -364
- package/src/Tests/BoxDrawer.test.ts +0 -217
- package/src/Tests/BoxRichTitle.test.ts +0 -105
- package/src/Tests/Chars500kBenchmark.test.ts +0 -151
- package/src/Tests/Chars500kEdits.test.ts +0 -321
- package/src/Tests/CollabPositions.test.ts +0 -146
- package/src/Tests/CompilerPathProfiling.test.ts +0 -186
- package/src/Tests/DOMMorpher.test.ts +0 -142
- package/src/Tests/DomPatchPerf.test.ts +0 -60
- package/src/Tests/EffectSegments.snapshot.json +0 -616
- package/src/Tests/EffectSegments.test.ts +0 -68
- package/src/Tests/FindNodeAtOffset.test.ts +0 -65
- package/src/Tests/Fuzzer.test.ts +0 -166
- package/src/Tests/GreenNodePool.test.ts +0 -153
- package/src/Tests/Lexer.test.ts +0 -238
- package/src/Tests/LyneMode.test.ts +0 -291
- package/src/Tests/ModelCoherence.test.ts +0 -180
- package/src/Tests/Partition.test.ts +0 -238
- package/src/Tests/PluginTags.test.ts +0 -150
- package/src/Tests/ProblematicSection.test.ts +0 -46
- package/src/Tests/ProblematicSectionHTML.test.ts +0 -58
- package/src/Tests/RedReuse.test.ts +0 -134
- package/src/Tests/ReproDelete20k.test.ts +0 -62
- package/src/Tests/SemanticValidators.test.ts +0 -136
- package/src/Tests/StableNodeIds.test.ts +0 -210
- package/src/Tests/StudioColorBloat.test.ts +0 -25
- package/src/Tests/StudioDebugText.test.ts +0 -27
- package/src/Tests/StudioTrailingChar.test.ts +0 -25
- package/src/Tests/StudioValidText.test.ts +0 -25
- package/src/Tests/UrlImgBug.test.ts +0 -23
- package/src/Tests/VisualBuilderFidelity.test.ts +0 -105
- package/src/Tests/referenceDocument.ts +0 -119
- package/src/Utils/dom-to-svg.test.ts +0 -86
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — HTMLRenderer
|
|
3
|
+
*
|
|
4
|
+
* Renders the Document Model to HTML for preview.
|
|
5
|
+
* This is the main renderer for the visual BBCode preview.
|
|
6
|
+
*
|
|
7
|
+
* Uses the TagRegistry for custom rendering.
|
|
8
|
+
* Plugins can register custom renderers for preview components.
|
|
9
|
+
*/
|
|
10
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
11
|
+
import { Visitor } from './Visitor';
|
|
12
|
+
import type { TagRegistry } from '../Model/TagRegistry';
|
|
13
|
+
import type { BBCodeDialect } from '../BBCode/BBCodeToGreenNode';
|
|
14
|
+
import { type TokenResolverFn, type TokenSource } from '../Tokens';
|
|
15
|
+
export interface HTMLRendererOptions {
|
|
16
|
+
/**
|
|
17
|
+
* Replicate osu! forum BBCode spacing quirks.
|
|
18
|
+
* Defaults to true for full compatibility with Miliastry.
|
|
19
|
+
* Set to false for a more logical, predictable rendering engine.
|
|
20
|
+
*/
|
|
21
|
+
osuBehaviour?: boolean;
|
|
22
|
+
/** Registry for resolving custom tags */
|
|
23
|
+
registry?: TagRegistry;
|
|
24
|
+
/** BBCode dialect to render for ('osu' | 'miliastry' | 'lyne') */
|
|
25
|
+
dialect?: BBCodeDialect;
|
|
26
|
+
/** Visual theme for markup classes ('osu' | 'lyne' | 'miliastry') */
|
|
27
|
+
theme?: 'osu' | 'lyne' | 'miliastry';
|
|
28
|
+
/** Safe media proxy callback to rewrite image and media URLs */
|
|
29
|
+
mediaProxy?: (url: string) => string;
|
|
30
|
+
/** Resolver for entity links like profile, guild, map */
|
|
31
|
+
entityLinkResolver?: (kind: string, value: string) => {
|
|
32
|
+
href: string;
|
|
33
|
+
external?: boolean;
|
|
34
|
+
} | null;
|
|
35
|
+
/**
|
|
36
|
+
* Forum-style `@mention` linkifier. Called with the bare name (no `@`);
|
|
37
|
+
* return null to leave the mention as plain text. Used by forum hosts that
|
|
38
|
+
* linkify `@username` to a profile route.
|
|
39
|
+
*/
|
|
40
|
+
mentionResolver?: (name: string) => {
|
|
41
|
+
href: string;
|
|
42
|
+
external?: boolean;
|
|
43
|
+
} | null;
|
|
44
|
+
/**
|
|
45
|
+
* Timestamp chip linkifier (`1:23`, `01:23.456`, `01:23:456`). Called with
|
|
46
|
+
* the millisecond offset and the display label; return null to leave the
|
|
47
|
+
* timestamp as plain text. Used by map hosts that deep-link into an editor.
|
|
48
|
+
*/
|
|
49
|
+
timestampResolver?: (ms: number, label: string) => {
|
|
50
|
+
href: string;
|
|
51
|
+
external?: boolean;
|
|
52
|
+
} | null;
|
|
53
|
+
/** Design tokens or resolver function */
|
|
54
|
+
tokens?: TokenSource;
|
|
55
|
+
}
|
|
56
|
+
export declare class HTMLRenderer extends Visitor<string> {
|
|
57
|
+
private tokenResolver?;
|
|
58
|
+
private options;
|
|
59
|
+
constructor(options?: HTMLRendererOptions);
|
|
60
|
+
setTokens(tokens?: TokenSource): void;
|
|
61
|
+
getTokenResolver(): TokenResolverFn | undefined;
|
|
62
|
+
private readonly BLOCK_TAGS;
|
|
63
|
+
private readonly INLINE_TAGS;
|
|
64
|
+
/**
|
|
65
|
+
* The ` data-node-id="…"` attribute, or `''` for nodes nobody looks up.
|
|
66
|
+
*
|
|
67
|
+
* ─── Why this is not emitted on everything ──────────────────────────────
|
|
68
|
+
*
|
|
69
|
+
* It used to be, carrying `node.id` — a process-global counter minted per
|
|
70
|
+
* RedNode, so a reparse renames every node in the document. Measured on a
|
|
71
|
+
* one-character edit: zero ids survive.
|
|
72
|
+
*
|
|
73
|
+
* `DOMMorpher` already noted that this rules the ids out as morph KEYS. The
|
|
74
|
+
* larger cost is that it also breaks the morpher's prefix/suffix trim, which
|
|
75
|
+
* uses `isEqualNode` — a comparison that includes attributes. An attribute
|
|
76
|
+
* that always differs makes every element compare unequal, so the trim never
|
|
77
|
+
* fires and the morpher walks the whole document. Measured on one keystroke
|
|
78
|
+
* in the reference document: **1665 `setAttribute` calls across 1725
|
|
79
|
+
* elements**, to write new numbers meaning the same thing, when the actual
|
|
80
|
+
* change was 10 insertions and 9 removals.
|
|
81
|
+
*
|
|
82
|
+
* ─── Why BLOCKS, and not stable ids ─────────────────────────────────────
|
|
83
|
+
*
|
|
84
|
+
* Making the id stable was the obvious repair and it does not work. Keying on
|
|
85
|
+
* the node's SPAN was measured: an edit at the END drops the writes to 6, but
|
|
86
|
+
* an insertion shifts every offset after it, so an edit near the START still
|
|
87
|
+
* cost 1637 — and spans are longer strings than `nN`, so the emitted HTML grew
|
|
88
|
+
* 10%. Stability under insertion is not something a position can have.
|
|
89
|
+
*
|
|
90
|
+
* The real observation is that no consumer ever wanted these on inline nodes.
|
|
91
|
+
* Both readers in the app are block-level: `usePreviewClick` walks up with
|
|
92
|
+
* `closest('[data-node-id]')` for *block selection*, and `useBlockHighlight`
|
|
93
|
+
* highlights and scrolls to a *block*. Emitting ids on the per-character
|
|
94
|
+
* spans of a gradient did not just cost — it made `closest()` stop at a
|
|
95
|
+
* character instead of the block the click meant.
|
|
96
|
+
*
|
|
97
|
+
* So the attribute goes where it is read. Inline nodes carry no id, compare
|
|
98
|
+
* equal, and let `isEqualNode` skip their subtrees natively; the handful of
|
|
99
|
+
* block containers that do carry one are few enough that their churn is
|
|
100
|
+
* noise.
|
|
101
|
+
*/
|
|
102
|
+
/**
|
|
103
|
+
* Text leaves emit their content directly, with no wrapper element.
|
|
104
|
+
*
|
|
105
|
+
* They used to come wrapped in `<span class="bb-text">` — one extra DOM
|
|
106
|
+
* element per text leaf, which is HALF the preview's elements (measured:
|
|
107
|
+
* 1726 → 851 on a 19.6 KB post, 17251 → 8510 on a 196 KB one). The class
|
|
108
|
+
* earned none of it: it has no CSS rule anywhere in the repo, carries no
|
|
109
|
+
* `data-node-id` (text is not an id-bearing kind, so click mapping and
|
|
110
|
+
* highlighting never looked at it), and every style a text leaf can have
|
|
111
|
+
* still emits its own `<span style="…">` below.
|
|
112
|
+
*
|
|
113
|
+
* A/B in a production build, steady state: flush 41.4 → 39.7 ms at 19.6 KB
|
|
114
|
+
* and 55.4 → 46.4 ms at 196 KB, plus ~27% less HTML to serialize and parse.
|
|
115
|
+
*/
|
|
116
|
+
private textWrap;
|
|
117
|
+
/**
|
|
118
|
+
* A qué elementos se les pone `data-node-id`.
|
|
119
|
+
*
|
|
120
|
+
* `'all'` (por defecto) — a todos. Es lo que permite que un clic en
|
|
121
|
+
* CUALQUIER punto del preview señale ese nodo exacto en el editor: en un
|
|
122
|
+
* degradado cada carácter es su propio nodo, y sin id no hay nada a lo que
|
|
123
|
+
* `closest()` pueda agarrarse.
|
|
124
|
+
*
|
|
125
|
+
* Esto estuvo desactivado por una buena razón que ya no aplica. Los ids se
|
|
126
|
+
* regeneraban en cada parseo, así que el atributo cambiaba en TODOS los
|
|
127
|
+
* elementos por pulsación: `isEqualNode` no casaba nunca, el morpher no
|
|
128
|
+
* podía saltarse ningún subárbol y se medían 1665 `setAttribute` sobre 1725
|
|
129
|
+
* elementos para escribir números nuevos que significaban lo mismo. Con la
|
|
130
|
+
* identidad estable entre reparseos eso desapareció: un nodo que no cambia
|
|
131
|
+
* conserva su id, su HTML es idéntico y el camino rápido del morpher sigue
|
|
132
|
+
* funcionando.
|
|
133
|
+
*
|
|
134
|
+
* El coste que queda es el tamaño: ~10 bytes por elemento, que hay que
|
|
135
|
+
* serializar y parsear. Medido con A/B en la misma sesión sobre el post con
|
|
136
|
+
* degradados (19,6 KB, 852 elementos):
|
|
137
|
+
*
|
|
138
|
+
* solo bloques (9 con id): latencia 48 ms · p95 72 ms
|
|
139
|
+
* todos (808 con id): latencia 56 ms · p95 104 ms
|
|
140
|
+
*
|
|
141
|
+
* Se paga a propósito: la precisión del clic es una función que se pidió, y
|
|
142
|
+
* 56 ms sigue holgadamente dentro de lo que se percibe como inmediato.
|
|
143
|
+
* `'blocks'` queda disponible para quien priorice la latencia, y `'none'`
|
|
144
|
+
* para los consumidores de solo lectura (foros, render estático): sin
|
|
145
|
+
* `data-node-id` en absoluto, el HTML es más pequeño y no hay nada que
|
|
146
|
+
* mantenga vivos los nodos del árbol.
|
|
147
|
+
*/
|
|
148
|
+
static idMode: 'blocks' | 'all' | 'none';
|
|
149
|
+
/**
|
|
150
|
+
* Nesting depth of `[tables]` while rendering. `[col]`/`[row]`/`[th]` are
|
|
151
|
+
* table cells only INSIDE a `[tables]`; orphaned ones (e.g. `[col]` inside
|
|
152
|
+
* `[columns]`, or stray cells) render as plain inline spans — the same rule
|
|
153
|
+
* LYNE's forum renderer applies.
|
|
154
|
+
*/
|
|
155
|
+
private tableDepth;
|
|
156
|
+
private idAttr;
|
|
157
|
+
/**
|
|
158
|
+
* Kinds that carry `data-node-id`.
|
|
159
|
+
*
|
|
160
|
+
* The block containers a user can select or be scrolled to, plus the media
|
|
161
|
+
* nodes, which are atomic and clickable in their own right. Deliberately NOT
|
|
162
|
+
* `text` or any inline formatting kind — see {@link idAttr}.
|
|
163
|
+
*/
|
|
164
|
+
private static readonly ID_BEARING_KINDS;
|
|
165
|
+
visit(node: RedNode): string;
|
|
166
|
+
/**
|
|
167
|
+
* Ancho de cada tabla abierta, apilado igual que `tableDepth`.
|
|
168
|
+
*
|
|
169
|
+
* `getTableContext` corre una vez POR CELDA y recorría todas las filas de
|
|
170
|
+
* la tabla en cada llamada, con un `.filter()` —y su array— por fila: una
|
|
171
|
+
* tabla de 20×20 hacía 8.000 arrays intermedios por renderizado para
|
|
172
|
+
* llegar 400 veces al mismo número. Ahora se calcula una vez al entrar en
|
|
173
|
+
* la tabla. Va en una pila y no en un caché por nodo porque los hijos de un
|
|
174
|
+
* `RedNode` SON mutables (`appendChild`/`removeChild`), así que la
|
|
175
|
+
* identidad del nodo no garantiza que su estructura siga siendo la misma
|
|
176
|
+
* entre renderizados.
|
|
177
|
+
*/
|
|
178
|
+
private maxColsStack;
|
|
179
|
+
render(root: RedNode): string;
|
|
180
|
+
/**
|
|
181
|
+
* Render every child and concatenate.
|
|
182
|
+
*
|
|
183
|
+
* Replaces the `children.map(c => this.renderNode(c)).join('')` idiom, which
|
|
184
|
+
* was repeated at 16 call sites and allocated a closure plus an intermediate
|
|
185
|
+
* array of N strings at every level of the tree. Appending to one string lets
|
|
186
|
+
* the engine use its rope representation instead.
|
|
187
|
+
*/
|
|
188
|
+
/**
|
|
189
|
+
* Render the direct children of `node` to HTML (no wrapper element).
|
|
190
|
+
*
|
|
191
|
+
* Public so the incremental preview (`BlockPatcher`) can morph a block
|
|
192
|
+
* element's inner content without re-rendering the whole document.
|
|
193
|
+
*/
|
|
194
|
+
renderChildren(node: RedNode): string;
|
|
195
|
+
private renderNode;
|
|
196
|
+
/** osu! quirk: newlines immediately preceding a [code] block are completely ignored */
|
|
197
|
+
private isNextCodeBlock;
|
|
198
|
+
/** Checks if this is the LAST empty_line right before a code block (skipping only spacing) */
|
|
199
|
+
private isImmediateEmptyLineBeforeCode;
|
|
200
|
+
private isPrevBlockBoundary;
|
|
201
|
+
private isTrailingBlockBoundary;
|
|
202
|
+
private renderError;
|
|
203
|
+
private wrapInline;
|
|
204
|
+
private wrapBlock;
|
|
205
|
+
/** Characters `escapeHtml` has to rewrite. Non-global on purpose: `test` must not carry `lastIndex`. */
|
|
206
|
+
private static readonly HTML_ESCAPE_RE;
|
|
207
|
+
private static readonly NAMED_COLORS;
|
|
208
|
+
/** Keyword-or-number CSS values (font-weight, font-style, text-decoration). */
|
|
209
|
+
private isCssKeyword;
|
|
210
|
+
/** Read a metadata field, falling back to the raw tag attribute. */
|
|
211
|
+
private colorStyle;
|
|
212
|
+
private fontSizeStyle;
|
|
213
|
+
private fontStyle;
|
|
214
|
+
private renderLink;
|
|
215
|
+
private renderProfile;
|
|
216
|
+
private renderEntity;
|
|
217
|
+
/**
|
|
218
|
+
* El aviso que ocupa el sitio de un medio que no se puede pintar.
|
|
219
|
+
*
|
|
220
|
+
* Lleva `data-bb-empty` con la etiqueta de origen porque el camino
|
|
221
|
+
* HTML→BBCode lee de vuelta lo que hay en el lienzo: sin la marca, el texto
|
|
222
|
+
* del aviso entraba al documento como contenido y se comía la etiqueta. En
|
|
223
|
+
* `docs/ai/hxovc.bbcode`, con cinco `[img][/img]` vacíos, cada edición del
|
|
224
|
+
* bloque convertía otro en la frase «[img] missing source URL».
|
|
225
|
+
*/
|
|
226
|
+
private mediaError;
|
|
227
|
+
private renderImage;
|
|
228
|
+
private renderVideo;
|
|
229
|
+
private renderAudio;
|
|
230
|
+
private hexToRgba;
|
|
231
|
+
private renderNotice;
|
|
232
|
+
private renderTables;
|
|
233
|
+
/** Celdas directas de una fila, sin materializar un array intermedio. */
|
|
234
|
+
private static countCells;
|
|
235
|
+
/**
|
|
236
|
+
* Columnas de la tabla más ancha bajo `tableNode`, memoizado por tabla.
|
|
237
|
+
*
|
|
238
|
+
* `getTableContext` se llama una vez POR CELDA, y recorría todas las filas
|
|
239
|
+
* de la tabla en cada llamada, con un `.filter()` —y su array— por fila.
|
|
240
|
+
* Una tabla de 20×20 hacía 8.000 arrays intermedios en cada renderizado
|
|
241
|
+
* para llegar 400 veces al mismo número. El caché se vacía al empezar cada
|
|
242
|
+
* render, así que no retiene nodos entre documentos.
|
|
243
|
+
*/
|
|
244
|
+
private static widestRow;
|
|
245
|
+
private getTableContext;
|
|
246
|
+
private renderGallery;
|
|
247
|
+
private renderColumns;
|
|
248
|
+
private renderSeparator;
|
|
249
|
+
private renderScroll;
|
|
250
|
+
private renderAbbr;
|
|
251
|
+
private renderTooltip;
|
|
252
|
+
private renderRaw;
|
|
253
|
+
private renderPlain;
|
|
254
|
+
private renderAlign;
|
|
255
|
+
private renderEffect;
|
|
256
|
+
private renderAnim;
|
|
257
|
+
private renderContainer;
|
|
258
|
+
private static readonly STYLE_PROP_WHITELIST;
|
|
259
|
+
private renderStyleTag;
|
|
260
|
+
private renderQuote;
|
|
261
|
+
private renderSpoilerbox;
|
|
262
|
+
private renderBox;
|
|
263
|
+
/**
|
|
264
|
+
* Marca un `[box]`/`[spoilerbox]` sin título propio.
|
|
265
|
+
*
|
|
266
|
+
* El `<summary>` siempre lleva texto ("Box", "Spoiler"), así que sin esta
|
|
267
|
+
* marca el camino HTML→BBCode leía ese relleno como si el autor lo hubiera
|
|
268
|
+
* escrito y devolvía `[box=Box]`.
|
|
269
|
+
*/
|
|
270
|
+
private bareTitleAttr;
|
|
271
|
+
private renderTitle;
|
|
272
|
+
/**
|
|
273
|
+
* `[box=Title:#hex]`, `[tables=striped:#hex]`, `[columns=2:#hex]` → un
|
|
274
|
+
* ` style="--<suffix>-accent:#hex;"` del que el CSS deriva la paleta
|
|
275
|
+
* (título + chevron y borde en boxw; gradientes/header/hover en tables;
|
|
276
|
+
* borde + fondo en columns). Devuelve '' si no hay color válido.
|
|
277
|
+
*/
|
|
278
|
+
private boxAccentStyle;
|
|
279
|
+
private renderList;
|
|
280
|
+
private renderListItem;
|
|
281
|
+
private renderCode;
|
|
282
|
+
private renderSVG;
|
|
283
|
+
/**
|
|
284
|
+
* Render an osu! BBCode imagemap.
|
|
285
|
+
*
|
|
286
|
+
* Structure:
|
|
287
|
+
* [imagemap]
|
|
288
|
+
* https://example.com/image.png ← first line = image URL
|
|
289
|
+
* 10 20 50 60 https://... Label ← subsequent lines = clickable areas
|
|
290
|
+
* [/imagemap]
|
|
291
|
+
*
|
|
292
|
+
* Each area line format: x y width height url [label]
|
|
293
|
+
* All values are PERCENTAGES (0–100) relative to the image dimensions.
|
|
294
|
+
* Uses CSS absolute positioning with percentage coordinates.
|
|
295
|
+
*/
|
|
296
|
+
private renderImagemap;
|
|
297
|
+
private collectNodeText;
|
|
298
|
+
/**
|
|
299
|
+
* Effect parameters off a node, with every colour re-validated.
|
|
300
|
+
*
|
|
301
|
+
* `startsWith('#')` was NOT a filter: `#a" onmouseover="alert(1)` passes
|
|
302
|
+
* it. Every stop has to survive the full colour allowlist or be dropped,
|
|
303
|
+
* because these values end up inside a `style` attribute.
|
|
304
|
+
*/
|
|
305
|
+
private effectParams;
|
|
306
|
+
/** Text inside an effect node, ignoring layout-only children. */
|
|
307
|
+
/**
|
|
308
|
+
* The plain text an effect modulates, line breaks included.
|
|
309
|
+
*
|
|
310
|
+
* A break is a childless `spacing` leaf carrying no text, so collecting
|
|
311
|
+
* it naively contributes nothing and the effect sees one long line.
|
|
312
|
+
* Every two-dimensional axis then collapses: `line` reports zero for
|
|
313
|
+
* the whole block, `column` stretches one row across the paragraph, and
|
|
314
|
+
* `radial` measures a rectangle one line tall. The break was being
|
|
315
|
+
* dropped from the OUTPUT as well, so a multi-line effect previewed as
|
|
316
|
+
* a single run-on line.
|
|
317
|
+
*
|
|
318
|
+
* The document's own plain text spells a break `\n` — that is what
|
|
319
|
+
* `stripColorWrappers` and the studio's sampler both count — so this
|
|
320
|
+
* agrees with them rather than inventing a third answer.
|
|
321
|
+
*/
|
|
322
|
+
private effectText;
|
|
323
|
+
private effectChildText;
|
|
324
|
+
/**
|
|
325
|
+
* Paint an effect's computed segments as spans.
|
|
326
|
+
*
|
|
327
|
+
* Shared by rainbow, grow and any modulated gradient, so the preview
|
|
328
|
+
* shows exactly the colours and sizes the BBCode export will contain
|
|
329
|
+
* rather than an approximation of them.
|
|
330
|
+
*/
|
|
331
|
+
private renderEffectSegments;
|
|
332
|
+
/**
|
|
333
|
+
* A gradient previews as a real CSS gradient when it is a plain
|
|
334
|
+
* left-to-right ramp, and as computed per-character spans otherwise.
|
|
335
|
+
*
|
|
336
|
+
* The CSS path is genuinely smoother — it interpolates per pixel rather
|
|
337
|
+
* than per glyph — but it can only express a linear sweep. A gradient
|
|
338
|
+
* with a waveform, a non-index axis or quantisation steps looked
|
|
339
|
+
* nothing like its own export while this was the only path.
|
|
340
|
+
*/
|
|
341
|
+
private renderGradient;
|
|
342
|
+
/**
|
|
343
|
+
* Escape for both text content and double-quoted attribute values.
|
|
344
|
+
*
|
|
345
|
+
* `'` is included because attribute values elsewhere in the codebase (and in
|
|
346
|
+
* consumer-supplied tag handlers) may be single-quoted; leaving it raw makes
|
|
347
|
+
* the escaping context-dependent, which is how injections get reintroduced.
|
|
348
|
+
*/
|
|
349
|
+
/**
|
|
350
|
+
* Escape the five HTML-significant characters.
|
|
351
|
+
*
|
|
352
|
+
* Was five chained `.replace(/x/g, …)` calls: five full scans of the string
|
|
353
|
+
* and up to five intermediate allocations for *every* text node, even though
|
|
354
|
+
* ordinary prose contains none of these characters. This tests once and
|
|
355
|
+
* returns the input untouched in that common case, then does a single pass
|
|
356
|
+
* when there is actually something to escape.
|
|
357
|
+
*/
|
|
358
|
+
/** Resolver configured at construction (read through a getter for brevity). */
|
|
359
|
+
private get mentionResolver();
|
|
360
|
+
/**
|
|
361
|
+
* `@mention` shape used by forum hosts: 3-15 word chars, boundaries that
|
|
362
|
+
* exclude longer usernames (same rule LYNE's forum uses). Non-global so
|
|
363
|
+
* `lastIndex` never leaks between calls.
|
|
364
|
+
*/
|
|
365
|
+
private static readonly MENTION_RE;
|
|
366
|
+
/**
|
|
367
|
+
* Linkify a plain-text leaf: `@mention` runs and (optionally) timestamp
|
|
368
|
+
* chips. Both run through their resolver; null leaves the run as text.
|
|
369
|
+
* Every interpolated string is HTML-escaped, and hrefs with dangerous
|
|
370
|
+
* protocols (javascript:, data:, vbscript:) are rejected (defence in depth;
|
|
371
|
+
* the resolvers themselves should never produce one).
|
|
372
|
+
*/
|
|
373
|
+
private linkifyText;
|
|
374
|
+
/** `1:23`, `01:23.456`, `01:23:456` — the editor deep-link shape. */
|
|
375
|
+
private static readonly TS_RE;
|
|
376
|
+
private linkifyTimestamps;
|
|
377
|
+
/** Root-relative, http(s), mailto and line:// hrefs are the only safe shapes. */
|
|
378
|
+
private isSafeHref;
|
|
379
|
+
private escapeHtml;
|
|
380
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — JSONExporter
|
|
3
|
+
*
|
|
4
|
+
* Exports the Document Model to JSON.
|
|
5
|
+
* Useful for:
|
|
6
|
+
* - Saving/loading documents in a structured format
|
|
7
|
+
* - Sending over the wire (collaboration)
|
|
8
|
+
* - Debugging and inspecting the document tree
|
|
9
|
+
* - Import/export between different tools
|
|
10
|
+
*/
|
|
11
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
12
|
+
import { Visitor } from './Visitor';
|
|
13
|
+
export interface JSONDocument {
|
|
14
|
+
version: number;
|
|
15
|
+
kind: string;
|
|
16
|
+
nodes: JSONNode[];
|
|
17
|
+
metadata?: Record<string, unknown>;
|
|
18
|
+
}
|
|
19
|
+
export interface JSONNode {
|
|
20
|
+
id: string;
|
|
21
|
+
kind: string;
|
|
22
|
+
text: string;
|
|
23
|
+
version: number;
|
|
24
|
+
children: JSONNode[];
|
|
25
|
+
attributes?: Record<string, unknown>;
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
range?: {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export declare class JSONExporter extends Visitor<string> {
|
|
33
|
+
/**
|
|
34
|
+
* Export a RedNode tree to a JSON string.
|
|
35
|
+
*/
|
|
36
|
+
visit(node: RedNode): string;
|
|
37
|
+
/**
|
|
38
|
+
* Export to a JSON object.
|
|
39
|
+
*/
|
|
40
|
+
toJSON(node: RedNode): JSONDocument;
|
|
41
|
+
private serializeNode;
|
|
42
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — MarkdownExporter
|
|
3
|
+
*
|
|
4
|
+
* Exports the Document Model to Markdown with hybrid BBCode embedding
|
|
5
|
+
* for features not natively supported in standard CommonMark (color, size,
|
|
6
|
+
* underline, alignment, collapsible boxes).
|
|
7
|
+
*/
|
|
8
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
9
|
+
import { Visitor } from './Visitor';
|
|
10
|
+
export declare class MarkdownExporter extends Visitor<string> {
|
|
11
|
+
visit(node: RedNode): string;
|
|
12
|
+
export(node: RedNode): string;
|
|
13
|
+
private exportNode;
|
|
14
|
+
private renderTitleMarkdown;
|
|
15
|
+
/**
|
|
16
|
+
* Read a BBCode tag's `=VALUE` attribute.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* El atributo del nodo, o `undefined` si no lleva.
|
|
20
|
+
*
|
|
21
|
+
* El recorte lo hace `nodeAttrValue`, el mismo lector del `HTMLRenderer`;
|
|
22
|
+
* aquí sólo se cambia el contrato del caso vacío. Este exportador encadena
|
|
23
|
+
* `metadata ?? atributo ?? contenido`, así que necesita un `undefined`
|
|
24
|
+
* explícito donde `nodeAttrValue` devuelve el texto crudo — es la única
|
|
25
|
+
* diferencia, y por eso no se llama directamente.
|
|
26
|
+
*/
|
|
27
|
+
private extractValue;
|
|
28
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
2
|
+
import { Visitor } from './Visitor';
|
|
3
|
+
import type { VisitorContext } from './Visitor';
|
|
4
|
+
/**
|
|
5
|
+
* SVGRenderer (Runtime ForeignObject Strategy)
|
|
6
|
+
*
|
|
7
|
+
* Instead of attempting to calculate CSS layouts manually,
|
|
8
|
+
* this runtime renderer wraps the exact HTML output in an SVG <foreignObject>.
|
|
9
|
+
*
|
|
10
|
+
* This gives 100% precision with zero DOM scanning overhead for real-time previews.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SVGRenderer extends Visitor<string> {
|
|
13
|
+
private htmlRenderer;
|
|
14
|
+
visit(node: RedNode, context?: VisitorContext): string;
|
|
15
|
+
render(root: RedNode): string;
|
|
16
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — TiptapExporter
|
|
3
|
+
*
|
|
4
|
+
* Exports the Document Model to Tiptap (ProseMirror) JSON format.
|
|
5
|
+
* This proves how easily Quasar's AST bridges to visual WYSIWYG editors.
|
|
6
|
+
*
|
|
7
|
+
* Tiptap uses a JSON format structured like:
|
|
8
|
+
* {
|
|
9
|
+
* type: "doc",
|
|
10
|
+
* content: [
|
|
11
|
+
* {
|
|
12
|
+
* type: "paragraph",
|
|
13
|
+
* content: [
|
|
14
|
+
* { type: "text", text: "Hello ", marks: [{ type: "bold" }] }
|
|
15
|
+
* ]
|
|
16
|
+
* }
|
|
17
|
+
* ]
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
21
|
+
import { Visitor } from './Visitor';
|
|
22
|
+
export interface TiptapNode {
|
|
23
|
+
type: string;
|
|
24
|
+
attrs?: Record<string, any>;
|
|
25
|
+
content?: TiptapNode[];
|
|
26
|
+
marks?: TiptapMark[];
|
|
27
|
+
text?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface TiptapMark {
|
|
30
|
+
type: string;
|
|
31
|
+
attrs?: Record<string, any>;
|
|
32
|
+
}
|
|
33
|
+
export declare class TiptapExporter extends Visitor<string> {
|
|
34
|
+
visit(node: RedNode): string;
|
|
35
|
+
toTiptap(node: RedNode): TiptapNode;
|
|
36
|
+
private processChildren;
|
|
37
|
+
private processNode;
|
|
38
|
+
private kindToMark;
|
|
39
|
+
private kindToBlockType;
|
|
40
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — Visitor
|
|
3
|
+
*
|
|
4
|
+
* Base visitor pattern for traversing the Red Tree.
|
|
5
|
+
* All exporters and renderers extend this.
|
|
6
|
+
*
|
|
7
|
+
* Instead of switch statements on tag names, use the visitor pattern.
|
|
8
|
+
* New languages/exporters don't modify existing code.
|
|
9
|
+
*
|
|
10
|
+
* Inspired by SwiftSyntax's Visitor pattern.
|
|
11
|
+
*/
|
|
12
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
13
|
+
export interface VisitorContext {
|
|
14
|
+
source: string;
|
|
15
|
+
options: Record<string, unknown>;
|
|
16
|
+
}
|
|
17
|
+
export declare abstract class Visitor<T = string> {
|
|
18
|
+
protected context: VisitorContext;
|
|
19
|
+
/**
|
|
20
|
+
* Visit a node and produce an output value.
|
|
21
|
+
*/
|
|
22
|
+
abstract visit(node: RedNode, context?: VisitorContext): T;
|
|
23
|
+
/**
|
|
24
|
+
* Visit all children and combine results.
|
|
25
|
+
*/
|
|
26
|
+
visitChildren(node: RedNode, separator?: string): T[];
|
|
27
|
+
/**
|
|
28
|
+
* Get the text content of a node.
|
|
29
|
+
*/
|
|
30
|
+
getText(node: RedNode): string;
|
|
31
|
+
/**
|
|
32
|
+
* Set the visitor context.
|
|
33
|
+
*/
|
|
34
|
+
setContext(context: VisitorContext): void;
|
|
35
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { Visitor } from './Visitor';
|
|
2
|
+
export type { VisitorContext } from './Visitor';
|
|
3
|
+
export { BBCodeExporter } from './BBCodeExporter';
|
|
4
|
+
export { HTMLRenderer } from './HTMLRenderer';
|
|
5
|
+
export { morphHTML } from './DOMMorpher';
|
|
6
|
+
export { MarkdownExporter } from './MarkdownExporter';
|
|
7
|
+
export { JSONExporter } from './JSONExporter';
|
|
8
|
+
export { SVGRenderer } from './SVGRenderer';
|
|
9
|
+
export type { JSONDocument, JSONNode } from './JSONExporter';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — BoxDrawer
|
|
3
|
+
*
|
|
4
|
+
* Drawer-style open/close animation for the `<details>` elements that
|
|
5
|
+
* HTMLRenderer emits for `[box]` and `[spoilerbox]`. The box grows downwards
|
|
6
|
+
* and progressively uncovers its content, which stays anchored under the
|
|
7
|
+
* summary instead of popping in all at once.
|
|
8
|
+
*
|
|
9
|
+
* This lives in Quasar rather than in a consumer because Quasar is what emits
|
|
10
|
+
* the `<details>` in the first place — the same reason `morphHTML` lives here.
|
|
11
|
+
* Any host that renders Quasar output gets the behaviour by binding it once.
|
|
12
|
+
*
|
|
13
|
+
* Why not CSS: while a `<details>` is closed its content is not rendered, so
|
|
14
|
+
* there is no height to interpolate between. `::details-content` combined with
|
|
15
|
+
* `interpolate-size: allow-keywords` would solve it, but it is Chromium-only in
|
|
16
|
+
* practice and hosts running on WebKit would silently lose the animation.
|
|
17
|
+
* Measuring the real height and driving it with the Web Animations API works on
|
|
18
|
+
* every engine.
|
|
19
|
+
*
|
|
20
|
+
* Heights are measured, not computed from summary + padding + borders, because
|
|
21
|
+
* that arithmetic breaks as soon as a theme puts margins on the summary or the
|
|
22
|
+
* boxes are nested. Toggling `open` and reading the rect yields the exact
|
|
23
|
+
* height the element will settle at, whatever the stylesheet does.
|
|
24
|
+
*/
|
|
25
|
+
export interface BoxDrawerOptions {
|
|
26
|
+
/** Length of a full open or close, in milliseconds. Partial travel is scaled down. */
|
|
27
|
+
durationMs?: number;
|
|
28
|
+
/** CSS easing function. */
|
|
29
|
+
easing?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Animate one `<details>` to its opposite state, reversing cleanly when it is
|
|
33
|
+
* already mid-animation.
|
|
34
|
+
*
|
|
35
|
+
* Exported so hosts that toggle boxes programmatically (a keyboard command, an
|
|
36
|
+
* "expand all" action) go through the same animation as a click.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toggleBoxWithDrawer(details: HTMLDetailsElement, options?: BoxDrawerOptions): void;
|
|
39
|
+
/**
|
|
40
|
+
* Intercept the native toggle of every box inside `root`.
|
|
41
|
+
*
|
|
42
|
+
* The listener is delegated rather than attached per box: hosts typically feed
|
|
43
|
+
* the preview through `morphHTML` on every keystroke, and per-element listeners
|
|
44
|
+
* would be torn down and re-attached continuously.
|
|
45
|
+
*
|
|
46
|
+
* @param root - container holding the rendered BBCode
|
|
47
|
+
* @returns disposer that removes the listener
|
|
48
|
+
*/
|
|
49
|
+
export declare function bindBoxDrawer(root: HTMLElement, options?: BoxDrawerOptions): () => void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DocumentEngine — Visuals
|
|
3
|
+
*
|
|
4
|
+
* Catálogo de estilos visuales por plataforma para la previsualización
|
|
5
|
+
* de BBCode. Cada plataforma puede tener su propia apariencia sin
|
|
6
|
+
* modificar el renderer HTML.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* // Desde la FUENTE, que es como lo consume el monorepo (Next.js, Vite,
|
|
10
|
+
* // Webpack): esta ruta funciona sin haber compilado nada.
|
|
11
|
+
* import '@miliastry/quasar/src/Visuals/osu.css'
|
|
12
|
+
*
|
|
13
|
+
* // Desde el paquete PUBLICADO. Solo resuelve tras `npm run build`, que es
|
|
14
|
+
* // lo que copia los CSS a dist/Visuals (ver scripts/copy-css.mjs).
|
|
15
|
+
* import '@miliastry/quasar/Visuals/osu.css'
|
|
16
|
+
*
|
|
17
|
+
* // Luego en el JSX: <div className="bbcode-preview" ...
|
|
18
|
+
*
|
|
19
|
+
* Para cambiar de tema visual, solo cambia el import del CSS.
|
|
20
|
+
*
|
|
21
|
+
* Temas disponibles:
|
|
22
|
+
* - osu → Estilo visual inspirado en los foros de osu!
|
|
23
|
+
* - miliastry → Estilo por defecto de Miliastry (próximamente)
|
|
24
|
+
*/
|
|
25
|
+
export { bindBoxDrawer, toggleBoxWithDrawer } from './BoxDrawer';
|
|
26
|
+
export type { BoxDrawerOptions } from './BoxDrawer';
|
|
27
|
+
export declare const visualThemes: readonly [{
|
|
28
|
+
readonly id: 'osu';
|
|
29
|
+
readonly name: 'osu! Forum Style';
|
|
30
|
+
readonly description: 'Estilo visual inspirado en los foros de osu!';
|
|
31
|
+
readonly cssFile: 'osu.css';
|
|
32
|
+
}, {
|
|
33
|
+
readonly id: 'lyne';
|
|
34
|
+
readonly name: 'Lyne Style';
|
|
35
|
+
readonly description: 'Estilo visual cyberpunk con cortes a 45° inspirado en Lyne';
|
|
36
|
+
readonly cssFile: 'lyne.css';
|
|
37
|
+
}];
|
|
38
|
+
export type VisualThemeId = (typeof visualThemes)[number]['id'];
|