igniteui-webcomponents 7.3.0-beta.0 → 7.3.0-beta.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/CHANGELOG.md +20 -0
- package/animations/player.d.ts +7 -2
- package/animations/player.js +1 -2
- package/animations/player.js.map +1 -1
- package/components/accordion/accordion.js +4 -16
- package/components/accordion/accordion.js.map +1 -1
- package/components/avatar/avatar.d.ts +0 -1
- package/components/avatar/avatar.js +5 -9
- package/components/avatar/avatar.js.map +1 -1
- package/components/badge/badge.d.ts +1 -3
- package/components/badge/badge.js +4 -8
- package/components/badge/badge.js.map +1 -1
- package/components/banner/banner.d.ts +6 -5
- package/components/banner/banner.js +19 -17
- package/components/banner/banner.js.map +1 -1
- package/components/button/button-base.d.ts +1 -1
- package/components/button/button-base.js.map +1 -1
- package/components/button-group/button-group.d.ts +0 -1
- package/components/button-group/button-group.js +12 -17
- package/components/button-group/button-group.js.map +1 -1
- package/components/calendar/base.d.ts +3 -13
- package/components/calendar/base.js +10 -31
- package/components/calendar/base.js.map +1 -1
- package/components/calendar/calendar.d.ts +2 -2
- package/components/calendar/months-view/months-view.d.ts +1 -1
- package/components/calendar/months-view/months-view.js.map +1 -1
- package/components/carousel/carousel-indicator.d.ts +1 -1
- package/components/carousel/carousel-indicator.js +13 -13
- package/components/carousel/carousel-indicator.js.map +1 -1
- package/components/carousel/carousel-slide.d.ts +0 -2
- package/components/carousel/carousel-slide.js +7 -9
- package/components/carousel/carousel-slide.js.map +1 -1
- package/components/carousel/carousel.d.ts +52 -35
- package/components/carousel/carousel.js +136 -122
- package/components/carousel/carousel.js.map +1 -1
- package/components/carousel/themes/carousel.base.css.js +1 -1
- package/components/carousel/themes/carousel.base.css.js.map +1 -1
- package/components/chat/chat-input.d.ts +1 -1
- package/components/chat/chat-input.js +21 -21
- package/components/chat/chat-input.js.map +1 -1
- package/components/chat/chat.d.ts +0 -2
- package/components/chat/chat.js +6 -12
- package/components/chat/chat.js.map +1 -1
- package/components/checkbox/checkbox-base.d.ts +1 -1
- package/components/checkbox/checkbox.d.ts +3 -5
- package/components/checkbox/checkbox.js +33 -44
- package/components/checkbox/checkbox.js.map +1 -1
- package/components/checkbox/switch.d.ts +1 -1
- package/components/checkbox/switch.js +23 -34
- package/components/checkbox/switch.js.map +1 -1
- package/components/chip/chip.d.ts +1 -14
- package/components/chip/chip.js +12 -33
- package/components/chip/chip.js.map +1 -1
- package/components/combo/combo-item.d.ts +1 -3
- package/components/combo/combo-item.js +5 -12
- package/components/combo/combo-item.js.map +1 -1
- package/components/combo/combo.d.ts +7 -20
- package/components/combo/combo.js +59 -81
- package/components/combo/combo.js.map +1 -1
- package/components/date-picker/date-picker.base.d.ts +12 -9
- package/components/date-picker/date-picker.base.js +24 -31
- package/components/date-picker/date-picker.base.js.map +1 -1
- package/components/date-picker/date-picker.d.ts +1 -1
- package/components/date-picker/date-picker.js +3 -5
- package/components/date-picker/date-picker.js.map +1 -1
- package/components/date-range-picker/date-range-input.d.ts +2 -4
- package/components/date-range-picker/date-range-input.js +6 -37
- package/components/date-range-picker/date-range-input.js.map +1 -1
- package/components/date-range-picker/date-range-picker.d.ts +2 -5
- package/components/date-range-picker/date-range-picker.js +15 -28
- package/components/date-range-picker/date-range-picker.js.map +1 -1
- package/components/date-range-picker/predefined-ranges-area.d.ts +2 -2
- package/components/date-range-picker/predefined-ranges-area.js +4 -6
- package/components/date-range-picker/predefined-ranges-area.js.map +1 -1
- package/components/date-range-picker/validators.d.ts +1 -1
- package/components/date-range-picker/validators.js +5 -18
- package/components/date-range-picker/validators.js.map +1 -1
- package/components/date-time-input/date-part.d.ts +2 -1
- package/components/date-time-input/date-part.js +38 -75
- package/components/date-time-input/date-part.js.map +1 -1
- package/components/date-time-input/date-time-input.base.d.ts +31 -12
- package/components/date-time-input/date-time-input.base.js +43 -11
- package/components/date-time-input/date-time-input.base.js.map +1 -1
- package/components/date-time-input/date-time-input.d.ts +1 -3
- package/components/date-time-input/date-time-input.js +7 -40
- package/components/date-time-input/date-time-input.js.map +1 -1
- package/components/date-time-input/datetime-mask-parser.d.ts +8 -0
- package/components/date-time-input/datetime-mask-parser.js +8 -8
- package/components/date-time-input/datetime-mask-parser.js.map +1 -1
- package/components/date-time-input/validators.js +3 -14
- package/components/date-time-input/validators.js.map +1 -1
- package/components/dialog/dialog.d.ts +6 -7
- package/components/dialog/dialog.js +21 -26
- package/components/dialog/dialog.js.map +1 -1
- package/components/divider/divider.d.ts +1 -4
- package/components/divider/divider.js +8 -17
- package/components/divider/divider.js.map +1 -1
- package/components/dropdown/dropdown-group.js +1 -6
- package/components/dropdown/dropdown-group.js.map +1 -1
- package/components/expansion-panel/expansion-panel.d.ts +15 -5
- package/components/expansion-panel/expansion-panel.js +23 -34
- package/components/expansion-panel/expansion-panel.js.map +1 -1
- package/components/file-input/file-input.d.ts +2 -14
- package/components/file-input/file-input.js +5 -23
- package/components/file-input/file-input.js.map +1 -1
- package/components/highlight/highlight.d.ts +6 -8
- package/components/highlight/highlight.js +12 -20
- package/components/highlight/highlight.js.map +1 -1
- package/components/icon/icon.d.ts +1 -1
- package/components/icon/registry/types.d.ts +1 -1
- package/components/icon/registry/types.js.map +1 -1
- package/components/input/input.d.ts +9 -19
- package/components/input/input.js +30 -60
- package/components/input/input.js.map +1 -1
- package/components/mask-input/mask-input.d.ts +1 -1
- package/components/mask-input/mask-input.js +2 -4
- package/components/mask-input/mask-input.js.map +1 -1
- package/components/nav-drawer/nav-drawer.d.ts +7 -7
- package/components/nav-drawer/nav-drawer.js +12 -23
- package/components/nav-drawer/nav-drawer.js.map +1 -1
- package/components/progress/base.d.ts +4 -7
- package/components/progress/base.js +21 -45
- package/components/progress/base.js.map +1 -1
- package/components/qr-code/qr-code.d.ts +1 -1
- package/components/qr-code/qr-code.js +3 -2
- package/components/qr-code/qr-code.js.map +1 -1
- package/components/qr-code/types.d.ts +1 -1
- package/components/qr-code/types.js.map +1 -1
- package/components/radio/controller.d.ts +2 -30
- package/components/radio/controller.js +8 -94
- package/components/radio/controller.js.map +1 -1
- package/components/radio/radio.d.ts +5 -5
- package/components/radio/radio.js +48 -58
- package/components/radio/radio.js.map +1 -1
- package/components/radio-group/radio-group.d.ts +1 -2
- package/components/radio-group/radio-group.js +2 -9
- package/components/radio-group/radio-group.js.map +1 -1
- package/components/rating/rating.d.ts +24 -12
- package/components/rating/rating.js +79 -73
- package/components/rating/rating.js.map +1 -1
- package/components/resize-container/default-ghost.js +4 -3
- package/components/resize-container/default-ghost.js.map +1 -1
- package/components/resize-container/resize-container.d.ts +1 -1
- package/components/resize-container/resize-container.js +5 -3
- package/components/resize-container/resize-container.js.map +1 -1
- package/components/resize-container/resize-controller.js +4 -3
- package/components/resize-container/resize-controller.js.map +1 -1
- package/components/select/select-group.d.ts +2 -1
- package/components/select/select-group.js +7 -11
- package/components/select/select-group.js.map +1 -1
- package/components/select/select.d.ts +3 -4
- package/components/select/select.js +23 -28
- package/components/select/select.js.map +1 -1
- package/components/slider/range-slider.d.ts +3 -2
- package/components/slider/range-slider.js +22 -70
- package/components/slider/range-slider.js.map +1 -1
- package/components/slider/slider-base.d.ts +9 -6
- package/components/slider/slider-base.js +27 -28
- package/components/slider/slider-base.js.map +1 -1
- package/components/slider/slider.js +9 -5
- package/components/slider/slider.js.map +1 -1
- package/components/splitter/splitter.d.ts +1 -1
- package/components/splitter/splitter.js.map +1 -1
- package/components/stepper/step.d.ts +3 -0
- package/components/stepper/step.js +9 -5
- package/components/stepper/step.js.map +1 -1
- package/components/stepper/stepper.d.ts +0 -11
- package/components/stepper/stepper.js +21 -86
- package/components/stepper/stepper.js.map +1 -1
- package/components/tabs/tab.d.ts +1 -1
- package/components/tabs/tab.js +6 -5
- package/components/tabs/tab.js.map +1 -1
- package/components/tabs/tabs.d.ts +1 -5
- package/components/tabs/tabs.js +12 -34
- package/components/tabs/tabs.js.map +1 -1
- package/components/textarea/textarea.d.ts +6 -7
- package/components/textarea/textarea.js +3 -10
- package/components/textarea/textarea.js.map +1 -1
- package/components/theme-provider/theme-provider.d.ts +2 -4
- package/components/theme-provider/theme-provider.js +11 -21
- package/components/theme-provider/theme-provider.js.map +1 -1
- package/components/tile-manager/tile-manager.d.ts +10 -21
- package/components/tile-manager/tile-manager.js +43 -74
- package/components/tile-manager/tile-manager.js.map +1 -1
- package/components/tile-manager/tile.d.ts +10 -18
- package/components/tile-manager/tile.js +50 -67
- package/components/tile-manager/tile.js.map +1 -1
- package/components/tooltip/tooltip.d.ts +4 -7
- package/components/tooltip/tooltip.js +20 -28
- package/components/tooltip/tooltip.js.map +1 -1
- package/components/tree/tree.d.ts +1 -14
- package/components/tree/tree.js +5 -23
- package/components/tree/tree.js.map +1 -1
- package/components/tree/tree.navigation.d.ts +1 -1
- package/components/tree/tree.navigation.js.map +1 -1
- package/components/validation-container/validation-container.d.ts +1 -2
- package/components/validation-container/validation-container.js.map +1 -1
- package/components/virtualization/engine.d.ts +40 -38
- package/components/virtualization/engine.js.map +1 -1
- package/components/virtualization/types.d.ts +6 -5
- package/components/virtualization/types.js.map +1 -1
- package/components/virtualization/virtualization.d.ts +94 -80
- package/components/virtualization/virtualization.js +10 -2
- package/components/virtualization/virtualization.js.map +1 -1
- package/custom-elements.json +9940 -7738
- package/igniteui-webcomponents.css-data.json +1 -1
- package/igniteui-webcomponents.html-data.json +1 -1
- package/internals/controllers/aria-projection.d.ts +6 -6
- package/internals/controllers/aria-projection.js.map +1 -1
- package/internals/controllers/context-provider.d.ts +48 -0
- package/internals/controllers/context-provider.js +29 -0
- package/internals/controllers/context-provider.js.map +1 -0
- package/internals/controllers/drag.js +6 -6
- package/internals/controllers/drag.js.map +1 -1
- package/internals/controllers/gestures.js +3 -0
- package/internals/controllers/gestures.js.map +1 -1
- package/internals/controllers/group.d.ts +64 -0
- package/internals/controllers/group.js +104 -0
- package/internals/controllers/group.js.map +1 -0
- package/internals/controllers/internals.d.ts +16 -3
- package/internals/controllers/internals.js +10 -3
- package/internals/controllers/internals.js.map +1 -1
- package/internals/controllers/key-bindings.d.ts +6 -0
- package/internals/controllers/key-bindings.js +3 -0
- package/internals/controllers/key-bindings.js.map +1 -1
- package/internals/controllers/roving-focus.d.ts +72 -0
- package/internals/controllers/roving-focus.js +61 -0
- package/internals/controllers/roving-focus.js.map +1 -0
- package/internals/controllers/slot.d.ts +8 -0
- package/internals/controllers/slot.js +4 -0
- package/internals/controllers/slot.js.map +1 -1
- package/internals/controllers/toggle.d.ts +96 -0
- package/internals/controllers/toggle.js +65 -0
- package/internals/controllers/toggle.js.map +1 -0
- package/internals/date/converters.js +2 -5
- package/internals/date/converters.js.map +1 -1
- package/internals/date/model.d.ts +4 -0
- package/internals/date/model.js +6 -0
- package/internals/date/model.js.map +1 -1
- package/internals/decorators/coerced-property.d.ts +47 -0
- package/internals/decorators/coerced-property.js +36 -0
- package/internals/decorators/coerced-property.js.map +1 -0
- package/internals/i18n/i18n-controller.d.ts +22 -3
- package/internals/i18n/i18n-controller.js +28 -6
- package/internals/i18n/i18n-controller.js.map +1 -1
- package/internals/mixins/alert.d.ts +1 -1
- package/internals/mixins/alert.js +5 -3
- package/internals/mixins/alert.js.map +1 -1
- package/internals/mixins/combo-box.d.ts +3 -12
- package/internals/mixins/combo-box.js +6 -32
- package/internals/mixins/combo-box.js.map +1 -1
- package/internals/mixins/forms/associated.js +18 -0
- package/internals/mixins/forms/associated.js.map +1 -1
- package/internals/mixins/forms/types.d.ts +20 -1
- package/internals/mixins/forms/types.js.map +1 -1
- package/internals/mixins/i18n.d.ts +31 -0
- package/internals/mixins/i18n.js +36 -0
- package/internals/mixins/i18n.js.map +1 -0
- package/internals/mixins/mask-behavior.d.ts +6 -5
- package/internals/mixins/mask-behavior.js +1 -2
- package/internals/mixins/mask-behavior.js.map +1 -1
- package/internals/mixins/option.js +4 -2
- package/internals/mixins/option.js.map +1 -1
- package/internals/templates/masked-input.d.ts +1 -1
- package/internals/templates/masked-input.js.map +1 -1
- package/internals/templates/slotted-icon.d.ts +32 -0
- package/internals/templates/slotted-icon.js +19 -0
- package/internals/templates/slotted-icon.js.map +1 -0
- package/internals/templates/toggle-shell.d.ts +46 -0
- package/internals/templates/toggle-shell.js +38 -0
- package/internals/templates/toggle-shell.js.map +1 -0
- package/internals/timing.d.ts +32 -0
- package/internals/timing.js +20 -0
- package/internals/timing.js.map +1 -0
- package/internals/utils/arrays.d.ts +2 -2
- package/internals/utils/arrays.js.map +1 -1
- package/internals/utils/dom.d.ts +22 -0
- package/internals/utils/dom.js +15 -1
- package/internals/utils/dom.js.map +1 -1
- package/internals/utils/math.d.ts +1 -1
- package/internals/utils/math.js.map +1 -1
- package/internals/utils/types.d.ts +1 -1
- package/internals/utils/types.js.map +1 -1
- package/internals/validators.d.ts +23 -0
- package/internals/validators.js +21 -0
- package/internals/validators.js.map +1 -1
- package/package.json +1 -1
- package/theming/theming-controller.d.ts +3 -3
- package/theming/theming-controller.js.map +1 -1
- package/web-types.json +2 -2
- package/internals/decorators/watch.d.ts +0 -5
- package/internals/decorators/watch.js +0 -19
- package/internals/decorators/watch.js.map +0 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { LitElement } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* The events emitted by a {@link ToggleController}.
|
|
4
|
+
*
|
|
5
|
+
* Include (a subset of) these in a host's event map to document them.
|
|
6
|
+
*/
|
|
7
|
+
export interface ToggleEventMap {
|
|
8
|
+
/** Emitted before opening. Cancelable - preventing it aborts the sequence. */
|
|
9
|
+
igcOpening: CustomEvent<unknown>;
|
|
10
|
+
/** Emitted after the host has opened and its transition has completed. */
|
|
11
|
+
igcOpened: CustomEvent<unknown>;
|
|
12
|
+
/** Emitted before closing. Cancelable - preventing it aborts the sequence. */
|
|
13
|
+
igcClosing: CustomEvent<unknown>;
|
|
14
|
+
/** Emitted after the host has closed and its transition has completed. */
|
|
15
|
+
igcClosed: CustomEvent<unknown>;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A toggleable host must expose the event-emitter mixin's `emitEvent` -
|
|
19
|
+
* extend {@link ../mixins/event-emitter.js#EventEmitterMixin | EventEmitterMixin}
|
|
20
|
+
* with (a subset of) the {@link ToggleEventMap}.
|
|
21
|
+
*/
|
|
22
|
+
type ToggleHost = LitElement & {
|
|
23
|
+
open: boolean;
|
|
24
|
+
emitEvent(name: string, init?: CustomEventInit): boolean;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Runs the host's visual transition to the requested state - flipping `open`,
|
|
28
|
+
* playing animations, awaiting updates - in whatever order the host needs.
|
|
29
|
+
*
|
|
30
|
+
* Resolving `false` marks the transition as superseded (an animation was
|
|
31
|
+
* interrupted by a newer one), which skips the trailing "-ed" event.
|
|
32
|
+
*/
|
|
33
|
+
type ToggleTransitionFunction = (open: boolean) => Promise<boolean> | boolean;
|
|
34
|
+
type ToggleControllerOptions = {
|
|
35
|
+
/**
|
|
36
|
+
* The host transition. When omitted, the controller flips `host.open` itself
|
|
37
|
+
* and the transition always counts as completed.
|
|
38
|
+
*/
|
|
39
|
+
transition?: ToggleTransitionFunction;
|
|
40
|
+
/** Factory for the `detail` payload of the emitted events. */
|
|
41
|
+
detail?: () => unknown;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Implements the open/close choreography shared by every toggleable component:
|
|
45
|
+
*
|
|
46
|
+
* 1. Bail when the host is already in the requested state.
|
|
47
|
+
* 2. When emitting, fire the cancelable `igcOpening`/`igcClosing` event and
|
|
48
|
+
* bail if the consumer prevented it.
|
|
49
|
+
* 3. Run the host transition.
|
|
50
|
+
* 4. When emitting and the transition completed, await the host update and
|
|
51
|
+
* fire the `igcOpened`/`igcClosed` event.
|
|
52
|
+
*
|
|
53
|
+
* The host keeps its public `open` property, `show()`/`hide()`/`toggle()`
|
|
54
|
+
* methods and event documentation, and delegates to the controller.
|
|
55
|
+
*
|
|
56
|
+
* Unlike the other controllers of this directory it is not registered with the
|
|
57
|
+
* host - it drives the host on demand and has no life-cycle of its own.
|
|
58
|
+
*/
|
|
59
|
+
declare class ToggleController {
|
|
60
|
+
private readonly _host;
|
|
61
|
+
private readonly _options;
|
|
62
|
+
/** The target of an in-flight operation - a transition may flip `host.open` only at its end. */
|
|
63
|
+
private _pending?;
|
|
64
|
+
/** Bumped per operation, so a superseded one can bail out instead of finishing. */
|
|
65
|
+
private _generation;
|
|
66
|
+
constructor(host: ToggleHost, options?: ToggleControllerOptions);
|
|
67
|
+
/**
|
|
68
|
+
* Events go through the host's `emitEvent` - it is the choke point
|
|
69
|
+
* consumers and framework wrappers observe.
|
|
70
|
+
*/
|
|
71
|
+
private _emit;
|
|
72
|
+
private _setOpenState;
|
|
73
|
+
/**
|
|
74
|
+
* Opens the host. When `emitEvents` is true, wraps the transition in
|
|
75
|
+
* `igcOpening`/`igcOpened` events.
|
|
76
|
+
*
|
|
77
|
+
* Returns `false` when the host was already open (or heading there), the
|
|
78
|
+
* opening event was canceled, or the operation was superseded - either by the
|
|
79
|
+
* transition reporting itself interrupted or by a newer request.
|
|
80
|
+
*/
|
|
81
|
+
show(emitEvents?: boolean): Promise<boolean>;
|
|
82
|
+
/**
|
|
83
|
+
* Closes the host. When `emitEvents` is true, wraps the transition in
|
|
84
|
+
* `igcClosing`/`igcClosed` events.
|
|
85
|
+
*
|
|
86
|
+
* Returns `false` when the host was already closed (or heading there), the
|
|
87
|
+
* closing event was canceled, or the operation was superseded - either by the
|
|
88
|
+
* transition reporting itself interrupted or by a newer request.
|
|
89
|
+
*/
|
|
90
|
+
hide(emitEvents?: boolean): Promise<boolean>;
|
|
91
|
+
/** Opens or closes the host based on its current state. */
|
|
92
|
+
toggle(emitEvents?: boolean): Promise<boolean>;
|
|
93
|
+
}
|
|
94
|
+
/** Creates and adds a {@link ToggleController} to the given host. */
|
|
95
|
+
export declare function addToggleController(host: ToggleHost, options?: ToggleControllerOptions): ToggleController;
|
|
96
|
+
export type { ToggleController, ToggleControllerOptions, ToggleHost };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class ToggleController {
|
|
2
|
+
constructor(host, options) {
|
|
3
|
+
this._generation = 0;
|
|
4
|
+
this._host = host;
|
|
5
|
+
this._options = { ...options };
|
|
6
|
+
}
|
|
7
|
+
_emit(name, cancelable) {
|
|
8
|
+
const host = this._host;
|
|
9
|
+
const detail = this._options.detail?.call(host);
|
|
10
|
+
return host.emitEvent(name, {
|
|
11
|
+
...(cancelable && { cancelable }),
|
|
12
|
+
...(detail !== undefined && { detail }),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
async _setOpenState(open, emitEvents) {
|
|
16
|
+
const host = this._host;
|
|
17
|
+
const { transition } = this._options;
|
|
18
|
+
if ((this._pending ?? host.open) === open) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (emitEvents && !this._emit(open ? 'igcOpening' : 'igcClosing', true)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const generation = ++this._generation;
|
|
25
|
+
this._pending = open;
|
|
26
|
+
let completed = true;
|
|
27
|
+
try {
|
|
28
|
+
if (transition) {
|
|
29
|
+
completed = (await transition.call(host, open)) !== false;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
host.open = open;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
finally {
|
|
36
|
+
if (generation === this._generation) {
|
|
37
|
+
this._pending = undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (generation !== this._generation) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (emitEvents && completed) {
|
|
44
|
+
await host.updateComplete;
|
|
45
|
+
if (generation !== this._generation) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
this._emit(open ? 'igcOpened' : 'igcClosed', false);
|
|
49
|
+
}
|
|
50
|
+
return completed;
|
|
51
|
+
}
|
|
52
|
+
show(emitEvents = false) {
|
|
53
|
+
return this._setOpenState(true, emitEvents);
|
|
54
|
+
}
|
|
55
|
+
hide(emitEvents = false) {
|
|
56
|
+
return this._setOpenState(false, emitEvents);
|
|
57
|
+
}
|
|
58
|
+
toggle(emitEvents = false) {
|
|
59
|
+
return this._host.open ? this.hide(emitEvents) : this.show(emitEvents);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function addToggleController(host, options) {
|
|
63
|
+
return new ToggleController(host, options);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=toggle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toggle.js","sourceRoot":"","sources":["../../../src/internals/controllers/toggle.ts"],"names":[],"mappings":"AA+DA,MAAM,gBAAgB;IAUpB,YAAY,IAAgB,EAAE,OAAiC;QAFvD,gBAAW,GAAG,CAAC,CAAC;QAGtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;IACjC,CAAC;IAMO,KAAK,CAAC,IAA0B,EAAE,UAAmB;QAC3D,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAIhD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;YAC1B,GAAG,CAAC,UAAU,IAAI,EAAE,UAAU,EAAE,CAAC;YACjC,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC;SACxC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,IAAa,EACb,UAAmB;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;QAErC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAC1C,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC;YACxE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,UAAU,GAAG,EAAE,IAAI,CAAC,WAAW,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAKrB,IAAI,SAAS,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,UAAU,EAAE,CAAC;gBACf,SAAS,GAAG,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC;YAC5D,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACnB,CAAC;QACH,CAAC;gBAAS,CAAC;YAET,IAAI,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACpC,IAAI,CAAC,QAAQ,GAAG,SAAS,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,IAAI,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,cAAc,CAAC;YAG1B,IAAI,UAAU,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC;gBACpC,OAAO,KAAK,CAAC;YACf,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtD,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAiBM,IAAI,CAAC,UAAU,GAAG,KAAK;QAC5B,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAC9C,CAAC;IAUM,IAAI,CAAC,UAAU,GAAG,KAAK;QAC5B,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAC/C,CAAC;IAGM,MAAM,CAAC,UAAU,GAAG,KAAK;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACzE,CAAC;CACF;AAGD,MAAM,UAAU,mBAAmB,CACjC,IAAgB,EAChB,OAAiC;IAEjC,OAAO,IAAI,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["import type { LitElement } from 'lit';\n\n/**\n * The events emitted by a {@link ToggleController}.\n *\n * Include (a subset of) these in a host's event map to document them.\n */\nexport interface ToggleEventMap {\n /** Emitted before opening. Cancelable - preventing it aborts the sequence. */\n igcOpening: CustomEvent<unknown>;\n /** Emitted after the host has opened and its transition has completed. */\n igcOpened: CustomEvent<unknown>;\n /** Emitted before closing. Cancelable - preventing it aborts the sequence. */\n igcClosing: CustomEvent<unknown>;\n /** Emitted after the host has closed and its transition has completed. */\n igcClosed: CustomEvent<unknown>;\n}\n\n/**\n * A toggleable host must expose the event-emitter mixin's `emitEvent` -\n * extend {@link ../mixins/event-emitter.js#EventEmitterMixin | EventEmitterMixin}\n * with (a subset of) the {@link ToggleEventMap}.\n */\ntype ToggleHost = LitElement & {\n open: boolean;\n emitEvent(name: string, init?: CustomEventInit): boolean;\n};\n\n/**\n * Runs the host's visual transition to the requested state - flipping `open`,\n * playing animations, awaiting updates - in whatever order the host needs.\n *\n * Resolving `false` marks the transition as superseded (an animation was\n * interrupted by a newer one), which skips the trailing \"-ed\" event.\n */\ntype ToggleTransitionFunction = (open: boolean) => Promise<boolean> | boolean;\n\ntype ToggleControllerOptions = {\n /**\n * The host transition. When omitted, the controller flips `host.open` itself\n * and the transition always counts as completed.\n */\n transition?: ToggleTransitionFunction;\n /** Factory for the `detail` payload of the emitted events. */\n detail?: () => unknown;\n};\n\n/**\n * Implements the open/close choreography shared by every toggleable component:\n *\n * 1. Bail when the host is already in the requested state.\n * 2. When emitting, fire the cancelable `igcOpening`/`igcClosing` event and\n * bail if the consumer prevented it.\n * 3. Run the host transition.\n * 4. When emitting and the transition completed, await the host update and\n * fire the `igcOpened`/`igcClosed` event.\n *\n * The host keeps its public `open` property, `show()`/`hide()`/`toggle()`\n * methods and event documentation, and delegates to the controller.\n *\n * Unlike the other controllers of this directory it is not registered with the\n * host - it drives the host on demand and has no life-cycle of its own.\n */\nclass ToggleController {\n private readonly _host: ToggleHost;\n private readonly _options: ToggleControllerOptions;\n\n /** The target of an in-flight operation - a transition may flip `host.open` only at its end. */\n private _pending?: boolean;\n\n /** Bumped per operation, so a superseded one can bail out instead of finishing. */\n private _generation = 0;\n\n constructor(host: ToggleHost, options?: ToggleControllerOptions) {\n this._host = host;\n this._options = { ...options };\n }\n\n /**\n * Events go through the host's `emitEvent` - it is the choke point\n * consumers and framework wrappers observe.\n */\n private _emit(name: keyof ToggleEventMap, cancelable: boolean): boolean {\n const host = this._host;\n const detail = this._options.detail?.call(host);\n\n // Both keys are omitted rather than passed as falsy, so that `emitEvent`\n // applies its own defaults and the init of a plain event stays empty.\n return host.emitEvent(name, {\n ...(cancelable && { cancelable }),\n ...(detail !== undefined && { detail }),\n });\n }\n\n private async _setOpenState(\n open: boolean,\n emitEvents: boolean\n ): Promise<boolean> {\n const host = this._host;\n const { transition } = this._options;\n\n if ((this._pending ?? host.open) === open) {\n return false;\n }\n\n if (emitEvents && !this._emit(open ? 'igcOpening' : 'igcClosing', true)) {\n return false;\n }\n\n const generation = ++this._generation;\n this._pending = open;\n\n // The default transition runs synchronously so the state flip - and the\n // `updateComplete` subscription below - happen within the caller's own\n // microtask, exactly as if the host had flipped the property itself.\n let completed = true;\n try {\n if (transition) {\n completed = (await transition.call(host, open)) !== false;\n } else {\n host.open = open;\n }\n } finally {\n // A newer operation owns the pending state from here on.\n if (generation === this._generation) {\n this._pending = undefined;\n }\n }\n\n if (generation !== this._generation) {\n return false;\n }\n\n if (emitEvents && completed) {\n await host.updateComplete;\n\n // A newer operation may have taken over while the update settled.\n if (generation !== this._generation) {\n return false;\n }\n\n this._emit(open ? 'igcOpened' : 'igcClosed', false);\n }\n\n return completed;\n }\n\n /*\n * The methods below deliberately return the underlying promise instead of\n * being `async` - every `async` wrapper that returns a promise costs extra\n * microtask hops on resolution, which shifts the timing of caller code\n * (e.g. focus management) relative to `updateComplete` subscribers.\n */\n\n /**\n * Opens the host. When `emitEvents` is true, wraps the transition in\n * `igcOpening`/`igcOpened` events.\n *\n * Returns `false` when the host was already open (or heading there), the\n * opening event was canceled, or the operation was superseded - either by the\n * transition reporting itself interrupted or by a newer request.\n */\n public show(emitEvents = false): Promise<boolean> {\n return this._setOpenState(true, emitEvents);\n }\n\n /**\n * Closes the host. When `emitEvents` is true, wraps the transition in\n * `igcClosing`/`igcClosed` events.\n *\n * Returns `false` when the host was already closed (or heading there), the\n * closing event was canceled, or the operation was superseded - either by the\n * transition reporting itself interrupted or by a newer request.\n */\n public hide(emitEvents = false): Promise<boolean> {\n return this._setOpenState(false, emitEvents);\n }\n\n /** Opens or closes the host based on its current state. */\n public toggle(emitEvents = false): Promise<boolean> {\n return this._host.open ? this.hide(emitEvents) : this.show(emitEvents);\n }\n}\n\n/** Creates and adds a {@link ToggleController} to the given host. */\nexport function addToggleController(\n host: ToggleHost,\n options?: ToggleControllerOptions\n): ToggleController {\n return new ToggleController(host, options);\n}\n\nexport type { ToggleController, ToggleControllerOptions, ToggleHost };\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isPlainObject, isString } from '../utils/types.js';
|
|
2
|
-
import { CalendarDay } from './model.js';
|
|
2
|
+
import { CalendarDay, truncateTime } from './model.js';
|
|
3
3
|
const ISO_DATE_PATTERN = /^\d{4}/;
|
|
4
4
|
const TIME_PATTERN = /^\d{2}:\d{2}/;
|
|
5
5
|
export function isValidDate(value) {
|
|
@@ -62,10 +62,7 @@ export function convertToDateRange(value) {
|
|
|
62
62
|
}
|
|
63
63
|
const start = convertToDate(parsed.start);
|
|
64
64
|
const end = convertToDate(parsed.end);
|
|
65
|
-
return {
|
|
66
|
-
start: start ? CalendarDay.from(start).native : null,
|
|
67
|
-
end: end ? CalendarDay.from(end).native : null,
|
|
68
|
-
};
|
|
65
|
+
return { start: truncateTime(start), end: truncateTime(end) };
|
|
69
66
|
}
|
|
70
67
|
export function getDateFormValue(value) {
|
|
71
68
|
return value ? value.toISOString() : null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/internals/date/converters.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"converters.js","sourceRoot":"","sources":["../../../src/internals/date/converters.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DateRangeValue } from '../../components/types.js';\nimport { isPlainObject, isString } from '../utils/types.js';\nimport { CalendarDay, truncateTime } from './model.js';\n\n/** Matches a string beginning with a four digit year, which is left to `Date` to parse. */\nconst ISO_DATE_PATTERN = /^\\d{4}/;\n\n/** Matches a time only string - `HH:MM` optionally followed by seconds and milliseconds. */\nconst TIME_PATTERN = /^\\d{2}:\\d{2}/;\n\n/** Whether `value` is a `Date` holding a valid time. */\nexport function isValidDate(value: unknown): value is Date {\n return value instanceof Date && !Number.isNaN(value.getTime());\n}\n\nfunction getValidDate(date: Date): Date | null {\n return isValidDate(date) ? date : null;\n}\n\n/** Parses an ISO 8601 date, or a time only string against the current date. */\nfunction parseISODate(value: string): Date | null {\n const string = value.trim();\n\n if (ISO_DATE_PATTERN.test(string)) {\n const timeComponent = !string.includes('T') ? 'T00:00:00' : '';\n return getValidDate(new Date(`${string}${timeComponent}`));\n }\n\n if (TIME_PATTERN.test(string)) {\n const today = CalendarDay.today;\n const month = `${today.month + 1}`.padStart(2, '0');\n const date = `${today.date}`.padStart(2, '0');\n\n return getValidDate(new Date(`${today.year}-${month}-${date}T${string}`));\n }\n\n return null;\n}\n\n/** Converts `value` to a `Date`, or to `null` when it is empty or cannot be parsed. */\nexport function convertToDate(value?: Date | string | null): Date | null {\n if (!value) {\n return null;\n }\n\n return isString(value) ? parseISODate(value) : getValidDate(value);\n}\n\n/**\n * Converts a comma-separated string of ISO 8601 dates, or an array of dates and ISO 8601\n * strings, into an array of `Date` objects, dropping the ones which cannot be parsed.\n */\nexport function convertToDates(\n value?: (Date | string)[] | string | null\n): Date[] | null {\n if (!value) {\n return null;\n }\n\n const values: Date[] = [];\n const sources = isString(value) ? value.split(',') : value;\n\n for (const source of sources) {\n const trimmed = isString(source) ? source.trim() : source;\n const date = convertToDate(trimmed);\n if (date) {\n values.push(date);\n }\n }\n\n return values;\n}\n\n/**\n * Converts `value` to a `DateRangeValue`, parsing a string as JSON and truncating the\n * time of both endpoints. Malformed input converts to `null` rather than throwing, since\n * this runs as an attribute converter.\n */\nexport function convertToDateRange(\n value?: DateRangeValue | string | null\n): DateRangeValue | null {\n if (!value) {\n return null;\n }\n\n if (!isString(value)) {\n return value;\n }\n\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(value);\n } catch {\n return null;\n }\n\n if (!isPlainObject(parsed)) {\n return null;\n }\n\n const start = convertToDate(parsed.start as Date | string | null);\n const end = convertToDate(parsed.end as Date | string | null);\n\n return { start: truncateTime(start), end: truncateTime(end) };\n}\n\n/** Converts a `Date` to an ISO 8601 string. */\nexport function getDateFormValue(value: Date | null): string | null {\n return value ? value.toISOString() : null;\n}\n"]}
|
|
@@ -13,6 +13,10 @@ type CalendarDayParams = {
|
|
|
13
13
|
};
|
|
14
14
|
export declare const DAYS_IN_WEEK = 7;
|
|
15
15
|
export declare function toCalendarDay(date: DayParameter): CalendarDay;
|
|
16
|
+
/** Null-preserving {@link toCalendarDay}: empty values convert to `null`. */
|
|
17
|
+
export declare function toCalendarDayOrNull(date?: DayParameter | null): CalendarDay | null;
|
|
18
|
+
/** Truncates the time portion of `date`, passing empty values through as `null`. */
|
|
19
|
+
export declare function truncateTime(date?: Date | null): Date | null;
|
|
16
20
|
/**
|
|
17
21
|
* Yields the days between `start` and `end`, stepping by `unit` and stopping short of
|
|
18
22
|
* `end` unless `inclusive` is set.
|
package/internals/date/model.js
CHANGED
|
@@ -5,6 +5,12 @@ const WEEKDAY_MAX = 5;
|
|
|
5
5
|
export function toCalendarDay(date) {
|
|
6
6
|
return date instanceof Date ? CalendarDay.from(date) : date;
|
|
7
7
|
}
|
|
8
|
+
export function toCalendarDayOrNull(date) {
|
|
9
|
+
return date ? toCalendarDay(date) : null;
|
|
10
|
+
}
|
|
11
|
+
export function truncateTime(date) {
|
|
12
|
+
return date ? CalendarDay.from(date).native : null;
|
|
13
|
+
}
|
|
8
14
|
export function* calendarRange(options) {
|
|
9
15
|
const { start, end, unit = 'day', inclusive = false } = options;
|
|
10
16
|
let currentDate = toCalendarDay(start);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/internals/date/model.ts"],"names":[],"mappings":"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","sourcesContent":["export type DayParameter = CalendarDay | Date;\n\nexport type CalendarRangeParams = {\n start: DayParameter;\n end: DayParameter | number;\n unit?: DayInterval;\n inclusive?: boolean;\n};\n\ntype DayInterval = 'year' | 'quarter' | 'month' | 'week' | 'day';\n\ntype CalendarDayParams = {\n year: number;\n month: number;\n date?: number;\n};\n\nexport const DAYS_IN_WEEK = 7;\nconst MILLISECONDS_PER_DAY = 86400000;\nconst WEEKDAY_MIN = 1; // Monday\nconst WEEKDAY_MAX = 5; // Friday\n\nexport function toCalendarDay(date: DayParameter): CalendarDay {\n return date instanceof Date ? CalendarDay.from(date) : date;\n}\n\n/**\n * Yields the days between `start` and `end`, stepping by `unit` and stopping short of\n * `end` unless `inclusive` is set.\n */\nexport function* calendarRange(\n options: CalendarRangeParams\n): Generator<CalendarDay, void, unknown> {\n const { start, end, unit = 'day', inclusive = false } = options;\n\n let currentDate = toCalendarDay(start);\n const endDate =\n typeof end === 'number'\n ? toCalendarDay(start).add(unit, end)\n : toCalendarDay(end);\n\n const isReversed = endDate.lessThan(currentDate);\n const step = isReversed ? -1 : 1;\n\n const shouldContinue = () => {\n if (inclusive) {\n return isReversed\n ? currentDate.greaterThanOrEqual(endDate)\n : currentDate.lessThanOrEqual(endDate);\n }\n return isReversed\n ? currentDate.greaterThan(endDate)\n : currentDate.lessThan(endDate);\n };\n\n while (shouldContinue()) {\n yield currentDate;\n currentDate = currentDate.add(unit, step);\n }\n}\n\nfunction checkRollover(\n original: CalendarDay,\n modified: CalendarDay\n): CalendarDay {\n return original.date !== modified.date ? modified.set({ date: 0 }) : modified;\n}\n\n/* blazorSuppress */\nexport class CalendarDay {\n private readonly _date: Date;\n\n /** Constructs and returns the current day. */\n public static get today(): CalendarDay {\n return CalendarDay.from(new Date());\n }\n\n /** Constructs a new CalendarDay instance from a Date object. */\n public static from(date: Date): CalendarDay {\n return new CalendarDay({\n year: date.getFullYear(),\n month: date.getMonth(),\n date: date.getDate(),\n });\n }\n\n /**\n * Compares the date portion of two date objects.\n *\n * @returns\n * ```\n * first === second // 0\n * first > second // 1\n * first < second // -1\n * ```\n */\n public static compare(first: DayParameter, second: DayParameter): number {\n const a = toCalendarDay(first);\n const b = toCalendarDay(second);\n\n if (a.equalTo(b)) {\n return 0;\n }\n return a.greaterThan(b) ? 1 : -1;\n }\n\n constructor(args: CalendarDayParams) {\n this._date = new Date(args.year, args.month, args.date ?? 1);\n }\n\n /** Returns a copy of this instance. */\n public clone(): CalendarDay {\n return CalendarDay.from(this._date);\n }\n\n /** Returns a new instance with the given values replaced. */\n public set(args: Partial<CalendarDayParams>): CalendarDay {\n const year = args.year ?? this.year;\n const month = args.month ?? this.month;\n const date = args.date ?? this.date;\n\n // Clamp date to the last day of the month if it exceeds the month's days\n if (date > 0) {\n const temp = new Date(year, month, date);\n if (temp.getMonth() !== month) {\n const lastDayOfMonth = new Date(year, month + 1, 0).getDate();\n return new CalendarDay({ year, month, date: lastDayOfMonth });\n }\n }\n\n return new CalendarDay({ year, month, date });\n }\n\n public add(unit: DayInterval, value: number): CalendarDay {\n const result = this.clone();\n\n switch (unit) {\n case 'year':\n result._date.setFullYear(result.year + value);\n return checkRollover(this, result);\n case 'quarter':\n result._date.setMonth(result.month + 3 * value);\n return checkRollover(this, result);\n case 'month':\n result._date.setMonth(result.month + value);\n return checkRollover(this, result);\n case 'week':\n result._date.setDate(result.date + 7 * value);\n return result;\n case 'day':\n result._date.setDate(result.date + value);\n return result;\n default:\n throw new Error(`Invalid interval: ${unit}`);\n }\n }\n\n /** Returns the day of the week (Sunday = 0). */\n public get day(): number {\n return this._date.getDay();\n }\n\n /** Returns the full year. */\n public get year(): number {\n return this._date.getFullYear();\n }\n\n /** Returns the month. */\n public get month(): number {\n return this._date.getMonth();\n }\n\n /** Returns the date */\n public get date(): number {\n return this._date.getDate();\n }\n\n /** Returns the timestamp since epoch in milliseconds. */\n public get timestamp(): number {\n return this._date.getTime();\n }\n\n /**\n * Returns the ISO 8601 week number.\n *\n * @remarks\n * Week 1 is the week containing the first Thursday of the year.\n * Weeks start on Monday. Some years can have 53 weeks.\n */\n public get week(): number {\n const target = new Date(this._date);\n\n const dayNum = target.getDay() || 7;\n target.setDate(target.getDate() + 4 - dayNum);\n\n const yearStart = new Date(target.getFullYear(), 0, 1);\n\n // Calculate full weeks to nearest Thursday\n const weekNo = Math.ceil(\n ((target.getTime() - yearStart.getTime()) / MILLISECONDS_PER_DAY + 1) /\n DAYS_IN_WEEK\n );\n\n return weekNo;\n }\n\n /** Returns the underlying native date instance. */\n public get native(): Date {\n return new Date(this._date);\n }\n\n /**\n * Whether the current date is a weekend day.\n *\n * @remarks\n * This is naive, since it does not account for locale specifics.\n */\n public get weekend(): boolean {\n return this.day < WEEKDAY_MIN || this.day > WEEKDAY_MAX;\n }\n\n public equalTo(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp === other;\n }\n\n public greaterThan(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp > other;\n }\n\n public greaterThanOrEqual(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp >= other;\n }\n\n public lessThan(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp < other;\n }\n\n public lessThanOrEqual(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp <= other;\n }\n\n public toString(): string {\n return `${this.native}`;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/internals/date/model.ts"],"names":[],"mappings":"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","sourcesContent":["export type DayParameter = CalendarDay | Date;\n\nexport type CalendarRangeParams = {\n start: DayParameter;\n end: DayParameter | number;\n unit?: DayInterval;\n inclusive?: boolean;\n};\n\ntype DayInterval = 'year' | 'quarter' | 'month' | 'week' | 'day';\n\ntype CalendarDayParams = {\n year: number;\n month: number;\n date?: number;\n};\n\nexport const DAYS_IN_WEEK = 7;\nconst MILLISECONDS_PER_DAY = 86400000;\nconst WEEKDAY_MIN = 1; // Monday\nconst WEEKDAY_MAX = 5; // Friday\n\nexport function toCalendarDay(date: DayParameter): CalendarDay {\n return date instanceof Date ? CalendarDay.from(date) : date;\n}\n\n/** Null-preserving {@link toCalendarDay}: empty values convert to `null`. */\nexport function toCalendarDayOrNull(\n date?: DayParameter | null\n): CalendarDay | null {\n return date ? toCalendarDay(date) : null;\n}\n\n/** Truncates the time portion of `date`, passing empty values through as `null`. */\nexport function truncateTime(date?: Date | null): Date | null {\n return date ? CalendarDay.from(date).native : null;\n}\n\n/**\n * Yields the days between `start` and `end`, stepping by `unit` and stopping short of\n * `end` unless `inclusive` is set.\n */\nexport function* calendarRange(\n options: CalendarRangeParams\n): Generator<CalendarDay, void, unknown> {\n const { start, end, unit = 'day', inclusive = false } = options;\n\n let currentDate = toCalendarDay(start);\n const endDate =\n typeof end === 'number'\n ? toCalendarDay(start).add(unit, end)\n : toCalendarDay(end);\n\n const isReversed = endDate.lessThan(currentDate);\n const step = isReversed ? -1 : 1;\n\n const shouldContinue = () => {\n if (inclusive) {\n return isReversed\n ? currentDate.greaterThanOrEqual(endDate)\n : currentDate.lessThanOrEqual(endDate);\n }\n return isReversed\n ? currentDate.greaterThan(endDate)\n : currentDate.lessThan(endDate);\n };\n\n while (shouldContinue()) {\n yield currentDate;\n currentDate = currentDate.add(unit, step);\n }\n}\n\nfunction checkRollover(\n original: CalendarDay,\n modified: CalendarDay\n): CalendarDay {\n return original.date !== modified.date ? modified.set({ date: 0 }) : modified;\n}\n\n/* blazorSuppress */\nexport class CalendarDay {\n private readonly _date: Date;\n\n /** Constructs and returns the current day. */\n public static get today(): CalendarDay {\n return CalendarDay.from(new Date());\n }\n\n /** Constructs a new CalendarDay instance from a Date object. */\n public static from(date: Date): CalendarDay {\n return new CalendarDay({\n year: date.getFullYear(),\n month: date.getMonth(),\n date: date.getDate(),\n });\n }\n\n /**\n * Compares the date portion of two date objects.\n *\n * @returns\n * ```\n * first === second // 0\n * first > second // 1\n * first < second // -1\n * ```\n */\n public static compare(first: DayParameter, second: DayParameter): number {\n const a = toCalendarDay(first);\n const b = toCalendarDay(second);\n\n if (a.equalTo(b)) {\n return 0;\n }\n return a.greaterThan(b) ? 1 : -1;\n }\n\n constructor(args: CalendarDayParams) {\n this._date = new Date(args.year, args.month, args.date ?? 1);\n }\n\n /** Returns a copy of this instance. */\n public clone(): CalendarDay {\n return CalendarDay.from(this._date);\n }\n\n /** Returns a new instance with the given values replaced. */\n public set(args: Partial<CalendarDayParams>): CalendarDay {\n const year = args.year ?? this.year;\n const month = args.month ?? this.month;\n const date = args.date ?? this.date;\n\n // Clamp date to the last day of the month if it exceeds the month's days\n if (date > 0) {\n const temp = new Date(year, month, date);\n if (temp.getMonth() !== month) {\n const lastDayOfMonth = new Date(year, month + 1, 0).getDate();\n return new CalendarDay({ year, month, date: lastDayOfMonth });\n }\n }\n\n return new CalendarDay({ year, month, date });\n }\n\n public add(unit: DayInterval, value: number): CalendarDay {\n const result = this.clone();\n\n switch (unit) {\n case 'year':\n result._date.setFullYear(result.year + value);\n return checkRollover(this, result);\n case 'quarter':\n result._date.setMonth(result.month + 3 * value);\n return checkRollover(this, result);\n case 'month':\n result._date.setMonth(result.month + value);\n return checkRollover(this, result);\n case 'week':\n result._date.setDate(result.date + 7 * value);\n return result;\n case 'day':\n result._date.setDate(result.date + value);\n return result;\n default:\n throw new Error(`Invalid interval: ${unit}`);\n }\n }\n\n /** Returns the day of the week (Sunday = 0). */\n public get day(): number {\n return this._date.getDay();\n }\n\n /** Returns the full year. */\n public get year(): number {\n return this._date.getFullYear();\n }\n\n /** Returns the month. */\n public get month(): number {\n return this._date.getMonth();\n }\n\n /** Returns the date */\n public get date(): number {\n return this._date.getDate();\n }\n\n /** Returns the timestamp since epoch in milliseconds. */\n public get timestamp(): number {\n return this._date.getTime();\n }\n\n /**\n * Returns the ISO 8601 week number.\n *\n * @remarks\n * Week 1 is the week containing the first Thursday of the year.\n * Weeks start on Monday. Some years can have 53 weeks.\n */\n public get week(): number {\n const target = new Date(this._date);\n\n const dayNum = target.getDay() || 7;\n target.setDate(target.getDate() + 4 - dayNum);\n\n const yearStart = new Date(target.getFullYear(), 0, 1);\n\n // Calculate full weeks to nearest Thursday\n const weekNo = Math.ceil(\n ((target.getTime() - yearStart.getTime()) / MILLISECONDS_PER_DAY + 1) /\n DAYS_IN_WEEK\n );\n\n return weekNo;\n }\n\n /** Returns the underlying native date instance. */\n public get native(): Date {\n return new Date(this._date);\n }\n\n /**\n * Whether the current date is a weekend day.\n *\n * @remarks\n * This is naive, since it does not account for locale specifics.\n */\n public get weekend(): boolean {\n return this.day < WEEKDAY_MIN || this.day > WEEKDAY_MAX;\n }\n\n public equalTo(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp === other;\n }\n\n public greaterThan(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp > other;\n }\n\n public greaterThanOrEqual(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp >= other;\n }\n\n public lessThan(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp < other;\n }\n\n public lessThanOrEqual(value: DayParameter): boolean {\n const other = toCalendarDay(value).timestamp;\n return this.timestamp <= other;\n }\n\n public toString(): string {\n return `${this.native}`;\n }\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Argument bag passed to the {@link coercedProperty} callbacks. */
|
|
2
|
+
export interface CoercedPropertyContext<T, H> {
|
|
3
|
+
/**
|
|
4
|
+
* For `transform` - the incoming raw value; for `onChange` - the value
|
|
5
|
+
* that was stored after coercion.
|
|
6
|
+
*/
|
|
7
|
+
value: T;
|
|
8
|
+
/** The component instance the property belongs to. */
|
|
9
|
+
host: H;
|
|
10
|
+
/** The previously stored value, or `undefined` on the initial assignment. */
|
|
11
|
+
previous: T | undefined;
|
|
12
|
+
}
|
|
13
|
+
/** Configuration for {@link coercedProperty}. */
|
|
14
|
+
export interface CoercedPropertyConfig<T, H> {
|
|
15
|
+
/** Coerces every incoming value, the field initializer included. */
|
|
16
|
+
transform?: (context: CoercedPropertyContext<T, H>) => T;
|
|
17
|
+
/**
|
|
18
|
+
* Runs after a value is stored. Skipped for the field initializer, matching
|
|
19
|
+
* the backing-field defaults of a hand-written accessor pair which never run
|
|
20
|
+
* through the setter.
|
|
21
|
+
*/
|
|
22
|
+
onChange?: (context: CoercedPropertyContext<T, H>) => void;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Replaces the hand-written backing-field accessor pair around a reactive
|
|
26
|
+
* property with a declarative coerce/side-effect configuration.
|
|
27
|
+
*
|
|
28
|
+
* Composes with `@property` - Lit must keep wrapping the accessor for change
|
|
29
|
+
* detection, and the manifest analyzer must keep seeing the `@property`
|
|
30
|
+
* declaration:
|
|
31
|
+
*
|
|
32
|
+
* ```ts
|
|
33
|
+
* @property({ type: Number })
|
|
34
|
+
* @coercedProperty<number, IgcSomeComponent>({
|
|
35
|
+
* transform: ({ value }) => clamp(value, 0, 100),
|
|
36
|
+
* onChange: ({ host }) => host._validate(),
|
|
37
|
+
* })
|
|
38
|
+
* public value = 0;
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* The declaration must keep its initializer - it provides the default the
|
|
42
|
+
* old backing field carried, and its assignment marks construction so
|
|
43
|
+
* `onChange` only fires for later sets. Properties whose getter computes a
|
|
44
|
+
* derived value or whose storage lives outside the instance (form value
|
|
45
|
+
* state, controllers) keep their hand-written accessors.
|
|
46
|
+
*/
|
|
47
|
+
export declare function coercedProperty<T, H extends object = object>(config: CoercedPropertyConfig<T, H>): (prototype: object, name: PropertyKey) => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export function coercedProperty(config) {
|
|
2
|
+
const { transform, onChange } = config;
|
|
3
|
+
return (prototype, name) => {
|
|
4
|
+
const wrapped = Object.getOwnPropertyDescriptor(prototype, name);
|
|
5
|
+
const store = new WeakMap();
|
|
6
|
+
const initialized = new WeakSet();
|
|
7
|
+
const read = wrapped?.get ??
|
|
8
|
+
function () {
|
|
9
|
+
return store.get(this);
|
|
10
|
+
};
|
|
11
|
+
const write = wrapped?.set ??
|
|
12
|
+
function (value) {
|
|
13
|
+
store.set(this, value);
|
|
14
|
+
};
|
|
15
|
+
Object.defineProperty(prototype, name, {
|
|
16
|
+
get() {
|
|
17
|
+
return read.call(this);
|
|
18
|
+
},
|
|
19
|
+
set(value) {
|
|
20
|
+
const initial = !initialized.has(this);
|
|
21
|
+
initialized.add(this);
|
|
22
|
+
const previous = initial ? undefined : read.call(this);
|
|
23
|
+
const next = transform
|
|
24
|
+
? transform({ value, host: this, previous })
|
|
25
|
+
: value;
|
|
26
|
+
write.call(this, next);
|
|
27
|
+
if (!initial) {
|
|
28
|
+
onChange?.({ value: next, host: this, previous });
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
configurable: true,
|
|
32
|
+
enumerable: true,
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=coerced-property.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coerced-property.js","sourceRoot":"","sources":["../../../src/internals/decorators/coerced-property.ts"],"names":[],"mappings":"AAmDA,MAAM,UAAU,eAAe,CAC7B,MAAmC;IAEnC,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAEvC,OAAO,CAAC,SAAiB,EAAE,IAAiB,EAAQ,EAAE;QAKpD,MAAM,OAAO,GAAG,MAAM,CAAC,wBAAwB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,OAAO,EAAa,CAAC;QACvC,MAAM,WAAW,GAAG,IAAI,OAAO,EAAU,CAAC;QAE1C,MAAM,IAAI,GACR,OAAO,EAAE,GAAG;YACZ;gBACE,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC,CAAC;QAEJ,MAAM,KAAK,GACT,OAAO,EAAE,GAAG;YACZ,UAAwB,KAAQ;gBAC9B,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACzB,CAAC,CAAC;QAEJ,MAAM,CAAC,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE;YACrC,GAAG;gBACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC;YACD,GAAG,CAAU,KAAQ;gBACnB,MAAM,OAAO,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACvC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAEtB,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAO,CAAC;gBAC9D,MAAM,IAAI,GAAG,SAAS;oBACpB,CAAC,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;oBAC5C,CAAC,CAAC,KAAK,CAAC;gBAEV,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;gBAEvB,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;YACD,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/** Argument bag passed to the {@link coercedProperty} callbacks. */\nexport interface CoercedPropertyContext<T, H> {\n /**\n * For `transform` - the incoming raw value; for `onChange` - the value\n * that was stored after coercion.\n */\n value: T;\n\n /** The component instance the property belongs to. */\n host: H;\n\n /** The previously stored value, or `undefined` on the initial assignment. */\n previous: T | undefined;\n}\n\n/** Configuration for {@link coercedProperty}. */\nexport interface CoercedPropertyConfig<T, H> {\n /** Coerces every incoming value, the field initializer included. */\n transform?: (context: CoercedPropertyContext<T, H>) => T;\n\n /**\n * Runs after a value is stored. Skipped for the field initializer, matching\n * the backing-field defaults of a hand-written accessor pair which never run\n * through the setter.\n */\n onChange?: (context: CoercedPropertyContext<T, H>) => void;\n}\n\n/**\n * Replaces the hand-written backing-field accessor pair around a reactive\n * property with a declarative coerce/side-effect configuration.\n *\n * Composes with `@property` - Lit must keep wrapping the accessor for change\n * detection, and the manifest analyzer must keep seeing the `@property`\n * declaration:\n *\n * ```ts\n * @property({ type: Number })\n * @coercedProperty<number, IgcSomeComponent>({\n * transform: ({ value }) => clamp(value, 0, 100),\n * onChange: ({ host }) => host._validate(),\n * })\n * public value = 0;\n * ```\n *\n * The declaration must keep its initializer - it provides the default the\n * old backing field carried, and its assignment marks construction so\n * `onChange` only fires for later sets. Properties whose getter computes a\n * derived value or whose storage lives outside the instance (form value\n * state, controllers) keep their hand-written accessors.\n */\nexport function coercedProperty<T, H extends object = object>(\n config: CoercedPropertyConfig<T, H>\n) {\n const { transform, onChange } = config;\n\n return (prototype: object, name: PropertyKey): void => {\n // When `@property` is written below this decorator it has already\n // installed Lit's accessor; wrap it instead of shadowing it so change\n // detection keeps working. In the canonical order (this decorator below\n // `@property`) there is no descriptor yet and Lit wraps ours.\n const wrapped = Object.getOwnPropertyDescriptor(prototype, name);\n const store = new WeakMap<object, T>();\n const initialized = new WeakSet<object>();\n\n const read =\n wrapped?.get ??\n function (this: object) {\n return store.get(this);\n };\n\n const write =\n wrapped?.set ??\n function (this: object, value: T) {\n store.set(this, value);\n };\n\n Object.defineProperty(prototype, name, {\n get(this: H) {\n return read.call(this);\n },\n set(this: H, value: T) {\n const initial = !initialized.has(this);\n initialized.add(this);\n\n const previous = initial ? undefined : (read.call(this) as T);\n const next = transform\n ? transform({ value, host: this, previous })\n : value;\n\n write.call(this, next);\n\n if (!initial) {\n onChange?.({ value: next, host: this, previous });\n }\n },\n configurable: true,\n enumerable: true,\n });\n };\n}\n"]}
|
|
@@ -11,7 +11,7 @@ interface I18nControllerHost extends ReactiveControllerHost, HTMLElement {
|
|
|
11
11
|
}
|
|
12
12
|
type ResourceChangeCallback = (event: CustomEvent<IResourceChangeEventArgs>) => unknown;
|
|
13
13
|
/** Configuration object for the I18nController. */
|
|
14
|
-
type I18nControllerConfig<T extends object> = {
|
|
14
|
+
export type I18nControllerConfig<T extends object> = {
|
|
15
15
|
/** The full default English resource strings object for the component. Should always come from igniteui-i18n-core. */
|
|
16
16
|
defaultEN: T;
|
|
17
17
|
/** @deprecated since 7.2.0. Optional name if component uses mixed resource strings. To be removed with deprecated resources. */
|
|
@@ -31,6 +31,8 @@ declare class I18nController<T extends object> implements ReactiveController {
|
|
|
31
31
|
private readonly _resourceMapName?;
|
|
32
32
|
private readonly _resourceChangeCallback?;
|
|
33
33
|
private _locale?;
|
|
34
|
+
/** Resolved lazily, and again whenever the locale or the locale data changes. */
|
|
35
|
+
private _dateTimeFormats?;
|
|
34
36
|
/** Cache of default resource strings coming from i18n Manager. */
|
|
35
37
|
private _defaultResourceStrings;
|
|
36
38
|
/** Collection containing only custom resource strings provided. Allows for partial override of resource strings. */
|
|
@@ -55,6 +57,13 @@ declare class I18nController<T extends object> implements ReactiveController {
|
|
|
55
57
|
set resourceStrings(value: T | undefined);
|
|
56
58
|
/** Get resolved resource strings for component */
|
|
57
59
|
get resourceStrings(): T;
|
|
60
|
+
/** The locale-default format for displaying a date-time value. */
|
|
61
|
+
get localeDisplayFormat(): string;
|
|
62
|
+
/**
|
|
63
|
+
* The locale-default format for editing a date-time value - the display
|
|
64
|
+
* format with leading zeros forced, the shape a mask needs.
|
|
65
|
+
*/
|
|
66
|
+
get localeInputFormat(): string;
|
|
58
67
|
constructor(host: I18nControllerHost, config: I18nControllerConfig<T>);
|
|
59
68
|
/** @internal */
|
|
60
69
|
hostConnected(): void;
|
|
@@ -62,6 +71,11 @@ declare class I18nController<T extends object> implements ReactiveController {
|
|
|
62
71
|
hostDisconnected(): void;
|
|
63
72
|
/** @internal */
|
|
64
73
|
handleEvent(event: CustomEvent<IResourceChangeEventArgs>): void;
|
|
74
|
+
/**
|
|
75
|
+
* Re-resolves the locale defaults and re-applies the custom overrides on top,
|
|
76
|
+
* so the merged strings never keep values resolved for a previous locale.
|
|
77
|
+
*/
|
|
78
|
+
private _refreshResourceStrings;
|
|
65
79
|
/**
|
|
66
80
|
* Gets the current, locale-specific resource strings for the component.
|
|
67
81
|
* The logic maps component keys (from defaultEN) to core library keys
|
|
@@ -70,10 +84,15 @@ declare class I18nController<T extends object> implements ReactiveController {
|
|
|
70
84
|
* Result is truncated, containing only relevant locale strings.
|
|
71
85
|
*/
|
|
72
86
|
private _getDefaultResourceStrings;
|
|
87
|
+
/**
|
|
88
|
+
* Deriving a format string from `Intl` is not free and the date editors
|
|
89
|
+
* consult these on every render, so they are cached against the resolved
|
|
90
|
+
* locale. A global resource change invalidates the cache, since the shared
|
|
91
|
+
* date formatter may have received new locale data.
|
|
92
|
+
*/
|
|
93
|
+
private _getDateTimeFormats;
|
|
73
94
|
private getMixedResourceStrings;
|
|
74
95
|
}
|
|
75
|
-
/** Returns the default date-time input format for a given locale */
|
|
76
|
-
export declare function getDefaultDateTimeFormat(locale: string): string;
|
|
77
96
|
/** Returns the date-time format string with the appropriate suffix if it's a predefined style */
|
|
78
97
|
export declare function getDateTimeFormat(format?: string, suffix?: 'Date' | 'Time'): string | undefined;
|
|
79
98
|
/**
|
|
@@ -4,7 +4,7 @@ class I18nController {
|
|
|
4
4
|
set locale(value) {
|
|
5
5
|
if (this._locale !== value) {
|
|
6
6
|
this._locale = value;
|
|
7
|
-
this.
|
|
7
|
+
this._refreshResourceStrings();
|
|
8
8
|
this._host.requestUpdate();
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -29,6 +29,12 @@ class I18nController {
|
|
|
29
29
|
get resourceStrings() {
|
|
30
30
|
return this._resourceStrings ?? this._defaultResourceStrings;
|
|
31
31
|
}
|
|
32
|
+
get localeDisplayFormat() {
|
|
33
|
+
return this._getDateTimeFormats().display;
|
|
34
|
+
}
|
|
35
|
+
get localeInputFormat() {
|
|
36
|
+
return this._getDateTimeFormats().input;
|
|
37
|
+
}
|
|
32
38
|
constructor(host, config) {
|
|
33
39
|
this._host = host;
|
|
34
40
|
this._defaultEN = config.defaultEN;
|
|
@@ -40,17 +46,24 @@ class I18nController {
|
|
|
40
46
|
}
|
|
41
47
|
hostConnected() {
|
|
42
48
|
getI18nManager().addEventListener('onResourceChange', this);
|
|
49
|
+
this._dateTimeFormats = undefined;
|
|
50
|
+
this._refreshResourceStrings();
|
|
51
|
+
this._host.requestUpdate();
|
|
43
52
|
}
|
|
44
53
|
hostDisconnected() {
|
|
45
54
|
getI18nManager().removeEventListener('onResourceChange', this);
|
|
46
55
|
}
|
|
47
56
|
handleEvent(event) {
|
|
57
|
+
this._dateTimeFormats = undefined;
|
|
58
|
+
this._refreshResourceStrings();
|
|
59
|
+
this._resourceChangeCallback?.call(this._host, event);
|
|
60
|
+
this._host.requestUpdate();
|
|
61
|
+
}
|
|
62
|
+
_refreshResourceStrings() {
|
|
48
63
|
this._defaultResourceStrings = this._getDefaultResourceStrings();
|
|
49
64
|
if (this._customResourceStrings) {
|
|
50
65
|
this._resourceStrings = Object.assign({}, this._defaultResourceStrings, this._customResourceStrings);
|
|
51
66
|
}
|
|
52
|
-
this._resourceChangeCallback?.call(this._host, event);
|
|
53
|
-
this._host.requestUpdate();
|
|
54
67
|
}
|
|
55
68
|
_getDefaultResourceStrings() {
|
|
56
69
|
const coreResourceStrings = getI18nManager().getCurrentResourceStrings(this.locale);
|
|
@@ -65,6 +78,18 @@ class I18nController {
|
|
|
65
78
|
}
|
|
66
79
|
return this.getMixedResourceStrings(normalizedResourceStrings);
|
|
67
80
|
}
|
|
81
|
+
_getDateTimeFormats() {
|
|
82
|
+
const locale = this.locale;
|
|
83
|
+
if (this._dateTimeFormats?.locale !== locale) {
|
|
84
|
+
const formatter = getDateFormatter();
|
|
85
|
+
this._dateTimeFormats = {
|
|
86
|
+
locale,
|
|
87
|
+
display: formatter.getLocaleDateTimeFormat(locale),
|
|
88
|
+
input: formatter.getLocaleDateTimeFormat(locale, true),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return this._dateTimeFormats;
|
|
92
|
+
}
|
|
68
93
|
getMixedResourceStrings(value) {
|
|
69
94
|
if (this._resourceMapName) {
|
|
70
95
|
return Object.assign({}, convertToCoreResource(value, this._resourceMapName), convertToIgcResource(value, this._resourceMapName));
|
|
@@ -76,9 +101,6 @@ const DATE_TIME_STYLES = new Set(['short', 'long', 'medium', 'full']);
|
|
|
76
101
|
function extractStyle(format, suffix) {
|
|
77
102
|
return format.toLowerCase().split(suffix)[0];
|
|
78
103
|
}
|
|
79
|
-
export function getDefaultDateTimeFormat(locale) {
|
|
80
|
-
return getDateFormatter().getLocaleDateTimeFormat(locale, true);
|
|
81
|
-
}
|
|
82
104
|
export function getDateTimeFormat(format, suffix = 'Date') {
|
|
83
105
|
return format && DATE_TIME_STYLES.has(format) ? `${format}${suffix}` : format;
|
|
84
106
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"i18n-controller.js","sourceRoot":"","sources":["../../../src/internals/i18n/i18n-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getCurrentI18n,\n getDateFormatter,\n getI18nManager,\n type IResourceChangeEventArgs,\n type IResourceStrings,\n} from 'igniteui-i18n-core';\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport {\n convertToCoreResource,\n convertToIgcResource,\n type I18nResourceMapNames,\n} from './utils.js';\n\n/**\n * Defines the structure for the host element that will use this controller.\n * The host must be a Lit element (ReactiveControllerHost) and an HTMLElement.\n */\ninterface I18nControllerHost extends ReactiveControllerHost, HTMLElement {\n // Properties the host is expected to have/use, though they are managed by the controller.\n resourceStrings?: unknown;\n locale?: string;\n}\n\ntype ResourceChangeCallback = (\n event: CustomEvent<IResourceChangeEventArgs>\n) => unknown;\n\n/** Configuration object for the I18nController. */\ntype I18nControllerConfig<T extends object> = {\n /** The full default English resource strings object for the component. Should always come from igniteui-i18n-core. */\n defaultEN: T;\n /** @deprecated since 7.2.0. Optional name if component uses mixed resource strings. To be removed with deprecated resources. */\n resourceMapName?: I18nResourceMapNames;\n /** An optional callback to execute when the global locale changes. */\n onResourceChange?: ResourceChangeCallback;\n};\n\n/**\n * Manages localization (i18n) for a Lit web component.\n * It handles the current locale, component-specific resource overrides,\n * and updates when the global localization state changes.\n */\nclass I18nController<T extends object> implements ReactiveController {\n //#region Internal properties and state\n\n private readonly _host: I18nControllerHost;\n private readonly _defaultEN: T;\n /** @deprecated since 7.2.0. Resource name to use when converting new to old and vice versa resource objects. */\n private readonly _resourceMapName?: I18nResourceMapNames;\n private readonly _resourceChangeCallback?: ResourceChangeCallback;\n\n private _locale?: string;\n /** Cache of default resource strings coming from i18n Manager. */\n private _defaultResourceStrings: T;\n /** Collection containing only custom resource strings provided. Allows for partial override of resource strings. */\n private _customResourceStrings?: T;\n /** Merged collection of custom resource strings and default resource strings. */\n private _resourceStrings?: T;\n\n //#endregion\n\n //#region Public properties\n\n /**\n * Sets a custom locale that overrides the global one for this host component instance.\n * Setting a new locale triggers an update of the resource strings.\n */\n public set locale(value: string | undefined) {\n if (this._locale !== value) {\n this._locale = value;\n this._defaultResourceStrings = this._getDefaultResourceStrings();\n this._host.requestUpdate();\n }\n }\n\n /**\n * Gets the resolved locale for the host component.\n * This is the component's custom locale if set, otherwise it falls back to the\n * global locale.\n */\n public get locale(): string {\n return this._locale ?? getCurrentI18n();\n }\n\n /**\n * Sets custom resource string for component with this controller.\n * Gets the resolved resource string for component.\n */\n public set resourceStrings(value: T | undefined) {\n if (this._resourceStrings !== value) {\n if (value) {\n this._customResourceStrings = this._resourceMapName\n ? this.getMixedResourceStrings(value)\n : value;\n this._resourceStrings = Object.assign(\n {},\n this._defaultResourceStrings,\n this._customResourceStrings\n );\n } else {\n this._customResourceStrings = value;\n this._resourceStrings = value;\n }\n\n this._host.requestUpdate();\n }\n }\n\n /** Get resolved resource strings for component */\n public get resourceStrings(): T {\n return this._resourceStrings ?? this._defaultResourceStrings;\n }\n\n //#endregion\n\n //#region Life-cycle hooks and event listener\n\n constructor(host: I18nControllerHost, config: I18nControllerConfig<T>) {\n this._host = host;\n this._defaultEN = config.defaultEN;\n this._resourceMapName = config.resourceMapName;\n this._resourceChangeCallback = config.onResourceChange;\n\n this._defaultResourceStrings = this._getDefaultResourceStrings();\n getI18nManager().registerI18n(\n this._defaultEN,\n getI18nManager().defaultLocale\n );\n\n this._host.addController(this);\n }\n\n /** @internal */\n public hostConnected(): void {\n getI18nManager().addEventListener('onResourceChange', this);\n }\n\n /** @internal */\n public hostDisconnected(): void {\n getI18nManager().removeEventListener('onResourceChange', this);\n }\n\n /** @internal */\n public handleEvent(event: CustomEvent<IResourceChangeEventArgs>): void {\n this._defaultResourceStrings = this._getDefaultResourceStrings();\n if (this._customResourceStrings) {\n this._resourceStrings = Object.assign(\n {},\n this._defaultResourceStrings,\n this._customResourceStrings\n );\n }\n this._resourceChangeCallback?.call(this._host, event);\n this._host.requestUpdate();\n }\n\n //#endregion\n\n //#region Internal API\n\n /**\n * Gets the current, locale-specific resource strings for the component.\n * The logic maps component keys (from defaultEN) to core library keys\n * and retrieves the localized string from the i18n manager.\n *\n * Result is truncated, containing only relevant locale strings.\n */\n private _getDefaultResourceStrings(): T {\n const coreResourceStrings = getI18nManager().getCurrentResourceStrings(\n this.locale\n );\n\n // Get all related resources to the component, based on the default resources.\n const normalizedResourceStrings: T = {} as T;\n const defaultComponentKeys = Object.keys(this._defaultEN) as (keyof T)[];\n for (const key of defaultComponentKeys) {\n let resolvedValue: T[keyof T] = this._defaultEN[key];\n if (key in coreResourceStrings) {\n // For a mix of old and core resources.\n // Only for internal default resources. Users shouldn't mix them.\n resolvedValue = coreResourceStrings[\n key as keyof IResourceStrings\n ] as T[keyof T];\n }\n\n normalizedResourceStrings[key] = resolvedValue;\n }\n\n return this.getMixedResourceStrings(normalizedResourceStrings);\n }\n\n private getMixedResourceStrings(value: T): T {\n if (this._resourceMapName) {\n return Object.assign(\n {},\n convertToCoreResource(value, this._resourceMapName),\n convertToIgcResource(value, this._resourceMapName)\n ) as T;\n }\n return value;\n }\n\n //#endregion\n}\n\n/**\n * Formats a date for display based on the specified format and locale.\n */\ntype DateTimeStyle = 'short' | 'long' | 'medium' | 'full';\n\nconst DATE_TIME_STYLES = new Set<string>(['short', 'long', 'medium', 'full']);\n\nfunction extractStyle(format: string, suffix: string): DateTimeStyle {\n return format.toLowerCase().split(suffix)[0] as DateTimeStyle;\n}\n\n/** Returns the default date-time input format for a given locale */\nexport function getDefaultDateTimeFormat(locale: string): string {\n return getDateFormatter().getLocaleDateTimeFormat(locale, true);\n}\n\n/** Returns the date-time format string with the appropriate suffix if it's a predefined style */\nexport function getDateTimeFormat(\n format?: string,\n suffix: 'Date' | 'Time' = 'Date'\n): string | undefined {\n return format && DATE_TIME_STYLES.has(format) ? `${format}${suffix}` : format;\n}\n\n/**\n * Formats a date for display using the specified format.\n */\nexport function formatDisplayDate(\n value: Date,\n locale: string,\n displayFormat?: string\n): string {\n if (!displayFormat) {\n return getDateFormatter().formatDateTime(value, locale, {});\n }\n\n // Full date+time styles (short, long, medium, full)\n if (DATE_TIME_STYLES.has(displayFormat)) {\n const style = displayFormat as DateTimeStyle;\n return getDateFormatter().formatDateTime(value, locale, {\n dateStyle: style,\n timeStyle: style,\n });\n }\n\n // Date-only styles (shortDate, longDate, etc.)\n if (displayFormat.endsWith('Date')) {\n return getDateFormatter().formatDateTime(value, locale, {\n dateStyle: extractStyle(displayFormat, 'date'),\n });\n }\n\n // Time-only styles (shortTime, longTime, etc.)\n if (displayFormat.endsWith('Time')) {\n return getDateFormatter().formatDateTime(value, locale, {\n timeStyle: extractStyle(displayFormat, 'time'),\n });\n }\n\n // Custom format string\n return getDateFormatter().formatDateCustomFormat(value, displayFormat, {\n locale,\n });\n}\n\n/** Factory function to create and attach the I18nController to a host. */\nexport function addI18nController<T extends object>(\n host: I18nControllerHost,\n config: I18nControllerConfig<T>\n): I18nController<T> {\n return new I18nController<T>(host, config);\n}\n\nexport type { I18nController };\n"]}
|
|
1
|
+
{"version":3,"file":"i18n-controller.js","sourceRoot":"","sources":["../../../src/internals/i18n/i18n-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getCurrentI18n,\n getDateFormatter,\n getI18nManager,\n type IResourceChangeEventArgs,\n type IResourceStrings,\n} from 'igniteui-i18n-core';\nimport type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport {\n convertToCoreResource,\n convertToIgcResource,\n type I18nResourceMapNames,\n} from './utils.js';\n\n/**\n * Defines the structure for the host element that will use this controller.\n * The host must be a Lit element (ReactiveControllerHost) and an HTMLElement.\n */\ninterface I18nControllerHost extends ReactiveControllerHost, HTMLElement {\n // Properties the host is expected to have/use, though they are managed by the controller.\n resourceStrings?: unknown;\n locale?: string;\n}\n\ntype ResourceChangeCallback = (\n event: CustomEvent<IResourceChangeEventArgs>\n) => unknown;\n\n/** The date-time formats a locale resolves to, cached against that locale. */\ntype LocaleDateTimeFormats = {\n locale: string;\n display: string;\n input: string;\n};\n\n/** Configuration object for the I18nController. */\nexport type I18nControllerConfig<T extends object> = {\n /** The full default English resource strings object for the component. Should always come from igniteui-i18n-core. */\n defaultEN: T;\n /** @deprecated since 7.2.0. Optional name if component uses mixed resource strings. To be removed with deprecated resources. */\n resourceMapName?: I18nResourceMapNames;\n /** An optional callback to execute when the global locale changes. */\n onResourceChange?: ResourceChangeCallback;\n};\n\n/**\n * Manages localization (i18n) for a Lit web component.\n * It handles the current locale, component-specific resource overrides,\n * and updates when the global localization state changes.\n */\nclass I18nController<T extends object> implements ReactiveController {\n //#region Internal properties and state\n\n private readonly _host: I18nControllerHost;\n private readonly _defaultEN: T;\n /** @deprecated since 7.2.0. Resource name to use when converting new to old and vice versa resource objects. */\n private readonly _resourceMapName?: I18nResourceMapNames;\n private readonly _resourceChangeCallback?: ResourceChangeCallback;\n\n private _locale?: string;\n /** Resolved lazily, and again whenever the locale or the locale data changes. */\n private _dateTimeFormats?: LocaleDateTimeFormats;\n /** Cache of default resource strings coming from i18n Manager. */\n private _defaultResourceStrings: T;\n /** Collection containing only custom resource strings provided. Allows for partial override of resource strings. */\n private _customResourceStrings?: T;\n /** Merged collection of custom resource strings and default resource strings. */\n private _resourceStrings?: T;\n\n //#endregion\n\n //#region Public properties\n\n /**\n * Sets a custom locale that overrides the global one for this host component instance.\n * Setting a new locale triggers an update of the resource strings.\n */\n public set locale(value: string | undefined) {\n if (this._locale !== value) {\n this._locale = value;\n this._refreshResourceStrings();\n this._host.requestUpdate();\n }\n }\n\n /**\n * Gets the resolved locale for the host component.\n * This is the component's custom locale if set, otherwise it falls back to the\n * global locale.\n */\n public get locale(): string {\n return this._locale ?? getCurrentI18n();\n }\n\n /**\n * Sets custom resource string for component with this controller.\n * Gets the resolved resource string for component.\n */\n public set resourceStrings(value: T | undefined) {\n if (this._resourceStrings !== value) {\n if (value) {\n this._customResourceStrings = this._resourceMapName\n ? this.getMixedResourceStrings(value)\n : value;\n this._resourceStrings = Object.assign(\n {},\n this._defaultResourceStrings,\n this._customResourceStrings\n );\n } else {\n this._customResourceStrings = value;\n this._resourceStrings = value;\n }\n\n this._host.requestUpdate();\n }\n }\n\n /** Get resolved resource strings for component */\n public get resourceStrings(): T {\n return this._resourceStrings ?? this._defaultResourceStrings;\n }\n\n /** The locale-default format for displaying a date-time value. */\n public get localeDisplayFormat(): string {\n return this._getDateTimeFormats().display;\n }\n\n /**\n * The locale-default format for editing a date-time value - the display\n * format with leading zeros forced, the shape a mask needs.\n */\n public get localeInputFormat(): string {\n return this._getDateTimeFormats().input;\n }\n\n //#endregion\n\n //#region Life-cycle hooks and event listener\n\n constructor(host: I18nControllerHost, config: I18nControllerConfig<T>) {\n this._host = host;\n this._defaultEN = config.defaultEN;\n this._resourceMapName = config.resourceMapName;\n this._resourceChangeCallback = config.onResourceChange;\n\n this._defaultResourceStrings = this._getDefaultResourceStrings();\n getI18nManager().registerI18n(\n this._defaultEN,\n getI18nManager().defaultLocale\n );\n\n this._host.addController(this);\n }\n\n /** @internal */\n public hostConnected(): void {\n getI18nManager().addEventListener('onResourceChange', this);\n\n // A global change while detached went unheard, so the resolved state can\n // be one of a locale that is no longer current.\n this._dateTimeFormats = undefined;\n this._refreshResourceStrings();\n this._host.requestUpdate();\n }\n\n /** @internal */\n public hostDisconnected(): void {\n getI18nManager().removeEventListener('onResourceChange', this);\n }\n\n /** @internal */\n public handleEvent(event: CustomEvent<IResourceChangeEventArgs>): void {\n this._dateTimeFormats = undefined;\n this._refreshResourceStrings();\n this._resourceChangeCallback?.call(this._host, event);\n this._host.requestUpdate();\n }\n\n //#endregion\n\n //#region Internal API\n\n /**\n * Re-resolves the locale defaults and re-applies the custom overrides on top,\n * so the merged strings never keep values resolved for a previous locale.\n */\n private _refreshResourceStrings(): void {\n this._defaultResourceStrings = this._getDefaultResourceStrings();\n\n if (this._customResourceStrings) {\n this._resourceStrings = Object.assign(\n {},\n this._defaultResourceStrings,\n this._customResourceStrings\n );\n }\n }\n\n /**\n * Gets the current, locale-specific resource strings for the component.\n * The logic maps component keys (from defaultEN) to core library keys\n * and retrieves the localized string from the i18n manager.\n *\n * Result is truncated, containing only relevant locale strings.\n */\n private _getDefaultResourceStrings(): T {\n const coreResourceStrings = getI18nManager().getCurrentResourceStrings(\n this.locale\n );\n\n // Get all related resources to the component, based on the default resources.\n const normalizedResourceStrings: T = {} as T;\n const defaultComponentKeys = Object.keys(this._defaultEN) as (keyof T)[];\n for (const key of defaultComponentKeys) {\n let resolvedValue: T[keyof T] = this._defaultEN[key];\n if (key in coreResourceStrings) {\n // For a mix of old and core resources.\n // Only for internal default resources. Users shouldn't mix them.\n resolvedValue = coreResourceStrings[\n key as keyof IResourceStrings\n ] as T[keyof T];\n }\n\n normalizedResourceStrings[key] = resolvedValue;\n }\n\n return this.getMixedResourceStrings(normalizedResourceStrings);\n }\n\n /**\n * Deriving a format string from `Intl` is not free and the date editors\n * consult these on every render, so they are cached against the resolved\n * locale. A global resource change invalidates the cache, since the shared\n * date formatter may have received new locale data.\n */\n private _getDateTimeFormats(): LocaleDateTimeFormats {\n const locale = this.locale;\n\n if (this._dateTimeFormats?.locale !== locale) {\n const formatter = getDateFormatter();\n this._dateTimeFormats = {\n locale,\n display: formatter.getLocaleDateTimeFormat(locale),\n input: formatter.getLocaleDateTimeFormat(locale, true),\n };\n }\n\n return this._dateTimeFormats;\n }\n\n private getMixedResourceStrings(value: T): T {\n if (this._resourceMapName) {\n return Object.assign(\n {},\n convertToCoreResource(value, this._resourceMapName),\n convertToIgcResource(value, this._resourceMapName)\n ) as T;\n }\n return value;\n }\n\n //#endregion\n}\n\n/**\n * Formats a date for display based on the specified format and locale.\n */\ntype DateTimeStyle = 'short' | 'long' | 'medium' | 'full';\n\nconst DATE_TIME_STYLES = new Set<string>(['short', 'long', 'medium', 'full']);\n\nfunction extractStyle(format: string, suffix: string): DateTimeStyle {\n return format.toLowerCase().split(suffix)[0] as DateTimeStyle;\n}\n\n/** Returns the date-time format string with the appropriate suffix if it's a predefined style */\nexport function getDateTimeFormat(\n format?: string,\n suffix: 'Date' | 'Time' = 'Date'\n): string | undefined {\n return format && DATE_TIME_STYLES.has(format) ? `${format}${suffix}` : format;\n}\n\n/**\n * Formats a date for display using the specified format.\n */\nexport function formatDisplayDate(\n value: Date,\n locale: string,\n displayFormat?: string\n): string {\n if (!displayFormat) {\n return getDateFormatter().formatDateTime(value, locale, {});\n }\n\n // Full date+time styles (short, long, medium, full)\n if (DATE_TIME_STYLES.has(displayFormat)) {\n const style = displayFormat as DateTimeStyle;\n return getDateFormatter().formatDateTime(value, locale, {\n dateStyle: style,\n timeStyle: style,\n });\n }\n\n // Date-only styles (shortDate, longDate, etc.)\n if (displayFormat.endsWith('Date')) {\n return getDateFormatter().formatDateTime(value, locale, {\n dateStyle: extractStyle(displayFormat, 'date'),\n });\n }\n\n // Time-only styles (shortTime, longTime, etc.)\n if (displayFormat.endsWith('Time')) {\n return getDateFormatter().formatDateTime(value, locale, {\n timeStyle: extractStyle(displayFormat, 'time'),\n });\n }\n\n // Custom format string\n return getDateFormatter().formatDateCustomFormat(value, displayFormat, {\n locale,\n });\n}\n\n/** Factory function to create and attach the I18nController to a host. */\nexport function addI18nController<T extends object>(\n host: I18nControllerHost,\n config: I18nControllerConfig<T>\n): I18nController<T> {\n return new I18nController<T>(host, config);\n}\n\nexport type { I18nController };\n"]}
|