@dooboostore/simple-web-component 1.0.23 → 1.0.25

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 (149) hide show
  1. package/README.md +64 -3212
  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 +97 -109
  9. package/dist/cjs/decorators/applyNode.js.map +2 -2
  10. package/dist/cjs/decorators/applyStyle.js +135 -0
  11. package/dist/cjs/decorators/applyStyle.js.map +7 -0
  12. package/dist/cjs/decorators/attribute.js +24 -11
  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 +78 -3
  25. package/dist/cjs/decorators/query.js.map +2 -2
  26. package/dist/cjs/decorators/queryAll.js +78 -3
  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/index.js +4 -4
  33. package/dist/cjs/index.js.map +2 -2
  34. package/dist/cjs/utils/Utils.js +141 -2
  35. package/dist/cjs/utils/Utils.js.map +2 -2
  36. package/dist/esm/decorators/addEventListener.js +1 -1
  37. package/dist/esm/decorators/addEventListener.js.map +2 -2
  38. package/dist/esm/decorators/applyAttribute.js +129 -0
  39. package/dist/esm/decorators/applyAttribute.js.map +7 -0
  40. package/dist/esm/decorators/applyClass.js +145 -0
  41. package/dist/esm/decorators/applyClass.js.map +7 -0
  42. package/dist/esm/decorators/applyNode.js +97 -109
  43. package/dist/esm/decorators/applyNode.js.map +2 -2
  44. package/dist/esm/decorators/applyStyle.js +116 -0
  45. package/dist/esm/decorators/applyStyle.js.map +7 -0
  46. package/dist/esm/decorators/attribute.js +24 -11
  47. package/dist/esm/decorators/attribute.js.map +2 -2
  48. package/dist/esm/decorators/changedAttributeHost.js +1 -1
  49. package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
  50. package/dist/esm/decorators/elementDefine.js +14 -23
  51. package/dist/esm/decorators/elementDefine.js.map +2 -2
  52. package/dist/esm/decorators/emitCustomEvent.js +5 -2
  53. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  54. package/dist/esm/decorators/index.js +3 -3
  55. package/dist/esm/decorators/index.js.map +1 -1
  56. package/dist/esm/decorators/lifecycles.js +9 -9
  57. package/dist/esm/decorators/lifecycles.js.map +2 -2
  58. package/dist/esm/decorators/query.js +78 -3
  59. package/dist/esm/decorators/query.js.map +2 -2
  60. package/dist/esm/decorators/queryAll.js +78 -3
  61. package/dist/esm/decorators/queryAll.js.map +2 -2
  62. package/dist/esm/elements/SwcAppEngine.js +19 -4
  63. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  64. package/dist/esm/elements/SwcAppMixin.js +2 -0
  65. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  66. package/dist/esm/index.js +4 -4
  67. package/dist/esm/index.js.map +2 -2
  68. package/dist/esm/utils/Utils.js +141 -2
  69. package/dist/esm/utils/Utils.js.map +2 -2
  70. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +3191 -506
  71. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  72. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  73. package/dist/types/decorators/applyAttribute.d.ts +22 -0
  74. package/dist/types/decorators/applyAttribute.d.ts.map +1 -0
  75. package/dist/types/decorators/applyClass.d.ts +65 -0
  76. package/dist/types/decorators/applyClass.d.ts.map +1 -0
  77. package/dist/types/decorators/applyNode.d.ts +18 -104
  78. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  79. package/dist/types/decorators/applyStyle.d.ts +21 -0
  80. package/dist/types/decorators/applyStyle.d.ts.map +1 -0
  81. package/dist/types/decorators/attribute.d.ts +12 -14
  82. package/dist/types/decorators/attribute.d.ts.map +1 -1
  83. package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
  84. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  85. package/dist/types/decorators/emitCustomEvent.d.ts +1 -1
  86. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  87. package/dist/types/decorators/index.d.ts +3 -3
  88. package/dist/types/decorators/index.d.ts.map +1 -1
  89. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  90. package/dist/types/decorators/query.d.ts +68 -4
  91. package/dist/types/decorators/query.d.ts.map +1 -1
  92. package/dist/types/decorators/queryAll.d.ts +70 -1
  93. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  94. package/dist/types/elements/SwcAppEngine.d.ts +7 -0
  95. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  96. package/dist/types/elements/SwcAppMixin.d.ts +1 -1
  97. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  98. package/dist/types/index.d.ts +1 -2
  99. package/dist/types/index.d.ts.map +1 -1
  100. package/dist/types/utils/Utils.d.ts +49 -0
  101. package/dist/types/utils/Utils.d.ts.map +1 -1
  102. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +3191 -506
  103. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  104. package/package.json +3 -3
  105. package/src/decorators/addEventListener.ts +1 -1
  106. package/src/decorators/applyAttribute.ts +147 -0
  107. package/src/decorators/applyClass.ts +158 -0
  108. package/src/decorators/applyNode.ts +126 -225
  109. package/src/decorators/applyStyle.ts +128 -0
  110. package/src/decorators/attribute.ts +42 -43
  111. package/src/decorators/changedAttributeHost.ts +2 -2
  112. package/src/decorators/elementDefine.ts +18 -39
  113. package/src/decorators/emitCustomEvent.ts +6 -3
  114. package/src/decorators/index.ts +3 -3
  115. package/src/decorators/lifecycles.ts +9 -11
  116. package/src/decorators/query.ts +148 -6
  117. package/src/decorators/queryAll.ts +149 -3
  118. package/src/elements/SwcAppEngine.ts +32 -4
  119. package/src/elements/SwcAppMixin.ts +2 -0
  120. package/src/index.ts +6 -6
  121. package/src/utils/Utils.ts +146 -1
  122. package/dist/cjs/decorators/classList.js +0 -134
  123. package/dist/cjs/decorators/classList.js.map +0 -7
  124. package/dist/cjs/decorators/setAttribute.js +0 -111
  125. package/dist/cjs/decorators/setAttribute.js.map +0 -7
  126. package/dist/cjs/decorators/style.js +0 -114
  127. package/dist/cjs/decorators/style.js.map +0 -7
  128. package/dist/cjs/utils/TemplateUtils.js +0 -109
  129. package/dist/cjs/utils/TemplateUtils.js.map +0 -7
  130. package/dist/esm/decorators/classList.js +0 -115
  131. package/dist/esm/decorators/classList.js.map +0 -7
  132. package/dist/esm/decorators/setAttribute.js +0 -92
  133. package/dist/esm/decorators/setAttribute.js.map +0 -7
  134. package/dist/esm/decorators/style.js +0 -95
  135. package/dist/esm/decorators/style.js.map +0 -7
  136. package/dist/esm/utils/TemplateUtils.js +0 -90
  137. package/dist/esm/utils/TemplateUtils.js.map +0 -7
  138. package/dist/types/decorators/classList.d.ts +0 -61
  139. package/dist/types/decorators/classList.d.ts.map +0 -1
  140. package/dist/types/decorators/setAttribute.d.ts +0 -23
  141. package/dist/types/decorators/setAttribute.d.ts.map +0 -1
  142. package/dist/types/decorators/style.d.ts +0 -49
  143. package/dist/types/decorators/style.d.ts.map +0 -1
  144. package/dist/types/utils/TemplateUtils.d.ts +0 -59
  145. package/dist/types/utils/TemplateUtils.d.ts.map +0 -1
  146. package/src/decorators/classList.ts +0 -172
  147. package/src/decorators/setAttribute.ts +0 -113
  148. package/src/decorators/style.ts +0 -140
  149. package/src/utils/TemplateUtils.ts +0 -92
