@dooboostore/simple-web-component 1.0.24 → 1.0.26

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 (130) hide show
  1. package/README.md +162 -33
  2. package/dist/cjs/decorators/addEventListener.js +1 -1
  3. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  4. package/dist/cjs/decorators/applyAttribute.js +148 -0
  5. package/dist/cjs/decorators/applyAttribute.js.map +7 -0
  6. package/dist/cjs/decorators/applyClass.js +164 -0
  7. package/dist/cjs/decorators/applyClass.js.map +7 -0
  8. package/dist/cjs/decorators/applyNode.js +87 -194
  9. package/dist/cjs/decorators/applyNode.js.map +2 -2
  10. package/dist/cjs/decorators/{style.js → applyStyle.js} +50 -60
  11. package/dist/cjs/decorators/applyStyle.js.map +7 -0
  12. package/dist/cjs/decorators/attribute.js +10 -16
  13. package/dist/cjs/decorators/attribute.js.map +2 -2
  14. package/dist/cjs/decorators/changedAttributeHost.js +1 -1
  15. package/dist/cjs/decorators/changedAttributeHost.js.map +2 -2
  16. package/dist/cjs/decorators/elementDefine.js +14 -23
  17. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  18. package/dist/cjs/decorators/emitCustomEvent.js +5 -2
  19. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  20. package/dist/cjs/decorators/index.js +3 -3
  21. package/dist/cjs/decorators/index.js.map +2 -2
  22. package/dist/cjs/decorators/lifecycles.js +9 -9
  23. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  24. package/dist/cjs/decorators/query.js +1 -1
  25. package/dist/cjs/decorators/query.js.map +2 -2
  26. package/dist/cjs/decorators/queryAll.js +1 -1
  27. package/dist/cjs/decorators/queryAll.js.map +2 -2
  28. package/dist/cjs/elements/SwcAppEngine.js +19 -4
  29. package/dist/cjs/elements/SwcAppEngine.js.map +2 -2
  30. package/dist/cjs/elements/SwcAppMixin.js +2 -0
  31. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  32. package/dist/cjs/utils/Utils.js +1 -1
  33. package/dist/cjs/utils/Utils.js.map +2 -2
  34. package/dist/esm/decorators/addEventListener.js +1 -1
  35. package/dist/esm/decorators/addEventListener.js.map +2 -2
  36. package/dist/esm/decorators/applyAttribute.js +129 -0
  37. package/dist/esm/decorators/applyAttribute.js.map +7 -0
  38. package/dist/esm/decorators/applyClass.js +145 -0
  39. package/dist/esm/decorators/applyClass.js.map +7 -0
  40. package/dist/esm/decorators/applyNode.js +87 -194
  41. package/dist/esm/decorators/applyNode.js.map +2 -2
  42. package/dist/esm/decorators/{style.js → applyStyle.js} +47 -57
  43. package/dist/esm/decorators/applyStyle.js.map +7 -0
  44. package/dist/esm/decorators/attribute.js +10 -16
  45. package/dist/esm/decorators/attribute.js.map +2 -2
  46. package/dist/esm/decorators/changedAttributeHost.js +1 -1
  47. package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
  48. package/dist/esm/decorators/elementDefine.js +14 -23
  49. package/dist/esm/decorators/elementDefine.js.map +2 -2
  50. package/dist/esm/decorators/emitCustomEvent.js +5 -2
  51. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  52. package/dist/esm/decorators/index.js +3 -3
  53. package/dist/esm/decorators/index.js.map +1 -1
  54. package/dist/esm/decorators/lifecycles.js +9 -9
  55. package/dist/esm/decorators/lifecycles.js.map +2 -2
  56. package/dist/esm/decorators/query.js +1 -1
  57. package/dist/esm/decorators/query.js.map +2 -2
  58. package/dist/esm/decorators/queryAll.js +1 -1
  59. package/dist/esm/decorators/queryAll.js.map +2 -2
  60. package/dist/esm/elements/SwcAppEngine.js +19 -4
  61. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  62. package/dist/esm/elements/SwcAppMixin.js +2 -0
  63. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  64. package/dist/esm/utils/Utils.js +1 -1
  65. package/dist/esm/utils/Utils.js.map +2 -2
  66. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +2853 -574
  67. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  68. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  69. package/dist/types/decorators/applyAttribute.d.ts +22 -0
  70. package/dist/types/decorators/applyAttribute.d.ts.map +1 -0
  71. package/dist/types/decorators/applyClass.d.ts +65 -0
  72. package/dist/types/decorators/applyClass.d.ts.map +1 -0
  73. package/dist/types/decorators/applyNode.d.ts +15 -123
  74. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  75. package/dist/types/decorators/applyStyle.d.ts +21 -0
  76. package/dist/types/decorators/applyStyle.d.ts.map +1 -0
  77. package/dist/types/decorators/attribute.d.ts +10 -19
  78. package/dist/types/decorators/attribute.d.ts.map +1 -1
  79. package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
  80. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  81. package/dist/types/decorators/emitCustomEvent.d.ts +1 -1
  82. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  83. package/dist/types/decorators/index.d.ts +3 -3
  84. package/dist/types/decorators/index.d.ts.map +1 -1
  85. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  86. package/dist/types/decorators/query.d.ts.map +1 -1
  87. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  88. package/dist/types/elements/SwcAppEngine.d.ts +7 -0
  89. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  90. package/dist/types/elements/SwcAppMixin.d.ts +1 -1
  91. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  92. package/dist/types/utils/Utils.d.ts.map +1 -1
  93. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +2853 -574
  94. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  95. package/package.json +2 -2
  96. package/src/decorators/addEventListener.ts +1 -1
  97. package/src/decorators/applyAttribute.ts +147 -0
  98. package/src/decorators/applyClass.ts +158 -0
  99. package/src/decorators/applyNode.ts +112 -330
  100. package/src/decorators/applyStyle.ts +128 -0
  101. package/src/decorators/attribute.ts +21 -55
  102. package/src/decorators/changedAttributeHost.ts +1 -1
  103. package/src/decorators/elementDefine.ts +18 -39
  104. package/src/decorators/emitCustomEvent.ts +6 -3
  105. package/src/decorators/index.ts +3 -3
  106. package/src/decorators/lifecycles.ts +9 -11
  107. package/src/decorators/query.ts +1 -1
  108. package/src/decorators/queryAll.ts +1 -1
  109. package/src/elements/SwcAppEngine.ts +32 -4
  110. package/src/elements/SwcAppMixin.ts +2 -0
  111. package/src/utils/Utils.ts +2 -1
  112. package/dist/cjs/decorators/classList.js +0 -177
  113. package/dist/cjs/decorators/classList.js.map +0 -7
  114. package/dist/cjs/decorators/setAttribute.js +0 -111
  115. package/dist/cjs/decorators/setAttribute.js.map +0 -7
  116. package/dist/cjs/decorators/style.js.map +0 -7
  117. package/dist/esm/decorators/classList.js +0 -158
  118. package/dist/esm/decorators/classList.js.map +0 -7
  119. package/dist/esm/decorators/setAttribute.js +0 -92
  120. package/dist/esm/decorators/setAttribute.js.map +0 -7
  121. package/dist/esm/decorators/style.js.map +0 -7
  122. package/dist/types/decorators/classList.d.ts +0 -71
  123. package/dist/types/decorators/classList.d.ts.map +0 -1
  124. package/dist/types/decorators/setAttribute.d.ts +0 -23
  125. package/dist/types/decorators/setAttribute.d.ts.map +0 -1
  126. package/dist/types/decorators/style.d.ts +0 -58
  127. package/dist/types/decorators/style.d.ts.map +0 -1
  128. package/src/decorators/classList.ts +0 -234
  129. package/src/decorators/setAttribute.ts +0 -114
  130. package/src/decorators/style.ts +0 -185
