@htmlplus/element 3.1.4 → 3.2.1

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
@@ -146,6 +146,46 @@ In the `index.html` file.
146
146
  TODO
147
147
  </details>
148
148
 
149
+ <details>
150
+ <summary>Debounce</summary>
151
+
152
+ Ensures that the method executes only after the specified delay, resetting the timer if called again within the delay period.
153
+
154
+ In the `my-element.tsx` file.
155
+
156
+ ```tsx
157
+ import { Debounce, Element, State } from '@htmlplus/element';
158
+
159
+ @Element()
160
+ export class MyCounter {
161
+ @State()
162
+ value: number = 0;
163
+
164
+ @Debounce()
165
+ onClick() {
166
+ this.value++;
167
+ }
168
+
169
+ render() {
170
+ return (
171
+ <host onClick={this.onClick}>
172
+ Count is {this.value}
173
+ </host>
174
+ )
175
+ }
176
+ }
177
+ ```
178
+
179
+ In the `index.html` file.
180
+
181
+ ```html
182
+ <body dir="rtl">
183
+ <my-counter></my-counter>
184
+ </body>
185
+ ```
186
+
187
+ </details>
188
+
149
189
  <details>
150
190
  <summary>Direction</summary>
151
191
 
@@ -540,7 +580,7 @@ export class MyButton {
540
580
  @Query('.btn')
541
581
  buttonRef!: HTMLButtonElement;
542
582
 
543
- loadedCallback() {
583
+ readyCallback() {
544
584
  console.log(this.buttonRef); // <button class="btn"></button>
545
585
  }
546
586
 
@@ -587,7 +627,7 @@ export class MyButton {
587
627
  @QueryAll('span')
588
628
  spanRefs!: NodeList;
589
629
 
590
- loadedCallback() {
630
+ readyCallback() {
591
631
  console.log(this.spanRefs); // [span, span]
592
632
  }
593
633
 
@@ -897,7 +937,7 @@ TODO
897
937
  <details>
898
938
  <summary>connectedCallback</summary>
899
939
 
900
- A lifecycle callback method that is called each time the element is added to the document.
940
+ Invoked when an element is added to the document's DOM.
901
941
 
902
942
  ```js
903
943
  import { Element } from '@htmlplus/element';
@@ -915,7 +955,7 @@ export class MyElement {
915
955
  <details>
916
956
  <summary>disconnectedCallback</summary>
917
957
 
918
- TODO
958
+ Invoked when an element is removed from the document's DOM.
919
959
 
920
960
  ```js
921
961
  import { Element } from '@htmlplus/element';
@@ -931,17 +971,40 @@ export class MyElement {
931
971
  </details>
932
972
 
933
973
  <details>
934
- <summary>loadedCallback</summary>
974
+ <summary>prepareCallback</summary>
935
975
 
936
- TODO
976
+ This lifecycle is asynchronous and is invoked before all other lifecycles.
977
+
978
+ ```js
979
+ import { Element } from '@htmlplus/element';
980
+
981
+ @Element()
982
+ export class MyElement {
983
+ prepareCallback() {
984
+ return new Promise((resolve) => {
985
+ setTimeout(resolve, 2500);
986
+ })
987
+ }
988
+ connectedCallback() {
989
+ console.log('The element connects after 2500 milliseconds!');
990
+ }
991
+ }
992
+ ```
993
+
994
+ </details>
995
+
996
+ <details>
997
+ <summary>readyCallback</summary>
998
+
999
+ Invoked after the elements's DOM has been updated the first time, immediately before `updatedCallback` is called.
937
1000
 
938
1001
  ```js
939
1002
  import { Element } from '@htmlplus/element';
940
1003
 
941
1004
  @Element()
942
1005
  export class MyElement {
943
- loadedCallback() {
944
- console.log('Element is loaded!');
1006
+ readyCallback() {
1007
+ console.log('Element is ready!');
945
1008
  }
946
1009
  }
947
1010
  ```
@@ -951,14 +1014,42 @@ export class MyElement {
951
1014
  <details>
952
1015
  <summary>updateCallback</summary>
953
1016
 
954
- TODO
1017
+ Invoked before the element is rendered, this method receives a Map where keys represent the names of changed properties, and values hold their corresponding previous states. Modifying Properties/State within this method does not trigger an element update.
1018
+
1019
+ ```js
1020
+ import { Element, Property } from '@htmlplus/element';
1021
+
1022
+ @Element()
1023
+ export class MyElement {
1024
+ @Property()
1025
+ value?: number = 0;
1026
+
1027
+ updateCallback(changes) {
1028
+ console.log('Changed properties are: ', changes);
1029
+ }
1030
+ }
1031
+ ```
955
1032
 
956
1033
  </details>
957
1034
 
958
1035
  <details>
959
1036
  <summary>updatedCallback</summary>
960
1037
 
961
- TODO
1038
+ Invoked after the element is rendered, this method receives a Map where keys represent the names of changed properties, and values hold their corresponding previous states.
1039
+
1040
+ ```js
1041
+ import { Element, Property } from '@htmlplus/element';
1042
+
1043
+ @Element()
1044
+ export class MyElement {
1045
+ @Property()
1046
+ value?: number = 0;
1047
+
1048
+ updatedCallback(changes) {
1049
+ console.log('Changed properties are: ', changes);
1050
+ }
1051
+ }
1052
+ ```
962
1053
 
963
1054
  </details>
964
1055
 
@@ -1,21 +1,5 @@
1
- import { kebabCase, camelCase, pascalCase } from 'change-case';
2
- import { API_HOST, STATIC_TAG, API_STACKS, API_REQUEST, API_CONNECTED, LIFECYCLE_UPDATE, STATIC_STYLE, API_STYLE, LIFECYCLE_UPDATED, API_RENDER_COMPLETED, METHOD_RENDER, TYPE_BOOLEAN, TYPE_NUMBER, TYPE_NULL, TYPE_DATE, TYPE_ARRAY, TYPE_OBJECT, TYPE_UNDEFINED, LIFECYCLE_CONNECTED, LIFECYCLE_DISCONNECTED, KEY, API_INSTANCE, MAPPER, LIFECYCLE_CONSTRUCTED, LIFECYCLE_ADOPTED, LIFECYCLE_LOADED } from './constants.js';
3
-
4
- const appendToMethod = (target, key, handler) => {
5
- // Gets the previous function
6
- const previous = target[key];
7
- // Creates new function
8
- function next(...parameters) {
9
- // Calls the previous
10
- const result = previous?.bind(this)(...parameters);
11
- // Calls the appended
12
- handler.bind(this)(...parameters);
13
- // Returns the result
14
- return result;
15
- }
16
- // Replaces the next with the previous one
17
- target[key] = next;
18
- };
1
+ import { kebabCase, pascalCase } from 'change-case';
2
+ import { API_HOST, STATIC_TAG, API_STACKS, API_REQUEST, API_CONNECTED, LIFECYCLE_UPDATE, STATIC_STYLE, API_STYLE, LIFECYCLE_UPDATED, API_RENDER_COMPLETED, METHOD_RENDER, TYPE_BOOLEAN, TYPE_NUMBER, TYPE_NULL, TYPE_DATE, TYPE_ARRAY, TYPE_OBJECT, TYPE_UNDEFINED, LIFECYCLE_CONNECTED, LIFECYCLE_DISCONNECTED, KEY, LIFECYCLE_PREPARE, LIFECYCLE_CONSTRUCTED, LIFECYCLE_ADOPTED, LIFECYCLE_READY } from './constants.js';
19
3
 
20
4
  /**
21
5
  * Indicates the host of the element.
@@ -87,11 +71,12 @@ const toEvent = (input) => {
87
71
 
88
72
  const updateAttribute = (target, key, value) => {
89
73
  const element = host(target);
90
- const name = kebabCase(key);
91
74
  if ([undefined, null, false].includes(value)) {
92
- return element.removeAttribute(name);
75
+ element.removeAttribute(key);
76
+ }
77
+ else {
78
+ element.setAttribute(key, value === true ? '' : value);
93
79
  }
94
- element.setAttribute(name, value === true ? '' : value);
95
80
  };
96
81
 
97
82
  const symbol = Symbol();
@@ -118,13 +103,13 @@ const attributes$2 = (target, attributes) => {
118
103
  if (isEvent(key))
119
104
  on(element, toEvent(key), next[key]);
120
105
  else
121
- updateAttribute(element, key, next[key]);
106
+ updateAttribute(element, kebabCase(key), next[key]);
122
107
  }
123
108
  element[symbol] = { ...next };
124
109
  };
125
110
 
126
- const call = (target, key, ...parameters) => {
127
- return target[key]?.call(target, ...parameters);
111
+ const call = (target, key, ...args) => {
112
+ return target[key]?.apply(target, args);
128
113
  };
129
114
 
130
115
  const typeOf = (input) => {
@@ -1091,7 +1076,7 @@ tag('svg');
1091
1076
  * @param previous The previous value of Property/State.
1092
1077
  * @param callback Invoked when the rendering phase is completed.
1093
1078
  */
1094
- const request = (target, name, previous, callback) => {
1079
+ const requestUpdate = (target, name, previous, callback) => {
1095
1080
  // Creates/Gets a stacks.
1096
1081
  const stacks = (target[API_STACKS] ||= new Map());
1097
1082
  // Creates/Updates a stack.
@@ -1204,11 +1189,27 @@ const styles$1 = (input) => {
1204
1189
  .join('; ');
1205
1190
  };
1206
1191
 
1207
- function toDecorator(util, ...parameters) {
1192
+ const toCSSColor = (input) => {
1193
+ return isCSSColor(input) ? input : undefined;
1194
+ };
1195
+
1196
+ const toCSSUnit = (input) => {
1197
+ if (input == null || input === '') {
1198
+ return;
1199
+ }
1200
+ if (typeof input === 'number' || !isNaN(Number(input))) {
1201
+ return `${input}px`;
1202
+ }
1203
+ if (/^\d+(\.\d+)?(px|pt|cm|mm|in|em|rem|%|vw|vh)$/.test(input)) {
1204
+ return input;
1205
+ }
1206
+ };
1207
+
1208
+ function toDecorator(util, ...args) {
1208
1209
  return function (target, key) {
1209
1210
  defineProperty(target, key, {
1210
1211
  get() {
1211
- return util(this, ...parameters);
1212
+ return util(this, ...args);
1212
1213
  }
1213
1214
  });
1214
1215
  };
@@ -1279,22 +1280,49 @@ const toUnit = (input, unit = 'px') => {
1279
1280
  return Number(input) + unit;
1280
1281
  };
1281
1282
 
1283
+ const wrapMethod = (mode, target, key, handler) => {
1284
+ // Gets the original function
1285
+ const original = target[key];
1286
+ // Validate target property
1287
+ if (original && typeof original !== 'function') {
1288
+ throw new TypeError(`Property ${String(key)} is not a function`);
1289
+ }
1290
+ // Creates new function
1291
+ function wrapped(...args) {
1292
+ // Calls the handler before the original
1293
+ if (mode == 'before') {
1294
+ handler.apply(this, args);
1295
+ }
1296
+ // Calls the original
1297
+ const result = original?.apply(this, args);
1298
+ // Calls the handler after the original
1299
+ if (mode == 'after') {
1300
+ handler.apply(this, args);
1301
+ }
1302
+ // Returns the result
1303
+ return result;
1304
+ }
1305
+ // Replaces the wrapped with the original one
1306
+ target[key] = wrapped;
1307
+ };
1308
+
1282
1309
  /**
1283
1310
  * Used to bind a method of a class to the current context,
1284
1311
  * making it easier to reference `this` within the method.
1285
1312
  */
1286
1313
  function Bind() {
1287
1314
  return function (target, key, descriptor) {
1315
+ const original = descriptor.value;
1288
1316
  return {
1289
1317
  configurable: true,
1290
1318
  get() {
1291
- const value = descriptor?.value.bind(this);
1319
+ const next = original.bind(this);
1292
1320
  defineProperty(this, key, {
1293
- value,
1321
+ value: next,
1294
1322
  configurable: true,
1295
1323
  writable: true
1296
1324
  });
1297
- return value;
1325
+ return next;
1298
1326
  }
1299
1327
  };
1300
1328
  };
@@ -1318,7 +1346,7 @@ function Provider(namespace) {
1318
1346
  dispatch(instance, `${prefix}:${instance[SUB]}:update`, options);
1319
1347
  };
1320
1348
  // TODO
1321
- appendToMethod(target, LIFECYCLE_CONNECTED, function () {
1349
+ wrapMethod('after', target, LIFECYCLE_CONNECTED, function () {
1322
1350
  const cleanup = () => {
1323
1351
  off(this, `${prefix}:presence`, onPresence);
1324
1352
  cleanups(this).delete(prefix);
@@ -1330,7 +1358,7 @@ function Provider(namespace) {
1330
1358
  on(this, `${prefix}:presence`, onPresence);
1331
1359
  cleanups(this).set(prefix, cleanup);
1332
1360
  });
1333
- appendToMethod(target, LIFECYCLE_UPDATE, function (states) {
1361
+ wrapMethod('after', target, LIFECYCLE_UPDATE, function (states) {
1334
1362
  update(this);
1335
1363
  if (cleanups(this).size && !states.has(SUB))
1336
1364
  return;
@@ -1347,7 +1375,7 @@ function Provider(namespace) {
1347
1375
  on(window, `${type}:presence`, onPresence);
1348
1376
  cleanups(this).set(type, cleanup);
1349
1377
  });
1350
- appendToMethod(target, LIFECYCLE_DISCONNECTED, function () {
1378
+ wrapMethod('after', target, LIFECYCLE_DISCONNECTED, function () {
1351
1379
  cleanups(this).forEach((cleanup) => cleanup());
1352
1380
  });
1353
1381
  };
@@ -1364,7 +1392,7 @@ function Consumer(namespace) {
1364
1392
  instance[key] = state;
1365
1393
  };
1366
1394
  // TODO
1367
- appendToMethod(target, LIFECYCLE_CONNECTED, function () {
1395
+ wrapMethod('after', target, LIFECYCLE_CONNECTED, function () {
1368
1396
  // TODO
1369
1397
  if (SUB && this[SUB])
1370
1398
  return;
@@ -1392,7 +1420,7 @@ function Consumer(namespace) {
1392
1420
  // TODO: When the `Provider` element is activated after the `Consumer` element.
1393
1421
  !connected && setTimeout(() => dispatch(this, `${prefix}:presence`, options));
1394
1422
  });
1395
- appendToMethod(target, LIFECYCLE_UPDATE, function (states) {
1423
+ wrapMethod('after', target, LIFECYCLE_UPDATE, function (states) {
1396
1424
  if (cleanups(this).size && !states.has(SUB))
1397
1425
  return;
1398
1426
  cleanups(this).get(`${prefix}:${states.get(SUB)}`)?.();
@@ -1414,12 +1442,41 @@ function Consumer(namespace) {
1414
1442
  cleanups(this).set(type, cleanup);
1415
1443
  dispatch(window, `${type}:presence`);
1416
1444
  });
1417
- appendToMethod(target, LIFECYCLE_DISCONNECTED, function () {
1445
+ wrapMethod('after', target, LIFECYCLE_DISCONNECTED, function () {
1418
1446
  cleanups(this).forEach((cleanup) => cleanup());
1419
1447
  });
1420
1448
  };
1421
1449
  }
1422
1450
 
1451
+ /**
1452
+ * A method decorator that applies debounce behavior to a class method.
1453
+ * Ensures that the method executes only after the specified delay,
1454
+ * resetting the timer if called again within the delay period.
1455
+ *
1456
+ * @param {number} delay - The debounce delay in milliseconds.
1457
+ */
1458
+ function Debounce(delay = 0) {
1459
+ return function (target, key, descriptor) {
1460
+ const KEY = Symbol();
1461
+ const original = descriptor.value;
1462
+ function clear() {
1463
+ if (!Object.hasOwn(this, KEY))
1464
+ return;
1465
+ clearTimeout(this[KEY]);
1466
+ delete this[KEY];
1467
+ }
1468
+ function debounced(...args) {
1469
+ clear.call(this);
1470
+ this[KEY] = window.setTimeout(() => {
1471
+ clear.call(this);
1472
+ original.apply(this, args);
1473
+ }, delay);
1474
+ }
1475
+ descriptor.value = debounced;
1476
+ return Bind()(target, key, descriptor);
1477
+ };
1478
+ }
1479
+
1423
1480
  /**
1424
1481
  * Indicates whether the [Direction](https://mdn.io/css-direction)
1425
1482
  * of the element is `Right-To-Left` or `Left-To-Right`.
@@ -1445,6 +1502,7 @@ function Element() {
1445
1502
  }
1446
1503
  const proxy = (constructor) => {
1447
1504
  return class Plus extends HTMLElement {
1505
+ #instance;
1448
1506
  static formAssociated = constructor['formAssociated'];
1449
1507
  static observedAttributes = constructor['observedAttributes'];
1450
1508
  constructor() {
@@ -1454,39 +1512,39 @@ const proxy = (constructor) => {
1454
1512
  delegatesFocus: constructor['delegatesFocus'],
1455
1513
  slotAssignment: constructor['slotAssignment']
1456
1514
  });
1457
- const instance = (this[API_INSTANCE] = new constructor());
1458
- instance[API_HOST] = () => this;
1459
- call(instance, LIFECYCLE_CONSTRUCTED);
1515
+ this.#instance = new constructor();
1516
+ this.#instance[API_HOST] = () => this;
1517
+ call(this.#instance, LIFECYCLE_CONSTRUCTED);
1460
1518
  }
1461
1519
  adoptedCallback() {
1462
- call(this[API_INSTANCE], LIFECYCLE_ADOPTED);
1520
+ call(this.#instance, LIFECYCLE_ADOPTED);
1463
1521
  }
1464
1522
  attributeChangedCallback(key, prev, next) {
1465
- // Ensures the integrity of readonly properties to prevent potential errors.
1466
- try {
1467
- const attribute = constructor[MAPPER]?.[key];
1468
- const property = attribute || camelCase(key);
1469
- this[property] = next;
1523
+ if (prev != next) {
1524
+ this.#instance['RAW:' + key] = next;
1470
1525
  }
1471
- catch { }
1472
1526
  }
1473
1527
  connectedCallback() {
1474
- const instance = this[API_INSTANCE];
1475
1528
  // TODO: experimental for global config
1476
- Object.assign(instance, getConfig('element', getTag(instance), 'property'));
1477
- instance[API_CONNECTED] = true;
1529
+ Object.assign(this.#instance, getConfig('element', getTag(this.#instance), 'property'));
1478
1530
  const connect = () => {
1479
- request(instance, undefined, undefined, () => {
1480
- call(instance, LIFECYCLE_LOADED);
1531
+ this.#instance[API_CONNECTED] = true;
1532
+ call(this.#instance, LIFECYCLE_CONNECTED);
1533
+ requestUpdate(this.#instance, undefined, undefined, () => {
1534
+ call(this.#instance, LIFECYCLE_READY);
1481
1535
  });
1482
1536
  };
1483
- const callback = call(instance, LIFECYCLE_CONNECTED);
1484
- if (!callback?.then)
1537
+ const hasPrepare = LIFECYCLE_PREPARE in this.#instance;
1538
+ if (!hasPrepare)
1485
1539
  return connect();
1486
- callback.then(() => connect());
1540
+ call(this.#instance, LIFECYCLE_PREPARE)
1541
+ .then(() => connect())
1542
+ .catch((error) => {
1543
+ throw new Error(`Failed to prepare <${getTag(this.#instance)}> element before connection.`, { cause: error });
1544
+ });
1487
1545
  }
1488
1546
  disconnectedCallback() {
1489
- call(this[API_INSTANCE], LIFECYCLE_DISCONNECTED);
1547
+ call(this.#instance, LIFECYCLE_DISCONNECTED);
1490
1548
  }
1491
1549
  };
1492
1550
  };
@@ -1499,47 +1557,43 @@ const proxy = (constructor) => {
1499
1557
  */
1500
1558
  function Event(options = {}) {
1501
1559
  return function (target, key) {
1502
- defineProperty(target, key, {
1503
- get() {
1504
- return (detail) => {
1505
- const element = host(this);
1506
- const framework = getFramework(this);
1507
- options.bubbles ??= false;
1508
- let type = String(key);
1509
- switch (framework) {
1510
- // TODO: Experimental
1511
- case 'blazor':
1512
- options.bubbles = true;
1513
- type = pascalCase(type);
1514
- try {
1515
- window['Blazor'].registerCustomEventType(type, {
1516
- createEventArgs: (event) => ({
1517
- detail: event.detail
1518
- })
1519
- });
1520
- }
1521
- catch { }
1522
- break;
1523
- case 'qwik':
1524
- case 'solid':
1525
- type = pascalCase(type).toLowerCase();
1526
- break;
1527
- case 'react':
1528
- case 'preact':
1529
- type = pascalCase(type);
1530
- break;
1531
- default:
1532
- type = kebabCase(type);
1533
- break;
1560
+ target[key] = function (detail) {
1561
+ const element = host(this);
1562
+ const framework = getFramework(this);
1563
+ options.bubbles ??= false;
1564
+ let type = String(key);
1565
+ switch (framework) {
1566
+ // TODO: Experimental
1567
+ case 'blazor':
1568
+ options.bubbles = true;
1569
+ type = pascalCase(type);
1570
+ try {
1571
+ window['Blazor'].registerCustomEventType(type, {
1572
+ createEventArgs: (event) => ({
1573
+ detail: event.detail
1574
+ })
1575
+ });
1534
1576
  }
1535
- let event;
1536
- event ||= getConfig('event', 'resolver')?.({ detail, element, framework, options, type });
1537
- event && element.dispatchEvent(event);
1538
- event ||= dispatch(this, type, { ...options, detail });
1539
- return event;
1540
- };
1577
+ catch { }
1578
+ break;
1579
+ case 'qwik':
1580
+ case 'solid':
1581
+ type = pascalCase(type).toLowerCase();
1582
+ break;
1583
+ case 'react':
1584
+ case 'preact':
1585
+ type = pascalCase(type);
1586
+ break;
1587
+ default:
1588
+ type = kebabCase(type);
1589
+ break;
1541
1590
  }
1542
- });
1591
+ let event;
1592
+ event ||= getConfig('event', 'resolver')?.({ detail, element, framework, options, type });
1593
+ event && element.dispatchEvent(event);
1594
+ event ||= dispatch(this, type, { ...options, detail });
1595
+ return event;
1596
+ };
1543
1597
  };
1544
1598
  }
1545
1599
 
@@ -1582,10 +1636,10 @@ function Listen(type, options) {
1582
1636
  return instance;
1583
1637
  }
1584
1638
  };
1585
- appendToMethod(target, LIFECYCLE_CONNECTED, function () {
1639
+ wrapMethod('before', target, LIFECYCLE_CONNECTED, function () {
1586
1640
  on(element(this), type, this[key], options);
1587
1641
  });
1588
- appendToMethod(target, LIFECYCLE_DISCONNECTED, function () {
1642
+ wrapMethod('before', target, LIFECYCLE_DISCONNECTED, function () {
1589
1643
  off(element(this), type, this[key], options);
1590
1644
  });
1591
1645
  return Bind()(target, key, descriptor);
@@ -1597,11 +1651,9 @@ function Listen(type, options) {
1597
1651
  * and invoke it as needed, both internally and externally.
1598
1652
  */
1599
1653
  function Method() {
1600
- return function (target, key) {
1601
- appendToMethod(target, LIFECYCLE_CONSTRUCTED, function () {
1602
- defineProperty(host(this), key, {
1603
- get: () => this[key].bind(this)
1604
- });
1654
+ return function (target, key, descriptor) {
1655
+ wrapMethod('before', target, LIFECYCLE_CONSTRUCTED, function () {
1656
+ host(this)[key] = this[key].bind(this);
1605
1657
  });
1606
1658
  };
1607
1659
  }
@@ -1612,89 +1664,110 @@ function Method() {
1612
1664
  */
1613
1665
  function Property(options) {
1614
1666
  return function (target, key, descriptor) {
1615
- // Creates a unique symbol for the lock flag.
1616
- const locked = Symbol();
1617
- // Converts property name to string.
1618
- const name = String(key);
1619
- // Calculates attribute.
1620
- const attribute = options?.attribute || kebabCase(name);
1621
- // Registers an attribute that is intricately linked to the property.
1667
+ // Unique symbol for property storage to avoid naming conflicts
1668
+ const KEY = Symbol();
1669
+ // Unique symbol for the lock flag to prevent infinite loops during updates
1670
+ const LOCKED = Symbol();
1671
+ // Calculate attribute name from the property key if not explicitly provided
1672
+ const attribute = options?.attribute || kebabCase(key);
1673
+ // Store the original setter (if it exists) to preserve its behavior
1674
+ const originalSetter = descriptor?.set;
1675
+ // Register the attribute in the observedAttributes array for the element
1622
1676
  (target.constructor['observedAttributes'] ||= []).push(attribute);
1623
- // TODO
1624
- if (attribute) {
1625
- // TODO
1626
- target.constructor[MAPPER] ||= {};
1627
- // TODO
1628
- target.constructor[MAPPER][attribute] = name;
1677
+ // Getter function to retrieve the property value
1678
+ function get() {
1679
+ return this[KEY];
1629
1680
  }
1630
- // TODO: This feature is an experimental
1631
- // When the property is a getter function.
1632
- if (descriptor) {
1633
- // Checks the reflection.
1634
- if (options?.reflect) {
1635
- // Stores the original getter function.
1636
- const getter = descriptor.get;
1637
- // Defines a new getter function.
1638
- descriptor.get = function () {
1639
- const value = getter?.apply(this);
1640
- this[locked] = true;
1641
- updateAttribute(this, attribute, value);
1642
- this[locked] = false;
1643
- return value;
1644
- };
1645
- // TODO: Check the lifecycle
1646
- appendToMethod(target, LIFECYCLE_UPDATED, function () {
1647
- // Calls the getter function to update the related attribute.
1648
- this[key];
1649
- });
1681
+ // Setter function to update the property value and trigger updates
1682
+ function set(value) {
1683
+ // Store the previous value
1684
+ const previous = this[KEY];
1685
+ // Store the new value
1686
+ const next = value;
1687
+ // Skip updates if the value hasn't changed and no custom setter is defined
1688
+ if (!originalSetter && next === previous)
1689
+ return;
1690
+ // If a custom setter exists, call it with the new value
1691
+ if (originalSetter) {
1692
+ originalSetter.call(this, next);
1650
1693
  }
1651
- }
1652
- // When the property is normal.
1653
- else {
1654
- // Creates a unique symbol.
1655
- const symbol = Symbol();
1656
- // Defines a getter function to use in the target class.
1657
- function get() {
1658
- return this[symbol];
1694
+ // Otherwise, update the property directly
1695
+ else {
1696
+ this[KEY] = next;
1659
1697
  }
1660
- // Defines a setter function to use in the target class.
1661
- function set(next) {
1662
- const previous = this[symbol];
1663
- if (next === previous)
1698
+ // Request an update
1699
+ requestUpdate(this, key, previous, (skipped) => {
1700
+ // Skip if the update was aborted
1701
+ if (skipped)
1664
1702
  return;
1665
- this[symbol] = next;
1666
- request(this, name, previous, (skipped) => {
1667
- if (skipped)
1668
- return;
1669
- if (!options?.reflect)
1670
- return;
1671
- this[locked] = true;
1672
- updateAttribute(this, attribute, next);
1673
- this[locked] = false;
1674
- });
1675
- }
1676
- // Attaches the getter and setter functions to the current property of the target class.
1677
- defineProperty(target, key, { get, set });
1703
+ // If reflection is enabled, update the corresponding attribute
1704
+ if (!options?.reflect)
1705
+ return;
1706
+ // Lock to prevent infinite loops
1707
+ this[LOCKED] = true;
1708
+ // Update the attribute
1709
+ updateAttribute(this, attribute, next);
1710
+ // Unlock
1711
+ this[LOCKED] = false;
1712
+ });
1713
+ }
1714
+ // Override the property descriptor if a custom setter exists
1715
+ if (originalSetter) {
1716
+ descriptor.set = set;
1717
+ }
1718
+ // Attach the getter and setter to the target class property if no descriptor exists
1719
+ if (!descriptor) {
1720
+ defineProperty(target, key, { configurable: true, get, set });
1678
1721
  }
1679
- // TODO: Check the lifecycle
1680
- appendToMethod(target, LIFECYCLE_CONSTRUCTED, function () {
1681
- // Defines a getter function to use in the host element.
1722
+ /**
1723
+ * Define a raw property setter to handle updates that trigger from the `attributeChangedCallback`,
1724
+ * To intercept and process raw attribute values before they are assigned to the property
1725
+ */
1726
+ defineProperty(target, 'RAW:' + attribute, {
1727
+ set(value) {
1728
+ if (!this[LOCKED]) {
1729
+ // Convert the raw value and set it to the corresponding property
1730
+ this[key] = toProperty(value, options?.type);
1731
+ }
1732
+ }
1733
+ });
1734
+ // Attach getter and setter to the host element on construction
1735
+ wrapMethod('before', target, LIFECYCLE_CONSTRUCTED, function () {
1682
1736
  const get = () => {
1737
+ if (descriptor && !descriptor.get) {
1738
+ throw new Error(`Property '${key}' does not have a getter. Unable to retrieve value.`);
1739
+ }
1683
1740
  return this[key];
1684
1741
  };
1685
- // Defines a setter function to use in the host element.
1686
- const set = descriptor
1687
- ? undefined
1688
- : (input) => {
1689
- if (this[locked]) {
1690
- return;
1691
- }
1692
- this[key] = toProperty(input, options?.type);
1693
- };
1694
- // TODO: Check the configuration.
1695
- // Attaches the getter and setter functions to the current property of the host element.
1696
- defineProperty(host(this), key, { get, set, configurable: true });
1742
+ const set = (value) => {
1743
+ if (descriptor && !descriptor.set) {
1744
+ throw new Error(`Property '${key}' does not have a setter. Unable to assign value.`);
1745
+ }
1746
+ this[key] = value;
1747
+ };
1748
+ defineProperty(host(this), key, { configurable: true, get, set });
1697
1749
  });
1750
+ /**
1751
+ * TODO: Review these behaviors again.
1752
+ *
1753
+ * When a property has a reflect and either a getter, a setter, or both are available,
1754
+ * three approaches are possible:
1755
+ *
1756
+ * 1. Only a getter is present: The attribute updates after each render is completed.
1757
+ * 2. Only a setter is present: The attribute updates after each setter call.
1758
+ * 3. Both getter and setter are present: The attribute is updated via the setter call
1759
+ * and also after each render is completed, resulting in two attribute update processes.
1760
+ */
1761
+ if (options?.reflect && descriptor?.get) {
1762
+ wrapMethod('before', target, LIFECYCLE_UPDATED, function () {
1763
+ // Lock to prevent infinite loops
1764
+ this[LOCKED] = true;
1765
+ // Update the attribute
1766
+ updateAttribute(this, attribute, this[key]);
1767
+ // Unlock
1768
+ this[LOCKED] = false;
1769
+ });
1770
+ }
1698
1771
  };
1699
1772
  }
1700
1773
 
@@ -1738,23 +1811,87 @@ function Slots() {
1738
1811
  */
1739
1812
  function State() {
1740
1813
  return function (target, key) {
1814
+ const KEY = Symbol();
1741
1815
  const name = String(key);
1742
- const symbol = Symbol();
1743
- function get() {
1744
- return this[symbol];
1745
- }
1746
- function set(next) {
1747
- const previous = this[symbol];
1748
- if (next === previous)
1749
- return;
1750
- this[symbol] = next;
1751
- request(this, name, previous);
1752
- }
1753
- // TODO: configurable
1754
- defineProperty(target, key, { get, set, configurable: true });
1816
+ defineProperty(target, key, {
1817
+ enumerable: true,
1818
+ configurable: true,
1819
+ get() {
1820
+ return this[KEY];
1821
+ },
1822
+ set(next) {
1823
+ const previous = this[KEY];
1824
+ if (next === previous)
1825
+ return;
1826
+ this[KEY] = next;
1827
+ requestUpdate(this, name, previous);
1828
+ }
1829
+ });
1755
1830
  };
1756
1831
  }
1757
1832
 
1833
+ // TODO: check the logic
1834
+ function Style() {
1835
+ return function (target, key) {
1836
+ const LAST = Symbol();
1837
+ const SHEET = Symbol();
1838
+ wrapMethod('before', target, LIFECYCLE_UPDATED, function () {
1839
+ let sheet = this[SHEET];
1840
+ let value = this[key];
1841
+ const update = (value) => (result) => {
1842
+ if (value && value !== this[LAST])
1843
+ return;
1844
+ sheet.replaceSync(toCssString(result));
1845
+ this[LAST] = undefined;
1846
+ };
1847
+ if (!sheet) {
1848
+ sheet = new CSSStyleSheet();
1849
+ this[SHEET] = sheet;
1850
+ shadowRoot(this)?.adoptedStyleSheets.push(sheet);
1851
+ }
1852
+ if (typeof value === 'function') {
1853
+ value = value.call(this);
1854
+ }
1855
+ if (value instanceof Promise) {
1856
+ value.then(update((this[LAST] = value))).catch((error) => {
1857
+ throw new Error('TODO', { cause: error });
1858
+ });
1859
+ }
1860
+ else {
1861
+ update()(value);
1862
+ }
1863
+ });
1864
+ };
1865
+ }
1866
+ const toCssString = (input, parent) => {
1867
+ if (typeof input == 'string') {
1868
+ return input.trim();
1869
+ }
1870
+ if (Array.isArray(input)) {
1871
+ return input
1872
+ .map((item) => toCssString(item, parent))
1873
+ .filter(Boolean)
1874
+ .join('\n');
1875
+ }
1876
+ if (typeof input != 'object')
1877
+ return '';
1878
+ let result = '';
1879
+ for (const key of Object.keys(input)) {
1880
+ const value = input[key];
1881
+ const ignore = [null, undefined, false].includes(value);
1882
+ if (ignore)
1883
+ continue;
1884
+ const cssKey = key.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
1885
+ if (typeof value === 'object') {
1886
+ result += `${cssKey} {${toCssString(value, cssKey)}}`;
1887
+ }
1888
+ else {
1889
+ result += `${cssKey}: ${value};`;
1890
+ }
1891
+ }
1892
+ return parent ? result : `:host {${result}}`;
1893
+ };
1894
+
1758
1895
  /**
1759
1896
  * Monitors `@Property` and `@State` to detect changes.
1760
1897
  * The decorated method will be called after any changes,
@@ -1769,7 +1906,7 @@ function Watch(keys, immediate) {
1769
1906
  // Gets all keys
1770
1907
  const all = [keys].flat().filter((item) => item);
1771
1908
  // Registers a lifecycle to detect changes.
1772
- appendToMethod(target, LIFECYCLE_UPDATED, function (states) {
1909
+ wrapMethod('after', target, LIFECYCLE_UPDATED, function (states) {
1773
1910
  // Skips the logic if 'immediate' wasn't passed.
1774
1911
  if (!immediate && !this[API_RENDER_COMPLETED])
1775
1912
  return;
@@ -1789,4 +1926,4 @@ const attributes = attributes$2;
1789
1926
  const html = html$1;
1790
1927
  const styles = styles$1;
1791
1928
 
1792
- export { Bind as B, Consumer as C, Direction as D, Element as E, Host as H, IsRTL as I, Listen as L, Method as M, Provider as P, Query as Q, Slots as S, Watch as W, dispatch as a, isRTL as b, classes as c, direction as d, queryAll as e, off as f, getConfig as g, host as h, isCSSColor as i, setConfig as j, Event as k, Property as l, QueryAll as m, State as n, on as o, attributes as p, query as q, html as r, slots as s, toUnit as t, styles as u };
1929
+ export { Bind as B, Consumer as C, Debounce as D, Element as E, Host as H, IsRTL as I, Listen as L, Method as M, Provider as P, Query as Q, Slots as S, Watch as W, dispatch as a, toCSSUnit as b, classes as c, direction as d, isRTL as e, queryAll as f, getConfig as g, host as h, isCSSColor as i, off as j, toUnit as k, setConfig as l, Direction as m, Event as n, on as o, Property as p, query as q, QueryAll as r, slots as s, toCSSColor as t, State as u, Style as v, attributes as w, html as x, styles as y };
@@ -13,6 +13,18 @@ interface HTMLPlusElement {
13
13
  declare function Provider(namespace: string): (target: HTMLPlusElement, key: PropertyKey, descriptor: PropertyDescriptor) => void;
14
14
  declare function Consumer(namespace: string): (target: HTMLPlusElement, key: PropertyKey) => void;
15
15
 
16
+ /**
17
+ * A method decorator that applies debounce behavior to a class method.
18
+ * Ensures that the method executes only after the specified delay,
19
+ * resetting the timer if called again within the delay period.
20
+ *
21
+ * @param {number} delay - The debounce delay in milliseconds.
22
+ */
23
+ declare function Debounce(delay?: number): (target: Object, key: PropertyKey, descriptor: PropertyDescriptor) => {
24
+ configurable: boolean;
25
+ get(): any;
26
+ };
27
+
16
28
  /**
17
29
  * Indicates whether the [Direction](https://mdn.io/css-direction)
18
30
  * of the element is `Right-To-Left` or `Left-To-Right`.
@@ -127,7 +139,7 @@ declare function Listen(type: string, options?: ListenOptions): (target: HTMLPlu
127
139
  * Provides a way to encapsulate functionality within an element
128
140
  * and invoke it as needed, both internally and externally.
129
141
  */
130
- declare function Method(): (target: HTMLPlusElement, key: PropertyKey) => void;
142
+ declare function Method(): (target: HTMLPlusElement, key: PropertyKey, descriptor: PropertyDescriptor) => void;
131
143
 
132
144
  /**
133
145
  * The configuration for property decorator.
@@ -152,7 +164,7 @@ interface PropertyOptions {
152
164
  * Creates a reactive property, reflecting a corresponding attribute value,
153
165
  * and updates the element when the property is set.
154
166
  */
155
- declare function Property(options?: PropertyOptions): (target: HTMLPlusElement, key: PropertyKey, descriptor?: PropertyDescriptor) => void;
167
+ declare function Property(options?: PropertyOptions): (target: HTMLPlusElement, key: string, descriptor?: PropertyDescriptor) => void;
156
168
 
157
169
  /**
158
170
  * Selects the first element in the shadow dom that matches a specified CSS selector.
@@ -188,6 +200,8 @@ declare function Slots$1(): (target: HTMLPlusElement, key: PropertyKey) => void;
188
200
  */
189
201
  declare function State(): (target: HTMLPlusElement, key: PropertyKey) => void;
190
202
 
203
+ declare function Style(): (target: HTMLPlusElement, key: PropertyKey) => void;
204
+
191
205
  /**
192
206
  * Monitors `@Property` and `@State` to detect changes.
193
207
  * The decorated method will be called after any changes,
@@ -297,6 +311,10 @@ type Slots = {
297
311
  */
298
312
  declare const slots: (target: HTMLElement | HTMLPlusElement) => Slots;
299
313
 
314
+ declare const toCSSColor: (input: string) => string | undefined;
315
+
316
+ declare const toCSSUnit: (input?: number | string | null) => string | undefined;
317
+
300
318
  /**
301
319
  * Converts a value to a unit.
302
320
  */
@@ -306,4 +324,4 @@ declare const attributes: any;
306
324
  declare const html: any;
307
325
  declare const styles: any;
308
326
 
309
- export { styles as A, Bind as B, type Config as C, Direction as D, Element$1 as E, Host as H, IsRTL as I, type ListenOptions as L, Method as M, Provider as P, Query as Q, Slots$1 as S, Watch as W, dispatch as a, isRTL as b, classes as c, direction as d, queryAll as e, off as f, getConfig as g, host as h, isCSSColor as i, setConfig as j, type ConfigOptions as k, Consumer as l, type EventEmitter as m, type EventOptions as n, on as o, Event as p, query as q, Listen as r, slots as s, toUnit as t, type PropertyOptions as u, Property as v, QueryAll as w, State as x, attributes as y, html as z };
327
+ export { State as A, Bind as B, type Config as C, Debounce as D, Element$1 as E, Style as F, attributes as G, Host as H, IsRTL as I, html as J, styles as K, type ListenOptions as L, Method as M, Provider as P, Query as Q, Slots$1 as S, Watch as W, type ConfigOptions as a, dispatch as b, classes as c, direction as d, toCSSUnit as e, isRTL as f, getConfig as g, host as h, isCSSColor as i, queryAll as j, off as k, toUnit as l, setConfig as m, Consumer as n, on as o, Direction as p, query as q, type EventEmitter as r, slots as s, toCSSColor as t, type EventOptions as u, Event as v, Listen as w, type PropertyOptions as x, Property as y, QueryAll as z };
package/dist/client.d.ts CHANGED
@@ -1 +1 @@
1
- export { B as Bind, C as Config, k as ConfigOptions, l as Consumer, D as Direction, E as Element, p as Event, m as EventEmitter, n as EventOptions, H as Host, I as IsRTL, r as Listen, L as ListenOptions, M as Method, v as Property, u as PropertyOptions, P as Provider, Q as Query, w as QueryAll, S as Slots, x as State, W as Watch, c as classes, d as direction, a as dispatch, g as getConfig, h as host, i as isCSSColor, b as isRTL, f as off, o as on, q as query, e as queryAll, j as setConfig, s as slots, t as toUnit } from './client-5FqNUiuz.js';
1
+ export { B as Bind, C as Config, a as ConfigOptions, n as Consumer, D as Debounce, p as Direction, E as Element, v as Event, r as EventEmitter, u as EventOptions, H as Host, I as IsRTL, w as Listen, L as ListenOptions, M as Method, y as Property, x as PropertyOptions, P as Provider, Q as Query, z as QueryAll, S as Slots, A as State, F as Style, W as Watch, c as classes, d as direction, b as dispatch, g as getConfig, h as host, i as isCSSColor, f as isRTL, k as off, o as on, q as query, j as queryAll, m as setConfig, s as slots, t as toCSSColor, e as toCSSUnit, l as toUnit } from './client-JA8zqh-l.js';
package/dist/client.js CHANGED
@@ -1,3 +1,3 @@
1
- export { B as Bind, C as Consumer, D as Direction, E as Element, k as Event, H as Host, I as IsRTL, L as Listen, M as Method, l as Property, P as Provider, Q as Query, m as QueryAll, S as Slots, n as State, W as Watch, c as classes, d as direction, a as dispatch, g as getConfig, h as host, i as isCSSColor, b as isRTL, f as off, o as on, q as query, e as queryAll, j as setConfig, s as slots, t as toUnit } from './client-BsD9JZY4.js';
1
+ export { B as Bind, C as Consumer, D as Debounce, m as Direction, E as Element, n as Event, H as Host, I as IsRTL, L as Listen, M as Method, p as Property, P as Provider, Q as Query, r as QueryAll, S as Slots, u as State, v as Style, W as Watch, c as classes, d as direction, a as dispatch, g as getConfig, h as host, i as isCSSColor, e as isRTL, j as off, o as on, q as query, f as queryAll, l as setConfig, s as slots, t as toCSSColor, b as toCSSUnit, k as toUnit } from './client-DgXF8gQw.js';
2
2
  import 'change-case';
3
3
  import './constants.js';
@@ -1,9 +1,7 @@
1
1
  declare const KEY = "htmlplus";
2
2
  declare const PACKAGE_NAME = "@htmlplus/element";
3
- declare const MAPPER: unique symbol;
4
3
  declare const API_CONNECTED: unique symbol;
5
4
  declare const API_HOST: unique symbol;
6
- declare const API_INSTANCE: unique symbol;
7
5
  declare const API_REQUEST: unique symbol;
8
6
  declare const API_RENDER_COMPLETED: unique symbol;
9
7
  declare const API_STACKS: unique symbol;
@@ -21,7 +19,8 @@ declare const LIFECYCLE_ADOPTED = "adoptedCallback";
21
19
  declare const LIFECYCLE_CONNECTED = "connectedCallback";
22
20
  declare const LIFECYCLE_CONSTRUCTED = "constructedCallback";
23
21
  declare const LIFECYCLE_DISCONNECTED = "disconnectedCallback";
24
- declare const LIFECYCLE_LOADED = "loadedCallback";
22
+ declare const LIFECYCLE_READY = "readyCallback";
23
+ declare const LIFECYCLE_PREPARE = "prepareCallback";
25
24
  declare const LIFECYCLE_UPDATE = "updateCallback";
26
25
  declare const LIFECYCLE_UPDATED = "updatedCallback";
27
26
  declare const METHOD_RENDER = "render";
@@ -47,4 +46,4 @@ declare const UTILS_STYLES_IMPORTED = "styles";
47
46
  declare const UTILS_STYLES_LOCAL = "UTILS_STYLES";
48
47
  declare const UTILS_PATH = "@htmlplus/element/internal.js";
49
48
 
50
- export { API_CONNECTED, API_HOST, API_INSTANCE, API_RENDER_COMPLETED, API_REQUEST, API_STACKS, API_STYLE, COMMENT_AUTO_ADDED, DECORATOR_CSS_VARIABLE, DECORATOR_ELEMENT, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_PROPERTY, DECORATOR_PROPERTY_TYPE, DECORATOR_STATE, ELEMENT_HOST_NAME, KEY, LIFECYCLE_ADOPTED, LIFECYCLE_CONNECTED, LIFECYCLE_CONSTRUCTED, LIFECYCLE_DISCONNECTED, LIFECYCLE_LOADED, LIFECYCLE_UPDATE, LIFECYCLE_UPDATED, MAPPER, METHOD_RENDER, PACKAGE_NAME, STATIC_STYLE, STATIC_TAG, STYLE_IMPORTED, TYPE_ARRAY, TYPE_BIGINT, TYPE_BOOLEAN, TYPE_DATE, TYPE_ENUM, TYPE_FUNCTION, TYPE_NULL, TYPE_NUMBER, TYPE_OBJECT, TYPE_STRING, TYPE_UNDEFINED, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, UTILS_PATH, UTILS_STYLES_IMPORTED, UTILS_STYLES_LOCAL };
49
+ export { API_CONNECTED, API_HOST, API_RENDER_COMPLETED, API_REQUEST, API_STACKS, API_STYLE, COMMENT_AUTO_ADDED, DECORATOR_CSS_VARIABLE, DECORATOR_ELEMENT, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_PROPERTY, DECORATOR_PROPERTY_TYPE, DECORATOR_STATE, ELEMENT_HOST_NAME, KEY, LIFECYCLE_ADOPTED, LIFECYCLE_CONNECTED, LIFECYCLE_CONSTRUCTED, LIFECYCLE_DISCONNECTED, LIFECYCLE_PREPARE, LIFECYCLE_READY, LIFECYCLE_UPDATE, LIFECYCLE_UPDATED, METHOD_RENDER, PACKAGE_NAME, STATIC_STYLE, STATIC_TAG, STYLE_IMPORTED, TYPE_ARRAY, TYPE_BIGINT, TYPE_BOOLEAN, TYPE_DATE, TYPE_ENUM, TYPE_FUNCTION, TYPE_NULL, TYPE_NUMBER, TYPE_OBJECT, TYPE_STRING, TYPE_UNDEFINED, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, UTILS_PATH, UTILS_STYLES_IMPORTED, UTILS_STYLES_LOCAL };
package/dist/constants.js CHANGED
@@ -1,11 +1,8 @@
1
1
  const KEY = 'htmlplus';
2
2
  const PACKAGE_NAME = '@htmlplus/element';
3
- // TODO
4
- const MAPPER = Symbol();
5
3
  // APIs
6
4
  const API_CONNECTED = Symbol();
7
5
  const API_HOST = Symbol();
8
- const API_INSTANCE = Symbol();
9
6
  const API_REQUEST = Symbol();
10
7
  const API_RENDER_COMPLETED = Symbol();
11
8
  const API_STACKS = Symbol();
@@ -28,7 +25,8 @@ const LIFECYCLE_ADOPTED = 'adoptedCallback';
28
25
  const LIFECYCLE_CONNECTED = 'connectedCallback';
29
26
  const LIFECYCLE_CONSTRUCTED = 'constructedCallback';
30
27
  const LIFECYCLE_DISCONNECTED = 'disconnectedCallback';
31
- const LIFECYCLE_LOADED = 'loadedCallback';
28
+ const LIFECYCLE_READY = 'readyCallback';
29
+ const LIFECYCLE_PREPARE = 'prepareCallback';
32
30
  const LIFECYCLE_UPDATE = 'updateCallback';
33
31
  const LIFECYCLE_UPDATED = 'updatedCallback';
34
32
  // methods
@@ -59,4 +57,4 @@ const UTILS_STYLES_IMPORTED = 'styles';
59
57
  const UTILS_STYLES_LOCAL = 'UTILS_STYLES';
60
58
  const UTILS_PATH = '@htmlplus/element/internal.js';
61
59
 
62
- export { API_CONNECTED, API_HOST, API_INSTANCE, API_RENDER_COMPLETED, API_REQUEST, API_STACKS, API_STYLE, COMMENT_AUTO_ADDED, DECORATOR_CSS_VARIABLE, DECORATOR_ELEMENT, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_PROPERTY, DECORATOR_PROPERTY_TYPE, DECORATOR_STATE, ELEMENT_HOST_NAME, KEY, LIFECYCLE_ADOPTED, LIFECYCLE_CONNECTED, LIFECYCLE_CONSTRUCTED, LIFECYCLE_DISCONNECTED, LIFECYCLE_LOADED, LIFECYCLE_UPDATE, LIFECYCLE_UPDATED, MAPPER, METHOD_RENDER, PACKAGE_NAME, STATIC_STYLE, STATIC_TAG, STYLE_IMPORTED, TYPE_ARRAY, TYPE_BIGINT, TYPE_BOOLEAN, TYPE_DATE, TYPE_ENUM, TYPE_FUNCTION, TYPE_NULL, TYPE_NUMBER, TYPE_OBJECT, TYPE_STRING, TYPE_UNDEFINED, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, UTILS_PATH, UTILS_STYLES_IMPORTED, UTILS_STYLES_LOCAL };
60
+ export { API_CONNECTED, API_HOST, API_RENDER_COMPLETED, API_REQUEST, API_STACKS, API_STYLE, COMMENT_AUTO_ADDED, DECORATOR_CSS_VARIABLE, DECORATOR_ELEMENT, DECORATOR_EVENT, DECORATOR_METHOD, DECORATOR_PROPERTY, DECORATOR_PROPERTY_TYPE, DECORATOR_STATE, ELEMENT_HOST_NAME, KEY, LIFECYCLE_ADOPTED, LIFECYCLE_CONNECTED, LIFECYCLE_CONSTRUCTED, LIFECYCLE_DISCONNECTED, LIFECYCLE_PREPARE, LIFECYCLE_READY, LIFECYCLE_UPDATE, LIFECYCLE_UPDATED, METHOD_RENDER, PACKAGE_NAME, STATIC_STYLE, STATIC_TAG, STYLE_IMPORTED, TYPE_ARRAY, TYPE_BIGINT, TYPE_BOOLEAN, TYPE_DATE, TYPE_ENUM, TYPE_FUNCTION, TYPE_NULL, TYPE_NUMBER, TYPE_OBJECT, TYPE_STRING, TYPE_UNDEFINED, UTILS_ATTRIBUTES_IMPORTED, UTILS_ATTRIBUTES_LOCAL, UTILS_HTML_IMPORTED, UTILS_HTML_LOCAL, UTILS_PATH, UTILS_STYLES_IMPORTED, UTILS_STYLES_LOCAL };
@@ -1 +1 @@
1
- export { y as attributes, z as html, A as styles } from './client-5FqNUiuz.js';
1
+ export { G as attributes, J as html, K as styles } from './client-JA8zqh-l.js';
package/dist/internal.js CHANGED
@@ -1,3 +1,3 @@
1
- export { p as attributes, r as html, u as styles } from './client-BsD9JZY4.js';
1
+ export { w as attributes, x as html, y as styles } from './client-DgXF8gQw.js';
2
2
  import 'change-case';
3
3
  import './constants.js';
@@ -1,6 +1,8 @@
1
1
  import 'react';
2
2
 
3
- type WithPart<K extends keyof React.JSX.IntrinsicElements> = React.JSX.IntrinsicElements[K] & { part?: string };
3
+ type WithPart<K extends keyof React.JSX.IntrinsicElements> = React.JSX.IntrinsicElements[K] & {
4
+ part?: string;
5
+ };
4
6
 
5
7
  declare namespace JSX {
6
8
  interface IntrinsicElements {
@@ -461,6 +461,10 @@ const customElement = (options) => {
461
461
  name.name = '.' + name.name;
462
462
  return;
463
463
  }
464
+ if (name.name == 'disabled') {
465
+ name.name = '.' + name.name;
466
+ return;
467
+ }
464
468
  const key = ['tabIndex', 'viewBox'];
465
469
  if (!key.includes(name.name))
466
470
  return;
@@ -512,9 +516,7 @@ const customElement = (options) => {
512
516
  return attribute.type == 'JSXSpreadAttribute';
513
517
  });
514
518
  if (hasSpreadAttribute) {
515
- parts.push(' ', 'ref=', t.arrowFunctionExpression([
516
- t.identifier('$element')
517
- ], TODO(t.identifier('$element'), attributes)));
519
+ parts.push(' ', 'ref=', t.arrowFunctionExpression([t.identifier('$element')], TODO(t.identifier('$element'), attributes)));
518
520
  }
519
521
  else {
520
522
  for (const attribute of attributes) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@htmlplus/element",
3
- "version": "3.1.4",
3
+ "version": "3.2.1",
4
4
  "license": "MIT",
5
5
  "sideEffects": false,
6
6
  "author": "Masood Abdolian <m.abdolian@gmail.com>",