@dooboostore/dom-render 1.0.100 → 1.0.102

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.
package/README.MD CHANGED
@@ -6,25 +6,25 @@ DOM-RENDER
6
6
  * all internal variables are managed by proxy. (DomRenderProxy)
7
7
 
8
8
  # 🚀 Quick start
9
- ```html
10
- <script src="https://cdn.jsdelivr.net/npm/dom-render@1.0.91/dist/bundle.js"></script>
9
+ ```typescript
10
+ import { DomRender } from '@dooboostore/dom-render';
11
+
12
+ class AppData {
13
+ name: string = 'my name is dom-render';
14
+ }
15
+
16
+ const data = new AppData();
17
+ DomRender.run(data, document.querySelector('#app')!);
11
18
  ```
12
19
  ```html
13
20
  <!DOCTYPE html>
14
21
  <html lang="en">
15
- <head``>
22
+ <head>
16
23
  <meta charset="UTF-8">
17
24
  <title>Title</title>
18
25
  </head>
19
26
  <body id="app">
20
27
  ${this.name}$
21
- <script src="https://cdn.jsdelivr.net/npm/dom-render@1.0.86/dist/bundle.js"></script>
22
- <script>
23
- let data = {
24
- name: 'my name is dom-render'
25
- };
26
- data = DomRender.run(data , document.querySelector('#app'));
27
- </script>
28
28
  </body>
29
29
  </html>
30
30
  ```
@@ -42,14 +42,18 @@ ${this.name}$
42
42
  <body id="app">
43
43
  ${this.name}$ <!-- outout: <i>my name is dom-render</i> -->
44
44
  #{this.name}# <!-- outout text is italic: my name is dom-render -->
45
- <script>
46
- let data = {
47
- name: '<i>my name is dom-render</i>'
48
- };
49
- data = DomRender.run(data , document.querySelector('#app'));
50
- </script>
51
45
  </body>
52
46
  ```
47
+ ```typescript
48
+ import { DomRender } from '@dooboostore/dom-render';
49
+
50
+ class AppData {
51
+ name: string = '<i>my name is dom-render</i>';
52
+ }
53
+
54
+ const data = new AppData();
55
+ DomRender.run(data, document.querySelector('#app')!);
56
+ ```
53
57
  </details>
54
58
 
55
59
  # dom-render attributes
@@ -141,14 +145,18 @@ uuid: rawSetUUID
141
145
  <body id="app">
142
146
  <div dr-if="true">true</div> <!-- render -->
143
147
  <div dr-if="this.gender === 'M'">gender: M</div> <!-- No Render -->
144
- <script>
145
- let data = {
146
- gender: 'F',
147
- };
148
- data = DomRender.run(data , document.querySelector('#app'));
149
- </script>
150
148
  </body>
151
149
  ```
150
+ ```typescript
151
+ import { DomRender } from '@dooboostore/dom-render';
152
+
153
+ class AppData {
154
+ gender: string = 'F';
155
+ }
156
+
157
+ const data = new AppData();
158
+ DomRender.run(data, document.querySelector('#app')!);
159
+ ```
152
160
  </details>
153
161
 
154
162
 
@@ -396,6 +404,7 @@ You can get a reference to DOM elements within your component's template using t
396
404
 
397
405
  - If the decorated property is **not an array type**, it returns the **first** matching element (like `querySelector`).
398
406
  - If the decorated property **is an array type** (e.g., `HTMLElement[]`), it returns **all** matching elements as an array (like `querySelectorAll`).
407
+ - When applied to a **method**, the method will be called with the queried element(s) as arguments after the component has been rendered. If the method expects a single element, the first match is passed. If it expects an array, all matches are passed.
399
408
 
400
409
  This is useful for directly accessing and manipulating elements you need to interact with from your component's logic.
401
410
 
@@ -428,6 +437,22 @@ export class MyComponent extends ComponentBase<{}> {
428
437
  });
429
438
  }
430
439
  }
440
+
441
+ // Method query: This method will be called with the first element matching '.my-button'
442
+ @query('.my-button')
443
+ private setupButton(button: HTMLButtonElement) {
444
+ if (button) {
445
+ button.addEventListener('click', () => alert('Button clicked from method query!'));
446
+ }
447
+ }
448
+
449
+ // Method query: This method will be called with an array of all elements matching 'span.item'
450
+ @query('span.item')
451
+ private processItems(spans: HTMLSpanElement[]) {
452
+ spans.forEach(span => {
453
+ span.style.fontWeight = 'bold';
454
+ });
455
+ }
431
456
  }
432
457
  ```
