@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.
Files changed (61) hide show
  1. package/README.md +15 -0
  2. package/dist/lib/accordion.d.ts +318 -0
  3. package/dist/lib/accordion.js +263 -0
  4. package/dist/lib/alert.d.ts +100 -0
  5. package/dist/lib/alert.js +66 -0
  6. package/dist/lib/config.d.ts +71 -0
  7. package/dist/lib/config.js +53 -0
  8. package/dist/lib/index.d.ts +11 -0
  9. package/dist/lib/index.js +11 -0
  10. package/dist/lib/modal/modal.d.ts +318 -0
  11. package/dist/lib/modal/modal.js +156 -0
  12. package/dist/lib/modal/scrollbars.d.ts +2 -0
  13. package/dist/lib/modal/scrollbars.js +27 -0
  14. package/dist/lib/pagination.d.ts +464 -0
  15. package/dist/lib/pagination.js +148 -0
  16. package/dist/lib/pagination.utils.d.ts +8 -0
  17. package/dist/lib/pagination.utils.js +110 -0
  18. package/dist/lib/rating.d.ts +209 -0
  19. package/dist/lib/rating.js +141 -0
  20. package/dist/lib/select.d.ts +199 -0
  21. package/dist/lib/select.js +240 -0
  22. package/dist/lib/services/checks.d.ts +32 -0
  23. package/dist/lib/services/checks.js +43 -0
  24. package/dist/lib/services/directiveUtils.d.ts +95 -0
  25. package/dist/lib/services/directiveUtils.js +190 -0
  26. package/dist/lib/services/focustrack.d.ts +19 -0
  27. package/dist/lib/services/focustrack.js +46 -0
  28. package/dist/lib/services/index.d.ts +6 -0
  29. package/dist/lib/services/index.js +6 -0
  30. package/dist/lib/services/portal.d.ts +6 -0
  31. package/dist/lib/services/portal.js +33 -0
  32. package/dist/lib/services/siblingsInert.d.ts +7 -0
  33. package/dist/lib/services/siblingsInert.js +40 -0
  34. package/dist/lib/services/stores.d.ts +140 -0
  35. package/dist/lib/services/stores.js +219 -0
  36. package/dist/lib/services/writables.d.ts +7 -0
  37. package/dist/lib/services/writables.js +16 -0
  38. package/dist/lib/transitions/baseTransitions.d.ts +136 -0
  39. package/dist/lib/transitions/baseTransitions.js +171 -0
  40. package/dist/lib/transitions/bootstrap/collapse.d.ts +2 -0
  41. package/dist/lib/transitions/bootstrap/collapse.js +15 -0
  42. package/dist/lib/transitions/bootstrap/fade.d.ts +1 -0
  43. package/dist/lib/transitions/bootstrap/fade.js +7 -0
  44. package/dist/lib/transitions/bootstrap/index.d.ts +2 -0
  45. package/dist/lib/transitions/bootstrap/index.js +2 -0
  46. package/dist/lib/transitions/collapse.d.ts +29 -0
  47. package/dist/lib/transitions/collapse.js +39 -0
  48. package/dist/lib/transitions/cssTransitions.d.ts +15 -0
  49. package/dist/lib/transitions/cssTransitions.js +38 -0
  50. package/dist/lib/transitions/index.d.ts +5 -0
  51. package/dist/lib/transitions/index.js +5 -0
  52. package/dist/lib/transitions/simpleClassTransition.d.ts +29 -0
  53. package/dist/lib/transitions/simpleClassTransition.js +28 -0
  54. package/dist/lib/transitions/utils.d.ts +20 -0
  55. package/dist/lib/transitions/utils.js +83 -0
  56. package/dist/lib/tsdoc-metadata.json +11 -0
  57. package/dist/lib/types.d.ts +58 -0
  58. package/dist/lib/types.js +7 -0
  59. package/dist/lib/utils.d.ts +2 -0
  60. package/dist/lib/utils.js +2 -0
  61. package/package.json +52 -0
