@brianmsm/quarto-bento 0.0.0-stage → 0.1.1

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.
Files changed (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +93 -2
  3. package/bin/qbento-npm.mjs +62 -0
  4. package/distribution/LICENSE +21 -0
  5. package/distribution/PACKAGING.md +59 -0
  6. package/distribution/bin/qbento +5 -0
  7. package/distribution/bin/qbento.cmd +4 -0
  8. package/distribution/manifest.json +720 -0
  9. package/distribution/runtime/LICENSE +21 -0
  10. package/distribution/runtime/_extensions/qbento/_extension.yml +24 -0
  11. package/distribution/runtime/_extensions/qbento/capture.lua +21 -0
  12. package/distribution/runtime/_extensions/qbento/guard.lua +7 -0
  13. package/distribution/runtime/_extensions/qbento/post.ts +2 -0
  14. package/distribution/runtime/_extensions/qbento/pre.ts +2 -0
  15. package/distribution/runtime/_extensions/qbento/producer-activation.js +129 -0
  16. package/distribution/runtime/src/bridge/browser.js +168 -0
  17. package/distribution/runtime/src/bridge/isolation.ts +55 -0
  18. package/distribution/runtime/src/browser/chromium.ts +218 -0
  19. package/distribution/runtime/src/cli.ts +232 -0
  20. package/distribution/runtime/src/core/agent.ts +546 -0
  21. package/distribution/runtime/src/core/annotations.ts +384 -0
  22. package/distribution/runtime/src/core/capture.ts +203 -0
  23. package/distribution/runtime/src/core/component-actions.ts +550 -0
  24. package/distribution/runtime/src/core/component-frames.ts +59 -0
  25. package/distribution/runtime/src/core/component-sync.ts +290 -0
  26. package/distribution/runtime/src/core/design-diagnostics.ts +78 -0
  27. package/distribution/runtime/src/core/design-registry.ts +287 -0
  28. package/distribution/runtime/src/core/graph-relations.ts +354 -0
  29. package/distribution/runtime/src/core/graph-scope.ts +63 -0
  30. package/distribution/runtime/src/core/graph-sync.ts +228 -0
  31. package/distribution/runtime/src/core/io.ts +27 -0
  32. package/distribution/runtime/src/core/kpi-appearance.ts +205 -0
  33. package/distribution/runtime/src/core/layouts.ts +245 -0
  34. package/distribution/runtime/src/core/project.ts +851 -0
  35. package/distribution/runtime/src/core/reconcile.ts +384 -0
  36. package/distribution/runtime/src/core/recovery.ts +1255 -0
  37. package/distribution/runtime/src/core/slide-actions.ts +158 -0
  38. package/distribution/runtime/src/core/source-scope.ts +50 -0
  39. package/distribution/runtime/src/core/sync.ts +2557 -0
  40. package/distribution/runtime/src/core/widgets.ts +300 -0
  41. package/distribution/runtime/src/integration/install.ts +98 -0
  42. package/distribution/runtime/src/integration/invocation.ts +100 -0
  43. package/distribution/runtime/src/integration/quarto.ts +457 -0
  44. package/distribution/runtime/src/render/assets.ts +66 -0
  45. package/distribution/runtime/src/render/capture.lua +8 -0
  46. package/distribution/runtime/src/render/chart.ts +165 -0
  47. package/distribution/runtime/src/render/components.ts +199 -0
  48. package/distribution/runtime/src/render/design.ts +820 -0
  49. package/distribution/runtime/src/render/diagnostics.ts +36 -0
  50. package/distribution/runtime/src/render/graphs.ts +747 -0
  51. package/distribution/runtime/src/render/html.ts +82 -0
  52. package/distribution/runtime/src/render/images.ts +268 -0
  53. package/distribution/runtime/src/render/inline.ts +259 -0
  54. package/distribution/runtime/src/render/kpi.ts +385 -0
  55. package/distribution/runtime/src/render/lists.ts +183 -0
  56. package/distribution/runtime/src/render/math.ts +413 -0
  57. package/distribution/runtime/src/render/measure.ts +185 -0
  58. package/distribution/runtime/src/render/native-layout.ts +174 -0
  59. package/distribution/runtime/src/render/producer-capture.ts +319 -0
  60. package/distribution/runtime/src/render/producer-environment.R +49 -0
  61. package/distribution/runtime/src/render/producer-environment.ts +96 -0
  62. package/distribution/runtime/src/render/producer-profile.R +91 -0
  63. package/distribution/runtime/src/render/producer-site-profile.R +18 -0
  64. package/distribution/runtime/src/render/project.ts +1806 -0
  65. package/distribution/runtime/src/render/quarto.ts +127 -0
  66. package/distribution/runtime/src/render/registry.ts +233 -0
  67. package/distribution/runtime/src/render/resources.ts +292 -0
  68. package/distribution/runtime/src/render/shell.ts +110 -0
  69. package/distribution/runtime/src/render/source-inline.ts +169 -0
  70. package/distribution/runtime/src/render/table.ts +220 -0
  71. package/distribution/runtime/src/render/text-overflow.ts +208 -0
  72. package/distribution/runtime/src/render/types.ts +71 -0
  73. package/distribution/runtime/src/render/validate.ts +572 -0
  74. package/distribution/runtime/src/rich/project.ts +117 -0
  75. package/distribution/runtime/src/rich/table.ts +374 -0
  76. package/distribution/runtime/src/source/annotations.ts +490 -0
  77. package/distribution/runtime/src/source/attributes.ts +415 -0
  78. package/distribution/runtime/src/source/chart.ts +165 -0
  79. package/distribution/runtime/src/source/code-language.ts +277 -0
  80. package/distribution/runtime/src/source/component-insertion.ts +160 -0
  81. package/distribution/runtime/src/source/deletion.ts +278 -0
  82. package/distribution/runtime/src/source/graphs.ts +517 -0
  83. package/distribution/runtime/src/source/identities.ts +256 -0
  84. package/distribution/runtime/src/source/identity-id.ts +6 -0
  85. package/distribution/runtime/src/source/image.ts +50 -0
  86. package/distribution/runtime/src/source/kpi.ts +196 -0
  87. package/distribution/runtime/src/source/mod.ts +876 -0
  88. package/distribution/runtime/src/source/notes.ts +308 -0
  89. package/distribution/runtime/src/source/structure.ts +647 -0
  90. package/distribution/runtime/src/source/table.ts +290 -0
  91. package/distribution/runtime/src/source/text-conversion.ts +146 -0
  92. package/distribution/runtime/src/state/components.ts +281 -0
  93. package/distribution/runtime/src/state/graphs.ts +200 -0
  94. package/distribution/runtime/src/state/json.ts +162 -0
  95. package/distribution/runtime/src/state/merge.ts +1034 -0
  96. package/distribution/runtime/src/state/mod.ts +5 -0
  97. package/distribution/runtime/src/state/store.ts +226 -0
  98. package/distribution/runtime/src/state/types.ts +151 -0
  99. package/distribution/runtime/src/studio/client.js +892 -0
  100. package/distribution/runtime/src/studio/components.js +188 -0
  101. package/distribution/runtime/src/studio/index.html +283 -0
  102. package/distribution/runtime/src/studio/layouts.js +170 -0
  103. package/distribution/runtime/src/studio/registry.js +283 -0
  104. package/distribution/runtime/src/studio/relations.js +169 -0
  105. package/distribution/runtime/src/studio/server.ts +461 -0
  106. package/distribution/runtime/src/widgets/deck.ts +39 -0
  107. package/distribution/runtime/src/widgets/plotly.ts +354 -0
  108. package/distribution/runtime/src/widgets/presenter.ts +367 -0
  109. package/distribution/runtime/src/widgets/snapshot.ts +116 -0
  110. package/distribution/runtime/vendor/bento/FONT_NOTICES.md +49 -0
  111. package/distribution/runtime/vendor/bento/LICENSE +21 -0
  112. package/distribution/runtime/vendor/bento/THIRD_PARTY_NOTICES.md +51 -0
  113. package/distribution/runtime/vendor/bento/font-licenses/fraunces-OFL.txt +93 -0
  114. package/distribution/runtime/vendor/bento/font-licenses/instrument-sans-OFL.txt +93 -0
  115. package/distribution/runtime/vendor/bento/pin.json +69 -0
  116. package/distribution/runtime/vendor/bento/provenance/slides.package-lock.json +1928 -0
  117. package/distribution/runtime/vendor/bento/provenance/slides.package.json +28 -0
  118. package/distribution/runtime/vendor/bento/runtime-dependencies.json +244 -0
  119. package/distribution/runtime/vendor/bento/runtime-licenses.json +4038 -0
  120. package/distribution/runtime/vendor/bento/shell.html +269 -0
  121. package/distribution/runtime/vendor/bento/slides.schema.json +2379 -0
  122. package/package.json +40 -4
@@ -0,0 +1,199 @@
1
+ import {
2
+ applyComponentDesign,
3
+ componentFrames,
4
+ type DesignDeclaration,
5
+ type DesignDefaults,
6
+ DesignError,
7
+ type Frame,
8
+ type MeasuredComponents,
9
+ } from "./design.ts";
10
+ import type { Element, Projection } from "./types.ts";
11
+
12
+ type Fields = NonNullable<Projection["design"]>[string];
13
+ const geometry = new Set(["x", "y", "w", "h"]);
14
+ /** Compose a bounded source component without pretending child transforms are parent edits. */
15
+ export function projectComponent(
16
+ groups: Element[][],
17
+ declaration: DesignDeclaration,
18
+ frame: Frame,
19
+ existing: Fields,
20
+ defaults: DesignDefaults = {},
21
+ measured?: MeasuredComponents,
22
+ ): { elements: Element[]; fields: Fields; decorativeIds: string[] } {
23
+ if (declaration.component === "layout") {
24
+ const slots =
25
+ componentFrames(declaration, frame, groups.length, defaults).children;
26
+ groups.forEach((group, i) => {
27
+ group = group.filter((element) => !measured?.omitted.has(element.id));
28
+ const width = Math.max(...group.map((e) => Number(e.x) + Number(e.w))) -
29
+ Math.min(...group.map((e) => Number(e.x)));
30
+ const height = Math.max(...group.map((e) => Number(e.y) + Number(e.h))) -
31
+ Math.min(...group.map((e) => Number(e.y)));
32
+ if (width > slots[i].w + .01 || height > slots[i].h + .01) {
33
+ const owned = group.some((element) =>
34
+ existing[element.id]?.ownedPaths.some((field) =>
35
+ ["fontSize", "letterSpacing", "strokeWidth", "radius"].includes(
36
+ field,
37
+ )
38
+ )
39
+ );
40
+ throw new DesignError(
41
+ owned ? "COMPONENT_CHILD_DESIGN_SCALE" : "COMPONENT_CONTENT_OVERFLOW",
42
+ "Measured content exceeds its final layout slot; refusing unreadable automatic shrink.",
43
+ );
44
+ }
45
+ });
46
+ }
47
+ const projected = applyComponentDesign(groups, declaration, {
48
+ ...defaults,
49
+ frame,
50
+ }, measured);
51
+ const fields: Fields = {};
52
+ const original = new Map(
53
+ groups.flat().map((element) => [element.id, element]),
54
+ );
55
+ for (const element of projected.elements) {
56
+ const previous = existing[element.id];
57
+ for (const field of previous?.ownedPaths ?? []) {
58
+ if (geometry.has(field)) {
59
+ // Even a coincidental equal value is ambiguous after a parent frame change.
60
+ throw new DesignError(
61
+ "COMPONENT_CHILD_GEOMETRY",
62
+ "Declare coupled geometry on the containing component, not its child objects.",
63
+ );
64
+ }
65
+ if (
66
+ ["fontSize", "letterSpacing", "strokeWidth", "radius"].includes(
67
+ field,
68
+ ) &&
69
+ element[field] !== original.get(element.id)![field]
70
+ ) {
71
+ throw new DesignError(
72
+ "COMPONENT_CHILD_DESIGN_SCALE",
73
+ "A parent component would rescale an explicitly authored child style; apply that field to the outer component or retain it as a native override.",
74
+ );
75
+ }
76
+ if (field in declaration.properties) {
77
+ throw new DesignError(
78
+ "AMBIGUOUS_DESIGN_OWNERSHIP",
79
+ "A component and child declare the same native visual field.",
80
+ );
81
+ }
82
+ // A default card theme must not override explicitly authored child typography.
83
+ element[field] = original.get(element.id)![field];
84
+ }
85
+ if (measured?.fixed.has(element.id)) {
86
+ const before = original.get(element.id)!;
87
+ for (
88
+ const field of [
89
+ "w",
90
+ "h",
91
+ "fontSize",
92
+ "fontFamily",
93
+ "fontWeight",
94
+ "lineHeight",
95
+ "letterSpacing",
96
+ "align",
97
+ "valign",
98
+ ]
99
+ ) {
100
+ if (element[field] !== before[field]) {
101
+ throw new DesignError(
102
+ "COMPONENT_MEASURED_STYLE",
103
+ "An enclosing component would change measured KPI metrics; declare typography on the KPI or its roles, and geometry on its enclosing layout.",
104
+ );
105
+ }
106
+ }
107
+ }
108
+ if (
109
+ element.type === "code" &&
110
+ Number(element.h) + 0.01 <
111
+ String(element.content).split("\n").length * Number(element.fontSize) *
112
+ Number(element.lineHeight ?? 1.25)
113
+ ) {
114
+ throw new DesignError(
115
+ "COMPONENT_CONTENT_OVERFLOW",
116
+ "Code typography exceeds its component box; use a taller frame or smaller explicit font.",
117
+ );
118
+ }
119
+ fields[element.id] = {
120
+ ownedPaths: [
121
+ ...new Set([
122
+ ...(previous?.ownedPaths ?? []),
123
+ ...(projected.ownershipByElement[element.id] ?? []),
124
+ ]),
125
+ ],
126
+ bindings: {
127
+ ...(previous?.bindings ?? {}),
128
+ ...Object.fromEntries(
129
+ Object.entries(projected.bindingsByElement[element.id] ?? {}).map(
130
+ ([field, attribute]) => [field, {
131
+ sourceId: declaration.sourceId,
132
+ attribute,
133
+ }],
134
+ ),
135
+ ),
136
+ },
137
+ };
138
+ }
139
+ // One object cannot establish an update to an attribute inherited by several
140
+ // siblings. Preserve source ownership, but require an explicit group adapter
141
+ // rather than changing their source from a single child's edit.
142
+ const counts = new Map<string, number>();
143
+ for (const entry of Object.values(fields)) {
144
+ for (const [field, binding] of Object.entries(entry.bindings)) {
145
+ if (binding.sourceId !== declaration.sourceId) continue;
146
+ const key = `${field}/${binding.attribute}`;
147
+ counts.set(key, (counts.get(key) ?? 0) + 1);
148
+ }
149
+ }
150
+ for (const entry of Object.values(fields)) {
151
+ for (const [field, binding] of Object.entries(entry.bindings)) {
152
+ if (
153
+ binding.sourceId === declaration.sourceId &&
154
+ counts.get(`${field}/${binding.attribute}`)! > 1
155
+ ) delete entry.bindings[field];
156
+ }
157
+ }
158
+ return {
159
+ elements: projected.elements,
160
+ fields,
161
+ decorativeIds: projected.decorativeIds,
162
+ };
163
+ }
164
+
165
+ /** Read only class tokens in the original opener, never text inside attribute values. */
166
+ export function sourceComponentClass(raw: string): string | undefined {
167
+ const content = /\{([^{}]*)\}[ \t]*$/.exec(raw.split(/\r?\n/)[0])?.[1];
168
+ const tokens = content?.match(/(?:[^\s"']|"[^"]*"|'[^']*')+/g) ?? [];
169
+ return tokens.find((token) =>
170
+ [".bento-card", ".bento-layout", ".bento-code", ".bento-kpi"].includes(
171
+ token,
172
+ )
173
+ );
174
+ }
175
+ /** Quarto itself owns layout= and interprets its value as JSON before projection. */
176
+ export function assertCompatibleComponentSource(
177
+ source: import("../source/mod.ts").SourceDocument,
178
+ ): void {
179
+ for (const block of source.blocks) {
180
+ if (block.kind !== "div") continue;
181
+ const content = /\{([^{}]*)\}[ \t]*$/.exec(block.raw.split(/\r?\n/)[0])
182
+ ?.[1];
183
+ if (content === undefined) continue;
184
+ const tokens: string[] = content.match(/(?:[^\s"']|"[^"]*"|'[^']*')+/g) ??
185
+ [];
186
+ if (!tokens.includes(".bento-layout")) continue;
187
+ if (
188
+ tokens.some((token, i) =>
189
+ /^layout=/.test(token) ||
190
+ token === "layout" && tokens[i + 1]?.startsWith("=")
191
+ )
192
+ ) {
193
+ throw new DesignError(
194
+ "QUARTO_LAYOUT_ATTRIBUTE_COLLISION",
195
+ 'Use bento-layout-name="two-column" on .bento-layout; layout= belongs to Quarto and expects its own JSON layout syntax.',
196
+ );
197
+ }
198
+ }
199
+ }