433
458
 
@@ -441,9 +466,11 @@ export class MyComponent extends ComponentBase<{}> {
441
466
  <li>Item 2</li>
442
467
  <li>Item 3</li>
443
468
  </ul>
469
+ <button class="my-button">Click Me</button>
470
+ <p><span class="item">First Span</span> <span class="item">Second Span</span></p>
444
471
  </div>
445
472
  ```
446
- The `@query` decorator will assign the corresponding element(s) to the decorated property. The property will be `null`/`undefined` (for single query) or an empty array (for multiple query) if no elements are found or before the component is rendered.
473
+ The `@query` decorator will assign the corresponding element(s) to the decorated property or pass them to the decorated method. The property will be `null`/`undefined` (for single query) or an empty array (for multiple query) if no elements are found or before the component is rendered. For methods, they will only be called if matching elements are found.
447
474
 
448
475
  </details>
449
476
 
@@ -637,16 +664,22 @@ dr-value-link: <input type="text" dr-value-link="@this@.office.addr.street"> <br
637
664
  age: <input name="age">
638
665
  <button type="submit">submit</button>
639
666
  </form>
640
- <script>
641
- let data = {
642
- form: {},
643
- submit() {
644
- console.log(this.form);
645
- }
646
- };
647
- data = DomRender.run(data , document.querySelector('#app'));
648
- </script>
649
667
  </body>
668
+ ```
669
+ ```typescript
670
+ import { DomRender } from '@dooboostore/dom-render';
671
+
672
+ class FormData {
673
+ form: any = {};
674
+
675
+ submit() {
676
+ console.log(this.form);
677
+ }
678
+ }
679
+
680
+ const data = new FormData();
681
+ DomRender.run(data, document.querySelector('#app')!);
682
+ ```
650
683
  <!-- 💥 submit call -->
651
684
  <!-- console: {name: 'name data', age: 'age data'} -->
652
685
  ```
@@ -662,24 +695,33 @@ dr-value-link: <input type="text" dr-value-link="@this@.office.addr.street"> <br
662
695
  age: <input name="age">
663
696
  <button type="submit">submit</button>
664
697
  </form>
665
- <script>
666
- const form = new FormValidator();
667
- form.name = new NotEmptyValidator();
668
- form.age = new NotEmptyValidator();
669
- let data = {
670
- form,
671
- submit() {
672
- if (this.form.valid()){
673
- console.log('valid');
674
- } else {
675
- console.log('inValid');
676
- }
677
- }
678
- };
679
- data = DomRender.run(data , document.querySelector('#app'));
680
- </script>
681
698
  </body>
682
699
  ```
700
+ ```typescript
701
+ import { DomRender } from '@dooboostore/dom-render';
702
+ import { FormValidator, NotEmptyValidator } from '@dooboostore/dom-render/validator';
703
+
704
+ class FormDataWithValidator {
705
+ form: FormValidator = new FormValidator();
706
+
707
+ constructor() {
708
+ this.form.name = new NotEmptyValidator();
709
+ this.form.age = new NotEmptyValidator();
710
+ }
711
+
712
+ submit() {
713
+ if (this.form.valid()){
714
+ console.log('valid');
715
+ } else {
716
+ console.log('inValid');
717
+ }
718
+ }
719
+ }
720
+
721
+ const data = new FormDataWithValidator();
722
+ DomRender.run(data, document.querySelector('#app')!);
723
+ ```
724
+ ```
683
725
  validator
684
726
  - Validator (abstract)
685
727
  - ValidatorArray (abstract)
@@ -16,7 +16,7 @@ export declare function attribute(options?: {
16
16
  name?: string;
17
17
  converter?: (value: string | null) => any;
18
18
  }): PropertyDecorator;
19
- export declare function query(selector: string): PropertyDecorator;
19
+ export declare function query(selector: string): (target: object, propertyKey: string | symbol, descriptor?: PropertyDescriptor) => void;
20
20
  export declare function event(options: {
21
21
  query: string;
22
22
  name: string;
@@ -8,32 +8,46 @@ var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
10
  import 'reflect-metadata';
11
+ import { ElementUtils } from '@dooboostore/core-web/element/ElementUtils';
11
12
  import { RawSet } from '../rawsets/RawSet';
12
13
  import { DomRenderNoProxy } from '../decorators/DomRenderNoProxy';
13
14
  import { ConvertUtils } from '@dooboostore/core/convert/ConvertUtils';
14
15
  import * as Render from '../rawsets/Render';
16
+ import { ReflectUtils } from '@dooboostore/core/reflect/ReflectUtils';
15
17
  export const ATTRIBUTE_METADATA_KEY = Symbol('attribute');
16
18
  export const QUERY_METADATA_KEY = Symbol('query');
17
19
  export const EVENT_METADATA_KEY = Symbol('event');
18
20
  export function attribute(options) {
19
21
  return (target, propertyKey) => {
20
- Reflect.defineMetadata(ATTRIBUTE_METADATA_KEY, Object.assign(Object.assign({}, options), { name: (options === null || options === void 0 ? void 0 : options.name) || propertyKey }), target, propertyKey);
22
+ const attributes = ReflectUtils.getMetadata(ATTRIBUTE_METADATA_KEY, target.constructor) || [];
23
+ attributes.push({
24
+ propertyKey: propertyKey,
25
+ name: (options === null || options === void 0 ? void 0 : options.name) || propertyKey,
26
+ converter: options === null || options === void 0 ? void 0 : options.converter
27
+ });
28
+ ReflectUtils.defineMetadata(ATTRIBUTE_METADATA_KEY, attributes, target.constructor);
21
29
  };
22
30
  }
23
31
  export function query(selector) {
24
- return (target, propertyKey) => {
25
- Reflect.defineMetadata(QUERY_METADATA_KEY, { selector }, target, propertyKey);
32
+ return (target, propertyKey, descriptor) => {
33
+ const queries = ReflectUtils.getMetadata(QUERY_METADATA_KEY, target.constructor) || [];
34
+ queries.push({
35
+ selector: selector,
36
+ propertyKey: propertyKey,
37
+ isMethod: !!descriptor
38
+ });
39
+ ReflectUtils.defineMetadata(QUERY_METADATA_KEY, queries, target.constructor);
26
40
  };
27
41
  }
28
42
  export function event(options) {
29
43
  return (target, propertyKey, descriptor) => {
30
- const events = Reflect.getMetadata(EVENT_METADATA_KEY, target.constructor) || [];
44
+ const events = ReflectUtils.getMetadata(EVENT_METADATA_KEY, target.constructor) || [];
31
45
  events.push({
32
46
  query: options.query,
33
47
  eventName: options.name,
34
48
  methodName: propertyKey
35
49
  });
36
- Reflect.defineMetadata(EVENT_METADATA_KEY, events, target.constructor);
50
+ ReflectUtils.defineMetadata(EVENT_METADATA_KEY, events, target.constructor);
37
51
  };
38
52
  }
39
53
  export class ComponentBase {
@@ -47,25 +61,13 @@ export class ComponentBase {
47
61
  var _a, _b, _c, _d;
48
62
  const e = this.getElement();
49
63
  if (e) {
50
- return Array.from(e.querySelectorAll(selector));
64
+ return ElementUtils.querySelectorAll(e, selector);
51
65
  }
52
66
  else {
53
67
  const startNode = (_b = (_a = this.rawSet) === null || _a === void 0 ? void 0 : _a.point) === null || _b === void 0 ? void 0 : _b.start;
54
68
  const endNode = (_d = (_c = this.rawSet) === null || _c === void 0 ? void 0 : _c.point) === null || _d === void 0 ? void 0 : _d.end;
55
- if (startNode && endNode && startNode.parentNode === endNode.parentNode) {
56
- const elements = [];
57
- let currentNode = startNode.nextSibling;
58
- while (currentNode && currentNode !== endNode) {
59
- if (currentNode.nodeType === Node.ELEMENT_NODE) {
60
- const currentElement = currentNode;
61
- if (currentElement.matches(selector)) {
62
- elements.push(currentElement);
63
- }
64
- elements.push(...Array.from(currentElement.querySelectorAll(selector)));
65
- }
66
- currentNode = currentNode.nextSibling;
67
- }
68
- return elements;
69
+ if (startNode && endNode) {
70
+ return ElementUtils.querySelectorAll({ start: startNode, end: endNode }, selector);
69
71
  }
70
72
  }
71
73
  return [];
@@ -171,12 +173,12 @@ export class ComponentBase {
171
173
  if (other.rawSet) {
172
174
  this.setRawSet(other.rawSet);
173
175
  }
174
- for (const propertyKey in this) {
175
- const metadata = Reflect.getMetadata(ATTRIBUTE_METADATA_KEY, this, propertyKey);
176
- if (metadata && metadata.name) {
177
- if (this.equalsAttributeName(name, metadata.name)) {
178
- const finalValue = metadata.converter ? metadata.converter(value) : value;
179
- this[propertyKey] = finalValue;
176
+ const attributes = ReflectUtils.getMetadata(ATTRIBUTE_METADATA_KEY, this.constructor);
177
+ if (attributes && Array.isArray(attributes)) {
178
+ for (const attrInfo of attributes) {
179
+ if (this.equalsAttributeName(name, attrInfo.name)) {
180
+ const finalValue = attrInfo.converter ? attrInfo.converter(value) : value;
181
+ this[attrInfo.propertyKey] = finalValue;
180
182
  }
181
183
  }
182
184
  }
@@ -189,21 +191,38 @@ export class ComponentBase {
189
191
  e.component = this;
190
192
  }
191
193
  // Handle @query decorators
192
- for (const propertyKey in this) {
193
- const metadata = Reflect.getMetadata(QUERY_METADATA_KEY, this, propertyKey);
194
- if (metadata && metadata.selector) {
195
- const propertyType = Reflect.getMetadata("design:type", this, propertyKey);
196
- const elements = this._queryElements(metadata.selector);
197
- if (propertyType === Array) {
198
- this[propertyKey] = elements;
194
+ const queries = ReflectUtils.getMetadata(QUERY_METADATA_KEY, this.constructor);
195
+ if (queries && Array.isArray(queries)) {
196
+ for (const queryInfo of queries) {
197
+ const { selector, propertyKey, isMethod } = queryInfo;
198
+ const elements = this._queryElements(selector);
199
+ if (isMethod) {
200
+ const method = this[propertyKey];
201
+ if (typeof method === 'function') {
202
+ const paramTypes = ReflectUtils.getParameterTypes(this, propertyKey);
203
+ if (paramTypes && paramTypes.length > 0 && paramTypes[0] === Array) {
204
+ method.call(this, elements);
205
+ }
206
+ else {
207
+ if (elements.length > 0) {
208
+ method.call(this, elements[0]);
209
+ }
210
+ }
211
+ }
199
212
  }
200
213
  else {
201
- this[propertyKey] = elements[0] || null;
214
+ const propertyType = ReflectUtils.getType(this, propertyKey);
215
+ if (propertyType === Array) {
216
+ this[propertyKey] = elements;
217
+ }
218
+ else {
219
+ this[propertyKey] = elements[0] || null;
220
+ }
202
221
  }
203
222
  }
204
223
  }
205
224
  // Handle @event decorators
206
- const events = Reflect.getMetadata(EVENT_METADATA_KEY, this.constructor);
225
+ const events = ReflectUtils.getMetadata(EVENT_METADATA_KEY, this.constructor);
207
226
  if (events && Array.isArray(events)) {
208
227
  for (const eventInfo of events) {
209
228
  const elements = this._queryElements(eventInfo.query);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dooboostore/dom-render",
3
- "version": "1.0.100",
3
+ "version": "1.0.102",
4
4
  "license": "MIT",
5
5
  "description": "html view template engine",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "reflect-metadata": "^0.2.2",
47
- "@dooboostore/core": "1.0.7",
47
+ "@dooboostore/core": "1.0.8",
48
48
  "@dooboostore/core-web": "1.0.1",
49
49
  "@dooboostore/core-node": "1.0.1"
50
50
  },