@dooboostore/simple-web-component 1.0.19 → 1.0.22

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 (174) hide show
  1. package/README.md +2759 -201
  2. package/dist/cjs/decorators/addEventListener.js +8 -4
  3. package/dist/cjs/decorators/addEventListener.js.map +2 -2
  4. package/dist/cjs/decorators/{appendChild.js → applyNode.js} +26 -18
  5. package/dist/cjs/decorators/applyNode.js.map +7 -0
  6. package/dist/cjs/decorators/attribute.js +162 -0
  7. package/dist/cjs/decorators/attribute.js.map +7 -0
  8. package/dist/cjs/decorators/{changedAttribute.js → changedAttributeHost.js} +11 -11
  9. package/dist/cjs/decorators/changedAttributeHost.js.map +7 -0
  10. package/dist/cjs/decorators/classList.js +15 -5
  11. package/dist/cjs/decorators/classList.js.map +2 -2
  12. package/dist/cjs/decorators/elementDefine.js +124 -46
  13. package/dist/cjs/decorators/elementDefine.js.map +3 -3
  14. package/dist/cjs/decorators/emitCustomEvent.js +8 -7
  15. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  16. package/dist/cjs/decorators/index.js +3 -3
  17. package/dist/cjs/decorators/index.js.map +2 -2
  18. package/dist/cjs/decorators/lifecycles.js +8 -4
  19. package/dist/cjs/decorators/lifecycles.js.map +2 -2
  20. package/dist/cjs/decorators/onConnectedInnerHtml.js +4 -4
  21. package/dist/cjs/decorators/onConnectedInnerHtml.js.map +2 -2
  22. package/dist/cjs/decorators/query.js +9 -5
  23. package/dist/cjs/decorators/query.js.map +2 -2
  24. package/dist/cjs/decorators/queryAll.js +9 -5
  25. package/dist/cjs/decorators/queryAll.js.map +2 -2
  26. package/dist/cjs/decorators/setAttribute.js +51 -21
  27. package/dist/cjs/decorators/setAttribute.js.map +2 -2
  28. package/dist/cjs/decorators/style.js +4 -4
  29. package/dist/cjs/decorators/style.js.map +2 -2
  30. package/dist/cjs/elements/SwcAppEngine.js +8 -8
  31. package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
  32. package/dist/cjs/elements/SwcAppMixin.js +28 -1
  33. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  34. package/dist/cjs/elements/SwcAsync.js +6 -6
  35. package/dist/cjs/elements/SwcAsync.js.map +2 -2
  36. package/dist/cjs/elements/SwcChoose.js +6 -6
  37. package/dist/cjs/elements/SwcChoose.js.map +2 -2
  38. package/dist/cjs/elements/SwcIf.js +6 -6
  39. package/dist/cjs/elements/SwcIf.js.map +2 -2
  40. package/dist/cjs/elements/SwcLoop.js +6 -6
  41. package/dist/cjs/elements/SwcLoop.js.map +2 -2
  42. package/dist/cjs/elements/register.js +19 -18
  43. package/dist/cjs/elements/register.js.map +2 -2
  44. package/dist/cjs/index.js +6 -17
  45. package/dist/cjs/index.js.map +2 -2
  46. package/dist/cjs/router/ElementRouter.js +7 -7
  47. package/dist/cjs/router/ElementRouter.js.map +2 -2
  48. package/dist/cjs/types.js.map +2 -2
  49. package/dist/esm/decorators/addEventListener.js +5 -1
  50. package/dist/esm/decorators/addEventListener.js.map +2 -2
  51. package/dist/esm/decorators/{appendChild.js → applyNode.js} +23 -15
  52. package/dist/esm/decorators/applyNode.js.map +7 -0
  53. package/dist/esm/decorators/attribute.js +143 -0
  54. package/dist/esm/decorators/attribute.js.map +7 -0
  55. package/dist/esm/decorators/{changedAttribute.js → changedAttributeHost.js} +4 -4
  56. package/dist/esm/decorators/changedAttributeHost.js.map +7 -0
  57. package/dist/esm/decorators/classList.js +12 -2
  58. package/dist/esm/decorators/classList.js.map +2 -2
  59. package/dist/esm/decorators/elementDefine.js +119 -41
  60. package/dist/esm/decorators/elementDefine.js.map +2 -2
  61. package/dist/esm/decorators/emitCustomEvent.js +5 -4
  62. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  63. package/dist/esm/decorators/index.js +3 -3
  64. package/dist/esm/decorators/index.js.map +1 -1
  65. package/dist/esm/decorators/lifecycles.js +5 -1
  66. package/dist/esm/decorators/lifecycles.js.map +2 -2
  67. package/dist/esm/decorators/onConnectedInnerHtml.js +1 -1
  68. package/dist/esm/decorators/onConnectedInnerHtml.js.map +1 -1
  69. package/dist/esm/decorators/query.js +6 -2
  70. package/dist/esm/decorators/query.js.map +2 -2
  71. package/dist/esm/decorators/queryAll.js +6 -2
  72. package/dist/esm/decorators/queryAll.js.map +2 -2
  73. package/dist/esm/decorators/setAttribute.js +47 -17
  74. package/dist/esm/decorators/setAttribute.js.map +2 -2
  75. package/dist/esm/decorators/style.js +1 -1
  76. package/dist/esm/decorators/style.js.map +1 -1
  77. package/dist/esm/elements/SwcAppEngine.js +4 -4
  78. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  79. package/dist/esm/elements/SwcAppMixin.js +28 -1
  80. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  81. package/dist/esm/elements/SwcAsync.js +3 -3
  82. package/dist/esm/elements/SwcAsync.js.map +2 -2
  83. package/dist/esm/elements/SwcChoose.js +3 -3
  84. package/dist/esm/elements/SwcChoose.js.map +2 -2
  85. package/dist/esm/elements/SwcIf.js +3 -3
  86. package/dist/esm/elements/SwcIf.js.map +2 -2
  87. package/dist/esm/elements/SwcLoop.js +3 -3
  88. package/dist/esm/elements/SwcLoop.js.map +2 -2
  89. package/dist/esm/elements/register.js +7 -6
  90. package/dist/esm/elements/register.js.map +2 -2
  91. package/dist/esm/index.js +6 -17
  92. package/dist/esm/index.js.map +2 -2
  93. package/dist/esm/router/ElementRouter.js +2 -2
  94. package/dist/esm/router/ElementRouter.js.map +1 -1
  95. package/dist/esm/types.js.map +2 -2
  96. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +5444 -3317
  97. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  98. package/dist/types/decorators/addEventListener.d.ts +6 -0
  99. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  100. package/dist/types/decorators/applyNode.d.ts +38 -0
  101. package/dist/types/decorators/applyNode.d.ts.map +1 -0
  102. package/dist/types/decorators/attribute.d.ts +29 -0
  103. package/dist/types/decorators/attribute.d.ts.map +1 -0
  104. package/dist/types/decorators/{changedAttribute.d.ts → changedAttributeHost.d.ts} +6 -2
  105. package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -0
  106. package/dist/types/decorators/classList.d.ts +25 -0
  107. package/dist/types/decorators/classList.d.ts.map +1 -1
  108. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  109. package/dist/types/decorators/emitCustomEvent.d.ts +14 -2
  110. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  111. package/dist/types/decorators/index.d.ts +3 -3
  112. package/dist/types/decorators/index.d.ts.map +1 -1
  113. package/dist/types/decorators/lifecycles.d.ts +2 -0
  114. package/dist/types/decorators/lifecycles.d.ts.map +1 -1
  115. package/dist/types/decorators/query.d.ts +6 -0
  116. package/dist/types/decorators/query.d.ts.map +1 -1
  117. package/dist/types/decorators/queryAll.d.ts +6 -0
  118. package/dist/types/decorators/queryAll.d.ts.map +1 -1
  119. package/dist/types/decorators/setAttribute.d.ts +8 -0
  120. package/dist/types/decorators/setAttribute.d.ts.map +1 -1
  121. package/dist/types/elements/SwcAppEngine.d.ts +5 -4
  122. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  123. package/dist/types/elements/SwcAppMixin.d.ts +1 -1
  124. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  125. package/dist/types/elements/register.d.ts +1 -1
  126. package/dist/types/elements/register.d.ts.map +1 -1
  127. package/dist/types/index.d.ts +3 -14
  128. package/dist/types/index.d.ts.map +1 -1
  129. package/dist/types/router/ElementRouter.d.ts +1 -1
  130. package/dist/types/router/ElementRouter.d.ts.map +1 -1
  131. package/dist/types/types.d.ts +3 -1
  132. package/dist/types/types.d.ts.map +1 -1
  133. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +5444 -3317
  134. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  135. package/package.json +10 -5
  136. package/src/decorators/addEventListener.ts +10 -1
  137. package/src/decorators/applyNode.ts +127 -0
  138. package/src/decorators/attribute.ts +192 -0
  139. package/src/decorators/{changedAttribute.ts → changedAttributeHost.ts} +6 -2
  140. package/src/decorators/classList.ts +33 -1
  141. package/src/decorators/elementDefine.ts +148 -47
  142. package/src/decorators/emitCustomEvent.ts +14 -6
  143. package/src/decorators/index.ts +3 -3
  144. package/src/decorators/lifecycles.ts +4 -2
  145. package/src/decorators/onConnectedInnerHtml.ts +1 -1
  146. package/src/decorators/query.ts +10 -1
  147. package/src/decorators/queryAll.ts +10 -1
  148. package/src/decorators/setAttribute.ts +57 -17
  149. package/src/decorators/style.ts +1 -1
  150. package/src/elements/SwcAppEngine.ts +10 -8
  151. package/src/elements/SwcAppMixin.ts +34 -2
  152. package/src/elements/SwcAsync.ts +3 -3
  153. package/src/elements/SwcChoose.ts +3 -3
  154. package/src/elements/SwcIf.ts +3 -3
  155. package/src/elements/SwcLoop.ts +3 -3
  156. package/src/elements/register.ts +8 -6
  157. package/src/index.ts +8 -16
  158. package/src/router/ElementRouter.ts +2 -2
  159. package/src/types.ts +3 -1
  160. package/dist/cjs/decorators/appendChild.js.map +0 -7
  161. package/dist/cjs/decorators/changedAttribute.js.map +0 -7
  162. package/dist/cjs/decorators/replaceChildren.js +0 -79
  163. package/dist/cjs/decorators/replaceChildren.js.map +0 -7
  164. package/dist/esm/decorators/appendChild.js.map +0 -7
  165. package/dist/esm/decorators/changedAttribute.js.map +0 -7
  166. package/dist/esm/decorators/replaceChildren.js +0 -60
  167. package/dist/esm/decorators/replaceChildren.js.map +0 -7
  168. package/dist/types/decorators/appendChild.d.ts +0 -17
  169. package/dist/types/decorators/appendChild.d.ts.map +0 -1
  170. package/dist/types/decorators/changedAttribute.d.ts.map +0 -1
  171. package/dist/types/decorators/replaceChildren.d.ts +0 -9
  172. package/dist/types/decorators/replaceChildren.d.ts.map +0 -1
  173. package/src/decorators/appendChild.ts +0 -86
  174. package/src/decorators/replaceChildren.ts +0 -64
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/simple-web-component",
3
- "version": "1.0.19",
3
+ "version": "1.0.22",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/index.js",
@@ -54,6 +54,11 @@
54
54
  "import": "./dist/esm/index.js",