@@ -1,13 +1,22 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { ensureInit, getElementConfig } from './elementDefine';
3
- import { SwcRootType } from '../types';
4
- import {SwcUtils} from "../utils/Utils";
3
+ import { HelperHostSet, SwcRootType } from '../types';
4
+ import { SwcUtils } from "../utils/Utils";
5
5
 
6
6
  export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText' | 'remove';
7
7
 
8
8
  export interface ApplyNodeOptions {
9
9
  position?: ApplyNodePosition;
10
10
  root?: SwcRootType;
11
+ /**
12
+ * Filter function to determine whether to perform DOM operation.
13
+ * If it returns false, the operation is skipped.
14
+ */
15
+ filter?: (target: HTMLElement | ShadowRoot, newValue: any, helper: HelperHostSet) => boolean;
16
+ /**
17
+ * Optional loading content to display while an async method is executing.
18
+ */
19
+ loading?: (helper: HelperHostSet) => any;
11
20
  }
12
21
 
13
22
  export interface ApplyNodeMetadata {
@@ -16,7 +25,7 @@ export interface ApplyNodeMetadata {
16
25
  options: ApplyNodeOptions;
17
26
  }
18
27
 
19
- export const APPLY_NODE_METADATA_KEY = Symbol('simple-web-component:apply-node');
28
+ export const APPLY_NODE_METADATA_KEY = Symbol.for('simple-web-component:apply-node');
20
29
 
21
30
  const normalizeNodes = (res: any, doc: Document): Node[] => {
22
31
  const items = Array.isArray(res) ? res : [res];
@@ -26,37 +35,41 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
26
35
  });
