@uiloos/core
Version:
The core of the uiloos headless UI
7,511 lines • 256 kB
TypeScript
/**
* A function which when called will unsubscribe from the observable.
*
* @since 1.0.0
*/
type UnsubscribeFunction = () => void;
/**
* The interface each component of uiloos/core implements so it
* can be subscribed to.
*
* Note: there is no reason to ever implement the `Observable`
* interface yourself. It is only exposed so bindings to frameworks
* can use the type.
*
* @since 1.4.0
*/
interface Observable<T, E> {
/**
* Subscribe to changes of the Observable. The function you provide
* will get called whenever changes occur in the Observable.
*
* Returns an unsubscribe function which when called will
* unsubscribe from the Observable.
*
* @param {Subscriber<T, E>} subscriber The subscriber which responds to changes in the Observable.
* @returns {UnsubscribeFunction} A function which when called will unsubscribe from the Observable.
*
* @since 1.4.0
*/
subscribe(subscriber: Subscriber<T, E>): UnsubscribeFunction;
}
/**
* A function which when called will subscribe to the observable.
*
* @since 1.4.0
*/
type Subscriber<T, E> = (observerable: T, event: E) => void;
/**
* Checks / validates the license for "uiloos".
*
* Note: you are not supposed to use this class directly. Use the
* variable `licenseChecker` instead.
*
* @since 1.0.0
*/
declare class _LicenseChecker {
private _licenseKey;
private _logOnSuccess;
private _success;
/**
* With `activateLicense` you can set activate your license key for
* uiloos. Make sure that you set your license key before using any
* functionality that uiloos provides.
*
* You can purchase a license at https://www.uiloos.dev.
*
* @param {string} licenseKey The license key of uiloos you want to activate.
* @param {ActivateLicenseOptions} options The optional options for the `activateLicense` function, can be used to suppress the "license activated" message.
* @since 1.0.0
*/
activateLicense(licenseKey: string, options?: ActivateLicenseOptions): void;
/**
* Checks the current license to see if it is valid.
*
* Note: this method is for internal use inside uiloos only.
*
* @since 1.0.0
*/
_checkLicense(): void;
}
/**
* The sole instance (a singleton) of the `_LicenseChecker` class.
*
* Use this instance of `_LicenseChecker` to call `activateLicense` to
* activate your license.
*
* @see _LicenseChecker
* @since 1.0.0
*
* @example
*
* Activating license
*
* You activate the license by calling "activateLicense" on the
* "licenseChecker" instance.
*
* ```js
* import { licenseChecker } from '@uiloos/core';
* licenseChecker.activateLicense("{LICENSE-HERE}");
* ```
*/
declare let licenseChecker: _LicenseChecker;
/**
* The options for the `activateLicense` functions. Can be used
* to silence the "license activated" message.
*
* @since 1.0.0
*/
type ActivateLicenseOptions = {
/**
* Whether or not to silence the "license activated" message
* when the license is valid.
*
* @since 1.0.0
*/
logLicenseActivated: boolean;
};
/**
* Configures the initial state of the `ActiveList`
*
* @since 1.0.0
*/
type ActiveListConfig<T> = {
/**
* The contents which you want to display, can be an array of anything
* you want.
*
* Note: the `ActiveList` will wrap each item in the `contents` array
* inside of a `ActiveListContent` item.
*
* Defaults to `[]` meaning there is no content.
*
* @since 1.0.0
*/
contents?: T[];
/**
* How many items can be active at the same time.
*
* When the value of `limit` is `false` there is no limit to the
* number of active items.
*
* Defaults to `1`.
*
* @since 1.0.0
*/
maxActivationLimit?: number | false;
/**
* How the limit is enforced. In other words what the behavior
* should be when the limit is surpassed.
*
* The modes are strings which can be the following values:
*
* 1. 'circular': the first item which was added will be removed so
* the last item can be added without violating the limit. This
* basically means that the first one in is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `ActiveListActivationLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an item is added and the limit
* is reached. The item is simply not added, but no error is
* thrown.
*
* Defaults to 'circular'.
*
* @since 1.0.0
*/
maxActivationLimitBehavior?: ActiveListMaxActivationLimitBehavior;
/**
* Which item or items in the content array are currently active.
*
* When the `active` is an array each item in the array is activated
* from left to right one at a time.
*
* Note: "active" is chosen over the "activeIndexes" property.
*
* Defaults to `[]` meaning no content is active.
*
* @since 1.0.0
*/
active?: T | T[];
/**
* Which index or indexes of the content array are currently active.
*
* When the `activeIndexes` is an array each index in the array
* is activated from left to right one at a time.
*
* Note: "active" is chosen over the "activeIndexes" property.
*
* Defaults to `[]` meaning no content is active.
*
* @since 1.0.0
*/
activeIndexes?: number | number[];
/**
* Whether or not the content starts back at the beginning when
* the end of the content is reached, and whether the content should
* go to the end when moving left of the start.
*
* Defaults to `true`.
*
* @since 1.0.0
*/
isCircular?: boolean;
/**
* Whether or not `autoPlay` is enabled. When `autoPlay` is enabled
* it will automatically move to the next content, based on the
* `duration`.
*
* When `isCircular` is `true` content will move to the right
* indefinitely. When `isCircular` is `false` it will stop autoPlay
* at the end of the content.
*
* Note: autoPlay will only start when one or more contents are
* currently active. The reason for this is that the `duration`, is
* based on the `ActiveList` `lastActivatedContent` property.
* Whenever there are no more items to activate the autoPlay will
* stop.
*
* Defaults to no autoPlay.
*
* @since 1.0.0
*/
autoPlay?: ActiveListAutoPlayConfig<T>;
/**
* Describes which strings should be associated with what
* direction, will be the value of the `ActiveList` property
* `direction`.
*
* So when setting the direction `next` to "up"` and the content
* moves up, the `ActiveList.direction` will be "up". Useful when
* wanting to apply CSS classes based on the direction.
*
* Defaults to `{ next: 'right', previous: 'left' }`.
*
* @since 1.0.0
*/
directions?: ActiveListDirection;
/**
* For how many items the `history` may contain in the `ActiveList`.
*
* Defaults to `0` meaning that it will not track history.
*
* @since 1.0.0
*/
keepHistoryFor?: number;
/**
* The `cooldown` is the number of milliseconds before another
* activation / deactivation is allowed. For example if the
* `cooldown` is `5000` the `ActiveList` will not allow
* transitions until after 5 seconds have passed. Any activation /
* deactivation in that period will simply be ignored.
*
* This can be useful when you have an animation which should be
* finished before allowing user interaction again.
*
* This global `cooldown` is the same for all transitions you might trigger.
* If you want a `cooldown` that differs per button use the `cooldown`
* in the `ActiveListActivationOptions` instead.
*
* Note that the `cooldown` options with the `ActiveListActivationOptions` takes
* precedence over this more global cooldown.
*
* IMPORTANT: `cooldown` is only ran when `isUserInteraction` within
* the `ActiveListActivationOptions` is `true`. This means that `autoPlay`, which
* is not a user interaction, ignores the `cooldown`.
*
* @since 1.0.0
*/
cooldown?: ActiveListCooldownConfig<T>;
};
/**
* Describes all the behaviors for when the limit of the ActiveList
* is surpassed.
*
* 1. 'circular': the first item which was added will be removed so
* the last item can be added without violating the limit. This
* basically means that the first one in is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `ActiveListActivationLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an item is added and the limit
* is reached. The item is simply not added, but no error is
* thrown.
*
* @since 1.0.0
*/
type ActiveListMaxActivationLimitBehavior = 'circular' | 'ignore' | 'error';
/**
* Represents options for activation / deactivation methods.
*
* @since 1.0.0
*/
type ActiveListActivationOptions<T> = {
/**
* Whether or not the action was taken by a user / human. This
* affects the `autoPlay` when `stopsOnUserInteraction` is `true`,
* the `autoPlay` stops, when `false` the autoPlay is debounced.
*
* Also affects the `cooldown` when `isUserInteraction` is `true`,
* the `cooldown` is checked, otherwise when `false`
* the `cooldown` is ignored.
*
* Defaults to `true`.
*
* @since 1.0.0
*/
isUserInteraction?: boolean;
/**
* The `cooldown` is the number of milliseconds before another
* activation / deactivation is allowed. For example if the
* `cooldown` is `5000` the `ActiveList` will not allow
* transitions until after 5 seconds have passed. Any activation /
* deactivation in that period will simply be ignored.
*
* This can be useful when you have an animation which should be
* finished before allowing user interaction again.
*
* The benefit of this `cooldown` over the `cooldown` in the
* `Config`, is that this `cooldown` can be different for different
* actions. For example: it allows you to create two buttons each
* with a different cooldown.
*
* Note that the `cooldown` options within the `ActiveListActivationOptions`
* takes precedence over the `cooldown` in the `Config`.
*
* IMPORTANT: `cooldown` is only ran when `isUserInteraction` within
* the `ActiveListActivationOptions` is `true`. This means that
* `autoPlay`, which is not a user interaction, ignores the
* `cooldown`.
*
* @since 1.0.0
*/
cooldown?: ActiveListCooldownConfig<T>;
};
/**
* The subscriber which is informed of all state changes the
* ActiveList goes through.
*
* @param {ActiveList<T>} activeList The ActiveList which had changes.
* @param {ActiveListEvent<T>} event The event that occurred.
*
* @since 1.0.0
*/
type ActiveListSubscriber<T> = (activeList: ActiveList<T>, event: ActiveListEvent<T>) => void;
/**
* Represents a bundle of data which is given as the first parameter
* to the ContentPredicate function. Based on this data the
* ContentPredicate must either return `true` or `false`.
*
* @since 1.0.0
*/
type ActiveListContentPredicateData<T> = {
/**
* The value the ActiveListContent wraps.
*
* @since 1.0.0
*/
value: T;
/**
* The index the ActiveListContent has within the ActiveList
*
* @since 1.0.0
*/
index: number;
/**
* A reference to the ActiveListContent which wraps the value.
*
* @since 1.0.0
*/
content: ActiveListContent<T>;
/**
* A reference to the ActiveList itself.
*
* @since 1.0.0
*/
activeList: ActiveList<T>;
};
/**
* Represents a callback which is given all relevant data for the
* action, and expects either `true` or `false` to be returned. If
* `true` is returned will perform the action.
*
* @param {ActiveListContentPredicateData<T>} data The data for which this predicate will determine if the action needs to be performed.
* @returns {boolean} Whether or not to perform the action associated with the predicate based on the given item and index.
*
* @since 1.0.0
*/
type ActiveListContentPredicate<T> = (data: ActiveListContentPredicateData<T>) => boolean;
/**
* Represents a bundle of data which is given whenever the
* AutoPlayDurationCallbackData function must determine the number
* of milliseconds the content should be active for.
*
* @since 1.0.0
*/
type ActiveListAutoPlayDurationCallbackData<T> = {
/**
* The value which is currently asking which autoPlay duration it should have.
*
* @since 1.0.0
*/
value: T;
/**
* The index the value has within the ActiveList
*
* @since 1.0.0
*/
index: number;
/**
* A reference to the ActiveListContent which wraps the value.
*
* @since 1.0.0
*/
content: ActiveListContent<T>;
/**
* A reference to the ActiveList itself.
*
* @since 1.0.0
*/
activeList: ActiveList<T>;
};
/**
* Represents a callback function which is given all relevant autoPlay
* duration data, and expects to be given back the number of
* milliseconds the content should be active before autoPlay moves on.
*
* @param {ActiveListAutoPlayDurationCallbackData<T>} data An object containing all relevant duration data for which the callback function must determine the number of milliseconds the content is active for.
* @returns {number} The time in milliseconds the content is active for the given AutoPlayDurationCallbackData.
*
* @since 1.0.0
*/
type ActiveListAutoPlayDurationCallback<T> = (config: ActiveListAutoPlayDurationCallbackData<T>) => number;
/**
* Represents the configuration for AutoPlay. AutoPlay means
* that the ActiveList will move to the next content by itself
* after a duration.
*
* @since 1.0.0
*/
type ActiveListAutoPlayConfig<T> = {
/**
* The time in milliseconds the ActiveListContent should remain active, before
* moving to the next ActiveListContent.
*
* @since 1.0.0
*/
duration: ActiveListAutoPlayDurationCallback<T> | number;
/**
* Whether or not the user interacting with the component should
* stop the autoPlay.
*
* When `true` any activation / deactivation method called on
* the `ActiveList` will stop the autoPlay. When `false` it will
* debounce the autoPlay instead by the duration.
*
* Defaults to `false`.
*
* @since 1.0.0
*/
stopsOnUserInteraction?: boolean;
};
/**
* AutoPlay means that the ActiveList will move to the next content by
* itself after a duration.
*
* Contains whether or not the autoPlay is playing via `isPlaying` and
* the current duration via `duration`.
*
* @since 1.0.0
*/
type ActiveListAutoPlay = {
/**
* Whether or not the ActiveList is playing. In other words whether
* or not the ActiveList is going to cycle through the content
* automatically.
*
* @since 1.0.0
*/
isPlaying: boolean;
/**
* The amount of milliseconds the item should remain active before
* jumping to the next item.
*
* This duration is the duration for the current item which is
* playing. It is not affected by calling pause, meaning that
* when the duration is set to 200ms and you pause after 100ms,
* the duration will still be 200ms.
*
* When calling `stop`, or when `stop` is called when the autoPlay
* reaches the end, the duration will be set to zero.
*
* @since 1.0.0
*/
duration: number;
/**
* Whether or not the ActiveList had the autoPlay stopped at one
* point before.
*
* Use case: say you are making a carousel which should stop on
* any user interaction, so you set `stopsOnUserInteraction` to
* `true`. Say you also have another feature: a pause whenever
* the user hovers over the carousel. These two features would cause
* a conflict:
*
* Whenever the mouse over happens you call `play()`, which negates
* the `stopsOnUserInteraction`, causing the carousel to play again.
*
* To fix this problem you should on the mouse over not call
* `play()` whenever `hasBeenStoppedBefore` is `true`.
*
* @since 1.1.0
*/
hasBeenStoppedBefore: boolean;
};
/**
* Represents the configuration of the cooldown.
*
* Can be two possible things:
*
* 1. A callback function which receives the relevant cooldown data,
* and which is required to return the duration in milliseconds.
* Useful for providing a different cooldown for different items.
*
* 2. A number in milliseconds. When it is a number all items will
* have the same cooldown.
*
* @since 1.0.0
*/
type ActiveListCooldownConfig<T> = ActiveListCooldownDurationCallback<T> | number;
/**
* Represents a bundle of data which is given whenever the
* CooldownDurationCallback function must determine what the number of
* milliseconds the content should be in a cooldown state.
*
* @since 1.0.0
*/
type ActiveListCooldownDurationCallbackData<T> = {
/**
* The value which is currently asking which cooldown it should have.
*
* @since 1.0.0
*/
value: T;
/**
* The index the value has within the ActiveList
*
* @since 1.0.0
*/
index: number;
/**
* A reference to the ActiveListContent which wraps the value.
*
* @since 1.0.0
*/
content: ActiveListContent<T>;
/**
* A reference to the ActiveList itself.
*
* @since 1.0.0
*/
activeList: ActiveList<T>;
};
/**
* Represents a callback function which is given all relevant cooldown
* duration data, and expects to be given back the number of
* milliseconds the content should be cooled down before it responds
* to user interaction again.
*
* WARNING: do not return a negative number or zero in this callback
* as this results in a `ActiveListCooldownDurationError`. The action
* will still occur however, this means that the ActiveList is invalid
* when this happens.
*
* @param {ActiveListCooldownDurationCallbackData<T>} data An object containing all relevant cooldown data for which the callback function must determine the cooldown duration in number of milliseconds.
* @returns {number} The time in milliseconds of the duration of the cooldown for the given CooldownCallbackData.
*
* @since 1.0.0
*/
type ActiveListCooldownDurationCallback<T> = (data: ActiveListCooldownDurationCallbackData<T>) => number;
/**
* A Cooldown is a time period in which all user made activations
* and deactivations are prevented / ignored. Activations and
* deactivations where the `isUserInteraction` is set to `false`
* always bypass the cooldown.
*
* The use-case is a cooldown can guarantees that animations are
* completed, before another is triggered.
*
* Contains whether or not the cooldown is active via `isActive` and
* the current duration via `duration`.
*
* @since 1.0.0
*/
type ActiveListCooldown = {
/**
* Whether or not the ActiveList is currently in the cooldown state.
* When in cooldown all activations and deactivations are ignored.
*
* @since 1.0.0
*/
isActive: boolean;
/**
* The amount of milliseconds the ActiveList should remain in
* the cooldown state.
*
* @since 1.0.0
*/
duration: number;
};
/**
* Describes which strings should be associated with what
* direction. For example it could be "right" and "left",
* or "down" and "up".
*
* Will be the value of the `ActiveList` property `direction`.
*
* Useful for when animations have a certain direction and you
* name your animation CSS classes `left-animation` and
* `right-animation`.
*
* @since 1.0.0
*/
type ActiveListDirection = {
/**
* The name of the direction when moving to the next item of the
* `ActiveList`.
*
* Could for example be "right" or "down".
*
* @since 1.0.0
*/
next: string;
/**
* The name of the direction when moving to the previous item of the
* `ActiveList`.
*
* Could for example be "left" or "up".
*
* @since 1.0.0
*/
previous: string;
};
/**
* Represents whether the `ActiveListEvent` was inserted, removed, activated
* swapped, etc etc.
*
* @since 1.0.0
*/
type ActiveListEventType = 'INITIALIZED' | 'INSERTED' | 'REMOVED' | 'REMOVED_MULTIPLE' | 'ACTIVATED' | 'ACTIVATED_MULTIPLE' | 'SWAPPED' | 'MOVED' | 'DEACTIVATED' | 'DEACTIVATED_MULTIPLE' | 'AUTO_PLAY_PLAYING' | 'AUTO_PLAY_PAUSED' | 'AUTO_PLAY_STOPPED' | 'COOLDOWN_STARTED' | 'COOLDOWN_ENDED';
/**
* Represents an event which happened in the ActiveList. Based
* on the `type` you can determine which event occurred.
*
* @since 1.0.0
*/
type ActiveListBaseEvent = {
/**
* Which event occurred
*
* @since 1.0.0
*/
type: ActiveListEventType;
/**
* The time the event occurred on as a Date object.
*
* @since 1.0.0
*/
time: Date;
};
/**
* Represents the initialization of the ActiveList
*
* @since 1.0.0
*/
type ActiveListInitializedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'INITIALIZED';
/**
* The values which were active upon initialization.
*
* Note: these are the values at the time of the initialization, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
values: T[];
/**
* The indexes of the values which were active upon initialization.
*
* Note: these are the indexes at the time of the initialization, it might
* no longer be accurate.
*
* @since 1.0.0
*/
indexes: number[];
};
/**
* Represents an insertion into the ActiveList.
*
* @since 1.0.0
*/
type ActiveListInsertedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'INSERTED';
/**
* The value which was inserted.
*
* Note: this was the value at the time of insertion, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
value: T;
/**
* The index of the insertion.
*
* Note: this was the index at the time of the insertion, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents an removal of an item of the ActiveList.
*
* @since 1.0.0
*/
type ActiveListRemovedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'REMOVED';
/**
* The value which was removed.
*
* Note: this was the value at the time of removal, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
value: T;
/**
* The index of removed item.
*
* Note: this was the index at the time of the removal, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents multiple removals of items in the ActiveList.
*
* @since 1.0.0
*/
type ActiveListRemovedMultipleEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'REMOVED_MULTIPLE';
/**
* The values which were removed
*
* Note: these are the values at the time of removal, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
values: T[];
/**
* The indexes of the removed items.
*
* Note: these are the indexes at the time of the removal, it might
* no longer be accurate.
*
* @since 1.0.0
*/
indexes: number[];
};
/**
* Represents an activation of an ActiveList.
*
* @since 1.0.0
*/
type ActiveListActivatedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'ACTIVATED';
/**
* The value which was activated.
*
* Note: this was the value at the time of activation, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
value: T;
/**
* The index of the activated item.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
/**
* The value which was deactivated, will be `null` when no value
* was deactivated as part of the activation.
*
* A deactivation will only happen as part of an activation when
* `maxActivationLimit` is set to a `number` and
* `maxActivationLimitBehavior` is set to `circular`.
*
* Note: these are the values at the time of deactivation, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.5.0
*/
deactivatedValue: T | null;
/**
* The index of the deactivated item, will be `-1` when no index
* was deactivated as part of the activation.
*
* A deactivation will only happen as part of an activation when
* `maxActivationLimit` is set to a `number` and
* `maxActivationLimitBehavior` is set to `circular`.
*
* Note: this was the index at the time of the deactivation, it might
* no longer be accurate.
*
* @since 1.5.0
*/
deactivatedIndex: number;
};
/**
* Represents multiple activations happening at the same time in an
* ActiveList.
*
* @since 1.0.0
*/
type ActiveListActivatedMultipleEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'ACTIVATED_MULTIPLE';
/**
* The values which were activated.
*
* Note: these are the values at the time of activation, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
values: T[];
/**
* The indexes of the activated items.
*
* Note: these are the indexes at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
indexes: number[];
/**
* The values which were deactivated.
*
* A deactivation will only happen as part of an activation when
* `maxActivationLimit` is set to a `number` and
* `maxActivationLimitBehavior` is set to `circular`.
*
* Note: these are the values at the time of deactivation, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.5.0
*/
deactivatedValues: T[];
/**
* The indexes of the deactivated items.
*
* A deactivation will only happen as part of an activation when
* `maxActivationLimit` is set to a `number` and
* `maxActivationLimitBehavior` is set to `circular`.
*
* Note: these are the indexes at the time of the deactivation, it might
* no longer be accurate.
*
* @since 1.5.0
*/
deactivatedIndexes: number[];
};
/**
* Represents a deactivation of an ActiveList.
*
* IMPORTANT: this event is only fired as a result of a direct
* deactivation call. So not when activating an item also deactivated
* an item due to a `maxActivationLimit` being set.
*
* @since 1.0.0
*/
type ActiveListDeactivatedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'DEACTIVATED';
/**
* The value which was deactivated.
*
* Note: this was the value at the time of deactivation, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
value: T;
/**
* The index of the deactivated item.
*
* Note: this was the index at the time of the deactivation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents multiple deactivations happening at the same time in an
* ActiveList.
*
* IMPORTANT: this event is only fired as a result of a direct
* deactivation call. So not when activating an item also deactivated
* an item due to a `maxActivationLimit` being set.
*
*
* @since 1.0.0
*/
type ActiveListDeactivatedMultipleEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'DEACTIVATED_MULTIPLE';
/**
* The values which were deactivated.
*
* Note: these are the values at the time of deactivation, they might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
values: T[];
/**
* The indexes of the deactivated items.
*
* Note: these are the indexes at the time of the deactivation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
indexes: number[];
};
/**
* Represents an activation of an ActiveList.
*
* @since 1.0.0
*/
type ActiveListSwappedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'SWAPPED';
/**
* An object containing the value of the items which were swapped.
*
* @since 1.0.0
*/
value: {
/**
* The value of the first item which was swapped.
*
* Note: this was the value at the time of the swap, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
a: T;
/**
* The value of the second item which was swapped.
*
* Note: this was the value at the time of the swap, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
b: T;
};
/**
* An object containing the indexes of the items which were swapped.
*
* @since 1.0.0
*/
index: {
/**
* The index of the first item before it was swapped.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
a: number;
/**
* The index of the second item before it was swapped.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
b: number;
};
};
/**
* Represents an activation of an ActiveList.
*
* @since 1.0.0
*/
type ActiveListMovedEvent<T> = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'MOVED';
/**
* The value which was moved.
*
* Note: this was the value at the time of the move, it might
* no longer be accurate. Keep in mind that when the `value` is
* an object or an array, they can still be mutated, because no
* copy is made.
*
* @since 1.0.0
*/
value: T;
/**
* An object containing the "from" and "to" index of the item which
* were moved.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: {
/**
* The index of the "from" item before it was moved.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
from: number;
/**
* The index of the "to" item before it was moved.
*
* Note: this was the index at the time of the activation, it might
* no longer be accurate.
*
* @since 1.0.0
*/
to: number;
};
};
/**
* Represents an ActiveList autoPlay being restarted again when it was
* stopped or paused.
*
* Note: this event is not fired when a ActiveList is initialized
* even though this does start the autoPlay.
*
* @since 1.0.0
*/
type ActiveListAutoPlayPlayingEvent = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_PLAY_PLAYING';
};
/**
* Represents an ActiveList autoPlay being paused.
*
* @since 1.0.0
*/
type ActiveListAutoPlayPausedEvent = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_PLAY_PAUSED';
};
/**
* Represents an ActiveList autoPlay being stopped.
*
* Can be fired for four reasons:
*
* 1. The `stop` method on the `ActiveList` is called.
*
* 2. The autoPlay reached the last of the items, which can only
* happen when `isCircular` is `false`.
*
* 3. When all content items are removed when the autoPlay is playing.
* It will then stop automatically since there are no more items.
*
* 4. When no more items are left active, in this case the autoPlay
* will stop as well.
*
* Note: due to reasons 3 and 4 this event can be fired right before
* a 'REMOVED', 'REMOVED_MULTIPLE', 'DEACTIVATED' and
* 'DEACTIVATED_MULTIPLE' event.
*
* @since 1.0.0
*/
type ActiveListAutoPlayStoppedEvent = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_PLAY_STOPPED';
};
/**
* Represents an ActiveList being in a cooldown state, meaning no
* activations or deactivations can occur.
*
* @since 1.0.0
*/
type ActiveListCooldownStartedEvent = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'COOLDOWN_STARTED';
};
/**
* Represents an ActiveList moving out of the cooldown state, meaning
* all activation and deactivations can occur again.
*
* @since 1.0.0
*/
type ActiveListCooldownEndedEvent = ActiveListBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'COOLDOWN_ENDED';
};
/**
* A ActiveListEvent represents an event happened in the ActiveList.
* For example the insertion, removal, or activation of a
* ActiveListContent<T>.
*
* @since 1.0.0
*/
type ActiveListEvent<T> = ActiveListInitializedEvent<T> | ActiveListInsertedEvent<T> | ActiveListRemovedEvent<T> | ActiveListRemovedMultipleEvent<T> | ActiveListActivatedEvent<T> | ActiveListActivatedMultipleEvent<T> | ActiveListSwappedEvent<T> | ActiveListMovedEvent<T> | ActiveListDeactivatedEvent<T> | ActiveListDeactivatedMultipleEvent<T> | ActiveListAutoPlayPlayingEvent | ActiveListAutoPlayPausedEvent | ActiveListAutoPlayStoppedEvent | ActiveListCooldownStartedEvent | ActiveListCooldownEndedEvent;
/**
* Represents where the action needs to take place for when a
* predicate is provided.
*
* 1. When the mode is 'at', the `ActiveListContent` is inserted to the
* position where the predicate matches. This is the `default`
* mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is inserted to after
* the position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is inserted to
* before the position where the predicate matches.
*
* @since 1.0.0
*/
type ActiveListPredicateMode = 'at' | 'before' | 'after';
/**
* Represents options for methods which require predicates.
*
* @since 1.0.0
*/
type ActiveListPredicateOptions = {
/**
* Represents where the action needs to take place for when a
* predicate is provided.
*
* Represents where the action needs to take place for when a
* predicate is provided.
*
* 1. When the mode is 'at', the `ActiveListContent` is inserted to the
* position where the predicate matches. This is the `default`
* mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is inserted to after
* the position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is inserted to
* before the position where the predicate matches.
*
* @since 1.0.0
*/
mode: ActiveListPredicateMode;
};
/**
* Represents a piece of content in the `contents` array of the `ActiveList`.
*
* The purpose of the ActiveListContent is to act as a wrapper around the
* value which is actually in the contents array. It knows things like
* whether the item is active or not.
*
* It also contains methods to activate, remove, swap and move itself
* within the ActiveList.
*
* @since 1.0.0
*/
declare class ActiveListContent<T> {
/**
* Reference to the ActiveList is it a part of.
*
* @since 1.0.0
*/
activeList: ActiveList<T>;
/**
* The index of the `ActiveListContent` which it has within the `contents`.
*
* @since 1.0.0
*/
index: number;
/**
* The actual `value` of the `ActiveListContent` it can be whatever the
* developer wants it to be.
*
* @since 1.0.0
*/
value: T;
/**
* Whether or not the `ActiveListContent` is currently active.
*
* @since 1.0.0
*/
isActive: boolean;
/**
* Whether or not the `ActiveListContent` has been active at least once
* in the past.
*
* @since 1.0.0
*/
hasBeenActiveBefore: boolean;
/**
* Whether or not the `ActiveListContent` is considered to be the first
* item in the `contents`.
*
* @since 1.0.0
*/
isFirst: boolean;
/**
* Whether or not the `ActiveListContent` is considered to be the last
* item in the `contents`.
*
* @since 1.0.0
*/
isLast: boolean;
/**
* Whether this `ActiveListContent` has at least one other `ActiveListContent` coming
* after it in the `contents`
*
* @since 1.0.0
*/
hasNext: boolean;
/**
* Whether this `ActiveListContent` has at least one other `ActiveListContent` coming
* before it in the `contents`.
*
* @since 1.0.0
*/
hasPrevious: boolean;
/**
* Whether this `ActiveListContent` comes directly after the `ActiveListContent`, in the
* `contents` array, which is currently the `lastActiveList`.
*
* @since 1.0.0
*/
isNext: boolean;
/**
* Whether this `ActiveListContent` comes directly before the `ActiveListContent`, in the
* `contents` array, which is currently the `lastActiveList`.
*
* @since 1.0.0
*/
isPrevious: boolean;
/**
* Creates an ActiveListContent which belongs to the given ActiveList.
*
* Note: you should never create instances of ActiveListContent yourself. You
* are supposed to let ActiveList do this for you.
*
* @param {ActiveList<T>} activeList The ActiveList this ActiveListContent belongs to.
* @param {number} index The index of this ActiveListContent within the ActiveList.
* @param {T} value The value this ActiveListContent wraps.
*
* @since 1.0.0
*/
constructor(activeList: ActiveList<T>, index: number, value: T);
/**
* When calling `activate` it will make this `ActiveListContent` active.
*
* @param {ActiveListActivationOptions<T>} [activationOptions] The activation options @see ActiveListActivationOptions<T>
*
* @since 1.0.0
*/
activate(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* When calling `deactivate` it will make this `ActiveListContent` inactive.
*
* @param {ActiveListActivationOptions<T>} [activationOptions] The activation options @see ActiveListActivationOptions<T>
*
* @since 1.0.0
*/
deactivate(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* When calling `toggle` it will flip the this `ActiveListContent`
* `isActive` state.
*
* So when `isActive` is `true` and `toggle` is called, `isActive`
* will become `false`. When `isActive` is `false` and `toggle` is
* called, `isActive` will become `true`.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {ActiveListActivationOptions<T>} [activationOptions] The activation options @see ActiveListActivationOptions<T>
*
* @since 1.0.0
*/
toggle(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* When calling `remove` it will remove this `ActiveListContent`, and return
* the `value` the ActiveListContent held.
*
* @returns {T} The removed value
*
* @since 1.0.0
*/
remove(): T;
/**
* Swaps the `ActiveListContent` with the `ActiveListContent` at the given index.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @param {number} index The index to swap the current `ActiveListContent` with.
* @throws {ActiveListItemNotFoundError} Item not found error
*
* @since 1.0.0
*/
swapWith(item: T): void;
/**
* Swaps the `ActiveListContent` with the `ActiveListContent` at the given index.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @param {number} index] The index to swap the current `ActiveListContent` with.
* @throws {ActiveListIndexOutOfBoundsError} Index out of bounds error.
*
* @since 1.0.0
*/
swapWithByIndex(index: number): void;
/**
* Swaps the `ActiveListContent` with the next `ActiveListContent` in the sequence.
*
* If `isCircular` of the `ActiveList` is `true` swapping whilst on
* the last index will make this `ActiveListContent` swap with the
* first index. If `isCircular` is `false` it will do nothing,
* and keep the `ActiveListContent` on the last index.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @since 1.0.0
*/
swapWithNext(): void;
/**
* Swaps the `ActiveListContent` with the previous `ActiveListContent` in the sequence.
*
* If `isCircular` of the `ActiveList` is `true` swapping whilst on
* the first index will make this `ActiveListContent` swap with the
* last index. If `isCircular` is `false` it will do nothing,
* and keep the `ActiveListContent` on the first index.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @since 1.0.0
*/
swapWithPrevious(): void;
/**
* Moves the `ActiveListContent` to the position at index "to".
*
* It is possible to move the `ActiveListContent` to the last place by making
* the "to" index the length of the `contents` array.
*
* Note: if the active `ActiveListContent` is moved it will stay active,
* meaning that the activeIndex will get updated.
*
* @param {number} to The location the `from` needs to move "to".
* @throws {ActiveListIndexOutOfBoundsError} Index out of bounds error.
*
* @since 1.0.0
*/
moveToIndex(to: number): void;
/**
* Moves the `ActiveListContent` to the position of the item for which
* the predicate returns `true`.
*
* If no item matches the predicate nothing is moved.
*
* The position to where the `ActiveListContent` is inserted can be altered by
* providing a mode:
*
* 1. When the mode is 'at', the `ActiveListContent` is inserted to the
* position where the predicate matches. This is the `default`
* mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is inserted to after
* the position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is inserted to
* before the position where the predicate matches.
*
* @param {ActiveListContentPredicate<T>} predicate The predicate function which when `true` is returned moves the item to after that position.
* @param {ActiveListPredicateOptions} options The options for the predicate, when no options are provided the mode will default to "at".
*
* @since 1.0.0
*/
moveToPredicate(predicate: ActiveListContentPredicate<T>, options?: ActiveListPredicateOptions): void;
/**
* Moves the `ActiveListContent` to the first position in the contents array.
*
* Note: if the active `ActiveListContent` is moved it will stay active,
* meaning that the activeIndex will get updated.
*
* @since 1.0.0
*/
moveToFirst(): void;
/**
* Moves the `ActiveListContent` to the last position in the contents array.
*
* Note: if the active `ActiveListContent` is moved it will stay active,
* meaning that the activeIndex will get updated.
*
* @since 1.0.0
*/
moveToLast(): void;
}
/**
* ActiveList is a class which represents visual elements which
* have multiple pieces of content which can be active or inactive.
*
* The `ActiveList` can be used to implement multiple types of
* components:
*
* 1. A tabs component for which one tab can be active at a time.
*
* 2. A carrousel component: the user sees single slide, which will
* autoPlay to the next slide automatically.
*
* 3. A dropdown menu with one active menu item.
*
* 4. A accordion component from which the user can open multiple
* items at once.
*
* 5. A list the user can sort and move around.
*
* 6. Etc etc
*
* Another way of defining the ActiveList is that it is an array
* / list like data structure, because it supports things like
* insertion and removal.
*
* ActiveList will make sure that when content is inserted, that
* the active content is not affected.
*
* @since 1.0.0
*/
declare class ActiveList<T> implements Observable<ActiveList<T>, ActiveListEvent<T>> {
/**
* Whether or not to inform subscribers of changes / record history.
* Used in the `initialize` to temporarily stop subscriptions running
* the initial activation, and altering the history.
*/
private _isInitializing;
/**
* The `ActiveListContent` instances which the `ActiveList` holds.
*
* @since 1.0.0
*/
readonly contents: ActiveListContent<T>[];
/**
* How many items can be active at the same time.
*
* When the value of `limit` is `false` there is no limit to the
* number of active items.
*
* Defaults to 1.
*
* @since 1.0.0
*/
maxActivationLimit: number | false;
/**
* How the `maxActivationLimit` is enforced. In other words what the
* behavior should be when the limit is surpassed.
*
* The modes are strings which can be the following values:
*
* 1. 'circular': the first item which was added will be removed so
* the last item can be added without violating the limit. This
* basically means that the first one in is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `ActiveListActivationLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an item is added and the limit
* is reached. The item is simply not added, but no error is
* thrown.
*
* Defaults to 'circular'.
*
* @since 1.0.0
*/
maxActivationLimitBehavior: ActiveListMaxActivationLimitBehavior;
/**
* All `value` of the content which are currently considered active.
*
* @since 1.0.0
*/
readonly active: T[];
/**
* All `ActiveListContent` which are currently considered active.
*
* @since 1.0.0
*/
readonly activeContents: ActiveListContent<T>[];
/**
* All indexes of which are currently considered active.
*
* @since 1.0.0
*/
readonly activeIndexes: number[];
/**
* Which `value` from within an `ActiveListContent` was the last
* value which was activated.
*
* In other words: of all active values which value was activated
* the last chronologically.
*
* When nothing is activated in the `ActiveList` the value of
* `lastActivated` will be `null`.
*
* @since 1.0.0
*/
lastActivated: T | null;
/**
* Which `ActiveListContent` is the last ActiveListContent which
* was activated.
*
* In other words: of all active contents which content was
* activated the last chronologically.
*
* When nothing is activated in the `ActiveList` the value of
* `lastActivatedContent` will be `null`.
*
* @since 1.0.0
*/
lastActivatedContent: ActiveListContent<T> | null;
/**
* Which index of the `contents` array was the last index which
* was activated.
*
* In other words: of all active indexes which index was activated
* the last chronologically.
*
* When nothing is activated in the `ActiveList` the value of
* `lastActivatedIndex` will be `-1`.
*
* @since 1.0.0
*/
lastActivatedIndex: number;
/**
* Which `value` from within an `ActiveListContent` was the last
* value which was deactivated.
*
* When nothing was deactivated previously in the `ActiveList` the
* value of `lastDeactivated` will be `null`.
*
* @since 1.5.0
*/
lastDeactivated: T | null;
/**
* Which `ActiveListContent` is the last ActiveListContent which
* was deactivated.
*
* When nothing was deactivated previously in the `ActiveList` the
* value of `lastDeactivatedContent` will be `null`.
*
* @since 1.5.0
*/
lastDeactivatedContent: ActiveListContent<T> | null;
/**
* Which index of the `contents` array was the last index which
* was deactivated.
*
* When nothing was deactivated previously in the `ActiveList` the
* value of `lastDeactivatedIndex` will be `-1`.
*
* @since 1.5.0
*/
lastDeactivatedIndex: number;
/**
* Whether or not the content starts back at the beginning when
* the end of the content is reached, and whether the content should
* go to the end when moving left of the start.
*
* Defaults to `false`.
*
* @since 1.0.0
*/
isCircular: boolean;
/**
* The direction the `ActiveList` has previously moved to on
* activation or deactivation.
*
* Useful for when animating the `ActiveList` when wanting to
* animate differently based on the direction the content is
* activating towards.
*
* The direction is determined using the following rules for
* activation:
*
* 1. When `isCircular` is `false`:
*
* a. If the `lastActivatedIndex` is -1 the direction is always `next`.
* The `lastActivatedIndex` is -1 when no item is active.
*
* b. If the `lastActivatedIndex` lies before the activated index the
* direction is `next`.
*
* c. If the `lastActivatedIndex` lies after the activated index the
* direction is `previous`.
*
* 2. When `isCircular` is `true`,
*
* a. If the `lastActivatedIndex` is -1 the direction is always `next`.
* The `lastActivatedIndex` is -1 when no item is active.
*
* b. The direction is determined by checking which direction
* is the shortest path. If the shortest paths are tied, the
* direction will become `next`.
*
* Note: the direction is only changed upon activation and
* deactivation. Removing / inserting, moving and swapping do not
* affect the direction.
*
* Defaults to the value of the `Config` property `direction.next`.
*
* @since 1.0.0
*/
direction: string;
/**
* The opposite of the `direction` property of the `ActiveList`.
* If the `direction` is `next` the opposite direction is always
* `previous` and vice versa.
*
* Defaults to the value of the `Config` property `direction.previous`.
*
* @since 1.5.0
*/
oppositeDirection: string;
private _history;
/**
* Contains the history of the changes in the contents array.
*
* Tracks 15 types of changes:
*
* 1. INITIALIZED: fired when ActiveList is initialized.
*
* 2. INSERTED: fired when an item is added.
*
* 3. REMOVED: fired when an item is removed.
*
* 4. REMOVED_MULTIPLE: fired when multiple items are removed with a predicate.
*
* 5. ACTIVATED: fired when an item is activated.
*
* 6 ACTIVATED_MULTIPLE: fired when multiple items are activated with a predicate.
*
* 7. DEACTIVATED: fired when an item is deactivated.
*
* 8. DEACTIVATED_MULTIPLE: fired when multiple items are deactivated with a predicate.
*
* 9. SWAPPED: fired when an item is swapped.
*
* 10. MOVED: fired when an item is moved.
*
* 11. AUTO_PLAY_PLAYING: fired when play is called.
*
* 12. AUTO_PLAY_PAUSED: fired when pause is called.
*
* 13. AUTO_PLAY_STOPPED: fired when stop is called, or the autoPlay stops due to a condition.
*
* 14. COOLDOWN_STARTED: fired when ActiveList goes into cooldown state
*
* 15. COOLDOWN_ENDED: fired when ActiveList goes out of cooldown state
*
* Goes only as far back as configured in the `Config` property
* `keepHistoryFor`, to prevent an infinitely growing history.
* Note that by default no history is kept, as `keepHistoryFor`
* is zero by default.
*
* The last item in the `history` is the current active item. The
* further to the left the further in the past you go.
*
* This means that a history at index 0 is further in the past than
* an item at index 1.
*
* WARNING: all events store indexes, values and combinations thereof.
* The `index` of an item in the history may no longer be accurate, it
* is the index at the time of the event. Same goes for the `value`
* when it is an array of object, as it might have been mutated, the
* history items do not store copies of the values.
*
* @since 1.0.0
*/
readonly history: ActiveListEvent<T>[];
private _observer;
/**
* Whether or not the `active` item has changed at least once.
* Useful when you want to know if the `ActiveList` is still
* in its initial state.
*
* Note: when the `initialize` method of the `Actions` is called this
* boolean is reset.
*
* @since 1.0.0
*/
hasActiveChangedAtLeastOnce: boolean;
private _activationCooldownTimer;
/**
* A Cooldown is a time period in which all user made activations
* and deactivations are prevented / ignored. Activations and
* deactivations where the `isUserInteraction` is set to `false`
* always bypass the cooldown.
*
* The use-case is a cooldown can guarantees that animations are
* completed, before another is triggered.
*
* Contains whether or not the cooldown is active via `isActive` and
* the current duration via `duration`.
*
* @since 1.0.0
*/
readonly cooldown: ActiveListCooldown;
private _autoPlay;
/**
* AutoPlay means that the ActiveList will move to the next content by
* itself after a duration.
*
* Contains whether or not the autoPlay is playing via `isPlaying`,
* the current duration via `duration`, and whether or not the
* autoPlay has been stopped before via `hasBeenStoppedBefore`
*
* @since 1.0.0
*/
readonly autoPlay: ActiveListAutoPlay;
private _directions;
/**
* Creates an ActiveList based on the ActiveListConfig config.
*
* You can also optionally provide an subscriber so you can get
* informed of the changes happening to the ActiveList.
*
* @param {ActiveListConfig<T>} config The initial configuration of the ActiveList.
* @param {ActiveListSubscriber<T> | undefined} subscriber An optional subscriber which responds to changes in the ActiveList.
* @throws {ActiveListAutoPlayDurationError} autoPlay duration must be a positive number when defined
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @since 1.0.0
*/
constructor(config?: ActiveListConfig<T>, subscriber?: ActiveListSubscriber<T>);
/**
* Subscribe to changes of the ActiveList. The function you
* provide will get called whenever changes occur in the
* ActiveList.
*
* Returns an unsubscribe function which when called will unsubscribe
* from the ActiveList.
*
* @param {ActiveListSubscriber<T>} subscriber The subscriber which responds to changes in the ActiveList.
* @returns {UnsubscribeFunction} A function which when called will unsubscribe from the ActiveList.
*
* @since 1.0.0
*/
subscribe(subscriber: ActiveListSubscriber<T>): UnsubscribeFunction;
/**
* Unsubscribe the subscriber so it no longer receives changes / updates
* of the state changes of the ActiveList.
*
* @param {ActiveListSubscriber<T>} subscriber The subscriber which you want to unsubscribe.
*
* @since 1.0.0
*/
unsubscribe(subscriber: ActiveListSubscriber<T>): void;
/**
* Unsubscribes all subscribers at once, all subscribers will no
* longer receives changes / updates of the state changes of
* the ActiveList.
*
* @since 1.5.0
*/
unsubscribeAll(): void;
/**
* Initializes the ActiveList based on the config provided. This can
* effectively reset the ActiveList when called, including the
* history, autoPlay and cooldown.
*
* @param {ActiveListConfig<T>} config The new configuration which will override the old one
* @throws {ActiveListAutoPlayDurationError} autoPlay duration must be a positive number when defined
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @since 1.0.0
*/
initialize(config: ActiveListConfig<T>): void;
private _initializeABrokenContent;
/**
* Activates an item based on the index in the content array.
*
* If the index does not exist an error will be thrown.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {number} index The index to activate
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activateByIndex(index: number, activationOptions?: ActiveListActivationOptions<T>): void;
private _doActivateByIndex;
/**
* Activates the given item based on identity by comparing the item
* via a `===` check. When multiple items match on `===` only the
* first matching item is activated.
*
* If the item does not exist in the content array it will
* throw an error.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {T} item The item to activate
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activate(item: T, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Activates all items that match the predicate.
*
* If no items match the predicate nothing happens.
*
* If multiple items were activated as a result of calling
* `activateByPredicate` they will be activated in order of
* appearance in the contents array.
*
* Items can also be deactivated if the `maxActivationLimit` is set
* to a number and the `maxActivationLimitBehavior` is set to
* "circular", if space needs to be made for the new activations.
*
* When `maxActivationLimitBehavior` is set to "error", all items
* that can be accommodated are activated, but when the limit is
* exceeded the activation stops. The subscribers are then informed
* of which items were activated, and then the error is thrown.
*
* Even through each item is activated sequentially, only one event
* is emitted, and one call is made to the subscribers, even if
* multiple items are activated and deactivated.
*
* Within the `ActiveListActivatedMultipleEvent` only the end
* activate / deactivate results are reported.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`. When the cooldown is configured
* as a function, the last activated content will be the parameter
* to the cooldown function.
*
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will activate that item.
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activateByPredicate(predicate: ActiveListContentPredicate<T>, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Activates the next item in the sequence based on the `lastActivated`
* ActiveListContent.
*
* If no `lastActivated` is present when `activateNext` is called
* the first element is activated.
*
* If the `contents` are empty when `activateNext` is called
* nothing will happen.
*
* When on the last position: if `isCircular` is `true` it will circle
* around and activate the first position. When `isCircular` is `false`
* it will stay on the last position and do nothing.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activateNext(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Activates the previous item in the sequence based on the
* `lastActivated` ActiveListContent.
*
* If no `lastActivated` is present when `activatePrevious` is called
* the first element is activated.
*
* If the `contents` are empty when `activatePrevious` is called
* nothing will happen.
*
* When on the first position: if `isCircular` is `true` it will circle
* around and activate the last position. When `isCircular` is `false`
* it will stay on the first position and do nothing.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activatePrevious(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Activates the first item of the contents.
*
* If the `contents` are empty when `activateFirst` is called
* nothing will happen.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activateFirst(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Activates the last item of the contents.
*
* If the `contents` are empty when `activateLast` is called
* nothing will happen.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListActivationLimitReachedError} thrown when maxActivationLimit is exceeded, and maxActivationLimitBehavior is "error".
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
activateLast(activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Deactivates an item based on the index in the content array.
*
* If the index does not exist an error will be thrown.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {number} index The index to deactivate
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
deactivateByIndex(index: number, activationOptions?: ActiveListActivationOptions<T>): void;
private _doDeactivateByIndex;
/**
* Deactivates the given item based on identity by comparing the item
* via a `===` check. When multiple items match on `===` only the
* first matching item is activated.
*
* If the item does not exist in the content array it will
* throw an error.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {T} item The item to deactivate
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
deactivate(item: T, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Deactivates all items that match the predicate.
*
* If no items match the predicate nothing happens.
*
* If multiple items match they will be deactivated in order of
* appearance in the contents array. Only one call is made to the
* subscribers, even if multiple items are deactivated.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`. When the cooldown is configured
* as a function, the last deactivated content will be the parameter
* to the cooldown function.
*
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will deactivate that item.
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListCooldownDurationError} cooldown duration must be a positive number when defined
*
* @since 1.0.0
*/
deactivateByPredicate(predicate: ActiveListContentPredicate<T>, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* When calling `toggleByIndex` it will flip the `ActiveListContent`
* which resides on the index `isActive` state .
*
* So when `isActive` is `true` and `toggle` is called, `isActive`
* will become `false`. When `isActive` is `false` and `toggle` is
* called, `isActive` will become `true`.
*
* If the index does not exist an error will be thrown.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {number} index The index to activate
* @param {ActiveListActivationOptions<T>} [activationOptions] The activation options
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
toggleByIndex(index: number, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Toggles the given item based on identity by comparing the item
* via a `===` check. When multiple items match on `===` only the
* first matching item is activated.
*
* So when `isActive` is `true` and `toggle` is called, `isActive`
* will become `false`. When `isActive` is `false` and `toggle` is
* called, `isActive` will become `true`.
*
* If the item does not exist in the content array it will
* throw an error.
*
* With the `activationOptions` you can determine the effects
* on `cooldown` and `autoPlay`.
*
* @param {T} item The item to toggle
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
*
* @since 1.0.0
*/
toggle(item: T, activationOptions?: ActiveListActivationOptions<T>): void;
/**
* Will start playing the ActiveList based on the active
* autoPlayConfig. When `autoPlayConfig` is not defined nothing
* will happen when calling play.
*
* When there is no more content the playing will stop automatically.
*
* Note: autoPlay will only start when one or more contents are
* currently active. The reason for this is that the `duration`, is
* based on the `ActiveList` `lastActivatedContent` property.
* Whenever there are no more items to activate the autoPlay will
* stop.
*
* @throws {ActiveListAutoPlayDurationError} autoPlay duration must be a positive number when defined
*
* @since 1.0.0
*/
play(): void;
/**
* When the ActiveList is playing it will pause the autoPlay.
*
* When paused, the current autoPlay duration is remember and resumed
* from that position, when `play` is called again.
*
* For example: when the duration is 1 second and the `pause` is
* called after 0.8 seconds, it will after `play` is called, take
* 0.2 seconds to go to the next content.
*
* Note: if the autoPlay is already paused calling `pause` again
* will do nothing, the time used for the remaining duration is
* based on the first pause.
*
* @since 1.0.0
*/
pause(): void;
/**
* When the ActiveList is playing it will stop the autoPlay.
*
* By calling `play` again it is possible to restart the autoPlay.
* However the duration will behave in this scenario as it if was
* reset.
*
* For example: when the duration is 1 second and the `stop` is
* called after 0.8 seconds, it will after `play` is called, take
* 1 second to go to the next content.
*
* @since 1.0.0
*/
stop(): void;
/**
* Configures the autoPlay, when the autoPlay is `null` the autoPlay
* is stopped.
*
* Can be used to reconfigure the speed of the autoPlay after the
* ActiveList has been created.
*
* Note: calling `configureAutoPlay` will not set (reset) the
* hasBeenStoppedBefore` to `false` when called.
*
* @param {ActiveListAutoPlayConfig<T> | null} autoPlayConfig The new autoPlay configuration
* @throws {ActiveListAutoPlayDurationError} autoPlay duration must be a positive number when defined
*
* @since 1.0.0
*/
configureAutoPlay(autoPlayConfig: ActiveListAutoPlayConfig<T> | null): void;
/**
* Will add an item to the `contents` array, at the specified `index`.
*
* Note: `insertAtIndex` will not allow holes to be created, this
* means that the index can only be between `0` and `contents.length`.
* If you give it a larger or smaller index it will throw an error.
*
* @param {T} item The item to insert.
* @param {number} index The index at which to insert the item.
* @returns {ActiveListContent<T>} The newly inserted item wrapped in an `ActiveListContent`
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
insertAtIndex(item: T, index: number): ActiveListContent<T>;
/**
* Will add an item to the end of the `contents` array.
*
* @param {T} item The item to insert.
* @returns {ActiveListContent<T>} The newly inserted item wrapped in an `ActiveListContent`
*
* @since 1.0.0
*/
push(item: T): ActiveListContent<T>;
/**
* Will add an item at the start of the `contents` array.
*
* @param {T} item The item to insert.
* @returns {ActiveListContent<T>} The newly inserted item wrapped in an `ActiveListContent`
*
* @since 1.0.0
*/
unshift(item: T): ActiveListContent<T>;
/**
* Will add an item at the position in the `contents` array when when
* the predicate returns `true` for the `item` and `index`.
*
* If no item matches the predicate nothing is inserted and `null`
* will be returned.
*
* The position to where the `ActiveListContent` is inserted can be altered by
* providing a mode:
*
* 1. When the mode is 'at', the `ActiveListContent` is inserted to the
* position where the predicate matches. This is the `default`
* mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is inserted to after
* the position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is inserted to
* before the position where the predicate matches.
*
* @param {T} item The item to insert.
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will move the item to that position.
* @param {ActiveListPredicateOptions} options The options for the predicate, when no options are provided the mode will default to "at".
*
* @since 1.0.0
*/
insertByPredicate(item: T, predicate: ActiveListContentPredicate<T>, options?: ActiveListPredicateOptions): ActiveListContent<T> | null;
/**
* Will remove an item in the `contents` array, at the specified `index`.
*
* If you remove the `lastDeactivated` item it will be set to null.
*
* Throws an error if the index does not exist within the `contents`
* array.
*
* @param {number} index The index at which to remove the item.
* @returns {T} The removed value
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
removeByIndex(index: number): T;
private _doRemoveAtIndex;
/**
* Removes the given item based on identity by comparing the item
* via a `===` check. When multiple items match on `===` only the
* first matching item is removed.
*
* If you remove the `lastDeactivated` item it will be set to null.
*
* If the item does not exist in the content array it will
* throw an error.
*
* @param {T} item The item to remove
* @returns {T} The removed item
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
*
* @since 1.0.0
*/
remove(item: T): T;
/**
* Removes the last item of the of the `contents` array.
*
* If you remove the `lastDeactivated` item it will be set to null.
*
* If the `contents` array at the time of the `pop` is empty
* `undefined` is returned.
*
* @param {ActiveListActivationOptions<T>} ActiveListActivationOptions The activation options
* @returns {T | undefined} The removed value, or undefined if the `contents` array is empty.
*
* @since 1.0.0
*/
pop(): T | undefined;
/**
* Removes the first item of the `contents` array.
*
* If you remove the `lastDeactivated` item it will be set to null.
*
* If the `contents` array at the time of the `shift` is empty
* `undefined` is returned.
*
* @returns {T | undefined} The removed value, or undefined if the `contents` array is empty.
*
* @since 1.0.0
*/
shift(): T | undefined;
/**
* Will remove all items from the `contents` array for which the
* predicate based on the `item` and `index` returns `true`.
*
* If no item matches the predicate nothing is removed and an empty
* array will be returned.
*
* If you remove the `lastDeactivated` item it will be set to null.
*
* @param {T} item The item to insert.
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will remove the item.
* @returns {T[]} The removed items.
*
* @since 1.0.0
*/
removeByPredicate(predicate: ActiveListContentPredicate<T>): T[];
/**
* Swaps the `ActiveListContent` at index a, with the `ActiveListContent` at index b.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @param {number} a The first index to swap.
* @param {number} b The second index to swap.
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
swapByIndex(a: number, b: number): void;
/**
* Swaps the `ActiveListContent` with item a, with the `ActiveListContent` with
* item b. Swaps the items based on identity by comparing the items
* via a `===` check. When multiple items match on `===` only the
* first matching item is swapped.
*
* Note: if the active `ActiveListContent` is swapped, it will stay active,
* it will only get a new position.
*
* @param {T} a The first item to swap.
* @param {T} b The second item to swap.
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
*
* @since 1.0.0
*/
swap(a: T, b: T): void;
/**
* Moves the `ActiveListContent` at index "from", to the position at index "to".
*
* It is possible to move the `ActiveListContent` to the last place by making
* the "to" index the length of the `contents` array.
*
* Note: if the active `ActiveListContent` is moved it will stay active,
* meaning that the lastActivatedIndex will get updated.
*
* @param {number} from The "from" index which needs to be moved
* @param {number} to The location the `from` needs to move "to".
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
moveByIndex(from: number, to: number): void;
/**
* Moves the item, to the position at index "to".
*
* It is possible to move the `ActiveListContent` to the last place by making
* the "to" index the length of the `contents` array.
*
* Note: if the active `ActiveListContent` is moved it will stay active,
* meaning that the lastActivatedIndex will get updated.
*
* @param {T} item The item to move
* @param {number} to The location the `item` needs to move "to".
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
* @throws {ActiveListIndexOutOfBoundsError} index cannot be out of bounds
*
* @since 1.0.0
*/
move(item: T, to: number): void;
/**
* Moves the `ActiveListContent`, at the index, to the position of the
* item for which the predicate returns `true`.
*
* If no item matches the predicate nothing is moved.
*
* The position to where the `ActiveListContent` moves can be altered by
* providing a mode:
*
* 1. When the mode is 'at', the `ActiveListContent` is moved to the position
* where the predicate matches. This is the `default` mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is moved to after the
* position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is moved to before
* the position where the predicate matches.
*
* @param {number} index The index to move.
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will move the item to that position.
* @param {ActiveListPredicateOptions} options The options for the predicate, when no options are provided the mode will default to "at".
*
* @since 1.0.0
*/
moveByIndexByPredicate(index: number, predicate: ActiveListContentPredicate<T>, options?: ActiveListPredicateOptions): void;
/**
* Moves the `ActiveListContent` which matches the value of the item based
* on `===` equality. To the position of the item for which
* the predicate returns `true`.
*
* When multiple items match on `===` only the first matching item is moved.
*
* If no item matches the predicate nothing is moved.
*
* The position to where the `ActiveListContent` moves can be altered by
* providing a mode:
*
* 1. When the mode is 'at', the `ActiveListContent` is moved to the position
* where the predicate matches. This is the `default` mode.
*
* 2. When the mode is 'after', the `ActiveListContent` is moved to after the
* position where the predicate matches.
*
* 3. When the mode is 'before', the `ActiveListContent` is moved to before
* the position where the predicate matches.
*
* @param {T} item The item to move.
* @param {ActiveListContentPredicate<T>} predicate A predicate function, when the predicate returns `true` it will move the item to after that position.
* @param {ActiveListPredicateOptions} options The options for the predicate, when no options are provided the mode will default to "at".
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
*
* @since 1.0.0
*/
moveByPredicate(item: T, predicate: ActiveListContentPredicate<T>, options?: ActiveListPredicateOptions): void;
/**
* Gets the index for a given item.
*
* If the item does not exist in the content array it will
* throw an error.
*
* @param {T} item The item to get the index for.
* @returns {number} The index of the given item.
* @throws {ActiveListItemNotFoundError} item must be in the contents array based on === equality
*
* @since 1.0.0
*/
getIndex(item: T): number;
/**
* Returns the final index available in the contents array.
*
* @returns {number} The last index of the contents array.
*
* @since 1.0.0
*/
getLastIndex(): number;
_getBoundedNextIndex(index: number): number;
_getBoundedPreviousIndex(index: number): number;
_getUnboundedNextIndex(index: number): number;
_getUnboundedPreviousIndex(index: number): number;
/**
* Whether or not the contents is an empty array.
*
* @since 1.0.0
*/
isEmpty(): boolean;
private _getDirectionWhenMovingToIndex;
private _repairContents;
private _repairContent;
private _emptyLastActives;
private _emptyLastDeactivated;
private _becameEmpty;
private _setLastActives;
private _deactivateContent;
private _execPred;
_inform(event: ActiveListEvent<T>): void;
private _checkIndex;
private _modeToMod;
}
/**
* The configuration for the `createActiveListSubscriber` function.
*
* You should provide all methods for the events that you want to
* listen to, the ones you are not interested
*
* @since 1.5.0
*/
type CreateActiveListSubscriberConfig<T> = {
/**
* Optionally whether or not you want to show debug logging.
*
* When `debug` is enabled whenever an event method is not provided
* but the event is fired, a `console.warn` message is logged. This
* allows you to easier detect missing methods during development.
*
* Defaults to `false`, meaning nothing will be logged to the console.
*
* @since 1.5.0
*/
debug?: boolean;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onMoved?: (event: ActiveListMovedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `INSERTED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onInserted?: (event: ActiveListInsertedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `INITIALIZED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onInitialized?: (event: ActiveListInitializedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `COOLDOWN_STARTED` event is
* fired from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onCooldownStarted?: (event: ActiveListCooldownStartedEvent, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `COOLDOWN_ENDED` event is
* fired from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onCooldownEnded?: (event: ActiveListCooldownEndedEvent, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `AUTO_PLAY_STOPPED` event is
* fired from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onAutoPlayStopped?: (event: ActiveListAutoPlayStoppedEvent, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `AUTO_PLAY_PLAYING` event is
* fired from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onAutoPlayPlaying?: (event: ActiveListAutoPlayPlayingEvent, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `AUTO_PLAY_PAUSED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onAutoPlayPaused?: (event: ActiveListAutoPlayPausedEvent, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `ACTIVATED_MULTIPLE` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onActivatedMultiple?: (event: ActiveListActivatedMultipleEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `ACTIVATED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onActivated?: (event: ActiveListActivatedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `DEACTIVATED_MULTIPLE` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onDeactivatedMultiple?: (event: ActiveListDeactivatedMultipleEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `DEACTIVATED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onDeactivated?: (event: ActiveListDeactivatedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `SWAPPED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onSwapped?: (event: ActiveListSwappedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `REMOVED` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onRemoved?: (event: ActiveListRemovedEvent<T>, activeList: ActiveList<T>) => void;
/**
* Method which is called whenever an `REMOVED_MULTIPLE` event is fired
* from within the ActiveList.
*
* @param {ActiveListMovedEvent<T>} event The event that was fired.
* @param {ActiveList<T>} activeList The ActiveList the event was fired from
* @since 1.5.0
*/
onRemovedMultiple?: (event: ActiveListRemovedMultipleEvent<T>, activeList: ActiveList<T>) => void;
};
/**
* A function that creates an `ActiveListSubscriber` which you can
* provide to an `ActiveList`, which maps all `ActiveListEvent` to
* methods.
*
* You provide `createActiveListSubscriber` with an object with all
* the events you want to handle as methods and it will call the
* methods for you. This way your code will not have any switch or
* if-statement to distinguish between events.
*
* For example if you wanted to handle the `ACTIVATED` event, you
* provide a method called `onActivated` within the config. Whenever
* the `ACTIVATED` event occurs `onActivated` will be called.
*
* All methods are called with two parameters: the first is the
* `event` that occurred and the second the `ActiveList` the event
* occurred on.
*
* `createActiveListSubscriber` should only be used when using
* Vanilla JavaScript or TypeScript and not when using a reactive
* framework because reactive frameworks (such as React or Vue) will
* handle the DOM manipulation for you.
*
* If an event is fired that you did not provide a method for,
* an `SubscriberMissingMethodError` error will be thrown.
*
* @param {CreateActiveListSubscriberConfig<T>} config An object containing all methods you want to listen to.
* @returns {ActiveListSubscriber<T>} A subscriber function which can be passed to an ActiveList.
* @since 1.5.0
*
* @example
* A. Simple example
*
* The example below shows what the subscriber could look like for
* a carousel component which has one slide active at a time.
*
* ```js
* import {
* ActiveList,
* createActiveListSubscriber
* } from "uiloos/core";
*
* const carouselSubscriber = createActiveListSubscriber({
* onActivated() {
* // Activate the active slide
* activeList.lastDeactivated.classList.remove('active');
*
* // Deactivates the last activated slide
* activeList.lastActivated.classList.add('active');
* },
* });
*
* const activeList = new ActiveList({
* // The slide div elements are the contents of the ActiveList
* contents: Array.from(document.querySelectorAll('.carousel .slide'))
* }, carouselSubscriber)
* ```
*
* @example
* B. All methods implemented
*
* Here is a nice example to get started which includes stub
* implementations for all method:
*
* ```js
* const subscriber = createActiveListSubscriber({
* onInitialized(event, activeList) {
* console.log('onInitialized', event, activeList);
* },
*
* onActivated(event, activeList) {
* console.log('onActivated', event, activeList);
* },
*
* onDeactivated(event, activeList) {
* console.log('onDeactivated', event, activeList);
* },
*
* onInserted(event, activeList) {
* console.log('onInserted', event, activeList);
* },
*
* onRemoved(event, activeList) {
* console.log('onRemoved', event, activeList);
* },
*
* onSwapped(event, activeList) {
* console.log('onSwapped', event, activeList);
* },
*
* onMoved(event, activeList) {
* console.log('onMoved', event, activeList);
* },
*
* onCooldownStarted(event, activeList) {
* console.log('onCooldownStarted', event, activeList);
* },
*
* onCooldownEnded(event, activeList) {
* console.log('onCooldownEnded', event, activeList);
* },
*
* onAutoPlayStopped(event, activeList) {
* console.log('onAutoPlayStopped', event, activeList);
* },
*
* onAutoPlayPlaying(event, activeList) {
* console.log('onAutoPlayPlaying', event, activeList);
* },
*
* onAutoPlayPaused(event, activeList) {
* console.log('onAutoPlayPaused', event, activeList);
* },
*
* onActivatedMultiple(event, activeList) {
* console.log('onActivatedMultiple', event, activeList);
* },
*
* onDeactivatedMultiple(event, activeList) {
* console.log('onDeactivatedMultiple', event, activeList);
* },
*
* onRemovedMultiple(event, activeList) {
* console.log('onRemovedMultiple', event, activeList);
* },
* });
* ```
*/
declare function createActiveListSubscriber<T>(config: CreateActiveListSubscriberConfig<T>): ActiveListSubscriber<T>;
/**
* Error which is thrown whenever the ActiveList is in
* `ActiveListMaxActivationLimitBehavior` mode `error`, when the
* `maxActivationLimit` is exceeded.
*
* @since 1.0.0
*/
declare class ActiveListActivationLimitReachedError extends Error {
/**
* ActiveListActivationLimitReachedError constructor
*
* @since 1.0.0
*/
constructor();
}
/**
* Error which is thrown whenever the autoPlay duration is zero or
* less than zero.
*
* @since 1.0.0
*/
declare class ActiveListAutoPlayDurationError extends Error {
/**
* ActiveListAutoPlayDurationError constructor
*
* @since 1.0.0
*/
constructor();
}
/**
* Error which is thrown whenever the cooldown duration is zero or
* less than zero.
*
* WARNING: when this error is thrown because a
* `ActiveListCooldownDurationCallback` callback function returned a
* negative or zero duration, the activation / deactivation will still
* have occurred! This error is considered a developer error on your
* part and you should prevent it, as the ActiveList is now invalid.
*
* @since 1.0.0
*/
declare class ActiveListCooldownDurationError extends Error {
/**
* ActiveListCooldownDurationError constructor
*
* @since 1.0.0
*/
constructor();
}
/**
* Error which is thrown whenever an index is out of bounds.
*
* @since 1.0.0
*/
declare class ActiveListIndexOutOfBoundsError extends Error {
/**
* ActiveListIndexOutOfBoundsError constructor
*
* @since 1.0.0
*/
constructor(message: string);
}
/**
* Error which is thrown whenever an item cannot be found in the
* `ActiveList` contents array based on '===' equality.
*
* @since 1.0.0
*/
declare class ActiveListItemNotFoundError extends Error {
/**
* ActiveListItemNotFoundError constructor
*
* @since 1.0.0
*/
constructor();
}
/**
* A ViewChannel is a class which represents an area on the screen
* which contains visual elements (views) which are visible for a
* certain amount of time, or until when the user performs a certain
* action.
*
* The `ViewChannel` can be used to implement multiple types of
* components:
*
* 1. A notification side bar in which the user sees notifications
* of the application for a limited amount of time.
*
* 2. A flash message area which contain messages that tell the user
* an action was successful or not. They disappear after a certain
* amount of time, or when the user clicks on them.
*
* 3. A modal: a window / frame which appears when the user must
* perform a specific action. The modal closes when the user
* either performs the action, or when the user cancels the
* action.
*
* 4. A confirmation dialog: a small window / frame which appears
* asking the user if they are sure they want to perform a
* certain action.
*
* The general idea is that often areas on the screen exists which
* contain contain a specific type of visual element. These elements
* are often presented (triggered) from code at a distance from the
* area they are displayed in. This is why `ViewChannel` is considered
* a "channel", it is a way of transporting views.
*
* This way you can have one part of the code consume the channel,
* and use it to simply display the views, and many places (in code)
* where you put views on the channel.
*
* The idea of the ViewChannel is that you instantiate one for each
* type of View you want to support, for example: you might have a
* flash message and a modal ViewChannel instance. Then you use these
* instances to send "views" to the channel.
*
* The ViewChannel also has a concept of "priority". Sometimes one
* view has more priority than another view. The ViewChannel will
* make sure that the views are sorted by priority. The higher the
* priority the earlier in the `views` array the view is placed.
* This makes the ViewChannel a priority queue like data structure.
*
* @since 1.0.0
*/
declare class ViewChannel<T, R = void> implements Observable<ViewChannel<T, R>, ViewChannelEvent<T, R>> {
/**
* The `ViewChannelView` instances which the `ViewChannel` holds.
*
* @since 1.0.0
*/
readonly views: ViewChannelView<T, R>[];
private _history;
/**
* Contains the history of the changes in the views array.
*
* Tracks 8 types of changes:
*
* 1. INITIALIZED: fired when ViewChannel is initialized.
*
* 2. PRESENTED: fired when ViewChannel presented a ViewChannelView.
*
* 3. DISMISSED: fired when ViewChannel dismissed a ViewChannelView.
*
* 4. DISMISSED_ALL: fired when ViewChannel dismisses all ViewChannelView's.
*
* 5. AUTO_DISMISS_PLAYING: fired when ViewChannelView started to
* play after a stop or pause.
*
* 6. AUTO_DISMISS_PAUSED: fired when a ViewChannelView auto
* dismiss was paused.
*
* 7. AUTO_DISMISS_STOPPED: fired when a ViewChannelView auto
* dismiss was stopped.
*
* 8. DATA_CHANGED: fired when a ViewChannelView data is changed.
*
* Goes only as far back as configured in the `Config` property
* `keepHistoryFor`, to prevent an infinitely growing history.
* Note that by default no history is kept, as `keepHistoryFor`
* is zero by default.
*
* The last item in the `history` is the current active item. The
* further to the left the further in the past you go.
*
* This means that a history at index 0 is further in the past than
* an item at index 1.
*
* @since 1.0.0
*/
history: ViewChannelEvent<T, R>[];
private _observer;
/**
* Creates an ViewChannel based on the ViewChannelConfig config.
*
* You can also optionally provide an subscriber so you can get
* informed of the changes happening to the ViewChannel.
*
* @param {ViewChannelConfig<T>} config The initial configuration of the ViewChannel.
* @param {ViewChannelSubscriber<T> | undefined} subscriber An optional subscriber which responds to changes in the ViewChannel.
*
* @since 1.0.0
*/
constructor(config?: ViewChannelConfig, subscriber?: ViewChannelSubscriber<T, R>);
/**
* Initializes the ViewChannel based on the config provided.
*
* This effectively resets the ViewChannel when called, including
* the history.
*
* @param {ViewChannelConfig<T>} config The new configuration which will override the old one
*
* @since 1.0.0
*/
initialize(config: ViewChannelConfig): void;
/**
* Subscribe to changes of the ViewChannel. The function you
* provide will get called whenever changes occur in the
* ViewChannel.
*
* Returns an unsubscribe function which when called will unsubscribe
* from the ViewChannel.
*
* @param {ViewChannelSubscriber<T>} subscriber The subscriber which responds to changes in the ViewChannel.
* @returns {UnsubscribeFunction} A function which when called will unsubscribe from the ViewChannel.
*
* @since 1.0.0
*/
subscribe(subscriber: ViewChannelSubscriber<T, R>): UnsubscribeFunction;
/**
* Unsubscribe the subscriber so it no longer receives changes / updates
* of the state changes of the ViewChannel.
*
* @param {ViewChannelSubscriber<T>} subscriber The subscriber which you want to unsubscribe.
*
* @since 1.0.0
*/
unsubscribe(subscriber: ViewChannelSubscriber<T, R>): void;
/**
* Unsubscribes all subscribers at once, all subscribers will no
* longer receives changes / updates of the state changes of
* the ViewChannel.
*
* @since 1.5.0
*/
unsubscribeAll(): void;
/**
* Takes the provided `ViewChannelViewConfig` turns it into a
* `ViewChannelView`, and places the `ViewChannelView` into the
* `views` array based on the priority given.
*
* @param {ViewChannelConfig<T, R>} viewConfig The configuration for the view which is presented and returned.
* @returns {ViewChannelView<R>} The view which was presented
* @throws {ViewChannelAutoDismissDurationError} autoDismiss duration must be a positive number when defined
*
* @since 1.0.0
*/
present(viewConfig: ViewChannelViewConfig<T, R>): ViewChannelView<T, R>;
_doRemoveByIndex(index: number, result: R, reason: ViewChannelViewDismissedEventReason): void;
/**
* Dismisses the `ViewChannelView` which resides at the index of
* the `views` array, with the given result.
*
* The result (R) is the value with which the promise of the
* `ViewChannelView` will be resolved. For example when making a
* confirmation dialog, you could set the result to `"CONFIRM"` when
* the user presses the confirm button, and set the result to
* `"CANCEL"` when the user either presses the cancel button, or
* clicks outside of the dialog.
*
* If the index does not exist an error will be thrown.
*
* @param {number} index The index of the ViewChannelView to dismiss
* @param {R} result The value to resolve the promise of the ViewChannelView with.
* @throws {ViewChannelIndexOutOfBoundsError} index cannot be out of bounds
* @since 1.0.0
*/
dismissByIndex(index: number, result: R): void;
/**
* Dismisses the `ViewChannelView` with the given result.
*
* The result (R) is the value with which the promise of the
* `ViewChannelView` will be resolved. For example when making a
* confirmation dialog, you could set the result to `"CONFIRM"` when
* the user presses the confirm button, and set the result to
* `"CANCEL"` when the user either presses the cancel button, or
* clicks outside of the dialog.
*
* Note: if the `ViewChannelView` `isPresented` is `false` the
* removal is ignored.
*
* Note: if the `ViewChannelView` does not exist in the views array it
* will throw an error.
*
* @param {ViewChannelView<T, R>} view The ViewChannelView to dismiss
* @param {R} result The value to resolve the promise of the ViewChannelView with.
* @throws {ViewChannelNotFoundError} item must be in the views array based on === equality
* @since 1.0.0
*/
dismiss(view: ViewChannelView<T, R>, result: R): void;
/**
* Dismisses all `ViewChannelView`s within this `ViewChannel` with
* the given result.
*
* The result (R) is the value with which the promise of all the
* `ViewChannelView` will be resolved with . For example when making
* a notifications bar, you could set the result to `"CLEARED"` when
* the user presses the a "clear all" button.
*
* Note: when there are no ViewChannelViews displayed (in the views
* array) calling dismissAll will result in nothing happening.
*
* @param {R} result The value to resolve the promises of all the ViewChannelViews within the ViewChannel.
* @since 1.0.0
*/
dismissAll(result: R): void;
/**
* Changes the data of the given ViewChannelView, and informs
* the subscribers of the change.
*
* Note: if you provide the exact same `data` it will still set the
* `data` and inform the subscribers, even though nothing has
* actually changed.
*
* This way, when `data` is an object or an array, you can mutate
* the object / array directly, and pass in the same `data` object
* to the `changeData`, without having to create copies.
*
* @param {number} index The index of the ViewChannelView to change the data for.
* @param {T} data The new data for the ViewChannelView
* @throws {ViewChannelIndexOutOfBoundsError} index cannot be out of bounds
* @since 1.6.0
*/
changeDataByIndex(index: number, data: T): void;
/**
* Changes the data of the given ViewChannelView, and informs
* the subscribers of the change.
*
* Note: if you provide the exact same `data` it will still set the
* `data` and inform the subscribers, even though nothing has
* actually changed.
*
* This way, when `data` is an object or an array, you can mutate
* the object / array directly, and pass in the same `data` object
* to the `changeData`, without having to create copies.
*
* @param {ViewChannelView<T, R>} view The ViewChannelView to change the data for
* @param {T} data The new data for the ViewChannelView
* @throws {ViewChannelNotFoundError} item must be in the views array based on === equality
* @since 1.6.0
*/
changeData(view: ViewChannelView<T, R>, data: T): void;
private _getIndexForPriority;
private _getPriorityAtLevel;
private _repairIndexes;
private _clearViews;
_inform(event: ViewChannelEvent<T, R>): void;
}
/**
* Configures the initial state of the `ViewChannel`.
*
* @since 1.0.0
*/
type ViewChannelConfig = {
/**
* For how many items the `history` may contain in the `ViewChannel`.
*
* Defaults to `0` meaning that it will not track history.
*
* @since 1.0.0
*/
keepHistoryFor?: number;
};
/**
* Represents the configuration for AutoDismiss. AutoDismiss means
* that the ViewChannelView will remove itself after a duration.
*
* @since 1.0.0
*/
type ViewChannelViewAutoDismissConfig<R> = {
/**
* The amount of milliseconds the view should remain visible to
* the user. Once the duration has passed the view is removed
* from the `ViewChannel` automatically.
*
* @since 1.0.0
*/
duration: number;
/**
* The value (R) to resolve the promise of the `ViewChannelView`
* with. This allows you to distinguish between user events,
* such as clicking a cancel / save button or an auto dismissal.
*
* @since 1.0.0
*/
result: R;
};
/**
* AutoDismiss means that the ViewChannelView will dismiss itself
* after a duration.
*
* Contains wether or not the autoDismiss is playing via `isPlaying`
* and the current duration via `duration`.
*
* @since 1.0.0
*/
type ViewChannelViewAutoDismiss = {
/**
* Whether or not the ViewChannelView is playing. In other words
* whether or not the ViewChannelView is going to be autoDismissed
* after a duration.
*
* @since 1.0.0
*/
isPlaying: boolean;
/**
* The amount of milliseconds the view should remain visible to
* the user. Once the duration has passed the view is removed
* from the `ViewChannel` automatically.
*
* This duration is the duration for when the ViewChannelView
* started playing. It is not affected by calling pause, meaning
* that when the duration is set to 200ms and you pause after
* 100ms, the duration will still be 200ms.
*
* When calling `stop`, or when the ViewChannelView is dismissed
* the duration will be set to zero.
*
* @since 1.0.0
*/
duration: number;
};
/**
* Holds the configuration of a view which is placed in the
* `ViewChannel`. From this configuration the actual
* `ViewChannelView` is created.
*
* @since 1.0.0
*/
type ViewChannelViewConfig<T, R> = {
/**
* The data for the presented view, "data" can be be anything from
* an object, string, array etc etc. It is used to pass along data
* to the view you might need to display the view, such as the
* text for a flash message or confirmation dialog.
*
* By default the value is `undefined`.
*
* @since 1.0.0
*/
data: T;
/**
* Whether or not `autoDismiss` is enabled. When `autoDismiss` is
* enabled it will dismiss the view, based on the `duration`.
*
* Defaults to no autoDismiss, meaning it will stay visible forever,
* until it is dismissed.
*
* @since 1.0.0
*/
autoDismiss?: ViewChannelViewAutoDismissConfig<R>;
/**
* The priority the `ViewChannelView` will have within the
* `ViewChannel`. The lower the priority the closer it will be to
* the start of the `ViewChannel` views array.
*
* A priority is expressed as an array of numbers, each index in the
* array represents a "level" in the priority, the earlier levels
* (the lower indexes) have higher priority over the later levels
* (the higher indexes).
*
* If two priorities are compared, first the level at index zero
* is compared, if they are the same the index at the second level
* is compared, if the second level is also the same the third
* level is compared, and so on and so on until there are no more
* levels.
*
* A couple examples:
*
* 1. [0, 0, 0] has a higher priority than [1, 0, 0]
*
* 2. [1, 0, 0] has a higher priority than [2, 0, 0]
*
* 3. [0, 0, 0] has a higher priority than [0, 1, 0]
*
* 4. [0, 1, 0] has a higher priority than [0, 2, 0]
*
* 5. [0, 0, 0] has a higher priority than [0, 0, 1]
*
* 6. [0, 0, 1] has a higher priority than [0, 0, 2]
*
* 7. [0, 0, 1] has a higher priority than [1, 0, 0]
*
* If the priority arrays when compared differ in size, the missing
* items are considered zeros. So for example:
*
* 1. [0] has a higher priority than [1, 0, 0]
*
* 2. [0, 0] has a higher priority than [0, 1, 1]
*
* If two priorities match exactly the view is placed after the
* existing view with the same priority. This means that the
* order will be the order of insertion.
*
* Note: you can provide a number instead of an array instead, in
* this case an array is created with the provided number as the
* first value in the array. So providing `5` will be treated as
* `[5]`.
*
* Defaults to `[0]` when no priority is given, this makes it the
* highest priority.
*
* @since 1.0.0
*/
priority?: number | number[];
};
/**
* The subscriber which is informed of all state changes the
* ViewChannel goes through.
*
* @param {ViewChannel<T, R>} viewChannel The ViewChannel which had changes.
* @param {ViewChannelEvent<T>} event The event that occurred.
*
* @since 1.0.0
*/
type ViewChannelSubscriber<T, R> = (viewChannel: ViewChannel<T, R>, event: ViewChannelEvent<T, R>) => void;
/**
* Represents whether the `ViewChannelEvent` was presented, dismissed
* or initialized.
*
* @since 1.0.0
*/
type ViewChannelEventType = 'INITIALIZED' | 'PRESENTED' | 'DISMISSED' | 'DISMISSED_ALL' | 'AUTO_DISMISS_PLAYING' | 'AUTO_DISMISS_PAUSED' | 'AUTO_DISMISS_STOPPED' | 'DATA_CHANGED';
/**
* Represents an event which happened in the ViewChannel. Based
* on the `type` you can determine which event occurred.
*
* @since 1.0.0
*/
type ViewChannelBaseEvent = {
/**
* Which event occurred
*
* @since 1.0.0
*/
type: ViewChannelEventType;
/**
* The time the event occurred on as a Date object.
*
* @since 1.0.0
*/
time: Date;
};
/**
* Represents the initialization of the ViewChannel
*
* @since 1.0.0
*/
type ViewChannelInitializedEvent = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'INITIALIZED';
};
/**
* Represents an insertion of a ViewChannelView into the ViewChannel.
*
* @since 1.0.0
*/
type ViewChannelViewPresentedEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'PRESENTED';
/**
* The view which was inserted.
*
* Note: this was the view at the time of insertion, it might
* currently be removed, so be aware that this view might no
* longer be displayed in the `ViewChannel`.
*
* @since 1.0.0
*/
view: ViewChannelView<T, R>;
/**
* The index of the insertion.
*
* Note: this was the index at the time of the insertion, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* The reason for dismissal, this can either be because the
* `duration` of the view passed, in which case it is
* `DURATION_PASSED`, or because the user closed the View, then
* the reason will be `USER_INTERACTION`.
*
* @since 1.0.0
*/
type ViewChannelViewDismissedEventReason = 'AUTO_DISMISS' | 'USER_INTERACTION';
/**
* Represents a dismissal of an ViewChannelView of the ViewChannel.
*
* Note: when this event is fired the "AUTO_DISMISS_STOPPED" event
* will not be fired even when autoDismiss is playing. The reason for
* this is because on "DISMISSED" the entire view should be cleared.
*
* @since 1.0.0
*/
type ViewChannelViewDismissedEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'DISMISSED';
/**
* The reason for dismissal, this can either be because the
* `duration` of the view passed, in which case it is
* `DURATION_PASSED`, or because the user closed the View, then
* the reason will be `USER_INTERACTION`.
*
* @since 1.0.0
*/
reason: ViewChannelViewDismissedEventReason;
/**
* The view which was removed.
*
* @since 1.0.0
*/
view: ViewChannelView<T, R>;
/**
* The index of removed item.
*
* Note: this was the index at the time of the dismissal, it might
* no longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents an dismissal of all ViewChannelViews of the ViewChannel.
*
* @since 1.0.0
*/
type ViewChannelViewDismissedAllEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'DISMISSED_ALL';
/**
* The views which were removed.
*
* @since 1.0.0
*/
views: ViewChannelView<T, R>[];
/**
* The indexes of the dismissed views.
*
* Note: there are the indexes at the time of the dismissal, it might
* no longer be accurate.
*
* @since 1.0.0
*/
indexes: number[];
};
/**
* Represents a ViewChannelView autoDismiss being restarted again
* when it was stopped or paused.
*
* Note: this event is not fired when a ViewChannelView is presented
* initially, even though this does start the autoDismiss.
*
* @since 1.0.0
*/
type ViewChannelViewAutoDismissPlayingEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_DISMISS_PLAYING';
/**
* The view which had its auto dismiss started / played.
*
* @since 1.0.0
*/
view: ViewChannelView<T, R>;
/**
* The index of the view which had its auto dismiss started /
* played.
*
* Note: this was the index at the time of playing, it might no
* longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents a ViewChannelView autoDismiss being paused of the given
* ViewChannel.
*
* @since 1.0.0
*/
type ViewChannelViewAutoDismissPausedEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_DISMISS_PAUSED';
/**
* The view which had its auto dismiss paused.
*
* @since 1.0.0
*/
view: ViewChannelView<T, R>;
/**
* The index of the view which had its auto dismiss paused.
*
* Note: this was the index at the time of pausing, it might no
* longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents a ViewChannelView autoDismiss being stopped of the given
* ViewChannel.
*
* @since 1.0.0
*/
type ViewChannelViewAutoDismissStoppedEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.0.0
*/
type: 'AUTO_DISMISS_STOPPED';
/**
* The view which had its auto dismiss stopped.
*
* @since 1.0.0
*/
view: ViewChannelView<T, R>;
/**
* The index of the view which had its auto dismiss stopped.
*
* Note: this was the index at the time of stopping, it might no
* longer be accurate.
*
* @since 1.0.0
*/
index: number;
};
/**
* Represents a changing of the data of a ViewChannelView
*
* @since 1.6.0
*/
type ViewChannelViewDataChangedEvent<T, R> = ViewChannelBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'DATA_CHANGED';
/**
* The views which had its data changed
*
* @since 1.6.0
*/
view: ViewChannelView<T, R>;
/**
* The new data for the ViewChannelView
*
* @since 1.6.0
*/
data: T;
/**
* The index of the view which had its data changed
*
* Note: this was the index at the time of changing, it might no
* longer be accurate.
*
* @since 1.6.0
*/
index: number;
};
/**
* A ViewChannelEvent represents an event happened in the ViewChannel.
* For example the presented and dismissal of the ViewChannelView.
*
* @since 1.0.0
*/
type ViewChannelEvent<T, R> = ViewChannelInitializedEvent | ViewChannelViewPresentedEvent<T, R> | ViewChannelViewDismissedEvent<T, R> | ViewChannelViewDismissedAllEvent<T, R> | ViewChannelViewAutoDismissPlayingEvent<T, R> | ViewChannelViewAutoDismissPausedEvent<T, R> | ViewChannelViewAutoDismissStoppedEvent<T, R> | ViewChannelViewDataChangedEvent<T, R>;
/**
* A ViewChannelView is a class which represents visual elements which
* are visible for a certain amount of time, or until when the user
* performs a certain action.
*
* For example:
*
* 1. A notification, a piece of text telling the user some event
* happened within the application.
*
* 2. A flash message, a small temporary message telling the user
* an action was successful or failed. They disappear after a
* certain amount of time, or when the user clicks on them.
*
* 3. A modal: a window / frame which appears when the user must
* perform a specific action. The modal closes when the user
* either performs the action, or when the user cancels the
* action.
*
* 4. A confirmation dialog: a small window / frame which appears
* asking the user if they are sure they want to perform a
* certain action.
*
* A ViewChannelView is always tied to a ViewChannel in which it
* appears.
*
* You should never instantiate a `ViewChannelView` directly, instead
* you should call `present` on the `ViewChannel` and provide a
* `ViewChannelViewConfig` from which the `ViewChannelView` is
* instantiated.
*
* @since 1.0.0
*/
declare class ViewChannelView<T, R> {
/**
* Whether or not this ViewChannelView is presented.
*
* @since 1.0.0
*/
isPresented: boolean;
/**
* Reference to the ViewChannel is it a part of.
*
* @since 1.0.0
*/
viewChannel: ViewChannel<T, R>;
/**
* The index of the `ViewChannelView` which it has within the `contents`.
*
* @since 1.0.0
*/
index: number;
/**
* The data for the presented view, "data" can be be anything from
* an object, string, array etc etc. It is used to pass along data
* to the view you might need to display the view, such as the
* text for a flash message or confirmation dialog.
*
* By default the value is `undefined`.
*
* @since 1.0.0
*/
data: T;
/**
* The priority the `ViewChannelView` will have within the
* `ViewChannel` the lower the priority the closer it will be
* to the start of the `ViewChannel` content array.
*
* @since 1.0.0
*/
priority: number[];
/**
* Whether or not `autoDismiss` is enabled. When `autoDismiss` is
* enabled it will dismiss the view, based on the `duration`.
*
* Defaults to no autoDismiss, meaning it will stay visible forever,
* until it is dismissed.
*
* @since 1.0.0
*/
private _autoDismiss;
/**
* AutoDismiss means that the ViewChannelView will dismiss itself
* after a duration.
*
* Contains whether or not the autoDismiss is playing via `isPlaying`
* and the current duration via `duration`.
*
* @since 1.0.0
*/
readonly autoDismiss: ViewChannelViewAutoDismiss;
/**
* A promise which will be resolved with the result (R) when this
* ViewChannelView is dismissed. This promise will never be rejected
* only resolved.
*
* For example when making a confirmation dialog, you could set the
* result to `"CONFIRM"` when the user presses the confirm button,
* and set the result to `"CANCEL"` when the user either presses the
* cancel button, or clicks outside of the dialog.
*
* This allows you to `await` for the promise to be fulfilled, and
* take the result an perform actions based on that result.
*
* Note: this promise might never get resolved if "dismiss" is
* never called.
*
* @since 1.0.0
*/
result: Promise<R>;
_resolve: (result: R | PromiseLike<R>) => void;
/**
* Creates an ViewChannelView which belongs to the given ViewChannel.
*
* Note: you should never create instances of ViewChannelView yourself. You
* are supposed to let ViewChannel do this for you.
*
* @param {ViewChannel<T, R>} viewChannel The ViewChannel this ViewChannelView belongs to.
* @param {number} index The index of this ViewChannelView within the ViewChannel.
* @param {T} data The data of this ViewChannelView.
* @param {number} priority The priority this ViewChannelView has within the ViewChannel
* @param {ViewChannelViewAutoDismissConfig<R>} autoDismiss Whether or not this ViewChannelView is auto dismissed after a duration.
*
* @since 1.0.0
*/
constructor(viewChannel: ViewChannel<T, R>, index: number, data: T, priority: number[], autoDismissConfig?: ViewChannelViewAutoDismissConfig<R>);
/**
* Dismisses the `ViewChannelView` with the given result.
*
* The result (R) is the value with which the promise of the
* `ViewChannelView` will be resolved. For example when making a
* confirmation dialog, you could set the result to `"CONFIRM"` when
* the user presses the confirm button, and set the result to
* `"CANCEL"` when the user either presses the cancel button, or
* clicks outside of the dialog.
*
* Note: if the `ViewChannelView` property `isPresented` is `false`
* the removal is ignored.
*
* Note: if the `ViewChannelView` does not exist in the views array it
* will throw an error.
*
* @param {number} index The index of the ViewChannelView to dismiss
* @param {R} result The value to resolve the promise of the ViewChannelView with.
* @throws {ViewChannelNotFoundError} item must be in the views array based on === equality
* @since 1.0.0
*/
dismiss(result: R): void;
/**
* Will resume auto dismissing the ViewChannelView based on the
* active autoDismiss. When `autoDismiss` is not defined nothing
* will happen when calling play.
*
* Important: you only need to call `play` yourself when also using
* either `pause` or `stop`, as `play` is called automatically when
* a view is presented.
*
* @throws {ViewChannelAutoDismissDurationError} autoDismiss duration must be a positive number when defined
*
* @since 1.0.0
*/
play(): void;
/**
* When the ViewChannelView is playing it will pause the
* autoDismiss.
*
* When paused, the current autoDismiss duration is remember and
* resumed from that position, when `play` is called again.
*
* For example: when the duration is 1 second and the `pause` is
* called after 0.8 seconds, it will after `play` is called, take
* 0.2 seconds to dismiss this view.
*
* Note: if the autoDismiss is already paused calling `pause` again
* will do nothing, the time used for the remaining duration is
* based on the first pause.
*
* @since 1.0.0
*/
pause(): void;
/**
* When the ViewChannelView is playing it will stop the autoDismiss.
*
* By calling `play` again it is possible to restart the autoDismiss.
* However the duration will behave in this scenario as it if was
* reset.
*
* For example: when the duration is 1 second and the `stop` is
* called after 0.8 seconds, it will after `play` is called, take
* 1 second to dismiss this view.
*
* @since 1.0.0
*/
stop(): void;
/**
* Changes the data of this ViewChannelView, and informs the
* subscribers of the change.
*
* Note: if you provide the exact same `data` it will still set the
* `data` and inform the subscribers, even though nothing has
* actually changed.
*
* This way, when `data` is an object or an array, you can mutate
* the object / array directly, and pass in the same `data` object
* to the `changeData`, without having to create copies.
*
*
* @param {T} data The new data for this ViewChannelView
* @since 1.6.0
*/
changeData(data: T): void;
}
/**
* Error which is thrown whenever an index is out of bounds.
*
* @since 1.0.0
*/
declare class ViewChannelIndexOutOfBoundsError extends Error {
/**
* ViewChannelIndexOutOfBoundsError constructor
*
* @since 1.0.0
*/
constructor(method: string);
}
/**
* Error which is thrown whenever the `ViewChannelView` was not found
* inside of the `views` array of the `ViewChannel`.
*
* @since 1.0.0
*/
declare class ViewChannelViewNotFoundError extends Error {
/**
* ViewChannelViewNotFoundError constructor
*
* @since 1.0.0
*/
constructor(method: string);
}
/**
* Error which is thrown whenever the autoDismiss duration is zero or
* less than zero.
*
* @since 1.0.0
*/
declare class ViewChannelAutoDismissDurationError extends Error {
/**
* ViewChannelAutoDismissDurationError constructor
*
* @since 1.0.0
*/
constructor();
}
/**
* The configuration for the `createViewChannelSubscriber` function.
*
* You should provide all methods for the events that you want to
* listen to, the ones you are not interested
*
* @since 1.5.0
*/
type CreateViewChannelSubscriberConfig<T, R> = {
/**
* Optionally whether or not you want to show debug logging.
*
* When `debug` is enabled whenever an event method is not provided
* but the event is fired, a `console.warn` message is logged. This
* allows you to easier detect missing methods during development.
*
* Defaults to `false`, meaning nothing will be logged to the console.
*
* @since 1.5.0
*/
debug?: boolean;
/**
* Method which is called whenever an `INITIALIZED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelInitializedEvent} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onInitialized?: (event: ViewChannelInitializedEvent, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `PRESENTED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewPresentedEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onPresented?: (event: ViewChannelViewPresentedEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `DISMISSED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewDismissedEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onDismissed?: (event: ViewChannelViewDismissedEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `DISMISSED_ALL` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewDismissedAllEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onDismissedAll?: (event: ViewChannelViewDismissedAllEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `AUTO_DISMISS_PLAYING` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewAutoDismissPlayingEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onAutoDismissPlaying?: (event: ViewChannelViewAutoDismissPlayingEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `AUTO_DISMISS_PAUSED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewAutoDismissPausedEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onAutoDismissPaused?: (event: ViewChannelViewAutoDismissPausedEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `AUTO_DISMISS_STOPPED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewAutoDismissStoppedEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onAutoDismissStopped?: (event: ViewChannelViewAutoDismissStoppedEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
/**
* Method which is called whenever an `DATA_CHANGED` event is fired
* from within the ViewChannel.
*
* @param {ViewChannelViewDataChangedEvent<T, R>} event The event that was fired.
* @param {ViewChannel<T, R>} viewChannel The ViewChannel the event was fired from
* @since 1.5.0
*/
onDataChanged?: (event: ViewChannelViewDataChangedEvent<T, R>, viewChannel: ViewChannel<T, R>) => void;
};
/**
* A function that creates an `ViewChannelSubscriber` which you can
* provide to an `ViewChannel`, which maps all `ViewChannelEvent` to
* methods.
*
* You provide `createViewChannelSubscriber` with an object with all
* the events you want to handle as methods and it will call the
* methods for you. This way your code will not have any switch or
* if-statement to distinguish between events.
*
* For example if you wanted to handle the `DISMISSED` event, you
* provide a method called `onDismissed` within the config. Whenever
* the `DISMISSED` event occurs `onDismissed` will be called.
*
* All methods are called with two parameters: the first is the
* `event` that occurred and the second the `ViewChannel` the event
* occurred on.
*
* `createViewChannelSubscriber` should only be used when using
* Vanilla JavaScript or TypeScript and not when using a reactive
* framework because reactive frameworks (such as React or Vue) will
* handle the DOM manipulation for you.
*
* If an event is fired that you did not provide a method for,
* an `SubscriberMissingMethodError` error will be thrown.
*
* @param {CreateViewChannelSubscriberConfig<T>} config An object containing all methods you want to listen to.
* @returns {ViewChannelSubscriber<T>} A subscriber function which can be passed to an ViewChannel.
* @since 1.5.0
*
* @example
* A. Simple example
*
* The example below shows what the subscriber could look like for
* a modal channel which presents and dismisses modal windows.
*
* ```js
* import {
* ViewChannel,
* createViewChannelSubscriber
* } from 'uiloos/core';
*
* const subscriber = createViewChannelSubscriber({
* onPresented() {
* // Show the view here
* },
*
* onDismissed() {
* // Hide the view here
* },
* });
*
* export const modalChannel = new ViewChannel(
* {},
* subscriber
* );
* ```
*
* @example
* B. All methods implemented
*
* Here is a nice example to get started which includes stub
* implementations for all method:
*
* ```js
* const subscriber = createViewChannelSubscriber({
* onInitialized(event, viewChannel) {
* console.log('onInitialized', event, viewChannel);
* },
*
* onPresented(event, viewChannel) {
* console.log('onPresented', event, viewChannel);
* },
*
* onDismissed(event, viewChannel) {
* console.log('onDismissed', event, viewChannel);
* },
*
* onDismissedAll(event, viewChannel) {
* console.log('onDismissedAll', event, viewChannel);
* },
*
* onAutoDismissPlaying(event, viewChannel) {
* console.log('onAutoDismissPlaying', event, viewChannel);
* },
*
* onAutoDismissPaused(event, viewChannel) {
* console.log('onAutoDismissPaused', event, viewChannel);
* },
*
* onAutoDismissStopped(event, viewChannel) {
* console.log('onAutoDismissStopped', event, viewChannel);
* },
*
* onDataChanged(event, viewChannel) {
* console.log('onDataChanged', event, viewChannel);
* },
* });
* ```
*/
declare function createViewChannelSubscriber<T, R>(config: CreateViewChannelSubscriberConfig<T, R>): ViewChannelSubscriber<T, R>;
/**
* Represents a cursor within a Typewriter.
*
* Note: when `initialize` is called on a `Typewriter` all cursors
* are reset, and the previously attached cursors become detached,
* this means that the positions of the cursors are no longer
* accurate.
*
* You should never instantiate a `TypewriterCursor` directly. It
* should always be given to you by the `Typewriter`.
*
* @since 1.2.0
*/
declare class TypewriterCursor<T> {
private _typewriter;
/**
* The position of the cursor within the `Typewriter` text.
*
* If the cursor also has a `selection`, the `position` will always
* either on the `start` or `end` of the `selection`.
*
* Note: when `initialize` is called on a `Typewriter` all cursors
* become detached, and the position is no longer accurate.
*
* @since 1.2.0
*/
position: number;
/**
* The data for the cursor, "data" can be be anything from an
* object, string, array etc etc. The idea is that you can store
* any information here you need to render the cursor. For example
* you could set the data to an object, containing the "name" and
* "color" for that cursor.
*
* By default the value is `undefined`.
*
* @since 1.2.0
*/
data?: T;
/**
* The range of positions which this cursor has selected, or when
* it is `undefined` signifying no selection.
*
* The `position` of a cursors is always either on the `start` or
* `end` of the `selection`.
*
* Note: whenever the cursor stops selecting text the selection
* will be turned into `undefined`. So be careful not to keep any
* references to selections.
*
* @since 1.2.0
*/
selection?: TypewriterCursorSelection;
/**
* Whether or not this cursor is blinking.
*
* A cursor does not blink when the user is typing, only when the
* user has stopped typing then after a little while the cursor
* will start blinking again.
*
* The time until the cursors blinks again is the `Typewriter`'s
* `blinkAfter` property.
*
* @since 1.2.0
*/
isBlinking: boolean;
private _blinkTimeoutId;
/**
* Creates an TypewriterCursor which belongs to the given Typewriter.
*
* Note: you should never create instances of TypewriterCursor
* yourself. You are supposed to let the Typewriter do this for you.
*
* @param {Typewriter<T>} typewriter The Typewriter this TypewriterCursor belongs to.
* @param {number} position The position of this TypewriterCursor within the Typewriter text.
* @param {T} data The data for this TypewriterCursor
* @param {selection} selection The selection of the TypewriterCursor
*
* @since 1.2.0
*/
constructor(typewriter: Typewriter<T>, position: number, data?: T, selection?: TypewriterCursorSelection);
_startBlink(): void;
_clearBlink(): void;
}
/**
* Represents the selection of a cursor. A selection has a `start`
* and and `end` which are both numbers representing two positions
* within a `Typewriter`'s `text` property.
*
* The `start` will always lie before the `end`.
*
* The `position` of a cursors is always either on the `start` or
* `end` of the `selection`.
*
* @since 1.2.0
*/
type TypewriterCursorSelection = {
/**
* The start position of the selection.
*
* @since 1.2.0
*/
start: number;
/**
* The end position of the selection.
*
* @since 1.2.0
*/
end: number;
};
/**
* Configures the initial state of the `TypewriterCursor`.
*
* @since 1.2.0
*/
type TypewriterCursorConfig<T> = {
/**
* The position of the cursor within the `Typewriter` text.
*
* @since 1.2.0
*/
position: number;
/**
* The data for the cursor, "data" can be be anything from an
* object, string, array etc etc. The idea is that you can store
* any information here you need to render the cursor. For example
* you could set the data to an object, containing the "name" and
* "color" for that cursor.
*
* By default the value is `undefined`.
*
* @since 1.2.0
*/
data?: T;
/**
* The range of positions which this cursor has selected.
*
* Defaults to undefined, meaning no selection has been made.
*
* @since 1.2.0
*/
selection?: TypewriterCursorSelection;
};
/**
* Configures the initial state of the `Typewriter`.
*
* @since 1.2.0
*/
type TypewriterConfig<T> = {
/**
* The cursors the `Typewriter` is going to have.
*
* Defaults to one cursor at the end of the provided `text`
* with an empty name.
*
* @since 1.2.0
*/
cursors?: TypewriterCursorConfig<T>[];
/**
* The actions this `Typewriter` is set to enter. Each stroke
* represents a key press on the Typewriter. A stroke can add
* or remove characters, or move the cursor.
*
* Defaults to an empty array, meaning no actions will be made.
*
* @since 1.2.0
*/
actions?: TypewriterAction[];
/**
* The initial text the `Typewriter` starts with.
*
* Defaults to '' meaning that the Typewriter will not have an
* initial text.
*
* @since 1.2.0
*/
text?: string;
/**
* The time it takes until a cursor starts blinking again after
* the cursor was used.
*
* A cursor does not blink when it is used until after a certain
* time. So if you keep typing the cursor does not blink, until
* you stop typing for some "predefined amount" of time.
*
* The `blinkAfter` is what represents that 'predefined amount' of
* time, you can also say this is a debounce time.
*
* Note: when you set the `blinkAfter` to a number lower or equal to
* the `delay` of a `TypewriterAction`, it will negate the debounce.
* The effect is that all "CHANGED" events will have a "BLINKING"
* event. This might not "visually" affect your animation, but
* will make the `Typewriter` send extra events. If this happens it
* is technically as "misconfiguration" on your part, but the
* Typewriter will not throw any errors, since visually nothing
* bad happens.
*
* Defaults to after `250` milliseconds.
*
* @since 1.2.0
*/
blinkAfter?: number;
/**
* For how many items the `history` may contain in the `Typewriter`.
*
* Defaults to `0` meaning that it will not track history.
*
* @since 1.2.0
*/
keepHistoryFor?: number;
/**
* Whether or not the animation will immediately start playing.
*
* When `true` the animation will start playing immediately, when
* `false` the animation will start when `play()` is called.
*
* Note: the animation will only start playing when there are
* actions defined.
*
* Defaults to `true` meaning that the animation will play instantly.
*
* @since 1.2.0
*/
autoPlay?: boolean;
/**
* Whether or not this animation repeats and how often.
*
* There are three ways to define `repeat`.
*
* 1. When `repeat` is `false` or `1` it will never repeat the
* animation, the animation will run only once.
*
* 2. When `repeat` is `true` it will repeat the animation forever.
*
* 3. When `repeat` is a number it will repeat the animation
* for given number of times. If the number is 0 or a negative
* number is provided a error occurs.
*
* Defaults to `false` meaning that the animation will run once.
*
* @since 1.2.0
*/
repeat?: boolean | number;
/**
* The time in milliseconds the animation is paused in between
* repeats.
*
* Defaults to `0` milliseconds, meaning an almost instant repeat.
*
* @since 1.2.0
*/
repeatDelay?: number;
};
/**
* The subscriber which is informed of all state changes the
* Typewriter goes through.
*
* @param {Typewriter<T>} typewriter The Typewriter which had changes.
* @param {TypewriterEvent<T>} event The event that occurred.
*
* @since 1.2.0
*/
type TypewriterSubscriber<T> = (typewriter: Typewriter<T>, event: TypewriterEvent<T>) => void;
/**
* The type of action which occurred on the Typewriter, can either
* be a keyboard press or a mouse click.
*
* @since 1.2.0
*/
type TypewriterActionType = 'mouse' | 'keyboard';
/**
* Represents an action taken by the user can either be a key press,
* or a mouse click.
*
* @since 1.2.0
*/
type BaseTypewriterAction = {
/**
* The time in milliseconds after the previous action to wait until
* the action is performed.
*
* @since 1.2.0
*/
delay: number;
/**
* The type of action which will be taken.
*
* @since 1.2.0
*/
type: TypewriterActionType;
/**
* The cursor responsible for the action. Is the value
* is the index of the cursor in the Typewriters cursors array.
*
* @since 1.2.0
*/
cursor: number;
};
/**
* Represents the user entering text via the keyboard.
*
* @since 1.2.0
*/
type TypewriterActionKeyboard = BaseTypewriterAction & {
/**
* The type signifying it is a keyboard event.
*
* @since 1.2.0
*/
type: 'keyboard';
/**
* The string that was typed in, can either be a word or a single
* character or a special symbol representing a special key on the
* keyboard. There are six special keys:
*
* 1. A backspace represented by '⌫'. It will when nothing is
* selected delete the previous character, and when the cursor
* does have a selection, remove all characters in the selection.
*
* 2. 'Clear all' represented by '⎚', it clears the entire text.
*
* 3. The left arrow key represented by '←'. When nothing is
* selected is will move the cursor one position to the left.
* When a selection is made it will move the cursor to the start
* of the selection.
*
* 4. The right arrow key represented by '→'. When nothing is
* selected is will move the cursor one position to the right.
* When a selection is made it will move the cursor to the end of
* the selection.
*
* 5. Select left, represented by ⇧←', when repeated grows the
* selection.
*
* 6. Select right, represented by ⇧→', when repeated grows the
* selection.
*
* @since 1.2.0
*/
text: string;
};
/**
* Represents the user clicking somewhere in the text, moving
* the cursor to the position.
*
* @since 1.2.0
*/
type TypewriterActionMouse = BaseTypewriterAction & {
/**
* The type signifying it is a mouse event.
*
* @since 1.2.0
*/
type: 'mouse';
/**
* The position the mouse click moves the cursor to.
*
* @since 1.2.0
*/
position: number;
/**
* Optionally the selection the mouse made when clicking.
*
* Normally there are two ways a someone can create selections with
* a mouse: the first is clicking and dragging the mouse, the second
* is double clicking on a word.
*
* The idea is that the `selection` covers the second use-case:
* double clicking on a word. In the animation you will see the
* selection happen instantly.
*
* For first use-case: mouse click selection, it is better to use
* a keyboard event using `⇧←` or `⇧→`. This way you animate the
* selection growing.
*
* @since 1.2.0
*/
selection?: TypewriterCursorSelection;
};
/**
* The type of action which occurred on the Typewriter, can either
* be a keyboard press or a mouse click.
*
* @since 1.2.0
*/
type TypewriterAction = TypewriterActionMouse | TypewriterActionKeyboard;
/**
* Represents whether the `TypewriterEvent` has changed the text,
* is playing, stopped or paused.
*
* @since 1.2.0
*/
type TypewriterEventType = 'INITIALIZED' | 'CHANGED' | 'PLAYING' | 'PAUSED' | 'STOPPED' | 'FINISHED' | 'BLINKING' | 'REPEATING';
/**
* Represents an event which happened in the Typewriter. Based on the
* `type` you can determine which event occurred.
*
* @since 1.2.0
*/
type TypewriterBaseEvent = {
/**
* Which event occurred.
*
* @since 1.2.0
*/
type: TypewriterEventType;
/**
* The time the event occurred on as a Date object.
*
* @since 1.2.0
*/
time: Date;
};
/**
* When you loop over a Typewriter, using a `for-of` statement, you
* iterate over all positions in the Typewriters text. These positions
* are represented by a `TypewriterPosition`.
*
* `TypewriterPosition` contains the character for that position,
* the position (index) of that character, and all cursors currently
* on the position. Lastly it will contain all cursors that have
* selected the position.
*
* @since 1.2.0
*/
type TypewriterPosition<T> = {
/**
* The position of the 'character' in the text.
*
* IMPORTANT: in JavaScript some unicode characters have a length
* bigger than 1. For example "😃".length is 2 not 1.
*
* The Typewriter "normalizes" these so all unicode characters have
* a length of 1, by calling `Array.from(text)`.
*
* @since 1.2.0
*/
position: number;
/**
* The character which is at this position in the text.
*
* @since 1.2.0
*/
character: string;
/**
* The cursors that are on this position.
*
* @since 1.2.0
*/
cursors: TypewriterCursor<T>[];
/**
* The cursors that have selected this position.
*
* @since 1.2.0
*/
selected: TypewriterCursor<T>[];
};
/**
* Represents the initialization of the Typewriter
*
* @since 1.2.0
*/
type TypewriterInitializedEvent = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'INITIALIZED';
};
/**
* Represents a change in the text of the typewriter, the moving
* of a cursor, or a change in a cursors selection.
*
* This also means that the typewriter is no longer blinking at
* this time, until the `BLINKING` event is triggered again.
*
* @since 1.2.0
*/
type TypewriterChangedEvent<T> = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'CHANGED';
/**
* The action that happened which triggered this
* `TypewriterChangedEvent`.
*
* @since 1.2.0
*/
action: TypewriterAction;
/**
* The cursor which triggered the changed event
*
* @since 1.2.0
*/
cursor: TypewriterCursor<T>;
};
/**
* Represents that the Typewriter is currently playing.
*
* @since 1.2.0
*/
type TypewriterPlayingEvent = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'PLAYING';
};
/**
* Represents that the Typewriter is now paused.
*
* @since 1.2.0
*/
type TypewriterPausedEvent = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'PAUSED';
};
/**
* Represents that the Typewriter is was stopped.
*
* @since 1.2.0
*/
type TypewriterStoppedEvent = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'STOPPED';
};
/**
* Represents that the Typewriter has finished the animation.
*
* Important: finishing only refers to the fact that the 'text' will
* no longer change, but a cursor might start blinking after the
* animation is finished.
*
* Also when you call `play()` again the animation restarts,
* for both these reasons "FINISHED" is not necessarily the last
* event that will take place.
*
* @since 1.2.0
*/
type TypewriterFinishedEvent<T> = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'FINISHED';
/**
* The action that happened which triggered this
* `TypewriterFinishedEvent`.
*
* @since 1.2.0
*/
action: TypewriterAction;
/**
* The cursor which triggered the finished event.
*
* @since 1.2.0
*/
cursor: TypewriterCursor<T>;
};
/**
* Represents that a Typewriters cursor should now be blinking.
*
* @since 1.2.0
*/
type TypewriterBlinkingEvent<T> = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'BLINKING';
/**
* The cursor which has started blinking.
*
* @since 1.2.0
*/
cursor: TypewriterCursor<T>;
};
/**
* Represents that the Typewriters has started repeating the animation.
*
* @since 1.2.0
*/
type TypewriterRepeatingEvent<T> = TypewriterBaseEvent & {
/**
* Which type occurred
*
* @since 1.2.0
*/
type: 'REPEATING';
/**
* The cursor which triggered the repeating event.
*
* @since 1.2.0
*/
cursor: TypewriterCursor<T>;
};
/**
* A TypewriterEvent represents an event happened in the Typewriter.
* For example changing of the text or finishing the animation.
*
* @since 1.2.0
*/
type TypewriterEvent<T> = TypewriterInitializedEvent | TypewriterChangedEvent<T> | TypewriterPlayingEvent | TypewriterPausedEvent | TypewriterStoppedEvent | TypewriterFinishedEvent<T> | TypewriterBlinkingEvent<T> | TypewriterRepeatingEvent<T>;
/**
* A component to create versatile typewriter animations with.
*
* A typewriter animation is an type of text based animation in which
* a piece of text is typed one letter at a time at a certain interval.
*
* Has support for: multiple cursors, cursor selection, mouse movement,
* and keyboard movement.
*
* There are two main ways to create a typewriter animation:
*
* 1. By using the `typewriterFromSentences` function, it can create
* single cursor animations from sentences (strings). It does do
* by comparing and diffing the sentences and generating the
* required keystrokes to go from one sentence to another.
*
* 2. You can use the typewriter composer, a web based tool to
* generate the animations using your own keyboard.
*
* It can be found at:
*
* https://www.uiloos.dev/docs/typewriter/composer/
*
* @since 1.2.0
*/
declare class Typewriter<T = void> implements Observable<Typewriter<T>, TypewriterEvent<T>> {
/**
* The cursors the `Typewriter` has.
*
* @since 1.2.0
*/
readonly cursors: TypewriterCursor<T>[];
private readonly _originalCursors;
/**
* The actions which the `Typewriter` is going to perform.
*
* Basically the representation of the entire animation.
*
* The actions happen in a linear fashion, meaning the first item
* in the array is chronologically the first action, and the last
* item in the array the last action.
*
* @since 1.2.0
*/
readonly actions: TypewriterAction[];
/**
* The last action that was performed by the Typewriter.
*
* Note: `lastPerformedAction` is not affected by repeats.
*
* @since 1.2.0
*/
lastPerformedAction: TypewriterAction | null;
/**
* The current text of the `Typewriter` which it currently displays.
*
* For example if the actions are type in 'a' 3 times then a
* backspace. The `text` would be the following, after each of
* the 4 actions:
*
* 1. 'a'
* 2. 'aa'
* 3. 'aaa'
* 4. 'aa'
*
* @since 1.2.0
*/
text: string;
private _originalText;
/**
* The time it takes until a cursor starts blinking again after
* the cursor was used.
*
* A cursor does not blink when it is used until after a certain
* time. So if you keep typing the cursor does not blink, until
* you stop typing for some "predefined amount" of time.
*
* The `blinkAfter` is what represents that 'predefined amount' of
* time, you can also say this is a debounce time.
*
* Note: when you set the `blinkAfter` to a number lower or equal to
* the `delay` of a `TypewriterAction`, it will negate the debounce.
* The effect is that all "CHANGED" events will have a "BLINKING"
* event. This might not "visually" affect your animation, but
* will make the `Typewriter` send extra events. If this happens it
* is technically as "misconfiguration" on your part, but the
* Typewriter will not throw any errors, since visually nothing
* bad happens.
*
* Defaults to after `250` milliseconds.
*
* @since 1.2.0
*/
blinkAfter: number;
/**
* Whether or not the `Typewriter` is currently playing.
*
* @since 1.2.0
*/
isPlaying: boolean;
private _stopped;
/**
* Whether or not the `Typewriter` has finished playing the entire
* animation.
*
* Note: when `repeat` is configured as `true` the animation will
* never finish.
*
* Note: when the `Typewriter` is initialized the `isFinished`
* boolean will always be set to `false`, regardless of whether
* or not there are any actions.
*
* @since 1.2.0
*/
isFinished: boolean;
/**
* Whether or not this animation repeats and how often.
*
* There are three ways to define `repeat`.
*
* 1. When `repeat` is `false` or `1` it will never repeat the
* animation, the animation will run only once.
*
* 2. When `repeat` is `true` it will repeat the animation forever.
*
* 3. When `repeat` is a number it will repeat the animation
* for given number of times. If the number is 0 or a negative
* number is provided a error occurs.
*
* Defaults to `false` meaning that the animation will run once.
*
* @since 1.2.0
*/
repeat: boolean | number;
/**
* The time in milliseconds the animation is paused in between repeats.
*
* @since 1.2.0
*/
repeatDelay: number;
private _repeated;
/**
* Whether or not the Typewriter has been stopped at one point
* before during the current animation.
*
* The `hasBeenStoppedBefore` is tied to the lifecycle of an
* animation, and reflects if the current animation has been
* stopped before or not.
*
* Whenever a new animation starts the `hasBeenStoppedBefore`
* resets to `false`. An animation starts whenever `play()` is
* called, or through autoPlay, and lasts until there are no
* more actions, or `stop()` is called.
*
* Use case: say you are making an animation which has a stop button
* to stop the animation. Say you also have another feature: a pause
* whenever the user hovers over the typewriter animation. These two
* features would cause a conflict:
*
* Whenever the mouse over happens you call `play()`, which negates
* the `stop()`, causing the typewriter to play again.
*
* To fix this problem you should on the mouse over not call
* `play()` whenever `hasBeenStoppedBefore` is `true`.
*
* `hasBeenStoppedBefore` is tied to the animation cycle so a user
* clicks on the stop button, and then on the play button, the
* hover on pause will work again. The hover now works only because
* `hasBeenStoppedBefore` is now false.
*
* @since 1.2.0
*/
hasBeenStoppedBefore: boolean;
private _index;
private _animationTimeoutId;
private _tickStarted;
private _pauseStarted;
private _history;
/**
* Contains the history of the changes in the views array.
*
* Tracks 8 types of changes:
*
* 1. INITIALIZED: fired when Typewriter is initialized
*
* 2. CHANGED: fired when a change in the text of the typewriter
* occurred, when a cursor moves, or a when a cursors selection
* changes.
*
* 3. PLAYING: fired when play is called.
*
* 4. PAUSED: fired when pause is called.
*
* 5. STOPPED: fire when stop is called.
*
* 6. FINISHED: fired when the animation was finished. When the
* Typewriter is configured to repeat indefinitely the FINISHED
* event will never fire.
*
* 7. BLINKING: fired when one of the cursors started blinking.
*
* 8. REPEATING: fired when the animation starts repeating.
*
* Goes only as far back as configured in the `Config` property
* `keepHistoryFor`, to prevent an infinitely growing history.
* Note that by default no history is kept, as `keepHistoryFor`
* is zero by default.
*
* The last item in the `history` is the current active item. The
* further to the left the further in the past you go.
*
* This means that a history at index 0 is further in the past than
* an item at index 1.
*
* @since 1.2.0
*/
history: TypewriterEvent<T>[];
private _observer;
/**
* Creates an Typewriter based on the TypewriterConfig config.
*
* You can also optionally provide an subscriber so you can get
* informed of the changes happening to the Typewriter.
*
* @param {TypewriterConfig<T>} config The initial configuration of the Typewriter.
* @param {TypewriterSubscriber<T> | undefined} subscriber An optional subscriber which responds to changes in the Typewriter.
* @throws {TypewriterBlinkAfterError} blinkAfter duration must be a positive number
* @throws {TypewriterDelayError} delay duration must be a positive number
* @throws {TypewriterRepeatError} repeat must be a positive number
* @throws {TypewriterRepeatDelayError} repeatDelay must be a positive number or zero
* @throws {TypewriterRepeatDelayError} repeatDelay must be a positive number or zero
* @throws {TypewriterCursorOutOfBoundsError} cursor must be in bounds of text
* @throws {TypewriterCursorNotAtSelectionEdgeError} when cursor has a selection the cursor must be on edges of the selection
* @throws {TypewriterCursorSelectionOutOfBoundsError} the start and end of the selection must be in bounds of the text
* @throws {TypewriterCursorSelectionInvalidRangeError} the start of a selection must on or after the end of a selection
* @throws {TypewriterActionUnknownCursorError} actions must use cursors that exist
* @since 1.2.0
*/
constructor(config?: TypewriterConfig<T>, subscriber?: TypewriterSubscriber<T>);
/**
* Initializes the Typewriter based on the config provided.
*
* This effectively resets the Typewriter when called,
* including the history.
*
* @param {TypewriterConfig<T>} config The new configuration which will override the old one
* @throws {TypewriterBlinkAfterError} blinkAfter duration must be a positive number
* @throws {TypewriterDelayError} delay duration must be a positive number
* @throws {TypewriterRepeatError} repeat must be a positive number
* @throws {TypewriterRepeatDelayError} repeatDelay must be a positive number or zero
* @throws {TypewriterRepeatDelayError} repeatDelay must be a positive number or zero
* @throws {TypewriterCursorOutOfBoundsError} cursor must be in bounds of text
* @throws {TypewriterCursorNotAtSelectionEdgeError} when cursor has a selection the cursor must be on edges of the selection
* @throws {TypewriterCursorSelectionOutOfBoundsError} the start and end of the selection must be in bounds of the text
* @throws {TypewriterCursorSelectionInvalidRangeError} the start of a selection must on or after the end of a selection
* @throws {TypewriterActionUnknownCursorError} actions must use cursors that exist
* @since 1.2.0
*/
initialize(config: TypewriterConfig<T>): void;
/**
* Subscribe to changes of the Typewriter. The function you provide
* will get called whenever changes occur in the Typewriter.
*
* Returns an unsubscribe function which when called will
* unsubscribe from the Typewriter.
*
* @param {TypewriterSubscriber<T>} subscriber The subscriber which responds to changes in the Typewriter.
* @returns {UnsubscribeFunction} A function which when called will unsubscribe from the Typewriter.
*
* @since 1.2.0
*/
subscribe(subscriber: TypewriterSubscriber<T>): UnsubscribeFunction;
/**
* Unsubscribe the subscriber so it no longer receives changes / updates
* of the state changes of the Typewriter.
*
* @param {TypewriterSubscriber<T>} subscriber The subscriber which you want to unsubscribe.
*
* @since 1.2.0
*/
unsubscribe(subscriber: TypewriterSubscriber<T>): void;
/**
* Unsubscribes all subscribers at once, all subscribers will no
* longer receives changes / updates of the state changes of
* the Typewriter.
*
* @since 1.5.0
*/
unsubscribeAll(): void;
/**
* When the Typewriter is paused or stopped it will start the
* animation from that point. If the animation was finished calling
* `play()` will restart the animation.
*
* When there are is no more animations the Typewriter will stop
* automatically.
*
* Is called automatically when the Typewriter is instantiated
* and there are `actions` configured and `autoPlay` is `true`.
*
* Note: the animation will only start when there are one or more
* actions are defined.
*
* @since 1.2.0
*/
play(): void;
/**
* When the Typewriter is playing it will pause the animation, as
* if the person using the typewriter stops typing, this means that
* the cursors will start blinking again.
*
* Calling `play()` again will continue the animation.
*
* For example: when the `pause` of the current `TypewriterAction`
* is 1 second and the `pause` is called after 0.8 seconds, it will
* after `play` is called, take 0.2 seconds to go to the next
* action.
*
* @since 1.2.0
*/
pause(): void;
/**
* When the Typewriter is playing it will stop the animation.
*
* Calling `play()` again will restart the animation.
*
* Note: this will keep the text of the Typewriter as is, util
* `play()` is called again then the text will reset.
*
* Note: calling stop will also reset the number of repeats if
* `repeat` was set to a number.
*
* @since 1.2.0
*/
stop(): void;
private _init;
private _tick;
private _clearAnimation;
private _resetTandC;
private _overlap;
private _same;
private _actionLorR;
private _actionSLorR;
private _change;
_inform(event: TypewriterEvent<T>): void;
/**
* Iterates over the Typewriters text, and returns all positions in
* the text. For each position you will be given a object of type:
* `TypewriterPosition`, which contains all information about that
* position, such as which cursors are on that position, and the
* character on that position.
*
* When there is a cursor on the last position, you will receive an
* additional `TypewriterPosition` which has an empty string for
* the `character` field.
*
* IMPORTANT: in JavaScript some unicode characters have a length
* bigger than 1. For example `"😃".length` is `2` not `1`.
*
* The Typewriter "normalizes" these so all unicode characters have
* a length of 1, by calling `Array.from(text)`.
*
* This means that the `.length` of the `Typewriter.text` can differ
* from the number of iterations you get from iterating over the
* Typewriter!
*
* @returns {Iterator<TypewriterPosition<T>>} an iterator which yields TypewriterCursor and strings.
* @since 1.2.0
*/
[Symbol.iterator](): Iterator<TypewriterPosition<T>>;
}
/**
* The configuration for the `createTypewriterSubscriber` function.
*
* You should provide all methods for the events that you want to
* listen to, the ones you are not interested
*
* @since 1.5.0
*/
type CreateTypewriterSubscriberConfig<T> = {
/**
* Optionally whether or not you want to show debug logging.
*
* When `debug` is enabled whenever an event method is not provided
* but the event is fired, a `console.warn` message is logged. This
* allows you to easier detect missing methods during development.
*
* Defaults to `false`, meaning nothing will be logged to the console.
*
* @since 1.5.0
*/
debug?: boolean;
/**
* Method which is called whenever an `INITIALIZED` event is fired
* from within the Typewriter.
*
* @param {TypewriterInitializedEvent} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onInitialized?: (event: TypewriterInitializedEvent, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `CHANGED` event is fired
* from within the Typewriter.
*
* @param {TypewriterChangedEvent<T>} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onChanged?: (event: TypewriterChangedEvent<T>, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `PLAYING` event is fired
* from within the Typewriter.
*
* @param {TypewriterPlayingEvent} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onPlaying?: (event: TypewriterPlayingEvent, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `PAUSED` event is fired
* from within the Typewriter.
*
* @param {TypewriterPausedEvent} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onPaused?: (event: TypewriterPausedEvent, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `STOPPED` event is fired
* from within the Typewriter.
*
* @param {TypewriterStoppedEvent} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onStopped?: (event: TypewriterStoppedEvent, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `FINISHED` event is fired
* from within the Typewriter.
*
* @param {TypewriterFinishedEvent<T>} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onFinished?: (event: TypewriterFinishedEvent<T>, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `BLINKING` event is fired
* from within the Typewriter.
*
* @param {TypewriterBlinkingEvent<T>} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onBlinking?: (event: TypewriterBlinkingEvent<T>, typewriter: Typewriter<T>) => void;
/**
* Method which is called whenever an `REPEATING` event is fired
* from within the Typewriter.
*
* @param {TypewriterRepeatingEvent<T>} event The event that was fired.
* @param {Typewriter<T>} typewriter The Typewriter the event was fired from
* @since 1.5.0
*/
onRepeating?: (event: TypewriterRepeatingEvent<T>, typewriter: Typewriter<T>) => void;
};
/**
* A function that creates an `TypewriterSubscriber` which you can
* provide to an `Typewriter`, which maps all `TypewriterEvent` to
* methods.
*
* You provide `createTypewriterSubscriber` with an object with all
* the events you want to handle as methods and it will call the
* methods for you. This way your code will not have any switch or
* if-statement to distinguish between events.
*
* For example if you wanted to handle the `CHANGED` event, you
* provide a method called `onChanged` within the config. Whenever
* the `CHANGED` event occurs `onChanged` will be called.
*
* All methods are called with two parameters: the first is the
* `event` that occurred and the second the `Typewriter` the event
* occurred on.
*
* `createTypewriterSubscriber` should only be used when using
* Vanilla JavaScript or TypeScript and not when using a reactive
* framework because reactive frameworks (such as Angular or Svelte) will
* handle the DOM manipulation for you.
*
* If an event is fired that you did not provide a method for,
* an `SubscriberMissingMethodError` error will be thrown.
*
* @param {CreateTypewriterSubscriberConfig<T>} config An object containing all methods you want to listen to.
* @returns {TypewriterSubscriber<T>} A subscriber function which can be passed to an Typewriter.
* @since 1.5.0
*
* @example
* A. Simple example
*
* The example below shows what the subscriber could look like for
* a typewriter which only listens to the 'CHANGED' event:
*
* ```js
* import {
* Typewriter,
* createTypewriterSubscriber
* } from "uiloos/core";
*
* const subscriber = createTypewriterSubscriber({
* onChanged() {
* const typewriterEl = document.getElementById('typewriter');
* typewriterEl.textContent = typewriter.text;
* }
* });
*
* const typewriter = new Typewriter({
* repeat: true,
* repeatDelay: 1000,
* autoPlay: false,
* actions: [
* {
* type: 'keyboard',
* cursor: 0,
* text: 'H',
* delay: 150,
* },
* {
* type: 'keyboard',
* cursor: 0,
* text: 'e',
* delay: 132,
* },
* {
* type: 'keyboard',
* cursor: 0,
* text: 'y',
* delay: 84,
* },
* ],
* }, subscriber);
* ```
*
* @example
* B. All methods implemented
*
* Here is a nice example to get started which includes stub
* implementations for all method:
*
* ```js
* const subscriber = createTypewriterSubscriber({
* onInitialized(event, typewriter) {
* console.log('onInitialized', event, typewriter);
* },
*
* onChanged(event, typewriter) {
* console.log('onChanged', event, typewriter);
* },
*
* onPlaying(event, typewriter) {
* console.log('onPlaying', event, typewriter);
* },
*
* onPaused(event, typewriter) {
* console.log('onPaused', event, typewriter);
* },
*
* onStopped(event, typewriter) {
* console.log('onStopped', event, typewriter);
* },
*
* onFinished(event, typewriter) {
* console.log('onFinished', event, typewriter);
* },
*
* onBlinking(event, typewriter) {
* console.log('onBlinking', event, typewriter);
* },
*
* onRepeating(event, typewriter) {
* console.log('onRepeating', event, typewriter);
* }
* });
* ```
*/
declare function createTypewriterSubscriber<T>(config: CreateTypewriterSubscriberConfig<T>): TypewriterSubscriber<T>;
/**
* Error which is thrown whenever the configured blinkAfter is zero
* or less than zero.
*
* @since 1.2.0
*/
declare class TypewriterBlinkAfterError extends Error {
/**
* TypewriterBlinkAfterError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the configured delay for a
* TypewriterAction is zero or less than zero.
*
* @since 1.2.0
*/
declare class TypewriterDelayError extends Error {
/**
* TypewriterDelayError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the configured repeat is zero
* or less than zero.
*
* @since 1.2.0
*/
declare class TypewriterRepeatError extends Error {
/**
* TypewriterRepeatError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the configured repeatDelay is less
* than zero.
*
* @since 1.2.0
*/
declare class TypewriterRepeatDelayError extends Error {
/**
* TypewriterRepeatDelayError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the cursors are placed outside
* of the text of the Typewriter.
*
* @since 1.2.0
*/
declare class TypewriterCursorOutOfBoundsError extends Error {
/**
* TypewriterCursorOutOfBoundsError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the cursor has a selection but the
* cursor itself is not placed at either the start or end of the
* selection.
*
* @since 1.2.0
*/
declare class TypewriterCursorNotAtSelectionEdgeError extends Error {
/**
* TypewriterCursorNotAtSelectionEdgeError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever a cursors selection is
* initialized to be outside of the text of the Typewriter.
*
* @since 1.2.0
*/
declare class TypewriterCursorSelectionOutOfBoundsError extends Error {
/**
* TypewriterCursorSelectionOutOfBoundsError constructor
*
* @since 1.2.0
*/
constructor(name: 'start' | 'end');
}
/**
* Error which is thrown whenever a cursors selection has a start
* which does not lie before the end. This happens when the start
* of the selection has a higher or equal value to the end of
* the selection.
*
* @since 1.2.0
*/
declare class TypewriterCursorSelectionInvalidRangeError extends Error {
/**
* TypewriterCursorSelectionInvalidRangeError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* Error which is thrown whenever the Typewriter is configured with an
* action which uses a cursor which does not exist.
*
* @since 1.2.0
*/
declare class TypewriterActionUnknownCursorError extends Error {
/**
* TypewriterActionUnknownCursorError constructor
*
* @since 1.2.0
*/
constructor();
}
/**
* The configuration for the `typewriterFromSentences` function.
*
* @since 1.2.0
*/
type TypewriterFromSentencesConfig = {
/**
* The sentences the Typewriter should animate.
*
* @since 1.2.0
*/
sentences: string[];
/**
* The delay in between letters, meaning the speed at which to type.
*
* Defaults to 50ms
*
* @since 1.2.0
*/
delay?: number;
/**
* The delay in between sentences.
*
* Defaults to 2000ms
*
* @since 1.2.0
*/
sentenceDelay?: number;
/**
* The initial text the `Typewriter` starts with.
*
* Defaults to '' meaning that the Typewriter will not have an
* initial text.
*
* @since 1.2.0
*/
text?: string;
/**
* The time it takes until a cursor starts blinking again after
* the cursor was used.
*
* A cursor does not blink when it is used until after a certain
* time. So if you keep typing the cursor does not blink, until
* you stop typing for some "predefined amount" of time.
*
* The `blinkAfter` is what represents that 'predefined amount' of
* time, you can also say this is a debounce time.
*
* Note: when you set the `blinkAfter` to a number lower or equal to
* the `delay` of a `TypewriterAction`, it will negate the debounce.
* The effect is that all "CHANGED" events will have a "BLINKING"
* event. This might not "visually" affect your animation, but
* will make the `Typewriter` send extra events. If this happens it
* is technically as "misconfiguration" on your part, but the
* Typewriter will not throw any errors, since visually nothing
* bad happens.
*
* Defaults to after `250` milliseconds.
*
* @since 1.2.0
*/
blinkAfter?: number;
/**
* For how many items the `history` may contain in the `Typewriter`.
*
* Defaults to `0` meaning that it will not track history.
*
* @since 1.2.0
*/
keepHistoryFor?: number;
/**
* Whether or not the animation will immediately start playing.
*
* When `true` the animation will start playing immediately, when
* `false` the animation will start when `play()` is called.
*
* Note: the animation will only start playing when there are
* actions defined.
*
* Defaults to `true` meaning that the animation will play instantly.
*
* @since 1.2.0
*/
autoPlay?: boolean;
/**
* Whether or not this animation repeats and how often.
*
* There are three ways to define `repeat`.
*
* 1. When `repeat` is `false` or `1` it will never repeat the
* animation, the animation will run only once.
*
* 2. When `repeat` is `true` it will repeat the animation forever.
*
* 3. When `repeat` is a number it will repeat the animation
* for given number of times. If the number is 0 or a negative
* number is provided a error occurs.
*
* Defaults to `false` meaning that the animation will run once.
*
* @since 1.2.0
*/
repeat?: boolean | number;
/**
* The time in milliseconds the animation is paused in between
* repeats.
*
* Defaults to `0` milliseconds, meaning an almost instant repeat.
*
* @since 1.2.0
*/
repeatDelay?: number;
};
/**
* Creates a Typewriter which will type in the provided sentences
* using a single cursor.
*
* Intelligently moves from one sentence to another, only removing
* parts of the sentence if necessary.
*
* For example when providing the following sentences array:
* `['I love dogs', 'I love cats]`.
*
* The Typewriter will type the sentence "I love dogs" first. Then it
* will do four backspaces to end up with "I love". Finally it will
* type in "dogs".
*
* @param {TypewriterFromSentencesConfig} config The configuration of the Typewriter.
* @param {TypewriterSubscriber | undefined} subscriber An optional subscriber which responds to changes in the Typewriter.
* @returns {Typewriter<void>} a configured typewriter
* @since 1.2.0
*/
declare function typewriterFromSentences(config: TypewriterFromSentencesConfig, subscriber?: TypewriterSubscriber<void>): Typewriter<void>;
/**
* A `DateGalleryEvent` represents things like birthdays, meetings
* doctors appointments etc etc inside of a `DateGallery`.
*
* A `DateGalleryEvent` keeps track of the events start and end date.
*
* Custom pieces of information can be found in the `data` property,
* which can be anything you'd like, from an object to a string. For
* example you could store the title and description of the event
* there.
*
* The `overlapsWith` property will tell you all the events that this
* event currently overlaps with.
*
* You should never instantiate a `DateGalleryEvent` directly, instead
* you should call `addEvent` on the `DateGallery` and provide a
* `DateGalleryEventConfig` from which the `DateGalleryEvent` is
* instantiated.
*
* Alternatively you can also provide events via the
* `DateGalleryConfig`s `events` property.
*
* @since 1.6.0
*/
declare class DateGalleryEvent<T> {
/**
* Reference to the DateGallery is it a part of.
*
* @since 1.6.0
*/
dateGallery: DateGallery<T>;
/**
* The data for this event, "data" can be be anything from an
* object, string, array etc etc. It is used to pass along data
* to the event you might need to display the event, such as the
* text for the event.
*
* By default the value is `undefined`.
*
* @since 1.6.0
*/
data: T;
/**
* The start date of the event, includes the time.
*
* The `startDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the event runs on
* monday, tuesday and wednesday.
*
* @since 1.6.0
*/
startDate: Date;
/**
* The end date of the event, includes the time.
*
* The `endDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the event runs on
* monday, tuesday and wednesday.
*
* @since 1.6.0
*/
endDate: Date;
/**
* The other events in the `DateGallery` this event overlaps with.
*
* @since 1.6.0
*/
readonly overlappingEvents: DateGalleryEvent<T>[];
/**
* Whether or not this `DateGalleryEvent` overlaps with other
* events.
*
* @since 1.6.0
*/
isOverlapping: boolean;
/**
* Whether or not this events spans over multiple days.
*
* Is `false` when the `startDate` and `endDate` are on the same
* day, is `true` when the `startDate` and `endDate` are
* on different days.
*
* @since 1.6.0
*/
spansMultipleDays: boolean;
/**
* Creates an DateGalleryEvent which belongs to the given DateGallery.
*
* Note: you should never create instances of DateGalleryEvent
* yourself. You are supposed to let DateGallery do this for you.
*
* @param {DateGallery<T>} dateGallery The DateGallery this DateGalleryEvent belongs to.
* @param {T} index The index of this DateGalleryEvent within the DateGallery.
* @param {T} data The data of this DateGalleryEvent
*
* @since 1.6.0
*/
constructor(dateGallery: DateGallery<T>, data: T, startDate: Date, endDate: Date);
_recalculate(): void;
/**
* Removes this `DateGalleryEvent` from the `DateGallery` it belongs
* to.
*
* @param {DateGalleryEvent<T>} event The event you want to remove.
* @since 1.6.0
*/
remove(): void;
/**
* Moves this `DateGalleryEvent` chronologically, or in other words
* it changes the events start and end time to the given range.
*
* @param {DateGalleryRange} range The new start and end times of the event.
* @throws {DateGalleryEventInvalidRangeError} an events start date must lie before on on the end date.
* @throws {DateGalleryEventNotFoundError} the provided event must be part of the DateGallery.
* @since 1.6.0
*/
move(range: DateGalleryRange): void;
/**
* Changes the data of this `DateGalleryEvent`, and informs the
* subscribers of the change.
*
* Note: if you provide the exact same `data` it will still set the
* `data` and inform the subscribers, even though nothing has
* actually changed.
*
* This way, when `data` is an object or an array, you can mutate
* the object / array directly, and pass in the same `data` object
* to the `changeData`, without having to create copies.
*
* @param {T} data The new data for this DateGalleryEvent
* @since 1.6.0
*/
changeData(data: T): void;
}
/**
* Represents a date inside of one of the `DateGallery` frames.
*
* A `DateGalleryDate` knows whether it has been selected or not,
* whether it is a padded date, which `DateGalleryEvent` lie on
* the date etc etc.
*
* You should never instantiate a `DateGalleryDate` directly instead
* the `DateGallery` should provide them to you.
*
* @since 1.6.0
*/
declare class DateGalleryDate<T> {
/**
* Reference to the DateGallery is it a part of.
*
* @since 1.6.0
*/
dateGallery: DateGallery<T>;
/**
* The date associated with this `DateGalleryDate`, the time of
* this date is midnight on 0 offset UTC.
*
* @since 1.6.0
*/
date: Date;
/**
* The events that occur on this date.
*
* @since 1.6.0
*/
events: DateGalleryEvent<T>[];
/**
* Whether or not this `DateGalleryDate` is padding for the date
* frame. Visually these are often "greyed out" dates on month
* calendars, used to pad out the calendar for a nicer visual.
*
* Padding can only occur in one of the month modes.
*
* @since 1.6.0
*/
isPadding: boolean;
/**
* Whether or not this `DateGalleryDate` is selected.
*
* @since 1.6.0
*/
isSelected: boolean;
/**
* Whether or not this `DateGalleryDate` can be selected, is
* determined by calling the `canSelect` from the `DateGalleryConfig`
* at the time of the `DateGalleryDate` construction.
*
* @since 1.6.0
*/
canBeSelected: boolean;
/**
* Whether or not this `DateGalleryDate` represents a date which is
* today.
*
* @since 1.6.0
*/
isToday: boolean;
/**
* Whether or not this `DateGalleryDate` has any events.
*
* @since 1.6.0
*/
hasEvents: boolean;
/**
* Whether or not this `DateGalleryDate` has events that
* overlap with each other. In other words whether this day has
* events on the same times as each other.
*
* @since 1.6.0
*/
hasEventsWithOverlap: boolean;
/**
* Creates an DateGalleryDate which belongs to the given DateGallery.
*
* Note: you should never create instances of DateGalleryDate yourself. You
* are supposed to let DateGallery do this for you.
*
* @param {DateGallery<T>} dateGallery The DateGallery this DateGalleryDate belongs to.
* @param {Date} Date The date this `DateGalleryDate` represents.
* @param {DateGalleryEvent<T>[]} events The events that lie on this date.
* @param {boolean} isPadding Whether or not this DateGalleryDate is padding.
* @param {boolean} isSelected Whether or not this DateGalleryDate is selected.
* @since 1.6.0
*/
constructor(dateGallery: DateGallery<T>, date: Date, events: DateGalleryEvent<T>[], isPadding: boolean, isSelected: boolean);
/**
* Selects the date represented by this DateGalleryDate.
*
* @since 1.6.0
*/
select(): void;
/**
* Deselects the date represented by this DateGalleryDate.
*
* @since 1.6.0
*/
deselect(): void;
/**
* Toggles the date selection the date represented by this
* DateGalleryDate.
*
* If the date is selected it becomes deselected, if the date is
* deselected it becomes selected.
*
* @since 1.6.0
*/
toggle(): void;
}
/**
* Configures the initial state of the `DateGallery`.
*
* @since 1.6.0
*/
type DateGalleryConfig<T> = {
/**
* The mode the `DateGallery` is going to start on.
*
* Can be one of these modes:
*
* 1. 'day': a single day per frame.
*
* 2. 'week': seven days per frame, starting at the configured
* `firstDayOfWeek`.
*
* 3. 'month': all days within a calendar month per frame. A frame
* will then always start on the first of the month, and end on
* the last day of the month.
*
* 4. 'month-six-weeks': all days within a calendar month, but padded
* out to six weeks. Meaning that there are always 42 days in the
* frame. Useful for when you want you calendar / datepicker to be
* visually stable height wise.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 5. 'month-pad-to-week': all days within a calendar month, but
* padded out to the closest `firstDayOfWeek`.
*
* For example given that firstDayOfWeek is set to 0 / Sunday:
* if the first day of the month starts on Wednesday it will pad to
* the previous Sunday of the previous month.
*
* If the month ends on a friday, it will add the next saturday
* of the next month.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 6. 'year': a frame will contain all 365 days (or 366 when a leap year)
* within a year.
*
* Defaults to 'month-six-weeks'.
*
* @since 1.6.0
*/
mode?: DateGalleryMode;
/**
* Whether the `DateGallery` is in UTC mode or not.
*
* When the `DateGallery` is in UTC mode all dates that are given
* to you via the `DateGallery` through a `DateGalleryDate` are
* given in UTC.
*
* Also all operations on `Date` objects within the `DateGallery`
* or done via the `UTC` variants.
*
* UTC is useful for when you want all datepickers / calendars
* to look the same al around the world, which is not very often.
*
* Defaults to `false` meaning the browsers local offset is used.
*
* @since 1.6.0
*/
isUTC?: boolean;
/**
* A date that will act as the initial anchor date for the date
* frame.
*
* It will set the date frame to the "closest" date given the
* `mode`.
*
* Can either be a `Date` instance, or a `string` which can be
* passed to the `Date` constructor to make a date.
*
* For example if you use "2023-06-23" as the `initialDate` and the
* `mode` is set to 'year', the date frame will be the year 2023. If
* for the same `initialDate` the `mode` was set to `month-six-weeks`
* the month of `June` would have been the date frame instead.
*
* Defaults to the current date.
*
* @since 1.6.0
*/
initialDate?: Date | string;
/**
* What is to be considered the first day of the week, is used in
* modes such as 'week' to determine on which day of the week to
* start the frame.
*
* The `firstDayOfWeek` is a number between 0 and 6, were each
* number represents a day of the week:
*
* 0 = Sunday
* 1 = Monday
* 2 = Tuesday
* 3 = Wednesday
* 4 = Thursday
* 5 = Friday
* 6 = Saturday
*
* Defaults to '0' which is 'sunday'.
*
* @since 1.6.0
*/
firstDayOfWeek?: DateGalleryDayOfWeek;
/**
* For how many items the `history` may contain in the `DateGallery`.
*
* Defaults to `0` meaning that it will not track history.
*
* @since 1.6.0
*/
keepHistoryFor?: number;
/**
* The initial events the `DateGallery` will start out with. Events
* in the sense of events on a calendar: birthdays / dentist
* appointments etc.
*
* Defaults to `[]` for no events.
*
* @since 1.6.0
*/
events?: DateGalleryEventConfig<T>[];
/**
* How many dates can be selected at the same time.
*
* When the value of `limit` is `false` there is no limit to the
* number of active items.
*
* Defaults to `false`.
*
* @since 1.6.0
*/
maxSelectionLimit?: number | false;
/**
* How the limit is enforced. In other words what the behavior
* should be when the limit is surpassed.
*
* The modes are strings which can be the following values:
*
* 1. 'circular': the first date that was selected which will be
* removed so the last selected date can be added without
* violating the limit. This basically means that the first one in
* is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `DateGallerySelectionLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an date is selected and the limit
* is reached. The date is simply not selected, but no error is
* thrown.
*
* Defaults to 'circular'.
*
* @since 1.6.0
*/
maxSelectionLimitBehavior?: DateGalleryMaxSelectionLimitBehavior;
/**
* The dates that are considered selected when the `DateGallery` is
* initialized.
*
* The dates you provide will be converted to midnight.
*
* Are passed through the `canSelect` predicate any date that
* cannot be selected is filtered out of the array.
*
* Defaults to `[]` for no events.
*
* @since 1.6.0
*/
selectedDates?: (Date | string)[];
/**
* An optional callback predicate that is given a `DateGalleryDate`
* and must return a boolean, when the boolean is `true` that date
* can be selected, when `false` the date cannot be selected.
*
* Useful for when wanting to implement a min and max date, or
* prevent the weekends from being selected, or dates that have
* events.
*
* This callback is called when:
*
* 1. A `DateGalleryDate` is constructed for a frame to determine
* the value of the `DateGalleryDate`s `canBeSelected` boolean.
* This happens when the frame changes, or when an event is
* added / removed, or a date is selected / deselected.
*
* 2. Whenever a date is about to get selected, to check if that
* date can be selected. Happens for example when `selectDate`
* or `selectRange` etc etc is called.
*
* IMPORTANT: try to make the predicate pure to make it easier to
* reason about. Otherwise you might get a scenario in which a
* `DateGalleryDate`s `canBeSelected` is `true`, but can still be
* selected via `selectDate`.
*
* Defaults to `undefined` meaning all dates an be selected.
*
* @since 1.6.0
*/
canSelect?: DateGalleryCanSelectPredicate<T>;
/**
* The number of frames that are visible at a time for the end user.
*
* This is useful for when you want to show a multiple frames at
* the same time. For example if you an entire years worth of
* `month-single-month` calendars you'd set the `numberOfFrames`
* to `12`.
*
* Defaults to `1` for a single frame at a time.
*
* @since 1.6.0
*/
numberOfFrames?: number;
};
/**
* Represents a callback predicate which is given a `DateGalleryDate`
* and needs to return a boolean, when `true` is returned the
* `DateGalleryDate` can be selected, when `false` is returned
* the `DateGalleryDate` cannot be selected.
*
* @param {DateGalleryDate<T>} dateGalleryDate The DateGalleryDate for which this predicate will determine if it can be selected.
* @returns {boolean} Whether or not the DateGalleryDate can be selected.
*
* @since 1.6.0
*/
type DateGalleryCanSelectPredicate<T> = (dateGalleryDate: DateGalleryDate<T>) => boolean;
/**
* The configuration object for the `DateGallery`'s `changeConfig`
* method.
*
* All properties are optional and can be used in any combination.
* Meaning you can change the `mode` and `numberOfFrames`, or the
* `mode` and `initialDate` or just the `numberOfFrames`.
*
* @since 1.6.0
*/
type DateGalleryChangeConfig = {
/**
* The mode the `DateGallery` is going to start on.
*
* Can be one of these modes:
*
* 1. 'day': a single day per frame.
*
* 2. 'week': seven days per frame, starting at the configured
* `firstDayOfWeek`.
*
* 3. 'month': all days within a calendar month per frame. A frame
* will then always start on the first of the month, and end on
* the last day of the month.
*
* 4. 'month-six-weeks': all days within a calendar month, but padded
* out to six weeks. Meaning that there are always 42 days in the
* frame. Useful for when you want you calendar / datepicker to be
* visually stable height wise.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 5. 'month-pad-to-week': all days within a calendar month, but
* padded out to the closest `firstDayOfWeek`.
*
* For example given that firstDayOfWeek is set to 0 / Sunday:
* if the first day of the month starts on Wednesday it will pad to
* the previous Sunday of the previous month.
*
* If the month ends on a friday, it will add the next saturday
* of the next month.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 6. 'year': a frame will contain all 365 days (or 366 when a leap year)
* within a year.
*
* Defaults to `undefined` meaning the mode is not changed.
*
* @since 1.6.0
*/
mode?: DateGalleryMode;
/**
* An optional date that will act as the initial anchor date
* for the date frame.
*
* When no `date` is provided the DateGallery will move to the
* `anchorDate` of the `firstFrame`.
*
* Some examples:
*
* 1. When going from `day` to `year` the year will be set to the
* year of the `anchorDate`.
*
* 2. When moving from `year` to `month` it will go to January
* 1st of the year of the `anchorDate`
*
* 3. When moving from `week` to `month` it will go to the first
* of the month from the start of the week.
*
* Can either be a `Date` instance, or a `string` which can be
* passed to the `Date` constructor to make a date.
*
* For example if you use "2023-06-23" as the `initialDate` and the
* `mode` is set to 'year', the date frame will be the year 2023. If
* for the same `initialDate` the `mode` was set to `month-six-weeks`
* the month of `June` would have been the date frame instead.
*
* Defaults `undefined` meaning the current anchor date is used.
*
* @since 1.6.0
*/
initialDate?: Date | string;
/**
* The number of frames that are visible at a time for the end user.
*
* This is useful for when you want to show a multiple frames at
* the same time. For example if you an entire years worth of
* `month-single-month` calendars you'd set the `numberOfFrames`
* to `12`.
*
* Defaults to `undefined` meaning the current `numberOfFrames`
* is used
*
* @since 1.6.0
*/
numberOfFrames?: number;
};
/**
* Represents a frame within the `DateGallery` it is an object
* containing all dates and events that belong on the frame.
*
* @since 1.6.0
*/
type DateGalleryFrame<T> = {
/**
* All dates that belong to this frame.
*
* @since 1.6.0
*/
dates: DateGalleryDate<T>[];
/**
* All events that occur within this frame
*
* @since 1.6.0
*/
events: DateGalleryEvent<T>[];
/**
* The date this frame is anchored to.
*
* For month based modes it is the first date of the month, for
* `'week'` it is the first day of the week, for `'year'` it is
* the first day of the year.
*
* Basically the same as the first date in the `dates` array which
* is not a padded date.
*
* @since 1.6.0
*/
anchorDate: Date;
};
/**
* Holds the configuration of an event which is placed in the
* `DateGallery`. From this configuration the actual
* `DateGalleryEvent` is created.
*
* @since 1.6.0
*/
type DateGalleryEventConfig<T> = {
/**
* The data for this event, "data" can be be anything from an
* object, string, array etc etc. It is used to pass along data
* to the event you might need to display the event, such as the
* text for the event.
*
* By default the value is `undefined`.
*
* @since 1.6.0
*/
data: T;
/**
* The start date of the event, includes the time.
*
* The `startDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the event runs on
* monday, tuesday and wednesday.
*
* Can either be a Date instance, or a string which can be passed
* to the `Date` constructor to make a date.
*
* @since 1.6.0
*/
startDate: Date | string;
/**
* The end date of the event, includes the time.
*
* The `endDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the event runs on
* monday, tuesday and wednesday.
*
* Can either be a Date instance, or a string which can be passed
* to the `Date` constructor to make a date.
*
* @since 1.6.0
*/
endDate: Date | string;
};
/**
* Represents all valid values that can be given to the
* `DateGalleryConfig`s `firstDayOfWeek` property.
*
* @since 1.6.0
*/
type DateGalleryDayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6;
/**
* An array of strings containing all predefined modes of the
* `DateGallery`.
*
* @see DateGalleryMode
* @since 1.6.0
*/
declare const DATE_GALLERY_MODES: readonly ["day", "week", "month", "month-six-weeks", "month-pad-to-week", "year"];
/**
* All predefined modes of the `DateGallery`:
*
* 1. 'day': a single day per frame.
*
* 2. 'week': seven days per frame, starting at the configured
* `firstDayOfWeek`.
*
* 3. 'month': all days within a calendar month per frame. A frame
* will then always start on the first of the month, and end on
* the last day of the month.
*
* 4. 'month-six-weeks': all days within a calendar month, but padded
* out to six weeks. Meaning that there are always 42 days in the
* frame. Useful for when you want you calendar / datepicker to be
* visually stable height wise.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 5. 'month-pad-to-week': all days within a calendar month, but padded
* out to the closest `firstDayOfWeek`.
*
* For example given that firstDayOfWeek is set to 0 / Sunday:
* if the first day of the month starts on Wednesday it will pad to
* the previous Sunday of the previous month.
*
* If the month ends on a friday, it will add the next saturday
* of the next month.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 6. 'year': a frame will contain all 365 days (or 366 when a leap year)
* within a year.
*
* @since 1.6.0
*/
type DateGalleryMode = (typeof DATE_GALLERY_MODES)[number];
/**
* Describes all the behaviors for when the selection limit of the
* DateGallery is surpassed.
*
* 1. 'circular': the first date that was selected which will be
* removed so the last selected date can be added without
* violating the limit. This basically means that the first one in
* is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `DateGallerySelectionLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an date is selected and the limit
* is reached. The date is simply not selected, but no error is
* thrown.
*
* @since 1.6.0
*/
type DateGalleryMaxSelectionLimitBehavior = 'circular' | 'ignore' | 'error';
/**
* Represents a range of dates, from a start date to and end date.
*
* @since 1.6.0
*/
type DateGalleryRange = {
/**
* The start date of the range, includes the time.
*
* The `startDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the range runs on
* monday, tuesday and wednesday.
*
* Can either be a Date instance, or a string which can be passed
* to the `Date` constructor to make a date.
*
* @since 1.6.0
*/
startDate: Date | string;
/**
* The end date of the range, includes the time.
*
* The `endDate` is inclusive: meaning if the event has a `startDate`
* which is monday and an `endDate` on wednesday, the range runs on
* monday, tuesday and wednesday.
*
* Can either be a Date instance, or a string which can be passed
* to the `Date` constructor to make a date.
*
* @since 1.6.0
*/
endDate: Date | string;
};
/**
* The subscriber which is informed of all state changes the
* DateGallery goes through.
*
* @param {DateGallery<T>} DateGallery The DateGallery which had changes.
* @param {DateGallerySubscriberEvent<T>} event The event that occurred.
*
* @since 1.6.0
*/
type DateGallerySubscriber<T> = (DateGallery: DateGallery<T>, event: DateGallerySubscriberEvent<T>) => void;
/**
* Represents whether the `DateGallery` changed frames, added an
* event, selected a date etc etc.
*
* @since 1.6.0
*/
type DateGallerySubscriberEventType = 'INITIALIZED' | 'FRAME_CHANGED' | 'CONFIG_CHANGED' | 'DATE_SELECTED' | 'DATE_SELECTED_MULTIPLE' | 'DATE_DESELECTED' | 'DATE_DESELECTED_MULTIPLE' | 'EVENT_ADDED' | 'EVENT_REMOVED' | 'EVENT_MOVED' | 'EVENT_DATA_CHANGED';
/**
* Represents an event which happened in the DateGallery. Based
* on the `type` you can determine which event occurred.
*
* @since 1.6.0
*/
type DateGalleryBaseEvent = {
/**
* Which event occurred
*
* @since 1.6.0
*/
type: DateGallerySubscriberEventType;
/**
* The time the event occurred on as a Date object.
*
* @since 1.6.0
*/
time: Date;
};
/**
* Represents the initialization of the DateGallery
*
* @since 1.6.0
*/
type DateGalleryInitializedEvent = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'INITIALIZED';
};
/**
* Represents the fact that the date frame has how changed, this
* occurs when the frame is moved to the next or previous frame.
*
* @since 1.6.0
*/
type DateGalleryFrameChangedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'FRAME_CHANGED';
/**
* The newly visible frames.
*
* @since 1.6.0
*/
frames: DateGalleryFrame<T>[];
};
/**
* Represents the fact that a date has been selected.
*
* @since 1.6.0
*/
type DateGalleryDateSelectedEvent = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'DATE_SELECTED';
/**
* The date that was selected.
*
* @since 1.6.0
*/
date: Date;
/**
* The date which was deselected, will be `null` when no value
* was deselected as part of the selection.
*
* A deselection will only happen as part of a selection when
* `maxSelectionLimit` is set to a `number` and
* `maxSelectionLimitBehavior` is set to `circular`.
*
* @since 1.6.0
*/
deselectedDate: Date | null;
};
/**
* Represents the fact that multiple dates have been selected.
*
* @since 1.6.0
*/
type DateGalleryDateSelectedMultipleEvent = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'DATE_SELECTED_MULTIPLE';
/**
* The dates that were selected.
*
* @since 1.6.0
*/
dates: Date[];
/**
* The dates which were deselected.
*
* A deselection will only happen as part of a selection when
* `maxSelectionLimit` is set to a `number` and
* `maxSelectionLimitBehavior` is set to `circular`.
*
* @since 1.6.0
*/
deselectedDates: Date[];
};
/**
* Represents the fact that a date has been deselected
*
* @since 1.6.0
*/
type DateGalleryDateDeselectedEvent = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'DATE_DESELECTED';
/**
* The date that was deselected.
*
* @since 1.6.0
*/
date: Date;
};
/**
* Represents the fact that multiple dates have been deselected
*
* @since 1.6.0
*/
type DateGalleryDateDeselectedMultipleEvent = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'DATE_DESELECTED_MULTIPLE';
/**
* The dates that were deselected.
*
* @since 1.6.0
*/
dates: Date[];
};
/**
* Represents the fact that an event has been added to the
* DateGallery.
*
* @since 1.6.0
*/
type DateGalleryEventAddedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'EVENT_ADDED';
/**
* The event that was added
*
* @since 1.6.0
*/
event: DateGalleryEvent<T>;
};
/**
* Represents the fact that an event has been removed from the
* DateGallery.
*
* @since 1.6.0
*/
type DateGalleryEventRemovedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'EVENT_REMOVED';
/**
* The event that was removed
*
* @since 1.6.0
*/
event: DateGalleryEvent<T>;
};
/**
* Represents the fact that an event was moved, it got either
* a new start or end date.
*
* @since 1.6.0
*/
type DateGalleryEventMovedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'EVENT_MOVED';
/**
* The event that was moved
*
* @since 1.6.0
*/
event: DateGalleryEvent<T>;
};
/**
* Represents a changing of the data of an event.
*
* @since 1.6.0
*/
type DateGalleryEventDataChangedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'EVENT_DATA_CHANGED';
/**
* The event which had its data changed
*
* @since 1.6.0
*/
event: DateGalleryEvent<T>;
/**
* The new data for the DateGalleryEvent
*
* @since 1.6.0
*/
data: T;
};
/**
* Represents a changing in the DateGallery's `mode`, `initialDate`,
* or `numberOfFrames`
*
* @since 1.6.0
*/
type DateGalleryConfigChangedEvent<T> = DateGalleryBaseEvent & {
/**
* Which type occurred
*
* @since 1.6.0
*/
type: 'CONFIG_CHANGED';
/**
* The current `mode` the DateGallery now has.
*
* @since 1.6.0
*/
mode: DateGalleryMode;
/**
* The current anchor date the firstFrame of the DateGallery now has.
*
* @since 1.6.0
*/
anchorDate: Date;
/**
* The current `numberOfFrames` the DateGallery now has.
*
* @since 1.6.0
*/
numberOfFrames: number;
/**
* The newly visible frames.
*
* @since 1.6.0
*/
frames: DateGalleryFrame<T>[];
};
/**
* A DateGallerySubscriberEvent represents an event happened in the DateGallery.
* For example the insertion, removal, or activation of a
* DateGalleryContent<T>.
*
* @since 1.6.0
*/
type DateGallerySubscriberEvent<T> = DateGalleryInitializedEvent | DateGalleryFrameChangedEvent<T> | DateGalleryDateSelectedEvent | DateGalleryDateDeselectedEvent | DateGalleryEventAddedEvent<T> | DateGalleryEventRemovedEvent<T> | DateGalleryDateSelectedMultipleEvent | DateGalleryDateDeselectedMultipleEvent | DateGalleryEventMovedEvent<T> | DateGalleryEventDataChangedEvent<T> | DateGalleryConfigChangedEvent<T>;
/**
* A DateGallery is a class that represents a frame of dates, a frame
* of dates is a sequence of chronologically sequential dates of a
* certain length.
*
* The idea is that whenever you are creating components that use
* sequences of dates, so for example: date pickers, range selectors,
* or calendars, that you can use the DateGallery class to handle the
* dates for you.
*
* The DateGallery comes in various modes:
*
* 1. 'day': a single day per frame.
*
* 2. 'week': seven days per frame, starting at the configured
* `firstDayOfWeek`.
*
* 3. 'month': all days within a calendar month per frame. A frame
* will then always start on the first of the month, and end on
* the last day of the month.
*
* 4. 'month-six-weeks': all days within a calendar month, but padded
* out to six weeks. Meaning that there are always 42 days in the
* frame. Useful for when you want you calendar / datepicker to be
* visually stable height wise.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 5. 'month-pad-to-week': all days within a calendar month, but
* padded out to the closest `firstDayOfWeek`.
*
* For example given that firstDayOfWeek is set to 0 / Sunday:
* if the first day of the month starts on Wednesday it will pad to
* the previous Sunday of the previous month.
*
* If the month ends on a friday, it will add the next saturday
* of the next month.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 6. 'year': a frame will contain all 365 days (or 366 when a leap year)
* within a year.
*
* The frame part of a DateGallery is what is visually displayed to a
* user, when making a monthly based calendar you are making a whole
* year available but only show one month at a time. The month that
* you show is a "frames", the dates that are visually displayed.
*
* The DateGallery provides methods for navigating through frames,
* for example you can go to the next / previous frame.
*
* You can ask the DateGallery for multiple frames at the same time
* by stetting the `numberOfFrames` property, this allows you to for
* example display three months at the same time, or five years at
* the same time.
*
* DateGallery also supports having events such as birthdays or
* holidays. For each "frame" that the DateGallery provides it will
* also tell you which events fall on that frame. Events also know
* if they are overlapping with other events.
*
* Finally the DateGallery can help you select dates. It will also
* put this information in each frame so you know which dates are
* selected.
*
* @since 1.6.0
*/
declare class DateGallery<T> implements Observable<DateGallery<T>, DateGallerySubscriberEvent<T>> {
/**
* Whether or not to inform subscribers of changes / record history.
* Used in the `initialize` to temporarily stop subscriptions running
* the initial activation, and altering the history.
*/
private _isInitializing;
/**
* Whether the `DateGallery` is in UTC mode or not.
*
* When the `DateGallery` is in UTC mode all dates that are given
* to you via the `DateGallery` through a `DateGalleryDate` are
* given in UTC.
*
* Also all operations on `Date` objects within the `DateGallery`
* or done via the `UTC` variants.
*
* UTC is useful for when you want all datepickers / calendars
* to look the same al around the world, which is not very often.
*
* @since 1.60
*/
isUTC: boolean;
/**
* The frames of dates that are currently visible to the user.
*
* @since 1.6.0
*/
readonly frames: DateGalleryFrame<T>[];
/**
* The first frame of dates that is visible to the user.
*
* Is a shortcut to the first frame in the `frames` property.
*
* If `numberOfFrames` is 1 this will be the only visible frame.
*
* @since 1.6.0
*/
firstFrame: DateGalleryFrame<T>;
/**
* The number of frames that are visible at a time for the end user.
*
* This is useful for when you want to show a multiple frames at
* the same time. For example if you an entire years worth of
* `month-single-month` calendars you'd set the `numberOfFrames`
* to `12`.
*
* @since 1.6.0
*/
numberOfFrames: number;
/**
* How many dates can be selected at the same time.
*
* When the value of `limit` is `false` there is no limit to the
* number of active items.
*
* Defaults to `false`.
*
* @since 1.6.0
*/
maxSelectionLimit: number | false;
/**
* How the limit is enforced. In other words what the behavior
* should be when the limit is surpassed.
*
* The modes are strings which can be the following values:
*
* 1. 'circular': the first date that was selected which will be
* removed so the last selected date can be added without
* violating the limit. This basically means that the first one in
* is the first one out.
*
* 2. 'error': An error is thrown whenever the limit is surpassed,
* the error is called the `DateGallerySelectionLimitReachedError`.
*
* 3. 'ignore': Nothing happens when an date is selected and the limit
* is reached. The date is simply not selected, but no error is
* thrown.
*
* Defaults to 'circular'.
*
* @since 1.6.0
*/
maxSelectionLimitBehavior: DateGalleryMaxSelectionLimitBehavior;
/**
* All dates which are currently considered selected.
*
* All dates will have their time set at midnight.
*
* The array is not sorted, the items will appear in insertion
* order.
*
* @since 1.6.0
*/
readonly selectedDates: Date[];
_canSelect: DateGalleryCanSelectPredicate<T> | undefined;
/**
* All events, such as birthdays, meetings etc that are associated
* with this `DateGallery`.
*
* Is sorted from old to new, events that appear earlier in the
* array are earlier than events that appear later in the array.
*
* @since 1.6.0
*/
readonly events: DateGalleryEvent<T>[];
/**
* The mode the `DateGallery` is on.
*
* 1. 'day': a single day per frame.
*
* 2. 'week': seven days per frame, starting at the configured
* `firstDayOfWeek`.
*
* 3. 'month': all days within a calendar month per frame. A frame
* will then always start on the first of the month, and end on
* the last day of the month.
*
* 4. 'month-six-weeks': all days within a calendar month, but padded
* out to six weeks. Meaning that there are always 42 days in the
* frame. Useful for when you want you calendar / datepicker to be
* visually stable height wise.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 5. 'month-pad-to-week': all days within a calendar month, but
* padded out to the closest `firstDayOfWeek`.
*
* For example given that firstDayOfWeek is set to 0 / Sunday:
* if the first day of the month starts on Wednesday it will pad to
* the previous Sunday of the previous month.
*
* If the month ends on a friday, it will add the next saturday
* of the next month.
*
* Starts the days on the configured `firstDayOfWeek`.
*
* 6. 'year': a frame will contain all 365 days (or 366 when a leap year)
* within a year.
*
* @since 1.6.0
*/
mode: DateGalleryMode;
/**
* What is to be considered the first day of the week, is used in
* modes such as 'week' to determine on which day of the week to
* start the frame.
*
* The `firstDayOfWeek` is a number between 0 and 6, were each
* number represents a day of the week:
*
* 0 = Sunday
* 1 = Monday
* 2 = Tuesday
* 3 = Wednesday
* 4 = Thursday
* 5 = Friday
* 6 = Saturday
*
* @since 1.6.0
*/
firstDayOfWeek: DateGalleryDayOfWeek;
private _anchorDate;
private _history;
/**
* Contains the history of the changes in the contents array.
*
* Tracks 11 types of changes:
*
* 1. INITIALIZED: fired when DateGallery is initialized.
*
* 2. FRAME_CHANGED: fired when the frames changes.
*
* 3. CONFIG_CHANGED: fires when the config is changed.
*
* 4. DATE_SELECTED: fires when a date is selected.
*
* 5. DATE_SELECTED_MULTIPLE: fires when multiple dates are selected.
*
* 6. DATE_DESELECTED: fires when a date is deselected.
*
* 7. DATE_DESELECTED_MULTIPLE: fires when multiple dates are
* deselected.
*
* 8. EVENT_ADDED: fires when an event such as a birthday /
* appointment is added.
*
* 9. EVENT_REMOVED: fires when an event such as a birthday /
* appointment is removed.
*
* 10. EVENT_MOVED': fires when an event such as a birthday /
* appointment is moved.
*
* 11. EVENT_MOVED': fires when an event such as a birthday /
* appointment has its data changed.
*
* Goes only as far back as configured in the `Config` property
* `keepHistoryFor`, to prevent an infinitely growing history.
* Note that by default no history is kept, as `keepHistoryFor`
* is zero by default.
*
* The last item in the `history` is the current active item. The
* further to the left the further in the past you go.
*
* This means that a history at index 0 is further in the past than
* an item at index 1.
*
* @since 1.6.0
*/
readonly history: DateGallerySubscriberEvent<T>[];
private _observer;
/**
* Creates an DateGallery based on the DateGalleryConfig config.
*
* You can also optionally provide an subscriber so you can get
* informed of the changes happening to the DateGallery.
*
* @param {DateGalleryConfig<T>} config The initial configuration of the DateGallery.
* @param {DateGallerySubscriber<T> | undefined} subscriber An optional subscriber which responds to changes in the DateGallery.
* @throws {DateGalleryEventInvalidRangeError} an events start date must lie before on on the end date.
* @throws {DateGalleryFirstDayOfWeekError} the configured day of the week must be between 0 and 6 inclusive.
* @throws {DateGalleryInvalidDateError} dates provided must be valid dates
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGallerySelectionLimitReachedError} thrown when maxSelectionLimit is exceeded, and maxSelectionLimitBehavior is "error".
* @since 1.6.0
*/
constructor(config?: DateGalleryConfig<T>, subscriber?: DateGallerySubscriber<T>);
/**
* Subscribe to changes of the DateGallery. The function you
* provide will get called whenever changes occur in the
* DateGallery.
*
* Returns an unsubscribe function which when called will unsubscribe
* from the DateGallery.
*
* @param {DateGallerySubscriber<T>} subscriber The subscriber which responds to changes in the DateGallery.
* @returns {UnsubscribeFunction} A function which when called will unsubscribe from the DateGallery.
*
* @since 1.6.0
*/
subscribe(subscriber: DateGallerySubscriber<T>): UnsubscribeFunction;
/**
* Unsubscribe the subscriber so it no longer receives changes / updates
* of the state changes of the DateGallery.
*
* @param {DateGallerySubscriber<T>} subscriber The subscriber which you want to unsubscribe.
*
* @since 1.6.0
*/
unsubscribe(subscriber: DateGallerySubscriber<T>): void;
/**
* Unsubscribes all subscribers at once, all subscribers will no
* longer receives changes / updates of the state changes of
* the DateGallery.
*
* @since 1.6.0
*/
unsubscribeAll(): void;
/**
* Initializes the DateGallery based on the config provided. This can
* effectively reset the DateGallery when called, including the
* frames and history.
*
* @param {DateGalleryConfig<T>} config The new configuration which will override the old one
* @throws {DateGalleryEventInvalidRangeError} an events start date must lie before on on the end date.
* @throws {DateGalleryFirstDayOfWeekError} the configured day of the week must be between 0 and 6 inclusive.
* @throws {DateGalleryInvalidDateError} dates provided must be valid dates
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGalleryNumberOfFramesError} numberOfFrames must be a positive number when defined
* @throws {DateGallerySelectionLimitReachedError} thrown when maxSelectionLimit is exceeded, and maxSelectionLimitBehavior is "error".
* @since 1.6.0
*/
initialize(config: DateGalleryConfig<T>): void;
private _doInitialize;
/**
* Changes the configuration of the DateGallery, allowing you
* to change the `mode` the initial date and `numberOfFrames`.
*
* All properties are optional and can be used in any combination.
* Meaning you can change the `mode` and `numberOfFrames`, or the
* `mode` and `initialDate` or just the `numberOfFrames`.
*
* Note: the `events` and `selectedDates` are kept as is.
*
* @param {DateGalleryChangeConfig} config The new configuration.
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGalleryInvalidDateError} the initialDate when provided must be valid date
* @throws {DateGalleryNumberOfFramesError} numberOfFrames must be a positive number when defined
* @since 1.6.0
*/
changeConfig(config: DateGalleryChangeConfig): void;
/**
* Changes the anchor date of the DateGallery to today.
*
* @since 1.6.0
*/
today(): void;
private _buildFrames;
/**
* Moves the frame of the DateGallery to the next frame.
*
* For example if the mode is set to `month` and the current anchor
* date is in March it will move to April.
*
* @since 1.6.0
*/
next(): void;
/**
* Moves the frame of the DateGallery to the previous frame.
*
* For example if the mode is set to `month` and the current anchor
* date is in April it will move to March.
*
* @since 1.6.0
*/
previous(): void;
private _moveFrame;
/**
* Selects the given date, the date can either be a `Date` instance,
* or a `string` which can be passed to the `Date`constructor to
* make a date.
*
* The given date will be converted to midnight, so all times in
* the `selectedDates` array are always at midnight.
*
* When a `canSelect` predicate is configured, the date is first
* checked to see if it can be added. When a date does not pass the
* check nothing happens, and no error is thrown.
*
* @param {Date | string} date An optional date to act as the new initial date
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGalleryInvalidDateError} date provided must be valid date
* @throws {DateGallerySelectionLimitReachedError} thrown when maxSelectionLimit is exceeded, and maxSelectionLimitBehavior is "error".
* @since 1.6.0
*/
selectDate(date: string | Date): void;
_doSelectDate(date: Date, method: string): void;
_pushSelectDate(date: Date, method: string, deselectedDates: Date[]): Date | null;
/**
* Deselects the given date, the date can either be a `Date`
* instance, or a `string` which can be passed to the `Date`
* constructor to make a date.
*
* The given date will be converted to midnight so it better matches
* the `selectedDates` which are always at midnight.
*
* @param {Date | string} date An optional date to act as the new initial date
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGalleryInvalidDateError} date provided must be valid date
* @since 1.6.0
*/
deselectDate(date: string | Date): void;
_doDeselectDate(index: number, date: Date): void;
/**
* Toggles the date selection of the given date, if the date is
* selected it becomes deselected, if the date is deselected it
* becomes selected.
*
* The given date can either be a `Date` instance, or a `string`
* which can be passed to the `Date` constructor to make a date.
*
* The given date will be converted to midnight, so all times in
* the `selectedDates` array are always at midnight.
*
* When a `canSelect` predicate is configured, the date is first
* checked to see if it can be added. When a date does not pass the
* check nothing happens, and no error is thrown.
*
* @param {Date | string} date An optional date to act as the new initial date
* @throws {DateGalleryModeError} the mode must be one of the predefined modes
* @throws {DateGalleryInvalidDateError} date provided must be valid date
* @throws {DateGallerySelectionLimitReachedError} thrown when maxSelectionLimit is exceeded, and maxSelectionLimitBehavior is "error".
* @since 1.6.0
*/
toggleDateSelection(date: string | Date): void;
private _indexOfDate;
/**
* Deselects all dates, effectively clearing the `selectedDates`
* property.
*
* @since 1.6.0
*/
deselectAll(): void;
/**
* Selects all dates from within the given date range.
*
* If the range is end inclusive meaning if the starts on Monday
* and end ends on Friday: Monday, Tuesday, Wednesday, Thursday
* and Friday are selected.
*
* The given dates can either be a `Date` instance, or a `string`
* which can be passed to the `Date` constructor to make a date.
*
* The order of the two parameters does not matter as `selectRange`
* will check whether `a` or `b` is the earlier date.
*
* If a date is already selected and falls within the range the date
* will stay selected.
*
* When a `canSelect` predicate is configured, the date is first
* checked to see if it can be added. When a date does not pass the
* check nothing happens, and no error is thrown.
*
* Dates can also become deselected if the `maxSelection` is set
* to a number and the `maxSelectionLimitBehavior` is set to
* "circular", if space needs to be made for the new dates.
*
* When `maxSelectionLimitBehavior` is set to "error", all dates
* that can be accommodated become selected, but when the limit is
* exceeded the selection stops. The subscribers are then informed
* of which dates were selected, and then the error is thrown.
*
* Even through each date is selected sequentially, only one event
* is emitted, and one call is made to the subscribers, even if
* multiple dates are selected and deselected.
*
* Within the `DateGalleryDateSelectedMultipleEvent` only the end
* activate / deactivate results are reported.
*
* @param {Date | string} a the start or end date of the range
* @param {Date | string} b The start or end date of the range
* @throws {DateGalleryInvalidDateError} dates provided must be valid dates
* @throws {DateGallerySelectionLimitReachedError} thrown when maxSelectionLimit is exceeded, and maxSelectionLimitBehavior is "error".
* @since 1.6.0
*/
selectRange(a: Date | string, b: Date | string): void;
/**
* Takes a `DateGalleryEventConfig` and adds that config as a
* `DateGalleryEvent` to the `DateGallery`.
*
* @param {DateGalleryEventConfig<T>} event The config of the event you want to add.
* @throws {DateGalleryEventInvalidRangeError} an events start date must lie before on on the end date.
* @throws {DateGalleryInvalidDateError} dates provided must be valid dates
* @returns {DateGalleryEvent} The created DateGalleryEvent.
* @since 1.6.0
*/
addEvent(event: DateGalleryEventConfig<T>): DateGalleryEvent<T>;
private _doAddEvent;
/**
* Takes a `DateGalleryEvent` and removes that event from this
* `DateGallery`, and all associated frames.
*
* Note: if the event cannot be found within the `DateGallery`
* nothing happens.
*
* @param {DateGalleryEvent<T>} event The event you want to remove.
* @returns {DateGalleryEvent} The removed DateGalleryEvent.
* @since 1.6.0
*/
removeEvent(event: DateGalleryEvent<T>): DateGalleryEvent<T>;
/**
* Takes a `DateGalleryEvent` and moves that event chronologically,
* in other words it changes the events start and end time to the
* given range.
*
* @param {DateGalleryEvent<T>} event The event you want to move / change the start / end time for.
* @param {DateGalleryRange} range The new start and end times of the event.
* @throws {DateGalleryEventInvalidRangeError} an events start date must lie before on on the end date.
* @throws {DateGalleryEventNotFoundError} the provided event must be part of the DateGallery.
* @since 1.6.0
*/
moveEvent(event: DateGalleryEvent<T>, range: DateGalleryRange): void;
/**
* Changes the data of the given DateGalleryEvent, and informs
* the subscribers of the change.
*
* Note: if you provide the exact same `data` it will still set the
* `data` and inform the subscribers, even though nothing has
* actually changed.
*
* This way, when `data` is an object or an array, you can mutate
* the object / array directly, and pass in the same `data` object
* to the `changeData`, without having to create copies.
*
* @param {DateGalleryEvent<T>} view The DateGalleryEvent to change the data for
* @param {T} data The new data for the DateGalleryEvent
* @throws {DateGalleryEventNotFoundError} item must be in the views array based on === equality
* @since 1.6.0
*/
changeEventData(event: DateGalleryEvent<T>, data: T): void;
private _dragAnchor;
_inform(event: DateGallerySubscriberEvent<T>): void;
private _toDate;
private _checkDate;
private _firstDayOfWeek;
private _addNoDates;
private _addMonth;
private _pushDay;
private _makeDate;
/**
* Compares two dates and returns whether or not they are on the
* same date.
*
* The given dates can either be a `Date` instance, or a `string`
* which can be passed to the `Date` constructor to make a date.
*
* Takes into account the `isUTC` of the `DateGallery` when UTC is
* `true` it will compare the UTC dates.
*
* @param {Date | string} a The first date you want to check
* @param {Date | string} b The second date you want to check
* @throws {DateGalleryInvalidDateError} dates provided must be valid dates
* @returns {boolean} whether or not the dates are on the same date.
* @since 1.6.0
*/
isSameDay(a: Date | string, b: Date | string): boolean;
_sameDay(a: Date, b: Date): boolean;
private _getFullYear;
private _getMonth;
private _getDate;
private _getDay;
private _checkMode;
private _toMidnight;
private _moveDateBy;
}
/**
* Error which is thrown whenever an event has a startDate that lies
* after the endDate.
*
* @since 1.6.0
*/
declare class DateGalleryEventInvalidRangeError extends Error {
/**
* DateGalleryEventInvalidRangeError constructor
*
* @since 1.6.0
*/
constructor();
}
/**
* Error which is thrown whenever the DateGallery is configured
* with a `firstDayOfWeek` which is not a number from 0 to 6,
* including 6.
*
* @since 1.6.0
*/
declare class DateGalleryFirstDayOfWeekError extends Error {
/**
* DateGalleryFirstDayOfWeekError constructor
*
* @since 1.6.0
*/
constructor();
}
/**
* Error which is thrown whenever the DateGallery is given an invalid
* Date object, or when Date object cannot be constructed from
* a string.
*
* An example of an invalid date would be '2000-42-42' as there is
* no 42th month.
*
* @since 1.6.0
*/
declare class DateGalleryInvalidDateError extends Error {
/**
* DateGalleryInvalidDateError constructor
*
* @since 1.6.0
*/
constructor(method: string, dateName: string);
}
/**
* Error which is thrown whenever the mode is unknown, meaning not
* part of the `DATE_FRAME_MODES` array of known modes.
*
* @since 1.6.0
*/
declare class DateGalleryModeError extends Error {
/**
* DateGalleryModeError constructor
*
* @since 1.6.0
*/
constructor(mode: string);
}
/**
* Error which is thrown whenever the numberOfFrames is zero or
* less than zero.
*
* @since 1.6.0
*/
declare class DateGalleryNumberOfFramesError extends Error {
/**
* DateGalleryNumberOfFramesError constructor
*
* @since 1.6.0
*/
constructor();
}
/**
* Error which is thrown whenever a move is performed on an
* DateGalleryEvent, but that event is not found within the
* DateGallery that is performing the move,
*
* This can occur whenever an event is removed and the instance
* is then moved.
*
* @since 1.6.0
*/
declare class DateGalleryEventNotFoundError extends Error {
/**
* DateGalleryEventNotFoundError constructor
*
* @since 1.6.0
*/
constructor(method: string);
}
/**
* Error which is thrown whenever the DateGallery is in
* `DateGalleryMaxSelectionLimitBehavior` mode `error`, when the
* `maxSelectionLimit` is exceeded.
*
* @since 1.6.0
*/
declare class DateGallerySelectionLimitReachedError extends Error {
/**
* DateGallerySelectionLimitReachedError constructor
*
* @since 1.6.0
*/
constructor(method: string);
}
/**
* The configuration for the `createDateGallery` function.
*
* You should provide all methods for the events that you want to
* listen to, the ones you are not interested
*
* @since 1.6.0
*/
type CreateDateGallerySubscriberConfig<T> = {
/**
* Optionally whether or not you want to show debug logging.
*
* When `debug` is enabled whenever an event method is not provided
* but the event is fired, a `console.warn` message is logged. This
* allows you to easier detect missing methods during development.
*
* Defaults to `false`, meaning nothing will be logged to the console.
*
* @since 1.6.0
*/
debug?: boolean;
/**
* Method which is called whenever an `INITIALIZED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryInitializedEvent} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onInitialized?: (event: DateGalleryInitializedEvent, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `FRAME_CHANGED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryFrameChangedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onFrameChanged?: (event: DateGalleryFrameChangedEvent<T>, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `CONFIG_CHANGED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryConfigChangedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onConfigChanged?: (event: DateGalleryConfigChangedEvent<T>, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryDateSelectedEvent} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onDateSelected?: (event: DateGalleryDateSelectedEvent, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryDateSelectedMultipleEvent} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onDateSelectedMultiple?: (event: DateGalleryDateSelectedMultipleEvent, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryDateDeselectedEvent} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onDateDeselected?: (event: DateGalleryDateDeselectedEvent, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryDateDeselectedMultipleEvent} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onDateDeselectedMultiple?: (event: DateGalleryDateDeselectedMultipleEvent, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryEventAddedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onEventAdded?: (event: DateGalleryEventAddedEvent<T>, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryEventRemovedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onEventRemoved?: (event: DateGalleryEventRemovedEvent<T>, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `MOVED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryEventMovedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onEventMoved?: (event: DateGalleryEventMovedEvent<T>, dateGallery: DateGallery<T>) => void;
/**
* Method which is called whenever an `EVENT_DATA_CHANGED` event is fired
* from within the DateGallery.
*
* @param {DateGalleryEventDataChangedEvent<T>} event The event that was fired.
* @param {DateGallery<T>} dateGallery The DateGallery the event was fired from
* @since 1.6.0
*/
onEventDataChanged?: (event: DateGalleryEventDataChangedEvent<T>, dateGallery: DateGallery<T>) => void;
};
/**
* A function that creates an `DateGallerySubscriber` which you can
* provide to an `DateGallery`, which maps all `DateGalleryEvent` to
* methods.
*
* You provide `createDateGallery` with an object with all the events
* you want to handle as methods and it will call the methods for you.
* This way your code will not have any switch or if-statement to
* distinguish between events.
*
* For example if you wanted to handle the `FRAME_CHANGED` event, you
* provide a method called `onFrameChanged` within the config.
* Whenever the `FRAME_CHANGED` event occurs `onFrameChanged` will be
* called.
*
* All methods are called with two parameters: the first is the
* `event` that occurred and the second the `DateGallery` the event
* occurred on.
*
* `createDateGallery` should only be used when using
* Vanilla JavaScript or TypeScript and not when using a reactive
* framework because reactive frameworks (such as React or Vue) will
* handle the DOM manipulation for you.
*
* If an event is fired that you did not provide a method for,
* an `SubscriberMissingMethodError` error will be thrown.
*
* @param {createDateGallerySubscriberConfig} config An object containing all methods you want to listen to.
* @returns {DateGallerySubscriber<T>} A subscriber function which can be passed to an DateGallery.
* @since 1.6.0
*
* @example
* A. Simple example
*
* The example below shows what the subscriber could look like for
* a calendar view which can change frames.
*
* ```js
* import {
* DateGallery,
* createDateGallerySubscriber
* } from 'uiloos/core';
*
* const subscriber = createDateGallerySubscriber({
* onInitialized() {
* // Setup initial week calendar UI
* },
*
* onFrameChanged() {
* // Whenever the user changes weeks re-render them.
* },
* });
*
* export const weekCalendar = new DateGallery(
* {
* mode: 'week'
* },
* subscriber
* );
* ```
*
* @example
* B. All methods implemented
*
* Here is a nice example to get started which includes stub
* implementations for all method:
*
* ```js
* const subscriber = createDateGallery({
* onInitialized(event, dateGallery) {
* console.log('onInitialized', event, dateGallery)
* },
*
* onFrameChanged(event, dateGallery) {
* console.log('onFrameChanged', event, dateGallery)
* },
*
* onConfigChanged(event, dateGallery) {
* console.log('onConfigChanged', event, dateGallery)
* },
*
* onDateSelected(event, dateGallery) {
* console.log('onDateSelected', event, dateGallery)
* },
*
* onDateSelectedMultiple(event, dateGallery) {
* console.log('onDateSelectedMultiple', event, dateGallery)
* },
*
* onDateDeselected(event, dateGallery) {
* console.log('onDateDeselected', event, dateGallery)
* },
*
* onDateDeselectedMultiple(event, dateGallery) {
* console.log('onDateDeselectedMultiple', event, dateGallery)
* },
*
* onEventAdded(event, dateGallery) {
* console.log('onEventAdded', event, dateGallery)
* },
*
* onEventRemoved(event, dateGallery) {
* console.log('onEventRemoved', event, dateGallery)
* },
*
* onEventMoved(event, dateGallery) {
* console.log('onEventMoved', event, dateGallery)
* },
*
* onEventDataChanged(event, dateGallery) {
* console.log('onEventDataChanged', event, dateGallery)
* },
* });
* ```
*/
declare function createDateGallerySubscriber<T>(config: CreateDateGallerySubscriberConfig<T>): DateGallerySubscriber<T>;
export { ActivateLicenseOptions, ActiveList, ActiveListActivatedEvent, ActiveListActivatedMultipleEvent, ActiveListActivationLimitReachedError, ActiveListActivationOptions, ActiveListAutoPlay, ActiveListAutoPlayConfig, ActiveListAutoPlayDurationCallback, ActiveListAutoPlayDurationCallbackData, ActiveListAutoPlayDurationError, ActiveListAutoPlayPausedEvent, ActiveListAutoPlayPlayingEvent, ActiveListAutoPlayStoppedEvent, ActiveListBaseEvent, ActiveListConfig, ActiveListContent, ActiveListContentPredicate, ActiveListContentPredicateData, ActiveListCooldown, ActiveListCooldownConfig, ActiveListCooldownDurationCallback, ActiveListCooldownDurationCallbackData, ActiveListCooldownDurationError, ActiveListCooldownEndedEvent, ActiveListCooldownStartedEvent, ActiveListDeactivatedEvent, ActiveListDeactivatedMultipleEvent, ActiveListDirection, ActiveListEvent, ActiveListEventType, ActiveListIndexOutOfBoundsError, ActiveListInitializedEvent, ActiveListInsertedEvent, ActiveListItemNotFoundError, ActiveListMaxActivationLimitBehavior, ActiveListMovedEvent, ActiveListPredicateMode, ActiveListPredicateOptions, ActiveListRemovedEvent, ActiveListRemovedMultipleEvent, ActiveListSubscriber, ActiveListSwappedEvent, BaseTypewriterAction, CreateActiveListSubscriberConfig, CreateDateGallerySubscriberConfig, CreateTypewriterSubscriberConfig, CreateViewChannelSubscriberConfig, DATE_GALLERY_MODES, DateGallery, DateGalleryBaseEvent, DateGalleryCanSelectPredicate, DateGalleryChangeConfig, DateGalleryConfig, DateGalleryConfigChangedEvent, DateGalleryDate, DateGalleryDateDeselectedEvent, DateGalleryDateDeselectedMultipleEvent, DateGalleryDateSelectedEvent, DateGalleryDateSelectedMultipleEvent, DateGalleryDayOfWeek, DateGalleryEvent, DateGalleryEventAddedEvent, DateGalleryEventConfig, DateGalleryEventDataChangedEvent, DateGalleryEventInvalidRangeError, DateGalleryEventMovedEvent, DateGalleryEventNotFoundError, DateGalleryEventRemovedEvent, DateGalleryFirstDayOfWeekError, DateGalleryFrame, DateGalleryFrameChangedEvent, DateGalleryInitializedEvent, DateGalleryInvalidDateError, DateGalleryMaxSelectionLimitBehavior, DateGalleryMode, DateGalleryModeError, DateGalleryNumberOfFramesError, DateGalleryRange, DateGallerySelectionLimitReachedError, DateGallerySubscriber, DateGallerySubscriberEvent, DateGallerySubscriberEventType, Observable, Subscriber, Typewriter, TypewriterAction, TypewriterActionKeyboard, TypewriterActionMouse, TypewriterActionType, TypewriterActionUnknownCursorError, TypewriterBaseEvent, TypewriterBlinkAfterError, TypewriterBlinkingEvent, TypewriterChangedEvent, TypewriterConfig, TypewriterCursor, TypewriterCursorConfig, TypewriterCursorNotAtSelectionEdgeError, TypewriterCursorOutOfBoundsError, TypewriterCursorSelection, TypewriterCursorSelectionInvalidRangeError, TypewriterCursorSelectionOutOfBoundsError, TypewriterDelayError, TypewriterEvent, TypewriterEventType, TypewriterFinishedEvent, TypewriterFromSentencesConfig, TypewriterInitializedEvent, TypewriterPausedEvent, TypewriterPlayingEvent, TypewriterPosition, TypewriterRepeatDelayError, TypewriterRepeatError, TypewriterRepeatingEvent, TypewriterStoppedEvent, TypewriterSubscriber, UnsubscribeFunction, ViewChannel, ViewChannelAutoDismissDurationError, ViewChannelBaseEvent, ViewChannelConfig, ViewChannelEvent, ViewChannelEventType, ViewChannelIndexOutOfBoundsError, ViewChannelInitializedEvent, ViewChannelSubscriber, ViewChannelView, ViewChannelViewAutoDismiss, ViewChannelViewAutoDismissConfig, ViewChannelViewAutoDismissPausedEvent, ViewChannelViewAutoDismissPlayingEvent, ViewChannelViewAutoDismissStoppedEvent, ViewChannelViewConfig, ViewChannelViewDataChangedEvent, ViewChannelViewDismissedAllEvent, ViewChannelViewDismissedEvent, ViewChannelViewDismissedEventReason, ViewChannelViewNotFoundError, ViewChannelViewPresentedEvent, _LicenseChecker, createActiveListSubscriber, createDateGallerySubscriber, createTypewriterSubscriber, createViewChannelSubscriber, licenseChecker, typewriterFromSentences };