cedar-embeddable-editor 2.0.9 → 2.0.11

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 CHANGED
@@ -7,8 +7,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+
12
+ - A second element, `cedar-embeddable-field`, registered by the same bundle. It renders one field's
13
+ control and nothing of the form around it, for a host that holds a field artifact rather
14
+ than a template — a designer collecting a default value, above all. The value goes in and
15
+ out as a discriminated union rather than as text: a literal, a number, an ISO temporal
16
+ literal, an IRI with a label, a list of literals, or an attribute-value field's named
17
+ slots. `readOnlyMode` presents rather than acquires, replacing an empty control with a
18
+ statement of what the field will accept. `fieldObject` takes a field artifact rather than a
19
+ field model, because the element and its host hold separate copies of the model library and
20
+ CEE reads an artifact through class identity. The bundle grows by 15,474 gzip bytes, to
21
+ 656,506 of the 840,000 the size gate allows.
22
+
10
23
  ### Changed
11
24
 
25
+ - Every field CEE renders now goes through one component. The eighteen-way widget switch and
26
+ the read-only choice between a control and a statement of the field's specification moved
27
+ out of the component renderer into `CedarFieldWidgetComponent`, which the renderer and the
28
+ new element both draw. A widget added or rerouted reaches both, and the element cannot
29
+ drift from the editor the way a second implementation would.
30
+
31
+ - The three settings the widgets themselves read — the authority endpoints, whether template
32
+ rich text is trusted, and read-only mode — are applied by one coordinator that both elements
33
+ use, rather than by the editor alone.
34
+
12
35
  - The download menu names each entry by the artifact it produces, then the serialization:
13
36
  `Template - YAML`, `Template - Compact YAML`, `Template - JSON Schema`, `Instance - YAML`,
14
37
  `Instance - Compact YAML`, `Instance - JSON-LD`. It lists the three template downloads before the
@@ -17,6 +40,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
17
40
  - Compact YAML downloads retain the template's root ID but omit the IDs of nested fields and
18
41
  elements. Full YAML downloads continue to carry the complete identity tree.
19
42
 
43
+ ### Fixed
44
+
45
+ - Reassigning `cedar-embeddable-field.fieldObject` recreates the control even when the field type
46
+ stays the same, so validators and other initialized settings follow the new artifact.
47
+ - `cedar-embeddable-field` emits `valueChange` when validity changes even if the normalized value
48
+ does not, including numeric edits such as `1.5` to `1.50` and back.
49
+
50
+ ## [2.0.11] - 2026-09-11
51
+
52
+ This release carries CEE's field presentation changes against the same public
53
+ `cedar-model-typescript-library@1.0.8` package 2.0.10 embedded. The model library remains compiled
54
+ into CEE's browser bundle and is not a runtime dependency for embedding applications.
55
+
56
+ ### Changed
57
+
58
+ - A field's hint, error and warning now start at the left edge of its box, a date field is sized to
59
+ the date it holds, the numeric stepper is replaced by a clear action with the unit centred, and
60
+ the CEE name and version are centred under the mark.
61
+
62
+ ## [2.0.10] - 2026-09-10
63
+
64
+ This release aligns CEE's build-time model dependency with the public
65
+ `cedar-model-typescript-library@1.0.8` package. The model library remains compiled into CEE's
66
+ browser bundle and is not a runtime dependency for embedding applications.
67
+
68
+ ### Changed
69
+
70
+ - The application and visual-test dependency graphs now pin the same public
71
+ `cedar-model-typescript-library@1.0.8` tarball from npmjs.
72
+
20
73
  ## [2.0.9] - 2026-09-08
21
74
 
22
75
  This release carries the same shipped code as 2.0.8 against the same public