27
36
  };
28
37
 
38
+ const applyToDom = (targetEl: any, res: any, pos: ApplyNodePosition, doc: Document) => {
39
+ if (!targetEl) return;
40
+
41
+ if (pos === 'innerHtml') {
42
+ targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
43
+ return;
44
+ }
45
+
46
+ if (pos === 'innerText') {
47
+ if (targetEl.innerText !== undefined) {
48
+ targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
49
+ }
50
+ return;
51
+ }
52
+
53
+ const isShadowRoot = targetEl instanceof ShadowRoot;
54
+ const nodes = normalizeNodes(res, doc);
55
+ if (pos === 'replace') {
56
+ if (!isShadowRoot) targetEl.replaceWith(...nodes);
57
+ } else if (pos === 'replaceChildren') {
58
+ targetEl.replaceChildren(...nodes);
59
+ } else {
60
+ if (pos === 'beforeEnd') targetEl.append(...nodes);
61
+ else if (pos === 'afterBegin') targetEl.prepend(...nodes);
62
+ else if (pos === 'beforeBegin' && !isShadowRoot) targetEl.before(...nodes);
63
+ else if (pos === 'afterEnd' && !isShadowRoot) targetEl.after(...nodes);
64
+ }
65
+ };
66
+
29
67
  /**
30
68
  * @applyNode decorator to surgically add/replace nodes to a target element.
31
- *
32
- * Usage examples:
33
- * @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
34
- * @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
35
- * @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
36
- * @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
37
- * @applyNode('#notification', { position: 'remove' }) dismissNotification() { return shouldDismiss; } // remove if truthy
38
- * @applyNode('.items', { position: 'remove', root: 'shadow' }) clearItems() { return true; } // remove shadow DOM elements
39
- *
40
- * Positions:
41
- * - 'beforeEnd' (default): Append at end of target
42
- * - 'afterBegin': Prepend at start of target
43
- * - 'beforeBegin': Insert before target
44
- * - 'afterEnd': Insert after target
45
- * - 'replace': Replace the entire target element
46
- * - 'replaceChildren': Replace all children of target element
47
- * - 'innerHtml': Set target's innerHTML
48
- * - 'innerText': Set target's innerText
49
- * - 'remove': Remove target element if returned value is truthy
50
- *
51
- * Root Options:
52
- * - 'auto' (default): Search shadow DOM first, then light DOM
53
- * - 'shadow': Search only in shadow DOM
54
- * - 'light': Search only in light DOM
55
- * - 'all': Use both (shadow preferred for query, both for remove)
56
69
  */
57
70
  export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
58
- return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
59
- const constructor = target.constructor;
71
+ return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
72
+ const constructor = targetObj.constructor;
60
73
  let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