@@ -1,12 +1,22 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
2
  import { ensureInit, getElementConfig } from './elementDefine';
3
- import { SwcRootType } from '../types';
3
+ import { HelperHostSet, SwcRootType } from '../types';
4
+ import { SwcUtils } from "../utils/Utils";
4
5
 
5
6
  export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText' | 'remove';
6
7
 
7
8
  export interface ApplyNodeOptions {
8
9
  position?: ApplyNodePosition;
9
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;
10
20
  }
11
21
 
12
22
  export interface ApplyNodeMetadata {
@@ -15,7 +25,7 @@ export interface ApplyNodeMetadata {
15
25
  options: ApplyNodeOptions;
16
26
  }
17
27
 
18
- 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');
19
29
 
20
30
  const normalizeNodes = (res: any, doc: Document): Node[] => {
21
31
  const items = Array.isArray(res) ? res : [res];
@@ -25,37 +35,41 @@ const normalizeNodes = (res: any, doc: Document): Node[] => {
25
35
  });
26
36
  };
27
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
+
28
67
  /**
29
68
  * @applyNode decorator to surgically add/replace nodes to a target element.
30
- *
31
- * Usage examples:
32
- * @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
33
- * @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
34
- * @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
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
38
- *
39
- * Positions:
40
- * - 'beforeEnd' (default): Append at end of target
41
- * - 'afterBegin': Prepend at start of target
42
- * - 'beforeBegin': Insert before target
43
- * - 'afterEnd': Insert after target
44
- * - 'replace': Replace the entire target element
45
- * - 'replaceChildren': Replace all children of target element
46
- * - 'innerHtml': Set target's innerHTML
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)
55
69
  */
