Skip to content

Commit

Permalink
feat: allow passing onX={x} in addition to on:X={x} in svelte components
Browse files Browse the repository at this point in the history
  • Loading branch information
divdavem committed Nov 13, 2023
1 parent a5e8e6b commit 4120bf3
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
2 changes: 1 addition & 1 deletion svelte/headless/slotTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {ComponentType, SvelteComponent} from 'svelte';

export const useSvelteSlot = Symbol('useSvelteSlot');

export type WidgetPropsProps<Props extends object> = Partial<Omit<Props, `on${string}`>>;
export type WidgetPropsProps<Props extends object> = Partial<Props>;

export type WidgetPropsEvents<Props extends object> = {
[K in keyof Props & `on${string}` as K extends `on${infer U}` ? Uncapitalize<U> : never]: NonNullable<Props[K]> extends (arg: infer U) => void
Expand Down
29 changes: 26 additions & 3 deletions svelte/headless/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type {Widget, WidgetFactory, WidgetProps} from '@agnos-ui/core';
import {findChangedProperties, toReadableStore} from '@agnos-ui/core';
import type {ReadableSignal} from '@amadeus-it-group/tansu';
import {computed} from '@amadeus-it-group/tansu';
import type {ReadableSignal, WritableSignal} from '@amadeus-it-group/tansu';
import {asReadable, computed, writable} from '@amadeus-it-group/tansu';
import {createEventDispatcher as svelteCreateEventDispatcher} from 'svelte';
import type {SlotContent, SlotSvelteComponent, SlotsPresent} from './slotTypes';
import {useSvelteSlot} from './slotTypes';
Expand All @@ -20,6 +20,25 @@ export function createPatchChangedProps<T extends object>(patchFn: (arg: Partial
export const createEventDispatcher = <T extends object>() =>
svelteCreateEventDispatcher<{[K in keyof T]: T[K] extends CustomEvent<infer U> ? U : never}>();

const mergeEventFns = <T extends any[]>(fn1: undefined | null | ((...args: T) => void), fn2: undefined | null | ((...args: T) => void)) =>
fn1 && fn2
? (...args: any) => {
fn1(...args);
fn2(...args);
}
: fn1 ?? fn2 ?? undefined;

const eventStore = <T extends any[]>(event: undefined | null | ((...args: T) => void)): WritableSignal<undefined | null | ((...args: T) => void)> => {
const store$ = writable<undefined | null | ((...args: T) => void)>(undefined, {equal: Object.is});
return asReadable(
computed(() => mergeEventFns(event, store$()) as any),
{
set: store$.set,
update: store$.update,
}
);
};

export const callWidgetFactoryWithConfig = <W extends Widget>({
factory,
$$slots,
Expand All @@ -40,10 +59,14 @@ export const callWidgetFactoryWithConfig = <W extends Widget>({
processedSlots[`slot${name[0].toUpperCase()}${name.substring(1)}`] = useSvelteSlot;
}
}
const props: {[key in keyof WidgetProps<W>]: WritableSignal<WidgetProps<W>[key]>} = {} as any;
for (const event of Object.keys(events) as (keyof WidgetProps<W> & `on${string}`)[]) {
props[event] = eventStore(events[event] as any) as any;
}
const widget = factory({
config: computed(() => ({...defaultConfig$(), ...widgetConfig?.(), ...processedSlots})),
props,
});
widget.patch(events);
return {...widget, patchChangedProps: createPatchChangedProps(widget.patch)};
};

Expand Down
1 change: 0 additions & 1 deletion svelte/lib/modal/modalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export async function openModal<Data>(options: Partial<ModalProps<Data>>, {conte
target,
props: options,
context,
// TODO: exclude events? it seems to work like this, but it is probably not the correct way
});
try {
return await component.api.open();
Expand Down

0 comments on commit 4120bf3

Please sign in to comment.