61
74
  if (!metaList) {
62
75
  metaList = new Map<string | symbol, ApplyNodeMetadata>();
@@ -65,113 +78,71 @@ export function applyNode(selector: string, options: ApplyNodeOptions = { positi
65
78
  metaList.set(propertyKey, { propertyKey, selector, options });
66
79
 
67
80
  const original = descriptor.value;
68
- descriptor.value = async function (...args: any[]) {
81
+ descriptor.value = function (...args: any[]) {
69
82
  ensureInit(this);
70
- const res = await original.apply(this, args);
71
- if (res !== undefined) {
72
- const conf = getElementConfig(this);
73
- const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
74
- const currentDoc = currentWin.document;
75
-
76
- const pos = options.position || 'beforeEnd';
83
+
84
+ const conf = getElementConfig(this);
85
+ const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
86
+ const currentDoc = currentWin.document;
87
+ const hostSet = SwcUtils.getHelperAndHostSet(currentWin, this);
88
+
89
+ const getTarget = () => {
77
90
  const r = options.root || 'auto';
78
91
  const applyRoot = (t: any) => {
79
- if (!t || !(t instanceof HTMLElement)) return t;
92
+ if (!t) return t;
80
93
  if (r === 'auto') return t.shadowRoot || t;
81
94
  if (r === 'shadow') return t.shadowRoot;
82
95
  if (r === 'light') return t;
83
- if (r === 'all') return t.shadowRoot || t; // query only returns one, so shadow preferred
96
+ if (r === 'all') return t.shadowRoot || t;
84
97
  return t;
85
98
  };
86
99
 
87
- const hostSet = SwcUtils.getHostSet(this);
88
- // const getTargetRoot = () => {
89
- // if (r === 'shadow') return this.shadowRoot;
90
- // if (r === 'light') return this as any;
91
- // if (r === 'all') return this.shadowRoot || (this as any);
92
- // return this.shadowRoot || (this as any); // auto
93
- // };
94
-
95
- if (pos === 'remove') {
96
- // Remove element(s) if returned value is truthy
97
- if (res) {
98
- if (selector === ':host' || !selector) {
99
- if (r === 'shadow' && this.shadowRoot) {
100
- // Remove all children from shadow DOM
101
- this.shadowRoot.replaceChildren();
102
- } else {
103
- // Remove the component itself
104
- (this as any).remove();
105
- }
106
- } else {
107
- const targetRoot = applyRoot(this);
108
- if (targetRoot) {
109
- const targets = targetRoot.querySelectorAll(selector);
110
- targets.forEach((el: Element) => el.remove());
111
- }
112
- }
113
- }
114
- } else {
115
- let targetEl: any = null;
100
+ if (selector === ':host') return applyRoot(this);
101
+ if (selector === ':parentHost') return applyRoot(hostSet.$parentHost);
102
+ if (selector === ':appHost') return applyRoot(hostSet.$appHost);
103
+ if (selector === ':firstHost') return applyRoot(hostSet.$firstHost);
104
+ if (selector === ':lastHost') return applyRoot(hostSet.$lastHost);
105
+
106
+ const targetRoot = applyRoot(this);
107
+ return targetRoot ? targetRoot.querySelector(selector) : null;
108
+ };
116
109
 
117
- if (selector === ':host') {
118
- targetEl = applyRoot(this)
119
- } else if (selector === ':parentHost') {
120
- targetEl = applyRoot(hostSet.$parentHost)
121
- } else if (selector === ':appHost') {
122
- targetEl = applyRoot(hostSet.$appHost)
123
- } else if (selector === ':firstHost') {
124
- targetEl = applyRoot(hostSet.$firstHost)
125
- } else if (selector === ':lastHost') {
126
- targetEl = applyRoot(hostSet.$lastHost)
127
- } else if (selector === ':firstAppHost') {
128
- targetEl = applyRoot(hostSet.$firstHost)
129
- } else if (selector === ':lastAppHost') {
130
- targetEl = applyRoot(hostSet.$lastAppHost);
131
- } else {
132
- const targetRoot = applyRoot(this);
133
- targetEl = targetRoot ? targetRoot.querySelector(selector) : null;
134
- }
110
+ const targetEl = getTarget();
111
+ const res = original.apply(this, args);
135
112
 
136
- if (targetEl) {
137
- const isShadowRoot = targetEl instanceof ShadowRoot;
138
- const nodes = normalizeNodes(res, currentDoc);
113
+ const runApply = (target: any, val: any) => {
114
+ const pos = options.position || 'beforeEnd';
115
+
116
+ // Intelligent Default Filter
117
+ const defaultFilter = (t: any, v: any) => {
118
+ if (v instanceof Node) return !t.contains(v);
119
+ if (pos === 'innerHtml' && typeof v === 'string') return t.innerHTML !== v;
120
+ if (pos === 'replaceChildren' && v instanceof Node) return !t.contains(v);
121
+ return true;
122
+ };
123
+
124
+ const activeFilter = options.filter || defaultFilter;
125
+
126
+ if (activeFilter(target, val, hostSet)) {
127
+ applyToDom(target, val, pos, currentDoc);
128
+ }
129
+ };
139
130
 
140
- if (pos === 'replace') {
141
- // ShadowRoot doesn't support replaceWith
142
- if (!isShadowRoot) {
143
- targetEl.replaceWith(...nodes);
144
- }
145
- } else if (pos === 'replaceChildren') {
146
- // Replace all children of target element
147
- targetEl.replaceChildren(...nodes);
148
- } else if (pos === 'innerHtml') {
149
- // Set innerHTML
150
- targetEl.innerHTML = res !== undefined && res !== null ? String(res) : '';
151
- } else if (pos === 'innerText') {
152
- // Set innerText
153
- if (targetEl.innerText !== undefined) {
154
- targetEl.innerText = res !== undefined && res !== null ? String(res) : '';
155
- }
156
- } else {
157
- /*
158
- <!-- beforebegin -->
159
- <p>
160
- <!-- afterbegin -->
161
- foo
162
- <!-- beforeend -->
163
- </p>
164
- <!-- afterend -->
165
- */
166
- if (pos === 'beforeEnd') targetEl.append(...nodes);
167
- else if (pos === 'afterBegin') targetEl.prepend(...nodes);
168
- else if (pos === 'beforeBegin' && !isShadowRoot) targetEl.before(...nodes);
169
- else if (pos === 'afterEnd' && !isShadowRoot) targetEl.after(...nodes);
170
- }
131
+ if (res instanceof Promise) {
132
+ // 비동기일 때만 로딩 표시
133
+ if (targetEl && options.loading) {
134
+ const loadingRes = options.loading.call(this, hostSet);
135
+ applyToDom(targetEl, loadingRes, options.position || 'beforeEnd', currentDoc);
171
136
  }
172
- }
137
+
138
+ return res.then(finalRes => {
139
+ if (finalRes !== undefined && targetEl) runApply(targetEl, finalRes);
140
+ return finalRes;
141
+ });
142
+ } else {
143
+ if (res !== undefined && targetEl) runApply(targetEl, res);
144
+ return res;
173
145
  }
174
- return res;
175
146
  };
176
147
  };
177
148
  }
@@ -187,223 +158,34 @@ export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, Appl
187
158
  return result;
188
159
  };
189
160
 
190
- /**
191
- * @applyNodeHost decorator - simplified version of @applyNode for :host selector
192
- * Usage: @applyNodeHost addItem() { return '<li>New Item</li>'; }
193
- * Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
194
- * Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
195
- */
196
- export function applyNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
197
- export function applyNodeHost(): MethodDecorator;
198
161
  export function applyNodeHost(options: ApplyNodeOptions): MethodDecorator;
162
+ export function applyNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
199
163
  export function applyNodeHost(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
200
- // Direct decorator usage: @applyNodeHost (no parentheses)
201
- console.log('vvvvv')
202
- if (propertyKey !== undefined && typeof propertyKey === 'string' || typeof propertyKey === 'symbol') {
203
- return applyNode(':host', { position: 'beforeEnd' })(targetOrOptions, propertyKey, descriptor);
204
- }
205
-
206
- // @applyNodeHost() or @applyNodeHost(options)
207
- if (typeof targetOrOptions === 'object' && targetOrOptions !== null) {
208
- const options = targetOrOptions as ApplyNodeOptions;
209
- return applyNode(':host', { ...options, position: options.position || 'beforeEnd' });
210
- } else {
211
- // @applyNodeHost() - use default position
212
- return applyNode(':host', { position: 'beforeEnd' });
213
- }
214
- }
215
-
216
- // Convenience decorators for specific positions
217
-
218
- /**
219
- * @applyBeforeBeginNode - Insert before target element
220
- */
221
- export function applyBeforeBeginNode(selector: string): MethodDecorator;
222
- export function applyBeforeBeginNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
223
- export function applyBeforeBeginNode(selector: string, options?: ApplyNodeOptions): any {
224
- return applyNode(selector, { ...options, position: 'beforeBegin' });
225
- }
226
-
227
- /**
228
- * @applyAfterBeginNode - Prepend to target element
229
- */
230
- export function applyAfterBeginNode(selector: string): MethodDecorator;
231
- export function applyAfterBeginNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
232
- export function applyAfterBeginNode(selector: string, options?: ApplyNodeOptions): any {
233
- return applyNode(selector, { ...options, position: 'afterBegin' });
234
- }
235
-
236
- /**
237
- * @applyBeforeEndNode - Append to target element (default)
238
- */
239
- export function applyBeforeEndNode(selector: string): MethodDecorator;
240
- export function applyBeforeEndNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
241
- export function applyBeforeEndNode(selector: string, options?: ApplyNodeOptions): any {
242
- return applyNode(selector, { ...options, position: 'beforeEnd' });
243
- }
244
-
245
- /**
246
- * @applyAfterEndNode - Insert after target element
247
- */
248
- export function applyAfterEndNode(selector: string): MethodDecorator;
249
- export function applyAfterEndNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
250
- export function applyAfterEndNode(selector: string, options?: ApplyNodeOptions): any {
251
- return applyNode(selector, { ...options, position: 'afterEnd' });
252
- }
253
-
254
- /**
255
- * @applyReplaceNode - Replace entire target element
256
- */
257
- export function applyReplaceNode(selector: string): MethodDecorator;
258
- export function applyReplaceNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
259
- export function applyReplaceNode(selector: string, options?: ApplyNodeOptions): any {
260
- return applyNode(selector, { ...options, position: 'replace' });
261
- }
262
-
263
- /**
264
- * @applyReplaceChildrenNode - Replace all children of target element
265
- */
266
- export function applyReplaceChildrenNode(selector: string): MethodDecorator;
267
- export function applyReplaceChildrenNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
268
- export function applyReplaceChildrenNode(selector: string, options?: ApplyNodeOptions): any {
269
- return applyNode(selector, { ...options, position: 'replaceChildren' });
270
- }
271
-
272
- /**
273
- * @applyInnerHtmlNode - Set target's innerHTML
274
- */
275
- export function applyInnerHtmlNode(selector: string): MethodDecorator;
276
- export function applyInnerHtmlNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
277
- export function applyInnerHtmlNode(selector: string, options?: ApplyNodeOptions): any {
278
- return applyNode(selector, { ...options, position: 'innerHtml' });
279
- }
280
-
281
- /**
282
- * @applyInnerTextNode - Set target's innerText
283
- */
284
- export function applyInnerTextNode(selector: string): MethodDecorator;
285
- export function applyInnerTextNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
286
- export function applyInnerTextNode(selector: string, options?: ApplyNodeOptions): any {
287
- return applyNode(selector, { ...options, position: 'innerText' });
288
- }
289
-
290
- /**
291
- * @applyRemoveNode - Remove target element if truthy
292
- */
293
- export function applyRemoveNode(selector: string): MethodDecorator;
294
- export function applyRemoveNode(selector: string, options: ApplyNodeOptions): MethodDecorator;
295
- export function applyRemoveNode(selector: string, options?: ApplyNodeOptions): any {
296
- return applyNode(selector, { ...options, position: 'remove' });
297
- }
298
-
299
- // Host versions
300
-
301
- /**
302
- * @applyBeforeBeginNodeHost - Insert before :host
303
- */
304
- export function applyBeforeBeginNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;
305
- export function applyBeforeBeginNodeHost(): MethodDecorator;
306
- export function applyBeforeBeginNodeHost(options: ApplyNodeOptions): MethodDecorator;
307
- export function applyBeforeBeginNodeHost(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
308
- if (propertyKey !== undefined) {
309
- const decorator = applyNode(':host', { position: 'beforeBegin' });
310
- return decorator(targetOrOptions, propertyKey, descriptor);
311
- }
312
- return applyNode(':host', { ...(targetOrOptions as ApplyNodeOptions || {}), position: 'beforeBegin' });
313
- }
314
-
315
- /**
316
- * @applyAfterBeginNodeHost - Prepend to :host
317
- */export function applyAfterBeginNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyAfterBeginNodeHost(): MethodDecorator;
318
- export function applyAfterBeginNodeHost(options: ApplyNodeOptions): MethodDecorator;
319
- export function applyAfterBeginNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
320
- if (propertyKey !== undefined) {
321
- const decorator = applyNode(':host', { position: 'afterBegin' });
322
- return decorator(optionsOrTarget, propertyKey, descriptor);
323
- }
324
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'afterBegin' });
325
- }
326
-
327
- /**
328
- * @applyBeforeEndNodeHost - Append to :host
329
- */export function applyBeforeEndNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyBeforeEndNodeHost(): MethodDecorator;
330
- export function applyBeforeEndNodeHost(options: ApplyNodeOptions): MethodDecorator;
331
- export function applyBeforeEndNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
332
- if (propertyKey !== undefined) {
333
- const decorator = applyNode(':host', { position: 'beforeEnd' });
334
- return decorator(optionsOrTarget, propertyKey, descriptor);
335
- }
336
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'beforeEnd' });
164
+ if (propertyKey !== undefined) return applyNode(':host', { position: 'beforeEnd' })(targetOrOptions, propertyKey, descriptor);
165
+ const opt = targetOrOptions || {};
166
+ return applyNode(':host', { position: 'beforeEnd', ...opt });
337
167
  }
