@dooboostore/simple-web-component 1.0.32 → 1.0.34

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 (143) hide show
  1. package/README.md +280 -43
  2. package/dist/cjs/decorators/addEventListener.js.map +1 -1
  3. package/dist/cjs/decorators/applyAttribute.js +67 -57
  4. package/dist/cjs/decorators/applyAttribute.js.map +2 -2
  5. package/dist/cjs/decorators/applyClass.js +80 -70
  6. package/dist/cjs/decorators/applyClass.js.map +2 -2
  7. package/dist/cjs/decorators/applyNode.js +1 -8
  8. package/dist/cjs/decorators/applyNode.js.map +2 -2
  9. package/dist/cjs/decorators/applyStyle.js +66 -56
  10. package/dist/cjs/decorators/applyStyle.js.map +2 -2
  11. package/dist/cjs/decorators/attribute.js +35 -29
  12. package/dist/cjs/decorators/attribute.js.map +2 -2
  13. package/dist/cjs/decorators/changedAttributeHost.js +32 -12
  14. package/dist/cjs/decorators/changedAttributeHost.js.map +2 -2
  15. package/dist/cjs/decorators/elementDefine.js +29 -16
  16. package/dist/cjs/decorators/elementDefine.js.map +2 -2
  17. package/dist/cjs/decorators/emitCustomEvent.js +57 -44
  18. package/dist/cjs/decorators/emitCustomEvent.js.map +2 -2
  19. package/dist/cjs/decorators/index.js +3 -1
  20. package/dist/cjs/decorators/index.js.map +2 -2
  21. package/dist/cjs/decorators/publishSwcAppMessage.js +86 -0
  22. package/dist/cjs/decorators/publishSwcAppMessage.js.map +7 -0
  23. package/dist/cjs/decorators/setProperty.js +50 -39
  24. package/dist/cjs/decorators/setProperty.js.map +2 -2
  25. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js +62 -0
  26. package/dist/cjs/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
  27. package/dist/cjs/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +16 -16
  28. package/dist/cjs/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
  29. package/dist/cjs/elements/SwcAppEngine.js +7 -7
  30. package/dist/cjs/elements/SwcAppEngine.js.map +3 -3
  31. package/dist/cjs/elements/SwcAppMixin.js +90 -43
  32. package/dist/cjs/elements/SwcAppMixin.js.map +2 -2
  33. package/dist/cjs/elements/SwcChoose.js +19 -15
  34. package/dist/cjs/elements/SwcChoose.js.map +2 -2
  35. package/dist/cjs/elements/register.js +21 -16
  36. package/dist/cjs/elements/register.js.map +2 -2
  37. package/dist/cjs/types.js.map +1 -1
  38. package/dist/cjs/utils/Utils.js +7 -3
  39. package/dist/cjs/utils/Utils.js.map +2 -2
  40. package/dist/esm/decorators/addEventListener.js.map +1 -1
  41. package/dist/esm/decorators/applyAttribute.js +67 -57
  42. package/dist/esm/decorators/applyAttribute.js.map +2 -2
  43. package/dist/esm/decorators/applyClass.js +80 -70
  44. package/dist/esm/decorators/applyClass.js.map +2 -2
  45. package/dist/esm/decorators/applyNode.js +1 -8
  46. package/dist/esm/decorators/applyNode.js.map +2 -2
  47. package/dist/esm/decorators/applyStyle.js +66 -56
  48. package/dist/esm/decorators/applyStyle.js.map +2 -2
  49. package/dist/esm/decorators/attribute.js +35 -29
  50. package/dist/esm/decorators/attribute.js.map +2 -2
  51. package/dist/esm/decorators/changedAttributeHost.js +32 -12
  52. package/dist/esm/decorators/changedAttributeHost.js.map +2 -2
  53. package/dist/esm/decorators/elementDefine.js +30 -17
  54. package/dist/esm/decorators/elementDefine.js.map +2 -2
  55. package/dist/esm/decorators/emitCustomEvent.js +57 -44
  56. package/dist/esm/decorators/emitCustomEvent.js.map +2 -2
  57. package/dist/esm/decorators/index.js +3 -1
  58. package/dist/esm/decorators/index.js.map +2 -2
  59. package/dist/esm/decorators/publishSwcAppMessage.js +67 -0
  60. package/dist/esm/decorators/publishSwcAppMessage.js.map +7 -0
  61. package/dist/esm/decorators/setProperty.js +50 -39
  62. package/dist/esm/decorators/setProperty.js.map +2 -2
  63. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js +43 -0
  64. package/dist/esm/decorators/subscribeSwcAppMessageWhileConnected.js.map +7 -0
  65. package/dist/esm/decorators/{subscribeSwcAppRouteChange.js → subscribeSwcAppRouteChangeWhileConnected.js} +13 -13
  66. package/dist/esm/decorators/subscribeSwcAppRouteChangeWhileConnected.js.map +7 -0
  67. package/dist/esm/elements/SwcAppEngine.js +6 -6
  68. package/dist/esm/elements/SwcAppEngine.js.map +2 -2
  69. package/dist/esm/elements/SwcAppMixin.js +90 -43
  70. package/dist/esm/elements/SwcAppMixin.js.map +2 -2
  71. package/dist/esm/elements/SwcChoose.js +20 -16
  72. package/dist/esm/elements/SwcChoose.js.map +2 -2
  73. package/dist/esm/elements/register.js +22 -17
  74. package/dist/esm/elements/register.js.map +2 -2
  75. package/dist/esm/types.js.map +1 -1
  76. package/dist/esm/utils/Utils.js +7 -3
  77. package/dist/esm/utils/Utils.js.map +2 -2
  78. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js +543 -348
  79. package/dist/esm-bundle/dooboostore-simple-web-component.esm.js.map +4 -4
  80. package/dist/types/decorators/addEventListener.d.ts +4 -1
  81. package/dist/types/decorators/addEventListener.d.ts.map +1 -1
  82. package/dist/types/decorators/applyAttribute.d.ts +5 -1
  83. package/dist/types/decorators/applyAttribute.d.ts.map +1 -1
  84. package/dist/types/decorators/applyClass.d.ts +4 -0
  85. package/dist/types/decorators/applyClass.d.ts.map +1 -1
  86. package/dist/types/decorators/applyNode.d.ts +4 -1
  87. package/dist/types/decorators/applyNode.d.ts.map +1 -1
  88. package/dist/types/decorators/applyStyle.d.ts +5 -1
  89. package/dist/types/decorators/applyStyle.d.ts.map +1 -1
  90. package/dist/types/decorators/attribute.d.ts +5 -0
  91. package/dist/types/decorators/attribute.d.ts.map +1 -1
  92. package/dist/types/decorators/changedAttributeHost.d.ts +13 -3
  93. package/dist/types/decorators/changedAttributeHost.d.ts.map +1 -1
  94. package/dist/types/decorators/elementDefine.d.ts +1 -0
  95. package/dist/types/decorators/elementDefine.d.ts.map +1 -1
  96. package/dist/types/decorators/emitCustomEvent.d.ts +5 -1
  97. package/dist/types/decorators/emitCustomEvent.d.ts.map +1 -1
  98. package/dist/types/decorators/index.d.ts +3 -1
  99. package/dist/types/decorators/index.d.ts.map +1 -1
  100. package/dist/types/decorators/publishSwcAppMessage.d.ts +13 -0
  101. package/dist/types/decorators/publishSwcAppMessage.d.ts.map +1 -0
  102. package/dist/types/decorators/setProperty.d.ts +5 -1
  103. package/dist/types/decorators/setProperty.d.ts.map +1 -1
  104. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts +16 -0
  105. package/dist/types/decorators/subscribeSwcAppMessageWhileConnected.d.ts.map +1 -0
  106. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts +18 -0
  107. package/dist/types/decorators/subscribeSwcAppRouteChangeWhileConnected.d.ts.map +1 -0
  108. package/dist/types/elements/SwcAppEngine.d.ts +6 -3
  109. package/dist/types/elements/SwcAppEngine.d.ts.map +1 -1
  110. package/dist/types/elements/SwcAppMixin.d.ts +8 -3
  111. package/dist/types/elements/SwcAppMixin.d.ts.map +1 -1
  112. package/dist/types/elements/register.d.ts.map +1 -1
  113. package/dist/types/types.d.ts +6 -0
  114. package/dist/types/types.d.ts.map +1 -1
  115. package/dist/types/utils/Utils.d.ts.map +1 -1
  116. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js +543 -348
  117. package/dist/umd-bundle/dooboostore-simple-web-component.umd.js.map +4 -4
  118. package/package.json +4 -4
  119. package/src/decorators/addEventListener.ts +1 -1
  120. package/src/decorators/applyAttribute.ts +74 -61
  121. package/src/decorators/applyClass.ts +91 -77
  122. package/src/decorators/applyNode.ts +3 -12
  123. package/src/decorators/applyStyle.ts +75 -61
  124. package/src/decorators/attribute.ts +55 -43
  125. package/src/decorators/changedAttributeHost.ts +47 -14
  126. package/src/decorators/elementDefine.ts +38 -19
  127. package/src/decorators/emitCustomEvent.ts +65 -49
  128. package/src/decorators/index.ts +3 -1
  129. package/src/decorators/publishSwcAppMessage.ts +100 -0
  130. package/src/decorators/setProperty.ts +58 -44
  131. package/src/decorators/subscribeSwcAppMessageWhileConnected.ts +73 -0
  132. package/src/decorators/subscribeSwcAppRouteChangeWhileConnected.ts +71 -0
  133. package/src/elements/SwcAppEngine.ts +11 -12
  134. package/src/elements/SwcAppMixin.ts +115 -44
  135. package/src/elements/SwcChoose.ts +28 -7
  136. package/src/elements/register.ts +28 -7
  137. package/src/types.ts +8 -0
  138. package/src/utils/Utils.ts +15 -5
  139. package/dist/cjs/decorators/subscribeSwcAppRouteChange.js.map +0 -7
  140. package/dist/esm/decorators/subscribeSwcAppRouteChange.js.map +0 -7
  141. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts +0 -18
  142. package/dist/types/decorators/subscribeSwcAppRouteChange.d.ts.map +0 -1
  143. package/src/decorators/subscribeSwcAppRouteChange.ts +0 -71
