@agnos-ui/core 0.0.1-alpha.0 → 0.0.1-alpha.2
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/README.md +4 -4
- package/{dist/lib/accordion.d.ts → accordion.d.ts} +17 -22
- package/{dist/lib/accordion.js → accordion.js} +66 -68
- package/{dist/lib/alert.d.ts → alert.d.ts} +2 -1
- package/{dist/lib/alert.js → alert.js} +10 -7
- package/commonProps.d.ts +6 -0
- package/commonProps.js +1 -0
- package/{dist/lib/config.d.ts → config.d.ts} +5 -0
- package/extendWidget.d.ts +3 -0
- package/extendWidget.js +28 -0
- package/{dist/lib/index.d.ts → index.d.ts} +3 -0
- package/{dist/lib/index.js → index.js} +3 -0
- package/{dist/lib/modal → modal}/modal.d.ts +3 -9
- package/{dist/lib/modal → modal}/modal.js +18 -14
- package/package.json +14 -28
- package/{dist/lib/pagination.d.ts → pagination.d.ts} +4 -12
- package/{dist/lib/pagination.js → pagination.js} +1 -1
- package/progressbar.d.ts +87 -0
- package/progressbar.js +78 -0
- package/{dist/lib/rating.d.ts → rating.d.ts} +5 -11
- package/{dist/lib/select.d.ts → select.d.ts} +2 -5
- package/{dist/lib/services → services}/checks.d.ts +5 -0
- package/{dist/lib/services → services}/checks.js +5 -0
- package/{dist/lib/services → services}/index.d.ts +2 -0
- package/{dist/lib/services → services}/index.js +2 -0
- package/services/intersection.d.ts +26 -0
- package/services/intersection.js +47 -0
- package/services/navManager.d.ts +5 -0
- package/services/navManager.js +52 -0
- package/services/sortUtils.d.ts +2 -0
- package/services/sortUtils.js +14 -0
- package/{dist/lib/services → services}/stores.d.ts +60 -23
- package/{dist/lib/services → services}/stores.js +92 -53
- package/{dist/lib/services → services}/writables.d.ts +2 -1
- package/{dist/lib/services → services}/writables.js +15 -1
- package/dist/lib/tsdoc-metadata.json +0 -11
- /package/{dist/lib/config.js → config.js} +0 -0
- /package/{dist/lib/modal → modal}/scrollbars.d.ts +0 -0
- /package/{dist/lib/modal → modal}/scrollbars.js +0 -0
- /package/{dist/lib/pagination.utils.d.ts → pagination.utils.d.ts} +0 -0
- /package/{dist/lib/pagination.utils.js → pagination.utils.js} +0 -0
- /package/{dist/lib/rating.js → rating.js} +0 -0
- /package/{dist/lib/select.js → select.js} +0 -0
- /package/{dist/lib/services → services}/directiveUtils.d.ts +0 -0
- /package/{dist/lib/services → services}/directiveUtils.js +0 -0
- /package/{dist/lib/services → services}/focustrack.d.ts +0 -0
- /package/{dist/lib/services → services}/focustrack.js +0 -0
- /package/{dist/lib/services → services}/portal.d.ts +0 -0
- /package/{dist/lib/services → services}/portal.js +0 -0
- /package/{dist/lib/services → services}/siblingsInert.d.ts +0 -0
- /package/{dist/lib/services → services}/siblingsInert.js +0 -0
- /package/{dist/lib/transitions → transitions}/baseTransitions.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/baseTransitions.js +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/collapse.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/collapse.js +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/fade.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/fade.js +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/index.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/bootstrap/index.js +0 -0
- /package/{dist/lib/transitions → transitions}/collapse.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/collapse.js +0 -0
- /package/{dist/lib/transitions → transitions}/cssTransitions.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/cssTransitions.js +0 -0
- /package/{dist/lib/transitions → transitions}/index.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/index.js +0 -0
- /package/{dist/lib/transitions → transitions}/simpleClassTransition.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/simpleClassTransition.js +0 -0
- /package/{dist/lib/transitions → transitions}/utils.d.ts +0 -0
- /package/{dist/lib/transitions → transitions}/utils.js +0 -0
- /package/{dist/lib/types.d.ts → types.d.ts} +0 -0
- /package/{dist/lib/types.js → types.js} +0 -0
- /package/{dist/lib/utils.d.ts → utils.d.ts} +0 -0
- /package/{dist/lib/utils.js → utils.js} +0 -0
package/package.json
CHANGED
|
@@ -1,52 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agnos-ui/core",
|
|
3
3
|
"description": "Framework-agnostic headless widget library.",
|
|
4
|
-
"homepage": "https://amadeusitgroup.github.io/AgnosUI/latest/",
|
|
5
4
|
"keywords": [
|
|
6
5
|
"headless",
|
|
7
6
|
"agnostic",
|
|
8
7
|
"components",
|
|
9
8
|
"widgets",
|
|
9
|
+
"accordion",
|
|
10
10
|
"alert",
|
|
11
11
|
"modal",
|
|
12
12
|
"pagination",
|
|
13
13
|
"rating"
|
|
14
14
|
],
|
|
15
15
|
"type": "module",
|
|
16
|
-
"main": "./
|
|
17
|
-
"module": "./
|
|
18
|
-
"types": "./
|
|
16
|
+
"main": "./index.js",
|
|
17
|
+
"module": "./index.js",
|
|
18
|
+
"types": "./index.d.ts",
|
|
19
19
|
"exports": {
|
|
20
20
|
".": {
|
|
21
|
-
"types": "./
|
|
22
|
-
"default": "./
|
|
21
|
+
"types": "./index.d.ts",
|
|
22
|
+
"default": "./index.js"
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
|
-
"scripts": {
|
|
26
|
-
"build": "npm run build:lib && npm run build:tsc && npm run build:api-extractor",
|
|
27
|
-
"build:lib": "node ../scripts/rm.js dist/lib && tsc -p tsconfig.lib.json",
|
|
28
|
-
"build:tsc": "tsc",
|
|
29
|
-
"build:api-extractor": "api-extractor run",
|
|
30
|
-
"test": "vitest run",
|
|
31
|
-
"tdd": "vitest",
|
|
32
|
-
"tdd:ui": "vitest --ui",
|
|
33
|
-
"test:coverage": "vitest run --coverage"
|
|
34
|
-
},
|
|
35
25
|
"dependencies": {
|
|
36
|
-
"@amadeus-it-group/tansu": "0.0.
|
|
26
|
+
"@amadeus-it-group/tansu": "0.0.23"
|
|
37
27
|
},
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"license": "MIT",
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"version": "v0.0.1-alpha.2",
|
|
30
|
+
"homepage": "https://amadeusitgroup.github.io/AgnosUI/latest/",
|
|
42
31
|
"bugs": "https://github.com/AmadeusITGroup/AgnosUI/issues",
|
|
32
|
+
"license": "MIT",
|
|
43
33
|
"repository": {
|
|
44
34
|
"type": "git",
|
|
45
35
|
"url": "https://github.com/AmadeusITGroup/AgnosUI.git",
|
|
46
|
-
"directory": "core"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
"eslint-plugin-jsdoc": "^46.4.6"
|
|
50
|
-
},
|
|
51
|
-
"version": "0.0.1-alpha.0"
|
|
52
|
-
}
|
|
36
|
+
"directory": "core/lib"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PropsConfig } from './services';
|
|
2
2
|
import type { Widget, SlotContent, WidgetSlotContext } from './types';
|
|
3
|
+
import type { WidgetsCommonPropsAndState } from './commonProps';
|
|
3
4
|
/**
|
|
4
5
|
* A type for the slot context of the pagination widget
|
|
5
6
|
*/
|
|
@@ -13,7 +14,7 @@ export interface PaginationNumberContext extends PaginationContext {
|
|
|
13
14
|
*/
|
|
14
15
|
displayedPage: number;
|
|
15
16
|
}
|
|
16
|
-
export interface PaginationCommonPropsAndState {
|
|
17
|
+
export interface PaginationCommonPropsAndState extends WidgetsCommonPropsAndState {
|
|
17
18
|
/**
|
|
18
19
|
* The current page.
|
|
19
20
|
*
|
|
@@ -86,11 +87,6 @@ export interface PaginationCommonPropsAndState {
|
|
|
86
87
|
* @defaultValue false
|
|
87
88
|
*/
|
|
88
89
|
boundaryLinks: boolean;
|
|
89
|
-
/**
|
|
90
|
-
* An input to add a custom class to the UL
|
|
91
|
-
* @defaultValue ''
|
|
92
|
-
*/
|
|
93
|
-
className: string;
|
|
94
90
|
/**
|
|
95
91
|
* The template to use for the ellipsis slot
|
|
96
92
|
* for I18n, we suggest to use the global configuration
|
|
@@ -398,11 +394,6 @@ export declare function getPaginationDefaultConfig(): {
|
|
|
398
394
|
* @defaultValue false
|
|
399
395
|
*/
|
|
400
396
|
boundaryLinks: boolean;
|
|
401
|
-
/**
|
|
402
|
-
* An input to add a custom class to the UL
|
|
403
|
-
* @defaultValue ''
|
|
404
|
-
*/
|
|
405
|
-
className: string;
|
|
406
397
|
/**
|
|
407
398
|
* The template to use for the ellipsis slot
|
|
408
399
|
* for I18n, we suggest to use the global configuration
|
|
@@ -455,10 +446,11 @@ export declare function getPaginationDefaultConfig(): {
|
|
|
455
446
|
* @param displayedPage - The current page number
|
|
456
447
|
*/
|
|
457
448
|
slotNumberLabel: SlotContent<PaginationNumberContext>;
|
|
449
|
+
className: string;
|
|
458
450
|
};
|
|
459
451
|
/**
|
|
460
452
|
* Create a PaginationWidget with given config props
|
|
461
|
-
* @param config - an optional
|
|
453
|
+
* @param config - an optional pagination config
|
|
462
454
|
* @returns a PaginationWidget
|
|
463
455
|
*/
|
|
464
456
|
export declare function createPagination(config?: PropsConfig<PaginationProps>): PaginationWidget;
|
|
@@ -64,7 +64,7 @@ const configValidator = {
|
|
|
64
64
|
};
|
|
65
65
|
/**
|
|
66
66
|
* Create a PaginationWidget with given config props
|
|
67
|
-
* @param config - an optional
|
|
67
|
+
* @param config - an optional pagination config
|
|
68
68
|
* @returns a PaginationWidget
|
|
69
69
|
*/
|
|
70
70
|
export function createPagination(config) {
|
package/progressbar.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { PropsConfig } from './services';
|
|
2
|
+
import type { SlotContent, Widget, WidgetSlotContext } from './types';
|
|
3
|
+
import type { WidgetsCommonPropsAndState } from './commonProps';
|
|
4
|
+
export type ProgressbarContext = WidgetSlotContext<ProgressbarWidget>;
|
|
5
|
+
export interface ProgressbarCommonPropsAndState extends WidgetsCommonPropsAndState {
|
|
6
|
+
/**
|
|
7
|
+
* The minimum value.
|
|
8
|
+
* @defaultValue 0
|
|
9
|
+
*/
|
|
10
|
+
min: number;
|
|
11
|
+
/**
|
|
12
|
+
* The maximum value.
|
|
13
|
+
* @defaultValue 100
|
|
14
|
+
*/
|
|
15
|
+
max: number;
|
|
16
|
+
/**
|
|
17
|
+
* The current value.
|
|
18
|
+
* @defaultValue 0
|
|
19
|
+
*/
|
|
20
|
+
value: number;
|
|
21
|
+
/**
|
|
22
|
+
* The aria label.
|
|
23
|
+
*/
|
|
24
|
+
ariaLabel: string;
|
|
25
|
+
/**
|
|
26
|
+
* Global template for the Progressbar content.
|
|
27
|
+
*/
|
|
28
|
+
slotContent: SlotContent<ProgressbarContext>;
|
|
29
|
+
/**
|
|
30
|
+
* Label of the progress.
|
|
31
|
+
*/
|
|
32
|
+
slotDefault: SlotContent<ProgressbarContext>;
|
|
33
|
+
/**
|
|
34
|
+
* Height of the progressbar, can be any valid css height value.
|
|
35
|
+
*/
|
|
36
|
+
height: string;
|
|
37
|
+
/**
|
|
38
|
+
* If `true`, shows a striped progressbar.
|
|
39
|
+
*/
|
|
40
|
+
striped: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* If `true`, animates a striped progressbar.
|
|
43
|
+
* Takes effect only for browsers supporting CSS3 animations, and if `striped` is `true`.
|
|
44
|
+
*/
|
|
45
|
+
animated: boolean;
|
|
46
|
+
}
|
|
47
|
+
export interface ProgressbarState extends ProgressbarCommonPropsAndState {
|
|
48
|
+
/**
|
|
49
|
+
* Percentage of completion.
|
|
50
|
+
*/
|
|
51
|
+
percentage: number;
|
|
52
|
+
/**
|
|
53
|
+
* `true` if the value is above its minimum value.
|
|
54
|
+
*/
|
|
55
|
+
started: boolean;
|
|
56
|
+
/**
|
|
57
|
+
* `true` if the value has reached its maximum value.
|
|
58
|
+
*/
|
|
59
|
+
finished: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* The aria value text.
|
|
62
|
+
*/
|
|
63
|
+
ariaValueText: string | undefined;
|
|
64
|
+
}
|
|
65
|
+
export interface ProgressbarProps extends ProgressbarCommonPropsAndState {
|
|
66
|
+
/**
|
|
67
|
+
* Return the value for the 'aria-valuetext' attribute.
|
|
68
|
+
* @param value - current value
|
|
69
|
+
* @param minimum - minimum value
|
|
70
|
+
* @param maximum - maximum value
|
|
71
|
+
*/
|
|
72
|
+
ariaValueTextFn: (value: number, minimum: number, maximum: number) => string | undefined;
|
|
73
|
+
}
|
|
74
|
+
export interface ProgressbarApi {
|
|
75
|
+
}
|
|
76
|
+
export type ProgressbarWidget = Widget<ProgressbarProps, ProgressbarState, ProgressbarApi, object, object>;
|
|
77
|
+
/**
|
|
78
|
+
* Retrieve a shallow copy of the default Progressbar config
|
|
79
|
+
* @returns the default Progressbar config
|
|
80
|
+
*/
|
|
81
|
+
export declare function getProgressbarDefaultConfig(): ProgressbarProps;
|
|
82
|
+
/**
|
|
83
|
+
* Create an ProgressbarWidget with given config props
|
|
84
|
+
* @param config - an optional progress bar config
|
|
85
|
+
* @returns an ProgressbarWidget
|
|
86
|
+
*/
|
|
87
|
+
export declare function createProgressbar(config?: PropsConfig<ProgressbarProps>): ProgressbarWidget;
|
package/progressbar.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { clamp } from './services/checks';
|
|
2
|
+
import { bindableDerived, stateStores, typeBoolean, typeFunction, typeNumber, typeString, writablesForProps } from './services';
|
|
3
|
+
import { computed, readable } from '@amadeus-it-group/tansu';
|
|
4
|
+
import { noop } from './utils';
|
|
5
|
+
const defaultConfig = {
|
|
6
|
+
min: 0,
|
|
7
|
+
max: 100,
|
|
8
|
+
value: 0,
|
|
9
|
+
ariaLabel: 'Progressbar',
|
|
10
|
+
className: '',
|
|
11
|
+
slotContent: undefined,
|
|
12
|
+
slotDefault: undefined,
|
|
13
|
+
height: '',
|
|
14
|
+
striped: false,
|
|
15
|
+
animated: false,
|
|
16
|
+
ariaValueTextFn: () => undefined,
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Retrieve a shallow copy of the default Progressbar config
|
|
20
|
+
* @returns the default Progressbar config
|
|
21
|
+
*/
|
|
22
|
+
export function getProgressbarDefaultConfig() {
|
|
23
|
+
return { ...defaultConfig };
|
|
24
|
+
}
|
|
25
|
+
const configValidator = {
|
|
26
|
+
min: typeNumber,
|
|
27
|
+
max: typeNumber,
|
|
28
|
+
value: typeNumber,
|
|
29
|
+
ariaLabel: typeString,
|
|
30
|
+
className: typeString,
|
|
31
|
+
height: typeString,
|
|
32
|
+
striped: typeBoolean,
|
|
33
|
+
animated: typeBoolean,
|
|
34
|
+
ariaValueTextFn: typeFunction,
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Create an ProgressbarWidget with given config props
|
|
38
|
+
* @param config - an optional progress bar config
|
|
39
|
+
* @returns an ProgressbarWidget
|
|
40
|
+
*/
|
|
41
|
+
export function createProgressbar(config) {
|
|
42
|
+
const [{
|
|
43
|
+
// dirty inputs that need adjustment:
|
|
44
|
+
max$: _dirtyMaximum$, value$: _dirtyValue$,
|
|
45
|
+
// clean inputs
|
|
46
|
+
min$, ariaValueTextFn$, ...stateProps }, patch,] = writablesForProps(defaultConfig, config, configValidator);
|
|
47
|
+
const max$ = bindableDerived(readable(noop), [_dirtyMaximum$, min$], ([dirtyMaximum, minimum]) => Math.max(minimum, dirtyMaximum));
|
|
48
|
+
const value$ = bindableDerived(readable(noop), [_dirtyValue$, min$, max$], ([dirtyValue, min, max]) => clamp(dirtyValue, max, min));
|
|
49
|
+
const percentage$ = computed(() => {
|
|
50
|
+
const max = max$();
|
|
51
|
+
const min = min$();
|
|
52
|
+
if (max > min) {
|
|
53
|
+
return clamp(((value$() - min) * 100) / (max - min), 100, 0);
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
const started$ = computed(() => value$() > min$());
|
|
60
|
+
const finished$ = computed(() => value$() === max$());
|
|
61
|
+
const ariaValueText$ = computed(() => ariaValueTextFn$()(value$(), min$(), max$()));
|
|
62
|
+
return {
|
|
63
|
+
...stateStores({
|
|
64
|
+
min$,
|
|
65
|
+
max$,
|
|
66
|
+
value$,
|
|
67
|
+
percentage$,
|
|
68
|
+
started$,
|
|
69
|
+
finished$,
|
|
70
|
+
ariaValueText$,
|
|
71
|
+
...stateProps,
|
|
72
|
+
}),
|
|
73
|
+
patch,
|
|
74
|
+
api: {},
|
|
75
|
+
directives: {},
|
|
76
|
+
actions: {},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PropsConfig } from './services';
|
|
2
2
|
import type { SlotContent, Widget } from './types';
|
|
3
|
+
import type { WidgetsCommonPropsAndState } from './commonProps';
|
|
3
4
|
export interface StarContext {
|
|
4
5
|
/**
|
|
5
6
|
* indicates how much the current star is filled, from 0 to 100
|
|
@@ -10,7 +11,7 @@ export interface StarContext {
|
|
|
10
11
|
*/
|
|
11
12
|
index: number;
|
|
12
13
|
}
|
|
13
|
-
export interface RatingCommonPropsAndState {
|
|
14
|
+
export interface RatingCommonPropsAndState extends WidgetsCommonPropsAndState {
|
|
14
15
|
/**
|
|
15
16
|
* The current rating. Could be a decimal value like `3.75`.
|
|
16
17
|
*/
|
|
@@ -38,10 +39,6 @@ export interface RatingCommonPropsAndState {
|
|
|
38
39
|
* If the component is disabled, `tabindex` will still be set to `-1`.
|
|
39
40
|
*/
|
|
40
41
|
tabindex: number;
|
|
41
|
-
/**
|
|
42
|
-
* Classname to be applied on the rating container
|
|
43
|
-
*/
|
|
44
|
-
className: string;
|
|
45
42
|
/**
|
|
46
43
|
* The template to override the way each star is displayed.
|
|
47
44
|
*/
|
|
@@ -57,7 +54,7 @@ export interface RatingCommonPropsAndState {
|
|
|
57
54
|
}
|
|
58
55
|
export interface RatingProps extends RatingCommonPropsAndState {
|
|
59
56
|
/**
|
|
60
|
-
* Return the value for the 'aria-
|
|
57
|
+
* Return the value for the 'aria-valuetext' attribute.
|
|
61
58
|
* @param rating - Current rating value.
|
|
62
59
|
* @param maxRating - maxRating value.
|
|
63
60
|
*/
|
|
@@ -134,7 +131,7 @@ export type RatingWidget = Widget<RatingProps, RatingState, object, RatingAction
|
|
|
134
131
|
*/
|
|
135
132
|
export declare function getRatingDefaultConfig(): {
|
|
136
133
|
/**
|
|
137
|
-
* Return the value for the 'aria-
|
|
134
|
+
* Return the value for the 'aria-valuetext' attribute.
|
|
138
135
|
* @param rating - Current rating value.
|
|
139
136
|
* @param maxRating - maxRating value.
|
|
140
137
|
*/
|
|
@@ -184,10 +181,6 @@ export declare function getRatingDefaultConfig(): {
|
|
|
184
181
|
* If the component is disabled, `tabindex` will still be set to `-1`.
|
|
185
182
|
*/
|
|
186
183
|
tabindex: number;
|
|
187
|
-
/**
|
|
188
|
-
* Classname to be applied on the rating container
|
|
189
|
-
*/
|
|
190
|
-
className: string;
|
|
191
184
|
/**
|
|
192
185
|
* The template to override the way each star is displayed.
|
|
193
186
|
*/
|
|
@@ -200,6 +193,7 @@ export declare function getRatingDefaultConfig(): {
|
|
|
200
193
|
* The aria labelled by
|
|
201
194
|
*/
|
|
202
195
|
ariaLabelledBy: string;
|
|
196
|
+
className: string;
|
|
203
197
|
};
|
|
204
198
|
/**
|
|
205
199
|
* Create a RatingWidget with given config props
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { HasFocus } from './services/focustrack';
|
|
2
2
|
import type { PropsConfig } from './services/stores';
|
|
3
3
|
import type { Widget } from './types';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* the class to attach to the select DOM element
|
|
7
|
-
*/
|
|
8
|
-
className: string;
|
|
4
|
+
import type { WidgetsCommonPropsAndState } from './commonProps';
|
|
5
|
+
export interface SelectCommonPropsAndState<Item> extends WidgetsCommonPropsAndState {
|
|
9
6
|
/**
|
|
10
7
|
* List of selected items
|
|
11
8
|
*/
|
|
@@ -22,6 +22,11 @@ export declare function isFunction(value: any): value is (...args: any[]) => any
|
|
|
22
22
|
* @returns true if the value is a string
|
|
23
23
|
*/
|
|
24
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[];
|
|
25
30
|
/**
|
|
26
31
|
* Clamp the value based on a maximum and optional minimum
|
|
27
32
|
* @param value the value to check
|
|
@@ -30,6 +30,11 @@ export function isFunction(value) {
|
|
|
30
30
|
export function isString(value) {
|
|
31
31
|
return typeof value === 'string';
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* an array type guard
|
|
35
|
+
* @returns true if the value is an array
|
|
36
|
+
*/
|
|
37
|
+
export const isArray = Array.isArray;
|
|
33
38
|
// TODO should we check that max > min?
|
|
34
39
|
/**
|
|
35
40
|
* Clamp the value based on a maximum and optional minimum
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PropsConfig } from './stores';
|
|
2
|
+
export interface IntersectionProps {
|
|
3
|
+
/**
|
|
4
|
+
* elements to observe
|
|
5
|
+
*/
|
|
6
|
+
elements: HTMLElement[];
|
|
7
|
+
/**
|
|
8
|
+
* IntersectionObserverInit used in the IntersectionObserver
|
|
9
|
+
*
|
|
10
|
+
* See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver#options)
|
|
11
|
+
*/
|
|
12
|
+
options: Partial<IntersectionObserverInit> | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare const createIntersection: (config?: PropsConfig<IntersectionProps>) => {
|
|
15
|
+
/**
|
|
16
|
+
* Readable of observed elements
|
|
17
|
+
*/
|
|
18
|
+
elements$: import("@amadeus-it-group/tansu").ReadableSignal<HTMLElement[]>;
|
|
19
|
+
/**
|
|
20
|
+
* Store of map that contains the visible elements (for the key) and the corresponding entries
|
|
21
|
+
*
|
|
22
|
+
* See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)
|
|
23
|
+
*/
|
|
24
|
+
visibleElements$: import("@amadeus-it-group/tansu").ReadableSignal<Map<Element, IntersectionObserverEntry>>;
|
|
25
|
+
patch: <U extends Partial<IntersectionProps>>(storesValues?: void | U | undefined) => void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { asReadable, derived } from '@amadeus-it-group/tansu';
|
|
2
|
+
import { noop } from '../utils';
|
|
3
|
+
import { writablesForProps } from './stores';
|
|
4
|
+
const defaultValues = {
|
|
5
|
+
elements: [],
|
|
6
|
+
options: undefined,
|
|
7
|
+
};
|
|
8
|
+
export const createIntersection = (config) => {
|
|
9
|
+
const [{ elements$, options$ }, patch] = writablesForProps(defaultValues, config);
|
|
10
|
+
const visibleElements$ = derived([elements$, options$], ([elements, options], set) => {
|
|
11
|
+
if (elements.length) {
|
|
12
|
+
const visibleElements = new Map();
|
|
13
|
+
const observer = new IntersectionObserver((entries) => {
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const { target, isIntersecting } = entry;
|
|
16
|
+
if (isIntersecting) {
|
|
17
|
+
visibleElements.set(target, entry);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
visibleElements.delete(target);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
set(visibleElements);
|
|
24
|
+
}, options);
|
|
25
|
+
for (const element of elements) {
|
|
26
|
+
observer.observe(element);
|
|
27
|
+
}
|
|
28
|
+
return () => {
|
|
29
|
+
observer.disconnect();
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return noop;
|
|
33
|
+
}, new Map());
|
|
34
|
+
return {
|
|
35
|
+
/**
|
|
36
|
+
* Readable of observed elements
|
|
37
|
+
*/
|
|
38
|
+
elements$: asReadable(elements$),
|
|
39
|
+
/**
|
|
40
|
+
* Store of map that contains the visible elements (for the key) and the corresponding entries
|
|
41
|
+
*
|
|
42
|
+
* See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserverEntry)
|
|
43
|
+
*/
|
|
44
|
+
visibleElements$: asReadable(visibleElements$),
|
|
45
|
+
patch,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { compareDomOrder } from './sortUtils';
|
|
2
|
+
import { registrationArray } from './directiveUtils';
|
|
3
|
+
import { computed } from '@amadeus-it-group/tansu';
|
|
4
|
+
// cf https://html.spec.whatwg.org/multipage/input.html#concept-input-apply
|
|
5
|
+
const textInputTypes = new Set(['text', 'search', 'url', 'tel', 'password']);
|
|
6
|
+
const isTextInput = (element) => element instanceof HTMLInputElement && textInputTypes.has(element.type);
|
|
7
|
+
export const createNavManager = () => {
|
|
8
|
+
const array$ = registrationArray();
|
|
9
|
+
const sortedArray$ = computed(() => [...array$()].sort(compareDomOrder));
|
|
10
|
+
const directive = (element) => {
|
|
11
|
+
const onKeyDown = (event) => {
|
|
12
|
+
let move = 0;
|
|
13
|
+
switch (event.key) {
|
|
14
|
+
case 'ArrowLeft':
|
|
15
|
+
move = -1;
|
|
16
|
+
break;
|
|
17
|
+
case 'ArrowRight':
|
|
18
|
+
move = 1;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
if (isTextInput(event.target)) {
|
|
22
|
+
const cursorPosition = event.target.selectionStart === event.target.selectionEnd ? event.target.selectionStart : null;
|
|
23
|
+
if ((cursorPosition !== 0 && move < 0) || (cursorPosition !== event.target.value.length && move > 0)) {
|
|
24
|
+
move = 0;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (move != 0) {
|
|
28
|
+
const array = sortedArray$();
|
|
29
|
+
const currentIndex = array.indexOf(element);
|
|
30
|
+
const newIndex = currentIndex + move;
|
|
31
|
+
if (newIndex < array.length && newIndex >= 0) {
|
|
32
|
+
const newItem = array[newIndex];
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
newItem.focus();
|
|
35
|
+
if (isTextInput(newItem)) {
|
|
36
|
+
const position = move < 0 ? newItem.value.length : 0;
|
|
37
|
+
newItem.setSelectionRange(position, position);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
element.addEventListener('keydown', onKeyDown);
|
|
43
|
+
const unregister = array$.register(element);
|
|
44
|
+
return {
|
|
45
|
+
destroy() {
|
|
46
|
+
element.removeEventListener('keydown', onKeyDown);
|
|
47
|
+
unregister();
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
return { directive };
|
|
52
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const compareDefault = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
|
|
2
|
+
export const compareDomOrder = (element1, element2) => {
|
|
3
|
+
if (element1 === element2) {
|
|
4
|
+
return 0;
|
|
5
|
+
}
|
|
6
|
+
const result = element1.compareDocumentPosition(element2);
|
|
7
|
+
if (result & Node.DOCUMENT_POSITION_FOLLOWING) {
|
|
8
|
+
return -1;
|
|
9
|
+
}
|
|
10
|
+
else if (result & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
11
|
+
return 1;
|
|
12
|
+
}
|
|
13
|
+
throw new Error('failed to compare elements');
|
|
14
|
+
};
|