assign-gingerly 0.0.92 → 0.0.93

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.
@@ -89,6 +89,16 @@ export class Infer {
89
89
  get valueProperty() {
90
90
  return inferValueProperty(this.enhancedElement);
91
91
  }
92
+ /**
93
+ * The effective language for this element, honoring `lang` / `xml:lang`
94
+ * inheritance up through ancestors and shadow-root hosts, then
95
+ * `<html lang>` and finally `navigator.language`.
96
+ * @returns a BCP-47 tag, or undefined if nothing is resolvable
97
+ */
98
+ get lang() {
99
+ const el = this.#weakRef.deref();
100
+ return el === undefined ? undefined : resolveLang(el);
101
+ }
92
102
  ['|'](itempropAttr, scopeBoundary = '[itemscope]') {
93
103
  return this.#queryScoped(`[itemprop="${itempropAttr}"]`, itempropAttr, scopeBoundary);
94
104
  }
@@ -244,6 +254,39 @@ export function serializeForProperty(propName, nv) {
244
254
  return JSON.stringify(nv);
245
255
  return nv;
246
256
  }
257
+ /**
258
+ * Resolve the effective language ("computed lang") for an element.
259
+ *
260
+ * There is no DOM accessor for this, so we walk: nearest ancestor element with a
261
+ * `lang` / `xml:lang` attribute, crossing shadow-root boundaries via the host
262
+ * (matching how `:lang()` behaves in modern browsers), then `<html lang>`, then
263
+ * `navigator.language`. Slot reprojection is intentionally not followed — HTML
264
+ * language inheritance is defined over the real node tree, not the flat tree.
265
+ *
266
+ * @returns a BCP-47 tag, or undefined if nothing is resolvable
267
+ */
268
+ export function resolveLang(element) {
269
+ let node = element;
270
+ while (node != null) {
271
+ if (node.nodeType === 1 /* ELEMENT_NODE */) {
272
+ const el = node;
273
+ const lang = el.getAttribute('lang') || el.getAttribute('xml:lang');
274
+ if (lang)
275
+ return lang;
276
+ node = node.parentNode;
277
+ }
278
+ else if (node.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE, incl. ShadowRoot */) {
279
+ node = node.host ?? null;
280
+ }
281
+ else {
282
+ node = null; // Document (9) or detached — stop
283
+ }
284
+ }
285
+ if (typeof document !== 'undefined' && document.documentElement.lang) {
286
+ return document.documentElement.lang;
287
+ }
288
+ return (typeof navigator !== 'undefined' && navigator.language) || undefined;
289
+ }
247
290
  /**
248
291
  * Infer the most appropriate display property for an element
249
292
  * @param element - The element to infer the property for
@@ -110,6 +110,17 @@ export class Infer<TValue = any, TDisplay = any> {
110
110
  return inferValueProperty(this.enhancedElement);
111
111
  }
112
112
 
113
+ /**
114
+ * The effective language for this element, honoring `lang` / `xml:lang`
115
+ * inheritance up through ancestors and shadow-root hosts, then
116
+ * `<html lang>` and finally `navigator.language`.
117
+ * @returns a BCP-47 tag, or undefined if nothing is resolvable
118
+ */
119
+ get lang(): string | undefined {
120
+ const el = this.#weakRef.deref();
121
+ return el === undefined ? undefined : resolveLang(el);
122
+ }
123
+
113
124
  ['|'](itempropAttr: string, scopeBoundary: string = '[itemscope]'){
114
125
  return this.#queryScoped(`[itemprop="${itempropAttr}"]`, itempropAttr, scopeBoundary);
115
126
  }
@@ -277,6 +288,37 @@ export function serializeForProperty(propName: string, nv: any): any {
277
288
  return nv;
278
289
  }
279
290
 
291
+ /**
292
+ * Resolve the effective language ("computed lang") for an element.
293
+ *
294
+ * There is no DOM accessor for this, so we walk: nearest ancestor element with a
295
+ * `lang` / `xml:lang` attribute, crossing shadow-root boundaries via the host
296
+ * (matching how `:lang()` behaves in modern browsers), then `<html lang>`, then
297
+ * `navigator.language`. Slot reprojection is intentionally not followed — HTML
298
+ * language inheritance is defined over the real node tree, not the flat tree.
299
+ *
300
+ * @returns a BCP-47 tag, or undefined if nothing is resolvable
301
+ */
302
+ export function resolveLang(element: Element): string | undefined {
303
+ let node: Node | null = element;
304
+ while (node != null) {
305
+ if (node.nodeType === 1 /* ELEMENT_NODE */) {
306
+ const el = node as Element;
307
+ const lang = el.getAttribute('lang') || el.getAttribute('xml:lang');
308
+ if (lang) return lang;
309
+ node = node.parentNode;
310
+ } else if (node.nodeType === 11 /* DOCUMENT_FRAGMENT_NODE, incl. ShadowRoot */) {
311
+ node = (node as ShadowRoot).host ?? null;
312
+ } else {
313
+ node = null; // Document (9) or detached — stop
314
+ }
315
+ }
316
+ if (typeof document !== 'undefined' && document.documentElement.lang) {
317
+ return document.documentElement.lang;
318
+ }
319
+ return (typeof navigator !== 'undefined' && navigator.language) || undefined;
320
+ }
321
+
280
322
  /**
281
323
  * Infer the most appropriate display property for an element
282
324
  * @param element - The element to infer the property for
@@ -15,14 +15,32 @@ export declare const display: symbol;
15
15
  */
16
16
  export declare class Infer<TValue = any, TDisplay = any> {
17
17
  get enhancedElement(): Element;
18
- constructor(enhancedElement?: Element);
18
+ constructor(enhancedElement?: Element, propName?: string);
19
+ /** Live, type-coerced read of the element's inferred value property. */
19
20
  get value(): TValue | undefined;
20
21
  set value(nv: TValue);
21
22
  get display(): TDisplay | undefined;
22
23
  set display(nv: TDisplay);
23
24
  get eventType(): string;
25
+ /** The inferred value property name (e.g. 'value', 'checked', 'dateTime'). */
26
+ get valueProperty(): string;
27
+ get defaultRemoteBindingPropName(): string;
28
+ /**
29
+ * EventTarget that emits an event named after the changed property.
30
+ * Custom elements with a native propagator return that; otherwise an
31
+ * InferencedPropagator using best-effort change detection.
32
+ */
33
+ getPropagator(): Promise<EventTarget>;
34
+ setDisplay(vm: any): void;
24
35
  }
25
36
 
37
+ /**
38
+ * Read the inferred value property off an element and coerce it to a natural
39
+ * JavaScript type (Date for <time>, number/boolean via JSON parse for <data>,
40
+ * schema.org itemtype hints honored, textContent verbatim).
41
+ */
42
+ export declare function coerceElementValue(element: Element, propName?: string): any;
43
+
26
44
  /**
27
45
  * Registry item for the Infer enhancement
28
46
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "assign-gingerly",
3
- "version": "0.0.92",
3
+ "version": "0.0.93",
4
4
  "description": "This package provides a utility function for carefully merging one object into another.",
5
5
  "homepage": "https://github.com/bahrus/assign-gingerly#readme",
6
6
  "bugs": {