@@ -1,7 +1,7 @@
1
- import {ReflectUtils, FunctionUtils, ActionExpression} from '@dooboostore/core';
2
- import {ensureInit, getElementConfig} from './elementDefine';
3
- import {SwcUtils} from '../utils/Utils';
4
- import {SpecialSelector, SwcQueryOptions} from '../types';
1
+ import { ReflectUtils, FunctionUtils, ActionExpression } from '@dooboostore/core';
2
+ import { ensureInit, getElementConfig } from './elementDefine';
3
+ import { SwcUtils } from '../utils/Utils';
4
+ import { SpecialSelector, SwcQueryOptions } from '../types';
5
5
  import { ConvertUtils } from '@dooboostore/core-web';
6
6
  export interface AttributeFieldOptions extends SwcQueryOptions {
7
7
  name?: string;
@@ -25,6 +25,44 @@ const convertValue = (val: string | null, type: any): any => {
25
25
  return val;
26
26
  };
27
27
 
28
+ export { convertValue };
29
+
30
+ export const getAttributeValue = (inst: any, attrName: string, options?: AttributeFieldOptions & { selector?: string }): any => {
31
+ const conf = getElementConfig(inst);
32
+ const currentWin = inst._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
33
+
34
+ // If selector is not provided, use inst itself
35
+ const targets = options?.selector ? resolveTargetEls(inst, options.selector, options, currentWin) : [inst];
36
+
37
+ const primaryTarget = targets[0];
38
+
39
+ if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function' && (primaryTarget as any).hasAttribute(attrName)) {
40
+ let domVal = (primaryTarget as any).getAttribute(attrName);
41
+
42
+ // 표현식 체크
43
+ const ae = new ActionExpression(domVal);
44
+ const expr = ae.getFirstExpression('call-return');
45
+ if (expr) {
46
+ try {
47
+ const result = FunctionUtils.executeReturn({
48
+ script: ConvertUtils.decodeHtmlEntity(expr.script, currentWin.document),
49
+ context: inst,
50
+ args: SwcUtils.getHelperAndHostSet(currentWin, inst)
51
+ });
52
+ return convertValue(result, options?.type);
53
+ } catch (e) {
54
+ console.error(`[SWC] Failed to execute directive {{= ${expr.script} }}:`, e);
55
+ return convertValue(domVal, options?.type);
56
+ }
57
+ }
58
+
59
+ return convertValue(domVal, options?.type);
60
+ }
61
+
62
+ // If no target found, return null
63
+ return null;
64
+ };
65
+
28
66
  export const resolveTargetEls = (inst: any, selector: string, options: AttributeFieldOptions, currentWin: any): HTMLElement[] => {
29
67
  const r = options.root || 'auto';
30
68
  const results: HTMLElement[] = [];
@@ -89,7 +127,7 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
89
127
  metaList = [];
90
128
  ReflectUtils.defineMetadata(ATTRIBUTE_FIELD_METADATA_KEY, metaList, constructor);
91
129
  }