56
70
  export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
57
- return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
58
- const constructor = target.constructor;
71
+ return (targetObj: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
72
+ const constructor = targetObj.constructor;
59
73
  let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
60
74
  if (!metaList) {
61
75
  metaList = new Map<string | symbol, ApplyNodeMetadata>();
@@ -64,95 +78,71 @@ export function applyNode(selector: string, options: ApplyNodeOptions = { positi
64
78
  metaList.set(propertyKey, { propertyKey, selector, options });
65
79
 
66
80
  const original = descriptor.value;
67
- descriptor.value = async function (...args: any[]) {
81
+ descriptor.value = function (...args: any[]) {
68
82
  ensureInit(this);
69
- const res = await original.apply(this, args);
70
- if (res !== undefined) {
71
- const conf = getElementConfig(this);
72
- const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
73
- const currentDoc = currentWin.document;
74
-
75
- 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 = () => {
76
90
  const r = options.root || 'auto';
77
-
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
91
+ const applyRoot = (t: any) => {
92
+ if (!t) return t;
93
+ if (r === 'auto') return t.shadowRoot || t;
94
+ if (r === 'shadow') return t.shadowRoot;
95
+ if (r === 'light') return t;
96
+ if (r === 'all') return t.shadowRoot || t;
97
+ return t;
83
98
  };
84
99
 
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
- }
112
- } else {
113
- const targetRoot = getTargetRoot();
114
- targetEl = targetRoot ? targetRoot.querySelector(selector) : null;
115
- }
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 (targetEl) {
118
- const isShadowRoot = targetEl instanceof ShadowRoot;
119
- const nodes = normalizeNodes(res, currentDoc);
110
+ const targetEl = getTarget();
111
+ const res = original.apply(this, args);
120
112
 
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
- }
152
- }
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);
153
128
  }
129
+ };
130
+
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);
136
+ }
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;
154
145
  }
155
- return res;
156
146
  };
157
147
  };
158
148
  }
@@ -168,123 +158,34 @@ export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, Appl
168
158
  return result;
169
159
  };
170
160
 
171
- /**
172
- * @applyNodeHost decorator - simplified version of @applyNode for :host selector
173
- * Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
174
- * Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
175
- */
176
- export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
177
- return applyNode(':host', options);
161
+ export function applyNodeHost(options: ApplyNodeOptions): MethodDecorator;
162
+ export function applyNodeHost(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): void;
163
+ export function applyNodeHost(targetOrOptions?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
164
+ if (propertyKey !== undefined) return applyNode(':host', { position: 'beforeEnd' })(targetOrOptions, propertyKey, descriptor);
165
+ const opt = targetOrOptions || {};
166
+ return applyNode(':host', { position: 'beforeEnd', ...opt });
178
167
  }
179
168
 
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' });
169
+ export function applyReplaceChildrenNodeHost(options: ApplyNodeOptions): MethodDecorator;
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 });
175
+ }
273
176
 
274
- /**
275
- * @applyInnerHtmlNodeHost - Set :host innerHTML
276
- */
277
- export const applyInnerHtmlNodeHost = (options: ApplyNodeOptions = {}) =>
278
- applyNode(':host', { ...options, position: 'innerHtml' });
177
+ export function applyInnerHtmlNodeHost(options: ApplyNodeOptions): MethodDecorator;
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 });
183
+ }
279
184
 
280
- /**
281
- * @applyInnerTextNodeHost - Set :host innerText
282
- */
283
- export const applyInnerTextNodeHost = (options: ApplyNodeOptions = {}) =>
284
- applyNode(':host', { ...options, position: 'innerText' });
185
+ export function applyReplaceChildrenNode(selector: string, options: ApplyNodeOptions = {}): MethodDecorator {
186
+ return applyNode(selector, { ...options, position: 'replaceChildren' });
187
+ }
285
188
 
286
- /**
287
- * @applyRemoveNodeHost - Remove :host if truthy
288
- */
289
- export const applyRemoveNodeHost = (options: ApplyNodeOptions = {}) =>
290
- applyNode(':host', { ...options, position: 'remove' });
189
+ export function applyInnerHtmlNode(selector: string, options: ApplyNodeOptions = {}): MethodDecorator {
190
+ return applyNode(selector, { ...options, position: 'innerHtml' });
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
+ };