@agnos-ui/core 0.0.1-alpha.3 → 0.0.1-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{accordion.d.ts → components/accordion/accordion.d.ts} +13 -4
- package/{accordion.js → components/accordion/accordion.js} +17 -11
- package/components/alert/alert.d.ts +32 -0
- package/components/alert/alert.js +23 -0
- package/{alert.d.ts → components/alert/common.d.ts} +17 -21
- package/{alert.js → components/alert/common.js} +12 -12
- package/{modal → components/modal}/modal.d.ts +28 -21
- package/{modal → components/modal}/modal.js +39 -13
- package/{pagination.d.ts → components/pagination/pagination.d.ts} +3 -3
- package/{pagination.js → components/pagination/pagination.js} +6 -4
- package/{progressbar.d.ts → components/progressbar/progressbar.d.ts} +2 -3
- package/{progressbar.js → components/progressbar/progressbar.js} +6 -6
- package/{rating.d.ts → components/rating/rating.d.ts} +2 -3
- package/{rating.js → components/rating/rating.js} +6 -9
- package/components/select/select.d.ts +337 -0
- package/components/select/select.js +266 -0
- package/components/slider/slider.d.ts +239 -0
- package/components/slider/slider.js +389 -0
- package/config.d.ts +13 -8
- package/config.js +3 -3
- package/index.d.ts +23 -12
- package/index.js +29 -12
- package/package.json +32 -4
- package/services/extendWidget.d.ts +23 -0
- package/{extendWidget.js → services/extendWidget.js} +8 -1
- package/services/floatingUI.d.ts +48 -0
- package/services/floatingUI.js +97 -0
- package/services/focustrack.js +1 -1
- package/services/intersection.d.ts +1 -1
- package/services/intersection.js +2 -2
- package/services/navManager.d.ts +83 -1
- package/services/navManager.js +153 -37
- package/services/portal.js +8 -4
- package/services/siblingsInert.d.ts +2 -1
- package/services/siblingsInert.js +2 -2
- package/{transitions → services/transitions}/baseTransitions.d.ts +1 -2
- package/{transitions → services/transitions}/baseTransitions.js +7 -10
- package/services/transitions/bootstrap/collapse.d.ts +2 -0
- package/services/transitions/bootstrap/fade.d.ts +1 -0
- package/services/transitions/bootstrap.d.ts +2 -0
- package/services/transitions/bootstrap.js +2 -0
- package/{transitions → services/transitions}/collapse.js +1 -1
- package/{transitions → services/transitions}/cssTransitions.js +2 -4
- package/{transitions → services/transitions}/simpleClassTransition.js +1 -1
- package/types.d.ts +37 -4
- package/types.js +1 -0
- package/{services/directiveUtils.js → utils/directive.js} +1 -1
- package/{services → utils/internal}/checks.d.ts +12 -0
- package/{services → utils/internal}/checks.js +12 -0
- package/utils/internal/dom.d.ts +13 -0
- package/utils/internal/dom.js +49 -0
- package/utils/internal/isFocusable.d.ts +9 -0
- package/utils/internal/isFocusable.js +35 -0
- package/utils/internal/math.d.ts +5 -0
- package/utils/internal/math.js +13 -0
- package/utils/internal/promise.d.ts +31 -0
- package/utils/internal/promise.js +113 -0
- package/{modal → utils/internal}/scrollbars.js +1 -1
- package/utils/internal/textDirection.d.ts +1 -0
- package/utils/internal/textDirection.js +1 -0
- package/utils/internal/traversal.d.ts +54 -0
- package/utils/internal/traversal.js +105 -0
- package/{services → utils}/stores.d.ts +11 -35
- package/{services → utils}/stores.js +21 -19
- package/utils/writables.d.ts +26 -0
- package/utils/writables.js +66 -0
- package/extendWidget.d.ts +0 -3
- package/select.d.ts +0 -196
- package/select.js +0 -240
- package/services/index.d.ts +0 -8
- package/services/index.js +0 -8
- package/services/writables.d.ts +0 -8
- package/services/writables.js +0 -30
- package/transitions/bootstrap/collapse.d.ts +0 -2
- package/transitions/bootstrap/fade.d.ts +0 -1
- package/transitions/bootstrap/index.d.ts +0 -2
- package/transitions/bootstrap/index.js +0 -2
- package/transitions/index.d.ts +0 -5
- package/transitions/index.js +0 -5
- package/transitions/utils.d.ts +0 -20
- package/transitions/utils.js +0 -83
- /package/{commonProps.d.ts → components/commonProps.d.ts} +0 -0
- /package/{commonProps.js → components/commonProps.js} +0 -0
- /package/{pagination.utils.d.ts → components/pagination/bootstrap.d.ts} +0 -0
- /package/{pagination.utils.js → components/pagination/bootstrap.js} +0 -0
- /package/{transitions → services/transitions}/bootstrap/collapse.js +0 -0
- /package/{transitions → services/transitions}/bootstrap/fade.js +0 -0
- /package/{transitions → services/transitions}/collapse.d.ts +0 -0
- /package/{transitions → services/transitions}/cssTransitions.d.ts +0 -0
- /package/{transitions → services/transitions}/simpleClassTransition.d.ts +0 -0
- /package/{services/directiveUtils.d.ts → utils/directive.d.ts} +0 -0
- /package/{utils.d.ts → utils/internal/func.d.ts} +0 -0
- /package/{utils.js → utils/internal/func.js} +0 -0
- /package/{modal → utils/internal}/scrollbars.d.ts +0 -0
- /package/{services/sortUtils.d.ts → utils/internal/sort.d.ts} +0 -0
- /package/{services/sortUtils.js → utils/internal/sort.js} +0 -0
package/services/portal.js
CHANGED
|
@@ -8,14 +8,18 @@ export const portal = (content, newArg) => {
|
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
10
|
const update = (newArg) => {
|
|
11
|
-
if (newArg !== arg) {
|
|
11
|
+
if (newArg !== arg && (newArg?.container !== arg?.container || newArg?.insertBefore !== arg?.insertBefore)) {
|
|
12
12
|
arg = newArg;
|
|
13
13
|
const container = arg?.container ?? arg?.insertBefore?.parentElement;
|
|
14
14
|
if (container) {
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const insertBefore = arg?.insertBefore ?? null;
|
|
16
|
+
const moveNeeded = content.parentElement !== container || content.nextSibling !== insertBefore;
|
|
17
|
+
if (moveNeeded) {
|
|
18
|
+
if (!replaceComment) {
|
|
19
|
+
replaceComment = content.parentNode?.insertBefore(content.ownerDocument.createComment('portal'), content);
|
|
20
|
+
}
|
|
21
|
+
container.insertBefore(content, insertBefore);
|
|
17
22
|
}
|
|
18
|
-
container.insertBefore(content, arg?.insertBefore ?? null);
|
|
19
23
|
}
|
|
20
24
|
else {
|
|
21
25
|
removeReplaceComment();
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import type { Directive } from '../types';
|
|
1
2
|
/**
|
|
2
3
|
* sliblingsInert directive
|
|
3
4
|
* When used on an element, all siblings of the element and of its ancestors will be inert with the inert attribute.
|
|
4
5
|
* In case it is used on multiple elements, only the last one has an effect (the directive keeps a stack of elements
|
|
5
6
|
* on which it is used, so when the last one disappears, the previous one in the list becomes the one in effect).
|
|
6
7
|
*/
|
|
7
|
-
export declare const sliblingsInert:
|
|
8
|
+
export declare const sliblingsInert: Directive;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed } from '@amadeus-it-group/tansu';
|
|
2
|
-
import { noop } from '../utils';
|
|
3
|
-
import { createStoreArrayDirective, directiveSubscribe, mergeDirectives } from '
|
|
2
|
+
import { noop } from '../utils/internal/func';
|
|
3
|
+
import { createStoreArrayDirective, directiveSubscribe, mergeDirectives } from '../utils/directive';
|
|
4
4
|
const internalSetSiblingsInert = (element) => {
|
|
5
5
|
const inertValues = new Map();
|
|
6
6
|
const recursiveHelper = (element) => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { batch, computed, derived, writable } from '@amadeus-it-group/tansu';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
2
|
+
import { typeBoolean, typeBooleanOrNull, typeFunction } from '../../utils/writables';
|
|
3
|
+
import { promiseWithResolve } from '../../utils/internal/promise';
|
|
4
|
+
import { noop } from '../../utils/internal/func';
|
|
5
|
+
import { bindableDerived, stateStores, writablesForProps } from '../../utils/stores';
|
|
6
|
+
import { createStoreDirective, directiveSubscribe, directiveUpdate, mergeDirectives } from '../../utils/directive';
|
|
5
7
|
const neverEndingPromise = new Promise(noop);
|
|
6
8
|
export const noAnimation = async (element, direction) => {
|
|
7
9
|
element.style.display = direction === 'show' ? '' : 'none';
|
|
@@ -23,13 +25,8 @@ const configValidator = {
|
|
|
23
25
|
transition: typeFunction,
|
|
24
26
|
onShown: typeFunction,
|
|
25
27
|
onHidden: typeFunction,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
let resolve;
|
|
29
|
-
const promise = new Promise((r) => {
|
|
30
|
-
resolve = r;
|
|
31
|
-
});
|
|
32
|
-
return { promise, resolve: resolve };
|
|
28
|
+
onVisibleChange: typeFunction,
|
|
29
|
+
initDone: typeBooleanOrNull,
|
|
33
30
|
};
|
|
34
31
|
export const createTransition = (config) => {
|
|
35
32
|
const [{ animation$, initDone$, visible$: requestedVisible$, transition$, onShown$, onHidden$, onVisibleChange$, animationOnInit$ }, patch] = writablesForProps(defaultValues, config, configValidator);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const fadeTransition: import("../baseTransitions").TransitionFn;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createCSSTransition } from './cssTransitions';
|
|
2
|
-
import { addClasses, reflow, removeClasses } from '
|
|
2
|
+
import { addClasses, reflow, removeClasses } from '../../utils/internal/dom';
|
|
3
3
|
export const createCollapseTransition = ({ dimension = 'height', showClasses, hideClasses, animationPendingClasses } = {}) => createCSSTransition((element, direction, animation, context) => {
|
|
4
4
|
if (animation) {
|
|
5
5
|
let { maxSize, minSize } = context;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { noop } from '../../utils/internal/func';
|
|
2
|
+
import { promiseFromEvent, promiseFromTimeout } from '../../utils/internal/promise';
|
|
2
3
|
/**
|
|
3
4
|
* Check if the provided html element has a transition
|
|
4
5
|
* @param element - the html element
|
|
@@ -18,9 +19,6 @@ export function getTransitionDurationMs(element) {
|
|
|
18
19
|
const transitionDurationSec = parseFloat(transitionDuration);
|
|
19
20
|
return (transitionDelaySec + transitionDurationSec) * 1000;
|
|
20
21
|
}
|
|
21
|
-
const noop = () => {
|
|
22
|
-
/* do nothing */
|
|
23
|
-
};
|
|
24
22
|
export const createCSSTransition = (start) => async (element, direction, animation, signal, context) => {
|
|
25
23
|
const endFn = start(element, direction, animation, context) ?? noop;
|
|
26
24
|
if (animation && hasTransition(element)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createCSSTransition } from './cssTransitions';
|
|
2
|
-
import { addClasses, reflow, removeClasses } from '
|
|
2
|
+
import { addClasses, reflow, removeClasses } from '../../utils/internal/dom';
|
|
3
3
|
export const createSimpleClassTransition = ({ animationPendingClasses, animationPendingShowClasses, animationPendingHideClasses, showClasses, hideClasses, }) => createCSSTransition((element, direction, animation, context) => {
|
|
4
4
|
removeClasses(element, showClasses);
|
|
5
5
|
removeClasses(element, hideClasses);
|
package/types.d.ts
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
|
-
import type { ReadableSignal, SubscribableStore } from '@amadeus-it-group/tansu';
|
|
2
|
-
|
|
1
|
+
import type { ReadableSignal, StoreOptions, SubscribableStore, WritableSignal } from '@amadeus-it-group/tansu';
|
|
2
|
+
export type ValuesOrReadableSignals<T extends object> = {
|
|
3
|
+
[K in keyof T]?: ReadableSignal<T[K] | undefined> | T[K];
|
|
4
|
+
};
|
|
5
|
+
export type ValuesOrWritableSignals<T extends object> = {
|
|
6
|
+
[K in keyof T]?: WritableSignal<T[K] | undefined> | T[K];
|
|
7
|
+
};
|
|
8
|
+
export interface PropsConfig<U extends object> {
|
|
9
|
+
/**
|
|
10
|
+
* Object containing, for each property, either its initial value, or a store that will contain the value at any time.
|
|
11
|
+
* When the value of a property is undefined or invalid, the value from the config is used.
|
|
12
|
+
*/
|
|
13
|
+
props?: ValuesOrWritableSignals<U>;
|
|
14
|
+
/**
|
|
15
|
+
* Either a store of objects containing, for each property, the default value,
|
|
16
|
+
* or an object containing, for each property, either a store containing the default value or the default value itself.
|
|
17
|
+
*/
|
|
18
|
+
config?: ReadableSignal<Partial<U>> | ValuesOrReadableSignals<Partial<U>>;
|
|
19
|
+
}
|
|
3
20
|
export interface Widget<Props extends object = object, State extends object = object, Api extends object = object, Actions extends object = object, Directives extends object = object> {
|
|
4
21
|
/**
|
|
5
22
|
* the reactive state of the widget, combining all the values served by the stores
|
|
@@ -29,6 +46,7 @@ export interface Widget<Props extends object = object, State extends object = ob
|
|
|
29
46
|
*/
|
|
30
47
|
api: Api;
|
|
31
48
|
}
|
|
49
|
+
export type ContextWidget<W extends Widget> = Pick<W, 'actions' | 'api' | 'directives' | 'state$' | 'stores'>;
|
|
32
50
|
export interface WidgetSlotContext<W extends Widget> {
|
|
33
51
|
/**
|
|
34
52
|
* the state of the widget
|
|
@@ -37,9 +55,9 @@ export interface WidgetSlotContext<W extends Widget> {
|
|
|
37
55
|
/**
|
|
38
56
|
* the widget
|
|
39
57
|
*/
|
|
40
|
-
widget:
|
|
58
|
+
widget: ContextWidget<W>;
|
|
41
59
|
}
|
|
42
|
-
export declare const toSlotContextWidget: <W extends Widget<object, object, object, object, object>>(w: W) =>
|
|
60
|
+
export declare const toSlotContextWidget: <W extends Widget<object, object, object, object, object>>(w: W) => ContextWidget<W>;
|
|
43
61
|
export type WidgetState<T extends {
|
|
44
62
|
state$: SubscribableStore<any>;
|
|
45
63
|
}> = T extends {
|
|
@@ -56,3 +74,18 @@ export type Directive<T = void> = (node: HTMLElement, args: T) => void | {
|
|
|
56
74
|
destroy?: () => void;
|
|
57
75
|
};
|
|
58
76
|
export type SlotContent<Props extends object = object> = undefined | null | string | ((props: Props) => string);
|
|
77
|
+
export declare const INVALID_VALUE: unique symbol;
|
|
78
|
+
export type NormalizeValue<T> = (value: T) => T | typeof INVALID_VALUE;
|
|
79
|
+
export interface WritableWithDefaultOptions<T> {
|
|
80
|
+
/**
|
|
81
|
+
* the normalize value function. should return the invalidValue symbol when the provided value is invalid
|
|
82
|
+
*/
|
|
83
|
+
normalizeValue?: NormalizeValue<T>;
|
|
84
|
+
/**
|
|
85
|
+
* the equal function, allowing to compare two values. used to check if a previous and current values are equals.
|
|
86
|
+
*/
|
|
87
|
+
equal?: StoreOptions<T>['equal'];
|
|
88
|
+
}
|
|
89
|
+
export type ConfigValidator<T extends object> = {
|
|
90
|
+
[K in keyof T]?: WritableWithDefaultOptions<T[K]>;
|
|
91
|
+
};
|
package/types.js
CHANGED
|
@@ -35,3 +35,15 @@ export declare const isArray: (arg: any) => arg is any[];
|
|
|
35
35
|
* @returns the clamped value
|
|
36
36
|
*/
|
|
37
37
|
export declare function clamp(value: number, max: number, min?: number): number;
|
|
38
|
+
/**
|
|
39
|
+
* an html element type guard
|
|
40
|
+
* @param value the value to check
|
|
41
|
+
* @returns true if the value is an instance of HTMLElement
|
|
42
|
+
*/
|
|
43
|
+
export declare const isHTMLElement: (value: any) => value is HTMLElement;
|
|
44
|
+
/**
|
|
45
|
+
* Returns a new type guard that is based on the provided type guard and also returns true for null values.
|
|
46
|
+
* @param isType base type guard
|
|
47
|
+
* @returns A type guard function that returns true for null values and calls the provided type guard for other values.
|
|
48
|
+
*/
|
|
49
|
+
export declare const allowNull: <T>(isType: (value: any) => value is T) => (value: any) => value is T | null;
|
|
@@ -46,3 +46,15 @@ export const isArray = Array.isArray;
|
|
|
46
46
|
export function clamp(value, max, min = 0) {
|
|
47
47
|
return Math.max(Math.min(value, max), min);
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* an html element type guard
|
|
51
|
+
* @param value the value to check
|
|
52
|
+
* @returns true if the value is an instance of HTMLElement
|
|
53
|
+
*/
|
|
54
|
+
export const isHTMLElement = (value) => value instanceof HTMLElement;
|
|
55
|
+
/**
|
|
56
|
+
* Returns a new type guard that is based on the provided type guard and also returns true for null values.
|
|
57
|
+
* @param isType base type guard
|
|
58
|
+
* @returns A type guard function that returns true for null values and calls the provided type guard for other values.
|
|
59
|
+
*/
|
|
60
|
+
export const allowNull = (isType) => (value) => value === null || isType(value);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the common ancestor of the provided DOM elements.
|
|
3
|
+
* @param elements - array of DOM elements
|
|
4
|
+
* @returns the common ancestor, or null if the array is empty or if there is no common ancestor (e.g.: if elements are detached)
|
|
5
|
+
*/
|
|
6
|
+
export declare const computeCommonAncestor: (elements: HTMLElement[]) => HTMLElement | null;
|
|
7
|
+
/**
|
|
8
|
+
* Launch a reflow using a call to the provided html element getBoudingClientRect
|
|
9
|
+
* @param element - the html element
|
|
10
|
+
*/
|
|
11
|
+
export declare function reflow(element?: HTMLElement): void;
|
|
12
|
+
export declare const addClasses: (element: HTMLElement, classes?: string[]) => void;
|
|
13
|
+
export declare const removeClasses: (element: HTMLElement, classes?: string[]) => void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the common ancestor of the provided DOM elements.
|
|
3
|
+
* @param elements - array of DOM elements
|
|
4
|
+
* @returns the common ancestor, or null if the array is empty or if there is no common ancestor (e.g.: if elements are detached)
|
|
5
|
+
*/
|
|
6
|
+
export const computeCommonAncestor = (elements) => {
|
|
7
|
+
const length = elements.length;
|
|
8
|
+
if (length === 0)
|
|
9
|
+
return null;
|
|
10
|
+
let ancestor = elements[0];
|
|
11
|
+
for (let i = 1; i < length && ancestor; i++) {
|
|
12
|
+
const element = elements[i];
|
|
13
|
+
while (ancestor) {
|
|
14
|
+
if (ancestor === element) {
|
|
15
|
+
break;
|
|
16
|
+
}
|
|
17
|
+
const comparison = ancestor.compareDocumentPosition(element);
|
|
18
|
+
if (comparison & Node.DOCUMENT_POSITION_CONTAINED_BY) {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
else if (comparison & Node.DOCUMENT_POSITION_CONTAINS) {
|
|
22
|
+
ancestor = element;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
else if (comparison & Node.DOCUMENT_POSITION_DISCONNECTED) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
ancestor = ancestor.parentElement;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return ancestor;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Launch a reflow using a call to the provided html element getBoudingClientRect
|
|
35
|
+
* @param element - the html element
|
|
36
|
+
*/
|
|
37
|
+
export function reflow(element = document.body) {
|
|
38
|
+
element.getBoundingClientRect();
|
|
39
|
+
}
|
|
40
|
+
export const addClasses = (element, classes) => {
|
|
41
|
+
if (classes && classes.length > 0) {
|
|
42
|
+
element.classList.add(...classes);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export const removeClasses = (element, classes) => {
|
|
46
|
+
if (classes && classes.length > 0) {
|
|
47
|
+
element.classList.remove(...classes);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if the given HTML element is programmatically focusable.
|
|
3
|
+
* Warning: this is a best-effort approximation of whether the element is really focusable.
|
|
4
|
+
* It may not handle all use cases accurately.
|
|
5
|
+
*
|
|
6
|
+
* @param element - element to test
|
|
7
|
+
* @returns true if the element is programmatically focusable.
|
|
8
|
+
*/
|
|
9
|
+
export declare const isFocusable: (element: HTMLElement) => boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const isInertOrInvisible = (element) => {
|
|
2
|
+
let curElement = element;
|
|
3
|
+
while (curElement) {
|
|
4
|
+
const style = getComputedStyle(curElement);
|
|
5
|
+
if (curElement.inert || curElement.hidden || style.display === 'none' || style.visibility === 'hidden') {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
curElement = curElement.parentElement;
|
|
9
|
+
}
|
|
10
|
+
return false;
|
|
11
|
+
};
|
|
12
|
+
const checkNotDisabled = (element) => {
|
|
13
|
+
if (element.disabled) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
const parentFieldset = element.parentElement?.closest('fieldset');
|
|
17
|
+
return parentFieldset ? checkNotDisabled(parentFieldset) : true;
|
|
18
|
+
};
|
|
19
|
+
const isFocusableOtherTags = (element) => element.isContentEditable || !!element.hasAttribute('tabindex');
|
|
20
|
+
const isFocusableByTagName = {
|
|
21
|
+
INPUT: (element) => element.type !== 'hidden' && checkNotDisabled(element),
|
|
22
|
+
SELECT: checkNotDisabled,
|
|
23
|
+
TEXTAREA: checkNotDisabled,
|
|
24
|
+
BUTTON: checkNotDisabled,
|
|
25
|
+
A: (element) => !!element.href || isFocusableOtherTags(element),
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Returns true if the given HTML element is programmatically focusable.
|
|
29
|
+
* Warning: this is a best-effort approximation of whether the element is really focusable.
|
|
30
|
+
* It may not handle all use cases accurately.
|
|
31
|
+
*
|
|
32
|
+
* @param element - element to test
|
|
33
|
+
* @returns true if the element is programmatically focusable.
|
|
34
|
+
*/
|
|
35
|
+
export const isFocusable = (element) => !isInertOrInvisible(element) && (isFocusableByTagName[element.tagName] ?? isFocusableOtherTags)(element);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const decimalRegExp = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
|
|
2
|
+
/**
|
|
3
|
+
* @param number - decimal number
|
|
4
|
+
* @returns the decimal precision of the number
|
|
5
|
+
*/
|
|
6
|
+
export function getDecimalPrecision(number) {
|
|
7
|
+
const matches = ('' + number).match(decimalRegExp);
|
|
8
|
+
return Math.max(0,
|
|
9
|
+
// Number of digits right of decimal point.
|
|
10
|
+
(matches[1]?.length ?? 0) -
|
|
11
|
+
// Adjust for exponential notation.
|
|
12
|
+
(+matches[2] || 0));
|
|
13
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ReadableSignal } from '@amadeus-it-group/tansu';
|
|
2
|
+
export interface PromisePendingResult {
|
|
3
|
+
/** Pending status */
|
|
4
|
+
status: 'pending';
|
|
5
|
+
}
|
|
6
|
+
export declare const promisePending: PromisePendingResult;
|
|
7
|
+
export type PromiseState<T> = PromiseFulfilledResult<T> | PromiseRejectedResult | PromisePendingResult;
|
|
8
|
+
export declare const promiseStateStore: <T>(value: T) => ReadableSignal<Readonly<PromiseState<Awaited<T>>>>;
|
|
9
|
+
export declare const promiseStoreToPromiseStateStore: <T>(promiseStore$: ReadableSignal<T>) => ReadableSignal<PromiseState<Awaited<T>>>;
|
|
10
|
+
export declare const promiseStateStoreToValueStore: <T>(store$: ReadableSignal<PromiseState<T>>, initialValue: T, equal?: ((a: T, b: T) => boolean) | undefined) => ReadableSignal<T>;
|
|
11
|
+
export declare const promiseStoreToValueStore: <T>(promiseStore$: ReadableSignal<T>, initialValue: Awaited<T>, equal?: ((a: Awaited<T>, b: Awaited<T>) => boolean) | undefined) => ReadableSignal<Awaited<T>>;
|
|
12
|
+
export declare const promiseFromStore: <T>(store: ReadableSignal<T>, condition?: (value: T) => boolean) => {
|
|
13
|
+
promise: Promise<T>;
|
|
14
|
+
unsubscribe(): void;
|
|
15
|
+
};
|
|
16
|
+
export declare const promiseFromEvent: (element: EventTarget, event: string) => {
|
|
17
|
+
promise: Promise<Event>;
|
|
18
|
+
unsubscribe(): void;
|
|
19
|
+
};
|
|
20
|
+
export declare const promiseFromTimeout: (delay: number) => {
|
|
21
|
+
promise: Promise<void>;
|
|
22
|
+
unsubscribe(): void;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Utility method to create a promise with resolve
|
|
26
|
+
* @returns a promise with resolve
|
|
27
|
+
*/
|
|
28
|
+
export declare const promiseWithResolve: () => {
|
|
29
|
+
promise: Promise<void>;
|
|
30
|
+
resolve: (value: void | Promise<void>) => void;
|
|
31
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { asReadable, computed, derived, equal, readable, writable } from '@amadeus-it-group/tansu';
|
|
2
|
+
import { noop } from './func';
|
|
3
|
+
export const promisePending = { status: 'pending' };
|
|
4
|
+
const isThenable = (value) => {
|
|
5
|
+
// cf https://tc39.es/ecma262/#sec-promise-resolve-functions
|
|
6
|
+
const type = typeof value;
|
|
7
|
+
return (type === 'object' && value !== null) || type === 'function' ? typeof value.then === 'function' : false;
|
|
8
|
+
};
|
|
9
|
+
const createPromiseStateStore = (promise) => {
|
|
10
|
+
const store = writable(promisePending);
|
|
11
|
+
Promise.resolve(promise).then((value) => store.set({ status: 'fulfilled', value }), (reason) => store.set({ status: 'rejected', reason }));
|
|
12
|
+
return asReadable(store);
|
|
13
|
+
};
|
|
14
|
+
const promiseWeakMap = new WeakMap();
|
|
15
|
+
export const promiseStateStore = (value) => {
|
|
16
|
+
if (!isThenable(value)) {
|
|
17
|
+
return readable({ status: 'fulfilled', value: value });
|
|
18
|
+
}
|
|
19
|
+
let response = promiseWeakMap.get(value);
|
|
20
|
+
if (!response) {
|
|
21
|
+
response = createPromiseStateStore(value);
|
|
22
|
+
promiseWeakMap.set(value, response);
|
|
23
|
+
}
|
|
24
|
+
return response;
|
|
25
|
+
};
|
|
26
|
+
const promiseStateStoreEqual = (a, b) => Object.is(a, b) ||
|
|
27
|
+
(a.status === b.status &&
|
|
28
|
+
(a.status !== 'fulfilled' || equal(a.value, b.value)) &&
|
|
29
|
+
(a.status !== 'rejected' || equal(a.reason, b.reason)));
|
|
30
|
+
export const promiseStoreToPromiseStateStore = (promiseStore$) => computed(() => promiseStateStore(promiseStore$())(), { equal: promiseStateStoreEqual });
|
|
31
|
+
export const promiseStateStoreToValueStore = (store$, initialValue, equal) => derived(store$, {
|
|
32
|
+
derive: (state, set) => {
|
|
33
|
+
if (state.status === 'fulfilled') {
|
|
34
|
+
set(state.value);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
equal,
|
|
38
|
+
}, initialValue);
|
|
39
|
+
export const promiseStoreToValueStore = (promiseStore$, initialValue, equal) => promiseStateStoreToValueStore(promiseStoreToPromiseStateStore(promiseStore$), initialValue, equal);
|
|
40
|
+
const truthyValue = (value) => !!value;
|
|
41
|
+
export const promiseFromStore = (store, condition = truthyValue) => {
|
|
42
|
+
let resolve;
|
|
43
|
+
const promise = new Promise((r) => (resolve = r));
|
|
44
|
+
let unsubscribe = () => {
|
|
45
|
+
storeUnsubscribe();
|
|
46
|
+
unsubscribe = noop;
|
|
47
|
+
};
|
|
48
|
+
let storeUnsubscribe = noop;
|
|
49
|
+
storeUnsubscribe = store.subscribe((value) => {
|
|
50
|
+
if (condition(value)) {
|
|
51
|
+
resolve(value);
|
|
52
|
+
unsubscribe();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
if (unsubscribe === noop) {
|
|
56
|
+
storeUnsubscribe();
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
promise,
|
|
60
|
+
unsubscribe() {
|
|
61
|
+
unsubscribe();
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
export const promiseFromEvent = (element, event) => {
|
|
66
|
+
let resolve;
|
|
67
|
+
const promise = new Promise((r) => (resolve = r));
|
|
68
|
+
let unsubscribe = () => {
|
|
69
|
+
element.removeEventListener(event, eventListener);
|
|
70
|
+
unsubscribe = noop;
|
|
71
|
+
};
|
|
72
|
+
const eventListener = (event) => {
|
|
73
|
+
if (event.target === element) {
|
|
74
|
+
resolve(event);
|
|
75
|
+
unsubscribe();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
element.addEventListener(event, eventListener);
|
|
79
|
+
return {
|
|
80
|
+
promise,
|
|
81
|
+
unsubscribe() {
|
|
82
|
+
unsubscribe();
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
export const promiseFromTimeout = (delay) => {
|
|
87
|
+
let timeout;
|
|
88
|
+
return {
|
|
89
|
+
promise: new Promise((r) => {
|
|
90
|
+
timeout = setTimeout(() => {
|
|
91
|
+
timeout = undefined;
|
|
92
|
+
r();
|
|
93
|
+
}, delay);
|
|
94
|
+
}),
|
|
95
|
+
unsubscribe() {
|
|
96
|
+
if (timeout) {
|
|
97
|
+
clearTimeout(timeout);
|
|
98
|
+
timeout = undefined;
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Utility method to create a promise with resolve
|
|
105
|
+
* @returns a promise with resolve
|
|
106
|
+
*/
|
|
107
|
+
export const promiseWithResolve = () => {
|
|
108
|
+
let resolve;
|
|
109
|
+
const promise = new Promise((r) => {
|
|
110
|
+
resolve = r;
|
|
111
|
+
});
|
|
112
|
+
return { promise, resolve: resolve };
|
|
113
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getTextDirection: (element: HTMLElement) => "rtl" | "ltr";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getTextDirection = (element) => getComputedStyle(element).direction;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
interface TraversalFnOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Remove symbol to return to remove the value
|
|
4
|
+
*/
|
|
5
|
+
removeSymbol?: symbol;
|
|
6
|
+
/**
|
|
7
|
+
* index of the array, when looping on the elements
|
|
8
|
+
*/
|
|
9
|
+
index?: number;
|
|
10
|
+
}
|
|
11
|
+
type TraversalFn = (key: string, value: any, options: TraversalFnOptions) => any;
|
|
12
|
+
/**
|
|
13
|
+
* Creates a JSON walker function that can be used to traverse and transform
|
|
14
|
+
* the properties of a JSON object.
|
|
15
|
+
*
|
|
16
|
+
* @param fn - The callback function called for each property in the JSON object.
|
|
17
|
+
* @returns A function that takes a JSON object as input and applies the provided
|
|
18
|
+
* callback function to each property.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const json = {
|
|
23
|
+
* name: 'John',
|
|
24
|
+
* age: 30,
|
|
25
|
+
* address: {
|
|
26
|
+
* city: 'New York',
|
|
27
|
+
* country: 'USA',
|
|
28
|
+
* },
|
|
29
|
+
* useless: '',
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const transform = createTraversal((key, value, {removeSymbol}) => {
|
|
33
|
+
* if (key === 'age') {
|
|
34
|
+
* return value * 2; // Double the age
|
|
35
|
+
* }
|
|
36
|
+
* if (key === 'useless') {
|
|
37
|
+
* return removeSymbol;
|
|
38
|
+
* }
|
|
39
|
+
* return value;
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* const transformedJson = transform(json);
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export declare function createTraversal(fn: TraversalFn): (json: any) => any;
|
|
46
|
+
/**
|
|
47
|
+
* Utility method to create a promise with resolve
|
|
48
|
+
* @returns a promise with resolve
|
|
49
|
+
*/
|
|
50
|
+
export declare const promiseWithResolve: () => {
|
|
51
|
+
promise: Promise<void>;
|
|
52
|
+
resolve: (value: void | Promise<void>) => void;
|
|
53
|
+
};
|
|
54
|
+
export {};
|