338
168
 
339
- /**
340
- * @applyAfterEndNodeHost - Insert after :host
341
- */export function applyAfterEndNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyAfterEndNodeHost(): MethodDecorator;
342
- export function applyAfterEndNodeHost(options: ApplyNodeOptions): MethodDecorator;
343
- export function applyAfterEndNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
344
- if (propertyKey !== undefined) {
345
- const decorator = applyNode(':host', { position: 'afterEnd' });
346
- return decorator(optionsOrTarget, propertyKey, descriptor);
347
- }
348
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'afterEnd' });
349
- }
350
-
351
- /**
352
- * @applyReplaceNodeHost - Replace :host
353
- */export function applyReplaceNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyReplaceNodeHost(): MethodDecorator;
354
- export function applyReplaceNodeHost(options: ApplyNodeOptions): MethodDecorator;
355
- export function applyReplaceNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
356
- if (propertyKey !== undefined) {
357
- const decorator = applyNode(':host', { position: 'replace' });
358
- return decorator(optionsOrTarget, propertyKey, descriptor);
359
- }
360
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'replace' });
361
- }
362
-
363
- /**
364
- * @applyReplaceChildrenNodeHost - Replace children of :host
365
- */export function applyReplaceChildrenNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyReplaceChildrenNodeHost(): MethodDecorator;
366
169
  export function applyReplaceChildrenNodeHost(options: ApplyNodeOptions): MethodDecorator;
