uhuu-components 0.3.0 → 0.3.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,324 @@
1
+ # Changelog
2
+
3
+ All notable changes to the `uhuu-components` Storybook workspace are documented here.
4
+
5
+ ### 2026-10-08 — Toolchain declarations (ECO-04)
6
+
7
+ - `package.json` declares the Node floor (>=24) and the package-manager pin (pnpm@10.30.3) the ecosystem
8
+ toolchain policy measures. Metadata only; the dependency resolution is unchanged.
9
+
10
+ ## 0.3.2 (unreleased)
11
+
12
+ ### Fixed
13
+
14
+ - The shell now follows the user's interface language inside the uhuu document editor. The editor
15
+ sends it once, in the handshake that the SDK re-emits as `loaded`, before the payload. Templates
16
+ that render nothing until the payload arrives (go-expose) mounted `InteractiveModeProvider` after
17
+ that event and fell back to `<html lang>`, the document's language. The package now subscribes
18
+ when it is imported, so the language is kept for any provider that mounts later.
19
+ - Per-language page and group labels now reach documents saved earlier. The page-editor state a
20
+ document stores keeps each item's label as saved, so restored documents showed the old English
21
+ string. On restore, a saved label that is one of the template label's values, or none, is replaced
22
+ by the current template label; a user's rename is kept. Found migrating go-expose.
23
+
24
+ ## 0.3.1 (unreleased)
25
+
26
+ ### Added
27
+
28
+ - The editor shell is translated: toolbar, page menus, add and reorder dialogs, zoom, image options
29
+ and notices ship in German, French, Italian and English, and follow the user's interface language
30
+ from the host handshake (`uhuuData.locale`, re-emitted by the SDK as `loaded`), then `?lang=`,
31
+ `<html lang>` and the browser. No new exports: `InteractiveModeProvider` takes `locale` and
32
+ `translations` (per-language overrides, or a whole catalog for another language, bundled or
33
+ fetched), `useInteractive()` reports the resolved `locale`, and `label` in `templateConfig` and
34
+ `pageOptions` (pages, groups, options, select and colour values) plus `reorderTitle` /
35
+ `reorderDescription` accept one string per language (`{ en: 'Cover', de: 'Titelseite' }`).
36
+ Plain string labels and developer tooling are unchanged. See `docs/editor-shell-translations.md`.
37
+
38
+ ### Changed
39
+
40
+ - Generate the delivery README from owning Storybook package documentation and include the source CHANGELOG with every release. Public documentation describes current static/flow, editor, image and BrandKit APIs.
41
+ - Ship one UMD artifact, `uhuu-components.umd.cjs`, for CommonJS and browser-global use, with its matching source map. The duplicate `.umd.js` is removed from future releases; package-root ESM and CommonJS entries remain compatible. Direct `.umd.js` URLs must stay on their existing pinned release or migrate to `.umd.cjs`.
42
+ - Replace the public handoff repository’s unrelated application ignore rules with package-specific rules. The published 0.3.0 artifacts remain immutable.
43
+
44
+ ## 0.3.0
45
+
46
+ ### Changed
47
+
48
+ - `BrandKitProvider` applies a Brand Kit `brandkit.json.runtime` block (`version: 2`, brandkit.json
49
+ "2.0") as published, with the token chains skipped:
50
+ - shadcn/ui role variables, `--<role>` and `--color-<role>` (`--primary`, `--muted-foreground`,
51
+ `--chart-1` …), so Tailwind v4's `bg-primary` / `text-muted-foreground` resolve with no bridge;
52
+ - the `--color-kit-*` / `--font-kit-*` aliases with the meanings templates were written against
53
+ (`kit-muted` is grey text, `kit-secondary` the strong second brand colour);
54
+ - `--font-<role>`.
55
+ Entries are re-validated against an allowlist of names (a published document cannot set
56
+ `--radius` or `--spacing`) and the colour policy. Fonts come from `runtime.fontStylesheets` and
57
+ `runtime.fontFaces` (through the same `@font-face` builder), so only what the four font roles use
58
+ is loaded. Any other `runtime` (including the never-published `version: 1`) is ignored and the
59
+ chains apply. `defaults` still fill gaps; the kit wins.
60
+ - **Colour policy:** `oklch()` and `oklab()` with plain components pass as written (Brand Kit
61
+ publishes oklch; Chrome prints it since 111). Relative colour syntax and nested functions are
62
+ still skipped.
63
+ - Kits without `runtime` (template-bundled kits) also land Brand Kit's
64
+ `tokens.light.semantic` roles on `--<role>` / `--color-<role>`. Flat tokens never feed a role:
65
+ extracted kits use some of these words with other meanings (`muted` is grey text there).
66
+ - New `BrandKitJson.runtime` / `colorMode` types (`BrandKitRuntimeBlock`, `version: 2`).
67
+ - **The provider loads the kit.** `src` fetches a brandkit.json (`brandKitSourceUrl(payload)` reads
68
+ `brandKitUrl`, `kit-…` ids with `brandKitTeamId`, or `brandKit.storage.publicUrl`); the `brandKit`
69
+ prop renders until it arrives and when the fetch fails. `status` (and `data-uhuu-brand-kit-status`
70
+ on the scope element) is `idle`, `loading`, `ready` or `error`. `loadBrandKit` is exported.
71
+ - **Assets from the kit.** `useBrandKit()` adds `logo({ kind, background })` (Brand Kit's
72
+ `logoSystem` first, then `logos`, then template-bundled shapes), `collection(kind)` (the assigned
73
+ media collection's promoted version, items resolved), `mapStyle(mode)`, `env(keys)` and
74
+ `resolveUrl(path)`, all resolving relative paths against the kit's `baseUrl` or its source URL.
75
+ The same functions are exported (`brandKitLogo`, `brandKitCollection`, `brandKitMapStyle`,
76
+ `brandKitEnv`). Templates delete their copied `src/brandkit/brand-kit-client.js` and
77
+ `BrandKitContext.jsx`; the registry-style.json request they made is gone (`runtime` carries the
78
+ shadcn roles).
79
+ - The Brand Kit Switcher story renders through `BrandKitProvider` and includes Brand Kit's golden
80
+ kit (`test/fixtures/golden-brandkit.json`, copied from uhuu-brandkit, brandkit.json "2.0").
81
+ - The copy of `dist/` into the open-source handoff checkout is an explicit step,
82
+ `npm run release:handoff` (`scripts/handoffDist.js`, with `HANDOFF_DIR` / `--handoff-dir` and
83
+ `--dry-run`). `npm run build` writes only under `dist/` and no longer overwrites the public
84
+ package tree as a side effect. `scripts/release-components.sh` runs build → handoff → verify.
85
+ Covered by `test/handoff-dist.test.mjs`.
86
+ - Release pipeline (`.github/workflows/release-components.yml`): installs with pnpm
87
+ (`pnpm/action-setup` reading the new `packageManager` pin, `pnpm install --frozen-lockfile`,
88
+ pnpm store cache) instead of `npm ci` against the absent `package-lock.json`; runs the test suite
89
+ after the build; reads `HANDOFF_REPO_TOKEN` / `NPM_TOKEN` only in the opt-in jobs through `env:`
90
+ with fail-fast checks, publishes through `actions/setup-node`'s registry `.npmrc`, and keeps
91
+ `GITHUB_TOKEN` read-only. `pnpm test` now builds first (`pnpm test:unit` skips the build).
92
+
93
+ ## 0.2.98
94
+
95
+ ### Added
96
+
97
+ - `getDialogProps` is exported for binding a template's own element to a dialog, using the same
98
+ renderer guard and markers as `Editable` and `ImageBlock`.
99
+ - `imageUrl` provides shared thumbnail sizing, source encoding, SVG pass-through and empty-image
100
+ handling. See [image-url.md](docs/image-url.md).
101
+ - `BrandKitProvider` and `useBrandKit` share token mapping, font loading and CSS variable scoping.
102
+ Brand fallbacks stay in templates. Font assets honor face-level stylesheets, root-relative URLs
103
+ and declared Google Fonts styles. See [brand-kit-runtime.md](docs/brand-kit-runtime.md).
104
+
105
+ ### Removed
106
+
107
+ - The unused internal `imgOptim` / `imgBlank` helpers (`src/uhuu/utility/helpers.js`). They were
108
+ never exported from the package root.
109
+
110
+ ### Fixed
111
+
112
+ - Empty `text`, `textarea` and `markdown` bindings stay clickable in the interactive editor.
113
+ `Editable` and `Static.FlowDocument` mark empty text content; elements bound with `getDialogProps`
114
+ use `data-uhuu-type` and `:empty`. The one-line affordance is scoped to editor screen output.
115
+ Templates control whether empty fields preserve space or disappear in print.
116
+ - The library continues to leave Markdown rendering and typography to templates; wrap the
117
+ template's renderer in `Editable` and pass `null` for empty text. No Markdown runtime is bundled.
118
+
119
+ ## 0.2.96
120
+
121
+ ### Added
122
+
123
+ - **Cover spread geometry for perfect binding (`Static.planCoverSpread`, `Static.resolveSheetSize`).**
124
+ Pure, DOM-free planner in `src/uhuu/pagination-static/spread-core.js` that turns
125
+ `pageFormat.binding = { spine, glue }` plus the filtered cover pages into the printer's two
126
+ wide sheets — outer (back cover · spine · front cover) and inner (inside front · blank
127
+ spine + glue zones · inside back) — with panel, spine and glue boxes in mm. Verified in
128
+ `test/cover-spread-core.test.mjs` against the approved Lienhardt InDesign export
129
+ (429 × 303 mm with 3 mm bleed) and the hand-coded Prozentbuch A6 cover sheet. `BindingConfig`
130
+ is typed on `pageFormat` / `PrintConfig.pageFormat` (see `docs/printer-cover-spine-support.md`).
131
+ - **`Static.CoverSpread` — one physical cover sheet for the Static-only template path.**
132
+ `sheet="outer"` renders back cover · spine · front cover, `sheet="inner"` inside front · blank
133
+ spine + glue masks · inside back. Panels are ordinary `Static.Sheet`s clipped at the spine, so
134
+ ImageBlock/overlays keep their bleed contract and full-bleed artwork is cut cleanly at the spine;
135
+ glue zones and the inner spine are masked to `--uhuu-paper-color`. With `showBleed` the spine and
136
+ glue strips carry hatched, labelled screen-only guides. Without a binding the panels degrade to
137
+ two plain sheets. Story: `Pagination/Cover Spread` (Lienhardt A4, Prozentbuch A6, outer only,
138
+ saddle-stitch fallback, print preview). Rendered-DOM contract tested from the built package in
139
+ `test/cover-spread-render.test.mjs`.
140
+ - **`PageEditor` composes perfect-binding cover spreads.** With `pageFormat.binding = { type: 'perfect',
141
+ spine, glue }` and `pageFilter.mode === 'cover'`, the filtered cover pages are laid out on the
142
+ printer's sheets through `Static.CoverSpread`: outer (back cover · spine · front cover) and inner
143
+ (inside front · blank spine + glue masks · inside back). `binding` is ignored in `all`/`text`
144
+ modes, so it can live in the base page format or in `printConfigs.cover.pageFormat`; the dev
145
+ print switcher picks it up unchanged. `two_pages` preview is coerced to single-page while a
146
+ spread is active. Cover page components receive a `spread` prop (`{ sheet, side, spine, glue,
147
+ bleed }`), and `templateConfig.spine.component` paints the outer spine strip (`SpineComponentProps`).
148
+ Thumbnails, add/reorder dialogs and flow measurement always use a binding-less setup so the
149
+ `@page` size never flips. Unsupported cases (coverPageCount other than 1 or 2, saddle stitch)
150
+ fall back to plain cover pages with a one-time dev warning. Decision logic is pure
151
+ (`cover-spread-layout.js`, tested in `test/cover-spread-layout.test.mjs`); stories under
152
+ `EditorShell/Cover Spine`.
153
+ - **Sheet-level CSS vars drive `@page`.** `--uhuu-sheet-width/height` default to page + bleed and
154
+ become `2 × width + spine + 2 × bleed` while `setup.binding.spine > 0`, alongside
155
+ `--uhuu-spine-width`, `--uhuu-glue-width` and `--uhuu-paper-color`. `PageSizeUtils.resolveCssVars`
156
+ exposes the map; `config.page` now also carries `binding` and `sheet`.
157
+
158
+ ### Changed
159
+
160
+ - **`PageSizeUtils.pageParams` returns the page config without a DOM.** Root CSS vars are only
161
+ written when `document` exists, but `ConfigContext` consumers (Sheet, CoverSpread, ImageBlock) now
162
+ see the same `page` during server rendering as in the browser; previously the context was empty on
163
+ the server.
164
+
165
+ ### Fixed
166
+
167
+ - **Editable nodes no longer override template layout utilities.** The indicator's fallback
168
+ `position: relative` now lives in Tailwind's `components` layer, so a template's normal
169
+ `absolute` utility wins in the editor as it does in renderer mode. Existing inline, important,
170
+ and wrapper workarounds remain compatible but are no longer needed.
171
+
172
+ ### Changed
173
+
174
+ - **`PageEditor` now opens fitted to the page.** `defaultZoomMode` defaults to `fit-page`
175
+ instead of `manual`, so a document loads with a whole sheet visible rather than at the
176
+ numeric `defaultZoom` (80%), which left large formats cropped on both axes until the author
177
+ opened the zoom menu. Fit keeps tracking layout and viewport changes until a manual zoom
178
+ (toolbar entry, ± buttons, Ctrl/Cmd-wheel or pinch) clears it. Pass
179
+ `defaultZoomMode="manual"` to restore the previous numeric-zoom start.
180
+
181
+ ### Fixed
182
+
183
+ - **A starting fit mode no longer flashes the unfitted page.** Fit cannot resolve during the
184
+ first commit — `Section` publishes its natural size from an effect — so the editor painted
185
+ `defaultZoom` for a frame or two before snapping to the fitted zoom. The sheet stack now stays
186
+ `visibility: hidden` (still laid out, so the measurements fit needs keep arriving) until the
187
+ first fit lands, with a 1s reveal fallback so an unmeasurable document can never stay hidden.
188
+
189
+ - **Pointer-anchored zoom now holds the point it was given.** The focal correction measured the
190
+ whole page stack, but the stack's height is *affine* in zoom rather than proportional — every
191
+ section contributes a header and spacer that stay a fixed pixel size, so it measures
192
+ `naturalTotal * zoom + chromeTotal`. `zoomFocalScrollDelta` maps a point by the ratio of the
193
+ before/after rects, which only holds for a uniformly scaled box, so the anchor drifted by the
194
+ accumulated chrome: **~64px going 122% → 200%**, and worse the deeper the target sat in the
195
+ document. The correction now anchors on the individual sheet under the pointer
196
+ (`pickZoomFocalAnchor`), which *is* uniformly scaled, making the mapping exact. Note the
197
+ earlier "sub-pixel" verification of this path was circular — it re-derived the expected
198
+ position with the same formula under test — so the drift went unnoticed.
199
+
200
+ - **Fit to Page no longer behaves like Fit to Width, and Fit to Height no longer overshoots.**
201
+ The pan viewport's geometry lived only in `section-page-resizer.css`, and not every consumer
202
+ ends up with that stylesheet — Template Studio renders the editor in an iframe whose document
203
+ never receives it. Without those rules the pane degraded to a plain block reporting its whole
204
+ content height (measured: **4711px inside a 665px iframe**), so fit divided by a viewport
205
+ seven times too tall: Fit to Height computed **413%** (clamped to `maxZoom`) and Fit to Page,
206
+ being `min(width, height)`, always collapsed to the width value. The pane and its content box
207
+ now carry their load-bearing geometry as inline styles, and `resolveFitPaneHeight` clamps the
208
+ measured pane to the space actually visible in its own document, so a mis-sized pane can no
209
+ longer corrupt fit. Verified in the Studio iframe: pane height now tracks the iframe viewport
210
+ (665 → 851 on resize) and Fit to Width / Fit to Height resolve to distinct values
211
+ (84.1% / 47.4%) where they were previously 90.2% / 413%.
212
+
213
+ ## 0.2.90
214
+
215
+ ### Fixed
216
+
217
+ - **A zoomed-in page can be scrolled to on both sides.** `SectionPageResizer` had no scroll
218
+ container of its own, so it rode the document scroller while centering the page stack with
219
+ `items-center`. Horizontal overflow was therefore split evenly to the left and right, and
220
+ because `scrollLeft` cannot go negative the left half was permanently unreachable —
221
+ measured at 277px of a 554px overflow in a 716px viewport. The editor now renders its own
222
+ pan viewport, so every pixel of the sheet is reachable at any zoom, in single-page and
223
+ facing modes alike.
224
+ - **Pointer-anchored zoom no longer drifts once zoomed in.** The scroll correction clamped at
225
+ `scrollLeft: 0` whenever the anchor sat left of centre, silently losing the point under the
226
+ cursor. With a real scroller on both axes the anchor now holds to sub-pixel accuracy
227
+ wherever scroll range exists.
228
+ - **The toolbar zoom controls keep their place.** `+` / `−` and the `%` input previously did
229
+ no scroll correction at all and drifted the viewport; all zoom entry points now share one
230
+ path and anchor on the centre of the visible pane.
231
+ - **Fit to Width / Height / Page measure real space.** Fit used fixed `32px` / `120px` insets
232
+ against the window; it now uses the pane's own box, its rendered gutters, and the measured
233
+ section chrome.
234
+
235
+ ### Changed
236
+
237
+ - **`SectionPageResizer` scrolls itself rather than the document.** Hosts that already provide
238
+ a scroller and want the previous behavior can pass `scrollMode="document"`. Note that the
239
+ editor no longer grows the page, so host-level page scrolling is replaced by pane scrolling.
240
+
241
+ ## 0.2.87
242
+
243
+ ### Fixed
244
+
245
+ - **The image options menu ("Edit image" / "Annotate") stays on the image in bleed and spread
246
+ mode.** It was rendered as a sibling of the absolutely positioned image container, so it
247
+ anchored to the page and landed in the page header — templates using `top`/`left`/`right`/
248
+ `bottom` insets (satellite and cadastral spreads) had to reposition it by hand. It is now
249
+ anchored to the image rect, clamped to the page the image renders on, so both halves of a
250
+ spread get the menu on their own visible corner. Bleed, spread and the anchor share one
251
+ width calculation (`image-anchor-geometry.ts`) so they cannot drift apart.
252
+
253
+ ## 0.2.86
254
+
255
+ ### Fixed
256
+
257
+ - **Wheel / pinch zoom keeps the pointer-anchored location.** After Ctrl/Cmd-wheel or trackpad
258
+ pinch, SectionPageResizer corrects document scroll so content under the pointer (e.g. a later
259
+ page) does not jump toward the first page as sheet heights grow.
260
+
261
+ ## 0.2.85
262
+
263
+ ### Added
264
+
265
+ - **PageEditor / SectionPageResizer support Ctrl/Cmd-wheel and trackpad-pinch zoom.** Plain wheel
266
+ still scrolls; modifier or pinch zooms proportionally (~0.3%/px, rAF-batched) and clears fit
267
+ mode the same way the toolbar ± controls do.
268
+
269
+ ## 0.2.84
270
+
271
+ ### Fixed
272
+
273
+ - **Single-page Fit to Page no longer sums every stacked sheet width.** Fit targets the first
274
+ sheet only (facing mode still fits the first pair). Multi-page documents no longer clamp to
275
+ `minZoom` (e.g. 25%) on load when `defaultZoomMode="fit-page"`.
276
+
277
+ ### Added
278
+
279
+ - Added `Static.FlowColumns` and `Static.planFlowColumnChunks` for bounded, non-recursive
280
+ sequential/parallel Flow stories. Each column advances its measured cursor independently on
281
+ every output page, exhausted tracks preserve their geometry, and all leaf keep/break/header,
282
+ oversized-item, and no-progress behavior continues to come from the existing Flow planner.
283
+ - Added column-scoped render hooks for track width, distribution, stack alignment, and measured
284
+ child spacing so authoring previews and published output can consume one authoritative plan.
285
+
286
+ ### Fixed
287
+
288
+ - Discarded short-page placement attempts no longer emit false unplaceable diagnostics when a
289
+ whole column group is successfully retried on a fresh page.
290
+ - Keep-with-next and avoid-break bundles now retry on a fresh physical page when the remaining
291
+ space would orphan their first leaf; composite header height determines whether that retry can
292
+ succeed.
293
+ - Repeated group headers retain continuation and `repeatHeader: false` state independently inside
294
+ each column, with header measurements scoped by column group, track, and group key.
295
+ - Column plans now reject duplicate/missing layout identities and leaf indexes before rendering,
296
+ terminate a page after controlled unplaceable output, and fail closed on any no-progress state.
297
+ - Measurement and output now share a geometry-invariant track contract: page-dependent column
298
+ styles and unmeasured vertical wrapper spacing are unsupported, while measured child margins
299
+ remain the canonical stack-gap mechanism.
300
+
301
+ - **PageEditor can now start in a layout-tracking fit mode.** `defaultZoomMode="fit-page"`
302
+ measures the current preview viewport and sheets directly, then keeps fit current through content
303
+ and viewport changes until the author chooses a manual zoom.
304
+
305
+ - **The package root is now a real dual ESM/CommonJS public API.** `import { Static } from
306
+ "uhuu-components"` resolves to the ESM bundle while CommonJS consumers resolve a `.cjs` copy of
307
+ the UMD bundle. Consumers no longer need a distribution-file deep import.
308
+
309
+ - Aligned `src/index.d.ts` with the actual minimal root runtime exports (`Static`, `EditorShell`,
310
+ `ImageBlock`, `Editable`) so TypeScript consumers are not offered imports that fail at runtime.
311
+ - Corrected the ImageBlock manifest to describe the existing root named import from
312
+ `uhuu-components`, not an unpublished `uhuu-components/ImageBlock` subpath.
313
+ - Made handoff checksum comparison explicit via `--compare-handoff` and kept CI npm publishing
314
+ downstream of a synced handoff repo checkout.
315
+ - Fixed the cross-repo Print Document Contract link in `docs/print-mode.md`.
316
+
317
+ ### Added
318
+
319
+ - GitHub Actions release workflow (`.github/workflows/release-components.yml`): tag `v*` or
320
+ `workflow_dispatch` build, dist integrity checks, sha256 bundle output, version bump guard vs npm
321
+ `latest`, optional handoff sync (`HANDOFF_REPO_TOKEN`) and npm publish (`NPM_TOKEN`).
322
+ - Release verification script `scripts/verifyDistRelease.js`, manual fallback
323
+ `scripts/release-components.sh`, and `npm run release:verify`.
324
+ - Component manifest pilot for `ImageBlock` (`src/manifests/image-block.manifest.json`) with JSON Schema (`src/manifests/component-manifest.schema.json`), docs (`docs/component-manifests.md`), validation test (`test/manifests.test.mjs`), and Storybook manifest story (`stories/ImageBlockManifest.stories.tsx`).
package/README.md CHANGED
@@ -1,56 +1,71 @@
1
+ <!-- Generated from uhuu-storybook/docs/package-readme.md; edit the owning source. -->
1
2
 
2
3
  # Uhuu Components
3
4
 
5
+ React components for printable documents with fixed pages, static flow pagination, interactive editing, image bleed/spread layouts and BrandKit styling.
4
6
 
7
+ ## Install
5
8
 
6
- Uhuu react components simplify printable document creation with configurable page attributes.<br/>
7
- Easily implement advanced features like pagination, bleeds, and spreads with precision and flexibility.
8
-
9
-
10
- ```bash
11
- # Install uhuu components via npm
12
- npm i uhuu-components
9
+ ```sh
10
+ npm install uhuu-components@^0.3.2 react react-dom
13
11
  ```
14
12
 
15
- Let’s bring your documents to life! 🎨📄
13
+ The delivery package declares React and React DOM `^18.0.0 || ^19.0.0` peers. Both must use the same React installation. Local owning verification uses React 19; the declared React 18 range is not evidence of a tested React 18 release. UI dependencies are bundled; React and React DOM remain external. No Next dependency is required by the delivery package.
14
+
15
+ ## Fixed pages and static flow
16
16
 
17
+ ```jsx
18
+ import { Static } from 'uhuu-components'
17
19
 
18
- <br/>
20
+ export function Document() {
21
+ return (
22
+ <Static.Pagination>
23
+ <Static.Sheet width={210} height={297}>
24
+ <h1>Document</h1>
25
+ </Static.Sheet>
26
+ </Static.Pagination>
27
+ )
28
+ }
29
+ ```
19
30
 
20
- ## Pagination Components
31
+ Page dimensions and bleed use millimetres. `Static.FlowPage`, `Static.FlowArea`, `Static.Flow` and `Static.FlowColumns` paginate explicit content inside static pages. Templates keep their layout and data rules. See [static flow pagination](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/static-flow-pagination.md) and [cover/spine printing](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/printer-cover-spine-support.md).
21
32
 
22
- ### **Static Pagination**
23
- For content that fits within defined page boundaries or requires fixed page breaks.
24
- Static pagination maintains precise control over the document layout.
33
+ ## Editor and field dialogs
25
34
 
26
- **Use Case**: Structured layouts like catalogs, brochures, and contracts.
35
+ `EditorShell` exports `TemplateDataProvider`, `PageEditor`, `InteractiveModeProvider`, `useInteractive` and `useIntegrationAdapter`. PageEditor owns the editing shell, page management and print filtering; its dialogs and internal helpers are not separate package exports.
27
36
 
28
- ### **Dynamic Pagination**
29
- Automatically flows content across pages, adding or removing pages as needed.
30
- Dynamic pagination is ideal for handling variable-length content.
37
+ ```jsx
38
+ import { Editable, getDialogProps } from 'uhuu-components'
31
39
 
32
- **Use Case**: Reports, invoices, or newsletters where content size changes dynamically.
40
+ <Editable dialog={{ path: 'title', type: 'text', value: title }}>{title}</Editable>
41
+ <p {...getDialogProps({ dialog: { path: 'intro', type: 'textarea', value: intro } })}>
42
+ {intro}
43
+ </p>
44
+ ```
33
45
 
34
- <br/>
35
- <br/>
46
+ Dialog click handlers are omitted in renderer mode. Empty text bindings remain editable; templates control their print visibility and Markdown renderer. See the [editor shell guide](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/editor-shell.md).
36
47
 
48
+ The shell's own words ship in German, French, Italian and English and follow the host's language; `InteractiveModeProvider` takes `locale` and `translations` to pin, override or add a language, and template labels accept one string per language. See [editor shell translations](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/editor-shell-translations.md).
37
49
 
50
+ ## Images and BrandKit
38
51
 
39
- ## Image Components
52
+ Use public `ImageBlock` with `mode="bleed"`, `mode="spread"` or `mode="auto"`; internal ImageBleed and ImageSpread components are not package exports. `imageUrl` provides print-aware thumbnail URLs and preserves SVG/data/relative URLs.
40
53
 
41
- ### **Image Bleed**
42
- Extends images beyond the trim edges into the bleed area to ensure clean edges after trimming.
43
- Designed for professional printing where content must exceed the final cut line.
54
+ ```jsx
55
+ import { BrandKitProvider, ImageBlock, imageUrl } from 'uhuu-components'
44
56
 
45
- **Key Feature**: Automatically adjusts images to fill the bleed space.
57
+ <BrandKitProvider brandKit={brandKit}>
58
+ <img src={imageUrl(cover)} alt="" />
59
+ <ImageBlock src={cover} mode="bleed" width={210} height={297} bleed={3} />
60
+ </BrandKitProvider>
61
+ ```
46
62
 
47
- **Use Case**: Borderless designs, posters, and full-page images.
63
+ `BrandKitProvider` and `useBrandKit` apply accepted kit runtime tokens, load declared fonts and expose logo, collection, map and environment helpers. `src` can fetch a kit while `brandKit` supplies its fallback. See [BrandKit runtime](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/brand-kit-runtime.md) and [image URLs](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/image-url.md).
48
64
 
65
+ ## Package entries and ownership
49
66
 
50
- ### **Image Spread**
51
- Covers two facing pages with a single image for high-impact visuals.
52
- Adds bleed to ensure proper alignment after cutting and binding.
67
+ ESM imports and CommonJS `require('uhuu-components')` expose the same public root API. The single UMD artifact is `uhuu-components.umd.cjs`; it also exposes `UhuuComponents` when loaded as a browser script. Direct URLs to older `.umd.js` files remain part of those pinned releases; future releases use `.umd.cjs`.
53
68
 
54
- **Key Feature**: Creates uninterrupted visuals across two pages.
69
+ See [distribution surface](https://github.com/uhuuio/uhuu-storybook/blob/main/docs/distribution-surface.md) for the measured exports and bundled dependency boundary. Release notes are included in `CHANGELOG.md`.
55
70
 
56
- **Use Case**: Magazine features, product showcases, and immersive storytelling.
71
+ Source, stories, documentation and release generation belong to [uhuu-storybook](https://github.com/uhuuio/uhuu-storybook). The [uhuu-components delivery repository](https://github.com/uhuuio/uhuu-components) contains generated releases. Build in Storybook, then explicitly hand off the reviewed artifacts. The generated README must be changed in Storybook's `docs/package-readme.md`.
package/index.d.ts CHANGED
@@ -469,6 +469,35 @@ export interface InteractiveModeContextValue {
469
469
  interactive: boolean;
470
470
  setInteractive: (interactive: boolean) => void;
471
471
  enableDevTools?: boolean;
472
+ /** The shell's resolved interface language (`de`, `fr`, `it`, `en`, or what the template passed). */
473
+ locale: string;
474
+ }
475
+
476
+ /**
477
+ * A label as one string, or one string per language: `{ en: 'Cover', de: 'Titelseite' }`.
478
+ * Accepted wherever `templateConfig` and `pageOptions` take a `label` (pages, groups, options,
479
+ * select and colour values) and by `reorderTitle` / `reorderDescription`. Resolved in the shell's
480
+ * language, then English, then the first entry.
481
+ */
482
+ export type LocalizedText = string | Record<string, string>;
483
+
484
+ /** Editor shell words, nested as in the English catalog (docs/editor-shell-translations.md). */
485
+ export type EditorShellTranslations = { [key: string]: string | EditorShellTranslations };
486
+
487
+ export interface InteractiveModeProviderProps {
488
+ children: ReactNode;
489
+ defaultInteractive?: boolean;
490
+ enableDevTools?: boolean;
491
+ /**
492
+ * The shell's interface language. Default: the host's (uhuu-app's locale from the SDK
493
+ * handshake), then `?lang=`, `<html lang>`, the browser's languages, then `en`.
494
+ */
495
+ locale?: string;
496
+ /**
497
+ * Per-language overrides of the shell's words, or a whole catalog for a language the package
498
+ * does not ship: `{ de: { toolbar: { add: 'Neu' } }, rm: romanshCatalog }`. Pass a stable object.
499
+ */
500
+ translations?: Record<string, EditorShellTranslations>;
472
501
  }
473
502
 
474
503
  export interface BrandKitOption {
@@ -535,8 +564,8 @@ export interface PageEditorProps {
535
564
  pageId?: string;
536
565
  parent?: unknown;
537
566
  }) => ReactNode;
538
- reorderTitle?: string;
539
- reorderDescription?: string;
567
+ reorderTitle?: LocalizedText;
568
+ reorderDescription?: LocalizedText;
540
569
  stateKey?: string;
541
570
  brandKits?: BrandKitOption[];
542
571
  activeBrandKitId?: string;
@@ -570,11 +599,7 @@ export interface IntegrationAdapter {
570
599
  export const EditorShell: {
571
600
  TemplateDataProvider: ComponentType<TemplateDataProviderProps>;
572
601
  PageEditor: ComponentType<PageEditorProps>;
573
- InteractiveModeProvider: ComponentType<{
574
- children: ReactNode;
575
- defaultInteractive?: boolean;
576
- enableDevTools?: boolean;
577
- }>;
602
+ InteractiveModeProvider: ComponentType<InteractiveModeProviderProps>;
578
603
  useInteractive: () => InteractiveModeContextValue;
579
604
  useIntegrationAdapter: (config: IntegrationAdapterConfig) => IntegrationAdapter;
580
605
  };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.3.0",
2
+ "version": "0.3.2",
3
3
  "name": "uhuu-components",
4
4
  "main": "uhuu-components.umd.cjs",
5
5
  "module": "uhuu-components.es.js",
@@ -15,6 +15,15 @@
15
15
  }
16
16
  },
17
17
  "license": "https://uhuu.io/license",
18
+ "files": [
19
+ "uhuu-components.es.js",
20
+ "uhuu-components.es.js.map",
21
+ "uhuu-components.umd.cjs",
22
+ "uhuu-components.umd.cjs.map",
23
+ "index.d.ts",
24
+ "README.md",
25
+ "CHANGELOG.md"
26
+ ],
18
27
  "peerDependencies": {
19
28
  "react": "^18.0.0 || ^19.0.0",
20
29
  "react-dom": "^18.0.0 || ^19.0.0"