55
55
  "require": "./dist/cjs/index.js"
56
56
  },
57
+ "./bundle-entry": {
58
+ "types": "./dist/types/bundle-entry.d.ts",
59
+ "import": "./dist/esm/bundle-entry.js",
60
+ "require": "./dist/cjs/bundle-entry.js"
61
+ },
57
62
  "./*": {
58
63
  "types": "./dist/types/*.d.ts",
59
64
  "import": "./dist/esm/*.js",
@@ -87,10 +92,10 @@
87
92
  "webpack": "^5.93.0",
88
93
  "webpack-cli": "^5.1.4",
89
94
  "webpack-dev-server": "^5.2.0",
90
- "@dooboostore/core": "1.0.28",
91
- "@dooboostore/core-node": "1.0.10",
92
- "@dooboostore/core-web": "1.0.9",
93
- "@dooboostore/simple-boot": "1.0.53"
95
+ "@dooboostore/core-web": "1.0.10",
96
+ "@dooboostore/core": "1.0.30",
97
+ "@dooboostore/core-node": "1.0.12",
98
+ "@dooboostore/simple-boot": "1.0.54"
94
99
  },
95
100
  "scripts": {
96
101
  "clean": "rm -rf dist",
@@ -1,4 +1,4 @@
1
- import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
1
+ import { ReflectUtils } from '@dooboostore/core';
2
2
  import { SpecialSelector, SwcQueryOptions } from '../types';
3
3
 
4
4
  export interface AddEventListenerBaseOptions extends EventListenerOptions {
@@ -44,3 +44,12 @@ export const getAddEventListenerMetadata = (target: any): AddEventListenerMetada
44
44
  const constructor = target instanceof Function ? target : target.constructor;
45
45
  return ReflectUtils.getMetadata(ADD_EVENT_LISTENER_METADATA_KEY, constructor);
46
46
  };
47
+
48
+ /**
49
+ * @addEventListenerHost decorator - simplified version of @addEventListener for :host selector
50
+ * Usage: @addEventListenerHost('click')
51
+ * Usage: @addEventListenerHost('click', { stopPropagation: true })
52
+ */
53
+ export function addEventListenerHost(type: string, options?: AddEventListenerBaseOptions & SwcQueryOptions): MethodDecorator {
54
+ return addEventListener(':host', type, options);
55
+ }
@@ -0,0 +1,127 @@
1
+ import { ReflectUtils } from '@dooboostore/core';
2
+ import { ensureInit, getElementConfig } from './elementDefine';
3
+
4
+ export type ApplyNodePosition = 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd' | 'replace' | 'replaceChildren' | 'innerHtml' | 'innerText';
5
+
6
+ export interface ApplyNodeOptions {
7
+ position?: ApplyNodePosition;
8
+ }
9
+
10
+ export interface ApplyNodeMetadata {
11
+ propertyKey: string | symbol;
12
+ selector: string;
13
+ options: ApplyNodeOptions;
14
+ }
15
+
16
+ export const APPLY_NODE_METADATA_KEY = Symbol('simple-web-component:apply-node');
17
+
18
+ const normalizeNodes = (res: any, doc: Document): Node[] => {
19
+ const items = Array.isArray(res) ? res : [res];
20
+ return items.map(it => {
21
+ if (it instanceof Node) return it;
22
+ return doc.createTextNode(it !== undefined && it !== null ? String(it) : '');
23
+ });
24
+ };
25
+
26
+ /**
27
+ * @applyNode decorator to surgically add/replace nodes to a target element.
28
+ *
29
+ * Usage examples:
30
+ * @applyNode('#list') addItem() { return '<li>New Item</li>'; } // append at end
31
+ * @applyNode('#header', { position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; } // prepend at start
32
+ * @applyNode('#item', { position: 'replace' }) replaceItem() { return '<div>Replaced</div>'; } // replace element
33
+ * @applyNode('#list', { position: 'replaceChildren' }) updateList() { return [item1, item2]; } // replace all children
34
+ *
35
+ * Positions:
36
+ * - 'beforeEnd' (default): Append at end of target
37
+ * - 'afterBegin': Prepend at start of target
38
+ * - 'beforeBegin': Insert before target
39
+ * - 'afterEnd': Insert after target
40
+ * - 'replace': Replace the entire target element
41
+ * - 'replaceChildren': Replace all children of target element
42
+ * - 'innerHtml': Set target's innerHTML
43
+ * - 'innerText': Set target's innerText
44
+ */
45
+ export function applyNode(selector: string, options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
46
+ return (target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
47
+ const constructor = target.constructor;
48
+ let metaList = ReflectUtils.getOwnMetadata(APPLY_NODE_METADATA_KEY, constructor) as Map<string | symbol, ApplyNodeMetadata>;
49
+ if (!metaList) {
50
+ metaList = new Map<string | symbol, ApplyNodeMetadata>();
51
+ ReflectUtils.defineMetadata(APPLY_NODE_METADATA_KEY, metaList, constructor);
52
+ }
53
+ metaList.set(propertyKey, { propertyKey, selector, options });
54
+
55
+ const original = descriptor.value;
56
+ descriptor.value = async function (...args: any[]) {
57
+ ensureInit(this);
58
+ const res = await original.apply(this, args);
59
+ if (res !== undefined) {
60
+ const conf = getElementConfig(this);
61
+ const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
62
+ const currentDoc = currentWin.document;
63
+
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
+ }
70
+
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) : '';
87
+ } 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);
101
+ }
102
+ }
103
+ }
104
+ return res;
105
+ };
106
+ };
107
+ }
108
+
109
+ export const findAllApplyNodeMetadata = (target: any): Map<string | symbol, ApplyNodeMetadata> => {
110
+ const result = new Map<string | symbol, ApplyNodeMetadata>();
111
+ const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ApplyNodeMetadata>>(APPLY_NODE_METADATA_KEY, target);
112
+ maps.forEach(map => {
113
+ if (map instanceof Map) {
114
+ map.forEach((v, k) => result.set(k, v));
115
+ }
116
+ });
117
+ return result;
118
+ };
119
+
120
+ /**
121
+ * @applyNodeHost decorator - simplified version of @applyNode for :host selector
122
+ * Usage: @applyNodeHost() addItem() { return '<li>New Item</li>'; }
123
+ * Usage: @applyNodeHost({ position: 'afterBegin' }) prependItem() { return '<h1>Title</h1>'; }
124
+ */
125
+ export function applyNodeHost(options: ApplyNodeOptions = { position: 'beforeEnd' }): MethodDecorator {
126
+ return applyNode(':host', options);
127
+ }
@@ -0,0 +1,192 @@
1
+ import { ReflectUtils } from '@dooboostore/core';
2
+ import { ensureInit, getElementConfig } from './elementDefine';
3
+ import { SwcUtils } from '../utils/Utils';
4
+ import { SpecialSelector, SwcQueryOptions } from '../types';
5
+
6
+ export interface AttributeOptions extends SwcQueryOptions {
7
+ name?: string;
8
+ connectedInitialize?: boolean;
9
+ type?: typeof Number | typeof Boolean | typeof String;
10
+ }
11
+
12
+ export interface AttributeMetadata {
13
+ propertyKey: string | symbol;
14
+ selector: string;
15
+ options: AttributeOptions;
16
+ privateKey: symbol; // Added to bypass getter during initialization
17
+ }
18
+
19
+ export const ATTRIBUTE_METADATA_KEY = Symbol('simple-web-component:attribute');
20
+
21
+ /**
22
+ * Helper to perform type conversion from string to target type
23
+ */
24
+ const convertValue = (val: string | null, type: any): any => {
25
+ if (val === null || val === undefined) return val;
26
+ if (type === Number) return Number(val);
27
+ if (type === Boolean) return val === 'false' || val === '0' ? false : true;
28
+ return val;
29
+ };
30
+
31
+ /**
32
+ * Helper to resolve target elements based on selector and root options
33
+ */
34
+ export const resolveTargetEls = (inst: any, selector: string, options: AttributeOptions, currentWin: any): HTMLElement[] => {
35
+ const r = options.root || 'auto';
36
+ const results: HTMLElement[] = [];
37
+
38
+ const applyRoot = (target: any) => {
39
+ if (!target) return;
40
+ if (r === 'auto') {
41
+ // Attributes belong to the ELEMENT, not the ShadowRoot.
42
+ // So for :host and direct attribute sync, we mostly want the element itself.
43
+ results.push(target);
44
+ } else {
45
+ if (r === 'light' || r === 'all') results.push(target);
46
+ if ((r === 'shadow' || r === 'all') && target.shadowRoot) results.push(target.shadowRoot);
47
+ }
48
+ };
49
+
50
+ if (selector === ':host' || !selector) {
51
+ applyRoot(inst);
52
+ } else if (selector === ':window') {
53
+ results.push(currentWin);
54
+ } else if (selector === ':document') {
55
+ results.push(currentWin.document);
56
+ } else {
57
+ const hostSet = SwcUtils.getHostSet(inst);
58
+ if (selector === ':parentHost') applyRoot(hostSet.$parentHost);
59
+ else if (selector === ':appHost') applyRoot(hostSet.$appHost as any);
60
+ else if (selector === ':firstHost') applyRoot(hostSet.$firstHost);
61
+ else if (selector === ':lastHost') applyRoot(hostSet.$lastHost);
62
+ else if (selector === ':firstAppHost') applyRoot(hostSet.$firstAppHost as any);
63
+ else if (selector === ':lastAppHost') applyRoot(hostSet.$lastAppHost as any);
64
+ else {
65
+ if (r === 'shadow') {
66
+ const found = inst.shadowRoot?.querySelectorAll(selector);
67
+ if (found) results.push(...found);
68
+ } else if (r === 'light') {
69
+ const found = inst.querySelectorAll(selector);
70
+ if (found) results.push(...found);
71
+ } else if (r === 'all') {
72
+ const sMatch = inst.shadowRoot?.querySelectorAll(selector);
73
+ const lMatch = inst.querySelectorAll(selector);
74
+ if (sMatch) results.push(...sMatch);
75
+ if (lMatch) results.push(...lMatch);
76
+ } else {
77
+ const found = (inst.shadowRoot || inst).querySelectorAll(selector);
78
+ if (found) results.push(...found);
79
+ }
80
+ }
81
+ }
82
+ return results;
83
+ };
84
+
85
+ /**
86
+ * @attribute decorator to sync a field value with an element's attribute.
87
+ */
88
+ export function attribute(selector: string, options: AttributeOptions = {}): PropertyDecorator {
89
+ return (target: Object, propertyKey: string | symbol) => {
90
+ const constructor = target.constructor;
91
+ const privateKey = Symbol(String(propertyKey));
92
+
93
+ const designType = (Reflect as any).getMetadata('design:type', target, propertyKey);
94
+
95
+ let metaList = ReflectUtils.getOwnMetadata(ATTRIBUTE_METADATA_KEY, constructor) as AttributeMetadata[];
96
+ if (!metaList) {
97
+ metaList = [];
98
+ ReflectUtils.defineMetadata(ATTRIBUTE_METADATA_KEY, metaList, constructor);
99
+ }
100
+ metaList.push({ propertyKey, selector, options, privateKey });
101
+
102
+ // Helper function to apply setAttribute to targets
103
+ const applySetAttribute = (inst: any, targets: HTMLElement[], attrName: string, nv: any) => {
104
+ targets.forEach(it => {
105
+ console.log('----->', it)
106
+ if (it && typeof (it as any).setAttribute === 'function') {
107
+ if (nv === null) {
108
+ (it as any).removeAttribute(attrName);
109
+ } else {
110
+ (it as any).setAttribute(attrName, String(nv));
111
+ }
112
+ } else {
113
+ inst[privateKey] = nv;
114
+ }
115
+ });
116
+ };
117
+
118
+ Object.defineProperty(target, propertyKey, {
119
+ get(this: any) {
120
+ const attrName = options.name || String(propertyKey);
121
+ const conf = getElementConfig(this);
122
+ const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
123
+ const targetType = options.type || designType;
124
+
125
+ console.log('type-->', propertyKey, targetType);
126
+ // During early init phase, if syncing memory to DOM, return memory.
127
+ if (this.__swc_syncing_init || (options.connectedInitialize && !this.__swc_connected)) {
128
+ return convertValue(this[privateKey], targetType);
129
+ }
130
+
131
+ const targets = resolveTargetEls(this, selector, options, currentWin);
132
+ const primaryTarget = targets[0];
133
+
134
+ if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function') {
135
+ if ((primaryTarget as any).hasAttribute(attrName)) {
136
+ const domVal = (primaryTarget as any).getAttribute(attrName);
137
+ return convertValue(domVal, targetType);
138
+ }
139
+ return null;
140
+ }
141
+
142
+ return convertValue(this[privateKey], targetType);
143
+ },
144
+ set(this: any, nv: any) {
145
+ const targetType = options.type || designType;
146
+ console.log('---set', propertyKey, targetType, nv, this, this.__swc_syncing_init);
147
+
148
+ const attrName = options.name || String(propertyKey);
149
+ const conf = getElementConfig(this);
150
+ const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
151
+
152
+ // During initialization/syncing phase
153
+ if (this.__swc_syncing_init) {
154
+ // If connectedInitialize is enabled, force setAttribute (JS -> DOM)
155
+ if (options.connectedInitialize === true) {
156
+ const targets = resolveTargetEls(this, selector, options, currentWin);
157
+ applySetAttribute(this, targets, attrName, nv);
158
+ } else {
159
+ // Otherwise just update memory
160
+ this[privateKey] = nv;
161
+ }
162
+ return;
163
+ }
164
+
165
+ // Before connected, save to memory only
166
+ if (!this.__swc_connected) {
167
+ this[privateKey] = nv;
168
+ return;
169
+ }
170
+
171
+ // After connected, normal setAttribute
172
+ const targets = resolveTargetEls(this, selector, options, currentWin);
173
+ applySetAttribute(this, targets, attrName, nv);
174
+ },
175
+ enumerable: true,
176
+ configurable: true
177
+ });
178
+ };
179
+ }
180
+
181
+ export const findAllAttributeMetadata = (target: any): AttributeMetadata[] => {
182
+ return ReflectUtils.findAllMetadata<AttributeMetadata[]>(ATTRIBUTE_METADATA_KEY, target).flat();
183
+ };
184
+
185
+ /**
186
+ * @hostAttribute decorator - simplified version of @attribute for :host selector
187
+ * Usage: @hostAttribute('data-product-id')
188
+ * Usage: @hostAttribute('disabled', { type: Boolean })
189
+ */
190
+ export function attributeHost(attrName: string, options: AttributeOptions = {}): PropertyDecorator {
191
+ return attribute(':host', { ...options, name: attrName });
192
+ }
@@ -1,8 +1,12 @@
1
- import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
1
+ import { ReflectUtils } from '@dooboostore/core';
2
2
 