367
- export function applyReplaceChildrenNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
368
- if (propertyKey !== undefined) {
369
- const decorator = applyNode(':host', { position: 'replaceChildren' });
370
- return decorator(optionsOrTarget, propertyKey, descriptor);
371
- }
372
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'replaceChildren' });
170
+ export function applyReplaceChildrenNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
171
+ export function applyReplaceChildrenNodeHost(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
172
+ if (propertyKey !== undefined) return applyNode(':host', { position: 'replaceChildren' })(targetOrOptions, propertyKey, descriptor);
173
+ const opt = targetOrOptions || {};
174
+ return applyNode(':host', { position: 'replaceChildren', ...opt });
373
175
  }
374
176
 
375
- /**
376
- * @applyInnerHtmlNodeHost - Set :host innerHTML
377
- */export function applyInnerHtmlNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyInnerHtmlNodeHost(): MethodDecorator;
378
177
  export function applyInnerHtmlNodeHost(options: ApplyNodeOptions): MethodDecorator;
379
- export function applyInnerHtmlNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
380
- if (propertyKey !== undefined) {
381
- const decorator = applyNode(':host', { position: 'innerHtml' });
382
- return decorator(optionsOrTarget, propertyKey, descriptor);
383
- }
384
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'innerHtml' });
178
+ export function applyInnerHtmlNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
179
+ export function applyInnerHtmlNodeHost(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
180
+ if (propertyKey !== undefined) return applyNode(':host', { position: 'innerHtml' })(targetOrOptions, propertyKey, descriptor);
181
+ const opt = targetOrOptions || {};
182
+ return applyNode(':host', { position: 'innerHtml', ...opt });
385
183
  }
