mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Theme Builder: Layout/Axes/Legend/Type panels, scheme-render fix, fail-loud gallery
This commit is contained in:
@@ -139,6 +139,17 @@ async function rerender(node: HTMLElement, spec: TopLevelSpec, config: Config) {
|
||||
**render-size** limit (the chart is physically too big), distinct from the readability
|
||||
cardinality warnings — don't conflate them. Only an _unbounded_ axis overflows: a
|
||||
`width: 'container'` axis is bounded, so it's the deleted (natural-height) axis to watch.
|
||||
- **Load fonts before rendering.** Vega measures every text label via canvas
|
||||
`measureText` **regardless of renderer** (even the `'none'` probe runs layout),
|
||||
so a face that finishes loading after embed lays the whole chart out with
|
||||
fallback metrics. `renderSpec` therefore gates on `document.fonts.load` for the
|
||||
families a spec+config reference (`collectFontFamilies`, core) before any layout
|
||||
pass. This is a non-critical enhancement, so it waits on `allSettled` + a
|
||||
timeout: a face failing (offline, 404, a system family with no `@font-face`)
|
||||
degrades to fallback metrics rather than failing the chart (the sanctioned
|
||||
swallow under §7's fail-loud rule). Chart fonts are self-hosted in
|
||||
`styles/chart-fonts.css` (offered by the Theme Builder's font control); only
|
||||
their latin subsets are precached, the rest runtime-cached (vite.config Workbox).
|
||||
- **Do** call `view.finalize()` on every previous view before rendering a new
|
||||
one, and on component unmount.
|
||||
- **Do** keep exactly one live view per preview node.
|
||||
@@ -218,7 +229,9 @@ The gallery (`core/theme-preview-specs.ts`, fixed inline-data swatch specs)
|
||||
renders `draftConfig` per card through the shared `renderSpec` with the
|
||||
**canvas** renderer and a per-card debounce + chain-lock (the LivePreview
|
||||
serialization pattern, one lock per card) — so invalid JSON mid-edit never
|
||||
blanks the preview, and seven concurrent embeds never interleave on a node.
|
||||
blanks the preview, and seven concurrent embeds never interleave on a node. A
|
||||
card whose render throws shows the error message in place of the chart (the same
|
||||
fail-loud treatment as LivePreview, §7), never a silent blank.
|
||||
`applyFontToConfig(config, family)` is the font control's transform: it sets
|
||||
the top-level `font` and rewrites every `font`/`*Font` string slot at any
|
||||
depth — explicit slots would otherwise keep overriding the new default.
|
||||
@@ -238,25 +251,42 @@ that boundary deliberately: merge bakes the selected theme into `spec.config`
|
||||
|
||||
### Structured controls
|
||||
|
||||
The builder's panels (`ColorControls`; the Type tab's font control) are
|
||||
accelerators over the same `draftConfig`: each reads a value and writes one back
|
||||
through `CustomThemeStore.mutateDraftConfig(fn)` — the single transform path,
|
||||
which reparses, reformats, and updates `draftConfig` so the JSON editor and
|
||||
gallery follow (a parse error disables the controls). The pure transforms live
|
||||
in `core/theme-controls.ts`: immutable config path get/set, the named-scheme
|
||||
catalog (`THEME_SCHEMES`), and `schemeColors` (scheme name → hex swatches, from
|
||||
the `vega-scale` registry — a focused vega sub-package). A color family holds
|
||||
**either** a named scheme string **or** an explicit color array; the picker
|
||||
materializes one to the other. Family by scale: `range.category` (nominal),
|
||||
`range.ramp` (continuous; `range.heatmap` for `rect`), `range.diverging`
|
||||
(continuous color with a `domainMid`).
|
||||
The builder's panels — Color, Type, Layout, Axes & grid, Legend
|
||||
(`ColorControls` + `TypeControls`/`LayoutControls`/`AxesControls`/`LegendControls`
|
||||
on the shared `ThemeFields` field primitives) — are accelerators over the same
|
||||
`draftConfig`: each reads a value and writes one back through
|
||||
`CustomThemeStore.mutateDraftConfig(fn)` — the single transform path, which
|
||||
reparses, reformats, and updates `draftConfig` so the JSON editor and gallery
|
||||
follow (a parse error disables the controls). The pure transforms live in
|
||||
`core/theme-controls.ts`: immutable config path get/set, leaf coercion, the
|
||||
named-scheme catalog (`THEME_SCHEMES`), and `schemeColors` (scheme name → hex
|
||||
swatches, from the `vega-scale` registry — a focused vega sub-package). A color
|
||||
family holds **either** a named scheme as Vega's range-scheme **object**
|
||||
`{ scheme: name }` **or** an explicit color array; the picker materializes one to
|
||||
the other. Family by scale: `range.category` (nominal), `range.ramp` (continuous;
|
||||
`range.heatmap` for `rect`), `range.diverging` (continuous color with a
|
||||
`domainMid`).
|
||||
|
||||
- **Do** route structured edits through `mutateDraftConfig` + `setConfigValue`,
|
||||
which sets a value at a path **immutably, preserving sibling keys**, and
|
||||
deletes (pruning emptied ancestors) on `undefined` so a theme stays a diff.
|
||||
Repeated control labels across panels ("Size", "Color", "Weight") get a
|
||||
qualified accessible name while keeping the short visible label; the section is a
|
||||
`role="group"` labelled by its heading (APG group pattern), so the name a screen
|
||||
reader announces is unambiguous.
|
||||
|
||||
- **Do** bind a panel's writes to the shared `useConfigSetter()` hook (in
|
||||
`CustomThemeStore` — beside `mutateDraftConfig`, not the JSX field module, which
|
||||
stays component-only for fast refresh). It is `mutateDraftConfig` + `setConfigValue`:
|
||||
sets a value at a path **immutably, preserving sibling keys**, and deletes
|
||||
(pruning emptied ancestors) on `undefined` so a theme stays a diff. A new panel
|
||||
uses it rather than re-inlining the pair.
|
||||
- **Don't** rebuild the config from a fixed schema: vega-themes presets carry
|
||||
Vega-_layer_ keys (`symbol`/`shape`/`path`/`group`) absent from the Vega-Lite
|
||||
`Config` schema but forwarded to Vega — a rebuild drops them. Merge in place.
|
||||
- **Do** write a named scheme into `range.*` as the object `{ scheme: name }`. A
|
||||
bare scheme-name string passes vega-lite _compile_ but Vega rejects it at
|
||||
_render_ ("Unrecognized scale range value"), blanking the chart.
|
||||
`normalizeRangeSchemes` (core) heals the bare form at the render-resolution
|
||||
points (`chartConfigForSelection`; the builder gallery) for configs authored or
|
||||
saved before this was enforced.
|
||||
- **Do** add a `theme-preview-specs.ts` gallery card for any new color family,
|
||||
so no control ships without a visible mirror.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user