cedar-embeddable-editor 2.0.9 → 2.0.10
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 +41 -0
- package/README.md +78 -0
- package/bundle-manifest.json +2 -2
- package/cedar-embeddable-editor.d.ts +147 -0
- package/cedar-embeddable-editor.js +167 -166
- package/package.json +1 -1
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,24 @@ 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.10] - 2026-09-10
|
|
51
|
+
|
|
52
|
+
This release aligns CEE's build-time model dependency with the public
|
|
53
|
+
`cedar-model-typescript-library@1.0.8` package. The model library remains compiled into CEE's
|
|
54
|
+
browser bundle and is not a runtime dependency for embedding applications.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- The application and visual-test dependency graphs now pin the same public
|
|
59
|
+
`cedar-model-typescript-library@1.0.8` tarball from npmjs.
|
|
60
|
+
|
|
20
61
|
## [2.0.9] - 2026-09-08
|
|
21
62
|
|
|
22
63
|
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
|
package/bundle-manifest.json
CHANGED
|
@@ -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
|
}
|