@agnos-ui/core 0.0.1-alpha.1 → 0.0.1-alpha.11
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} +27 -18
- package/{accordion.js → components/accordion/accordion.js} +80 -76
- package/components/accordion/index.d.ts +1 -0
- package/components/accordion/index.js +1 -0
- package/components/alert/alert.d.ts +31 -0
- package/components/alert/alert.js +22 -0
- package/{alert.d.ts → components/alert/common.d.ts} +17 -21
- package/{alert.js → components/alert/common.js} +21 -19
- package/components/alert/index.d.ts +2 -0
- package/components/alert/index.js +2 -0
- package/components/modal/index.d.ts +1 -0
- package/components/modal/index.js +1 -0
- package/{modal → components/modal}/modal.d.ts +28 -21
- package/{modal → components/modal}/modal.js +58 -28
- package/components/pagination/index.d.ts +2 -0
- package/components/pagination/index.js +2 -0
- package/{pagination.d.ts → components/pagination/pagination.d.ts} +2 -3
- package/{pagination.js → components/pagination/pagination.js} +5 -4
- package/components/progressbar/index.d.ts +1 -0
- package/components/progressbar/index.js +1 -0
- package/components/progressbar/progressbar.d.ts +86 -0
- package/components/progressbar/progressbar.js +78 -0
- package/components/rating/index.d.ts +1 -0
- package/components/rating/index.js +1 -0
- package/{rating.d.ts → components/rating/rating.d.ts} +4 -5
- package/{rating.js → components/rating/rating.js} +6 -9
- package/components/select/index.d.ts +1 -0
- package/components/select/index.js +1 -0
- package/components/select/select.d.ts +337 -0
- package/components/select/select.js +266 -0
- package/components/slider/index.d.ts +1 -0
- package/components/slider/index.js +1 -0
- package/components/slider/slider.d.ts +245 -0
- package/components/slider/slider.js +415 -0
- package/config.d.ts +17 -7
- package/config.js +3 -3
- package/index.d.ts +23 -10
- package/index.js +29 -10
- package/package.json +32 -4
- package/services/extendWidget.d.ts +23 -0
- package/services/extendWidget.js +35 -0
- package/services/floatingUI.d.ts +56 -0
- package/services/floatingUI.js +105 -0
- package/services/focustrack.js +5 -5
- package/services/intersection.d.ts +9 -1
- package/services/intersection.js +10 -2
- package/services/navManager.d.ts +93 -0
- package/services/navManager.js +172 -0
- package/services/portal.d.ts +7 -0
- package/services/portal.js +15 -4
- package/services/siblingsInert.d.ts +2 -1
- package/services/siblingsInert.js +2 -2
- package/{transitions → services/transitions}/baseTransitions.d.ts +15 -2
- package/{transitions → services/transitions}/baseTransitions.js +21 -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/services/transitions/collapse.d.ts +43 -0
- package/{transitions → services/transitions}/collapse.js +15 -2
- package/{transitions → services/transitions}/cssTransitions.d.ts +6 -0
- package/{transitions → services/transitions}/cssTransitions.js +8 -4
- package/{transitions → services/transitions}/simpleClassTransition.d.ts +12 -1
- package/services/transitions/simpleClassTransition.js +42 -0
- package/types.d.ts +43 -4
- package/types.js +7 -0
- package/{services/directiveUtils.js → utils/directive.js} +1 -1
- package/utils/internal/checks.d.ts +49 -0
- package/utils/internal/checks.js +60 -0
- package/utils/internal/dom.d.ts +25 -0
- package/utils/internal/dom.js +61 -0
- package/utils/internal/func.d.ts +11 -0
- package/utils/internal/func.js +11 -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 +87 -0
- package/utils/internal/promise.js +169 -0
- package/utils/internal/scrollbars.d.ts +8 -0
- package/{modal → utils/internal}/scrollbars.js +7 -1
- package/utils/internal/sort.d.ts +16 -0
- package/utils/internal/sort.js +28 -0
- package/utils/internal/textDirection.d.ts +7 -0
- package/utils/internal/textDirection.js +7 -0
- package/utils/internal/traversal.d.ts +54 -0
- package/utils/internal/traversal.js +105 -0
- package/{services → utils}/stores.d.ts +67 -33
- package/{services → utils}/stores.js +121 -59
- package/utils/writables.d.ts +32 -0
- package/utils/writables.js +72 -0
- package/modal/scrollbars.d.ts +0 -2
- package/select.d.ts +0 -196
- package/select.js +0 -240
- package/services/checks.d.ts +0 -32
- package/services/checks.js +0 -43
- package/services/index.d.ts +0 -7
- package/services/index.js +0 -7
- package/services/writables.d.ts +0 -7
- package/services/writables.js +0 -16
- 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/collapse.d.ts +0 -29
- package/transitions/index.d.ts +0 -5
- package/transitions/index.js +0 -5
- package/transitions/simpleClassTransition.js +0 -28
- package/transitions/utils.d.ts +0 -20
- package/transitions/utils.js +0 -83
- package/utils.d.ts +0 -2
- package/utils.js +0 -2
- /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/{services/directiveUtils.d.ts → utils/directive.d.ts} +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { computed, writable } from '@amadeus-it-group/tansu';
|
|
2
|
+
import { registrationArray } from '../utils/directive';
|
|
3
|
+
import { computeCommonAncestor } from '../utils/internal/dom';
|
|
4
|
+
import { isFocusable } from '../utils/internal/isFocusable';
|
|
5
|
+
import { compareDomOrder } from '../utils/internal/sort';
|
|
6
|
+
import { getTextDirection } from '../utils/internal/textDirection';
|
|
7
|
+
// cf https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
|
|
8
|
+
const textInputTypes = new Set(['text', 'search', 'url', 'tel', 'password']);
|
|
9
|
+
const isTextInput = (element) => element instanceof HTMLInputElement && textInputTypes.has(element.type);
|
|
10
|
+
/**
|
|
11
|
+
* Returns the key name given the keyboard event. The key name is built using event.key (such as ArrowLeft, PageDown...),
|
|
12
|
+
* prefixed with the modifiers. If present, modifiers are always in the same order: Meta+Ctrl+Alt+Shift+...
|
|
13
|
+
* @param event - keyboard event
|
|
14
|
+
* @returns the name of the key, including modifiers
|
|
15
|
+
*/
|
|
16
|
+
export const getKeyName = (event) => {
|
|
17
|
+
let key = event.key;
|
|
18
|
+
if (event.shiftKey) {
|
|
19
|
+
key = `Shift+${key}`;
|
|
20
|
+
}
|
|
21
|
+
if (event.altKey) {
|
|
22
|
+
key = `Alt+${key}`;
|
|
23
|
+
}
|
|
24
|
+
if (event.ctrlKey) {
|
|
25
|
+
key = `Ctrl+${key}`;
|
|
26
|
+
}
|
|
27
|
+
if (event.metaKey) {
|
|
28
|
+
key = `Meta+${key}`;
|
|
29
|
+
}
|
|
30
|
+
return key;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Returns true if the keyboard event is an ArrowLeft, ArrowRight, Home or End key press that should make the cursor move inside
|
|
34
|
+
* the input and false otherwise (i.e. the key is not ArrowLeft, ArrowRight, Home or End key, or that would not make the cursor move
|
|
35
|
+
* because it is already at one end of the input)
|
|
36
|
+
* @param event - keyboard event
|
|
37
|
+
* @returns true if the keyboard event is an ArrowLeft, ArrowRight, Home or End key press that should make the cursor move inside
|
|
38
|
+
* the input and false otherwise.
|
|
39
|
+
*/
|
|
40
|
+
export const isInternalInputNavigation = (event) => {
|
|
41
|
+
const { target, key } = event;
|
|
42
|
+
if (isTextInput(target) && (key === 'ArrowLeft' || key === 'ArrowRight' || key === 'Home' || key === 'End')) {
|
|
43
|
+
let startPosition;
|
|
44
|
+
if (key === 'ArrowLeft' || key === 'ArrowRight') {
|
|
45
|
+
const direction = getTextDirection(target);
|
|
46
|
+
startPosition = key === (direction === 'ltr' ? 'ArrowLeft' : 'ArrowRight');
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
startPosition = key === 'Home';
|
|
50
|
+
}
|
|
51
|
+
const cursorPosition = target.selectionStart === target.selectionEnd ? target.selectionStart : null;
|
|
52
|
+
if ((startPosition && cursorPosition !== 0) || (!startPosition && cursorPosition !== target.value.length)) {
|
|
53
|
+
// let the text input process the key
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
const defaultSelector = (directiveElement) => [directiveElement];
|
|
60
|
+
/**
|
|
61
|
+
* Returns a new instance of the navigation manager.
|
|
62
|
+
*
|
|
63
|
+
* The navigation manager simplifies keyboard navigation for a set of DOM elements.
|
|
64
|
+
* It provides a directive to use on some DOM elements, both to add the keydown event handler and to specify which elements should be managed
|
|
65
|
+
* (either by directly putting the directive on those elements, or by putting the directive on a parent element and
|
|
66
|
+
* specifying which child elements should be included through a selector function).
|
|
67
|
+
*
|
|
68
|
+
* It provides some utilities to move the focus between those elements (focusFirst/focusLast, focusLeft/focusRight, focusPrevious/focusNext).
|
|
69
|
+
*
|
|
70
|
+
* @returns a new instance of the navigation manager
|
|
71
|
+
*/
|
|
72
|
+
export const createNavManager = () => {
|
|
73
|
+
const directiveInstances$ = registrationArray();
|
|
74
|
+
const elementsRefresh$ = writable({});
|
|
75
|
+
const refreshElements = () => elementsRefresh$.set({});
|
|
76
|
+
const elements$ = computed(() => {
|
|
77
|
+
elementsRefresh$();
|
|
78
|
+
const res = [];
|
|
79
|
+
for (const item of directiveInstances$()) {
|
|
80
|
+
res.push(...item());
|
|
81
|
+
}
|
|
82
|
+
return res;
|
|
83
|
+
});
|
|
84
|
+
const commonAncestor$ = computed(() => computeCommonAncestor(elements$()), { equal: Object.is });
|
|
85
|
+
const elementsInDomOrder$ = computed(() => [...elements$()].sort(compareDomOrder));
|
|
86
|
+
const ancestorDirection = () => {
|
|
87
|
+
const commonAncestor = commonAncestor$();
|
|
88
|
+
return commonAncestor ? getTextDirection(commonAncestor) : 'ltr';
|
|
89
|
+
};
|
|
90
|
+
const preventDefaultIfRelevant = (value, event) => {
|
|
91
|
+
if (value) {
|
|
92
|
+
event?.preventDefault();
|
|
93
|
+
}
|
|
94
|
+
return value;
|
|
95
|
+
};
|
|
96
|
+
const focusIndex = (index, moveDirection = 0) => {
|
|
97
|
+
const array = elementsInDomOrder$();
|
|
98
|
+
while (index >= 0 && index < array.length) {
|
|
99
|
+
const newItem = array[index];
|
|
100
|
+
if (isFocusable(newItem)) {
|
|
101
|
+
newItem.focus();
|
|
102
|
+
if (moveDirection != 0 && isTextInput(newItem)) {
|
|
103
|
+
const changeDirection = ancestorDirection() !== getTextDirection(newItem);
|
|
104
|
+
const position = moveDirection > 0 !== changeDirection ? 0 : newItem.value.length;
|
|
105
|
+
newItem.setSelectionRange(position, position, position === 0 ? 'forward' : 'backward');
|
|
106
|
+
}
|
|
107
|
+
return newItem;
|
|
108
|
+
}
|
|
109
|
+
if (moveDirection === 0) {
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
index += moveDirection;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
};
|
|
118
|
+
const createFocusNeighbour = (moveDirection) => ({ event, referenceElement = event?.target ?? document.activeElement, } = {}) => {
|
|
119
|
+
const curIndex = referenceElement ? elementsInDomOrder$().indexOf(referenceElement) : -1;
|
|
120
|
+
if (curIndex > -1) {
|
|
121
|
+
return preventDefaultIfRelevant(focusIndex(curIndex + moveDirection, moveDirection), event);
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
};
|
|
125
|
+
const directive = (directiveElement, config) => {
|
|
126
|
+
const onKeyDown = (event) => {
|
|
127
|
+
if (isInternalInputNavigation(event)) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const keyName = getKeyName(event);
|
|
131
|
+
const handler = config.keys?.[keyName];
|
|
132
|
+
if (handler) {
|
|
133
|
+
refreshElements();
|
|
134
|
+
handler({ event, directiveElement, navManager });
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
directiveElement.addEventListener('keydown', onKeyDown);
|
|
138
|
+
const unregister = directiveInstances$.register(() => (config?.selector ?? defaultSelector)(directiveElement));
|
|
139
|
+
return {
|
|
140
|
+
update(newConfig) {
|
|
141
|
+
config = newConfig;
|
|
142
|
+
},
|
|
143
|
+
destroy() {
|
|
144
|
+
directiveElement.removeEventListener('keydown', onKeyDown);
|
|
145
|
+
unregister();
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
const focusPrevious = createFocusNeighbour(-1);
|
|
150
|
+
const focusNext = createFocusNeighbour(1);
|
|
151
|
+
const focusFirst = ({ event } = {}) => preventDefaultIfRelevant(focusIndex(0, 1), event);
|
|
152
|
+
const focusLast = ({ event } = {}) => preventDefaultIfRelevant(focusIndex(elementsInDomOrder$().length - 1, -1), event);
|
|
153
|
+
const focusLeft = (...args) => (ancestorDirection() === 'rtl' ? focusNext : focusPrevious)(...args);
|
|
154
|
+
const focusRight = (...args) => (ancestorDirection() === 'rtl' ? focusPrevious : focusNext)(...args);
|
|
155
|
+
const focusFirstLeft = (...args) => (ancestorDirection() === 'rtl' ? focusLast : focusFirst)(...args);
|
|
156
|
+
const focusFirstRight = (...args) => (ancestorDirection() === 'rtl' ? focusFirst : focusLast)(...args);
|
|
157
|
+
const navManager = {
|
|
158
|
+
elementsInDomOrder$,
|
|
159
|
+
directive,
|
|
160
|
+
focusIndex,
|
|
161
|
+
focusPrevious,
|
|
162
|
+
focusNext,
|
|
163
|
+
focusFirst,
|
|
164
|
+
focusFirstLeft,
|
|
165
|
+
focusFirstRight,
|
|
166
|
+
focusLast,
|
|
167
|
+
focusLeft,
|
|
168
|
+
focusRight,
|
|
169
|
+
refreshElements,
|
|
170
|
+
};
|
|
171
|
+
return navManager;
|
|
172
|
+
};
|
package/services/portal.d.ts
CHANGED
|
@@ -3,4 +3,11 @@ export type PortalDirectiveArg = {
|
|
|
3
3
|
container?: HTMLElement | null | undefined;
|
|
4
4
|
insertBefore?: HTMLElement | null | undefined;
|
|
5
5
|
} | null | undefined;
|
|
6
|
+
/**
|
|
7
|
+
* Creates a portal directive, allowing to attach content to any element.
|
|
8
|
+
*
|
|
9
|
+
* @param content - the content of the portal
|
|
10
|
+
* @param newArg - {@link PortalDirectiveArg} args
|
|
11
|
+
* @returns the portal directive
|
|
12
|
+
*/
|
|
6
13
|
export declare const portal: Directive<PortalDirectiveArg>;
|
package/services/portal.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a portal directive, allowing to attach content to any element.
|
|
3
|
+
*
|
|
4
|
+
* @param content - the content of the portal
|
|
5
|
+
* @param newArg - {@link PortalDirectiveArg} args
|
|
6
|
+
* @returns the portal directive
|
|
7
|
+
*/
|
|
1
8
|
export const portal = (content, newArg) => {
|
|
2
9
|
let arg;
|
|
3
10
|
let replaceComment;
|
|
@@ -8,14 +15,18 @@ export const portal = (content, newArg) => {
|
|
|
8
15
|
}
|
|
9
16
|
};
|
|
10
17
|
const update = (newArg) => {
|
|
11
|
-
if (newArg !== arg) {
|
|
18
|
+
if (newArg !== arg && (newArg?.container !== arg?.container || newArg?.insertBefore !== arg?.insertBefore)) {
|
|
12
19
|
arg = newArg;
|
|
13
20
|
const container = arg?.container ?? arg?.insertBefore?.parentElement;
|
|
14
21
|
if (container) {
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
const insertBefore = arg?.insertBefore ?? null;
|
|
23
|
+
const moveNeeded = content.parentElement !== container || content.nextSibling !== insertBefore;
|
|
24
|
+
if (moveNeeded) {
|
|
25
|
+
if (!replaceComment) {
|
|
26
|
+
replaceComment = content.parentNode?.insertBefore(content.ownerDocument.createComment('portal'), content);
|
|
27
|
+
}
|
|
28
|
+
container.insertBefore(content, insertBefore);
|
|
17
29
|
}
|
|
18
|
-
container.insertBefore(content, arg?.insertBefore ?? null);
|
|
19
30
|
}
|
|
20
31
|
else {
|
|
21
32
|
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,5 +1,4 @@
|
|
|
1
|
-
import type { PropsConfig } from '
|
|
2
|
-
import type { Directive, Widget } from '../types';
|
|
1
|
+
import type { Directive, PropsConfig, Widget } from '../../types';
|
|
3
2
|
/**
|
|
4
3
|
* Function that implements a transition.
|
|
5
4
|
*/
|
|
@@ -132,5 +131,19 @@ export interface TransitionDirectives {
|
|
|
132
131
|
directive: Directive<void | Partial<TransitionProps>>;
|
|
133
132
|
}
|
|
134
133
|
export type TransitionWidget = Widget<TransitionProps, TransitionState, TransitionApi, object, TransitionDirectives>;
|
|
134
|
+
/**
|
|
135
|
+
* A transition to show / hide an element without any animation. It uses the HTML `display` attribute.
|
|
136
|
+
*
|
|
137
|
+
* @param element - the element to animate
|
|
138
|
+
* @param direction - the direction
|
|
139
|
+
*/
|
|
135
140
|
export declare const noAnimation: TransitionFn;
|
|
141
|
+
/**
|
|
142
|
+
* Create a transition widget.
|
|
143
|
+
*
|
|
144
|
+
* The widget will include a patch function, stores to track the animation states and a directive to apply the animation to an element.
|
|
145
|
+
*
|
|
146
|
+
* @param config - the props config of the transition
|
|
147
|
+
* @returns the transition widget
|
|
148
|
+
*/
|
|
136
149
|
export declare const createTransition: (config?: PropsConfig<TransitionProps>) => TransitionWidget;
|
|
@@ -1,8 +1,16 @@
|
|
|
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);
|
|
8
|
+
/**
|
|
9
|
+
* A transition to show / hide an element without any animation. It uses the HTML `display` attribute.
|
|
10
|
+
*
|
|
11
|
+
* @param element - the element to animate
|
|
12
|
+
* @param direction - the direction
|
|
13
|
+
*/
|
|
6
14
|
export const noAnimation = async (element, direction) => {
|
|
7
15
|
element.style.display = direction === 'show' ? '' : 'none';
|
|
8
16
|
};
|
|
@@ -23,14 +31,17 @@ const configValidator = {
|
|
|
23
31
|
transition: typeFunction,
|
|
24
32
|
onShown: typeFunction,
|
|
25
33
|
onHidden: typeFunction,
|
|
34
|
+
onVisibleChange: typeFunction,
|
|
35
|
+
initDone: typeBooleanOrNull,
|
|
26
36
|
};
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Create a transition widget.
|
|
39
|
+
*
|
|
40
|
+
* The widget will include a patch function, stores to track the animation states and a directive to apply the animation to an element.
|
|
41
|
+
*
|
|
42
|
+
* @param config - the props config of the transition
|
|
43
|
+
* @returns the transition widget
|
|
44
|
+
*/
|
|
34
45
|
export const createTransition = (config) => {
|
|
35
46
|
const [{ animation$, initDone$, visible$: requestedVisible$, transition$, onShown$, onHidden$, onVisibleChange$, animationOnInit$ }, patch] = writablesForProps(defaultValues, config, configValidator);
|
|
36
47
|
const { element$, directive: storeDirective } = createStoreDirective();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const fadeTransition: import("../baseTransitions").TransitionFn;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { TransitionFn } from './baseTransitions';
|
|
2
|
+
export interface CollapseContext {
|
|
3
|
+
/**
|
|
4
|
+
* the maximum size of the collapseable content.
|
|
5
|
+
*/
|
|
6
|
+
maxSize?: string;
|
|
7
|
+
/**
|
|
8
|
+
* the minimum size of the collapseable content
|
|
9
|
+
*/
|
|
10
|
+
minSize?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CollapseConfig {
|
|
13
|
+
/**
|
|
14
|
+
* the direction in which the collapsing is performed
|
|
15
|
+
*/
|
|
16
|
+
dimension?: 'width' | 'height';
|
|
17
|
+
/**
|
|
18
|
+
* the list of classes to add to the collapsable element when shown
|
|
19
|
+
*/
|
|
20
|
+
showClasses?: string[];
|
|
21
|
+
/**
|
|
22
|
+
* the list of classes to add to the collapsable element when collapsed
|
|
23
|
+
*/
|
|
24
|
+
hideClasses?: string[];
|
|
25
|
+
/**
|
|
26
|
+
* the list of classes to add to the collapsable element while transitioning
|
|
27
|
+
*/
|
|
28
|
+
animationPendingClasses?: string[];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create a collapse transition.
|
|
32
|
+
*
|
|
33
|
+
* The transition attaches / removes classes during the different states of the collapse transition.
|
|
34
|
+
* It also updates the dimension value when reaching a non-pending state.
|
|
35
|
+
*
|
|
36
|
+
* @param config - the collapse config
|
|
37
|
+
* @param config.dimension - the dimension, `height` or `width`, on which the collapse applies
|
|
38
|
+
* @param config.showClasses - the classes to attach when the element is fully visible
|
|
39
|
+
* @param config.hideClasses - the classes to attach when the element is fully collapsed
|
|
40
|
+
* @param config.animationPendingClasses - the classes to attach when the transition is pending
|
|
41
|
+
* @returns the collapse transition
|
|
42
|
+
*/
|
|
43
|
+
export declare const createCollapseTransition: ({ dimension, showClasses, hideClasses, animationPendingClasses, }?: CollapseConfig) => TransitionFn;
|
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { createCSSTransition } from './cssTransitions';
|
|
2
|
-
import { addClasses, reflow, removeClasses } from '
|
|
3
|
-
|
|
2
|
+
import { addClasses, reflow, removeClasses } from '../../utils/internal/dom';
|
|
3
|
+
/**
|
|
4
|
+
* Create a collapse transition.
|
|
5
|
+
*
|
|
6
|
+
* The transition attaches / removes classes during the different states of the collapse transition.
|
|
7
|
+
* It also updates the dimension value when reaching a non-pending state.
|
|
8
|
+
*
|
|
9
|
+
* @param config - the collapse config
|
|
10
|
+
* @param config.dimension - the dimension, `height` or `width`, on which the collapse applies
|
|
11
|
+
* @param config.showClasses - the classes to attach when the element is fully visible
|
|
12
|
+
* @param config.hideClasses - the classes to attach when the element is fully collapsed
|
|
13
|
+
* @param config.animationPendingClasses - the classes to attach when the transition is pending
|
|
14
|
+
* @returns the collapse transition
|
|
15
|
+
*/
|
|
16
|
+
export const createCollapseTransition = ({ dimension = 'height', showClasses, hideClasses, animationPendingClasses, } = {}) => createCSSTransition((element, direction, animation, context) => {
|
|
4
17
|
if (animation) {
|
|
5
18
|
let { maxSize, minSize } = context;
|
|
6
19
|
if (!maxSize) {
|
|
@@ -12,4 +12,10 @@ export declare function hasTransition(element: HTMLElement): boolean;
|
|
|
12
12
|
*/
|
|
13
13
|
export declare function getTransitionDurationMs(element: HTMLElement): number;
|
|
14
14
|
export type CSSTransitionFn = (element: HTMLElement, direction: 'show' | 'hide', animation: boolean, context: object) => void | (() => void);
|
|
15
|
+
/**
|
|
16
|
+
* Create a simple css transition.
|
|
17
|
+
*
|
|
18
|
+
* @param start - a function that creates the css animation and returns a clean-up function
|
|
19
|
+
* @returns the css transition
|
|
20
|
+
*/
|
|
15
21
|
export declare const createCSSTransition: (start: CSSTransitionFn) => TransitionFn;
|
|
@@ -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,12 @@ export function getTransitionDurationMs(element) {
|
|
|
18
19
|
const transitionDurationSec = parseFloat(transitionDuration);
|
|
19
20
|
return (transitionDelaySec + transitionDurationSec) * 1000;
|
|
20
21
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Create a simple css transition.
|
|
24
|
+
*
|
|
25
|
+
* @param start - a function that creates the css animation and returns a clean-up function
|
|
26
|
+
* @returns the css transition
|
|
27
|
+
*/
|
|
24
28
|
export const createCSSTransition = (start) => async (element, direction, animation, signal, context) => {
|
|
25
29
|
const endFn = start(element, direction, animation, context) ?? noop;
|
|
26
30
|
if (animation && hasTransition(element)) {
|
|
@@ -26,4 +26,15 @@ export interface SimpleClassTransitionContext {
|
|
|
26
26
|
*/
|
|
27
27
|
started?: boolean;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Create a transition based on css classes to attach.
|
|
31
|
+
*
|
|
32
|
+
* The config includes the classes that will be attached / removed depending on the transition state.
|
|
33
|
+
* `animationPendingClasses` are the classes attached when the transition is in a pending state
|
|
34
|
+
* `animationPendingShowClasses` and `animationPendingHideClasses` are attached when transitionning towards one direction
|
|
35
|
+
* `showClasses` and `hideClasses` are attached when the transition has reached the show or hide state respectively
|
|
36
|
+
*
|
|
37
|
+
* @param config - the transition config
|
|
38
|
+
* @returns the simple class transition
|
|
39
|
+
*/
|
|
40
|
+
export declare const createSimpleClassTransition: (config: SimpleClassTransitionConfig) => import("./baseTransitions").TransitionFn;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createCSSTransition } from './cssTransitions';
|
|
2
|
+
import { addClasses, reflow, removeClasses } from '../../utils/internal/dom';
|
|
3
|
+
/**
|
|
4
|
+
* Create a transition based on css classes to attach.
|
|
5
|
+
*
|
|
6
|
+
* The config includes the classes that will be attached / removed depending on the transition state.
|
|
7
|
+
* `animationPendingClasses` are the classes attached when the transition is in a pending state
|
|
8
|
+
* `animationPendingShowClasses` and `animationPendingHideClasses` are attached when transitionning towards one direction
|
|
9
|
+
* `showClasses` and `hideClasses` are attached when the transition has reached the show or hide state respectively
|
|
10
|
+
*
|
|
11
|
+
* @param config - the transition config
|
|
12
|
+
* @returns the simple class transition
|
|
13
|
+
*/
|
|
14
|
+
export const createSimpleClassTransition = (config) => {
|
|
15
|
+
const { animationPendingClasses, animationPendingShowClasses, animationPendingHideClasses, showClasses, hideClasses } = config;
|
|
16
|
+
return createCSSTransition((element, direction, animation, context) => {
|
|
17
|
+
removeClasses(element, showClasses);
|
|
18
|
+
removeClasses(element, hideClasses);
|
|
19
|
+
if (animation) {
|
|
20
|
+
removeClasses(element, direction === 'show' ? animationPendingHideClasses : animationPendingShowClasses);
|
|
21
|
+
if (!context.started) {
|
|
22
|
+
context.started = true;
|
|
23
|
+
// if the animation is starting, explicitly sets the initial state (reverse of the direction)
|
|
24
|
+
// so that it is not impacted by another reflow done somewhere else before we had time to put
|
|
25
|
+
// the right classes:
|
|
26
|
+
const classes = direction === 'show' ? hideClasses : showClasses;
|
|
27
|
+
addClasses(element, classes);
|
|
28
|
+
reflow(element);
|
|
29
|
+
removeClasses(element, classes);
|
|
30
|
+
}
|
|
31
|
+
addClasses(element, animationPendingClasses);
|
|
32
|
+
reflow(element);
|
|
33
|
+
addClasses(element, direction === 'show' ? animationPendingShowClasses : animationPendingHideClasses);
|
|
34
|
+
}
|
|
35
|
+
return () => {
|
|
36
|
+
removeClasses(element, animationPendingClasses);
|
|
37
|
+
removeClasses(element, animationPendingShowClasses);
|
|
38
|
+
removeClasses(element, animationPendingHideClasses);
|
|
39
|
+
addClasses(element, direction === 'show' ? showClasses : hideClasses);
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
};
|
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,15 @@ export interface WidgetSlotContext<W extends Widget> {
|
|
|
37
55
|
/**
|
|
38
56
|
* the widget
|
|
39
57
|
*/
|
|
40
|
-
widget:
|
|
58
|
+
widget: ContextWidget<W>;
|
|
41
59
|
}
|
|
42
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Extract actions, api, directives, state and stores from the widget to be passed to slots as context.
|
|
62
|
+
*
|
|
63
|
+
* @param w - the widget
|
|
64
|
+
* @returns the slot context
|
|
65
|
+
*/
|
|
66
|
+
export declare const toSlotContextWidget: <W extends Widget<object, object, object, object, object>>(w: W) => ContextWidget<W>;
|
|
43
67
|
export type WidgetState<T extends {
|
|
44
68
|
state$: SubscribableStore<any>;
|
|
45
69
|
}> = T extends {
|
|
@@ -56,3 +80,18 @@ export type Directive<T = void> = (node: HTMLElement, args: T) => void | {
|
|
|
56
80
|
destroy?: () => void;
|
|
57
81
|
};
|
|
58
82
|
export type SlotContent<Props extends object = object> = undefined | null | string | ((props: Props) => string);
|
|
83
|
+
export declare const INVALID_VALUE: unique symbol;
|
|
84
|
+
export type NormalizeValue<T> = (value: T) => T | typeof INVALID_VALUE;
|
|
85
|
+
export interface WritableWithDefaultOptions<T> {
|
|
86
|
+
/**
|
|
87
|
+
* the normalize value function. should return the invalidValue symbol when the provided value is invalid
|
|
88
|
+
*/
|
|
89
|
+
normalizeValue?: NormalizeValue<T>;
|
|
90
|
+
/**
|
|
91
|
+
* the equal function, allowing to compare two values. used to check if a previous and current values are equals.
|
|
92
|
+
*/
|
|
93
|
+
equal?: StoreOptions<T>['equal'];
|
|
94
|
+
}
|
|
95
|
+
export type ConfigValidator<T extends object> = {
|
|
96
|
+
[K in keyof T]?: WritableWithDefaultOptions<T[K]>;
|
|
97
|
+
};
|
package/types.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract actions, api, directives, state and stores from the widget to be passed to slots as context.
|
|
3
|
+
*
|
|
4
|
+
* @param w - the widget
|
|
5
|
+
* @returns the slot context
|
|
6
|
+
*/
|
|
1
7
|
export const toSlotContextWidget = (w) => ({
|
|
2
8
|
actions: w.actions,
|
|
3
9
|
api: w.api,
|
|
@@ -5,3 +11,4 @@ export const toSlotContextWidget = (w) => ({
|
|
|
5
11
|
state$: w.state$,
|
|
6
12
|
stores: w.stores,
|
|
7
13
|
});
|
|
14
|
+
export const INVALID_VALUE = Symbol();
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* a number type guard
|
|
3
|
+
* @param value - the value to check
|
|
4
|
+
* @returns true if the value is a number
|
|
5
|
+
*/
|
|
6
|
+
export declare function isNumber(value: any): value is number;
|
|
7
|
+
/**
|
|
8
|
+
* a boolean type guard
|
|
9
|
+
* @param value - the value to check
|
|
10
|
+
* @returns true if the value is a boolean
|
|
11
|
+
*/
|
|
12
|
+
export declare function isBoolean(value: any): value is boolean;
|
|
13
|
+
/**
|
|
14
|
+
* a function type guard
|
|
15
|
+
* @param value - the value to check
|
|
16
|
+
* @returns true if the value is a function
|
|
17
|
+
*/
|
|
18
|
+
export declare function isFunction(value: any): value is (...args: any[]) => any;
|
|
19
|
+
/**
|
|
20
|
+
* a string type guard
|
|
21
|
+
* @param value - the value to check
|
|
22
|
+
* @returns true if the value is a string
|
|
23
|
+
*/
|
|
24
|
+
export declare function isString(value: any): value is string;
|
|
25
|
+
/**
|
|
26
|
+
* an array type guard
|
|
27
|
+
* @returns true if the value is an array
|
|
28
|
+
*/
|
|
29
|
+
export declare const isArray: (arg: any) => arg is any[];
|
|
30
|
+
/**
|
|
31
|
+
* Clamp the value based on a maximum and optional minimum
|
|
32
|
+
* @param value - the value to check
|
|
33
|
+
* @param max - the max to clamp to
|
|
34
|
+
* @param [min] - the min to clamp to
|
|
35
|
+
* @returns the clamped value
|
|
36
|
+
*/
|
|
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;
|