@joist/element 4.0.0-next.4 → 4.0.0-next.6
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/README.md +2 -2
- package/package.json +4 -3
- package/src/lib/attr.test.ts +107 -98
- package/src/lib/attr.ts +2 -2
- package/src/lib/element.test.ts +84 -80
- package/src/lib/element.ts +5 -13
- package/src/lib/lifecycle.test.ts +31 -0
- package/src/lib/lifecycle.ts +9 -0
- package/src/lib/listen.ts +1 -1
- package/src/lib/metadata.ts +1 -0
- package/src/lib/query.test.ts +43 -44
- package/src/lib/query.ts +1 -1
- package/src/lib/result.ts +2 -22
- package/src/lib/tags.ts +28 -13
- package/src/lib/template.test.ts +65 -0
- package/src/lib/template.ts +132 -0
- package/src/lib.ts +3 -2
- package/target/lib/attr.d.ts +1 -1
- package/target/lib/attr.js +1 -1
- package/target/lib/attr.js.map +1 -1
- package/target/lib/attr.test.js +258 -252
- package/target/lib/attr.test.js.map +1 -1
- package/target/lib/element.d.ts +2 -5
- package/target/lib/element.js +3 -9
- package/target/lib/element.js.map +1 -1
- package/target/lib/element.test.js +181 -179
- package/target/lib/element.test.js.map +1 -1
- package/target/lib/lifecycle.d.ts +1 -0
- package/target/lib/lifecycle.js +8 -0
- package/target/lib/lifecycle.js.map +1 -0
- package/target/lib/lifecycle.test.d.ts +1 -0
- package/target/lib/lifecycle.test.js +48 -0
- package/target/lib/lifecycle.test.js.map +1 -0
- package/target/lib/listen.d.ts +1 -1
- package/target/lib/listen.js.map +1 -1
- package/target/lib/metadata.d.ts +1 -0
- package/target/lib/metadata.js +1 -0
- package/target/lib/metadata.js.map +1 -1
- package/target/lib/query.d.ts +1 -1
- package/target/lib/query.test.js +72 -74
- package/target/lib/query.test.js.map +1 -1
- package/target/lib/result.d.ts +2 -9
- package/target/lib/result.js +1 -14
- package/target/lib/result.js.map +1 -1
- package/target/lib/tags.d.ts +11 -7
- package/target/lib/tags.js +20 -11
- package/target/lib/tags.js.map +1 -1
- package/target/lib/template.d.ts +6 -0
- package/target/lib/template.js +91 -0
- package/target/lib/template.js.map +1 -0
- package/target/lib/template.test.d.ts +1 -0
- package/target/lib/template.test.js +47 -0
- package/target/lib/template.test.js.map +1 -0
- package/target/lib.d.ts +3 -2
- package/target/lib.js +3 -2
- package/target/lib.js.map +1 -1
package/src/lib/query.test.ts
CHANGED
|
@@ -1,54 +1,53 @@
|
|
|
1
|
-
import { expect } from '
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
|
|
2
3
|
import { element } from './element.js';
|
|
3
4
|
import { query } from './query.js';
|
|
4
5
|
import { html } from './tags.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
7
|
+
it('should work', () => {
|
|
8
|
+
@element({
|
|
9
|
+
tagName: 'query-test-1',
|
|
10
|
+
shadow: [
|
|
11
|
+
html`
|
|
12
|
+
<form>
|
|
13
|
+
<input id="fname" name="fname" />
|
|
14
|
+
<input id="lname" name="lname" />
|
|
15
|
+
</form>
|
|
16
|
+
`
|
|
17
|
+
]
|
|
18
|
+
})
|
|
19
|
+
class MyElement extends HTMLElement {
|
|
20
|
+
fname = query<HTMLInputElement>('#fname');
|
|
21
|
+
lname = query<HTMLInputElement>('#lname');
|
|
22
|
+
}
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const el = new MyElement();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
expect(el.fname()).to.equal(el.shadowRoot?.querySelector('#fname'));
|
|
27
|
+
expect(el.lname()).to.equal(el.shadowRoot?.querySelector('#lname'));
|
|
28
|
+
});
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
it('should patch the selected item', () => {
|
|
31
|
+
@element({
|
|
32
|
+
tagName: 'query-test-2',
|
|
33
|
+
shadow: [
|
|
34
|
+
html`
|
|
35
|
+
<form>
|
|
36
|
+
<input id="fname" name="fname" />
|
|
37
|
+
<input id="lname" name="lname" />
|
|
38
|
+
</form>
|
|
39
|
+
`
|
|
40
|
+
]
|
|
41
|
+
})
|
|
42
|
+
class MyElement extends HTMLElement {
|
|
43
|
+
fname = query<HTMLInputElement>('#fname');
|
|
44
|
+
lname = query<HTMLInputElement>('#lname');
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
const el = new MyElement();
|
|
48
|
+
el.fname({ value: 'Foo' });
|
|
49
|
+
el.lname({ value: 'Bar' });
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
});
|
|
51
|
+
expect(el.shadowRoot?.querySelector<HTMLInputElement>('#fname')?.value).to.equal('Foo');
|
|
52
|
+
expect(el.shadowRoot?.querySelector<HTMLInputElement>('#lname')?.value).to.equal('Bar');
|
|
54
53
|
});
|
package/src/lib/query.ts
CHANGED
|
@@ -7,7 +7,7 @@ type QueryResult<T> = (updates?: Partial<T>) => T;
|
|
|
7
7
|
export function query<K extends Tags>(selectors: K): QueryResult<HTMLElementTagNameMap[K]>;
|
|
8
8
|
export function query<K extends SVGTags>(selectors: K): QueryResult<SVGElementTagNameMap[K]>;
|
|
9
9
|
export function query<K extends MathTags>(selectors: K): QueryResult<MathMLElementTagNameMap[K]>;
|
|
10
|
-
export function query<E extends
|
|
10
|
+
export function query<E extends HTMLElement = HTMLElement>(selectors: string): QueryResult<E>;
|
|
11
11
|
export function query<K extends Tags>(query: K): QueryResult<HTMLElementTagNameMap[K]> {
|
|
12
12
|
let res: HTMLElementTagNameMap[K] | null = null;
|
|
13
13
|
|
package/src/lib/result.ts
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
export interface ShadowResult {
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export abstract class JoistShadowResult implements ShadowResult {
|
|
6
|
-
strings;
|
|
7
|
-
values;
|
|
8
|
-
|
|
9
|
-
constructor(raw: TemplateStringsArray, ...values: any[]) {
|
|
10
|
-
this.strings = raw;
|
|
11
|
-
this.values = values;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
run(el: HTMLElement) {
|
|
15
|
-
if (!el.shadowRoot) {
|
|
16
|
-
throw new Error('ShadowResult has not been applied');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
this.setup(el.shadowRoot);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
abstract setup(root: ShadowRoot): void;
|
|
1
|
+
export interface ShadowResult<T extends HTMLElement> {
|
|
2
|
+
apply(el: T): void;
|
|
23
3
|
}
|
package/src/lib/tags.ts
CHANGED
|
@@ -1,28 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ShadowResult } from './result.js';
|
|
2
2
|
|
|
3
|
-
export class HTMLResult extends
|
|
4
|
-
|
|
5
|
-
let template = document.createElement('template');
|
|
6
|
-
template.innerHTML = concat(this.strings);
|
|
3
|
+
export class HTMLResult<T extends HTMLElement> implements ShadowResult<T> {
|
|
4
|
+
#template;
|
|
7
5
|
|
|
8
|
-
|
|
6
|
+
constructor(raw: TemplateStringsArray, ..._values: any[]) {
|
|
7
|
+
this.#template = document.createElement('template');
|
|
8
|
+
this.#template.innerHTML = concat(raw);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
apply(el: T): void {
|
|
12
|
+
if (el.shadowRoot) {
|
|
13
|
+
el.shadowRoot.append(this.#template.content.cloneNode(true));
|
|
14
|
+
}
|
|
9
15
|
}
|
|
10
16
|
}
|
|
11
17
|
|
|
12
|
-
export function html
|
|
18
|
+
export function html<T extends HTMLElement>(
|
|
19
|
+
strings: TemplateStringsArray,
|
|
20
|
+
...values: any[]
|
|
21
|
+
): HTMLResult<T> {
|
|
13
22
|
return new HTMLResult(strings, ...values);
|
|
14
23
|
}
|
|
15
24
|
|
|
16
|
-
export class CSSResult extends
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
export class CSSResult<T extends HTMLElement> implements ShadowResult<T> {
|
|
26
|
+
#sheet;
|
|
27
|
+
|
|
28
|
+
constructor(raw: TemplateStringsArray, ..._values: any[]) {
|
|
29
|
+
this.#sheet = new CSSStyleSheet();
|
|
30
|
+
this.#sheet.replaceSync(concat(raw));
|
|
31
|
+
}
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
apply(el: HTMLElement): void {
|
|
34
|
+
if (el.shadowRoot) {
|
|
35
|
+
el.shadowRoot.adoptedStyleSheets = [...el.shadowRoot.adoptedStyleSheets, this.#sheet];
|
|
36
|
+
}
|
|
22
37
|
}
|
|
23
38
|
}
|
|
24
39
|
|
|
25
|
-
export function css(strings: TemplateStringsArray): CSSResult {
|
|
40
|
+
export function css<T extends HTMLElement>(strings: TemplateStringsArray): CSSResult<T> {
|
|
26
41
|
return new CSSResult(strings);
|
|
27
42
|
}
|
|
28
43
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { assert } from 'chai';
|
|
2
|
+
|
|
3
|
+
import { template } from './template.js';
|
|
4
|
+
|
|
5
|
+
// Run all tests with both shadow and light dom
|
|
6
|
+
const TESTS = [
|
|
7
|
+
function comments(el: HTMLElement, root: HTMLElement | ShadowRoot) {
|
|
8
|
+
it(`should intialize template comments ${root instanceof ShadowRoot ? '(ShadowDOM)' : '(LightDOM)'}`, () => {
|
|
9
|
+
el.title = 'Hello World';
|
|
10
|
+
el.ariaLabel = 'This is the label';
|
|
11
|
+
el.ariaDescription = 'This is the description';
|
|
12
|
+
|
|
13
|
+
root.innerHTML = /*html*/ `
|
|
14
|
+
<!--#:title-->
|
|
15
|
+
|
|
16
|
+
<ul>
|
|
17
|
+
<li><!--#:ariaLabel--></li>
|
|
18
|
+
<li><!--#:ariaDescription--></li>
|
|
19
|
+
</ul>
|
|
20
|
+
`;
|
|
21
|
+
|
|
22
|
+
const render = template();
|
|
23
|
+
|
|
24
|
+
render.call(el);
|
|
25
|
+
|
|
26
|
+
assert.equal(
|
|
27
|
+
root.innerHTML
|
|
28
|
+
.split('\n')
|
|
29
|
+
.map((res) => res.trim())
|
|
30
|
+
.join(''),
|
|
31
|
+
'Hello World<ul><li>This is the label</li><li>This is the description</li></ul>'
|
|
32
|
+
);
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
function attributes(el: HTMLElement, root: HTMLElement | ShadowRoot) {
|
|
36
|
+
it(`should intialize template attributes ${root instanceof ShadowRoot ? '(ShadowDOM)' : '(LightDOM)'}`, () => {
|
|
37
|
+
el.ariaLabel = 'This is the label';
|
|
38
|
+
el.ariaDescription = 'This is the description';
|
|
39
|
+
|
|
40
|
+
root.innerHTML = /*html*/ `
|
|
41
|
+
<ul aria-label="#:ariaLabel" aria-description="#:ariaDescription"></ul>
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const render = template();
|
|
45
|
+
|
|
46
|
+
render.call(el);
|
|
47
|
+
|
|
48
|
+
assert.equal(
|
|
49
|
+
root.innerHTML
|
|
50
|
+
.split('\n')
|
|
51
|
+
.map((res) => res.trim())
|
|
52
|
+
.join(''),
|
|
53
|
+
'<ul aria-label="This is the label" aria-description="This is the description"></ul>'
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
for (let test of TESTS) {
|
|
60
|
+
const lightEl = document.createElement('div');
|
|
61
|
+
test(lightEl, lightEl);
|
|
62
|
+
|
|
63
|
+
const shadowEl = document.createElement('div');
|
|
64
|
+
test(shadowEl, shadowEl.attachShadow({ mode: 'open' }));
|
|
65
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const TOKEN_PREFIX = '#:';
|
|
2
|
+
|
|
3
|
+
class NodeMap extends Map<Node, string> {}
|
|
4
|
+
|
|
5
|
+
export interface TemplateOpts {}
|
|
6
|
+
|
|
7
|
+
export interface RenderOpts {
|
|
8
|
+
refresh?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function template(_templateOpts?: TemplateOpts) {
|
|
12
|
+
// make sure we only initialize once
|
|
13
|
+
let initialized = false;
|
|
14
|
+
|
|
15
|
+
// Track all nodes that can be updated and their associated property
|
|
16
|
+
const nodes = new NodeMap();
|
|
17
|
+
|
|
18
|
+
return function render<T extends HTMLElement>(this: T, renderOpts?: RenderOpts) {
|
|
19
|
+
if (renderOpts?.refresh) {
|
|
20
|
+
initialized = false;
|
|
21
|
+
nodes.clear();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (initialized) {
|
|
25
|
+
return updateNodes(this, nodes);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// find and track nodes
|
|
29
|
+
initializeNodes(this, nodes);
|
|
30
|
+
|
|
31
|
+
initialized = true;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function initializeNodes(el: HTMLElement, nodes: NodeMap) {
|
|
36
|
+
const iterator = document.createTreeWalker(
|
|
37
|
+
el.shadowRoot || el,
|
|
38
|
+
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
while (iterator.nextNode()) {
|
|
42
|
+
const res = trackNode(el, iterator.currentNode, nodes);
|
|
43
|
+
|
|
44
|
+
if (res !== null) {
|
|
45
|
+
iterator.currentNode = res;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function updateNodes(el: HTMLElement, nodes: NodeMap) {
|
|
51
|
+
for (let [node, prop] of nodes) {
|
|
52
|
+
const value = Reflect.get(el, prop);
|
|
53
|
+
|
|
54
|
+
const isAttribute = node.nodeType === Node.ATTRIBUTE_NODE;
|
|
55
|
+
|
|
56
|
+
if (isAttribute && isBooleanAttributeNode(node as Attr)) {
|
|
57
|
+
manageBooleanAttribute(el, node as Attr);
|
|
58
|
+
} else if (value !== node.nodeValue) {
|
|
59
|
+
node.nodeValue = value;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* configures and tracks a given Node so that it can be updated in place later.
|
|
66
|
+
*/
|
|
67
|
+
function trackNode(el: HTMLElement, node: Node, nodes: NodeMap): Node | null {
|
|
68
|
+
switch (node.nodeType) {
|
|
69
|
+
case Node.COMMENT_NODE: {
|
|
70
|
+
const nodeValue = node.nodeValue?.trim();
|
|
71
|
+
|
|
72
|
+
if (nodeValue?.startsWith(TOKEN_PREFIX)) {
|
|
73
|
+
if (node.parentNode) {
|
|
74
|
+
const propertyKey = nodeValue.replace(TOKEN_PREFIX, '');
|
|
75
|
+
const textNode = document.createTextNode(Reflect.get(el, propertyKey));
|
|
76
|
+
|
|
77
|
+
node.parentNode.replaceChild(textNode, node);
|
|
78
|
+
|
|
79
|
+
nodes.set(textNode, propertyKey);
|
|
80
|
+
|
|
81
|
+
return textNode;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
case Node.ELEMENT_NODE: {
|
|
89
|
+
const element = node as Element;
|
|
90
|
+
|
|
91
|
+
for (let attr of element.attributes) {
|
|
92
|
+
const nodeValue = attr.value.trim();
|
|
93
|
+
|
|
94
|
+
if (isBooleanAttributeNode(attr)) {
|
|
95
|
+
manageBooleanAttribute(el, attr);
|
|
96
|
+
|
|
97
|
+
nodes.set(attr, attr.value);
|
|
98
|
+
} else if (nodeValue.startsWith(TOKEN_PREFIX)) {
|
|
99
|
+
const propertyKey = nodeValue.replace(TOKEN_PREFIX, '');
|
|
100
|
+
|
|
101
|
+
attr.value = Reflect.get(el, propertyKey);
|
|
102
|
+
|
|
103
|
+
nodes.set(attr, propertyKey);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function isBooleanAttributeNode(attr: Attr) {
|
|
115
|
+
return attr.name.startsWith(TOKEN_PREFIX);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function manageBooleanAttribute(el: HTMLElement, attr: Attr) {
|
|
119
|
+
const realAttributeName = attr.name.replace(TOKEN_PREFIX, '');
|
|
120
|
+
|
|
121
|
+
if (attr.ownerElement) {
|
|
122
|
+
let value = attr.value.startsWith('!')
|
|
123
|
+
? !Reflect.get(el, attr.value.replace('!', ''))
|
|
124
|
+
: Reflect.get(el, attr.value);
|
|
125
|
+
|
|
126
|
+
if (value) {
|
|
127
|
+
attr.ownerElement.setAttribute(realAttributeName, '');
|
|
128
|
+
} else {
|
|
129
|
+
attr.ownerElement.removeAttribute(realAttributeName);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
package/src/lib.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { JoistShadowResult as TemplateResult } from './lib/result.js';
|
|
2
1
|
export { css, html, HTMLResult, CSSResult } from './lib/tags.js';
|
|
3
2
|
export { attr } from './lib/attr.js';
|
|
4
3
|
export { listen } from './lib/listen.js';
|
|
5
|
-
export { element
|
|
4
|
+
export { element } from './lib/element.js';
|
|
6
5
|
export { query } from './lib/query.js';
|
|
6
|
+
export { template } from './lib/template.js';
|
|
7
|
+
export { ready } from './lib/lifecycle.js';
|
package/target/lib/attr.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export interface AttrOpts {
|
|
2
|
-
|
|
2
|
+
observed?: boolean;
|
|
3
3
|
}
|
|
4
4
|
export declare function attr(opts?: AttrOpts): <This extends HTMLElement>({ get, set }: ClassAccessorDecoratorTarget<This, unknown>, ctx: ClassAccessorDecoratorContext<This>) => ClassAccessorDecoratorResult<This, any>;
|
package/target/lib/attr.js
CHANGED
package/target/lib/attr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attr.js","sourceRoot":"","sources":["../../src/lib/attr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM9C,MAAM,UAAU,IAAI,CAAC,IAAe;IAClC,OAAO,SAAS,aAAa,CAC3B,EAAE,GAAG,EAAE,GAAG,EAA+C,EACzD,GAAwC;QAExC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE9C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACd,QAAQ,EAAE,GAAG,CAAC,IAAI;YAClB,QAAQ;YACR,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"attr.js","sourceRoot":"","sources":["../../src/lib/attr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM9C,MAAM,UAAU,IAAI,CAAC,IAAe;IAClC,OAAO,SAAS,aAAa,CAC3B,EAAE,GAAG,EAAE,GAAG,EAA+C,EACzD,GAAwC;QAExC,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAE9C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACd,QAAQ,EAAE,GAAG,CAAC,IAAI;YAClB,QAAQ;YACR,OAAO,EAAE,IAAI,EAAE,QAAQ,IAAI,IAAI;SAChC,CAAC,CAAC;QAEH,OAAO;YACL,GAAG,CAAC,KAAc;gBAChB,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBACnB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBAClC,CAAC;qBAAM,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;oBAC3B,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;gBACjC,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC7C,CAAC;gBAED,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACxB,CAAC;YACD,GAAG;gBACD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;gBAEzC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAElB,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;wBAChB,OAAO,IAAI,CAAC;oBACd,CAAC;oBAGD,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;wBAChC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;oBACtB,CAAC;oBAGD,OAAO,IAAI,CAAC;gBACd,CAAC;gBAGD,OAAO,OAAO,CAAC;YACjB,CAAC;SACF,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAoB;IACzC,IAAI,KAAa,CAAC;IAElB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;YACpB,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,GAAG,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC"}
|