uhuu-components 0.4.0 → 0.4.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/index.d.ts CHANGED
@@ -414,6 +414,246 @@ export interface ImageUrlOptions {
414
414
  */
415
415
  export function imageUrl(src: ImageSource, options?: ImageUrlOptions): string | undefined;
416
416
 
417
+ // --- Image frames (src/uhuu/frame/). See docs/frame-block.md. ---
418
+ // The read helpers are the vendored `uhuu.frame.v1` module (src/uhuu/frame/vendor, generated from
419
+ // uhuu-editor-dialogs). dist ships this file alone, so the module's types are mirrored here;
420
+ // test/frame-vendor.test.mjs checks the mirror against the vendored source.
421
+
422
+ /** `value.uhuuFrame.schema` of a frame. */
423
+ export const FRAME_SCHEMA: "uhuu.frame.v1";
424
+ /** Key of the frame record inside a frame value. Namespaced so it cannot collide with template keys. */
425
+ export const FRAME_KEY: "uhuuFrame";
426
+
427
+ /** Which legacy image wins when an old value carries both a generated image and a pick. */
428
+ export type FrameLegacyPrecedence = "generated" | "pick";
429
+
430
+ /** A transform applied to a source's image (crop, AI enhance, …). Its base is the previous step. */
431
+ export interface FrameStep {
432
+ type: string;
433
+ url: string;
434
+ width?: number;
435
+ height?: number;
436
+ mimeType?: string;
437
+ /** Replayable parameters or result metadata (crop box, AI asset id, …). */
438
+ state?: Record<string, unknown>;
439
+ }
440
+
441
+ /** An overlay drawn over a source's image by the page (annotation). Never composited into the image. */
442
+ export interface FrameLayer {
443
+ state: unknown;
444
+ /** The image the overlay was drawn on. */
445
+ baseUrl?: string;
446
+ /** The image under the overlay changed after it was drawn. */
447
+ stale?: boolean;
448
+ }
449
+
450
+ /** One dialog's own entry: its last image, the state it reopens with, its steps and layers. */
451
+ export interface FrameSource {
452
+ /** Absent for state-only saves (a map saved without a design image). */
453
+ url?: string;
454
+ /** Key the dialog used for its URL (`image` for generated dialogs); reproduced when it reopens. */
455
+ urlKey?: string;
456
+ width?: number;
457
+ height?: number;
458
+ mimeType?: string;
459
+ /** Everything else the dialog saved, URL keys removed. */
460
+ state?: Record<string, unknown>;
461
+ steps?: FrameStep[];
462
+ layers?: Record<string, FrameLayer>;
463
+ }
464
+
465
+ /** One-level undo: the active source before the last action and the entry it changed. */
466
+ export interface FrameUndo {
467
+ active: string | null;
468
+ /** Source entry the action changed; absent when only `active` moved. */
469
+ type?: string;
470
+ /** That entry before the action; `null` when the action created it. */
471
+ before?: FrameSource | null;
472
+ }
473
+
474
+ /** `value.uhuuFrame`: every source the slot holds and the one it shows. */
475
+ export interface FrameRecord {
476
+ schema: "uhuu.frame.v1";
477
+ active: string | null;
478
+ sources: Record<string, FrameSource>;
479
+ previous?: FrameUndo;
480
+ }
481
+
482
+ /**
483
+ * A frame value as stored in the payload. Its top level mirrors the active source in the shape it
484
+ * saved before frames — a map's image under `image`, a pick's under `contentUrl`, both also under
485
+ * `url` — so `imageUrl(value)` and the readers templates already have keep working.
486
+ */
487
+ export type FrameValue = Record<string, unknown> & { uhuuFrame: FrameRecord };
488
+
489
+ export interface FrameOptions {
490
+ /** Source types the field declares, in order. Resolves a legacy generated shape with no identifying key (a bare `{ image }`). */
491
+ sources?: readonly string[];
492
+ /** Default `'generated'`. Implenia IM passes `'pick'`. */
493
+ legacyPrecedence?: FrameLegacyPrecedence;
494
+ /**
495
+ * A legacy generated value whose upload failed keeps its render as a `data:` URL
496
+ * (`dataImage`). `'show'` (default) shows it, as Implenia IM, implenia-teaser and jbre's
497
+ * cadastral do; `'ignore'` treats the source as having no image, as wuw, evernest, go and
498
+ * jbre's map do (their placeholder shows). New saves never carry one.
499
+ */
500
+ legacyDataImage?: 'show' | 'ignore';
501
+ /**
502
+ * Also draw the overlay a source dialog keeps in its own state (cadastral's
503
+ * `annotationSvg`). Off by default: the cadastral dialog bakes that outline into its image.
504
+ */
505
+ intrinsicOverlays?: boolean;
506
+ /** A legacy overlay saved at a separate path (`annotationPath`); folded into the active source. */
507
+ legacyLayer?: unknown;
508
+ /** Layer type the legacy overlay becomes. Default `'annotation'`. */
509
+ legacyLayerType?: string;
510
+ }
511
+
512
+ export interface FrameDisplay {
513
+ /** The image to show; `''` when there is none. */
514
+ url: string;
515
+ width?: number;
516
+ height?: number;
517
+ mimeType?: string;
518
+ /** Active source type. */
519
+ source: string | null;
520
+ /** Number of transforms applied on top of the source image. */
521
+ steps: number;
522
+ }
523
+
524
+ export interface FrameOverlay {
525
+ /** Layer type, or the source type for an overlay the source dialog drew itself (cadastral). */
526
+ key: string;
527
+ svg: string;
528
+ stale: boolean;
529
+ /** Drawn by the source dialog as part of its own output. */
530
+ intrinsic: boolean;
531
+ }
532
+
533
+ /** The image an image-accepting dialog opens with (`eventData.input`). */
534
+ export interface FrameImageInput {
535
+ url: string;
536
+ width?: number;
537
+ height?: number;
538
+ mimeType?: string;
539
+ /** Frame source the image comes from. */
540
+ source?: string;
541
+ }
542
+
543
+ /** True when `value` carries a `uhuu.frame.v1` record. */
544
+ export function isFrameValue(value: unknown): value is FrameValue;
545
+
546
+ /**
547
+ * The frame record of any value: a frame (validated), or a value saved before frames (URL string,
548
+ * ImageObject, a generated dialog's output) read into one in memory. Never writes. `null` for an
549
+ * empty slot. A frame whose mirrored `contentUrl` was patched by a writer that does not know frames
550
+ * reads that patch as the newest pick.
551
+ */
552
+ export function normalizeFrame(value: unknown, options?: FrameOptions): FrameRecord | null;
553
+
554
+ /** What the page should show for this value: URL, size and the source it comes from. */
555
+ export function frameDisplay(value: unknown, options?: FrameOptions): FrameDisplay;
556
+
557
+ /** The image URL to show for a frame or legacy value; `''` when there is none. */
558
+ export function frameImage(value: unknown, options?: FrameOptions): string;
559
+
560
+ /** The active source type, or `null`. */
561
+ export function frameActive(value: unknown, options?: FrameOptions): string | null;
562
+
563
+ /** The input an image-accepting dialog opens with; `null` when nothing is shown. */
564
+ export function frameInput(value: unknown, options?: FrameOptions): FrameImageInput | null;
565
+
566
+ /**
567
+ * The overlays to draw over the shown image, bottom to top: the source dialog's own overlay
568
+ * (cadastral's `annotationSvg`), then the active source's layers. Stale layers are included.
569
+ */
570
+ export function frameOverlays(value: unknown, options?: FrameOptions): FrameOverlay[];
571
+
572
+ /**
573
+ * The value a source dialog reopens with, in the shape it saved (`{ list, home, mapbox, image }` for
574
+ * the map). `undefined` when the source has never been saved.
575
+ */
576
+ export function frameSourceView(value: unknown, type: string, options?: FrameOptions): Record<string, unknown> | undefined;
577
+
578
+ /** Any value as a stored frame, showing what it showed before. `null` for an empty slot. */
579
+ export function toFrameValue(value: unknown, options?: FrameOptions): FrameValue | null;
580
+
581
+ /**
582
+ * The options every reader of a slot passes, from its declaration: its sources, legacy
583
+ * precedence, failed-upload rule, and the overlay saved at `annotationPath` (read from `payload`).
584
+ */
585
+ export function frameOptionsOf(declaration: Partial<FrameDeclaration>, payload?: unknown): FrameOptions;
586
+
587
+ /** The image shown now and the overlay saved at `annotationPath`: what an editor without frames annotates. */
588
+ export interface FrameLegacyCurrent {
589
+ image?: string;
590
+ annotation?: unknown;
591
+ }
592
+
593
+ /**
594
+ * `{ path, frame, types }`: the message `$uhuu.editFrame` sends, for an `ImageBlock` `dialog` or an
595
+ * SDK without `editFrame`. `types` is the chooser an editor without frames shows. `null` without a
596
+ * `path` or a source with a `type`.
597
+ */
598
+ export function frameEditDialog(
599
+ declaration: FrameDeclaration,
600
+ current?: FrameLegacyCurrent | null,
601
+ ): { path: string; frame: Omit<FrameDeclaration, "path">; types: Record<string, unknown>[] } | null;
602
+
603
+ /** Opens a frame from a template's own click handler: `$uhuu.editFrame` when the SDK has it, else `editDialog` with `frameEditDialog`'s message. No host, no call. */
604
+ export function openFrame(declaration: FrameDeclaration, current?: FrameLegacyCurrent | null): void;
605
+
606
+ /** One dialog a frame offers: its type, its title in the chooser, and that dialog's own options. */
607
+ export interface FrameDialogEntry {
608
+ type: string;
609
+ title?: string;
610
+ /** The dialog's configuration (coordinates, styles, zoom, `visualGallery`, …). */
611
+ config?: Record<string, unknown>;
612
+ /** Other options for that dialog (`imageGalleryPath`, `galleryUpload`, …). */
613
+ [key: string]: unknown;
614
+ }
615
+
616
+ /** What `$uhuu.editFrame` takes (uhuu-sdk): the slot and the dialogs it offers. */
617
+ export interface FrameDeclaration {
618
+ /** Where the frame is saved. */
619
+ path: string;
620
+ /** The dialogs that create the image (`map`, `satellite`, `cadastral`, `image`, …), in chooser order. */
621
+ sources: FrameDialogEntry[];
622
+ /** Overlays drawn over the shown image (`annotation`). */
623
+ layers?: FrameDialogEntry[];
624
+ /** Transforms offered on the shown image (`image-editor`, `ai-marketing-studio`). Default: all the editor offers; `false` for none. */
625
+ transforms?: string[] | false;
626
+ /** Crop aspect ratio, width / height. */
627
+ ratio?: number;
628
+ /** Which image an old document shows when it holds both a generated image and a pick. Default `'generated'`. */
629
+ legacyPrecedence?: FrameLegacyPrecedence;
630
+ /** Whether an old map whose upload failed shows its unsaved render (`'show'`, default) or the placeholder (`'ignore'`). */
631
+ legacyDataImage?: 'show' | 'ignore';
632
+ /** An overlay saved at its own path before frames. Pass its value as FrameBlock's `annotation`. */
633
+ annotationPath?: string;
634
+ }
635
+
636
+ export interface FrameBlockProps extends FrameDeclaration, Omit<ImageBlockProps, "src" | "dialog" | "annotation"> {
637
+ /** The value at `path`: a frame, or anything saved there before frames. */
638
+ value?: unknown;
639
+ /** Also draw a source's own outline (cadastral `annotationSvg`); off because the cadastral image has it baked in. */
640
+ intrinsicOverlays?: boolean;
641
+ /** The overlay value saved at `annotationPath`; read as the active source's layer until the frame holds its own. */
642
+ annotation?: ImageBlockAnnotationValue | null;
643
+ /** Rendered instead of the frame's image: a template adapter's own URL. */
644
+ src?: string;
645
+ /** `imageUrl` options for the shown image (`print`, `size`, `printSize`, `format`). */
646
+ imageUrlOptions?: ImageUrlOptions;
647
+ }
648
+
649
+ /**
650
+ * An image slot several dialogs write (map, satellite, cadastral, gallery pick, crop, annotation),
651
+ * stored as a `uhuu.frame.v1` value. Renders the shown image through `imageUrl` with every overlay
652
+ * of the active source over it, and opens `$uhuu.editFrame` on click in the editor (`editDialog`
653
+ * with the legacy `types` on an older SDK; nothing in renderer mode). Layout props are ImageBlock's.
654
+ */
655
+ export const FrameBlock: ComponentType<FrameBlockProps>;
656
+
417
657
  // --- Brand-kit runtime (src/uhuu/brand-kit/). See docs/brand-kit-runtime.md. ---
418
658
 
419
659
  export interface BrandKitFontFile {
@@ -852,7 +1092,8 @@ export interface PageEditorTemplateConfig {
852
1092
 
853
1093
  export interface PageOptionSelectValue {
854
1094
  label: LocalizedText;
855
- value: string;
1095
+ /** Matched to the stored value as a string (`2` is `"2"`); a payload option writes it typed by `valueType`. */
1096
+ value: string | number | boolean;
856
1097
  hex?: string;
857
1098
  }
858
1099
 
@@ -883,12 +1124,27 @@ export type ColorSeriesPageOption = BasePageOption & {
883
1124
  };
884
1125
  export type PageOption = SelectPageOption | TogglePageOption | SliderPageOption | CounterPageOption | ColorSeriesPageOption;
885
1126
 
1127
+ /** How a payload option writes a choice: default `boolean` for a toggle, `number` for a slider or counter, else `string`. */
1128
+ export type OptionValueType = "string" | "number" | "boolean";
1129
+
1130
+ /** What a payload option (a page option without callbacks, or a document option) adds to its control. */
1131
+ interface PayloadOptionStorage {
1132
+ /** Shown while the payload holds no value (`stored ?? defaultValue`). */
1133
+ defaultValue?: any;
1134
+ /** The stored key. Default: `id`. */
1135
+ field?: string;
1136
+ valueType?: OptionValueType;
1137
+ }
1138
+
886
1139
  type PayloadOptionFor<Option> = Option extends PageOption
887
- ? Omit<Option, "getValue" | "onChange" | "applyPatch"> & { defaultValue?: any; field?: string }
1140
+ ? Omit<Option, "getValue" | "onChange" | "applyPatch"> & PayloadOptionStorage
888
1141
  : never;
889
- /** A page option stored automatically in `payload.pages`, without custom callbacks. */
1142
+ /** A page option stored automatically in `payload.pages[pageId]`, without custom callbacks. */
890
1143
  export type PayloadOptionDefinition = PayloadOptionFor<PageOption>;
891
1144
 
1145
+ /** The corner of PageEditor's floating toolbar. */
1146
+ export type ToolbarPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
1147
+
892
1148
  export interface PageEditorProps {
893
1149
  /** Pages, groups and initial items; `pageManagement` sets the page-management controls. */
894
1150
  templateConfig: PageEditorTemplateConfig;
@@ -907,6 +1163,12 @@ export interface PageEditorProps {
907
1163
  pageFilter?: PageFilterConfig;
908
1164
  printConfigs?: PrintConfigMap;
909
1165
  defaultZoomMode?: PageEditorDefaultZoomMode;
1166
+ /**
1167
+ * The corner the floating toolbar (page count, Add, Reorder, document options, zoom) starts in.
1168
+ * Default `bottom-right`. A user moves it from the zoom menu; their corner is remembered in the
1169
+ * browser and wins over this one.
1170
+ */
1171
+ toolbarPosition?: ToolbarPosition;
910
1172
  onItemsChange?: (items: PageItem[], state: PageEditorState) => void;
911
1173
  onStateChange?: (state: PageEditorState) => void;
912
1174
  /**
@@ -963,26 +1225,32 @@ export interface IntegrationAdapter {
963
1225
  [key: string]: unknown;
964
1226
  }
965
1227
 
1228
+ type DocumentOptionFor<Option> = Option extends PageOption
1229
+ ? Omit<Option, "getValue" | "onChange" | "applyPatch" | "appliesTo"> & PayloadOptionStorage
1230
+ : never;
1231
+
966
1232
  /**
967
- * One document-level option: a top-level payload key the template reads (`payload.language`).
968
- * The shape `uhuu templates theme inspect <templateId> --snippet` prints from a legacy template
969
- * theme. See docs/document-options.md.
1233
+ * The 0.4 shape, as `uhuu templates theme inspect <templateId> --snippet` prints a legacy theme:
1234
+ * `key` names the payload key, and a select may leave out `type`.
1235
+ * @deprecated Define document options as payload page options are, with `id`.
970
1236
  */
971
- export interface DocumentOptionDefinition {
972
- /** The top-level payload key, the same one the platform's theme option wrote. */
1237
+ export interface LegacyDocumentOptionDefinition {
973
1238
  key: string;
974
- /** Default `select`. */
975
1239
  type?: "select" | "toggle";
976
1240
  label: LocalizedText;
977
1241
  description?: LocalizedText;
978
- /** A select's choices. A stored value matches a choice as a string: `2` matches `"2"`. */
979
1242
  options?: Array<{ value: string | number | boolean; label: LocalizedText }>;
980
- /** Shown while the payload has no value for the key (`payload[key] ?? defaultValue`). */
981
1243
  defaultValue?: unknown;
982
- /** Local onChange previews: default `string` for a select, `boolean` for a toggle. Editor selects save strings. */
983
- valueType?: "string" | "number" | "boolean";
1244
+ valueType?: OptionValueType;
984
1245
  }
985
1246
 
1247
+ /**
1248
+ * One document-level option: a top-level payload key the template reads (`payload.language`),
1249
+ * defined, valued and drawn as a payload page option is (`id` names the key, `field` overrides
1250
+ * it). See docs/document-options.md.
1251
+ */
1252
+ export type DocumentOptionDefinition = DocumentOptionFor<PageOption> | LegacyDocumentOptionDefinition;
1253
+
986
1254
  export interface DocumentOptionsProps {
987
1255
  /**
988
1256
  * The payload the template renders. Required outside a TemplateDataProvider; inside one, the
@@ -993,14 +1261,13 @@ export interface DocumentOptionsProps {
993
1261
  /** Heading of the control. Default: "Document options" in the shell's interface language. */
994
1262
  title?: LocalizedText;
995
1263
  /**
996
- * Called for local choices when no supported $uhuu.editDialog is available. The editor field
997
- * saves through the next payload update and does not call onChange.
1264
+ * Called for local choices, when there is no uhuu document editor on the page. In the editor a
1265
+ * choice arrives through the next payload update.
998
1266
  */
999
1267
  onChange?: (key: string, value: unknown) => void;
1000
- /**
1001
- * Inside PageEditor's floating toolbar: the entry's wrapper. Otherwise the control's own
1002
- * floating bar, bottom right by default (move it with `style`, e.g. `{ top: 16, bottom: "auto" }`).
1003
- */
1268
+ /** The corner of the control's own floating bar, drawn when no PageEditor toolbar is on screen. Default `bottom-right`. */
1269
+ toolbarPosition?: ToolbarPosition;
1270
+ /** Inside PageEditor's floating toolbar: the entry's wrapper. Otherwise the control's own floating bar. */
1004
1271
  className?: string;
1005
1272
  style?: CSSProperties;
1006
1273
  }
@@ -1012,9 +1279,10 @@ export const EditorShell: {
1012
1279
  useInteractive: () => InteractiveModeContextValue;
1013
1280
  useIntegrationAdapter: (config: IntegrationAdapterConfig) => IntegrationAdapter;
1014
1281
  /**
1015
- * Document-level switches for top-level payload keys, edited through the released editor's
1016
- * `$uhuu.editDialog` field. Joins the nearest InteractiveModeProvider's PageEditor toolbar, else floats bottom right.
1017
- * Hidden outside edit mode, in the PDF renderer and in print. See docs/document-options.md.
1282
+ * Document-level options for top-level payload keys, defined and drawn as page options are. A
1283
+ * choice is an edit in the uhuu document editor. Joins the nearest InteractiveModeProvider's
1284
+ * PageEditor toolbar, else floats in a corner. Hidden outside edit mode, in the PDF renderer and
1285
+ * in print. See docs/document-options.md.
1018
1286
  */
1019
1287
  DocumentOptions: ComponentType<DocumentOptionsProps>;
1020
1288
  };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.4.0",
2
+ "version": "0.4.2",
3
3
  "name": "uhuu-components",
4
4
  "main": "uhuu-components.umd.cjs",
5
5
  "module": "uhuu-components.es.js",