3
3
  export const ON_ATTRIBUTE_CHANGED_METADATA_KEY = Symbol('simple-web-component:on-attribute-changed');
4
4
 
5
- export function changedAttribute(attributeName?: string): MethodDecorator {
5
+ /**
6
+ * @changedAttributeHost decorator - fires when any attribute on :host changes
7
+ * Usage: @changedAttributeHost('data-product-id')
8
+ */
9
+ export function changedAttributeHost(attributeName?: string): MethodDecorator {
6
10
  return (target: Object, propertyKey: string | symbol) => {
7
11
  const constructor = target.constructor;
8
12
  let meta = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as Map<string, (string | symbol)[]>;
@@ -1,4 +1,4 @@
1
- import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
1
+ import { ReflectUtils } from '@dooboostore/core';
2
2
  import { ensureInit } from './elementDefine';
3
3
  import { SwcUtils } from '../utils/Utils';
4
4
 
@@ -105,6 +105,38 @@ export const removeClassList = createClassListDecorator('remove');
105
105
  */
106
106
  export const toggleClassList = createClassListDecorator('toggle');
107
107
 
108
+ // Host-specific versions (for :host selector)
109
+
110
+ /**
111
+ * @setClassListHost decorator to set classes on :host element.
112
+ * Returns: string | string[]
113
+ */
114
+ export const setClassListHost = createClassListDecorator('set').bind(null, ':host');
115
+
116
+ /**
117
+ * @updateClassListHost decorator to update specific classes on :host.
118
+ * Returns: Record<string, boolean> (toggle with force) | string | string[] (add)
119
+ */
120
+ export const updateClassListHost = createClassListDecorator('update').bind(null, ':host');
121
+
122
+ /**
123
+ * @addClassListHost decorator to add classes to :host element.
124
+ * Returns: string | string[]
125
+ */
126
+ export const addClassListHost = createClassListDecorator('add').bind(null, ':host');
127
+
128
+ /**
129
+ * @removeClassListHost decorator to remove classes from :host element.
130
+ * Returns: string | string[]
131
+ */
132
+ export const removeClassListHost = createClassListDecorator('remove').bind(null, ':host');
133
+
134
+ /**
135
+ * @toggleClassListHost decorator to toggle classes on :host element.
136
+ * Returns: string | string[]
137
+ */
138
+ export const toggleClassListHost = createClassListDecorator('toggle').bind(null, ':host');
139
+
108
140
  export const findAllClassListMetadata = (target: any): Map<string | symbol, ClassListMetadata> => {
109
141
  const result = new Map<string | symbol, ClassListMetadata>();
110
142
  const maps = ReflectUtils.findAllMetadata<Map<string | symbol, ClassListMetadata>>(CLASS_LIST_METADATA_KEY, target);