@agnos-ui/core 0.0.1-alpha.0
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 +15 -0
- package/dist/lib/accordion.d.ts +318 -0
- package/dist/lib/accordion.js +263 -0
- package/dist/lib/alert.d.ts +100 -0
- package/dist/lib/alert.js +66 -0
- package/dist/lib/config.d.ts +71 -0
- package/dist/lib/config.js +53 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.js +11 -0
- package/dist/lib/modal/modal.d.ts +318 -0
- package/dist/lib/modal/modal.js +156 -0
- package/dist/lib/modal/scrollbars.d.ts +2 -0
- package/dist/lib/modal/scrollbars.js +27 -0
- package/dist/lib/pagination.d.ts +464 -0
- package/dist/lib/pagination.js +148 -0
- package/dist/lib/pagination.utils.d.ts +8 -0
- package/dist/lib/pagination.utils.js +110 -0
- package/dist/lib/rating.d.ts +209 -0
- package/dist/lib/rating.js +141 -0
- package/dist/lib/select.d.ts +199 -0
- package/dist/lib/select.js +240 -0
- package/dist/lib/services/checks.d.ts +32 -0
- package/dist/lib/services/checks.js +43 -0
- package/dist/lib/services/directiveUtils.d.ts +95 -0
- package/dist/lib/services/directiveUtils.js +190 -0
- package/dist/lib/services/focustrack.d.ts +19 -0
- package/dist/lib/services/focustrack.js +46 -0
- package/dist/lib/services/index.d.ts +6 -0
- package/dist/lib/services/index.js +6 -0
- package/dist/lib/services/portal.d.ts +6 -0
- package/dist/lib/services/portal.js +33 -0
- package/dist/lib/services/siblingsInert.d.ts +7 -0
- package/dist/lib/services/siblingsInert.js +40 -0
- package/dist/lib/services/stores.d.ts +140 -0
- package/dist/lib/services/stores.js +219 -0
- package/dist/lib/services/writables.d.ts +7 -0
- package/dist/lib/services/writables.js +16 -0
- package/dist/lib/transitions/baseTransitions.d.ts +136 -0
- package/dist/lib/transitions/baseTransitions.js +171 -0
- package/dist/lib/transitions/bootstrap/collapse.d.ts +2 -0
- package/dist/lib/transitions/bootstrap/collapse.js +15 -0
- package/dist/lib/transitions/bootstrap/fade.d.ts +1 -0
- package/dist/lib/transitions/bootstrap/fade.js +7 -0
- package/dist/lib/transitions/bootstrap/index.d.ts +2 -0
- package/dist/lib/transitions/bootstrap/index.js +2 -0
- package/dist/lib/transitions/collapse.d.ts +29 -0
- package/dist/lib/transitions/collapse.js +39 -0
- package/dist/lib/transitions/cssTransitions.d.ts +15 -0
- package/dist/lib/transitions/cssTransitions.js +38 -0
- package/dist/lib/transitions/index.d.ts +5 -0
- package/dist/lib/transitions/index.js +5 -0
- package/dist/lib/transitions/simpleClassTransition.d.ts +29 -0
- package/dist/lib/transitions/simpleClassTransition.js +28 -0
- package/dist/lib/transitions/utils.d.ts +20 -0
- package/dist/lib/transitions/utils.js +83 -0
- package/dist/lib/tsdoc-metadata.json +11 -0
- package/dist/lib/types.d.ts +58 -0
- package/dist/lib/types.js +7 -0
- package/dist/lib/utils.d.ts +2 -0
- package/dist/lib/utils.js +2 -0
- package/package.json +52 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// Utility functions
|
|
2
|
+
function _applyPagination(page, maxSize) {
|
|
3
|
+
const pp = Math.ceil(page / maxSize) - 1;
|
|
4
|
+
const start = pp * maxSize;
|
|
5
|
+
// console.log('start', start, 'pp', pp, 'page', page, 'maxSize', maxSize);
|
|
6
|
+
const end = start + maxSize;
|
|
7
|
+
return [start, end];
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Appends ellipses and first/last page number to the displayed pages
|
|
11
|
+
* @param start - the first page number
|
|
12
|
+
* @param end - the last page number
|
|
13
|
+
* @param ellipses - apply ellipses
|
|
14
|
+
* @param pages - the pages to apply the function to
|
|
15
|
+
* @param pageCount - the total number of pages
|
|
16
|
+
*/
|
|
17
|
+
function _applyEllipses(start, end, ellipses, pages, pageCount) {
|
|
18
|
+
if (ellipses) {
|
|
19
|
+
if (start > 0) {
|
|
20
|
+
// The first page will always be included. If the displayed range
|
|
21
|
+
// starts after the third page, then add ellipsis. But if the range
|
|
22
|
+
// starts on the third page, then add the second page instead of
|
|
23
|
+
// an ellipsis, because the ellipsis would only hide a single page.
|
|
24
|
+
if (start > 2) {
|
|
25
|
+
pages.unshift(-1);
|
|
26
|
+
}
|
|
27
|
+
else if (start === 2) {
|
|
28
|
+
pages.unshift(2);
|
|
29
|
+
}
|
|
30
|
+
pages.unshift(1);
|
|
31
|
+
}
|
|
32
|
+
if (end < pageCount) {
|
|
33
|
+
// The last page will always be included. If the displayed range
|
|
34
|
+
// ends before the third-last page, then add ellipsis. But if the range
|
|
35
|
+
// ends on third-last page, then add the second-last page instead of
|
|
36
|
+
// an ellipsis, because the ellipsis would only hide a single page.
|
|
37
|
+
if (end < pageCount - 2) {
|
|
38
|
+
pages.push(-1);
|
|
39
|
+
}
|
|
40
|
+
else if (end === pageCount - 2) {
|
|
41
|
+
pages.push(pageCount - 1);
|
|
42
|
+
}
|
|
43
|
+
pages.push(pageCount);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Rotates page numbers based on maxSize items visible.
|
|
49
|
+
* Currently selected page stays in the middle:
|
|
50
|
+
*
|
|
51
|
+
* Ex. for selected page = 6:
|
|
52
|
+
* [5,*6*,7] for maxSize = 3
|
|
53
|
+
* [4,5,*6*,7] for maxSize = 4
|
|
54
|
+
*
|
|
55
|
+
* @param page - the page number
|
|
56
|
+
* @param maxSize - the max size
|
|
57
|
+
* @param pageCount - the page count
|
|
58
|
+
* @returns the rotated page numbers
|
|
59
|
+
*/
|
|
60
|
+
function _applyRotation(page, maxSize, pageCount) {
|
|
61
|
+
let start = 0;
|
|
62
|
+
let end = pageCount;
|
|
63
|
+
const leftOffset = Math.floor(maxSize / 2);
|
|
64
|
+
const rightOffset = maxSize % 2 === 0 ? leftOffset - 1 : leftOffset;
|
|
65
|
+
if (page <= leftOffset) {
|
|
66
|
+
// very beginning, no rotation -> [0..maxSize]
|
|
67
|
+
end = maxSize;
|
|
68
|
+
}
|
|
69
|
+
else if (pageCount - page < leftOffset) {
|
|
70
|
+
// very end, no rotation -> [len-maxSize..len]
|
|
71
|
+
start = pageCount - maxSize;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
// rotate
|
|
75
|
+
start = page - leftOffset - 1;
|
|
76
|
+
end = page + rightOffset;
|
|
77
|
+
}
|
|
78
|
+
return [start, end];
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* This is the pagination algorithm used by ng-bootstrap. While this is not the default implementation of our widget, we export it to ease the migration from ng-bootstrap pagination.
|
|
82
|
+
* @param maxSize - the max size
|
|
83
|
+
* @param rotate - rotate the pages
|
|
84
|
+
* @param ellipses - enable ellipses
|
|
85
|
+
* @returns the pages
|
|
86
|
+
*/
|
|
87
|
+
export function ngBootstrapPagination(maxSize, rotate, ellipses) {
|
|
88
|
+
return function (page, pageCount) {
|
|
89
|
+
let pages = [];
|
|
90
|
+
for (let i = 1; i <= pageCount; i++) {
|
|
91
|
+
pages.push(i);
|
|
92
|
+
}
|
|
93
|
+
// apply maxSize if necessary
|
|
94
|
+
if (maxSize > 0 && pageCount > maxSize) {
|
|
95
|
+
let start = 0;
|
|
96
|
+
let end = pageCount;
|
|
97
|
+
// either paginating or rotating page numbers
|
|
98
|
+
if (rotate) {
|
|
99
|
+
[start, end] = _applyRotation(page, maxSize, pageCount);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
[start, end] = _applyPagination(page, maxSize);
|
|
103
|
+
}
|
|
104
|
+
pages = pages.slice(start, end);
|
|
105
|
+
// adding ellipses
|
|
106
|
+
_applyEllipses(start, end, ellipses, pages, pageCount);
|
|
107
|
+
}
|
|
108
|
+
return pages;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { PropsConfig } from './services';
|
|
2
|
+
import type { SlotContent, Widget } from './types';
|
|
3
|
+
export interface StarContext {
|
|
4
|
+
/**
|
|
5
|
+
* indicates how much the current star is filled, from 0 to 100
|
|
6
|
+
*/
|
|
7
|
+
fill: number;
|
|
8
|
+
/**
|
|
9
|
+
* the position of the star in the rating
|
|
10
|
+
*/
|
|
11
|
+
index: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RatingCommonPropsAndState {
|
|
14
|
+
/**
|
|
15
|
+
* The current rating. Could be a decimal value like `3.75`.
|
|
16
|
+
*/
|
|
17
|
+
rating: number;
|
|
18
|
+
/**
|
|
19
|
+
* The maximum rating that can be given.
|
|
20
|
+
*/
|
|
21
|
+
maxRating: number;
|
|
22
|
+
/**
|
|
23
|
+
* If `true`, the rating is disabled.
|
|
24
|
+
*/
|
|
25
|
+
disabled: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* If `true`, the rating can't be changed.
|
|
28
|
+
*/
|
|
29
|
+
readonly: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Define if the rating can be reset.
|
|
32
|
+
*
|
|
33
|
+
* If set to true, the user can 'unset' the rating value by cliking on the current rating value.
|
|
34
|
+
*/
|
|
35
|
+
resettable: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Allows setting a custom rating tabindex.
|
|
38
|
+
* If the component is disabled, `tabindex` will still be set to `-1`.
|
|
39
|
+
*/
|
|
40
|
+
tabindex: number;
|
|
41
|
+
/**
|
|
42
|
+
* Classname to be applied on the rating container
|
|
43
|
+
*/
|
|
44
|
+
className: string;
|
|
45
|
+
/**
|
|
46
|
+
* The template to override the way each star is displayed.
|
|
47
|
+
*/
|
|
48
|
+
slotStar: SlotContent<StarContext>;
|
|
49
|
+
/**
|
|
50
|
+
* The aria label
|
|
51
|
+
*/
|
|
52
|
+
ariaLabel: string;
|
|
53
|
+
/**
|
|
54
|
+
* The aria labelled by
|
|
55
|
+
*/
|
|
56
|
+
ariaLabelledBy: string;
|
|
57
|
+
}
|
|
58
|
+
export interface RatingProps extends RatingCommonPropsAndState {
|
|
59
|
+
/**
|
|
60
|
+
* Return the value for the 'aria-value' attribute.
|
|
61
|
+
* @param rating - Current rating value.
|
|
62
|
+
* @param maxRating - maxRating value.
|
|
63
|
+
*/
|
|
64
|
+
ariaValueTextFn: (rating: number, maxRating: number) => string;
|
|
65
|
+
/**
|
|
66
|
+
* An event emitted when the rating is changed.
|
|
67
|
+
*
|
|
68
|
+
* Event payload is equal to the newly selected rating.
|
|
69
|
+
*/
|
|
70
|
+
onRatingChange: (rating: number) => void;
|
|
71
|
+
/**
|
|
72
|
+
* An event emitted when the user is hovering over a given rating.
|
|
73
|
+
*
|
|
74
|
+
* Event payload is equal to the rating being hovered over.
|
|
75
|
+
*/
|
|
76
|
+
onHover: (rating: number) => void;
|
|
77
|
+
/**
|
|
78
|
+
* An event emitted when the user stops hovering over a given rating.
|
|
79
|
+
*
|
|
80
|
+
* Event payload is equal to the rating of the last item being hovered over.
|
|
81
|
+
*/
|
|
82
|
+
onLeave: (rating: number) => void;
|
|
83
|
+
}
|
|
84
|
+
export interface RatingState extends RatingCommonPropsAndState {
|
|
85
|
+
/**
|
|
86
|
+
* the aria value of the rating
|
|
87
|
+
*/
|
|
88
|
+
ariaValueText: string;
|
|
89
|
+
/**
|
|
90
|
+
* the visible value of the rating (it changes when hovering over the rating even though the real value did not change)
|
|
91
|
+
*/
|
|
92
|
+
visibleRating: number;
|
|
93
|
+
/**
|
|
94
|
+
* is the rating interactive i.e. listening to hover, click and keyboard events
|
|
95
|
+
*/
|
|
96
|
+
isInteractive: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* the list of stars
|
|
99
|
+
*/
|
|
100
|
+
stars: StarContext[];
|
|
101
|
+
}
|
|
102
|
+
export interface RatingActions {
|
|
103
|
+
/**
|
|
104
|
+
* Method to be used when a star is clicked.
|
|
105
|
+
*
|
|
106
|
+
* To be used in the onclick event of a star
|
|
107
|
+
* @param index - Star index, starting from 1
|
|
108
|
+
*/
|
|
109
|
+
click(index: number): void;
|
|
110
|
+
/**
|
|
111
|
+
* Method to be used when the mouse enter in a star.
|
|
112
|
+
*
|
|
113
|
+
* To be used in the onmouseenter of a star
|
|
114
|
+
* @param index - Star index, starting from 1
|
|
115
|
+
*/
|
|
116
|
+
hover(index: number): void;
|
|
117
|
+
/**
|
|
118
|
+
* Method to be used when the mouse leave the widget.
|
|
119
|
+
*
|
|
120
|
+
* To be used in the onmouseleave of the rating container
|
|
121
|
+
*/
|
|
122
|
+
leave(): void;
|
|
123
|
+
/**
|
|
124
|
+
* Method to be used to handle the keyboard.
|
|
125
|
+
*
|
|
126
|
+
* To be used in the onkeydown of the rating container
|
|
127
|
+
*/
|
|
128
|
+
handleKey(event: KeyboardEvent): void;
|
|
129
|
+
}
|
|
130
|
+
export type RatingWidget = Widget<RatingProps, RatingState, object, RatingActions>;
|
|
131
|
+
/**
|
|
132
|
+
* Returns a shallow copy of the default rating config.
|
|
133
|
+
* @returns a copy of the default config
|
|
134
|
+
*/
|
|
135
|
+
export declare function getRatingDefaultConfig(): {
|
|
136
|
+
/**
|
|
137
|
+
* Return the value for the 'aria-value' attribute.
|
|
138
|
+
* @param rating - Current rating value.
|
|
139
|
+
* @param maxRating - maxRating value.
|
|
140
|
+
*/
|
|
141
|
+
ariaValueTextFn: (rating: number, maxRating: number) => string;
|
|
142
|
+
/**
|
|
143
|
+
* An event emitted when the rating is changed.
|
|
144
|
+
*
|
|
145
|
+
* Event payload is equal to the newly selected rating.
|
|
146
|
+
*/
|
|
147
|
+
onRatingChange: (rating: number) => void;
|
|
148
|
+
/**
|
|
149
|
+
* An event emitted when the user is hovering over a given rating.
|
|
150
|
+
*
|
|
151
|
+
* Event payload is equal to the rating being hovered over.
|
|
152
|
+
*/
|
|
153
|
+
onHover: (rating: number) => void;
|
|
154
|
+
/**
|
|
155
|
+
* An event emitted when the user stops hovering over a given rating.
|
|
156
|
+
*
|
|
157
|
+
* Event payload is equal to the rating of the last item being hovered over.
|
|
158
|
+
*/
|
|
159
|
+
onLeave: (rating: number) => void;
|
|
160
|
+
/**
|
|
161
|
+
* The current rating. Could be a decimal value like `3.75`.
|
|
162
|
+
*/
|
|
163
|
+
rating: number;
|
|
164
|
+
/**
|
|
165
|
+
* The maximum rating that can be given.
|
|
166
|
+
*/
|
|
167
|
+
maxRating: number;
|
|
168
|
+
/**
|
|
169
|
+
* If `true`, the rating is disabled.
|
|
170
|
+
*/
|
|
171
|
+
disabled: boolean;
|
|
172
|
+
/**
|
|
173
|
+
* If `true`, the rating can't be changed.
|
|
174
|
+
*/
|
|
175
|
+
readonly: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Define if the rating can be reset.
|
|
178
|
+
*
|
|
179
|
+
* If set to true, the user can 'unset' the rating value by cliking on the current rating value.
|
|
180
|
+
*/
|
|
181
|
+
resettable: boolean;
|
|
182
|
+
/**
|
|
183
|
+
* Allows setting a custom rating tabindex.
|
|
184
|
+
* If the component is disabled, `tabindex` will still be set to `-1`.
|
|
185
|
+
*/
|
|
186
|
+
tabindex: number;
|
|
187
|
+
/**
|
|
188
|
+
* Classname to be applied on the rating container
|
|
189
|
+
*/
|
|
190
|
+
className: string;
|
|
191
|
+
/**
|
|
192
|
+
* The template to override the way each star is displayed.
|
|
193
|
+
*/
|
|
194
|
+
slotStar: SlotContent<StarContext>;
|
|
195
|
+
/**
|
|
196
|
+
* The aria label
|
|
197
|
+
*/
|
|
198
|
+
ariaLabel: string;
|
|
199
|
+
/**
|
|
200
|
+
* The aria labelled by
|
|
201
|
+
*/
|
|
202
|
+
ariaLabelledBy: string;
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Create a RatingWidget with given config props
|
|
206
|
+
* @param config - an optional alert config
|
|
207
|
+
* @returns a RatingWidget
|
|
208
|
+
*/
|
|
209
|
+
export declare function createRating(config?: PropsConfig<RatingProps>): RatingWidget;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { computed, writable } from '@amadeus-it-group/tansu';
|
|
2
|
+
import { INVALID_VALUE, bindableDerived, stateStores, writablesForProps } from './services';
|
|
3
|
+
import { isNumber } from './services/checks';
|
|
4
|
+
import { typeBoolean, typeFunction, typeNumber, typeString } from './services/writables';
|
|
5
|
+
// TODO use getValueInRange
|
|
6
|
+
function adjustRating(rating, maxRating) {
|
|
7
|
+
return Math.max(Math.min(rating, maxRating), 0);
|
|
8
|
+
}
|
|
9
|
+
const noop = () => { };
|
|
10
|
+
const defaultConfig = {
|
|
11
|
+
rating: 0,
|
|
12
|
+
tabindex: 0,
|
|
13
|
+
maxRating: 10,
|
|
14
|
+
disabled: false,
|
|
15
|
+
readonly: false,
|
|
16
|
+
resettable: true,
|
|
17
|
+
ariaValueTextFn: (rating, maxRating) => `${rating} out of ${maxRating}`,
|
|
18
|
+
onHover: noop,
|
|
19
|
+
onLeave: noop,
|
|
20
|
+
onRatingChange: noop,
|
|
21
|
+
className: '',
|
|
22
|
+
slotStar: ({ fill }) => String.fromCharCode(fill === 100 ? 9733 : 9734),
|
|
23
|
+
ariaLabel: 'Rating',
|
|
24
|
+
ariaLabelledBy: '',
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Returns a shallow copy of the default rating config.
|
|
28
|
+
* @returns a copy of the default config
|
|
29
|
+
*/
|
|
30
|
+
export function getRatingDefaultConfig() {
|
|
31
|
+
return { ...defaultConfig };
|
|
32
|
+
}
|
|
33
|
+
// TODO export normalize function in utils and test them.
|
|
34
|
+
const configValidator = {
|
|
35
|
+
rating: typeNumber,
|
|
36
|
+
tabindex: typeNumber,
|
|
37
|
+
maxRating: { normalizeValue: (value) => (isNumber(value) ? Math.max(0, value) : INVALID_VALUE) },
|
|
38
|
+
disabled: typeBoolean,
|
|
39
|
+
readonly: typeBoolean,
|
|
40
|
+
resettable: typeBoolean,
|
|
41
|
+
ariaValueTextFn: typeFunction,
|
|
42
|
+
onHover: typeFunction,
|
|
43
|
+
onLeave: typeFunction,
|
|
44
|
+
onRatingChange: typeFunction,
|
|
45
|
+
className: typeString,
|
|
46
|
+
ariaLabel: typeString,
|
|
47
|
+
ariaLabelledBy: typeString,
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Create a RatingWidget with given config props
|
|
51
|
+
* @param config - an optional alert config
|
|
52
|
+
* @returns a RatingWidget
|
|
53
|
+
*/
|
|
54
|
+
export function createRating(config) {
|
|
55
|
+
const [{
|
|
56
|
+
// dirty inputs that need adjustment:
|
|
57
|
+
rating$: _dirtyRating$, tabindex$: _dirtyTabindex$,
|
|
58
|
+
// clean inputs with value validation:
|
|
59
|
+
ariaValueTextFn$, onHover$, onLeave$, onRatingChange$, ...stateProps }, patch,] = writablesForProps(defaultConfig, config, configValidator);
|
|
60
|
+
const { maxRating$, disabled$, readonly$, resettable$ } = stateProps;
|
|
61
|
+
// clean inputs adjustment to valid range
|
|
62
|
+
const tabindex$ = computed(() => (disabled$() ? -1 : _dirtyTabindex$()));
|
|
63
|
+
const rating$ = bindableDerived(onRatingChange$, [_dirtyRating$, maxRating$], ([dirtyRating, maxRating]) => adjustRating(dirtyRating, maxRating));
|
|
64
|
+
// internal inputs
|
|
65
|
+
const _hoveredRating$ = writable(0);
|
|
66
|
+
// computed
|
|
67
|
+
const isInteractive$ = computed(() => !disabled$() && !readonly$());
|
|
68
|
+
const visibleRating$ = computed(() => {
|
|
69
|
+
const rating = rating$(); // call rating unconditionnally (for the bindableDerived to stay active)
|
|
70
|
+
const hoveredRating = _hoveredRating$();
|
|
71
|
+
return hoveredRating !== 0 ? hoveredRating : rating;
|
|
72
|
+
});
|
|
73
|
+
const ariaValueText$ = computed(() => ariaValueTextFn$()(visibleRating$(), maxRating$()));
|
|
74
|
+
const stars$ = computed(() => {
|
|
75
|
+
const visibleRating = visibleRating$();
|
|
76
|
+
return Array.from({ length: maxRating$() }, (_v, i) => ({
|
|
77
|
+
fill: Math.round(Math.max(Math.min(visibleRating - i, 1), 0) * 100),
|
|
78
|
+
index: i,
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
...stateStores({
|
|
83
|
+
ariaValueText$,
|
|
84
|
+
isInteractive$,
|
|
85
|
+
rating$,
|
|
86
|
+
stars$,
|
|
87
|
+
tabindex$,
|
|
88
|
+
visibleRating$,
|
|
89
|
+
...stateProps,
|
|
90
|
+
}),
|
|
91
|
+
patch,
|
|
92
|
+
actions: {
|
|
93
|
+
click: (index) => {
|
|
94
|
+
if (isInteractive$() && index > 0 && index <= maxRating$()) {
|
|
95
|
+
patch({ rating: rating$() === index && resettable$() ? 0 : index });
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
hover: (index) => {
|
|
99
|
+
if (isInteractive$() && index > 0 && index <= maxRating$()) {
|
|
100
|
+
_hoveredRating$.set(index);
|
|
101
|
+
onHover$()(index);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
leave: () => {
|
|
105
|
+
if (isInteractive$()) {
|
|
106
|
+
onLeave$()(_hoveredRating$());
|
|
107
|
+
_hoveredRating$.set(0);
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
handleKey(event) {
|
|
111
|
+
if (isInteractive$()) {
|
|
112
|
+
const { key } = event;
|
|
113
|
+
switch (key) {
|
|
114
|
+
case 'ArrowLeft':
|
|
115
|
+
case 'ArrowDown':
|
|
116
|
+
patch({ rating: rating$() - 1 });
|
|
117
|
+
break;
|
|
118
|
+
case 'ArrowRight':
|
|
119
|
+
case 'ArrowUp':
|
|
120
|
+
patch({ rating: rating$() + 1 });
|
|
121
|
+
break;
|
|
122
|
+
case 'Home':
|
|
123
|
+
case 'PageDown':
|
|
124
|
+
patch({ rating: 0 });
|
|
125
|
+
break;
|
|
126
|
+
case 'End':
|
|
127
|
+
case 'PageUp':
|
|
128
|
+
patch({ rating: maxRating$() });
|
|
129
|
+
break;
|
|
130
|
+
default:
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
event.preventDefault();
|
|
134
|
+
event.stopPropagation();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
directives: {},
|
|
139
|
+
api: {},
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import type { HasFocus } from './services/focustrack';
|
|
2
|
+
import type { PropsConfig } from './services/stores';
|
|
3
|
+
import type { Widget } from './types';
|
|
4
|
+
export interface SelectCommonPropsAndState<Item> {
|
|
5
|
+
/**
|
|
6
|
+
* the class to attach to the select DOM element
|
|
7
|
+
*/
|
|
8
|
+
className: string;
|
|
9
|
+
/**
|
|
10
|
+
* List of selected items
|
|
11
|
+
*/
|
|
12
|
+
selected: Item[];
|
|
13
|
+
/**
|
|
14
|
+
* Filtered text to be display in the filter input
|
|
15
|
+
*/
|
|
16
|
+
filterText: string;
|
|
17
|
+
/**
|
|
18
|
+
* true if the select is disabled
|
|
19
|
+
*/
|
|
20
|
+
disabled: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* true if the select is open
|
|
23
|
+
*/
|
|
24
|
+
opened: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* true if a loading process is being done
|
|
27
|
+
*/
|
|
28
|
+
loading: boolean;
|
|
29
|
+
}
|
|
30
|
+
export interface SelectProps<T> extends SelectCommonPropsAndState<T> {
|
|
31
|
+
/**
|
|
32
|
+
* List of available items for the dropdown
|
|
33
|
+
*/
|
|
34
|
+
items: T[];
|
|
35
|
+
/**
|
|
36
|
+
* Custom function to filter an item.
|
|
37
|
+
* By default, item is considered as a string, and the function returns true if the text is found
|
|
38
|
+
*/
|
|
39
|
+
matchFn(item: T, text: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Custom function to get the id of an item
|
|
42
|
+
* By default, the item is returned
|
|
43
|
+
*/
|
|
44
|
+
itemId(item: T): string;
|
|
45
|
+
/**
|
|
46
|
+
* Callback called when the text filter change
|
|
47
|
+
* @param text - Filtered text
|
|
48
|
+
*/
|
|
49
|
+
onFilterTextChange?(text: string): void;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Item representation built from the items provided in parameters
|
|
53
|
+
*/
|
|
54
|
+
export interface ItemCtx<T> {
|
|
55
|
+
/**
|
|
56
|
+
* Original item given in the parameters
|
|
57
|
+
*/
|
|
58
|
+
item: T;
|
|
59
|
+
/**
|
|
60
|
+
* Unique id to identify the item
|
|
61
|
+
*/
|
|
62
|
+
id: string;
|
|
63
|
+
/**
|
|
64
|
+
* Specify if the item is checked
|
|
65
|
+
*/
|
|
66
|
+
selected: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Select the item
|
|
69
|
+
*/
|
|
70
|
+
select(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Unselect the item
|
|
73
|
+
*/
|
|
74
|
+
unselect(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Toggle the item selection
|
|
77
|
+
*/
|
|
78
|
+
toggle(): void;
|
|
79
|
+
}
|
|
80
|
+
export interface SelectState<Item> extends SelectCommonPropsAndState<Item> {
|
|
81
|
+
/**
|
|
82
|
+
* List of visible items displayed in the menu
|
|
83
|
+
*/
|
|
84
|
+
visible: ItemCtx<Item>[];
|
|
85
|
+
/**
|
|
86
|
+
* Highlighted item context.
|
|
87
|
+
* It is designed to define the highlighted item in the dropdown menu
|
|
88
|
+
*/
|
|
89
|
+
highlighted: ItemCtx<Item> | undefined;
|
|
90
|
+
}
|
|
91
|
+
export interface SelectApi<Item> {
|
|
92
|
+
/**
|
|
93
|
+
* Clear all the selected items
|
|
94
|
+
*/
|
|
95
|
+
clear(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Clear the filter text
|
|
98
|
+
*/
|
|
99
|
+
clearText(): void;
|
|
100
|
+
/**
|
|
101
|
+
* Highlight the given item, if there is a corresponding match among the visible list
|
|
102
|
+
*/
|
|
103
|
+
highlight(item: Item): void;
|
|
104
|
+
/**
|
|
105
|
+
* Highlight the first item among the visible list
|
|
106
|
+
*/
|
|
107
|
+
highlightFirst(): void;
|
|
108
|
+
/**
|
|
109
|
+
* Highlight the previous item among the visible list
|
|
110
|
+
* Loop to the last item if needed
|
|
111
|
+
*/
|
|
112
|
+
highlightPrevious(): void;
|
|
113
|
+
/**
|
|
114
|
+
* Highlight the next item among the visible list.
|
|
115
|
+
* Loop to the first item if needed
|
|
116
|
+
*/
|
|
117
|
+
highlightNext(): void;
|
|
118
|
+
/**
|
|
119
|
+
* Highlight the last item among the visible list
|
|
120
|
+
*/
|
|
121
|
+
highlightLast(): void;
|
|
122
|
+
/**
|
|
123
|
+
* Focus the provided item among the selected list.
|
|
124
|
+
* The focus feature is designed to know what item must be focused in the UI, i.e. among the badge elements.
|
|
125
|
+
*/
|
|
126
|
+
focus(item: Item): void;
|
|
127
|
+
/**
|
|
128
|
+
* Focus the first element
|
|
129
|
+
*/
|
|
130
|
+
focusFirst(): void;
|
|
131
|
+
/**
|
|
132
|
+
* Focus the previous element. If no element was focused before the call, nothing happens.
|
|
133
|
+
*/
|
|
134
|
+
focusPrevious(): void;
|
|
135
|
+
/**
|
|
136
|
+
* Focus the next element. If no element was focused before the call, nothing happens.
|
|
137
|
+
*/
|
|
138
|
+
focusNext(): void;
|
|
139
|
+
/**
|
|
140
|
+
* Focus the last element. If no element was focused before the call, nothing happens.
|
|
141
|
+
*/
|
|
142
|
+
focusLast(): void;
|
|
143
|
+
/**
|
|
144
|
+
* Select the provided item.
|
|
145
|
+
* The selected list is used to
|
|
146
|
+
* @param item - the item to select
|
|
147
|
+
*/
|
|
148
|
+
select(item: Item): void;
|
|
149
|
+
/**
|
|
150
|
+
* Unselect the provided item.
|
|
151
|
+
* @param item - the item to unselect
|
|
152
|
+
*/
|
|
153
|
+
unselect(item: Item): void;
|
|
154
|
+
/**
|
|
155
|
+
* Toggle the selection of an item
|
|
156
|
+
* @param item - the item to toggle
|
|
157
|
+
* @param selected - an optional boolean to enforce the selected/unselected state instead of toggling
|
|
158
|
+
*/
|
|
159
|
+
toggleItem(item: Item, selected?: boolean): void;
|
|
160
|
+
/**
|
|
161
|
+
* open the select
|
|
162
|
+
*/
|
|
163
|
+
open(): void;
|
|
164
|
+
/**
|
|
165
|
+
* close the select
|
|
166
|
+
*/
|
|
167
|
+
close(): void;
|
|
168
|
+
/**
|
|
169
|
+
* Toggle the dropdown menu
|
|
170
|
+
* @param isOpen - If specified, set the menu in the defined state.
|
|
171
|
+
*/
|
|
172
|
+
toggle(isOpen?: boolean): void;
|
|
173
|
+
}
|
|
174
|
+
export interface SelectDirectives {
|
|
175
|
+
/**
|
|
176
|
+
* Directive to be used in the input group and the menu containers
|
|
177
|
+
*/
|
|
178
|
+
hasFocusDirective: HasFocus['directive'];
|
|
179
|
+
}
|
|
180
|
+
export interface SelectActions {
|
|
181
|
+
/**
|
|
182
|
+
* Method to be plugged to on the 'input' event. The input text will be used as the filter text.
|
|
183
|
+
*/
|
|
184
|
+
onInput: (e: {
|
|
185
|
+
target: any;
|
|
186
|
+
}) => void;
|
|
187
|
+
/**
|
|
188
|
+
* Method to be plugged to on an keydown event, in order to control the keyboard interactions with the highlighted item.
|
|
189
|
+
* It manages arrow keys to move the highlighted item, or enter to toggle the item.
|
|
190
|
+
*/
|
|
191
|
+
onInputKeydown: (e: any) => void;
|
|
192
|
+
}
|
|
193
|
+
export type SelectWidget<Item> = Widget<SelectProps<Item>, SelectState<Item>, SelectApi<Item>, SelectActions, SelectDirectives>;
|
|
194
|
+
/**
|
|
195
|
+
* Create a SelectWidget with given config props
|
|
196
|
+
* @param config - an optional alert config
|
|
197
|
+
* @returns a SelectWidget
|
|
198
|
+
*/
|
|
199
|
+
export declare function createSelect<Item>(config?: PropsConfig<SelectProps<Item>>): SelectWidget<Item>;
|