92
- metaList.push({propertyKey, selector, options, privateKey});
130
+ metaList.push({ propertyKey, selector, options, privateKey });
93
131
 
94
132
  const applySetAttribute = (inst: any, targets: HTMLElement[], attrName: string, nv: any) => {
95
133
  targets.forEach(it => {
@@ -111,45 +149,20 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
111
149
  // delete target[propertyKey];
112
150
 
113
151
  // const defineTarget = target instanceof Function ? target : (target as any).constructor;
114
-
152
+
115
153
  Object.defineProperty(target, propertyKey, {
116
154
  get(this: any) {
117
155
  const attrName = options.name || String(propertyKey);
118
- const conf = getElementConfig(this);
119
- const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
120
- const targetType = options.type || designType;
121
156
 
122
- const targets = resolveTargetEls(this, selector, options, currentWin);
123
- const primaryTarget = targets[0];
124
-
125
- if (primaryTarget && typeof (primaryTarget as any).hasAttribute === 'function') {
126
- if ((primaryTarget as any).hasAttribute(attrName)) {
127
- let domVal = (primaryTarget as any).getAttribute(attrName);
128
-
129
- // 표현식 체크
130
- const ae = new ActionExpression(domVal);
131
- const expr = ae.getFirstExpression('call-return');
132
- if (expr) {
133
- try {
134
- const result = FunctionUtils.executeReturn({
135
- script: ConvertUtils.decodeHtmlEntity(expr.script, currentWin.document),
136
- context: this,
137
- args: SwcUtils.getHelperAndHostSet(currentWin, this)
138
- });
139
- return convertValue(result, targetType);
140
- } catch (e) {
141
- console.error(`[SWC] Failed to execute directive {{= ${expr.script} }}:`, e);
142
- return convertValue(domVal, targetType);
143
- }
144
- }
145
-
146
- return convertValue(domVal, targetType);
147
- }
148
- return null;
149
- }
157
+ // Merge designType fallback into options once
158
+ const mergedOptions = {
159
+ ...options,
160
+ selector,
161
+ type: options.type || designType
162
+ };
150
163
 
151
- const data = convertValue(this[privateKey], targetType);
152
- return data;
164
+ const result = getAttributeValue(this, attrName, mergedOptions);
165
+ return result !== null ? result : this[privateKey];
153
166
  },
154
167
  set(this: any, nv: any) {
155
168
  // this[propertyKey] = nv;
@@ -158,7 +171,6 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
158
171
  const conf = getElementConfig(this);
159
172
  const currentWin = this._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as any);
160
173
 
161
-
162
174
  // if (!this.__swc_connected) {
163
175
  // this[privateKey] = nv;
164
176
  // return;
@@ -170,9 +182,9 @@ export function attribute(selector: string, options: AttributeFieldOptions = {})
170
182
  enumerable: true,
171
183
  configurable: true
172
184
  });
173
- } catch (err) {
174
- console.error('[SWC] defineProperty error:', err);
175
- }
185
+ } catch (err) {
186
+ console.error('[SWC] defineProperty error:', err);
187
+ }
176
188
  };
