snice 1.14.3 → 2.1.0
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/bin/templates/base/tsconfig.json +5 -4
- package/components/accordion/demo.html +403 -0
- package/components/accordion/snice-accordion-item.css +85 -0
- package/components/accordion/snice-accordion-item.ts +226 -0
- package/components/accordion/snice-accordion.css +31 -0
- package/components/accordion/snice-accordion.ts +182 -0
- package/components/accordion/snice-accordion.types.ts +32 -0
- package/components/alert/demo.html +445 -0
- package/components/alert/snice-alert.css +195 -0
- package/components/alert/snice-alert.ts +141 -0
- package/components/alert/snice-alert.types.ts +12 -0
- package/components/avatar/demo.html +598 -0
- package/components/avatar/snice-avatar.css +131 -0
- package/components/avatar/snice-avatar.ts +136 -0
- package/components/avatar/snice-avatar.types.ts +13 -0
- package/components/badge/demo.html +523 -0
- package/components/badge/snice-badge.css +161 -0
- package/components/badge/snice-badge.ts +117 -0
- package/components/badge/snice-badge.types.ts +16 -0
- package/components/breadcrumbs/demo.html +404 -0
- package/components/breadcrumbs/snice-breadcrumbs.css +133 -0
- package/components/breadcrumbs/snice-breadcrumbs.ts +191 -0
- package/components/breadcrumbs/snice-breadcrumbs.types.ts +26 -0
- package/components/breadcrumbs/snice-crumb.ts +26 -0
- package/components/button/demo.html +42 -0
- package/components/button/snice-button.css +230 -0
- package/components/button/snice-button.ts +169 -0
- package/components/button/snice-button.types.ts +25 -0
- package/components/card/demo.html +525 -0
- package/components/card/snice-card.css +140 -0
- package/components/card/snice-card.ts +102 -0
- package/components/card/snice-card.types.ts +10 -0
- package/components/checkbox/demo.html +253 -0
- package/components/checkbox/snice-checkbox.css +164 -0
- package/components/checkbox/snice-checkbox.ts +223 -0
- package/components/checkbox/snice-checkbox.types.ts +22 -0
- package/components/chip/demo.html +383 -0
- package/components/chip/snice-chip.css +195 -0
- package/components/chip/snice-chip.ts +139 -0
- package/components/chip/snice-chip.types.ts +15 -0
- package/components/date-picker/README.md +233 -0
- package/components/date-picker/demo.html +191 -0
- package/components/date-picker/snice-date-picker.css +330 -0
- package/components/date-picker/snice-date-picker.ts +777 -0
- package/components/date-picker/snice-date-picker.types.ts +83 -0
- package/components/divider/demo.html +233 -0
- package/components/divider/snice-divider.css +155 -0
- package/components/divider/snice-divider.ts +69 -0
- package/components/divider/snice-divider.types.ts +15 -0
- package/components/drawer/demo.html +328 -0
- package/components/drawer/snice-drawer.css +476 -0
- package/components/drawer/snice-drawer.ts +287 -0
- package/components/drawer/snice-drawer.types.ts +17 -0
- package/components/global.d.ts +14 -0
- package/components/input/demo.html +303 -0
- package/components/input/snice-input.css +257 -0
- package/components/input/snice-input.ts +442 -0
- package/components/input/snice-input.types.ts +59 -0
- package/components/input/test.html +77 -0
- package/components/layout/README.md +260 -0
- package/components/layout/demo.html +538 -0
- package/components/layout/snice-layout-blog.css +129 -0
- package/components/layout/snice-layout-blog.ts +48 -0
- package/components/layout/snice-layout-card.css +104 -0
- package/components/layout/snice-layout-card.ts +35 -0
- package/components/layout/snice-layout-centered.css +51 -0
- package/components/layout/snice-layout-centered.ts +22 -0
- package/components/layout/snice-layout-dashboard.css +98 -0
- package/components/layout/snice-layout-dashboard.ts +45 -0
- package/components/layout/snice-layout-fullscreen.css +72 -0
- package/components/layout/snice-layout-fullscreen.ts +34 -0
- package/components/layout/snice-layout-landing.css +92 -0
- package/components/layout/snice-layout-landing.ts +47 -0
- package/components/layout/snice-layout-minimal.css +16 -0
- package/components/layout/snice-layout-minimal.ts +19 -0
- package/components/layout/snice-layout-sidebar.css +117 -0
- package/components/layout/snice-layout-sidebar.ts +48 -0
- package/components/layout/snice-layout-split.css +103 -0
- package/components/layout/snice-layout-split.ts +29 -0
- package/components/layout/snice-layout.css +72 -0
- package/components/layout/snice-layout.ts +35 -0
- package/components/layout/snice-layout.types.ts +5 -0
- package/components/login/demo-auth-controller.ts +185 -0
- package/components/login/demo.html +470 -0
- package/components/login/snice-login.css +204 -0
- package/components/login/snice-login.ts +337 -0
- package/components/login/snice-login.types.ts +34 -0
- package/components/modal/demo.html +291 -0
- package/components/modal/snice-modal.css +203 -0
- package/components/modal/snice-modal.ts +233 -0
- package/components/modal/snice-modal.types.ts +21 -0
- package/components/pagination/demo.html +395 -0
- package/components/pagination/snice-pagination.ts +333 -0
- package/components/pagination/snice-pagination.types.ts +21 -0
- package/components/progress/demo.html +510 -0
- package/components/progress/snice-progress.css +267 -0
- package/components/progress/snice-progress.ts +247 -0
- package/components/progress/snice-progress.types.ts +19 -0
- package/components/radio/demo.html +287 -0
- package/components/radio/snice-radio.css +171 -0
- package/components/radio/snice-radio.ts +218 -0
- package/components/radio/snice-radio.types.ts +21 -0
- package/components/select/demo.html +511 -0
- package/components/select/snice-option.ts +52 -0
- package/components/select/snice-option.types.ts +14 -0
- package/components/select/snice-select.css +392 -0
- package/components/select/snice-select.ts +796 -0
- package/components/select/snice-select.types.ts +55 -0
- package/components/skeleton/demo.html +514 -0
- package/components/skeleton/snice-skeleton.css +109 -0
- package/components/skeleton/snice-skeleton.ts +126 -0
- package/components/skeleton/snice-skeleton.types.ts +11 -0
- package/components/switch/demo.html +284 -0
- package/components/switch/snice-switch.css +221 -0
- package/components/switch/snice-switch.ts +229 -0
- package/components/switch/snice-switch.types.ts +23 -0
- package/components/symbols.ts +23 -0
- package/components/table/demo-table-controller.ts +100 -0
- package/components/table/demo.html +480 -0
- package/components/table/snice-cell-boolean.ts +112 -0
- package/components/table/snice-cell-date.ts +210 -0
- package/components/table/snice-cell-duration.ts +91 -0
- package/components/table/snice-cell-filesize.ts +90 -0
- package/components/table/snice-cell-number.ts +165 -0
- package/components/table/snice-cell-progress.ts +83 -0
- package/components/table/snice-cell-rating.ts +82 -0
- package/components/table/snice-cell-sparkline.ts +253 -0
- package/components/table/snice-cell-text.ts +125 -0
- package/components/table/snice-cell.css +296 -0
- package/components/table/snice-cell.ts +473 -0
- package/components/table/snice-column.ts +353 -0
- package/components/table/snice-header.css +243 -0
- package/components/table/snice-header.ts +261 -0
- package/components/table/snice-progress.ts +66 -0
- package/components/table/snice-rating.ts +45 -0
- package/components/table/snice-row.css +255 -0
- package/components/table/snice-row.ts +331 -0
- package/components/table/snice-table.css +241 -0
- package/components/table/snice-table.ts +737 -0
- package/components/table/snice-table.types.ts +158 -0
- package/components/tabs/demo.html +487 -0
- package/components/tabs/snice-tab-panel.css +264 -0
- package/components/tabs/snice-tab-panel.ts +47 -0
- package/components/tabs/snice-tab.css +96 -0
- package/components/tabs/snice-tab.ts +65 -0
- package/components/tabs/snice-tabs.css +189 -0
- package/components/tabs/snice-tabs.ts +332 -0
- package/components/tabs/snice-tabs.types.ts +28 -0
- package/components/theme/theme.css +234 -0
- package/components/toast/demo.html +329 -0
- package/components/toast/snice-toast-container.ts +256 -0
- package/components/toast/snice-toast.css +213 -0
- package/components/toast/snice-toast.ts +276 -0
- package/components/toast/snice-toast.types.ts +35 -0
- package/components/tooltip/demo.html +350 -0
- package/components/tooltip/snice-tooltip-portal.css +79 -0
- package/components/tooltip/snice-tooltip.css +117 -0
- package/components/tooltip/snice-tooltip.ts +612 -0
- package/components/tooltip/snice-tooltip.types.ts +32 -0
- package/components/transitions.ts +94 -0
- package/components/tsconfig.json +18 -0
- package/dist/index.cjs +441 -329
- package/dist/index.cjs.map +1 -1
- package/dist/index.cjs.min.map +1 -1
- package/dist/index.esm.js +441 -329
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +3 -3
- package/dist/index.esm.min.js.map +1 -1
- package/dist/index.iife.js +441 -329
- package/dist/index.iife.js.map +1 -1
- package/dist/index.iife.min.js +3 -3
- package/dist/index.iife.min.js.map +1 -1
- package/dist/symbols.esm.js +1 -1
- package/dist/transitions.esm.js +1 -1
- package/dist/types/controller.d.ts +1 -1
- package/dist/types/element.d.ts +10 -10
- package/dist/types/events.d.ts +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/observe.d.ts +1 -1
- package/dist/types/request-response.d.ts +2 -3
- package/dist/types/router.d.ts +1 -1
- package/package.json +9 -3
- package/dist/index.cjs.min +0 -15
- package/dist/symbols.cjs +0 -103
- package/dist/transitions.cjs +0 -219
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* snice v1.14.
|
|
2
|
+
* snice v1.14.3
|
|
3
3
|
* Imperative TypeScript framework for building vanilla web components with decorators, routing, and controllers. No virtual DOM, no build complexity.
|
|
4
4
|
* (c) 2024
|
|
5
5
|
* Released under the MIT License.
|
|
@@ -82,24 +82,27 @@ function on(eventName, selectorOrOptions, options) {
|
|
|
82
82
|
selector = undefined;
|
|
83
83
|
opts = selectorOrOptions;
|
|
84
84
|
}
|
|
85
|
-
return function (target,
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
return function (target, context) {
|
|
86
|
+
const propertyKey = context.name;
|
|
87
|
+
context.addInitializer(function () {
|
|
88
|
+
const constructor = this.constructor;
|
|
89
|
+
// Store event handler metadata
|
|
90
|
+
if (!constructor.prototype[ON_HANDLERS]) {
|
|
91
|
+
constructor.prototype[ON_HANDLERS] = [];
|
|
92
|
+
}
|
|
93
|
+
// Normalize to array and expand at decoration time
|
|
94
|
+
const eventNames = Array.isArray(eventName) ? eventName : [eventName];
|
|
95
|
+
// Create a handler entry for each event
|
|
96
|
+
for (const event of eventNames) {
|
|
97
|
+
constructor.prototype[ON_HANDLERS].push({
|
|
98
|
+
eventName: event,
|
|
99
|
+
selector,
|
|
100
|
+
methodName: propertyKey,
|
|
101
|
+
method: target,
|
|
102
|
+
options: opts
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
});
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
// Helper to setup event handlers for elements
|
|
@@ -293,13 +296,12 @@ function cleanupEventHandlers(instance) {
|
|
|
293
296
|
* @param options Optional configuration extending EventInit
|
|
294
297
|
*/
|
|
295
298
|
function dispatch(eventName, options) {
|
|
296
|
-
return function (
|
|
297
|
-
const originalMethod = descriptor.value;
|
|
299
|
+
return function (originalMethod, _context) {
|
|
298
300
|
// Create timing wrappers for dispatch
|
|
299
301
|
let debounceTimeout;
|
|
300
302
|
let throttleLastCall = 0;
|
|
301
303
|
let throttleTimeout;
|
|
302
|
-
|
|
304
|
+
return function (...args) {
|
|
303
305
|
// Call the original method
|
|
304
306
|
const result = originalMethod.apply(this, args);
|
|
305
307
|
// Helper to dispatch the event
|
|
@@ -354,7 +356,6 @@ function dispatch(eventName, options) {
|
|
|
354
356
|
timedDispatch(result);
|
|
355
357
|
return result;
|
|
356
358
|
};
|
|
357
|
-
return descriptor;
|
|
358
359
|
};
|
|
359
360
|
}
|
|
360
361
|
|
|
@@ -381,27 +382,30 @@ function observe(observeTarget, selectorOrOptions, options) {
|
|
|
381
382
|
selector = undefined;
|
|
382
383
|
opts = selectorOrOptions;
|
|
383
384
|
}
|
|
384
|
-
return function (target,
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
type
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
385
|
+
return function (target, context) {
|
|
386
|
+
const propertyKey = context.name;
|
|
387
|
+
context.addInitializer(function () {
|
|
388
|
+
const constructor = this.constructor;
|
|
389
|
+
// Store observer metadata
|
|
390
|
+
if (!constructor.prototype[OBSERVERS]) {
|
|
391
|
+
constructor.prototype[OBSERVERS] = [];
|
|
392
|
+
}
|
|
393
|
+
// Normalize to array
|
|
394
|
+
const observeTargets = Array.isArray(observeTarget) ? observeTarget : [observeTarget];
|
|
395
|
+
// Create an observer entry for each target
|
|
396
|
+
for (const targetString of observeTargets) {
|
|
397
|
+
// Parse the observation type from the observeTarget string
|
|
398
|
+
const [type, ...modifiers] = targetString.split(':');
|
|
399
|
+
constructor.prototype[OBSERVERS].push({
|
|
400
|
+
type,
|
|
401
|
+
target: modifiers.join(':'), // Rejoin for media queries or mutation types
|
|
402
|
+
selector,
|
|
403
|
+
methodName: propertyKey,
|
|
404
|
+
method: target,
|
|
405
|
+
options: opts
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
});
|
|
405
409
|
};
|
|
406
410
|
}
|
|
407
411
|
// Helper to setup observers for elements
|
|
@@ -694,13 +698,12 @@ function cleanupObservers(instance) {
|
|
|
694
698
|
* @param options Optional configuration
|
|
695
699
|
*/
|
|
696
700
|
function request(requestName, options) {
|
|
697
|
-
return function (
|
|
698
|
-
const originalMethod = descriptor.value;
|
|
701
|
+
return function (originalMethod, _context) {
|
|
699
702
|
// Create timing variables for debounce/throttle
|
|
700
703
|
let debounceTimeout;
|
|
701
704
|
let throttleLastCall = 0;
|
|
702
705
|
let throttleTimeout;
|
|
703
|
-
|
|
706
|
+
return async function (...args) {
|
|
704
707
|
const actualRequest = async () => {
|
|
705
708
|
// @request always acts as requester (client side)
|
|
706
709
|
const responseTimeout = options?.timeout ?? 120000; // Default 2 minute timeout
|
|
@@ -824,7 +827,6 @@ function request(requestName, options) {
|
|
|
824
827
|
// No timing applied, execute immediately
|
|
825
828
|
return actualRequest();
|
|
826
829
|
};
|
|
827
|
-
return descriptor;
|
|
828
830
|
};
|
|
829
831
|
}
|
|
830
832
|
/**
|
|
@@ -834,20 +836,22 @@ function request(requestName, options) {
|
|
|
834
836
|
* @param options Optional configuration
|
|
835
837
|
*/
|
|
836
838
|
function respond(requestName, options) {
|
|
837
|
-
return function (target,
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
839
|
+
return function (target, context) {
|
|
840
|
+
const propertyKey = context.name;
|
|
841
|
+
context.addInitializer(function () {
|
|
842
|
+
const constructor = this.constructor;
|
|
843
|
+
// Store response metadata on the prototype
|
|
844
|
+
// This will be picked up by setupResponseHandlers
|
|
845
|
+
if (!constructor.prototype[CHANNEL_HANDLERS]) {
|
|
846
|
+
constructor.prototype[CHANNEL_HANDLERS] = [];
|
|
847
|
+
}
|
|
848
|
+
constructor.prototype[CHANNEL_HANDLERS].push({
|
|
849
|
+
channelName: requestName,
|
|
850
|
+
methodName: propertyKey,
|
|
851
|
+
method: target,
|
|
852
|
+
options: options
|
|
853
|
+
});
|
|
849
854
|
});
|
|
850
|
-
return descriptor;
|
|
851
855
|
};
|
|
852
856
|
}
|
|
853
857
|
// Helper to setup response handlers for elements and controllers
|
|
@@ -998,7 +1002,7 @@ class ControllerScope {
|
|
|
998
1002
|
* @param name The name to register the controller under
|
|
999
1003
|
*/
|
|
1000
1004
|
function controller(name) {
|
|
1001
|
-
return function (constructor) {
|
|
1005
|
+
return function (constructor, _context) {
|
|
1002
1006
|
snice.controllerRegistry.set(name, constructor);
|
|
1003
1007
|
// Mark as controller class for channel decorator detection
|
|
1004
1008
|
constructor.prototype[IS_CONTROLLER_CLASS] = true;
|
|
@@ -1345,10 +1349,12 @@ function applyElementFunctionality(constructor) {
|
|
|
1345
1349
|
// Mark that properties have been initialized
|
|
1346
1350
|
this[PROPERTIES_INITIALIZED] = true;
|
|
1347
1351
|
// Reflect properties that were explicitly set before connection
|
|
1348
|
-
//
|
|
1349
|
-
if (properties
|
|
1352
|
+
// AND also reflect initial values that have reflect: true
|
|
1353
|
+
if (properties) {
|
|
1350
1354
|
for (const [propName, propOptions] of properties) {
|
|
1351
|
-
|
|
1355
|
+
const wasExplicitlySet = this[EXPLICITLY_SET_PROPERTIES] && this[EXPLICITLY_SET_PROPERTIES].has(propName);
|
|
1356
|
+
const hasInitialValue = propName in this[PROPERTY_VALUES];
|
|
1357
|
+
if (propOptions.reflect && hasInitialValue && (wasExplicitlySet || this[PROPERTY_VALUES][propName] !== undefined)) {
|
|
1352
1358
|
const value = this[PROPERTY_VALUES][propName];
|
|
1353
1359
|
const attributeName = typeof propOptions.attribute === 'string' ? propOptions.attribute : propName.toLowerCase();
|
|
1354
1360
|
if (value !== null && value !== undefined && value !== false &&
|
|
@@ -1597,176 +1603,224 @@ function applyElementFunctionality(constructor) {
|
|
|
1597
1603
|
};
|
|
1598
1604
|
}
|
|
1599
1605
|
function element(tagName) {
|
|
1600
|
-
return function (constructor) {
|
|
1606
|
+
return function (constructor, context) {
|
|
1607
|
+
// Transfer metadata from context to constructor
|
|
1608
|
+
if (context.metadata && context.metadata[PROPERTIES]) {
|
|
1609
|
+
if (!constructor[PROPERTIES]) {
|
|
1610
|
+
constructor[PROPERTIES] = new Map();
|
|
1611
|
+
}
|
|
1612
|
+
for (const [key, value] of context.metadata[PROPERTIES]) {
|
|
1613
|
+
constructor[PROPERTIES].set(key, value);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1601
1616
|
applyElementFunctionality(constructor);
|
|
1602
1617
|
customElements.define(tagName, constructor);
|
|
1618
|
+
return constructor;
|
|
1603
1619
|
};
|
|
1604
1620
|
}
|
|
1605
1621
|
function layout(tagName) {
|
|
1606
|
-
return function (constructor) {
|
|
1622
|
+
return function (constructor, context) {
|
|
1623
|
+
// Transfer metadata from context to constructor
|
|
1624
|
+
if (context.metadata && context.metadata[PROPERTIES]) {
|
|
1625
|
+
if (!constructor[PROPERTIES]) {
|
|
1626
|
+
constructor[PROPERTIES] = new Map();
|
|
1627
|
+
}
|
|
1628
|
+
for (const [key, value] of context.metadata[PROPERTIES]) {
|
|
1629
|
+
constructor[PROPERTIES].set(key, value);
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1607
1632
|
applyElementFunctionality(constructor);
|
|
1608
1633
|
customElements.define(tagName, constructor);
|
|
1634
|
+
return constructor;
|
|
1609
1635
|
};
|
|
1610
1636
|
}
|
|
1611
1637
|
function property(options) {
|
|
1612
|
-
return function (
|
|
1613
|
-
const
|
|
1614
|
-
//
|
|
1638
|
+
return function (_value, context) {
|
|
1639
|
+
const propertyKey = context.name;
|
|
1640
|
+
// Use metadata to store property information at decoration time
|
|
1641
|
+
if (!context.metadata) {
|
|
1642
|
+
context.metadata = {};
|
|
1643
|
+
}
|
|
1644
|
+
if (!context.metadata[PROPERTIES]) {
|
|
1645
|
+
context.metadata[PROPERTIES] = new Map();
|
|
1646
|
+
}
|
|
1647
|
+
context.metadata[PROPERTIES].set(propertyKey, options || {});
|
|
1648
|
+
// Warn about problematic reflection usage at decoration time
|
|
1615
1649
|
if (options?.reflect && options?.type === Array) {
|
|
1616
1650
|
console.warn(`⚠️ Property '${propertyKey}' uses reflect:true with Array type.`);
|
|
1617
1651
|
}
|
|
1618
1652
|
if (options?.reflect && options?.type === Object) {
|
|
1619
1653
|
console.warn(`⚠️ Property '${propertyKey}' uses reflect:true with Object type.`);
|
|
1620
1654
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
set(value) {
|
|
1633
|
-
if (!this[PROPERTY_VALUES]) {
|
|
1634
|
-
this[PROPERTY_VALUES] = {};
|
|
1635
|
-
}
|
|
1636
|
-
if (!this[EXPLICITLY_SET_PROPERTIES]) {
|
|
1637
|
-
this[EXPLICITLY_SET_PROPERTIES] = new Set();
|
|
1638
|
-
}
|
|
1639
|
-
const oldValue = this[PROPERTY_VALUES][propertyKey];
|
|
1640
|
-
// Don't update if value hasn't changed
|
|
1641
|
-
if (oldValue === value)
|
|
1642
|
-
return;
|
|
1643
|
-
// Mark as explicitly set in these cases:
|
|
1644
|
-
// 1. There was a previous value (normal property update)
|
|
1645
|
-
// 2. This is during element construction and we have a non-null/non-undefined value
|
|
1646
|
-
// (this handles default values declared in class properties)
|
|
1647
|
-
const isInitialDefaultValue = oldValue === undefined && !this[PROPERTIES_INITIALIZED];
|
|
1648
|
-
if (oldValue !== undefined || (isInitialDefaultValue && value !== null && value !== undefined)) {
|
|
1649
|
-
this[EXPLICITLY_SET_PROPERTIES].add(propertyKey);
|
|
1650
|
-
}
|
|
1651
|
-
this[PROPERTY_VALUES][propertyKey] = value;
|
|
1652
|
-
// Only reflect to attributes if:
|
|
1653
|
-
// 1. Properties have been initialized from attributes
|
|
1654
|
-
// 2. The property was explicitly set (not just default value)
|
|
1655
|
-
// This prevents default values from creating attributes
|
|
1656
|
-
if (options?.reflect && this.setAttribute && this[PROPERTIES_INITIALIZED] && this[EXPLICITLY_SET_PROPERTIES].has(propertyKey)) {
|
|
1657
|
-
const attributeName = typeof options.attribute === 'string' ? options.attribute : propertyKey.toLowerCase();
|
|
1658
|
-
if (value === null || value === undefined || value === false ||
|
|
1659
|
-
(options?.type === SimpleArray && Array.isArray(value) && value.length === 0)) {
|
|
1660
|
-
this.removeAttribute(attributeName);
|
|
1661
|
-
}
|
|
1662
|
-
else {
|
|
1663
|
-
// Handle special types for reflection
|
|
1664
|
-
let attributeValue;
|
|
1665
|
-
if (value instanceof Date) {
|
|
1666
|
-
attributeValue = value.toISOString();
|
|
1655
|
+
context.addInitializer(function () {
|
|
1656
|
+
// No longer need warnings here since they're at decoration time
|
|
1657
|
+
});
|
|
1658
|
+
// Return a field initializer function for new decorators
|
|
1659
|
+
return function (initialValue) {
|
|
1660
|
+
// Set up the property descriptor on first access
|
|
1661
|
+
if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
|
|
1662
|
+
const descriptor = {
|
|
1663
|
+
get() {
|
|
1664
|
+
if (!this[PROPERTY_VALUES]) {
|
|
1665
|
+
this[PROPERTY_VALUES] = {};
|
|
1667
1666
|
}
|
|
1668
|
-
|
|
1669
|
-
|
|
1667
|
+
return this[PROPERTY_VALUES][propertyKey];
|
|
1668
|
+
},
|
|
1669
|
+
set(newValue) {
|
|
1670
|
+
if (!this[PROPERTY_VALUES]) {
|
|
1671
|
+
this[PROPERTY_VALUES] = {};
|
|
1670
1672
|
}
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
+
if (!this[EXPLICITLY_SET_PROPERTIES]) {
|
|
1674
|
+
this[EXPLICITLY_SET_PROPERTIES] = new Set();
|
|
1673
1675
|
}
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
+
const oldValue = this[PROPERTY_VALUES][propertyKey];
|
|
1677
|
+
if (oldValue === newValue)
|
|
1678
|
+
return;
|
|
1679
|
+
const isInitialDefaultValue = oldValue === undefined && !this[PROPERTIES_INITIALIZED];
|
|
1680
|
+
if (oldValue !== undefined || (isInitialDefaultValue && newValue !== null && newValue !== undefined)) {
|
|
1681
|
+
this[EXPLICITLY_SET_PROPERTIES].add(propertyKey);
|
|
1676
1682
|
}
|
|
1677
|
-
this
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
// Call specific property watchers
|
|
1684
|
-
if (watchers.has(propertyKey)) {
|
|
1685
|
-
const propertyWatchers = watchers.get(propertyKey);
|
|
1686
|
-
for (const watcher of propertyWatchers) {
|
|
1687
|
-
try {
|
|
1688
|
-
// Always pass oldValue, newValue, and propertyName
|
|
1689
|
-
watcher.method.call(this, oldValue, value, propertyKey);
|
|
1683
|
+
this[PROPERTY_VALUES][propertyKey] = newValue;
|
|
1684
|
+
if (options?.reflect && this.setAttribute && this[PROPERTIES_INITIALIZED] && this[EXPLICITLY_SET_PROPERTIES].has(propertyKey)) {
|
|
1685
|
+
const attributeName = typeof options.attribute === 'string' ? options.attribute : propertyKey.toLowerCase();
|
|
1686
|
+
if (newValue === null || newValue === undefined || newValue === false ||
|
|
1687
|
+
(options?.type === SimpleArray && Array.isArray(newValue) && newValue.length === 0)) {
|
|
1688
|
+
this.removeAttribute(attributeName);
|
|
1690
1689
|
}
|
|
1691
|
-
|
|
1692
|
-
|
|
1690
|
+
else {
|
|
1691
|
+
let attributeValue;
|
|
1692
|
+
if (newValue instanceof Date) {
|
|
1693
|
+
attributeValue = newValue.toISOString();
|
|
1694
|
+
}
|
|
1695
|
+
else if (typeof newValue === 'bigint') {
|
|
1696
|
+
attributeValue = newValue.toString() + 'n';
|
|
1697
|
+
}
|
|
1698
|
+
else if (options?.type === SimpleArray && Array.isArray(newValue)) {
|
|
1699
|
+
attributeValue = SimpleArray.serialize(newValue);
|
|
1700
|
+
}
|
|
1701
|
+
else {
|
|
1702
|
+
attributeValue = String(newValue);
|
|
1703
|
+
}
|
|
1704
|
+
this.setAttribute(attributeName, attributeValue);
|
|
1693
1705
|
}
|
|
1694
1706
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1707
|
+
const constructor = this.constructor;
|
|
1708
|
+
const watchers = constructor[PROPERTY_WATCHERS];
|
|
1709
|
+
if (watchers) {
|
|
1710
|
+
if (watchers.has(propertyKey)) {
|
|
1711
|
+
const propertyWatchers = watchers.get(propertyKey);
|
|
1712
|
+
for (const watcher of propertyWatchers) {
|
|
1713
|
+
try {
|
|
1714
|
+
watcher.method.call(this, oldValue, newValue, propertyKey);
|
|
1715
|
+
}
|
|
1716
|
+
catch (error) {
|
|
1717
|
+
console.error(`Error in @watch('${propertyKey}') method ${watcher.methodName}:`, error);
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1703
1720
|
}
|
|
1704
|
-
|
|
1705
|
-
|
|
1721
|
+
if (watchers.has('*')) {
|
|
1722
|
+
const wildcardWatchers = watchers.get('*');
|
|
1723
|
+
for (const watcher of wildcardWatchers) {
|
|
1724
|
+
try {
|
|
1725
|
+
watcher.method.call(this, oldValue, newValue, propertyKey);
|
|
1726
|
+
}
|
|
1727
|
+
catch (error) {
|
|
1728
|
+
console.error(`Error in @watch('*') method ${watcher.methodName}:`, error);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1706
1731
|
}
|
|
1707
1732
|
}
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1733
|
+
if (this.requestUpdate) {
|
|
1734
|
+
this.requestUpdate(propertyKey, oldValue);
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
configurable: true,
|
|
1738
|
+
enumerable: true
|
|
1739
|
+
};
|
|
1740
|
+
Object.defineProperty(this.constructor.prototype, propertyKey, descriptor);
|
|
1741
|
+
}
|
|
1742
|
+
// Initialize the property value
|
|
1743
|
+
if (!this[PROPERTY_VALUES]) {
|
|
1744
|
+
this[PROPERTY_VALUES] = {};
|
|
1745
|
+
}
|
|
1746
|
+
this[PROPERTY_VALUES][propertyKey] = initialValue;
|
|
1747
|
+
return initialValue;
|
|
1717
1748
|
};
|
|
1718
|
-
Object.defineProperty(target, propertyKey, descriptor);
|
|
1719
1749
|
};
|
|
1720
1750
|
}
|
|
1721
1751
|
function query(selector, options = {}) {
|
|
1722
|
-
return function (
|
|
1752
|
+
return function (_value, context) {
|
|
1723
1753
|
// Default to shadow DOM only
|
|
1724
1754
|
const { light = false, shadow = true } = options;
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1755
|
+
const propertyKey = context.name;
|
|
1756
|
+
// Return a field initializer function for new decorators
|
|
1757
|
+
return function (initialValue) {
|
|
1758
|
+
// Set up the property descriptor on first access
|
|
1759
|
+
if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
|
|
1760
|
+
const descriptor = {
|
|
1761
|
+
get() {
|
|
1762
|
+
// Check if this is a controller using the symbol
|
|
1763
|
+
const isController = this[IS_CONTROLLER_INSTANCE] === true;
|
|
1764
|
+
const root = isController && this.element ? this.element : this;
|
|
1765
|
+
// Query in specified contexts
|
|
1766
|
+
let result = null;
|
|
1767
|
+
if (shadow && root.shadowRoot) {
|
|
1768
|
+
result = root.shadowRoot.querySelector(selector);
|
|
1769
|
+
}
|
|
1770
|
+
if (!result && light) {
|
|
1771
|
+
result = root.querySelector(selector);
|
|
1772
|
+
}
|
|
1773
|
+
return result || null;
|
|
1774
|
+
},
|
|
1775
|
+
set() {
|
|
1776
|
+
// Query results are read-only
|
|
1777
|
+
},
|
|
1778
|
+
configurable: true,
|
|
1779
|
+
enumerable: true
|
|
1780
|
+
};
|
|
1781
|
+
Object.defineProperty(this.constructor.prototype, propertyKey, descriptor);
|
|
1782
|
+
}
|
|
1783
|
+
return initialValue;
|
|
1784
|
+
};
|
|
1743
1785
|
};
|
|
1744
1786
|
}
|
|
1745
1787
|
function queryAll(selector, options = {}) {
|
|
1746
|
-
return function (
|
|
1788
|
+
return function (_value, context) {
|
|
1747
1789
|
// Default to shadow DOM only
|
|
1748
1790
|
const { light = false, shadow = true } = options;
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1791
|
+
const propertyKey = context.name;
|
|
1792
|
+
// Return a field initializer function for new decorators
|
|
1793
|
+
return function (initialValue) {
|
|
1794
|
+
// Set up the property descriptor on first access
|
|
1795
|
+
if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
|
|
1796
|
+
const descriptor = {
|
|
1797
|
+
get() {
|
|
1798
|
+
// Check if this is a controller using the symbol
|
|
1799
|
+
const isController = this[IS_CONTROLLER_INSTANCE] === true;
|
|
1800
|
+
const root = isController && this.element ? this.element : this;
|
|
1801
|
+
// Query in specified contexts and combine results
|
|
1802
|
+
const results = [];
|
|
1803
|
+
if (shadow && root.shadowRoot) {
|
|
1804
|
+
const shadowResults = root.shadowRoot.querySelectorAll(selector);
|
|
1805
|
+
results.push(...shadowResults);
|
|
1806
|
+
}
|
|
1807
|
+
if (light) {
|
|
1808
|
+
const lightResults = root.querySelectorAll(selector);
|
|
1809
|
+
results.push(...lightResults);
|
|
1810
|
+
}
|
|
1811
|
+
// Return a static NodeList-like object
|
|
1812
|
+
return results;
|
|
1813
|
+
},
|
|
1814
|
+
set() {
|
|
1815
|
+
// Query results are read-only
|
|
1816
|
+
},
|
|
1817
|
+
configurable: true,
|
|
1818
|
+
enumerable: true
|
|
1819
|
+
};
|
|
1820
|
+
Object.defineProperty(this.constructor.prototype, propertyKey, descriptor);
|
|
1821
|
+
}
|
|
1822
|
+
return initialValue;
|
|
1823
|
+
};
|
|
1770
1824
|
};
|
|
1771
1825
|
}
|
|
1772
1826
|
/**
|
|
@@ -1776,6 +1830,7 @@ function queryAll(selector, options = {}) {
|
|
|
1776
1830
|
* Strings cannot contain the full-width comma character
|
|
1777
1831
|
*/
|
|
1778
1832
|
class SimpleArray {
|
|
1833
|
+
static { this.SEPARATOR = ','; } // U+FF0C Full-width comma
|
|
1779
1834
|
/**
|
|
1780
1835
|
* Serialize array to string for attribute storage
|
|
1781
1836
|
*/
|
|
@@ -1825,24 +1880,25 @@ class SimpleArray {
|
|
|
1825
1880
|
});
|
|
1826
1881
|
}
|
|
1827
1882
|
}
|
|
1828
|
-
SimpleArray.SEPARATOR = ','; // U+FF0C Full-width comma
|
|
1829
1883
|
function watch(...propertyNames) {
|
|
1830
|
-
return function (target,
|
|
1831
|
-
const
|
|
1832
|
-
|
|
1833
|
-
constructor
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1884
|
+
return function (target, context) {
|
|
1885
|
+
const methodName = context.name;
|
|
1886
|
+
context.addInitializer(function () {
|
|
1887
|
+
const constructor = this.constructor;
|
|
1888
|
+
if (!constructor[PROPERTY_WATCHERS]) {
|
|
1889
|
+
constructor[PROPERTY_WATCHERS] = new Map();
|
|
1890
|
+
}
|
|
1891
|
+
// Store the watcher method for each property
|
|
1892
|
+
for (const propertyName of propertyNames) {
|
|
1893
|
+
if (!constructor[PROPERTY_WATCHERS].has(propertyName)) {
|
|
1894
|
+
constructor[PROPERTY_WATCHERS].set(propertyName, []);
|
|
1895
|
+
}
|
|
1896
|
+
constructor[PROPERTY_WATCHERS].get(propertyName).push({
|
|
1897
|
+
methodName,
|
|
1898
|
+
method: target
|
|
1899
|
+
});
|
|
1839
1900
|
}
|
|
1840
|
-
|
|
1841
|
-
methodName,
|
|
1842
|
-
method: descriptor.value
|
|
1843
|
-
});
|
|
1844
|
-
}
|
|
1845
|
-
return descriptor;
|
|
1901
|
+
});
|
|
1846
1902
|
};
|
|
1847
1903
|
}
|
|
1848
1904
|
/**
|
|
@@ -1850,46 +1906,57 @@ function watch(...propertyNames) {
|
|
|
1850
1906
|
* The context is automatically provided to page components by the router
|
|
1851
1907
|
*/
|
|
1852
1908
|
function context() {
|
|
1853
|
-
return function (
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1909
|
+
return function (_value, context) {
|
|
1910
|
+
const propertyKey = context.name;
|
|
1911
|
+
// Return a field initializer function for new decorators
|
|
1912
|
+
return function (initialValue) {
|
|
1913
|
+
// Set up the property descriptor on first access
|
|
1914
|
+
if (!Object.hasOwnProperty.call(this.constructor.prototype, propertyKey)) {
|
|
1915
|
+
const descriptor = {
|
|
1916
|
+
get() {
|
|
1917
|
+
// First check if context is stored directly on this element
|
|
1918
|
+
if (this[ROUTER_CONTEXT] !== undefined) {
|
|
1919
|
+
return this[ROUTER_CONTEXT];
|
|
1920
|
+
}
|
|
1921
|
+
// Otherwise, request context from parent page via event
|
|
1922
|
+
const detail = { target: this };
|
|
1923
|
+
const event = new CustomEvent('@context/request', {
|
|
1924
|
+
bubbles: true,
|
|
1925
|
+
cancelable: true,
|
|
1926
|
+
detail
|
|
1927
|
+
});
|
|
1928
|
+
// Dispatch event and wait for response
|
|
1929
|
+
// Check if this is a controller using the symbol
|
|
1930
|
+
const isController = this[IS_CONTROLLER_INSTANCE] === true;
|
|
1931
|
+
let targetElement = isController && this.element ? this.element : this;
|
|
1932
|
+
// If element is null (e.g., controller was detached), can't get context
|
|
1933
|
+
if (!targetElement || !targetElement.dispatchEvent) {
|
|
1934
|
+
return undefined;
|
|
1935
|
+
}
|
|
1936
|
+
// If we're in shadow DOM, dispatch on the host element to ensure proper bubbling
|
|
1937
|
+
if (targetElement.getRootNode && targetElement.getRootNode() instanceof ShadowRoot) {
|
|
1938
|
+
const shadowRoot = targetElement.getRootNode();
|
|
1939
|
+
targetElement = shadowRoot.host;
|
|
1940
|
+
}
|
|
1941
|
+
targetElement.dispatchEvent(event);
|
|
1942
|
+
// Check if context was provided via the event
|
|
1943
|
+
if (detail.context !== undefined) {
|
|
1944
|
+
// Cache it for future use
|
|
1945
|
+
this[ROUTER_CONTEXT] = detail.context;
|
|
1946
|
+
return detail.context;
|
|
1947
|
+
}
|
|
1948
|
+
return undefined;
|
|
1949
|
+
},
|
|
1950
|
+
set() {
|
|
1951
|
+
// Context is read-only
|
|
1952
|
+
},
|
|
1953
|
+
configurable: true,
|
|
1954
|
+
enumerable: true
|
|
1955
|
+
};
|
|
1956
|
+
Object.defineProperty(this.constructor.prototype, propertyKey, descriptor);
|
|
1957
|
+
}
|
|
1958
|
+
return initialValue;
|
|
1959
|
+
};
|
|
1893
1960
|
};
|
|
1894
1961
|
}
|
|
1895
1962
|
/**
|
|
@@ -1898,16 +1965,18 @@ function context() {
|
|
|
1898
1965
|
* Supports async methods
|
|
1899
1966
|
*/
|
|
1900
1967
|
function ready() {
|
|
1901
|
-
return function (target,
|
|
1902
|
-
const
|
|
1903
|
-
|
|
1904
|
-
constructor
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1968
|
+
return function (target, context) {
|
|
1969
|
+
const methodName = context.name;
|
|
1970
|
+
context.addInitializer(function () {
|
|
1971
|
+
const constructor = this.constructor;
|
|
1972
|
+
if (!constructor[READY_HANDLERS]) {
|
|
1973
|
+
constructor[READY_HANDLERS] = [];
|
|
1974
|
+
}
|
|
1975
|
+
constructor[READY_HANDLERS].push({
|
|
1976
|
+
methodName,
|
|
1977
|
+
method: target
|
|
1978
|
+
});
|
|
1909
1979
|
});
|
|
1910
|
-
return descriptor;
|
|
1911
1980
|
};
|
|
1912
1981
|
}
|
|
1913
1982
|
/**
|
|
@@ -1915,16 +1984,18 @@ function ready() {
|
|
|
1915
1984
|
* Used for cleanup tasks when element is removed from DOM
|
|
1916
1985
|
*/
|
|
1917
1986
|
function dispose() {
|
|
1918
|
-
return function (target,
|
|
1919
|
-
const
|
|
1920
|
-
|
|
1921
|
-
constructor
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1987
|
+
return function (target, context) {
|
|
1988
|
+
const methodName = context.name;
|
|
1989
|
+
context.addInitializer(function () {
|
|
1990
|
+
const constructor = this.constructor;
|
|
1991
|
+
if (!constructor[DISPOSE_HANDLERS]) {
|
|
1992
|
+
constructor[DISPOSE_HANDLERS] = [];
|
|
1993
|
+
}
|
|
1994
|
+
constructor[DISPOSE_HANDLERS].push({
|
|
1995
|
+
methodName,
|
|
1996
|
+
method: target
|
|
1997
|
+
});
|
|
1926
1998
|
});
|
|
1927
|
-
return descriptor;
|
|
1928
1999
|
};
|
|
1929
2000
|
}
|
|
1930
2001
|
/**
|
|
@@ -1933,27 +2004,20 @@ function dispose() {
|
|
|
1933
2004
|
* When the decorated method is called, it automatically re-renders its part
|
|
1934
2005
|
*/
|
|
1935
2006
|
function part(partName, options = {}) {
|
|
1936
|
-
return function (
|
|
1937
|
-
const
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
const originalMethod = descriptor.value;
|
|
1948
|
-
if (!constructor[PARTS]) {
|
|
1949
|
-
constructor[PARTS] = new Map();
|
|
1950
|
-
}
|
|
1951
|
-
constructor[PARTS].set(partName, {
|
|
1952
|
-
methodName,
|
|
1953
|
-
method: originalMethod
|
|
2007
|
+
return function (originalMethod, context) {
|
|
2008
|
+
const methodName = context.name;
|
|
2009
|
+
context.addInitializer(function () {
|
|
2010
|
+
const constructor = this.constructor;
|
|
2011
|
+
if (!constructor[PARTS]) {
|
|
2012
|
+
constructor[PARTS] = new Map();
|
|
2013
|
+
}
|
|
2014
|
+
constructor[PARTS].set(partName, {
|
|
2015
|
+
methodName,
|
|
2016
|
+
method: originalMethod
|
|
2017
|
+
});
|
|
1954
2018
|
});
|
|
1955
|
-
//
|
|
1956
|
-
|
|
2019
|
+
// Return wrapped method that automatically re-renders the part when called
|
|
2020
|
+
return function (...args) {
|
|
1957
2021
|
// Initialize timers storage if not present
|
|
1958
2022
|
if (!this[PART_TIMERS]) {
|
|
1959
2023
|
this[PART_TIMERS] = new Map();
|
|
@@ -1967,58 +2031,96 @@ function part(partName, options = {}) {
|
|
|
1967
2031
|
});
|
|
1968
2032
|
}
|
|
1969
2033
|
const timers = this[PART_TIMERS].get(partName);
|
|
1970
|
-
//
|
|
1971
|
-
const
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
const content = result instanceof Promise ? await result : result;
|
|
1975
|
-
// Re-render the part if shadow DOM exists and content is defined
|
|
2034
|
+
// Call the original method first to get its result
|
|
2035
|
+
const result = originalMethod.apply(this, args);
|
|
2036
|
+
// Helper function to update DOM
|
|
2037
|
+
const updateDOM = (content) => {
|
|
1976
2038
|
if (this.shadowRoot && content !== undefined) {
|
|
1977
2039
|
const partElement = this.shadowRoot.querySelector(`[part="${partName}"]`);
|
|
1978
2040
|
if (partElement) {
|
|
1979
2041
|
partElement.innerHTML = content;
|
|
1980
2042
|
}
|
|
1981
2043
|
}
|
|
1982
|
-
return content;
|
|
1983
2044
|
};
|
|
1984
|
-
//
|
|
1985
|
-
if (
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2045
|
+
// Check if result is a Promise (async method)
|
|
2046
|
+
if (result instanceof Promise) {
|
|
2047
|
+
// Handle async method
|
|
2048
|
+
if (options.debounce !== undefined && options.debounce > 0) {
|
|
2049
|
+
// Debounce: defer DOM update, return original Promise
|
|
2050
|
+
if (timers.debounceTimer) {
|
|
2051
|
+
clearTimeout(timers.debounceTimer);
|
|
2052
|
+
}
|
|
1990
2053
|
timers.debounceTimer = setTimeout(async () => {
|
|
1991
|
-
const
|
|
1992
|
-
|
|
2054
|
+
const content = await result;
|
|
2055
|
+
updateDOM(content);
|
|
1993
2056
|
}, options.debounce);
|
|
2057
|
+
return result;
|
|
2058
|
+
}
|
|
2059
|
+
if (options.throttle !== undefined && options.throttle > 0) {
|
|
2060
|
+
// Throttle: handle timing but return original Promise
|
|
2061
|
+
const now = Date.now();
|
|
2062
|
+
if (timers.lastThrottleCall === 0 || now - timers.lastThrottleCall >= options.throttle) {
|
|
2063
|
+
timers.lastThrottleCall = now;
|
|
2064
|
+
return result.then(content => {
|
|
2065
|
+
updateDOM(content);
|
|
2066
|
+
return content;
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
else {
|
|
2070
|
+
if (!timers.throttleTimer) {
|
|
2071
|
+
const remainingTime = options.throttle - (now - timers.lastThrottleCall);
|
|
2072
|
+
timers.throttleTimer = setTimeout(async () => {
|
|
2073
|
+
timers.throttleTimer = null;
|
|
2074
|
+
timers.lastThrottleCall = Date.now();
|
|
2075
|
+
const content = await result;
|
|
2076
|
+
updateDOM(content);
|
|
2077
|
+
}, remainingTime);
|
|
2078
|
+
}
|
|
2079
|
+
return result;
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
// No timing: update DOM after Promise resolves
|
|
2083
|
+
return result.then(content => {
|
|
2084
|
+
updateDOM(content);
|
|
2085
|
+
return content;
|
|
1994
2086
|
});
|
|
1995
2087
|
}
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
timers.
|
|
2001
|
-
|
|
2088
|
+
else {
|
|
2089
|
+
// Handle sync method
|
|
2090
|
+
if (options.debounce !== undefined && options.debounce > 0) {
|
|
2091
|
+
// Debounce: defer DOM update, return result immediately
|
|
2092
|
+
if (timers.debounceTimer) {
|
|
2093
|
+
clearTimeout(timers.debounceTimer);
|
|
2094
|
+
}
|
|
2095
|
+
timers.debounceTimer = setTimeout(() => {
|
|
2096
|
+
updateDOM(result);
|
|
2097
|
+
}, options.debounce);
|
|
2098
|
+
return result;
|
|
2002
2099
|
}
|
|
2003
|
-
|
|
2004
|
-
//
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
timers.
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2100
|
+
if (options.throttle !== undefined && options.throttle > 0) {
|
|
2101
|
+
// Throttle: handle timing for DOM updates
|
|
2102
|
+
const now = Date.now();
|
|
2103
|
+
if (timers.lastThrottleCall === 0 || now - timers.lastThrottleCall >= options.throttle) {
|
|
2104
|
+
timers.lastThrottleCall = now;
|
|
2105
|
+
updateDOM(result);
|
|
2106
|
+
}
|
|
2107
|
+
else {
|
|
2108
|
+
if (!timers.throttleTimer) {
|
|
2109
|
+
const remainingTime = options.throttle - (now - timers.lastThrottleCall);
|
|
2110
|
+
timers.throttleTimer = setTimeout(() => {
|
|
2111
|
+
timers.throttleTimer = null;
|
|
2112
|
+
timers.lastThrottleCall = Date.now();
|
|
2113
|
+
updateDOM(result);
|
|
2114
|
+
}, remainingTime);
|
|
2115
|
+
}
|
|
2012
2116
|
}
|
|
2013
|
-
|
|
2014
|
-
// The actual render will happen in the scheduled timeout
|
|
2015
|
-
return undefined;
|
|
2117
|
+
return result;
|
|
2016
2118
|
}
|
|
2119
|
+
// No timing: update DOM immediately
|
|
2120
|
+
updateDOM(result);
|
|
2121
|
+
return result;
|
|
2017
2122
|
}
|
|
2018
|
-
// No throttle/debounce - render immediately
|
|
2019
|
-
return await renderPart();
|
|
2020
2123
|
};
|
|
2021
|
-
return descriptor;
|
|
2022
2124
|
};
|
|
2023
2125
|
}
|
|
2024
2126
|
|
|
@@ -2790,7 +2892,16 @@ function Router(options) {
|
|
|
2790
2892
|
* @returns A decorator function to apply to a custom element class.
|
|
2791
2893
|
*/
|
|
2792
2894
|
function page(pageOptions) {
|
|
2793
|
-
return function (constructor) {
|
|
2895
|
+
return function (constructor, context) {
|
|
2896
|
+
// Transfer metadata from context to constructor (for new decorators)
|
|
2897
|
+
if (context.metadata && context.metadata[PROPERTIES]) {
|
|
2898
|
+
if (!constructor[PROPERTIES]) {
|
|
2899
|
+
constructor[PROPERTIES] = new Map();
|
|
2900
|
+
}
|
|
2901
|
+
for (const [key, value] of context.metadata[PROPERTIES]) {
|
|
2902
|
+
constructor[PROPERTIES].set(key, value);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2794
2905
|
// Apply all element functionality (properties, queries, watchers, controllers, etc.)
|
|
2795
2906
|
applyElementFunctionality(constructor);
|
|
2796
2907
|
// Store transition config on constructor for later use
|
|
@@ -2830,6 +2941,7 @@ function Router(options) {
|
|
|
2830
2941
|
customElements.define(pageOptions.tag, constructor);
|
|
2831
2942
|
// Register the routes with guards and layout
|
|
2832
2943
|
pageOptions.routes.forEach(route => register(route, pageOptions.tag, pageOptions.transition, pageOptions.guards, pageOptions.layout));
|
|
2944
|
+
return constructor;
|
|
2833
2945
|
};
|
|
2834
2946
|
}
|
|
2835
2947
|
/**
|