@dooboostore/simple-web-component 1.0.22 → 1.0.23

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.
Files changed (71) hide show
  1. package/README.md +361 -19
  2. package/dist/cjs/decorators/applyNode.js +98 -24
  3. package/dist/cjs/decorators/applyNode.js.map +2 -2
  4. package/dist/cjs/decorators/attribute.js +0 -1
  5. package/dist/cjs/decorators/attribute.js.map +2 -2
  6. package/dist/cjs/decorators/classList.js +39 -19
  7. package/dist/cjs/decorators/classList.js.map +2 -2
  8. package/dist/cjs/decorators/elementDefine.js +1 -2
  9. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  10. package/dist/cjs/decorators/index.js +0 -1
  11. package/dist/cjs/decorators/index.js.map +2 -2
  12. package/dist/cjs/decorators/lifecycles.js +25 -0
  13. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  14. package/dist/cjs/decorators/query.js.map +2 -2
  15. package/dist/cjs/decorators/style.js +39 -13
  16. package/dist/cjs/decorators/style.js.map +2 -2
  17. package/dist/cjs/utils/TemplateUtils.js +6 -0
  18. package/dist/cjs/utils/TemplateUtils.js.map +2 -2
  19. package/dist/esm/decorators/applyNode.js +98 -24
  20. package/dist/esm/decorators/applyNode.js.map +2 -2
  21. package/dist/esm/decorators/attribute.js +0 -1
  22. package/dist/esm/decorators/attribute.js.map +2 -2
  23. package/dist/esm/decorators/classList.js +39 -19
  24. package/dist/esm/decorators/classList.js.map +2 -2
  25. package/dist/esm/decorators/elementDefine.js +1 -2
  26. package/dist/esm/decorators/elementDefine.js.map +2 -2
  27. package/dist/esm/decorators/index.js +0 -1
  28. package/dist/esm/decorators/index.js.map +2 -2
  29. package/dist/esm/decorators/lifecycles.js +25 -0
  30. package/dist/esm/decorators/lifecycles.js.map +2 -2
  31. package/dist/esm/decorators/query.js.map +2 -2
  32. package/dist/esm/decorators/style.js +39 -13
  33. package/dist/esm/decorators/style.js.map +2 -2
  34. package/dist/esm/utils/TemplateUtils.js +6 -0
  35. package/dist/esm/utils/TemplateUtils.js.map +2 -2
  36. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +204 -81
  37. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +3 -3
  38. package/dist/types/decorators/applyNode.d.ts +84 -1
  39. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  40. package/dist/types/decorators/classList.d.ts +12 -10
  41. package/dist/types/decorators/classList.d.ts.map +1 -1
  42. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  43. package/dist/types/decorators/index.d.ts +0 -1
  44. package/dist/types/decorators/index.d.ts.map +1 -1
  45. package/dist/types/decorators/lifecycles.d.ts +14 -0
  46. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  47. package/dist/types/decorators/query.d.ts +0 -3
  48. package/dist/types/decorators/query.d.ts.map +1 -1
  49. package/dist/types/decorators/style.d.ts +28 -3
  50. package/dist/types/decorators/style.d.ts.map +1 -1
  51. package/dist/types/utils/TemplateUtils.d.ts +5 -0
  52. package/dist/types/utils/TemplateUtils.d.ts.map +1 -1
  53. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +204 -81
  54. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +3 -3
  55. package/package.json +3 -3
  56. package/src/decorators/applyNode.ts +199 -36
  57. package/src/decorators/attribute.ts +1 -1
  58. package/src/decorators/classList.ts +45 -22
  59. package/src/decorators/elementDefine.ts +1 -2
  60. package/src/decorators/index.ts +0 -1
  61. package/src/decorators/lifecycles.ts +40 -0
  62. package/src/decorators/query.ts +0 -2
  63. package/src/decorators/style.ts +64 -13
  64. package/src/utils/TemplateUtils.ts +9 -0
  65. package/dist/cjs/decorators/onConnectedInnerHtml.js +0 -48
  66. package/dist/cjs/decorators/onConnectedInnerHtml.js.map +0 -7
  67. package/dist/esm/decorators/onConnectedInnerHtml.js +0 -29
  68. package/dist/esm/decorators/onConnectedInnerHtml.js.map +0 -7
  69. package/dist/types/decorators/onConnectedInnerHtml.d.ts +0 -15
  70. package/dist/types/decorators/onConnectedInnerHtml.d.ts.map +0 -1
  71. package/src/decorators/onConnectedInnerHtml.ts +0 -42
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -93,9 +93,9 @@
93
93
  "webpack-cli": "^5.1.4",