177
189
  }
178
190
 
@@ -2,34 +2,67 @@ import {ReflectUtils} from '@dooboostore/core';
2
2
 
3
3
  export const ON_ATTRIBUTE_CHANGED_METADATA_KEY = Symbol.for('simple-web-component:on-attribute-changed');
4
4
 
5
+ export interface ChangedAttributeHostOptions {
6
+ type?: typeof Number | typeof Boolean | typeof String;
7
+ }
8
+
9
+ export interface ChangedAttributeHostMetadata {
10
+ attributeName: string;
11
+ propertyKey: string | symbol;
12
+ options: ChangedAttributeHostOptions;
13
+ }
14
+
15
+ const convertValue = (val: any, type: any): any => {
16
+ if (val === null || val === undefined) return val;
17
+ if (type === Number) return Number(val);
18
+ if (type === Boolean) return val === 'false' || val === '0' ? false : true;
19
+ return val;
20
+ };
21
+
5
22
  /**
6
23
  * @changedAttributeHost decorator - fires when any attribute on :host changes
7
24
  * Usage: @changedAttributeHost('data-product-id')
25
+ * @changedAttributeHost('count', { type: Number })
8
26
  */
9
- export function changedAttributeHost(attributeName?: string): MethodDecorator {
27
+ export function changedAttributeHost(attributeName?: string, options: ChangedAttributeHostOptions = {}): MethodDecorator {
10
28
  return (target: Object, propertyKey: string | symbol) => {
11
29
  const constructor = target.constructor;
12
- let meta = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as Map<string, (string | symbol)[]>;
13
- if (!meta) {
14
- meta = new Map<string, (string | symbol)[]>();
15
- ReflectUtils.defineMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, meta, constructor);
30
+ let metaList = ReflectUtils.getOwnMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) as ChangedAttributeHostMetadata[];
31
+ if (!metaList) {
32
+ metaList = [];
33
+ ReflectUtils.defineMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, metaList, constructor);
16
34
  }
17
35
 
18
36
  const name = attributeName || String(propertyKey);
19
- let methods = meta.get(name);
20
- if (!methods) {
21
- methods = [];
22
- meta.set(name, methods);
23
- }
24
- if (!methods.includes(propertyKey)) methods.push(propertyKey);
37
+ metaList.push({
38
+ attributeName: name,
39
+ propertyKey,
40
+ options
41
+ });
25
42
  };
26
43
  }
27
44
 