386
184
 
387
- /**
388
- * @applyInnerTextNodeHost - Set :host innerText
389
- */export function applyInnerTextNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyInnerTextNodeHost(): MethodDecorator;
390
- export function applyInnerTextNodeHost(options: ApplyNodeOptions): MethodDecorator;
391
- export function applyInnerTextNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
392
- if (propertyKey !== undefined) {
393
- const decorator = applyNode(':host', { position: 'innerText' });
394
- return decorator(optionsOrTarget, propertyKey, descriptor);
395
- }
396
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'innerText' });
185
+ export function applyReplaceChildrenNode(selector: string, options: ApplyNodeOptions = {}): MethodDecorator {
186
+ return applyNode(selector, { ...options, position: 'replaceChildren' });
397
187
  }
398
188
 
399
- /**
400
- * @applyRemoveNodeHost - Remove :host if truthy
401
- */export function applyRemoveNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): any;export function applyRemoveNodeHost(): MethodDecorator;
402
- export function applyRemoveNodeHost(options: ApplyNodeOptions): MethodDecorator;
403
- export function applyRemoveNodeHost(optionsOrTarget?: ApplyNodeOptions | any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
404
- if (propertyKey !== undefined) {
405
- const decorator = applyNode(':host', { position: 'remove' });
406
- return decorator(optionsOrTarget, propertyKey, descriptor);
407
- }
408
- return applyNode(':host', { ...(optionsOrTarget as ApplyNodeOptions || {}), position: 'remove' });
189
+ export function applyInnerHtmlNode(selector: string, options: ApplyNodeOptions = {}): MethodDecorator {
190
+ return applyNode(selector, { ...options, position: 'innerHtml' });
409
191
  }
@@ -0,0 +1,128 @@
1
+ import { ReflectUtils } from '@dooboostore/core';
2
+ import { ensureInit } from './elementDefine';
3
+ import { SwcUtils } from '../utils/Utils';
4
+ import { SwcQueryOptions, HelperHostSet } from '../types';
5
+
6
+ export type StyleAction = 'set' | 'update' | 'remove';
7
+
8
+ export interface StyleApplyOptions extends SwcQueryOptions {}
9
+
10
+ export interface StyleApplyMetadata {
11
+ propertyKey: string | symbol;
12
+ selector: string;
13
+ action: StyleAction;
14
+ options: StyleApplyOptions;
15
+ }
16
+
17
+ export const STYLE_METADATA_KEY = Symbol.for('simple-web-component:style');
18
+
19
+ function createStyleDecorator(action: StyleAction) {
20
+ return (selector: string, options: StyleApplyOptions = {}): MethodDecorator => {
21
+ return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
22
+ const constructor = target.constructor;
23
+ let metaList = ReflectUtils.getOwnMetadata(STYLE_METADATA_KEY, constructor) as Map<string | symbol, StyleApplyMetadata>;
24
+ if (!metaList) {
25
+ metaList = new Map<string | symbol, StyleApplyMetadata>();
26
+ ReflectUtils.defineMetadata(STYLE_METADATA_KEY, metaList, constructor);
27
+ }
28
+ metaList.set(propertyKey, { propertyKey, selector, action, options });
29
+
30
+ const original = descriptor.value;
31
+ descriptor.value = async function (...args: any[]) {
32
+ ensureInit(this);
33
+ const res = await (original as any).apply(this, args);
34
+ if (res !== undefined) {
35
+ const win = (this as any).ownerDocument?.defaultView || window;
36
+ const host = this as unknown as HTMLElement;
37
+ const hostSet = { ...SwcUtils.getHelperAndHostSet(win, host), $this: this };
38
+ const r = options.root || 'auto';
39
+ const targetEls: HTMLElement[] = [];
40
+
41
+ const applyRoot = (t: any) => {
42
+ if (!t || !(t instanceof win.HTMLElement)) return;
43
+ targetEls.push(t);
44
+ };
45
+
46
+ if (selector === ':parentHost') applyRoot(hostSet.$parentHost);
47
+ else if (selector === ':appHost') applyRoot(hostSet.$appHost);
48
+ else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);
49
+ else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);
50
+ else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost);
51
+ else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost);
52
+ else if (selector === ':hosts') hostSet.$hosts.forEach(applyRoot);
53
+ else if (selector === ':appHosts') hostSet.$appHosts.forEach(applyRoot);
54
+ else if (selector === ':host' || !selector) applyRoot(host);
55
+ else {
56
+ const targetRoot = r === 'auto' ? (host.shadowRoot || host) : (r === 'shadow' ? host.shadowRoot : host);
57
+ if (targetRoot) {
58
+ const found = targetRoot.querySelectorAll(selector);
59
+ if (found) targetEls.push(...(Array.from(found) as HTMLElement[]));
60
+ }
61
+ }
62
+
63
+ targetEls.forEach(targetEl => {
64
+ const resolvedRes = typeof res === 'function' ? (res as any)(targetEl, hostSet) : res;
65
+
66
+ if (action === 'set' || action === 'update') {
67
+ if (action === 'set') targetEl.style.cssText = '';
68
+
69
+ if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {
70
+ Object.entries(resolvedRes as any).forEach(([prop, val]) => {
71
+ const finalVal = typeof val === 'function' ? val(targetEl, hostSet) : val;
72
+ if (finalVal === null || finalVal === undefined) {
73
+ targetEl.style.removeProperty(prop);
74
+ } else {
75
+ targetEl.style[prop as any] = String(finalVal);
76
+ }
77
+ });
78
+ } else if (typeof resolvedRes === 'string') {
79
+ targetEl.style.cssText = resolvedRes;
80
+ }
81
+ } else if (action === 'remove') {
82
+ if (typeof resolvedRes === 'object' && resolvedRes !== null && !Array.isArray(resolvedRes)) {
83
+ Object.entries(resolvedRes as any).forEach(([prop, val]) => {
84
+ const shouldRemove = typeof val === 'function' ? val(targetEl, hostSet) : !!val;
85
+ if (shouldRemove) {
86
+ targetEl.style.removeProperty(prop);
87
+ }
88
+ });
89
+ } else {
90
+ const props = Array.isArray(resolvedRes) ? resolvedRes : [resolvedRes];
91
+ props.forEach(p => targetEl.style.removeProperty(String(p)));
92
+ }
93
+ }
94
+ });
95
+ }
96
+ return res;
97
+ };
98
+ return descriptor;
99
+ };
100
+ };
101
+ }
102
+
103
+ export function applyStyle(selector: string, action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {
104
+ return createStyleDecorator(action)(selector, options);
105
+ }
106
+
107
+ export const setStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('set')(selector, options);
108
+ export const updateStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('update')(selector, options);
109
+ export const removeStyle = (selector: string, options: StyleApplyOptions = {}) => createStyleDecorator('remove')(selector, options);
110
+
111
+ // Host versions
112
+ export function applyStyleHost(action: StyleAction = 'update', options: StyleApplyOptions = {}): MethodDecorator {
113
+ return createStyleDecorator(action)(':host', options);
114
+ }
115
+ export const setStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('set')(':host', options);
116
+ export const updateStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('update')(':host', options);
117
+ export const removeStyleHost = (options: StyleApplyOptions = {}) => createStyleDecorator('remove')(':host', options);
118
+
119
+ export const findAllStyleMetadata = (target: any): Map<string | symbol, StyleApplyMetadata> => {
120
+ const result = new Map<string | symbol, StyleApplyMetadata>();
121
+ const maps = ReflectUtils.findAllMetadata<Map<string | symbol, StyleApplyMetadata>>(STYLE_METADATA_KEY, target);
122
+ maps.forEach(map => {
123
+ if (map instanceof Map) {
124
+ map.forEach((v, k) => result.set(k, v));
125
+ }
126
+ });
127
+ return result;
128
+ };