@agnos-ui/core 0.1.1 → 0.2.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.
@@ -2,16 +2,20 @@ import type { ConfigValidator, SlotContent, Widget, WidgetFactory, WidgetProps,
2
2
  /**
3
3
  * Type extending the original Widget props and state with ExtraProps
4
4
  */
5
- export type ExtendWidgetProps<W extends Widget, ExtraProps extends object> = Widget<ExtendWidgetAdaptSlotWidgetProps<WidgetProps<W>, ExtraProps>, ExtendWidgetAdaptSlotWidgetProps<WidgetState<W>, ExtraProps>, W['api'], W['actions'], W['directives']>;
5
+ export type ExtendWidgetProps<W extends Widget, ExtraProps extends object, ExtraDirectives extends object = object> = Widget<ExtendWidgetAdaptSlotWidgetProps<WidgetProps<W>, ExtraProps, ExtraDirectives>, ExtendWidgetAdaptSlotWidgetProps<WidgetState<W>, ExtraProps, ExtraDirectives>, W['api'], W['actions'], ExtendWidgetInterfaces<W['directives'], ExtraDirectives>>;
6
+ /**
7
+ * Type merging the passed interfaces together
8
+ */
9
+ export type ExtendWidgetInterfaces<Interfaces, ExtraInterfaces> = Interfaces & ExtraInterfaces;
6
10
  /**
7
11
  * Type replacing the original Props with WidgetSlotContext contaning ExtraProps
8
12
  */
9
- export type ExtendWidgetAdaptSlotContentProps<Props extends Record<string, any>, ExtraProps extends object> = Props extends WidgetSlotContext<infer U> ? WidgetSlotContext<ExtendWidgetProps<U, ExtraProps>> & Omit<Props, keyof WidgetSlotContext<any>> : Props;
13
+ export type ExtendWidgetAdaptSlotContentProps<Props extends Record<string, any>, ExtraProps extends object, ExtraDirectives extends object> = Props extends WidgetSlotContext<infer U> ? WidgetSlotContext<ExtendWidgetProps<U, ExtraProps, ExtraDirectives>> & Omit<Props, keyof WidgetSlotContext<any>> : Props;
10
14
  /**
11
15
  * Type enriching the original widget slot Props with ExtraProps slots
12
16
  */
13
- export type ExtendWidgetAdaptSlotWidgetProps<Props, ExtraProps extends object> = Omit<Props, `slot${string}`> & ExtraProps & {
14
- [K in keyof Props & `slot${string}`]: Props[K] extends SlotContent<infer U> ? SlotContent<ExtendWidgetAdaptSlotContentProps<U, ExtraProps>> : Props[K];
17
+ export type ExtendWidgetAdaptSlotWidgetProps<Props, ExtraProps extends object, ExtraDirectives extends object> = Omit<Props, `slot${string}`> & ExtraProps & {
18
+ [K in keyof Props & `slot${string}`]: Props[K] extends SlotContent<infer U> ? SlotContent<ExtendWidgetAdaptSlotContentProps<U, ExtraProps, ExtraDirectives>> : Props[K];
15
19
  };
16
20
  /**
17
21
  * Method to extend the original widget with extra props with validator
@@ -20,4 +24,4 @@ export type ExtendWidgetAdaptSlotWidgetProps<Props, ExtraProps extends object> =
20
24
  * @param extraPropsConfig - object verifying the type of each extra prop
21
25
  * @returns widget factory with the extra props
22
26
  */
23
- export declare const extendWidgetProps: <W extends Widget<object, object, object, object, object>, ExtraProps extends object>(factory: WidgetFactory<W>, extraPropsDefaults: ExtraProps, extraPropsConfig?: ConfigValidator<ExtraProps> | undefined) => WidgetFactory<ExtendWidgetProps<W, ExtraProps>>;
27
+ export declare const extendWidgetProps: <W extends Widget<object, object, object, object, object>, ExtraProps extends object, ExtraDirectives extends object = object>(factory: WidgetFactory<W>, extraPropsDefaults: ExtraProps, extraPropsConfig?: ConfigValidator<ExtraProps> | undefined) => WidgetFactory<ExtendWidgetProps<W, ExtraProps, ExtraDirectives>>;
@@ -0,0 +1,2 @@
1
+ /** Store exposing the location.hash string */
2
+ export declare const hash$: import("@amadeus-it-group/tansu").ReadableSignal<string>;
@@ -0,0 +1,13 @@
1
+ import { readable } from '@amadeus-it-group/tansu';
2
+ /** Store exposing the location.hash string */
3
+ export const hash$ = readable('', {
4
+ onUse({ set }) {
5
+ function handleHashChange() {
6
+ const hash = location.hash;
7
+ set(hash ? hash.substring(1) : '');
8
+ }
9
+ handleHashChange();
10
+ window.addEventListener('hashchange', handleHashChange);
11
+ return () => window.removeEventListener('hashchange', handleHashChange);
12
+ },
13
+ });
@@ -1,4 +1,3 @@
1
- import type { Directive } from '../types';
2
1
  export type NavManager = ReturnType<typeof createNavManager>;
3
2
  /**
4
3
  * Returns the key name given the keyboard event. The key name is built using event.key (such as ArrowLeft, PageDown...),
@@ -23,27 +22,32 @@ export declare const isInternalInputNavigation: (event: KeyboardEvent) => boolea
23
22
  * - directiveElement: DOM element which has the navigation manager directive
24
23
  * - navManager: navigation manager instance
25
24
  */
26
- export type NavManagerKeyHandler = (info: {
25
+ export type NavManagerKeyHandler<T = any> = (info: {
27
26
  directiveElement: HTMLElement;
28
- event: KeyboardEvent;
27
+ event: Event;
29
28
  navManager: NavManager;
29
+ context?: T;
30
30
  }) => void;
31
31
  /**
32
32
  * Type of the parameter of the navigation manager directive.
33
33
  */
34
- export interface NavManagerItemConfig {
34
+ export interface NavManagerItemConfig<T = any> {
35
35
  /**
36
36
  * Map of key handlers.
37
37
  * The key in the map should match the result of calling {@link getKeyName} on the key event (for example "ArrowLeft" or "Ctrl+PageDown").
38
38
  * The value in the map is the corresponding key handler.
39
39
  */
40
- keys?: Record<string, NavManagerKeyHandler>;
40
+ keys?: Record<string, NavManagerKeyHandler<T>>;
41
41
  /**
42
42
  * Function returning DOM elements to include in the navigation manager.
43
43
  * It receives as a parameter the DOM element on which the navigation manager directive is used.
44
44
  * If not specified, the default selector function only returns the element on which the navigation manager directive is used.
45
45
  */
46
46
  selector?: (directiveElement: HTMLElement) => Iterable<HTMLElement>;
47
+ /**
48
+ *
49
+ */
50
+ context?: T;
47
51
  }
48
52
  /**
49
53
  * Returns a new instance of the navigation manager.
@@ -59,35 +63,38 @@ export interface NavManagerItemConfig {
59
63
  */
60
64
  export declare const createNavManager: () => {
61
65
  elementsInDomOrder$: import("@amadeus-it-group/tansu").ReadableSignal<HTMLElement[]>;
62
- directive: Directive<NavManagerItemConfig>;
66
+ directive: <T = any>(directiveElement: HTMLElement, config: NavManagerItemConfig<T>) => {
67
+ update(newConfig: NavManagerItemConfig<T>): void;
68
+ destroy(): void;
69
+ };
63
70
  focusIndex: (index: number, moveDirection?: -1 | 0 | 1) => HTMLElement | null;
64
71
  focusPrevious: ({ event, referenceElement, }?: {
65
- event?: KeyboardEvent | undefined;
72
+ event?: Event | undefined;
66
73
  referenceElement?: HTMLElement | null | undefined;
67
74
  }) => HTMLElement | null;
68
75
  focusNext: ({ event, referenceElement, }?: {
69
- event?: KeyboardEvent | undefined;
76
+ event?: Event | undefined;
70
77
  referenceElement?: HTMLElement | null | undefined;
71
78
  }) => HTMLElement | null;
72
79
  focusFirst: ({ event }?: {
73
- event?: KeyboardEvent | undefined;
80
+ event?: Event | undefined;
74
81
  }) => HTMLElement | null;
75
82
  focusFirstLeft: (args_0?: {
76
- event?: KeyboardEvent | undefined;
83
+ event?: Event | undefined;
77
84
  } | undefined) => HTMLElement | null;
78
85
  focusFirstRight: (args_0?: {
79
- event?: KeyboardEvent | undefined;
86
+ event?: Event | undefined;
80
87
  } | undefined) => HTMLElement | null;
81
88
  focusLast: ({ event }?: {
82
- event?: KeyboardEvent | undefined;
89
+ event?: Event | undefined;
83
90
  }) => HTMLElement | null;
84
91
  focusLeft: (args_0?: {
85
- event?: KeyboardEvent | undefined;
92
+ event?: Event | undefined;
86
93
  referenceElement?: HTMLElement | null | undefined;
87
94
  } | undefined) => HTMLElement | null;
88
95
  focusRight: (args_0?: {
89
- event?: KeyboardEvent | undefined;
96
+ event?: Event | undefined;
90
97
  referenceElement?: HTMLElement | null | undefined;
91
98
  } | undefined) => HTMLElement | null;
92
- refreshElements: () => void;
99
+ refreshElements: (now?: boolean) => void;
93
100
  };
@@ -72,7 +72,13 @@ const defaultSelector = (directiveElement) => [directiveElement];
72
72
  export const createNavManager = () => {
73
73
  const directiveInstances$ = registrationArray();
74
74
  const elementsRefresh$ = writable({});
75
- const refreshElements = () => elementsRefresh$.set({});
75
+ const refreshElements = (now = true) => {
76
+ elementsRefresh$.set({});
77
+ if (now) {
78
+ commonAncestor$();
79
+ elementsInDomOrder$();
80
+ }
81
+ };
76
82
  const elements$ = computed(() => {
77
83
  elementsRefresh$();
78
84
  const res = [];
@@ -130,8 +136,8 @@ export const createNavManager = () => {
130
136
  const keyName = getKeyName(event);
131
137
  const handler = config.keys?.[keyName];
132
138
  if (handler) {
133
- refreshElements();
134
- handler({ event, directiveElement, navManager });
139
+ refreshElements(false);
140
+ handler({ event, directiveElement, navManager, context: config.context });
135
141
  }
136
142
  };
137
143
  directiveElement.addEventListener('keydown', onKeyDown);
@@ -0,0 +1,14 @@
1
+ import type { ReadableSignal } from '@amadeus-it-group/tansu';
2
+ /**
3
+ * Create a resize observer object
4
+ * @returns An object containing the store with the dimentions of observed element (ResizeObserverEntry), the directive to be applied to the html element to be observed
5
+ */
6
+ export declare const createResizeObserver: () => {
7
+ /**
8
+ * Store which contains the dimensions of the observed element (ResizeObserverEntry type)
9
+ * See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)
10
+ */
11
+ dimensions$: ReadableSignal<ResizeObserverEntry | undefined>;
12
+ /** Directive to be attached to html element in order to listen to resize events */
13
+ directive: import("..").Directive;
14
+ };
@@ -0,0 +1,29 @@
1
+ import { derived } from '@amadeus-it-group/tansu';
2
+ import { createStoreDirective } from '../utils/directive';
3
+ import { noop } from '../utils/internal/func';
4
+ /**
5
+ * Create a resize observer object
6
+ * @returns An object containing the store with the dimentions of observed element (ResizeObserverEntry), the directive to be applied to the html element to be observed
7
+ */
8
+ export const createResizeObserver = () => {
9
+ const { element$, directive } = createStoreDirective();
10
+ const observedElement$ = derived(element$, (element, set) => {
11
+ if (element === null) {
12
+ return noop;
13
+ }
14
+ const observer = new ResizeObserver((entries) => {
15
+ set(entries[0]);
16
+ });
17
+ observer.observe(element);
18
+ return () => observer?.disconnect();
19
+ }, undefined);
20
+ return {
21
+ /**
22
+ * Store which contains the dimensions of the observed element (ResizeObserverEntry type)
23
+ * See the [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry)
24
+ */
25
+ dimensions$: observedElement$,
26
+ /** Directive to be attached to html element in order to listen to resize events */
27
+ directive,
28
+ };
29
+ };
@@ -2,6 +2,6 @@ import { createSimpleClassTransition } from '../simpleClassTransition';
2
2
  export const fadeTransition = createSimpleClassTransition({
3
3
  animationPendingClasses: ['fade'],
4
4
  animationPendingShowClasses: ['show'],
5
- showClasses: ['show'],
6
- hideClasses: ['d-none'],
5
+ showClasses: ['show', 'fade'],
6
+ hideClasses: ['d-none', 'fade'],
7
7
  });
@@ -22,6 +22,14 @@ export declare const bindDirective: <T>(directive: Directive<T>, directiveArg$:
22
22
  * @returns The resulting directive.
23
23
  */
24
24
  export declare const bindDirectiveNoArg: <T>(directive: Directive<void | T>) => Directive;
25
+ /**
26
+ * Maps the argument to another argument of a directive using a provided function.
27
+ *
28
+ * @param directive - The directive to be applied.
29
+ * @param fn - The function to map the argument.
30
+ * @returns A new directive that applies the mapping function to the argument.
31
+ */
32
+ export declare const mapDirectiveArg: <T, U>(directive: Directive<U>, fn: (arg: T) => U) => Directive<T>;
25
33
  /**
26
34
  * Returns a directive that subscribes to the given store while it is used on a DOM element,
27
35
  * and that unsubscribes from it when it is no longer used.
@@ -43,6 +43,22 @@ const noArg = readable(undefined);
43
43
  * @returns The resulting directive.
44
44
  */
45
45
  export const bindDirectiveNoArg = (directive) => bindDirective(directive, noArg);
46
+ /**
47
+ * Maps the argument to another argument of a directive using a provided function.
48
+ *
49
+ * @param directive - The directive to be applied.
50
+ * @param fn - The function to map the argument.
51
+ * @returns A new directive that applies the mapping function to the argument.
52
+ */
53
+ export const mapDirectiveArg = (directive, fn) => (node, arg) => {
54
+ const instance = directive(node, fn(arg));
55
+ return {
56
+ update: (arg) => {
57
+ instance?.update?.(fn(arg));
58
+ },
59
+ destroy: () => instance?.destroy?.(),
60
+ };
61
+ };
46
62
  /**
47
63
  * Returns a directive that subscribes to the given store while it is used on a DOM element,
48
64
  * and that unsubscribes from it when it is no longer used.
@@ -23,3 +23,18 @@ export declare const addClasses: (element: HTMLElement, classes?: string[]) => v
23
23
  * @param classes - the css classes
24
24
  */
25
25
  export declare const removeClasses: (element: HTMLElement, classes?: string[]) => void;
26
+ /**
27
+ * Adds an event listener to the specified element.
28
+ *
29
+ * @param element - The HTML element to which the event listener will be added.
30
+ * @param type - A string representing the event type to listen for.
31
+ * @param fn - The event listener function or object.
32
+ * @returns A function that removes the event listener from the element.
33
+ */
34
+ export declare function addEvent<K extends keyof HTMLElementEventMap>(element: HTMLElement, type: K, fn: (this: HTMLElement, ev: HTMLElementEventMap[K]) => any): () => void;
35
+ /**
36
+ * Generates a unique ID with the format 'auId-[counter]'.
37
+ *
38
+ * @returns The generated ID.
39
+ */
40
+ export declare const generateId: () => string;
@@ -59,3 +59,24 @@ export const removeClasses = (element, classes) => {
59
59
  element.classList.remove(...classes);
60
60
  }
61
61
  };
62
+ /**
63
+ * Adds an event listener to the specified element.
64
+ *
65
+ * @param element - The HTML element to which the event listener will be added.
66
+ * @param type - A string representing the event type to listen for.
67
+ * @param fn - The event listener function or object.
68
+ * @returns A function that removes the event listener from the element.
69
+ */
70
+ export function addEvent(element, type, fn) {
71
+ element.addEventListener(type, fn);
72
+ return function () {
73
+ element.removeEventListener(type, fn);
74
+ };
75
+ }
76
+ let idCount = 0;
77
+ /**
78
+ * Generates a unique ID with the format 'auId-[counter]'.
79
+ *
80
+ * @returns The generated ID.
81
+ */
82
+ export const generateId = () => `auId-${idCount++}`;
@@ -32,4 +32,6 @@ const isFocusableByTagName = {
32
32
  * @param element - element to test
33
33
  * @returns true if the element is programmatically focusable.
34
34
  */
35
- export const isFocusable = (element) => !isInertOrInvisible(element) && (isFocusableByTagName[element.tagName] ?? isFocusableOtherTags)(element);
35
+ export const isFocusable = (element) => {
36
+ return document.contains(element) && !isInertOrInvisible(element) && (isFocusableByTagName[element.tagName] ?? isFocusableOtherTags)(element);
37
+ };
@@ -4,4 +4,4 @@
4
4
  * @param element - the HTML element
5
5
  * @returns the text direction of the element, 'ltr' or 'rtl'
6
6
  */
7
- export declare const getTextDirection: (element: HTMLElement) => "rtl" | "ltr";
7
+ export declare const getTextDirection: (element: HTMLElement) => "ltr" | "rtl";
package/utils/stores.d.ts CHANGED
@@ -164,11 +164,22 @@ export declare const stateStores: <A extends {
164
164
  stores: { [key in `${string}$` & keyof A]: ReadableSignal<ValueOfStore<A[key]>>; };
165
165
  };
166
166
  /**
167
- * Creates a computed store that binds to multiple stores and triggers a callback when the value changes.
168
- * @param onChange$ - A readable signal callback function to execute when the value changes.
167
+ * Creates a derived store that binds to multiple stores and triggers a callback when the value changes for any reason.
168
+ * @param onChange$ - A readable signal containing a callback function to execute when the value changes.
169
169
  * @param stores - An array of Svelte stores, with the main store at index 0.
170
170
  * @param adjustValue - A function to adjust the value of the main store. By default, the value of the main store is returned.
171
171
  * @param equal - A function to determine if two values are equal. Used to compare the ajusted value with the current one.
172
172
  * @returns The derived store that reflects the combined state of the input stores.
173
173
  */
174
- export declare const bindableDerived: <T, U extends [WritableSignal<T, T>, ...StoreInput<any>[]]>(onChange$: ReadableSignal<(value: T) => void>, stores: U, adjustValue?: (arg: StoresInputValues<U>) => T, equal?: (currentValue: T, newValue: T) => boolean) => ReadableSignal<T>;
174
+ export declare const bindableDerived: <T, U extends [WritableSignal<T, T>, ...StoreInput<any>[]]>(onChange$: ReadableSignal<(value: T) => void>, stores: U, adjustValue?: (arg: StoresInputValues<U>) => T, equal?: (currentValue: T, newValue: T) => boolean) => WritableSignal<T, T>;
175
+ /**
176
+ * Creates a computed store that contains the adjusted value of the given store and that triggers a callback when the value changes from the set or update
177
+ * method of the returned writable store.
178
+ * @param store$ - store to be bound
179
+ * @param onChange$ - A readable signal containing a callback function to execute when the value changes from the set or update method of the returned writable store.
180
+ * @param adjustValue - A function to adjust the value of the store, called in a reactive context each time the value changes or any called dependency changes.
181
+ * By default, the value of store$ is returned.
182
+ * @param equal - A function to determine if two values are equal.
183
+ * @returns A writable store that contains the adjusted value of the given store, with the set or update functions that trigger the onChange$ callback.
184
+ */
185
+ export declare const bindableProp: <T>(store$: WritableSignal<T, T | undefined>, onChange$: ReadableSignal<(newValue: T) => void>, adjustValue?: (value: T) => T, equal?: (a: T, b: T) => boolean) => WritableSignal<T, T>;
package/utils/stores.js CHANGED
@@ -1,4 +1,4 @@
1
- import { asReadable, asWritable, batch, computed, derived, get, readable, writable } from '@amadeus-it-group/tansu';
1
+ import { asReadable, asWritable, batch, computed, derived, equal as tansuDefaultEqual, get, readable, writable } from '@amadeus-it-group/tansu';
2
2
  import { INVALID_VALUE } from '../types';
3
3
  import { identity } from './internal/func';
4
4
  /**
@@ -252,8 +252,8 @@ export const stateStores = (inputStores) => {
252
252
  };
253
253
  };
254
254
  /**
255
- * Creates a computed store that binds to multiple stores and triggers a callback when the value changes.
256
- * @param onChange$ - A readable signal callback function to execute when the value changes.
255
+ * Creates a derived store that binds to multiple stores and triggers a callback when the value changes for any reason.
256
+ * @param onChange$ - A readable signal containing a callback function to execute when the value changes.
257
257
  * @param stores - An array of Svelte stores, with the main store at index 0.
258
258
  * @param adjustValue - A function to adjust the value of the main store. By default, the value of the main store is returned.
259
259
  * @param equal - A function to determine if two values are equal. Used to compare the ajusted value with the current one.
@@ -261,7 +261,7 @@ export const stateStores = (inputStores) => {
261
261
  */
262
262
  export const bindableDerived = (onChange$, stores, adjustValue = (arg) => arg[0], equal = (currentValue, newValue) => newValue === currentValue) => {
263
263
  let currentValue = stores[0]();
264
- return derived(stores, {
264
+ return asWritable(derived(stores, {
265
265
  derive(values) {
266
266
  const newValue = adjustValue(values);
267
267
  const rectifiedValue = !equal(values[0], newValue);
@@ -277,5 +277,22 @@ export const bindableDerived = (onChange$, stores, adjustValue = (arg) => arg[0]
277
277
  return newValue;
278
278
  },
279
279
  equal,
280
- });
280
+ }), stores[0].set.bind(stores[0]));
281
281
  };
282
+ /**
283
+ * Creates a computed store that contains the adjusted value of the given store and that triggers a callback when the value changes from the set or update
284
+ * method of the returned writable store.
285
+ * @param store$ - store to be bound
286
+ * @param onChange$ - A readable signal containing a callback function to execute when the value changes from the set or update method of the returned writable store.
287
+ * @param adjustValue - A function to adjust the value of the store, called in a reactive context each time the value changes or any called dependency changes.
288
+ * By default, the value of store$ is returned.
289
+ * @param equal - A function to determine if two values are equal.
290
+ * @returns A writable store that contains the adjusted value of the given store, with the set or update functions that trigger the onChange$ callback.
291
+ */
292
+ export const bindableProp = (store$, onChange$, adjustValue = identity, equal = tansuDefaultEqual) => asWritable(computed(() => adjustValue(store$()), { equal }), (newValue) => {
293
+ const adjustedValue = adjustValue(newValue);
294
+ if (!equal(store$(), adjustedValue)) {
295
+ store$.set(adjustedValue);
296
+ onChange$()(adjustedValue);
297
+ }
298
+ });