@cosmicdrift/kumiko-types 0.220.1 → 0.221.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cosmicdrift/kumiko-types",
3
- "version": "0.220.1",
3
+ "version": "0.221.0",
4
4
  "description": "Framework-Type-Definitions für Kumiko — FeatureDefinition, BootCheck-Types und die reinen Engine-Types. Erlaubt Downstream-Konsumenten, gegen die Type-Contracts zu bauen, ohne das ganze Framework-Package zu importieren. Enthaelt keine identitaets-sensitiven Runtime-Werte mehr (Error-Klassen leben seit #1629 in kumiko-framework, Brand-Symbole nutzen Symbol.for) und ist deshalb eine plain dependency, keine peerDependency.",
5
5
  "license": "BUSL-1.1",
6
6
  "author": "Marc Frost <marc@cosmicdriftgamestudio.com>",
@@ -166,6 +166,10 @@
166
166
  "types": "./src/nav-icon.ts",
167
167
  "default": "./src/nav-icon.ts"
168
168
  },
169
+ "./field-icon": {
170
+ "types": "./src/field-icon.ts",
171
+ "default": "./src/field-icon.ts"
172
+ },
169
173
  "./ownership": {
170
174
  "types": "./src/ownership.ts",
171
175
  "default": "./src/ownership.ts"
@@ -0,0 +1,23 @@
1
+ // Closed vocabulary of edit-field prefix icon keys. EditFieldSpec.icon,
2
+ // InputProps.icon and EditFieldViewModel.icon are typed against this union,
3
+ // so a typo (`"mial"`) is a compile error at the screen-def / view-model
4
+ // call site instead of a silent missing-icon at runtime.
5
+ //
6
+ // The renderer-web FIELD_ICONS map (packages/renderer-web/src/primitives/
7
+ // index.tsx) is checked against this same union via `satisfies`, so the
8
+ // two can't drift — add a key here only together with its lucide-react
9
+ // entry there, and vice versa.
10
+ export type FieldIconKey =
11
+ | "mail"
12
+ | "lock"
13
+ | "hash"
14
+ | "search"
15
+ | "user"
16
+ | "phone"
17
+ | "calendar"
18
+ | "link"
19
+ | "tag"
20
+ | "building"
21
+ | "globe"
22
+ | "key"
23
+ | "map-pin";
package/src/nav.ts CHANGED
@@ -79,6 +79,9 @@ export type NavDefinition = {
79
79
  // `parent` may point at another feature's nav QN; the boot validator rejects
80
80
  // dangling refs, so a collection mounted under a feature that isn't mounted
81
81
  // fails boot instead of silently disappearing from the sidebar.
82
+ /** Client editor format for r.contentCollection() — not template body storage formats. */
83
+ export type ContentEditorFormat = "plain" | "rich" | "markdown";
84
+
82
85
  export type ContentCollectionDefinition = {
83
86
  // Feature-local short id, kebab-case. Also becomes the nav entry's id, so
84
87
  // it must not collide with an r.nav()/r.screen() id in the same feature.
@@ -104,7 +107,7 @@ export type ContentCollectionDefinition = {
104
107
  // the content is stored. "rich" still stores HTML, because mail and PDF
105
108
  // rendering want HTML either way. "markdown" stores markdown text, not
106
109
  // HTML. Defaults to "plain" (textarea).
107
- readonly contentFormat?: "plain" | "rich" | "markdown";
110
+ readonly contentFormat?: ContentEditorFormat;
108
111
  // Fixed variable names the collection's editor offers as insertable chips,
109
112
  // mapped to an example value the Preview substitutes in for `{{name}}`
110
113
  // (e.g. `{ customerName: "Max Mustermann", orderId: "A-1042" }` for an
package/src/screen.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import type { FieldIconKey } from "./field-icon";
1
2
  import type { FieldDefinition } from "./fields";
2
3
  import type { AccessRule } from "./handlers";
3
4
  import type { NavIconKey } from "./nav-icon";
4
5
 
6
+ export type { FieldIconKey } from "./field-icon";
7
+
5
8
  // Screen definitions describe how a feature surfaces data to the user.
6
9
  // Pure data — the engine stores these verbatim and ui-core / the renderer
7
10
  // packages decide what to do with them. The framework must not import
@@ -55,6 +58,8 @@ export interface FieldFormatRegistry {
55
58
  number: { readonly locale?: string };
56
59
  decimal: { readonly locale?: string };
57
60
  bigInt: { readonly locale?: string };
61
+ // Value is percent *points* (12 → "12 %"), not a 0..1 ratio — Intl
62
+ // style:"unit"/unit:"percent" does NOT multiply by 100 (unlike style:"percent").
58
63
  unit: {
59
64
  readonly unit: UnitKey;
60
65
  readonly locale?: string;
@@ -64,6 +69,8 @@ export interface FieldFormatRegistry {
64
69
  // `<feature>:entity:<entity>:field:<field>:option:<value>` — same
65
70
  // fallback-to-raw-value rule as buildOptionLabels: an untranslated key
66
71
  // renders the raw enum value instead of the literal i18n key.
72
+ // Prefer fieldOptionLabelKeyPrefix() from @cosmicdrift/kumiko-headless
73
+ // over hand-typed prefix strings.
67
74
  enumOption: { readonly keyPrefix: string };
68
75
  }
69
76
 
@@ -222,20 +229,10 @@ export type RowActionWriteHandler = {
222
229
  readonly style?: "primary" | "secondary" | "danger";
223
230
  };
224
231
 
225
- export type RowActionNavigate = {
232
+ export type RowActionNavigateBase = {
226
233
  readonly kind: "navigate";
227
234
  readonly id: string;
228
235
  readonly label: string;
229
- /** Screen-id (kurz, unqualified) zu dem navigiert wird. Boot-
230
- * Validator prüft Existenz im selben Feature. Genau eines von
231
- * `screen`/`entity` muss gesetzt sein. */
232
- readonly screen?: string;
233
- /** Entity-Name statt Screen-Id (fw#2228) — löst zur Boot-Zeit auf den
234
- * Screen auf, der `detailFor: "<entity>"` deklariert (siehe ObjectTarget/
235
- * resolveTarget in @cosmicdrift/kumiko-renderer's nav.tsx), egal in
236
- * welchem Feature dieser liegt. Genau eines von `screen`/`entity` muss
237
- * gesetzt sein. */
238
- readonly entity?: string;
239
236
  /** Feldname dessen Wert als entityId in den URL-Pfad eingebettet wird
240
237
  * (`/<workspace>/<screen>/<entityId>`). entityEdit liest die Id
241
238
  * AUSSCHLIESSLICH aus dem Pfad. Default: "id" wenn der Ziel-Screen ein
@@ -257,6 +254,25 @@ export type RowActionNavigate = {
257
254
  readonly rowClick?: boolean;
258
255
  };
259
256
 
257
+ /** Exactly one of `screen` / `entity` — mutual exclusivity is type-enforced
258
+ * (boot validator still rejects both/neither for untyped schemas). */
259
+ export type RowActionNavigate = RowActionNavigateBase &
260
+ (
261
+ | {
262
+ /** Screen-id (kurz, unqualified). Boot-Validator prüft Existenz im
263
+ * selben Feature. */
264
+ readonly screen: string;
265
+ readonly entity?: never;
266
+ }
267
+ | {
268
+ /** Entity-Name statt Screen-Id (fw#2228) — löst zur Boot-Zeit auf den
269
+ * Screen auf, der `detailFor: "<entity>"` deklariert (siehe ObjectTarget/
270
+ * resolveTarget in @cosmicdrift/kumiko-renderer's nav.tsx). */
271
+ readonly entity: string;
272
+ readonly screen?: never;
273
+ }
274
+ );
275
+
260
276
  // ToolbarAction — button in the list header. Three variants: navigate to
261
277
  // another screen (e.g. a full-page actionForm), dispatch a handler directly
262
278
  // (e.g. "Sync All" without a form), or mount an actionForm in a Drawer
@@ -354,9 +370,10 @@ export type EntityListScreenDefinition = {
354
370
  // User-toggleable facet dropdown on a projectionList screen (fw#2224).
355
371
  // entityList derives the same UI from `filterable: true` entity fields plus
356
372
  // the `<feature>:entity:<entity>:field:<field>:option:<value>` i18n
357
- // convention a projectionList has no entity to derive from, so every
358
- // label here is explicit instead. Sent to the server as
359
- // `{field, op:"in", value}` in `payload.filters`, ANDed with `filter`.
373
+ // convention. Labels here (`label`, `options[].label`, `trueLabel`/
374
+ // `falseLabel`) are i18n keys resolved via `translate()` with passthrough
375
+ // for unknown keys (fw#2373) — not raw display strings. Sent to the server
376
+ // as `{field, op:"in", value}` in `payload.filters`, ANDed with `filter`.
360
377
  export type ListFacetSpec =
361
378
  | {
362
379
  readonly field: string;
@@ -609,14 +626,13 @@ export type EditFieldSpec =
609
626
  readonly readOnly?: FieldCondition;
610
627
  readonly required?: FieldCondition;
611
628
  readonly renderer?: FieldRenderer;
612
- /** Prefix icon on the input — symbolic key into the FIELD_ICONS
613
- * registry (renderer-web), analogous to `ScreenNavSugar.icon`.
614
- * Unknown key → no icon (clean fallback, no boot-fail). Only takes
615
- * effect for single-line `type: "text"` and `"number"` — a `text`
616
- * field with `multiline` routes to a textarea (no icon slot), and
617
- * other input kinds (select, combobox, date, …) silently ignore
618
- * the key. */
619
- readonly icon?: string;
629
+ /** Prefix icon on the input — closed FieldIconKey vocabulary into
630
+ * the FIELD_ICONS registry (renderer-web), analogous to
631
+ * `ScreenNavSugar.icon` / NavIconKey. Only takes effect for
632
+ * single-line `type: "text"` and `"number"` — a `text` field with
633
+ * `multiline` routes to a textarea (no icon slot), and other input
634
+ * kinds (select, combobox, date, …) silently ignore the key. */
635
+ readonly icon?: FieldIconKey;
620
636
  };
621
637
 
622
638
  // A section is a normal field-grid (default — `kind` omitted keeps every