@@ -0,0 +1,66 @@
1
+ import { bindDirectiveNoArg, stateStores, typeBoolean, typeString, writablesForProps } from './services';
2
+ import { createTransition } from './transitions';
3
+ import { fadeTransition } from './transitions/bootstrap';
4
+ import { noop } from './utils';
5
+ const defaultConfig = {
6
+ visible: true,
7
+ dismissible: true,
8
+ type: 'primary',
9
+ ariaCloseButtonLabel: 'Close',
10
+ onVisibleChange: noop,
11
+ onShown: noop,
12
+ onHidden: noop,
13
+ slotStructure: undefined,
14
+ slotDefault: undefined,
15
+ animation: true,
16
+ animationOnInit: false,
17
+ transition: fadeTransition,
18
+ };
19
+ /**
20
+ * Retrieve a shallow copy of the default alert config
21
+ * @returns the default alert config
22
+ */
23
+ export function getAlertDefaultConfig() {
24
+ return { ...defaultConfig };
25
+ }
26
+ const configValidator = {
27
+ dismissible: typeBoolean,
28
+ type: typeString,
29
+ };
30
+ /**
31
+ * Create an AlertWidget with given config props
32
+ * @param config - an optional alert config
33
+ * @returns an AlertWidget
34
+ */
35
+ export function createAlert(config) {
36
+ const [{ transition$, animationOnInit$, animation$, visible$: requestedVisible$, onVisibleChange$, onHidden$, onShown$, ...stateProps }, patch,] = writablesForProps(defaultConfig, config, configValidator);
37
+ const transition = createTransition({
38
+ transition: transition$,
39
+ visible: requestedVisible$,
40
+ animation: animation$,
41
+ animationOnInit: animationOnInit$,
42
+ onVisibleChange: onVisibleChange$,
43
+ onHidden: onHidden$,
44
+ onShown: onShown$,
45
+ });
46
+ const close = () => {
47
+ patch({ visible: false });
48
+ };
49
+ const open = () => {
50
+ patch({ visible: true });
51
+ };
52
+ const visible$ = transition.stores.visible$;
53
+ const hidden$ = transition.stores.hidden$;
54
+ return {
55
+ ...stateStores({ ...stateProps, visible$, hidden$ }),
56
+ patch,
57
+ api: {
58
+ open,
59
+ close,
60
+ },
61
+ directives: {
62
+ transitionDirective: bindDirectiveNoArg(transition.directives.directive),
63
+ },
64
+ actions: {},
65
+ };
66
+ }
@@ -0,0 +1,71 @@
1
+ import type { ReadableSignal, WritableSignal } from '@amadeus-it-group/tansu';
2
+ import type { ModalProps } from './modal/modal';
3
+ import type { AlertProps } from './alert';
4
+ import type { PaginationProps } from './pagination';
5
+ import type { RatingProps } from './rating';
6
+ import type { SelectProps } from './select';
7
+ import type { AccordionProps } from './accordion';
8
+ export type Partial2Levels<T> = Partial<{
9
+ [Level1 in keyof T]: Partial<T[Level1]>;
10
+ }>;
11
+ export type WidgetsConfigStore<T> = WritableSignal<Partial2Levels<T>> & {
12
+ own$: WritableSignal<Partial2Levels<T>>;
13
+ parent$: undefined | WritableSignal<Partial2Levels<T>>;
14
+ adaptedParent$: undefined | ReadableSignal<Partial2Levels<T>>;
15
+ };
16
+ /**
17
+ * Merges source object into destination object, up to the provided number of levels.
18
+ * @param destination - destination object
19
+ * @param source - source object
20
+ * @param levels - number of levels to merge
21
+ * @returns the destination object in most cases, or the source in some cases (if the source is not undefined and either levels is smaller than 1
22
+ * or the source is not an object)
23
+ */
24
+ export declare const mergeInto: <T>(destination: T, source: T | undefined, levels?: number) => T;
25
+ /**
26
+ * Creates a new widgets default configuration store, optionally inheriting from a parent store, and containing
27
+ * its own set of widgets configuration properties that override the same properties form the parent configuration.
28
+ *
29
+ * @remarks
30
+ * The resulting store has a value computed from the parent store in two steps:
31
+ * - first step: the parent configuration is transformed by the adaptParentConfig function (if specified).
32
+ * If adaptParentConfig is not specified, this step is skipped.
33
+ * - second step: the configuration from step 1 is merged (2-levels deep) with the own$ store. The own$ store initially contains
34
+ * an empty object (i.e. no property from the parent is overridden). It can be changed by calling set on the store returned by this function.
35
+ *
36
+ * @param parent$ - optional parent widgets default configuration store.
37
+ * @param adaptParentConfig - optional function that receives a 2-levels copy of the widgets default configuration
38
+ * from parent$ (or an empty object if parent$ is not specified) and returns the widgets default configuration to be used.
39
+ * It is called only if the configuration is needed, and was not yet computed for the current value of the parent configuration.
40
+ * It is called in a tansu reactive context, so it can use any tansu store and will be called again if those stores change.
41
+ * @returns the resulting widgets default configuration store, which contains 3 additional properties that are stores:
42
+ * parent$, adaptedParent$ (containing the value computed after the first step), and own$ (that contains only overridding properties).
43
+ * The resulting store is writable, its set function is actually the set function of the own$ store.
44
+ */
45
+ export declare const createWidgetsConfig: <T>(parent$?: WidgetsConfigStore<T> | undefined, adaptParentConfig?: (config: Partial<{ [Level1 in keyof T]: Partial<T[Level1]>; }>) => Partial<{ [Level1 in keyof T]: Partial<T[Level1]>; }>) => WidgetsConfigStore<T>;
46
+ export interface WidgetsConfig {
47
+ /**
48
+ * the pagination widget config
49
+ */
50
+ pagination: PaginationProps;
51
+ /**
52
+ * the rating widget config
53
+ */
54
+ rating: RatingProps;
55
+ /**
56
+ * the select widget config
57
+ */
58
+ select: SelectProps<any>;
59
+ /**
60
+ * the modal widget config
61
+ */
62
+ modal: ModalProps;
63
+ /**
64
+ * the alert widget config
65
+ */
66
+ alert: AlertProps;
67
+ /**
68
+ * the accordion widget config
69
+ */
70
+ accordion: AccordionProps;
71
+ }
@@ -0,0 +1,53 @@
1
+ import { asReadable, computed, writable } from '@amadeus-it-group/tansu';
2
+ import { identity } from './utils';
3
+ /**
4
+ * Merges source object into destination object, up to the provided number of levels.
5
+ * @param destination - destination object
6
+ * @param source - source object
7
+ * @param levels - number of levels to merge
8
+ * @returns the destination object in most cases, or the source in some cases (if the source is not undefined and either levels is smaller than 1
9
+ * or the source is not an object)
10
+ */
11
+ export const mergeInto = (destination, source, levels = Infinity) => {
12
+ if (source !== undefined) {
13
+ if (typeof source === 'object' && source && levels >= 1) {
14
+ for (const key of Object.keys(source)) {
15
+ destination[key] = mergeInto(destination[key] ?? {}, source[key], levels - 1);
16
+ }
17
+ }
18
+ else {
19
+ return source;
20
+ }
21
+ }
22
+ return destination;
23
+ };
24
+ /**
25
+ * Creates a new widgets default configuration store, optionally inheriting from a parent store, and containing
26
+ * its own set of widgets configuration properties that override the same properties form the parent configuration.
27
+ *
28
+ * @remarks
29
+ * The resulting store has a value computed from the parent store in two steps:
30
+ * - first step: the parent configuration is transformed by the adaptParentConfig function (if specified).
31
+ * If adaptParentConfig is not specified, this step is skipped.
32
+ * - second step: the configuration from step 1 is merged (2-levels deep) with the own$ store. The own$ store initially contains
33
+ * an empty object (i.e. no property from the parent is overridden). It can be changed by calling set on the store returned by this function.
34
+ *
35
+ * @param parent$ - optional parent widgets default configuration store.
36
+ * @param adaptParentConfig - optional function that receives a 2-levels copy of the widgets default configuration
37
+ * from parent$ (or an empty object if parent$ is not specified) and returns the widgets default configuration to be used.
38
+ * It is called only if the configuration is needed, and was not yet computed for the current value of the parent configuration.
39
+ * It is called in a tansu reactive context, so it can use any tansu store and will be called again if those stores change.
40
+ * @returns the resulting widgets default configuration store, which contains 3 additional properties that are stores:
41
+ * parent$, adaptedParent$ (containing the value computed after the first step), and own$ (that contains only overridding properties).
42
+ * The resulting store is writable, its set function is actually the set function of the own$ store.
43
+ */
44
+ export const createWidgetsConfig = (parent$, adaptParentConfig = identity) => {
45
+ const own$ = writable({});
46
+ const adaptedParent$ = adaptParentConfig === identity ? parent$ : computed(() => adaptParentConfig(mergeInto({}, parent$?.(), 2)));
47
+ return asReadable(computed(() => mergeInto(mergeInto({}, adaptedParent$?.(), 2), own$(), 2)), {
48
+ ...own$,
49
+ own$,
50
+ adaptedParent$,
51
+ parent$,
52
+ });
53
+ };
@@ -0,0 +1,11 @@
1
+ export * from './types';
2
+ export * from './select';
3
+ export * from './services';
4
+ export * from './transitions';
5
+ export * from './rating';
6
+ export * from './pagination';
7
+ export * from './pagination.utils';
8
+ export * from './config';
9
+ export * from './modal/modal';
10
+ export * from './alert';
11
+ export * from './accordion';
@@ -0,0 +1,11 @@
1
+ export * from './types';
2
+ export * from './select';
3
+ export * from './services';
4
+ export * from './transitions';
5
+ export * from './rating';
6
+ export * from './pagination';
7
+ export * from './pagination.utils';
8
+ export * from './config';
9
+ export * from './modal/modal';
10
+ export * from './alert';
11
+ export * from './accordion';
@@ -0,0 +1,318 @@
1
+ import type { PropsConfig } from '../services';
2
+ import type { TransitionFn } from '../transitions';
3
+ import type { Widget, Directive, SlotContent, WidgetSlotContext } from '../types';
4
+ /**
5
+ * Value present in the {@link ModalBeforeCloseEvent.result|result} property of the {@link ModalProps.onBeforeClose|onBeforeClose} event
6
+ * and returned by the {@link ModalApi.open|open} method, when the modal is closed by a click inside the viewport but outside the modal.
7
+ */
8
+ export declare const modalOutsideClick: unique symbol;
9
+ /**
10
+ * Value present in the {@link ModalBeforeCloseEvent.result|result} property of the {@link ModalProps.onBeforeClose|onBeforeClose} event
11
+ * and returned by the {@link ModalApi.open|open} method, when the modal is closed by a click on the close button.
12
+ */
13
+ export declare const modalCloseButtonClick: unique symbol;
14
+ /**
15
+ * Context of the modal slots.
16
+ */
17
+ export type ModalContext = WidgetSlotContext<ModalWidget>;
18
+ /**
19
+ * Properties of the modal widget that are also in the state of the modal.
20
+ */
21
+ export interface ModalCommonPropsAndState {
22
+ /**
23
+ * Value of the aria-label attribute to put on the close button.
24
+ */
25
+ ariaCloseButtonLabel: string;
26
+ /**
27
+ * Classes to add on the backdrop DOM element.
28
+ */
29
+ backdropClass: string;
30
+ /**
31
+ * Whether to display the close button.
32
+ */
33
+ closeButton: boolean;
34
+ /**
35
+ * Which element should contain the modal and backdrop DOM elements.
36
+ * If it is not null, the modal and backdrop DOM elements are moved to the specified container.
37
+ * Otherwise, they stay where the widget is located.
38
+ */
39
+ container: HTMLElement | null;
40
+ /**
41
+ * Classes to add on the modal DOM element.
42
+ */
43
+ modalClass: string;
44
+ /**
45
+ * Body of the modal.
46
+ */
47
+ slotDefault: SlotContent<ModalContext>;
48
+ /**
49
+ * Footer of the modal.
50
+ */
51
+ slotFooter: SlotContent<ModalContext>;
52
+ /**
53
+ * Header of the modal. The default header includes {@link ModalCommonPropsAndState.slotTitle|slotTitle}.
54
+ */
55
+ slotHeader: SlotContent<ModalContext>;
56
+ /**
57
+ * Structure of the modal.
58
+ * The default structure uses {@link ModalCommonPropsAndState.slotHeader|slotHeader}, {@link ModalCommonPropsAndState.slotDefault|slotDefault} and {@link ModalCommonPropsAndState.slotFooter|slotFooter}.
59
+ */
60
+ slotStructure: SlotContent<ModalContext>;
61
+ /**
62
+ * Title of the modal.
63
+ */
64
+ slotTitle: SlotContent<ModalContext>;
65
+ /**
66
+ * Whether the modal should be visible when the transition is completed.
67
+ */
68
+ visible: boolean;
69
+ }
70
+ /**
71
+ * Type of the parameter of {@link ModalProps.onBeforeClose|onBeforeClose}.
72
+ */
73
+ export interface ModalBeforeCloseEvent {
74
+ /**
75
+ * Result of the modal, which is the value passed to the {@link ModalApi.close|close} method
76
+ * and later resolved by the promise returned by the {@link ModalApi.open|open} method.
77
+ * If needed, it can be changed from the {@link ModalProps.onBeforeClose|onBeforeClose} event handler.
78
+ */
79
+ result: any;
80
+ /**
81
+ * Whether to cancel the close of the modal.
82
+ * It can be changed from the {@link ModalProps.onBeforeClose|onBeforeClose} event handler.
83
+ */
84
+ cancel: boolean;
85
+ }
86
+ /**
87
+ * Properties of the modal widget.
88
+ */
89
+ export interface ModalProps extends ModalCommonPropsAndState {
90
+ /**
91
+ * Whether the modal and its backdrop (if present) should be animated when shown or hidden.
92
+ */
93
+ animation: boolean;
94
+ /**
95
+ * Whether a backdrop should be created behind the modal.
96
+ */
97
+ backdrop: boolean;
98
+ /**
99
+ * The transition to use for the backdrop behind the modal (if present).
100
+ */
101
+ backdropTransition: TransitionFn;
102
+ /**
103
+ * Whether the modal should be closed when clicking on the viewport outside the modal.
104
+ */
105
+ closeOnOutsideClick: boolean;
106
+ /**
107
+ * The transition to use for the modal.
108
+ */
109
+ modalTransition: TransitionFn;
110
+ /**
111
+ * Event to be triggered when the modal is about to be closed (i.e. the {@link ModalApi.close|close} method was called).
112
+ *
113
+ * @param event - event giving access to the argument given to the {@link ModalApi.close|close} method and allowing
114
+ * to cancel the close process.
115
+ */
116
+ onBeforeClose: (event: ModalBeforeCloseEvent) => void;
117
+ /**
118
+ * Event to be triggered when the visible property changes.
119
+ *
120
+ * @param visible - new value of the visible propery
121
+ */
122
+ onVisibleChange: (visible: boolean) => void;
123
+ /**
124
+ * Event to be triggered when the transition is completed and the modal is not visible.
125
+ */
126
+ onHidden: () => void;
127
+ /**
128
+ * Event to be triggered when the transition is completed and the modal is visible.
129
+ */
130
+ onShown: () => void;
131
+ }
132
+ /**
133
+ * State of the modal widget.
134
+ */
135
+ export interface ModalState extends ModalCommonPropsAndState {
136
+ /**
137
+ * Whether the backdrop is fully hidden. This can be true either because {@link ModalProps.backdrop|backdrop} is false or
138
+ * because {@link ModalCommonPropsAndState.visible|visible} is false and there is no current transition.
139
+ */
140
+ backdropHidden: boolean;
141
+ /**
142
+ * Whether the modal is fully hidden.
143
+ */
144
+ hidden: boolean;
145
+ /**
146
+ * Whether there is an active transition to either display or hide the modal.
147
+ */
148
+ transitioning: boolean;
149
+ /**
150
+ * DOM element of the modal.
151
+ */
152
+ modalElement: HTMLElement | null;
153
+ }
154
+ /**
155
+ * API of the modal widget.
156
+ */
157
+ export interface ModalApi {
158
+ /**
159
+ * Closes the modal with the given result.
160
+ *
161
+ * @param result - result of the modal, as passed in the {@link ModalBeforeCloseEvent.result|result} property of the event passed to the
162
+ * {@link ModalProps.onBeforeClose|onBeforeClose} event handler (and possibly changed by it) and resolved by the promise returned by the {@link ModalApi.open|open} method.
163
+ */
164
+ close(result?: any): void;
165
+ /**
166
+ * Opens the modal and returns a promise that is resolved when the modal is closed.
167
+ * The resolved value is the result passed to the {@link ModalApi.close|close} method and possibly changed by the
168
+ * {@link ModalProps.onBeforeClose|onBeforeClose} event handler
169
+ */
170
+ open(): Promise<any>;
171
+ /**
172
+ * Method to change some modal properties.
173
+ */
174
+ patch: ModalWidget['patch'];
175
+ }
176
+ /**
177
+ * Actions of the modal widget.
178
+ */
179
+ export interface ModalActions {
180
+ /**
181
+ * Action to be called when the user clicks on the close button. It closes the modal with the {@link modalCloseButtonClick} result.
182
+ * @param event - mouse event
183
+ */
184
+ closeButtonClick(event: Pick<MouseEvent, never>): void;
185
+ /**
186
+ * Action to be called when the user clicks on the modal DOM element (which is supposed to have the size of the full viewport).
187
+ * If the click is not done on a descendant of the modal DOM element, it is considered to be done outside the modal
188
+ * and, depending on the value of the {@link ModalProps.closeOnOutsideClick|closeOnOutsideClick} prop, the modal is or isn't closed
189
+ * (with the {@link modalOutsideClick} result).
190
+ * @param event - mouse event
191
+ */
192
+ modalClick(event: Pick<MouseEvent, 'target' | 'currentTarget'>): void;
193
+ }
194
+ /**
195
+ * Directives of the modal widget.
196
+ */
197
+ export interface ModalDirectives {
198
+ /**
199
+ * Directive to put on the modal DOM element.
200
+ */
201
+ modalDirective: Directive;
202
+ /**
203
+ * Directive to put on the backdrop DOM element.
204
+ */
205
+ backdropDirective: Directive;
206
+ /**
207
+ * Portal directive to put on the modal DOM element.
208
+ */
209
+ modalPortalDirective: Directive;
210
+ /**
211
+ * Portal directive to put on the backdrop DOM element.
212
+ */
213
+ backdropPortalDirective: Directive;
214
+ }
215
+ /**
216
+ * Modal widget.
217
+ */
218
+ export type ModalWidget = Widget<ModalProps, ModalState, ModalApi, ModalActions, ModalDirectives>;
219
+ /**
220
+ * Returns a copy of the default modal config.
221
+ * @returns a copy of the default modal config
222
+ */
223
+ export declare function getModalDefaultConfig(): {
224
+ /**
225
+ * Whether the modal and its backdrop (if present) should be animated when shown or hidden.
226
+ */
227
+ animation: boolean;
228
+ /**
229
+ * Whether a backdrop should be created behind the modal.
230
+ */
231
+ backdrop: boolean;
232
+ /**
233
+ * The transition to use for the backdrop behind the modal (if present).
234
+ */
235
+ backdropTransition: TransitionFn;
236
+ /**
237
+ * Whether the modal should be closed when clicking on the viewport outside the modal.
238
+ */
239
+ closeOnOutsideClick: boolean;
240
+ /**
241
+ * The transition to use for the modal.
242
+ */
243
+ modalTransition: TransitionFn;
244
+ /**
245
+ * Event to be triggered when the modal is about to be closed (i.e. the {@link ModalApi.close|close} method was called).
246
+ *
247
+ * @param event - event giving access to the argument given to the {@link ModalApi.close|close} method and allowing
248
+ * to cancel the close process.
249
+ */
250
+ onBeforeClose: (event: ModalBeforeCloseEvent) => void;
251
+ /**
252
+ * Event to be triggered when the visible property changes.
253
+ *
254
+ * @param visible - new value of the visible propery
255
+ */
256
+ onVisibleChange: (visible: boolean) => void;
257
+ /**
258
+ * Event to be triggered when the transition is completed and the modal is not visible.
259
+ */
260
+ onHidden: () => void;
261
+ /**
262
+ * Event to be triggered when the transition is completed and the modal is visible.
263
+ */
264
+ onShown: () => void;
265
+ /**
266
+ * Value of the aria-label attribute to put on the close button.
267
+ */
268
+ ariaCloseButtonLabel: string;
269
+ /**
270
+ * Classes to add on the backdrop DOM element.
271
+ */
272
+ backdropClass: string;
273
+ /**
274
+ * Whether to display the close button.
275
+ */
276
+ closeButton: boolean;
277
+ /**
278
+ * Which element should contain the modal and backdrop DOM elements.
279
+ * If it is not null, the modal and backdrop DOM elements are moved to the specified container.
280
+ * Otherwise, they stay where the widget is located.
281
+ */
282
+ container: HTMLElement | null;
283
+ /**
284
+ * Classes to add on the modal DOM element.
285
+ */
286
+ modalClass: string;
287
+ /**
288
+ * Body of the modal.
289
+ */
290
+ slotDefault: SlotContent<ModalContext>;
291
+ /**
292
+ * Footer of the modal.
293
+ */
294
+ slotFooter: SlotContent<ModalContext>;
295
+ /**
296
+ * Header of the modal. The default header includes {@link ModalCommonPropsAndState.slotTitle|slotTitle}.
297
+ */
298
+ slotHeader: SlotContent<ModalContext>;
299
+ /**
300
+ * Structure of the modal.
301
+ * The default structure uses {@link ModalCommonPropsAndState.slotHeader|slotHeader}, {@link ModalCommonPropsAndState.slotDefault|slotDefault} and {@link ModalCommonPropsAndState.slotFooter|slotFooter}.
302
+ */
303
+ slotStructure: SlotContent<ModalContext>;
304
+ /**
305
+ * Title of the modal.
306
+ */
307
+ slotTitle: SlotContent<ModalContext>;
308
+ /**
309
+ * Whether the modal should be visible when the transition is completed.
310
+ */
311
+ visible: boolean;
312
+ };
313
+ /**
314
+ * Creates a new modal widget instance.
315
+ * @param config$ - config of the modal, either as a store or as an object containing values or stores.
316
+ * @returns a new modal widget instance
317
+ */
318
+ export declare const createModal: (config$?: PropsConfig<ModalProps>) => ModalWidget;
@@ -0,0 +1,156 @@
1
+ import { computed, readable } from '@amadeus-it-group/tansu';
2
+ import { sliblingsInert, bindDirective, bindDirectiveNoArg, directiveSubscribe, mergeDirectives, portal, registrationArray, stateStores, writablesForProps, } from '../services';
3
+ import { createTransition } from '../transitions';
4
+ import { fadeTransition } from '../transitions/bootstrap/fade';
5
+ import { promiseFromStore } from '../transitions/utils';
6
+ import { noop } from '../utils';
7
+ import { removeScrollbars, revertScrollbars } from './scrollbars';
8
+ /**
9
+ * Value present in the {@link ModalBeforeCloseEvent.result|result} property of the {@link ModalProps.onBeforeClose|onBeforeClose} event
10
+ * and returned by the {@link ModalApi.open|open} method, when the modal is closed by a click inside the viewport but outside the modal.
11
+ */
12
+ export const modalOutsideClick = Symbol();
13
+ /**
14
+ * Value present in the {@link ModalBeforeCloseEvent.result|result} property of the {@link ModalProps.onBeforeClose|onBeforeClose} event
15
+ * and returned by the {@link ModalApi.open|open} method, when the modal is closed by a click on the close button.
16
+ */
17
+ export const modalCloseButtonClick = Symbol();
18
+ const defaultConfig = {
19
+ animation: true,
20
+ ariaCloseButtonLabel: 'Close',
21
+ backdrop: true,
22
+ backdropClass: '',
23
+ backdropTransition: fadeTransition,
24
+ closeButton: true,
25
+ closeOnOutsideClick: true,
26
+ container: typeof window !== 'undefined' ? document.body : null,
27
+ modalClass: '',
28
+ modalTransition: fadeTransition,
29
+ onBeforeClose: noop,
30
+ onVisibleChange: noop,
31
+ onHidden: noop,
32
+ onShown: noop,
33
+ slotDefault: undefined,
34
+ slotFooter: undefined,
35
+ slotHeader: undefined,
36
+ slotStructure: undefined,
37
+ slotTitle: undefined,
38
+ visible: false,
39
+ };
40
+ /**
41
+ * Returns a copy of the default modal config.
42
+ * @returns a copy of the default modal config
43
+ */
44
+ export function getModalDefaultConfig() {
45
+ return { ...defaultConfig };
46
+ }
47
+ const modals$ = registrationArray();
48
+ const hasModals$ = computed(() => modals$().length > 0);
49
+ const scrollbarsAction$ = computed(() => {
50
+ if (hasModals$()) {
51
+ removeScrollbars();
52
+ }
53
+ else {
54
+ revertScrollbars();
55
+ }
56
+ });
57
+ const modalsAction$ = computed(() => {
58
+ scrollbarsAction$();
59
+ });
60
+ /**
61
+ * Creates a new modal widget instance.
62
+ * @param config$ - config of the modal, either as a store or as an object containing values or stores.
63
+ * @returns a new modal widget instance
64
+ */
65
+ export const createModal = (config$) => {
66
+ const [{ animation$, backdrop$, backdropTransition$, closeOnOutsideClick$, container$, modalTransition$, onBeforeClose$, onVisibleChange$, onHidden$, onShown$, visible$: requestedVisible$, ...stateProps }, patch,] = writablesForProps(defaultConfig, config$);
67
+ const modalTransition = createTransition({
68
+ transition: modalTransition$,
69
+ visible: requestedVisible$,
70
+ animation: animation$,
71
+ animationOnInit: animation$,
72
+ onVisibleChange: onVisibleChange$,
73
+ // TODO: for onHidden and onShown, should we combine with information from the backdrop transition?
74
+ // (especially in case one of the two transitions takes more time than the other)
75
+ onHidden: onHidden$,
76
+ onShown: onShown$,
77
+ });
78
+ const visible$ = modalTransition.stores.visible$;
79
+ const backdropTransition = createTransition({
80
+ transition: backdropTransition$,
81
+ visible: requestedVisible$,
82
+ animation: animation$,
83
+ animationOnInit: animation$,
84
+ });
85
+ const transitioning$ = computed(() => modalTransition.stores.transitioning$() || (backdrop$() && backdropTransition.stores.transitioning$()));
86
+ const hidden$ = computed(() => !transitioning$() && !visible$());
87
+ const backdropHidden$ = computed(() => !backdrop$() || hidden$());
88
+ let hideResult;
89
+ const close = (result) => {
90
+ hideResult = result;
91
+ const beforeCloseEvent = {
92
+ get result() {
93
+ return hideResult;
94
+ },
95
+ set result(value) {
96
+ hideResult = value;
97
+ },
98
+ cancel: false,
99
+ };
100
+ onBeforeClose$()(beforeCloseEvent);
101
+ if (beforeCloseEvent.cancel) {
102
+ return;
103
+ }
104
+ patch({ visible: false });
105
+ };
106
+ const modalPortalDirective = bindDirective(portal, computed(() => ({ container: container$() })));
107
+ const backdropPortalDirective = bindDirective(portal, computed(() => ({
108
+ container: container$(),
109
+ insertBefore: container$() && modalTransition.stores.element$()?.parentElement === container$() ? modalTransition.stores.element$() : undefined,
110
+ })));
111
+ const registerModalAction$ = readable(undefined, () => modals$.register(res));
112
+ const action$ = computed(() => {
113
+ if (modalTransition.stores.elementPresent$() && !hidden$()) {
114
+ registerModalAction$();
115
+ }
116
+ modalsAction$();
117
+ });
118
+ const res = {
119
+ ...stateStores({
120
+ backdropHidden$,
121
+ container$,
122
+ hidden$,
123
+ transitioning$,
124
+ visible$,
125
+ modalElement$: modalTransition.stores.element$,
126
+ ...stateProps,
127
+ }),
128
+ directives: {
129
+ modalPortalDirective,
130
+ backdropPortalDirective,
131
+ backdropDirective: bindDirectiveNoArg(backdropTransition.directives.directive),
132
+ modalDirective: mergeDirectives(bindDirectiveNoArg(modalTransition.directives.directive), sliblingsInert, directiveSubscribe(action$)),
133
+ },
134
+ patch,
135
+ api: {
136
+ close,
137
+ async open() {
138
+ patch({ visible: true });
139
+ await promiseFromStore(hidden$).promise;
140
+ return hideResult;
141
+ },
142
+ patch,
143
+ },
144
+ actions: {
145
+ modalClick(event) {
146
+ if (event.currentTarget === event.target && closeOnOutsideClick$()) {
147
+ close(modalOutsideClick);
148
+ }
149
+ },
150
+ closeButtonClick(event) {
151
+ close(modalCloseButtonClick);
152
+ },
153
+ },
154
+ };
155
+ return res;
156
+ };