28
- export const getChangedAttributeMetadata = (target: any): Map<string, (string | symbol)[]> | undefined => {
45
+ export const getChangedAttributeMetadata = (target: any): ChangedAttributeHostMetadata[] | undefined => {
29
46
  const constructor = target instanceof Function ? target : target.constructor;
30
47
  return ReflectUtils.getMetadata(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor);
31
48
  };
32
49
 
33
- export const findAllAttributeChangedMetadata = (target: any): Map<string, (string | symbol)[]> => {
34
- return ReflectUtils.findAllMapMetadata<string, string | symbol>(ON_ATTRIBUTE_CHANGED_METADATA_KEY, target);
50
+ export const findAllAttributeChangedMetadata = (target: any): Map<string, ChangedAttributeHostMetadata[]> => {
51
+ const constructor = target instanceof Function ? target : target.constructor;
52
+ const metaList = ReflectUtils.findAllMetadata<ChangedAttributeHostMetadata[]>(ON_ATTRIBUTE_CHANGED_METADATA_KEY, constructor) || [];
53
+
54
+ const result = new Map<string, ChangedAttributeHostMetadata[]>();
55
+ metaList.forEach(meta => {
56
+ meta.forEach(item => {
57
+ if (!result.has(item.attributeName)) {
58
+ result.set(item.attributeName, []);
59
+ }
60
+ result.get(item.attributeName)!.push(item);
61
+ });
62
+ });
63
+ return result;
64
+ };
65
+
66
+ export const convertAttributeValue = (val: any, type?: typeof Number | typeof Boolean | typeof String): any => {
67
+ return convertValue(val, type);
35
68
  };
@@ -2,7 +2,7 @@ import { ReflectUtils, FunctionUtils, ActionExpression } from '@dooboostore/core
2
2
  import { getAddEventListenerMetadata } from './addEventListener';
3
3
  import { ON_INITIALIZE_METADATA_KEY, ON_BEFORE_CONNECTED_METADATA_KEY, ON_AFTER_CONNECTED_METADATA_KEY, ON_BEFORE_DISCONNECTED_METADATA_KEY, ON_AFTER_DISCONNECTED_METADATA_KEY, ON_BEFORE_ADOPTED_METADATA_KEY, ON_AFTER_ADOPTED_METADATA_KEY, findAllLifecycleMetadata, getOnConnectedInnerHtmlMetadata } from './lifecycles';
4
4
  import { getEmitCustomEventMetadataList } from './emitCustomEvent';
5
- import { findAllAttributeChangedMetadata } from './changedAttributeHost';
5
+ import { findAllAttributeChangedMetadata, convertAttributeValue } from './changedAttributeHost';
6
6
  import { findAllAttributeApplyMetadata } from './applyAttribute';
7
7
  import { findAllAttributeMetadata } from './attribute';
8
8
  import { getQueryMetadata } from './query';
@@ -22,6 +22,7 @@ export interface ElementConfig {
22
22
  observedAttributes?: string[];
23
23
  customElementRegistry?: any;
24
24
  window?: Window;
25
+ useShadow?: boolean | 'open' | 'closed';
25
26
  }
26
27
 
27
28
  export interface ElementMetadata extends Omit<ElementConfig, 'window'> {
@@ -125,8 +126,8 @@ const handleGlobalSwcEvent = async (event: Event) => {
125
126
  }
126
127
  };
127
128
 
128
- function buildEnv(configWindow?: Window) {
129
- const win: Window = configWindow || ((typeof window !== 'undefined' ? window : undefined) as any);
129
+ function buildEnv(configWindow: Window) {
130
+ const win: Window = configWindow;
130
131
  const doc: Document = win?.document;
131
132
  const builtInTagMap = new Map<any, string>();
132
133
  for (const [cls, tag] of HTML_TAG_ENTRIES) {
@@ -170,7 +171,7 @@ const setupPrototype = (proto: any) => {
170
171
  const aConf = getElementConfig(ancestors[i]);
171
172
  if (aConf?.window) return aConf.window;
172
173
  }
173
- return (typeof window !== 'undefined' ? window : undefined) as Window;
174
+ return getElementConfig(this).window ?? (typeof window !== 'undefined' ? window : undefined) as Window;
174
175
  };
175
176
 
176
177
  proto._invokeLifecycleMethod = function (methodName: string | symbol, hostSet?: HostSet, extraArgs: any[] = []) {
@@ -292,8 +293,15 @@ export const elementDefine =
292
293
  // const attributeListNames = attributeList.map(it => it.options.name || String(it.propertyKey));
293
294
  const hostAttributes = attributeList.filter(it => it.selector === ':host').map(it=>it.options.name || String(it.propertyKey));
294
295
 
296
+ const proto = constructor.prototype;
297
+
298
+ // Get original static observedAttributes before they're overwritten by Object.defineProperty
299
+ const originalStaticObservedAttributes = (constructor.observedAttributes ?? []) as string[];
300
+
301
+ // proto.observedAttributes??[];
295
302
  const mergedObservedAttributes = [...new Set([
296
303
  ...(metadata.observedAttributes ?? []),
304
+ ...originalStaticObservedAttributes,
297
305
  ...attrChangeMap.keys(),
298
306
  ...attributeApplyNames,
299
307
  ...hostAttributes,
@@ -304,7 +312,6 @@ export const elementDefine =
304
312
 
305
313
  const connectedInnerHtmlList = getOnConnectedInnerHtmlMetadata(constructor) || [];
306
314
 
307
- const proto = constructor.prototype;
308
315
  setupPrototype(proto);
309
316
 
310
317
  const originalConnected = proto.connectedCallback;
@@ -316,8 +323,10 @@ export const elementDefine =
316
323
  const conf = getElementConfig(this);
317
324
  const currentWin = (this as any)._resolveWindow(conf);
318
325
 
319
- if (connectedInnerHtmlList.some(it => it.options.useShadow === true) && !this.shadowRoot) {
320
- this.attachShadow({ mode: 'open' });
326
+ const shadowMode = conf?.useShadow || connectedInnerHtmlList.find(it => it.options.useShadow)?.options.useShadow;
327
+ if (shadowMode && !this.shadowRoot) {
328
+ const mode = shadowMode === true ? 'open' : shadowMode;
329
+ this.attachShadow({ mode: mode as ShadowRootMode });
321
330
  }
322
331
 
323
332
  (this as any)._executeSwcScript('swc-on-before-connected', hostSet);
@@ -335,12 +344,16 @@ export const elementDefine =
335
344
  // console.log('------res0', res);
336
345
  // console.log('------res1', res1);
337
346
  if (res !== undefined) {
338
- if (meta.options.useShadow) sContent += res;
347
+ if (meta.options.useShadow || conf?.useShadow) sContent += res;
339
348
  else lContent += res;
340
349
  }
341
350
  }
342
- if (this.shadowRoot) this.shadowRoot.innerHTML = sContent;
343
- if (lContent) this.innerHTML = lContent;
351
+ try {
352
+ if (this.shadowRoot) this.shadowRoot.innerHTML = sContent;
353
+ if (lContent) this.innerHTML = lContent;
354
+ } catch (e) {
355
+ console.error('[ElementDefine] innerHTML setting error:', e);
356
+ }
344
357
  }
345
358
 
346
359
  const root = this.getRootNode();
@@ -467,7 +480,7 @@ export const elementDefine =
467
480
  // Apply filter if specified
468
481
  if (options.filter) {
469
482
  const helper = SwcUtils.getHelperAndHostSet(currentWin, t as HTMLElement);
470
- if (!options.filter(event, helper)) {
483
+ if (!options.filter(event, {currentThis: this,helper})) {
471
484
  return; // Skip if filter returns false
472
485
  }
473
486
  }
@@ -564,21 +577,24 @@ export const elementDefine =
564
577
  const hSet = SwcUtils.getHostSet(this as any);
565
578
 
566
579
  // Process expression directive before passing to handlers
567
- let processedVal = newVal;
580
+ let processedVal: any = newVal;
568
581
  if (newVal !== null) {
569
582
  const ae = new ActionExpression(newVal);
570
583
  const expr = ae.getFirstExpression('call-return');
571
584
  if (expr) {
572
585
  const win = (this as any)._resolveWindow?.() || ((typeof window !== 'undefined' ? window : undefined) as any);
586
+ const helperAndHostSet = SwcUtils.getHelperAndHostSet(win,this as any);
573
587
  try {
588
+ const script = ConvertUtils.decodeHtmlEntity(expr.script, win.document);
574
589
  const result = FunctionUtils.executeReturn({
575
- script: ConvertUtils.decodeHtmlEntity(expr.script, win.document),
590
+ script: script,
576
591
  context: this,
577
- args: SwcUtils.getHelperAndHostSet(win,this as any)
592
+ args: helperAndHostSet
578
593
  });
579
- processedVal = String(result);
594
+ // Pass the result object directly without serialization
595
+ processedVal = result;
580
596
  } catch (e) {
581
- console.error(`[SWC] Failed to execute directive {{= ${expr.script} }} on attribute ${name}:`, e);
597
+ console.error(`[SWC] Failed to execute directive {{= ${expr.script} }} on attribute ${name}: ${helperAndHostSet}`, e);
582
598
  processedVal = newVal;
583
599
  }
584
600
  }
@@ -596,9 +612,12 @@ export const elementDefine =
596
612
  (this as any)._bindAttributeEvent(this as any, name, newVal, hostCustomEventMeta.type);
597
613
  }
598
614
 
599
- const mKeys = attrChangeMap.get(name);
600
- if (mKeys && Array.isArray(mKeys)) {
601
- for (const key of mKeys) (this as any)[key](processedVal, old, name, hSet);
615
+ const metaList = attrChangeMap.get(name);
616
+ if (metaList && Array.isArray(metaList)) {
617
+ for (const meta of metaList) {
618
+ const convertedVal = convertAttributeValue(processedVal, meta.options.type);
619
+ (this as any)[meta.propertyKey](convertedVal, old, name, hSet);
620
+ }
602
621
  }
603
622
  };
604
623
 
@@ -1,5 +1,5 @@
1
1
  import { ReflectUtils } from '@dooboostore/core';
2
- import { SpecialSelector, SwcQueryOptions } from '../types';
2
+ import { SpecialSelector, SwcQueryOptions, HelperHostSet } from '../types';
3
3
  import { ensureInit, getElementConfig } from './elementDefine';
4
4
  import { SwcUtils } from '../utils/Utils';
5
5
 
@@ -7,6 +7,7 @@ export interface EmitCustomEventBaseOptions {
7
7
  bubbles?: boolean;
8
8
  composed?: boolean;
9
9
  cancelable?: boolean;
10
+ filter?: (target: EventTarget, detail: any, meta: {currentThis: any, helper: HelperHostSet}) => boolean;
10
11
  }
11
12
 
12
13
  export interface EmitCustomEventMetadata {
@@ -39,59 +40,74 @@ export function emitCustomEvent(selectorOrTarget: string, type: string, options:
39
40
  list.push({ propertyKey, selector: selectorOrTarget, type, options: fullOptions });
40
41
 
41
42
  const original = descriptor.value;
42
- descriptor.value = async function (...args: any[]) {
43
+ descriptor.value = function (...args: any[]) {
43
44
  ensureInit(this);
44
- const detail = await original.apply(this, args);
45
- const event = new CustomEvent(type, {
46
- detail,
47
- bubbles: fullOptions.bubbles,
48
- composed: fullOptions.composed,
49
- cancelable: fullOptions.cancelable
50
- });
51
-
52
- const hostSet = SwcUtils.getHostSet(this as any);
53
- const conf = getElementConfig(this);
54
- const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
55
- // console.log('emitEEEEEEEEEEE', hostSet);
56
-
57
- const eventTargets: EventTarget[] = [];
58
- if (selectorOrTarget === ':window') eventTargets.push(currentWin);
59
- else if (selectorOrTarget === ':document') eventTargets.push(currentWin.document);
60
- else if (selectorOrTarget === ':parentHost') {
61
- if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
62
- } else if (selectorOrTarget === ':appHost') {
63
- if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
64
- } else if (selectorOrTarget === ':firstHost') {
65
- if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
66
- } else if (selectorOrTarget === ':lastHost') {
67
- if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
68
- } else if (selectorOrTarget === ':firstAppHost') {
69
- if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
70
- } else if (selectorOrTarget === ':lastAppHost') {
71
- if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
72
- } else if (selectorOrTarget === ':hosts') {
73
- hostSet.$hosts.forEach(h => eventTargets.push(h));
74
- } else if (selectorOrTarget === ':appHosts') {
75
- hostSet.$appHosts.forEach(h => eventTargets.push(h));
76
- } else if (selectorOrTarget === ':host' || !selectorOrTarget) eventTargets.push(this as any);
77
- else {
78
- const r = fullOptions.root || 'auto';
79
- const searchRoots: (HTMLElement | ShadowRoot)[] = [];
80
- if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
81
- else if (r === 'light') searchRoots.push(this as any);
82
- else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
83
- else if (r === 'all') {
84
- searchRoots.push(this as any);
85
- if (this.shadowRoot) searchRoots.push(this.shadowRoot);
45
+ const res = original.apply(this, args);
46
+
47
+ const handleResult = (detail: any) => {
48
+ const event = new CustomEvent(type, {
49
+ detail,
50
+ bubbles: fullOptions.bubbles,
51
+ composed: fullOptions.composed,
52
+ cancelable: fullOptions.cancelable
53
+ });
54
+
55
+ const hostSet = SwcUtils.getHostSet(this as any);
56
+ const conf = getElementConfig(this);
57
+ const currentWin = (this as any)._resolveWindow?.(conf) || ((typeof window !== 'undefined' ? window : undefined) as Window);
58
+
59
+ const eventTargets: EventTarget[] = [];
60
+ if (selectorOrTarget === ':window') eventTargets.push(currentWin);
61
+ else if (selectorOrTarget === ':document') eventTargets.push(currentWin.document);
62
+ else if (selectorOrTarget === ':parentHost') {
63
+ if (hostSet.$parentHost) eventTargets.push(hostSet.$parentHost);
64
+ } else if (selectorOrTarget === ':appHost') {
65
+ if (hostSet.$appHost) eventTargets.push(hostSet.$appHost);
66
+ } else if (selectorOrTarget === ':firstHost') {
67
+ if (hostSet.$firstHost) eventTargets.push(hostSet.$firstHost);
68
+ } else if (selectorOrTarget === ':lastHost') {
69
+ if (hostSet.$lastHost) eventTargets.push(hostSet.$lastHost);
70
+ } else if (selectorOrTarget === ':firstAppHost') {
71
+ if (hostSet.$firstAppHost) eventTargets.push(hostSet.$firstAppHost);
72
+ } else if (selectorOrTarget === ':lastAppHost') {
73
+ if (hostSet.$lastAppHost) eventTargets.push(hostSet.$lastAppHost);
74
+ } else if (selectorOrTarget === ':hosts') {
75
+ hostSet.$hosts.forEach(h => eventTargets.push(h));
76
+ } else if (selectorOrTarget === ':appHosts') {
77
+ hostSet.$appHosts.forEach(h => eventTargets.push(h));
78
+ } else if (selectorOrTarget === ':host' || !selectorOrTarget) {
79
+ eventTargets.push(this as any);
80
+ } else {
81
+ const r = fullOptions.root || 'auto';
82
+ const searchRoots: (HTMLElement | ShadowRoot)[] = [];
83
+ if (r === 'auto') searchRoots.push(this.shadowRoot || (this as any));
84
+ else if (r === 'light') searchRoots.push(this as any);
85
+ else if (r === 'shadow' && this.shadowRoot) searchRoots.push(this.shadowRoot);
86
+ else if (r === 'all') {
87
+ searchRoots.push(this as any);
88
+ if (this.shadowRoot) searchRoots.push(this.shadowRoot);
89
+ }
90
+
91
+ searchRoots.forEach(sr => {
92
+ sr.querySelectorAll(selectorOrTarget).forEach(el => eventTargets.push(el));
93
+ });
86
94
  }
87
95
 
88
- searchRoots.forEach(sr => {
89
- sr.querySelectorAll(selectorOrTarget).forEach(el => eventTargets.push(el));
96
+ eventTargets.forEach(t => {
97
+ if (fullOptions.filter && !fullOptions.filter(t, detail, {currentThis: this, helper: hostSet})) {
98
+ return;
99
+ }
100
+ t.dispatchEvent(event);
90
101
  });
91
- }
92
102
 
93
- eventTargets.forEach(t => t.dispatchEvent(event));
94
- return detail;
103
+ return detail;
104
+ };
105
+
106
+ if (res instanceof Promise) {
107
+ return res.then(handleResult);
108
+ } else {
109
+ return handleResult(res);
110
+ }
95
111
  };
96
112
  };
97
113
  }
@@ -11,4 +11,6 @@ export * from './applyClass';
11
11
  export * from './applyStyle';
12
12
  export * from './applyAttribute';
13
13
  export * from './setProperty';
14
- export * from './subscribeSwcAppRouteChange';
14
+ export * from './subscribeSwcAppRouteChangeWhileConnected';
15
+ export * from './subscribeSwcAppMessageWhileConnected';
16
+ export * from './publishSwcAppMessage';
@@ -0,0 +1,100 @@
1
+ import { ReflectUtils } from '@dooboostore/core';
2
+ import { SwcAppMessage } from '../types';
3
+ import { SwcUtils } from '../utils/Utils';
4
+
5
+ export const PUBLISH_SWC_APP_MESSAGE_METADATA_KEY = Symbol.for('simple-web-component:publish-swc-app-message');
6
+
7
+ export interface PublishSwcAppMessageMetadata {
8
+ propertyKey: string | symbol;
9
+ messageType?: string;
10
+ }
11
+
12
+ export interface PublishSwcAppMessageOptions {
13
+ messageType?: string;
14
+ }
15
+
16
+ function createPublishSwcAppMessage(messageType?: string): MethodDecorator {
17
+ return (target: Object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => {
18
+ const constructor = target.constructor;
19
+ let list = ReflectUtils.getOwnMetadata(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, constructor) as PublishSwcAppMessageMetadata[];
20
+ if (!list) {
21
+ list = [];
22
+ ReflectUtils.defineMetadata(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, list, constructor);
23
+ }
24
+ list.push({ propertyKey, messageType });
25
+
26
+ if (!descriptor) {
27
+ return descriptor;
28
+ }
29
+
30
+ // 메서드 래핑 - 원본 메서드의 반환값을 캡처하여 메시지 발행
31
+ const originalMethod = descriptor.value;
32
+ descriptor.value = function (...args: any[]) {
33
+ // 원본 메서드 실행
34
+ const result = originalMethod.apply(this, args);
35
+
36
+ // Promise 체크
37
+ if (result instanceof Promise) {
38
+ result.then((data) => {
39
+ // appHost 찾아서 메시지 발행
40
+ const appHost = SwcUtils.getAppHost(this as HTMLElement);
41
+ if (appHost) {
42
+ appHost.publishMessage({
43
+ publisher: this,
44
+ data,
45
+ type: messageType
46
+ });
47
+ }
48
+ }).catch((err) => {
49
+ console.warn('publishSwcAppMessage async error:', err);
50
+ });
51
+ } else {
52
+ // 동기 호출 - 바로 메시지 발행
53
+ const appHost = SwcUtils.getAppHost(this as HTMLElement);
54
+ if (appHost) {
55
+ appHost.publishMessage({
56
+ publisher: this,
57
+ data: result,
58
+ type: messageType
59
+ });
60
+ }
61
+ }
62
+
63
+ return result;
64
+ };
65
+
66
+ return descriptor;
67
+ };
68
+ }
69
+
70
+ // 오버로드 시그니처 - 직접 사용 (괄호 없음)
71
+ export function publishSwcAppMessage(target: Object, propertyKey: string | symbol, descriptor: PropertyDescriptor): PropertyDescriptor | void;
72
+ // 오버로드 시그니처 - 함수 호출 (괄호 있음)
73
+ export function publishSwcAppMessage(): MethodDecorator;
74
+ export function publishSwcAppMessage(messageType: string): MethodDecorator;
75
+
76
+ export function publishSwcAppMessage(targetOrMessageType?: any, propertyKey?: string | symbol, descriptor?: PropertyDescriptor): any {
77
+ // 직접 데코레이터로 사용된 경우 (괄호 없음): @publishSwcAppMessage
78
+ if (targetOrMessageType && typeof targetOrMessageType === 'object' &&
79
+ propertyKey && (typeof propertyKey === 'string' || typeof propertyKey === 'symbol') &&
80
+ descriptor) {
81
+ const target = targetOrMessageType;
82
+ return createPublishSwcAppMessage()(target, propertyKey, descriptor);
83
+ }
84
+
85
+ // 함수로 호출된 경우 (괄호 있음): @publishSwcAppMessage() / @publishSwcAppMessage('messageType')
86
+ let messageType: string | undefined;
87
+
88
+ if (typeof targetOrMessageType === 'string') {
89
+ // 메시지 타입 전달: @publishSwcAppMessage('messageType')
90
+ messageType = targetOrMessageType;
91
+ }
92
+
93
+ return createPublishSwcAppMessage(messageType);
94
+ }
95
+
96
+ // Helper function to retrieve publish message metadata
97
+ export const getPublishSwcAppMessageMetadata = (target: any): PublishSwcAppMessageMetadata[] | undefined => {
98
+ const constructor = target instanceof Function ? target : target.constructor;
99
+ return ReflectUtils.getOwnMetadata(PUBLISH_SWC_APP_MESSAGE_METADATA_KEY, constructor);
100
+ };