package/README.md CHANGED
@@ -103,6 +103,84 @@ takes the same page apart step by step, and
103
103
  [Embedding in a Framework](https://metadatacenter.readthedocs.io/en/latest/cedar-embeddable-editor/frameworks/)
104
104
  covers Angular, React, and Ember.
105
105
 
106
+ ## Embedding a Single Field
107
+
108
+ The bundle registers a second element. `<cedar-embeddable-field>` renders one field's
109
+ control — the same control the editor renders for that field, from the same component
110
+ — and nothing of the form around it: no label, no description, no card. A host that
111
+ holds a field artifact rather than a template puts this where the control belongs and
112
+ draws the rest itself.
113
+
114
+ Designing a template is what this is for. An author giving a field a default value
115
+ needs somewhere to type it, and the box that collects one has to be the control the
116
+ field will actually have: a date picker for a date, a term lookup for a controlled
117
+ term, a bounded number box for a number.
118
+
119
+ ```html
120
+ <cedar-embeddable-field></cedar-embeddable-field>
121
+
122
+ <script src="/assets/cedar-embeddable-editor.js"></script>
123
+ <script type="module">
124
+ const artifact = await (await fetch('/assets/organism-field.json')).json();
125
+
126
+ await customElements.whenDefined('cedar-embeddable-field');
127
+ const field = document.querySelector('cedar-embeddable-field');
128
+
129
+ field.config = { terminologyBaseUrl: 'https://terminology.metadatacenter.org/' };
130
+ field.addEventListener('valueChange', (event) => console.log(event.detail.value));
131
+
132
+ field.fieldObject = artifact;
133
+ </script>
134
+ ```
135
+
136
+ A field artifact, not a field model. A host holding a `TemplateField` from the CEDAR
137
+ Model TypeScript Library — a designer that just built one, say — writes it out and
138
+ assigns the result rather than assigning the object.
139
+
140
+ Assigning the object costs nothing and looks as though it should work, which is why
141
+ this is worth stating. The element's copy of the model library sits inside the CEE
142
+ bundle and the host's sits inside its own, so the two hold different classes, and CEE
143
+ decides what a field is by identity: `field.cedarFieldType === CedarFieldType.TEXT`,
144
+ and `instanceof` in three dozen other places. Every one of those comparisons is false
145
+ for an instance built elsewhere, so the field renders as a default rather than
146
+ failing. A serialization also survives the two packages pinning different versions of
147
+ the model library, which shared objects would not. The editor's `templateObject`
148
+ takes an artifact for the same reason.
149
+
150
+ The value comes back as a discriminated union rather than as text, because the
151
+ distinctions are real ones a host has to make again the moment it writes the value
152
+ into an artifact: a number is a number, a term is an IRI with a label, and a checkbox
153
+ group holds a set.
154
+
155
+ ```typescript
156
+ import type { CedarEmbeddableFieldChangeDetail, CedarEmbeddableFieldValue } from 'cedar-embeddable-editor';
157
+
158
+ declare function recordDefault(value: CedarEmbeddableFieldValue): void;
159
+
160
+ const field = document.querySelector('cedar-embeddable-field');
161
+
162
+ field?.addEventListener('valueChange', (event: CustomEvent<CedarEmbeddableFieldChangeDetail>) => {
163
+ const { value, valid } = event.detail;
164
+ if (valid) {
165
+ recordDefault(value);
166
+ }
167
+ });
168
+ ```
169
+
170
+ `fieldObject` may be reassigned as often as a host likes, and each assignment builds
171
+ the control afresh — the field being designed changes type under its author's hand.
172
+ `config` takes one assignment, as the editor's does. A value of a kind the field
173
+ cannot hold is reported through `eventHandler` and ignored rather than coerced.
174
+
175
+ Requiredness and cardinality belong to a field's deployment inside a template, and
176
+ this element deploys nothing, so the value it acquires is single and is allowed to be
177
+ absent. That is what makes it usable for a default, which is optional by definition. A
178
+ field declaring its own default starts out holding it.
179
+
180
+ `readOnlyMode` is the presentation half of the same element: with a value it shows the
181
+ value, and with none it replaces the control with a statement of what the field will
182
+ accept, which is what the editor shows for a template nobody has filled in.
183
+
106
184
  ## Building the Web Component
107
185
 
108
186
  One command produces the single file an embedder loads. Do not concatenate named
@@ -4,6 +4,6 @@
4
4
  "main.js",
5
5
  "polyfills.js"
6
6
  ],
7
- "bytes": 2205237,
8
- "sha256": "e6b0007a5479c2039d96dc85402872a4e5b4ea837f242f0a9bc627a22c46b101"
7
+ "bytes": 2350175,
8
+ "sha256": "1bde3c8415a0edab0561db02ffeebd9c4263af4c1619218e0a18721cb12c0fc1"
9
9
  }