94
94
  "webpack-dev-server": "^5.2.0",
95
95
  "@dooboostore/core-web": "1.0.10",
96
- "@dooboostore/core": "1.0.30",
97
96
  "@dooboostore/core-node": "1.0.12",
98
- "@dooboostore/simple-boot": "1.0.54"
97
+ "@dooboostore/simple-boot": "1.0.54",
98
+ "@dooboostore/core": "1.0.30"
99
99
  },
100
100
  "scripts": {
101
101
  "clean": "rm -rf dist",
@@ -1,10 +1,12 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { ensureInit, getElementConfig } from './elementDefine';
3
+ import { SwcRootType } from '../types';
3
4
 
4
- export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText';
5
+ export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText' | 'remove';
5
6
 
6
7
  export interface ApplyNodeOptions {
7
8
  position?: ApplyNodePosition;
9
+ root?: SwcRootType;
8
10
  }
9
11
 
10
12
  export interface ApplyNodeMetadata {
@@ -31,6 +33,8 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
31
33
  * @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
32
34
  * @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
33
35
  * @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
36
+ * @applyNode('#notification', { position: 'remove' }) dismissNotification() { return shouldDismiss; } // remove if truthy
37
+ * @applyNode('.items', { position: 'remove', root: 'shadow' }) clearItems() { return true; } // remove shadow DOM elements
34
38
  *
35
39
  * Positions:
36
40
  * - 'beforeEnd' (default): Append at end of target
@@ -41,6 +45,13 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
41
45
  * - 'replaceChildren': Replace all children of target element
42
46
  * - 'innerHtml': Set target's innerHTML
43
47
  * - 'innerText': Set target's innerText
48
+ * - 'remove': Remove target element if returned value is truthy
49
+ *
50
+ * Root Options:
51
+ * - 'auto' (default): Search shadow DOM first, then light DOM
52
+ * - 'shadow': Search only in shadow DOM
53
+ * - 'light': Search only in light DOM
54
+ * - 'all': Use both (shadow preferred for query, both for remove)
44
55
  */
45
56
  export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
46
57
  return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
@@ -61,43 +72,83 @@ export function applyNode(selector: string, options: ApplyNodeOptions = { positi
61
72
  const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
62
73
  const currentDoc = currentWin.document;
63
74
 
64
- let targetEl: HTMLElement | null = null;
65
- if (selector === ':host' || !selector) {
66
- targetEl = this as any;
67
- } else {
68
- targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
69
- }
75
+ const pos = options.position || 'beforeEnd';
76
+ const r = options.root || 'auto';
70
77
 
71
- if (targetEl) {
72
- const nodes = normalizeNodes(res, currentDoc);
73
- const pos = options.position || 'beforeEnd';
74
-
75
- if (pos === 'replace') {
76
- // Replace the entire target element with new nodes
77
- targetEl.replaceWith(...nodes);
78
- } else if (pos === 'replaceChildren') {
79
- // Replace all children of target element
80
- targetEl.replaceChildren(...nodes);
81
- } else if (pos === 'innerHtml') {
82
- // Set innerHTML
83
- targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
84
- } else if (pos === 'innerText') {
85
- // Set innerText
86
- targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
78
+ const getTargetRoot = () => {
79
+ if (r === 'shadow') return this.shadowRoot;
80
+ if (r === 'light') return this as any;
81
+ if (r === 'all') return this.shadowRoot || (this as any);
82
+ return this.shadowRoot || (this as any); // auto
83
+ };
84
+
85
+ if (pos === 'remove') {
86
+ // Remove element(s) if returned value is truthy
87
+ if (res) {
88
+ if (selector === ':host' || !selector) {
89
+ if (r === 'shadow' && this.shadowRoot) {
90
+ // Remove all children from shadow DOM
91
+ this.shadowRoot.replaceChildren();
92
+ } else {
93
+ // Remove the component itself
94
+ (this as any).remove();
95
+ }
96
+ } else {
97
+ const targetRoot = getTargetRoot();
98
+ if (targetRoot) {
99
+ const targets = targetRoot.querySelectorAll(selector);
100
+ targets.forEach((el: Element) => el.remove());
101
+ }
102
+ }
103
+ }
104
+ } else {
105
+ let targetEl: any = null;
106
+ if (selector === ':host' || !selector) {
107
+ if (r === 'shadow') {
108
+ targetEl = this.shadowRoot; // Target shadow DOM root
109
+ } else {
110
+ targetEl = this as any; // Target the component itself
111
+ }
87
112
  } else {
88
- /*
89
- <!-- beforebegin -->
90
- <p>
91
- <!-- afterbegin -->
92
- foo
93
- <!-- beforeend -->
94
- </p>
95
- <!-- afterend -->
96
- */
97
- if (pos === 'beforeEnd') targetEl.append(...nodes);
98
- else if (pos === 'afterBegin') targetEl.prepend(...nodes);
99
- else if (pos === 'beforeBegin') targetEl.before(...nodes);
100
- else if (pos === 'afterEnd') targetEl.after(...nodes);
113
+ const targetRoot = getTargetRoot();
114
+ targetEl = targetRoot ? targetRoot.querySelector(selector) : null;
115
+ }
116
+
117
+ if (targetEl) {
118
+ const isShadowRoot = targetEl instanceof ShadowRoot;
119
+ const nodes = normalizeNodes(res, currentDoc);
120
+
121
+ if (pos === 'replace') {
122
+ // ShadowRoot doesn't support replaceWith
123
+ if (!isShadowRoot) {
124
+ targetEl.replaceWith(...nodes);
125
+ }
126
+ } else if (pos === 'replaceChildren') {
127
+ // Replace all children of target element
128
+ targetEl.replaceChildren(...nodes);
129
+ } else if (pos === 'innerHtml') {
130
+ // Set innerHTML
131
+ targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
132
+ } else if (pos === 'innerText') {
133
+ // Set innerText
134
+ if (targetEl.innerText !== undefined) {
135
+ targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
136
+ }
137
+ } else {
138
+ /*
139
+ <!-- beforebegin -->
140
+ <p>
141
+ <!-- afterbegin -->
142
+ foo
143
+ <!-- beforeend -->
144
+ </p>
145
+ <!-- afterend -->
146
+ */
147
+ if (pos === 'beforeEnd') targetEl.append(...nodes);
148
+ else if (pos === 'afterBegin') targetEl.prepend(...nodes);
149
+ else if (pos === 'beforeBegin' && !isShadowRoot) targetEl.before(...nodes);
150
+ else if (pos === 'afterEnd' && !isShadowRoot) targetEl.after(...nodes);
151
+ }
101
152
  }
102
153
  }
103
154
  }
@@ -125,3 +176,115 @@ export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, Appl
125
176
  export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
126
177
  return applyNode(':host', options);
127
178
  }
179
+
180
+ // Convenience decorators for specific positions
181
+
182
+ /**
183
+ * @applyBeforeBeginNode - Insert before target element
184
+ */
185
+ export const applyBeforeBeginNode = (selector: string, options: ApplyNodeOptions = {}) =>
186
+ applyNode(selector, { ...options, position: 'beforeBegin' });
187
+
188
+ /**
189
+ * @applyAfterBeginNode - Prepend to target element
190
+ */
191
+ export const applyAfterBeginNode = (selector: string, options: ApplyNodeOptions = {}) =>
192
+ applyNode(selector, { ...options, position: 'afterBegin' });
193
+
194
+ /**
195
+ * @applyBeforeEndNode - Append to target element (default)
196
+ */
197
+ export const applyBeforeEndNode = (selector: string, options: ApplyNodeOptions = {}) =>
198
+ applyNode(selector, { ...options, position: 'beforeEnd' });
199
+
200
+ /**
201
+ * @applyAfterEndNode - Insert after target element
202
+ */
203
+ export const applyAfterEndNode = (selector: string, options: ApplyNodeOptions = {}) =>
204
+ applyNode(selector, { ...options, position: 'afterEnd' });
205
+
206
+ /**
207
+ * @applyReplaceNode - Replace entire target element
208
+ */
209
+ export const applyReplaceNode = (selector: string, options: ApplyNodeOptions = {}) =>
210
+ applyNode(selector, { ...options, position: 'replace' });
211
+
212
+ /**
213
+ * @applyReplaceChildrenNode - Replace all children of target element
214
+ */
215
+ export const applyReplaceChildrenNode = (selector: string, options: ApplyNodeOptions = {}) =>
216
+ applyNode(selector, { ...options, position: 'replaceChildren' });
217
+
218
+ /**
219
+ * @applyInnerHtmlNode - Set target's innerHTML
220
+ */
221
+ export const applyInnerHtmlNode = (selector: string, options: ApplyNodeOptions = {}) =>
222
+ applyNode(selector, { ...options, position: 'innerHtml' });
223
+
224
+ /**
225
+ * @applyInnerTextNode - Set target's innerText
226
+ */
227
+ export const applyInnerTextNode = (selector: string, options: ApplyNodeOptions = {}) =>
228
+ applyNode(selector, { ...options, position: 'innerText' });
229
+
230
+ /**
231
+ * @applyRemoveNode - Remove target element if truthy
232
+ */
233
+ export const applyRemoveNode = (selector: string, options: ApplyNodeOptions = {}) =>
234
+ applyNode(selector, { ...options, position: 'remove' });
235
+
236
+ // Host versions
237
+
238
+ /**
239
+ * @applyBeforeBeginNodeHost - Insert before :host
240
+ */
241
+ export const applyBeforeBeginNodeHost = (options: ApplyNodeOptions = {}) =>
242
+ applyNode(':host', { ...options, position: 'beforeBegin' });
243
+
244
+ /**
245
+ * @applyAfterBeginNodeHost - Prepend to :host
246
+ */
247
+ export const applyAfterBeginNodeHost = (options: ApplyNodeOptions = {}) =>
248
+ applyNode(':host', { ...options, position: 'afterBegin' });
249
+
250
+ /**
251
+ * @applyBeforeEndNodeHost - Append to :host
252
+ */
253
+ export const applyBeforeEndNodeHost = (options: ApplyNodeOptions = {}) =>
254
+ applyNode(':host', { ...options, position: 'beforeEnd' });
255
+
256
+ /**
257
+ * @applyAfterEndNodeHost - Insert after :host
258
+ */
259
+ export const applyAfterEndNodeHost = (options: ApplyNodeOptions = {}) =>
260
+ applyNode(':host', { ...options, position: 'afterEnd' });
261
+
262
+ /**
263
+ * @applyReplaceNodeHost - Replace :host
264
+ */
265
+ export const applyReplaceNodeHost = (options: ApplyNodeOptions = {}) =>
266
+ applyNode(':host', { ...options, position: 'replace' });
267
+
268
+ /**
269
+ * @applyReplaceChildrenNodeHost - Replace children of :host
270
+ */
271
+ export const applyReplaceChildrenNodeHost = (options: ApplyNodeOptions = {}) =>
272
+ applyNode(':host', { ...options, position: 'replaceChildren' });
273
+
274
+ /**
275
+ * @applyInnerHtmlNodeHost - Set :host innerHTML
276
+ */
277
+ export const applyInnerHtmlNodeHost = (options: ApplyNodeOptions = {}) =>
278
+ applyNode(':host', { ...options, position: 'innerHtml' });
279
+
280
+ /**
281
+ * @applyInnerTextNodeHost - Set :host innerText
282
+ */
283
+ export const applyInnerTextNodeHost = (options: ApplyNodeOptions = {}) =>
284
+ applyNode(':host', { ...options, position: 'innerText' });
285
+
286
+ /**
287
+ * @applyRemoveNodeHost - Remove :host if truthy
288
+ */
289
+ export const applyRemoveNodeHost = (options: ApplyNodeOptions = {}) =>
290
+ applyNode(':host', { ...options, position: 'remove' });
@@ -143,7 +143,7 @@ export function attribute(selector: string, options: AttributeOptions = {}): Pro
143
143
  },
144
144
  set(this: any, nv: any) {
145
145
  const targetType = options.type || designType;
146
- console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
146
+ // console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
147
147
 
148
148
  const attrName = options.name || String(propertyKey);
149
149
  const conf = getElementConfig(this);
@@ -1,6 +1,7 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { ensureInit } from './elementDefine';
3
3
  import { SwcUtils } from '../utils/Utils';
4
+ import { SwcQueryOptions } from '../types';
4
5
 
5
6
  export const CLASS_LIST_METADATA_KEY = Symbol('simple-web-component:class-list');
6
7
 
@@ -10,10 +11,11 @@ export interface ClassListMetadata {
10
11
  propertyKey: string | symbol;
11
12
  selector: string;
12
13
  action: ClassListAction;
14
+ options: SwcQueryOptions;
13
15
  }
14
16
 
15
17
  function createClassListDecorator(action: ClassListAction) {
16
- return (selector: string): MethodDecorator => {
18
+ return (selector: string, options: SwcQueryOptions = {}): MethodDecorator => {
17
19
  return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
18
20
  const constructor = target.constructor;
19
21
  let metaList = ReflectUtils.getOwnMetadata(CLASS_LIST_METADATA_KEY, constructor) as Map<string | symbol, ClassListMetadata>;
@@ -21,22 +23,43 @@ function createClassListDecorator(action: ClassListAction) {
21
23
  metaList = new Map<string | symbol, ClassListMetadata>();
22
24
  ReflectUtils.defineMetadata(CLASS_LIST_METADATA_KEY, metaList, constructor);
23
25
  }
24
- metaList.set(propertyKey, { propertyKey, selector, action });
26
+ metaList.set(propertyKey, { propertyKey, selector, action, options });
25
27
 
26
28
  const original = descriptor.value;
27
29
  descriptor.value = async function (...args: any[]) {
28
30
  ensureInit(this);
29
31
  const res = await original.apply(this, args);
30
32
  if (res !== undefined) {
33
+ const r = options.root || 'auto';
31
34
  const hostSet = SwcUtils.getHostSet(this as any);
35
+ const targetEls: HTMLElement[] = [];
36
+
37
+ if (selector === ':host' || !selector) {
38
+ targetEls.push(this as any);
39
+ } else if (selector === ':parentHost') {
40
+ if (hostSet.$parentHost) targetEls.push(hostSet.$parentHost);
41
+ } else if (selector === ':appHost') {
42
+ if (hostSet.$appHost) targetEls.push(hostSet.$appHost);
43
+ } else {
44
+ if (r === 'shadow') {
45
+ const found = this.shadowRoot?.querySelectorAll(selector);
46
+ if (found) targetEls.push(...found);
47
+ } else if (r === 'light') {
48
+ const found = (this as any).querySelectorAll(selector);
49
+ if (found) targetEls.push(...found);
50
+ } else if (r === 'all') {
51
+ const sFound = this.shadowRoot?.querySelectorAll(selector);
52
+ const lFound = (this as any).querySelectorAll(selector);
53
+ if (sFound) targetEls.push(...sFound);
54
+ if (lFound) targetEls.push(...lFound);
55
+ } else {
56
+ // auto
57
+ const found = (this.shadowRoot || (this as any)).querySelectorAll(selector);
58
+ if (found) targetEls.push(...found);
59
+ }
60
+ }
32
61
 
33
- let targetEl: HTMLElement | null = null;
34
- if (selector === ':host' || !selector) targetEl = this as any;
35
- else if (selector === ':parentHost') targetEl = hostSet.$parentHost;
36
- else if (selector === ':appHost') targetEl = hostSet.$appHost;
37
- else targetEl = (this.shadowRoot || (this as any)).querySelector(selector);
38
-
39
- if (targetEl) {
62
+ targetEls.forEach(targetEl => {
40
63
  if (action === 'set') {
41
64
  let classes = '';
42
65
  if (typeof res === 'object' && res !== null && !Array.isArray(res)) {
@@ -51,7 +74,7 @@ function createClassListDecorator(action: ClassListAction) {
51
74
  } else if (action === 'update') {
52
75
  if (typeof res === 'object' && res !== null && !Array.isArray(res)) {
53
76
  Object.entries(res).forEach(([cls, force]) => {
54
- targetEl!.classList.toggle(cls, !!force);
77
+ targetEl.classList.toggle(cls, !!force);
55
78
  });
56
79
  } else if (res !== undefined && res !== null) {
57
80
  const classes = Array.isArray(res) ? res.map(String) : [String(res)];
@@ -65,9 +88,9 @@ function createClassListDecorator(action: ClassListAction) {
65
88
  targetEl.classList.remove(...classes);
66
89
  } else if (action === 'toggle') {
67
90
  const classes = Array.isArray(res) ? res.map(String) : [String(res)];
68
- classes.forEach(c => targetEl!.classList.toggle(c));
91
+ classes.forEach(c => targetEl.classList.toggle(c));
69
92
  }
70
- }
93
+ });
71
94
  }
72
95
  return res;
73
96
  };
@@ -79,31 +102,31 @@ function createClassListDecorator(action: ClassListAction) {
79
102
  * @setClassList decorator to surgically replace all classes on a target element.
80
103
  * Returns: string | string[]
81
104
  */
82
- export const setClassList = createClassListDecorator('set');
105
+ export const setClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('set')(selector, options);
83
106
 
84
107
  /**
85
108
  * @updateClassList decorator to surgically update specific classes.
86
109
  * Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
87
110
  */
88
- export const updateClassList = createClassListDecorator('update');
111
+ export const updateClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('update')(selector, options);
89
112
 
90
113
  /**
91
114
  * @addClassList decorator to surgically add classes to a target element.
92
115
  * Returns: string | string[]
93
116
  */
94
- export const addClassList = createClassListDecorator('add');
117
+ export const addClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('add')(selector, options);
95
118
 
96
119
  /**
97
120
  * @removeClassList decorator to surgically remove classes from a target element.
98
121
  * Returns: string | string[]
99
122
  */
100
- export const removeClassList = createClassListDecorator('remove');
123
+ export const removeClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('remove')(selector, options);
101
124
 
102
125
  /**
103
126
  * @toggleClassList decorator to surgically toggle classes on a target element.
104
127
  * Returns: string | string[]
105
128
  */
106
- export const toggleClassList = createClassListDecorator('toggle');
129
+ export const toggleClassList = (selector: string, options: SwcQueryOptions = {}) => createClassListDecorator('toggle')(selector, options);
107
130
 
108
131
  // Host-specific versions (for :host selector)
109
132
 
@@ -111,31 +134,31 @@ export const toggleClassList = createClassListDecorator('toggle');
111
134
  * @setClassListHost decorator to set classes on :host element.
112
135
  * Returns: string | string[]
113
136
  */
114
- export const setClassListHost = createClassListDecorator('set').bind(null, ':host');
137
+ export const setClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('set')(':host', options);
115
138
 
116
139
  /**
117
140
  * @updateClassListHost decorator to update specific classes on :host.
118
141
  * Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
119
142
  */
120
- export const updateClassListHost = createClassListDecorator('update').bind(null, ':host');
143
+ export const updateClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('update')(':host', options);
121
144
 
122
145
  /**
123
146
  * @addClassListHost decorator to add classes to :host element.
124
147
  * Returns: string | string[]
125
148
  */
126
- export const addClassListHost = createClassListDecorator('add').bind(null, ':host');
149
+ export const addClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('add')(':host', options);
127
150
 
128
151
  /**
129
152
  * @removeClassListHost decorator to remove classes from :host element.
130
153
  * Returns: string | string[]
131
154
  */
132
- export const removeClassListHost = createClassListDecorator('remove').bind(null, ':host');
155
+ export const removeClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('remove')(':host', options);
133
156
 
134
157
  /**
135
158
  * @toggleClassListHost decorator to toggle classes on :host element.
136
159
  * Returns: string | string[]
137
160
  */
138
- export const toggleClassListHost = createClassListDecorator('toggle').bind(null, ':host');
161
+ export const toggleClassListHost = (options: SwcQueryOptions = {}) => createClassListDecorator('toggle')(':host', options);
139
162
 
140
163
  export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
141
164
  const result = new Map<string | symbol, ClassListMetadata>();
@@ -1,8 +1,7 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { FunctionUtils } from '@dooboostore/core';
3
- import { getOnConnectedInnerHtmlMetadata } from './onConnectedInnerHtml';
4
3
  import { getAddEventListenerMetadata } from './addEventListener';
5
- import { ON_CONSTRUCTOR_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata } from './lifecycles';
4
+ import { ON_CONSTRUCTOR_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata, getOnConnectedInnerHtmlMetadata } from './lifecycles';
6
5
  import { getEmitCustomEventMetadataList } from './emitCustomEvent';
7
6
  import { findAllAttributeChangedMetadata } from './changedAttributeHost';
8
7
  import { findAllSetAttributeMetadata } from './setAttribute';
@@ -8,6 +8,5 @@ export * from './applyNode';
8
8
  export * from './lifecycles';
9
9
  export * from './query';
10
10
  export * from './queryAll';
11
- export * from './onConnectedInnerHtml';
12
11
  export * from './classList';
13
12
  export * from './style';
@@ -10,9 +10,19 @@ export const ON_AFTER_DISCONNECTED_METADATA_KEY = Symbol('simple-web-component:o
10
10
  export const ON_BEFORE_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-before-adopted');
11
11
  export const ON_AFTER_ADOPTED_METADATA_KEY = Symbol('simple-web-component:on-after-adopted');
12
12
  export const ON_ADD_EVENT_LISTENER_METADATA_KEY = Symbol('simple-web-component:on-add-event-listener');
13
+ export const INNER_HTML_METADATA_KEY = Symbol('simple-web-component:inner-html');
13
14
 
14
15
  export const ATTRIBUTE_CHANGED_WILDCARD = '*';
15
16
 
17
+ export interface InnerHtmlOptions {
18
+ useShadow?: boolean;
19
+ }
20
+
21
+ export interface InnerHtmlMetadata {
22
+ propertyKey: string | symbol;
23
+ options: InnerHtmlOptions;
24
+ }
25
+
16
26
  function createLifecycleDecorator(metadataKey: symbol): MethodDecorator {
17
27
  return (target: Object, propertyKey: string | symbol) => {
18
28
  const constructor = target.constructor;
@@ -40,6 +50,31 @@ export const onAdopted = onAfterAdopted;
40
50
 
41
51
  export const onAddEventListener = createLifecycleDecorator(ON_ADD_EVENT_LISTENER_METADATA_KEY);
42
52
 
53
+ /**
54
+ * @onConnectedInnerHtml decorator to define the initial HTML content when connected.
55
+ */
56
+ export function onConnectedInnerHtml(options: InnerHtmlOptions): MethodDecorator;
57
+ export function onConnectedInnerHtml(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
58
+ export function onConnectedInnerHtml(arg1?: InnerHtmlOptions | Object, arg2?: string | symbol, arg3?: PropertyDescriptor): MethodDecorator | void {
59
+ const decorator = (options: InnerHtmlOptions, target: Object, propertyKey: string | symbol) => {
60
+ const constructor = target.constructor;
61
+ let list = ReflectUtils.getMetadata<InnerHtmlMetadata[]>(INNER_HTML_METADATA_KEY, constructor);
62
+ if (!list) {
63
+ list = [];
64
+ ReflectUtils.defineMetadata(INNER_HTML_METADATA_KEY, list, constructor);
65
+ }
66
+ list.push({ propertyKey, options });
67
+ };
68
+
69
+ if (arg2) {
70
+ return decorator({}, arg1!, arg2);
71
+ }
72
+
73
+ return (target: Object, propertyKey: string | symbol) => {
74
+ decorator((arg1 as InnerHtmlOptions) || {}, target, propertyKey);
75
+ };
76
+ }
77
+
43
78
  /**
44
79
  * 프로토타입 체인을 순회하며 모든 라이프사이클 메서드를 수집합니다.
45
80
  */
@@ -47,3 +82,8 @@ export const findAllLifecycleMetadata = <T = (string | symbol)[]>(target: any, m
47
82
  const results = ReflectUtils.findAllMetadataFlatten(metadataKey, target);
48
83
  return results.length > 0 ? (results as unknown as T) : undefined;
49
84
  };
85
+
86
+ export const getOnConnectedInnerHtmlMetadata = (target: any): InnerHtmlMetadata[] | undefined => {
87
+ const constructor = target instanceof Function ? target : target.constructor;
88
+ return ReflectUtils.getMetadata(INNER_HTML_METADATA_KEY, constructor);
89
+ };
@@ -3,8 +3,6 @@ import { getElementConfig, ensureInit } from './elementDefine';
3
3
  import { SwcUtils } from '../utils/Utils';
4
4
  import { SpecialSelector, SwcQueryOptions } from '../types';
5
5
 
6
- export type QueryOptions = { root?: 'light' | 'shadow' | 'all' | 'auto' };
7
-
8
6
  export interface QueryMetadata {
9
7
  propertyKey: string | symbol;
10
8
  selector: string;