mount-observer 0.0.45 → 0.0.47

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/MountObserver.js CHANGED
@@ -58,17 +58,21 @@ export class MountObserver extends EventTarget {
58
58
  return this.#calculatedSelector;
59
59
  }
60
60
  async composeFragment(fragment, level) {
61
- const bis = fragment.querySelectorAll(inclTemplQry);
61
+ const bis = fragment.querySelectorAll(`${inclTemplQry},${itemscopeQry}`);
62
62
  for (const bi of bis) {
63
63
  await this.#compose(bi, level);
64
64
  }
65
65
  }
66
66
  async #compose(el, level) {
67
- if (!el.hasAttribute('src')) {
68
- return;
67
+ if (el.hasAttribute('src')) {
68
+ const { compose } = await import('./compose.js');
69
+ await compose(this, el, level);
70
+ }
71
+ const itemscope = el.getAttribute('itemscope');
72
+ if (itemscope && itemscope.includes('-')) {
73
+ const { Newish } = await import('./Newish.js');
74
+ new Newish(el, itemscope, this.#mountInit.assigner);
69
75
  }
70
- const { compose } = await import('./compose.js');
71
- await compose(this, el, level);
72
76
  }
73
77
  #templLookUp = new Map();
74
78
  findByID(id, fragment) {
@@ -393,7 +397,7 @@ export class MountObserver extends EventTarget {
393
397
  return returnSet;
394
398
  }
395
399
  async #filterAndMount(els, checkMatch, initializing) {
396
- const { whereSatisfies, whereInstanceOf } = this.#mountInit;
400
+ const { whereSatisfies, whereInstanceOf, assigner } = this.#mountInit;
397
401
  const match = await this.#selector();
398
402
  const elsToMount = els.filter(x => {
399
403
  if (checkMatch) {
@@ -415,6 +419,12 @@ export class MountObserver extends EventTarget {
415
419
  await this.#compose(elToMount, 0);
416
420
  }
417
421
  }
422
+ for (const el of els) {
423
+ if (el.matches(itemscopeQry)) {
424
+ const { Newish } = await import('./Newish.js');
425
+ new Newish(el, el.getAttribute('itemscope'), assigner);
426
+ }
427
+ }
418
428
  this.#mount(elsToMount, initializing);
419
429
  }
420
430
  async #inspectWithin(within, initializing) {
@@ -425,6 +435,7 @@ export class MountObserver extends EventTarget {
425
435
  }
426
436
  const refCountErr = 'mount-observer ref count mismatch';
427
437
  export const inclTemplQry = 'template[src^="#"]:not([hidden])';
438
+ export const itemscopeQry = '[itemscope*="-"]';
428
439
  // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
429
440
  /**
430
441
  * The `mutation-event` event represents something that happened.
package/MountObserver.ts CHANGED
@@ -69,18 +69,23 @@ export class MountObserver extends EventTarget implements IMountObserver{
69
69
  }
70
70
 
71
71
  async composeFragment(fragment: DocumentFragment, level: number){
72
- const bis = fragment.querySelectorAll(inclTemplQry) as NodeListOf<HTMLTemplateElement>;
72
+ const bis = fragment.querySelectorAll(`${inclTemplQry},${itemscopeQry}`) as NodeListOf<HTMLTemplateElement>;
73
73
  for(const bi of bis){
74
74
  await this.#compose(bi, level);
75
75
  }
76
76
  }
77
77
 
78
+
78
79
  async #compose(el: HTMLTemplateElement, level: number){
79
- if(!el.hasAttribute('src')){
80
- return;
80
+ if(el.hasAttribute('src')){
81
+ const {compose} = await import('./compose.js');
82
+ await compose(this, el, level);
83
+ }
84
+ const itemscope = el.getAttribute('itemscope');
85
+ if(itemscope && itemscope.includes('-')){
86
+ const {Newish} = await import('./Newish.js');
87
+ new Newish(el, itemscope, this.#mountInit.assigner);
81
88
  }
82
- const {compose} = await import('./compose.js');
83
- await compose(this, el, level);
84
89
  }
85
90
  #templLookUp: Map<string, HTMLElement> = new Map();
86
91
  findByID(id: string, fragment: DocumentFragment): HTMLElement | null{
@@ -410,7 +415,7 @@ export class MountObserver extends EventTarget implements IMountObserver{
410
415
  }
411
416
 
412
417
  async #filterAndMount(els: Array<Element>, checkMatch: boolean, initializing: boolean){
413
- const {whereSatisfies, whereInstanceOf} = this.#mountInit;
418
+ const {whereSatisfies, whereInstanceOf, assigner} = this.#mountInit;
414
419
  const match = await this.#selector();
415
420
  const elsToMount = els.filter(x => {
416
421
  if(checkMatch){
@@ -428,6 +433,13 @@ export class MountObserver extends EventTarget implements IMountObserver{
428
433
  if(elToMount.matches(inclTemplQry)){
429
434
  await this.#compose(elToMount as HTMLTemplateElement, 0)
430
435
  }
436
+
437
+ }
438
+ for(const el of els){
439
+ if(el.matches(itemscopeQry)){
440
+ const {Newish} = await import('./Newish.js');
441
+ new Newish(el, el.getAttribute('itemscope')!, assigner);
442
+ }
431
443
  }
432
444
  this.#mount(elsToMount, initializing);
433
445
  }
@@ -444,6 +456,7 @@ export class MountObserver extends EventTarget implements IMountObserver{
444
456
 
445
457
  const refCountErr = 'mount-observer ref count mismatch';
446
458
  export const inclTemplQry = 'template[src^="#"]:not([hidden])';
459
+ export const itemscopeQry = '[itemscope*="-"]';
447
460
  export interface MountObserver extends IMountObserver{}
448
461
 
449
462
  // https://github.com/webcomponents-cg/community-protocols/issues/12#issuecomment-872415080
package/Newish.js ADDED
@@ -0,0 +1,69 @@
1
+ export { waitForEvent } from './waitForEvent.js';
2
+ export class Newish {
3
+ queue = [];
4
+ isResolved = false;
5
+ #ce;
6
+ #assigner = undefined;
7
+ constructor(enhancedElement, itemscope, assigner) {
8
+ this.#assigner = assigner;
9
+ this.#do(enhancedElement, itemscope);
10
+ }
11
+ async #do(enhancedElement, itemscope) {
12
+ //if(Object.hasOwn(enhancedElement, 'host')) return;
13
+ await customElements.whenDefined(itemscope);
14
+ const initPropVals = enhancedElement['ish'];
15
+ //check to make sure it didn't already get attached while waiting
16
+ if (initPropVals === undefined || customElements.getName(initPropVals.constructor) !== itemscope) {
17
+ if (enhancedElement instanceof HTMLElement) {
18
+ if (enhancedElement.dataset.ish) {
19
+ const parsedHostProps = JSON.parse(enhancedElement.dataset.ish);
20
+ this.queue.push(parsedHostProps);
21
+ }
22
+ }
23
+ if (initPropVals !== undefined)
24
+ this.queue.push(initPropVals);
25
+ const ce = document.createElement(itemscope);
26
+ if ('attachedCallback' in ce && typeof ce.attachedCallback === 'function') {
27
+ await ce.attachedCallback(enhancedElement);
28
+ }
29
+ this.#ce = ce;
30
+ const self = this;
31
+ Object.defineProperty(enhancedElement, 'ish', {
32
+ get() {
33
+ return self.#ce;
34
+ },
35
+ set(nv) {
36
+ self.queue.push(nv);
37
+ self.#assignGingerly();
38
+ },
39
+ enumerable: true,
40
+ configurable: true,
41
+ });
42
+ this.#assignGingerly();
43
+ }
44
+ this.isResolved = true;
45
+ enhancedElement.dispatchEvent(new Event('ishAttached'));
46
+ }
47
+ async #assignGingerly() {
48
+ let ce = this.#ce;
49
+ if (ce === undefined) {
50
+ throw 500;
51
+ }
52
+ //const {assignGingerly} = await import('../lib/assignGingerly.js');
53
+ while (this.queue.length > 0) {
54
+ const fi = this.queue.shift();
55
+ //TODO: Provide support for a virtual slice of a very large list
56
+ if (Array.isArray(fi)) {
57
+ ce.$ = fi;
58
+ }
59
+ else {
60
+ if (this.#assigner !== undefined) {
61
+ await this.#assigner(ce, fi);
62
+ }
63
+ else {
64
+ Object.assign(ce, fi);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
package/Newish.ts ADDED
@@ -0,0 +1,73 @@
1
+ export {waitForEvent} from './waitForEvent.js';
2
+ export class Newish{
3
+ queue: Array<any> = [];
4
+ isResolved = false;
5
+ #ce: HTMLElement | undefined;
6
+
7
+ #assigner: undefined | ((target: any, source: any) => Promise<void>) = undefined;
8
+
9
+ constructor(enhancedElement: Element, itemscope: string, assigner?: (target: any, source: any) => Promise<void>){
10
+ this.#assigner = assigner;
11
+ this.#do(enhancedElement, itemscope);
12
+ }
13
+
14
+ async #do(enhancedElement: Element, itemscope: string){
15
+ //if(Object.hasOwn(enhancedElement, 'host')) return;
16
+ await customElements.whenDefined(itemscope);
17
+ const initPropVals = (<any>enhancedElement)['ish'];
18
+ //check to make sure it didn't already get attached while waiting
19
+ if(initPropVals === undefined || customElements.getName(initPropVals.constructor) !== itemscope){
20
+ if(enhancedElement instanceof HTMLElement){
21
+ if(enhancedElement.dataset.ish){
22
+ const parsedHostProps = JSON.parse(enhancedElement.dataset.ish);
23
+ this.queue.push(parsedHostProps);
24
+ }
25
+ }
26
+ if(initPropVals !== undefined) this.queue.push(initPropVals);
27
+ const ce = document.createElement(itemscope);
28
+ if('attachedCallback' in ce && typeof ce.attachedCallback === 'function'){
29
+ await ce.attachedCallback(enhancedElement)
30
+ }
31
+ this.#ce = ce;
32
+ const self = this;
33
+ Object.defineProperty(enhancedElement, 'ish', {
34
+ get(){
35
+ return self.#ce;
36
+ },
37
+ set(nv: any){
38
+ self.queue.push(nv);
39
+ self.#assignGingerly();
40
+ },
41
+ enumerable: true,
42
+ configurable: true,
43
+ });
44
+ this.#assignGingerly();
45
+ }
46
+
47
+ this.isResolved = true;
48
+ enhancedElement.dispatchEvent(new Event('ishAttached'));
49
+ }
50
+
51
+ async #assignGingerly(){
52
+ let ce = this.#ce!;
53
+ if(ce === undefined){
54
+ throw 500;
55
+ }
56
+ //const {assignGingerly} = await import('../lib/assignGingerly.js');
57
+ while(this.queue.length > 0 ){
58
+ const fi = this.queue.shift();
59
+ //TODO: Provide support for a virtual slice of a very large list
60
+ if(Array.isArray(fi)){
61
+ (<any>ce).$ = fi;
62
+ }else{
63
+ if(this.#assigner !== undefined){
64
+ await this.#assigner(ce, fi);
65
+ }else{
66
+ Object.assign(ce, fi);
67
+ }
68
+ }
69
+
70
+ }
71
+ }
72
+
73
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mount-observer",
3
- "version": "0.0.45",
3
+ "version": "0.0.47",
4
4
  "description": "Observe and act on css matches.",
5
5
  "main": "MountObserver.js",
6
6
  "module": "MountObserver.js",
@@ -17,6 +17,10 @@
17
17
  "default": "./MountObserver.js",
18
18
  "types": "./MountObserver.ts"
19
19
  },
20
+ "./Newish.js": {
21
+ "default": "./Newish.js",
22
+ "types": "./Newish.ts"
23
+ },
20
24
  "./Synthesizer.js": {
21
25
  "default": "./Synthesizer.js",
22
26
  "types": "./Synthesizer.ts"
@@ -24,6 +28,14 @@
24
28
  "./compose.js": {
25
29
  "default": "./compose.js",
26
30
  "types": "./compose.ts"
31
+ },
32
+ "./waitForEvent.js": {
33
+ "default": "./waitForEvent.js",
34
+ "types": "./waitForEvent.ts"
35
+ },
36
+ "./waitForIsh.js": {
37
+ "default": "./waitForIsh.js",
38
+ "types": "./waitForIsh.ts"
27
39
  }
28
40
  },
29
41
  "files": [
@@ -0,0 +1,27 @@
1
+ import {IEnhancement, BEAllProps} from '../trans-render/be/types';
2
+ import {StringWithAutocompleteOptions} from '../trans-render/types';
3
+
4
+ export interface EndUserProps extends IEnhancement{
5
+ duration: number,
6
+ attr: StringWithAutocompleteOptions<
7
+ |'value'
8
+ |'textContent'
9
+ |'innerHTML'
10
+ |'shadowRoot'
11
+ >,
12
+ css: string,
13
+ }
14
+
15
+ export interface AllProps extends EndUserProps{}
16
+
17
+ export type AP = AllProps;
18
+
19
+ export type PAP = Partial<AP>;
20
+
21
+ export type ProPAP = Promise<PAP>;
22
+
23
+ export type BAP = AP & BEAllProps;
24
+
25
+ export interface Actions{
26
+ hydrate(self: BAP): ProPAP;
27
+ }
@@ -0,0 +1,26 @@
1
+ import {IEnhancement, BEAllProps} from '../trans-render/be/types';
2
+ import {AllProps as XPAsAllProps} from '../xp-as/types';
3
+
4
+ export interface EndUserProps extends IEnhancement{
5
+ xpAsAttr: string;
6
+ }
7
+
8
+ export interface AllProps extends EndUserProps{
9
+ }
10
+
11
+ export type AP = AllProps;
12
+
13
+ export type PAP = Partial<AP>;
14
+
15
+ export type ProPAP = Promise<PAP>;
16
+
17
+ export type BAP = AP & BEAllProps;
18
+
19
+ export interface Actions {
20
+ hydrate(self: BAP): ProPAP;
21
+ }
22
+
23
+ export interface Factor{
24
+ NameOfProp: string,
25
+ xpAs: XPAsAllProps,
26
+ }
@@ -46,8 +46,16 @@ export interface ObservingParameters{
46
46
  punt: boolean,
47
47
  mappings?: Array<AndIfThen>,
48
48
  aggKey: StringWithAutocompleteOptions<aggKeys>,
49
+ interpolatingExpr: string,
49
50
  JSExpr: string,
50
51
  ONExpr: string,
52
+ action:
53
+ | 'set'
54
+ | 'toggle'
55
+ | 'increment'
56
+ | 'decrement'
57
+ | 'set-class'
58
+ | 'set-part'
51
59
  //aggregateRemoteVals?: 'Union' | 'Conjunction' | 'ObjectAssign' | 'Sum' | 'Product' | 'ArrayPush'
52
60
  }
53
61
 
@@ -24,7 +24,8 @@ export interface MountInit extends JSONSerializableMountInit{
24
24
  readonly withTargetShadowRoot?: ShadowRoot,
25
25
  readonly whereInstanceOf?: Array<{new(): Element}>,
26
26
  readonly whereSatisfies?: PipelineProcessor<boolean>,
27
- readonly do?: MountObserverCallbacks
27
+ readonly do?: MountObserverCallbacks,
28
+ readonly assigner?: (target: any, source: any) => Promise<void>,
28
29
  // /**
29
30
  // * Purpose -- there are scenarios where we may only want to affect changes that occur after the initial
30
31
  // * server rendering, so we only want to mount elements that appear
@@ -72,6 +72,14 @@ export interface ASMROptions<TProp = any>{
72
72
  export interface SetOptions<TProp = any> extends ASMROptions<TProp>{
73
73
  valToDisplay?: (v: TProp) => string;
74
74
  allowUnsafe?: boolean;
75
+ action?:
76
+ |'set'
77
+ |'toggle'
78
+ |'increment'
79
+ |'decrement'
80
+ |'set-class'
81
+ |'set-part'
82
+ ;
75
83
  }
76
84
 
77
85
  export interface AbsOptions<TProp = any> {
@@ -25,6 +25,10 @@ export type DirectionalScopeSigils =
25
25
  * modulo
26
26
  */
27
27
  |'%'
28
+ /**
29
+ * itemscoped host
30
+ */
31
+ |'$'
28
32
  ;
29
33
 
30
34
  export type AttrSigils =
@@ -51,6 +55,16 @@ export type asOptions =
51
55
  | 'boolean|number'
52
56
  ;
53
57
 
58
+ export interface $copeDetail{
59
+ ceName?: string,
60
+ itemProp?: string,
61
+ }
62
+
63
+ export interface $ScopeHierarchy {
64
+ home: Element;
65
+ satellites?: Array<Element>;
66
+ }
67
+
54
68
  export interface Specifier {
55
69
  /** Directional Scope Sigil */
56
70
  dss?: DirectionalScopeSigils,
@@ -106,9 +120,21 @@ export interface Specifier {
106
120
 
107
121
  as?: asOptions
108
122
 
109
-
123
+ /**
124
+ * is a scope query within the aria-[row|col|row]index[text]
125
+ */
110
126
  isModulo?: boolean;
127
+ /**
128
+ * Specify which aria-[?]index to use
129
+ */
111
130
  modulo?: Modulo;
131
+
132
+ /**
133
+ * itemscope hierarchy domain specifier
134
+ */
135
+ is$cope?: boolean;
136
+
137
+ $copeDetail?: $copeDetail
112
138
  }
113
139
 
114
140
  export type Modulo = 'aria-rowindex' | 'aria-colindex' | 'aria-rowindextext'
@@ -126,7 +152,7 @@ export type CSSSelector = string;
126
152
 
127
153
  /**
128
154
  * starts with a dash, typically all kebab case
129
- * inferrered prop name will be camel cased based on this.
155
+ * inferred prop name will be camel cased based on this.
130
156
  */
131
157
  export type MarkerString = string;
132
158
 
@@ -156,4 +182,8 @@ export interface PIP<TProp = any, TElement = Element> extends EventListenerObjec
156
182
  disconnect();
157
183
  toString(nv: TProp): string;
158
184
  readonly outEvtName: string;
185
+ }
186
+
187
+ export interface HasIshList extends HTMLElement{
188
+ ishList: Array<any>;
159
189
  }
@@ -319,7 +319,7 @@ export interface PropInfo{
319
319
  ip?: boolean;
320
320
  }
321
321
 
322
- export type ConstString = String;
322
+ export type ConstString = string;
323
323
 
324
324
  export type NameOfProp = string;
325
325
 
@@ -0,0 +1,20 @@
1
+ import {IEnhancement, BEAllProps} from '../trans-render/be/types';
2
+
3
+ export interface EndUserProps extends IEnhancement{
4
+ }
5
+
6
+ export interface AllProps extends EndUserProps{
7
+ props: EventTarget;
8
+ }
9
+
10
+ export type AP = AllProps;
11
+
12
+ export type PAP = Partial<AP>;
13
+
14
+ export type ProPAP = Promise<PAP>;
15
+
16
+ export type BAP = AP & BEAllProps;
17
+
18
+ export interface Actions {
19
+
20
+ }
@@ -0,0 +1,12 @@
1
+ export function waitForEvent(et, eventName, failureEventName) {
2
+ return new Promise((resolved, rejected) => {
3
+ et.addEventListener(eventName, e => {
4
+ resolved(e);
5
+ }, { once: true });
6
+ if (failureEventName !== undefined) {
7
+ et.addEventListener(failureEventName, e => {
8
+ rejected(e);
9
+ }, { once: true });
10
+ }
11
+ });
12
+ }
@@ -0,0 +1,13 @@
1
+ export function waitForEvent<TEvent extends Event = Event>(et: EventTarget, eventName: string, failureEventName?: string): Promise<TEvent>{
2
+ return new Promise((resolved, rejected) => {
3
+ et.addEventListener(eventName, e => {
4
+ resolved(e as TEvent);
5
+ }, {once: true});
6
+ if(failureEventName !== undefined){
7
+ et.addEventListener(failureEventName, e => {
8
+ rejected(e as TEvent);
9
+ }, {once: true});
10
+ }
11
+
12
+ });
13
+ }
package/waitForIsh.js ADDED
@@ -0,0 +1,20 @@
1
+ export function waitForIsh(el) {
2
+ return new Promise((resolve, reject) => {
3
+ const ish = el['ish'];
4
+ if (ish) {
5
+ resolve(ish);
6
+ }
7
+ else {
8
+ // If the element is not yet defined, wait for it to be defined
9
+ el.addEventListener('ishAttached', () => {
10
+ const ish = el['ish'];
11
+ if (ish) {
12
+ resolve(ish);
13
+ }
14
+ else {
15
+ reject(new Error('ish not found'));
16
+ }
17
+ }, { once: true });
18
+ }
19
+ });
20
+ }
package/waitForIsh.ts ADDED
@@ -0,0 +1,19 @@
1
+ export function waitForIsh(el: Element){
2
+ return new Promise((resolve, reject) => {
3
+ const ish = (<any>el)['ish'];
4
+ if (ish) {
5
+ resolve(ish);
6
+ } else {
7
+ // If the element is not yet defined, wait for it to be defined
8
+ el.addEventListener('ishAttached', () => {
9
+ const ish = (<any>el)['ish'];
10
+ if (ish) {
11
+ resolve(ish);
12
+ } else {
13
+ reject(new Error('ish not found'));
14
+ }
15
+ }, { once: true });
16
+
17
+ }
18
+ });
19
+ }