@@ -276,6 +276,10 @@ export interface CedarEmbeddableEditorElement extends HTMLElement {
276
276
  /**
277
277
  * The template to render, as a parsed CEDAR artifact.
278
278
  *
279
+ * An artifact, not a model, for the reason given at `cedar-embeddable-field`'s
280
+ * `fieldObject`: the element and its host hold separate copies of the model library,
281
+ * and CEE reads a template through class identity.
282
+ *
279
283
  * Assignable more than once while no instance has been supplied: each one replaces the
280
284
  * form, building a fresh context, so nothing of the previous template survives. Once an
281
285
  * instance is loaded the template is fixed, and a further assignment is reported and
@@ -316,8 +320,151 @@ export interface CedarEmbeddableEditorElement extends HTMLElement {
316
320
  /** What CEE thinks of the instance. Read-only. */
317
321
  readonly dataQualityReport: CeeDataQualityReport;
318
322
  }
323
+ /**
324
+ * What one field holds, in the terms its own type is written in.
325
+ *
326
+ * The six shapes a CEDAR field value comes in, kept apart rather than flattened to
327
+ * text: a number is a number, a term is an IRI with a label beside it, a checkbox
328
+ * group holds a set, and an attribute-value field holds named slots. A host writing
329
+ * one of these back into an artifact needs the distinction, and collapsing it here
330
+ * only means the host parses its own input again — which is the fault the CEDAR
331
+ * Embeddable Designer's single `defaultValue: string` has.
332
+ *
333
+ * `none` is an unfilled field. It is also what a numeric field reports while it holds
334
+ * something that is not yet a number, `3.` on the way to `3.5`; `valid` on the change
335
+ * detail separates that from empty.
336
+ */
337
+ export type CedarEmbeddableFieldValue = {
338
+ kind: 'none';
339
+ }
340
+ /** Text, paragraph, email, phone, a radio choice, a single-choice list. */
341
+ | {
342
+ kind: 'literal';
343
+ value: string;
344
+ }
345
+ /** A numeric field, once what it holds is a finite number. */
346
+ | {
347
+ kind: 'number';
348
+ value: number;
349
+ }
350
+ /** A date or time, as the ISO literal its granularity calls for. */
351
+ | {
352
+ kind: 'temporal';
353
+ value: string;
354
+ }
355
+ /** A controlled term or an external authority record; a link, whose label is null. */
356
+ | {
357
+ kind: 'iri';
358
+ iri: string;
359
+ label: string | null;
360
+ }
361
+ /** A checkbox group or a multi-select list. */
362
+ | {
363
+ kind: 'literals';
364
+ values: string[];
365
+ }
366
+ /** An attribute-value field, whose slots are named by whoever fills them in. */
367
+ | {
368
+ kind: 'attributes';
369
+ values: Readonly<Record<string, string | null>>;
370
+ };
371
+ /** Detail carried by the `cedar-embeddable-field` element's `valueChange` event. */
372
+ export interface CedarEmbeddableFieldChangeDetail {
373
+ /** What the field now holds. */
374
+ value: CedarEmbeddableFieldValue;
375
+ /** Whether it satisfies the constraints the field declares. */
376
+ valid: boolean;
377
+ }
378
+ /**
379
+ * The configuration `cedar-embeddable-field` accepts.
380
+ *
381
+ * The subset of `CeeConfig` that describes a field rather than the form around one.
382
+ * The keys left out — the download menu, the expand controls, the template
383
+ * description — settle what an editor draws around its fields, and this element draws
384
+ * nothing around its own.
385
+ */
386
+ export type CedarEmbeddableFieldConfig = Pick<CeeConfig, 'readOnlyMode' | 'trustTemplateRichText' | 'terminologyBaseUrl' | 'bridgeBaseUrl' | 'defaultLanguage' | 'fallbackLanguage' | 'languageMapPathPrefix'>;
387
+ /**
388
+ * One field's control, as a host sees it.
389
+ *
390
+ * Registered as `cedar-embeddable-field`. It renders exactly the widget the editor
391
+ * renders for that field — the same component, not a second implementation — and
392
+ * reports what the widget holds. Around it there is nothing: no label, no description,
393
+ * no card. A host that has a field artifact and wants a value for it draws its own
394
+ * surroundings and puts this where the control goes.
395
+ *
396
+ * Read-only is the presentation half of the same element. Editable, the field is a
397
+ * control to fill in; read-only with nothing in it, the widget is replaced by a
398
+ * statement of what the field will accept, which is what the editor shows when it
399
+ * renders a template nobody has filled in yet.
400
+ *
401
+ * A field artifact carries no requiredness and no cardinality — both belong to a
402
+ * field's deployment in a template, and this element deploys nothing — so the value
403
+ * it acquires is single and is allowed to be absent. That is what makes it usable for
404
+ * a default value, which is optional by definition.
405
+ */
406
+ export interface CedarEmbeddableFieldElement extends HTMLElement {
407
+ /** Typed value event; the inherited overloads still handle every other DOM event. */
408
+ addEventListener(type: 'valueChange', listener: ((this: CedarEmbeddableFieldElement, event: CustomEvent<CedarEmbeddableFieldChangeDetail>) => unknown) | null, options?: boolean | AddEventListenerOptions): void;
409
+ addEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, event: HTMLElementEventMap[K]) => unknown, options?: boolean | AddEventListenerOptions): void;
410
+ addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
411
+ removeEventListener(type: 'valueChange', listener: ((this: CedarEmbeddableFieldElement, event: CustomEvent<CedarEmbeddableFieldChangeDetail>) => unknown) | null, options?: boolean | EventListenerOptions): void;
412
+ removeEventListener<K extends keyof HTMLElementEventMap>(type: K, listener: (this: HTMLElement, event: HTMLElementEventMap[K]) => unknown, options?: boolean | EventListenerOptions): void;
413
+ removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
414
+ /**
415
+ * Configuration. Takes one assignment, as the editor's does.
416
+ *
417
+ * The endpoints and the languages are facts about the deployment rather than about
418
+ * the field, and read-only is what this element *is* rather than a state it moves
419
+ * through: a host wanting the other mode creates the other element.
420
+ */
421
+ config: CedarEmbeddableFieldConfig;
422
+ /**
423
+ * The field to render, as a parsed CEDAR field artifact.
424
+ *
425
+ * An artifact, not a model. A host holding a `TemplateField` from the CEDAR Model
426
+ * TypeScript Library — a designer building one is the likely case — writes it out and
427
+ * assigns the result, rather than assigning the object.
428
+ *
429
+ * That is a constraint rather than a preference, and it is worth stating because the
430
+ * object would appear to work. Passing it costs nothing, but the element's copy of the
431
+ * model library is inside this bundle and the host's is inside its own, so the two hold
432
+ * different classes. CEE decides what a field is by identity — `field.cedarFieldType
433
+ * === CedarFieldType.TEXT`, and `instanceof` in three dozen other places — and every
434
+ * one of those comparisons is false for an instance built elsewhere. Nothing throws;
435
+ * the field falls through to a default rendering. A serialization also survives the two
436
+ * packages pinning different library versions, which class shapes do not.
437
+ *
438
+ * Assignable as often as a host likes, and each assignment builds the widget afresh.
439
+ * Set-once protects answers somebody has been typing, and there are none here: the
440
+ * field being designed changes type under its author's hand, and a designer that had
441
+ * to discard and rebuild an element for each change would pay a bootstrap for it.
442
+ *
443
+ * A field declaring its own default value starts out holding it, so a host can hand
444
+ * back what it read and see what it wrote.
445
+ */
446
+ fieldObject: CeeJsonObject;
447
+ /**
448
+ * What the field should hold, replacing whatever it holds now.
449
+ *
450
+ * A value whose kind the field cannot take is reported through the event handler and
451
+ * ignored, rather than being coerced into the nearest thing that would fit. An
452
+ * attribute-value field takes none: its slots are named by the control that creates
453
+ * them. A value assigned before the field is checked when the field arrives.
454
+ * Accepted assignments survive compatible field replacements; incompatible ones
455
+ * are discarded and cannot reappear after a later replacement.
456
+ */
457
+ value: CedarEmbeddableFieldValue;
458
+ /** Host callbacks, which may be replaced: the last one assigned receives. */
459
+ eventHandler: CeeEventHandler;
460
+ /** What the field holds. Read-only. */
461
+ readonly currentValue: CedarEmbeddableFieldValue;
462
+ /** Whether what it holds satisfies the field's constraints. Read-only. */
463
+ readonly currentValueValid: boolean;
464
+ }
319
465
  declare global {
320
466
  interface HTMLElementTagNameMap {
321
467
  'cedar-embeddable-editor': CedarEmbeddableEditorElement;
468
+ 'cedar-embeddable-field': CedarEmbeddableFieldElement;
322
469
  }
323
470
  }