Skip to content

Commit

Permalink
feat(svelte/demo/daisyui): svelte 5 migration
Browse files Browse the repository at this point in the history
  • Loading branch information
quentinderoubaix committed Sep 24, 2024
1 parent 9128d8c commit 526b694
Show file tree
Hide file tree
Showing 18 changed files with 148 additions and 106 deletions.
3 changes: 2 additions & 1 deletion svelte/demo/src/daisyui/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import App from './App.svelte';
import {mount} from 'svelte';

export const main = new App({
export const main = mount(App, {
target: document.getElementById('root')!,
});
13 changes: 9 additions & 4 deletions svelte/demo/src/daisyui/samples/accordion/Accordion.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@
import {type AccordionProps, createAccordion} from '@agnos-ui/svelte-headless/components/accordion';
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
import {setAccordionApi} from './accordion';
import type {Snippet} from 'svelte';
type $$Props = Partial<Pick<AccordionProps, 'closeOthers' | 'onItemShown' | 'onItemHidden' | 'itemDestroyOnHide' | 'className'>>;
let {
children,
...props
}: Partial<Pick<AccordionProps, 'closeOthers' | 'onItemShown' | 'onItemHidden' | 'itemDestroyOnHide' | 'className'>> & {children: Snippet} =
$props();
const widget = callWidgetFactory({
factory: createAccordion,
widgetName: 'accordion',
$$props,
props,
});
setAccordionApi(widget.api);
$: widget.patchChangedProps($$props);
$effect(() => widget.patchChangedProps({...props}));
</script>

<div class="flex flex-col gap-2" use:widget.directives.accordionDirective>
<slot />
{@render children()}
</div>
25 changes: 16 additions & 9 deletions svelte/demo/src/daisyui/samples/accordion/AccordionItem.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,29 @@
import {type AccordionItemProps, type AccordionItemWidget} from '@agnos-ui/svelte-headless/components/accordion';
import type {WidgetFactory} from '@agnos-ui/svelte-headless/types';
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
import {onMount} from 'svelte';
import {onMount, type Snippet} from 'svelte';
import {createSimpleClassTransition} from '@agnos-ui/svelte-headless/services/transitions/simpleClassTransition';
import {getAccordionApi} from './accordion';
type $$Props = Partial<Pick<AccordionItemProps, 'className' | 'destroyOnHide' | 'onVisibleChange' | 'visible' | 'onHidden' | 'onShown' | 'id'>>;
let {
header,
children,
visible = $bindable(),
...props
}: Partial<Pick<AccordionItemProps, 'className' | 'destroyOnHide' | 'onVisibleChange' | 'visible' | 'onHidden' | 'onShown' | 'id'>> & {
header: Snippet;
children: Snippet;
} = $props();
const transition = createSimpleClassTransition({
showClasses: ['collapse-open'],
animationPendingShowClasses: ['collapse-open'],
});
const {registerItem} = getAccordionApi();
export let visible: boolean | undefined = undefined;
const widget = callWidgetFactory({
factory: registerItem as WidgetFactory<AccordionItemWidget>,
$$props,
props: {visible, ...props},
events: {
onVisibleChange: (event) => {
visible = event;
Expand All @@ -32,9 +39,9 @@
directives: {itemDirective, toggleDirective, transitionDirective, bodyContainerAttrsDirective},
api: {toggle},
} = widget;
$: widget.patchChangedProps($$props);
$effect(() => widget.patchChangedProps({visible, ...props}));
const onEnter = (e: KeyboardEvent) => {
const onkeydown = (e: KeyboardEvent) => {
if (e.key === 'Enter') {
toggle();
}
Expand All @@ -43,12 +50,12 @@
</script>

<div class="collapse collapse-arrow bg-base-200" use:itemDirective use:transitionDirective>
<div role="button" tabindex="0" class="collapse-title text-xl font-medium focus-visible:outline-none" use:toggleDirective on:keydown={onEnter}>
<slot name="header"></slot>
<div role="button" tabindex="0" class="collapse-title text-xl font-medium focus-visible:outline-none" use:toggleDirective {onkeydown}>
{@render header()}
</div>
<div class="collapse-content" use:bodyContainerAttrsDirective>
{#if $shouldBeInDOM$}
<slot name="body"></slot>
{@render children()}
{/if}
</div>
</div>
18 changes: 12 additions & 6 deletions svelte/demo/src/daisyui/samples/accordion/Default.route.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@

<Accordion closeOthers itemDestroyOnHide>
<AccordionItem visible>
<svelte:fragment slot="header">First header</svelte:fragment>
<svelte:fragment slot="body">First content</svelte:fragment>
{#snippet header()}
First header
{/snippet}
First content
</AccordionItem>
<AccordionItem>
<svelte:fragment slot="header">Second header</svelte:fragment>
<svelte:fragment slot="body">Second content</svelte:fragment>
{#snippet header()}
Second header
{/snippet}
Second content
</AccordionItem>
<AccordionItem>
<svelte:fragment slot="header">Third header</svelte:fragment>
<svelte:fragment slot="body">Third content</svelte:fragment>
{#snippet header()}
Third header
{/snippet}
Third content
</AccordionItem>
</Accordion>
20 changes: 12 additions & 8 deletions svelte/demo/src/daisyui/samples/alert/Alert.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,29 @@
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
import {createSimpleClassTransition} from '@agnos-ui/svelte-headless/services/transitions/simpleClassTransition';
import closeIconSvg from '@agnos-ui/common/samples/common/close_icon.svg?raw';
type $$Props = Partial<Pick<AlertProps, 'className' | 'visible' | 'dismissible' | 'ariaCloseButtonLabel'>>;
import type {Snippet} from 'svelte';
let {
visible = $bindable(),
children,
...props
}: Partial<Pick<AlertProps, 'className' | 'visible' | 'dismissible' | 'ariaCloseButtonLabel'>> & {children: Snippet} = $props();
const transition = createSimpleClassTransition({
showClasses: ['transition-opacity'],
hideClasses: ['opacity-0'],
animationPendingHideClasses: ['opacity-0', 'transition-opacity'],
});
export const {
const {
stores: {className$, dismissible$, ariaCloseButtonLabel$, hidden$},
directives: {transitionDirective},
patchChangedProps,
api,
} = callWidgetFactory({
factory: createAlert,
widgetName: 'alert',
$$props,
props: {...props, visible},
defaultConfig: {transition},
events: {
onVisibleChange: (event) => {
Expand All @@ -29,16 +35,14 @@
},
});
export let visible: boolean | undefined = undefined;
$: patchChangedProps($$props);
$effect(() => patchChangedProps({...props, visible}));
</script>

{#if !$hidden$}
<div role="alert" class="flex alert {$className$}" use:transitionDirective>
<slot />
{@render children()}
{#if $dismissible$}
<button class="btn btn-sm btn-circle btn-ghost ms-auto" on:click={api.close} aria-label={$ariaCloseButtonLabel$}>
<button class="btn btn-sm btn-circle btn-ghost ms-auto" onclick={api.close} aria-label={$ariaCloseButtonLabel$}>
{@html closeIconSvg}
</button>
{/if}
Expand Down
4 changes: 2 additions & 2 deletions svelte/demo/src/daisyui/samples/alert/Default.route.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script lang="ts">
import Alert from './Alert.svelte';
let visible = true;
let visible = $state(true);
</script>

<button class="btn btn-primary" on:click={() => (visible = true)}>Reset Alert</button>
<button class="btn btn-primary" onclick={() => (visible = true)}>Reset Alert</button>
<div class="flex flex-col gap-3 mt-3">
<Alert className="alert-success" bind:visible>
<svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"
Expand Down
13 changes: 6 additions & 7 deletions svelte/demo/src/daisyui/samples/modal/Default.route.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<script lang="ts">
import Modal from './Modal.svelte';
let visible = false;
<script>
import {openModal} from './modal';
const onclick = () => openModal({children: modalContent, closeOnOutsideClick: true});
</script>

<Modal bind:visible closeOnOutsideClick>
{#snippet modalContent()}
<h3 class="font-bold text-lg">A simple modal</h3>
<p class="py-4">Press ESC key, click on ✕ button or click outside the modal to close</p>
</Modal>
<button class="btn" aria-haspopup="dialog" on:click={() => (visible = true)}> Open modal </button>
{/snippet}
<button class="btn" aria-haspopup="dialog" {onclick}> Open modal </button>
30 changes: 14 additions & 16 deletions svelte/demo/src/daisyui/samples/modal/Modal.svelte
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
<script lang="ts">
import {createModal} from '@agnos-ui/svelte-headless/components/modal';
import type {ModalProps} from '@agnos-ui/svelte-headless/components/modal';
import type {DaisyModalProps} from './modal';
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
type $$Props = Partial<Pick<ModalProps, 'closeOnOutsideClick' | 'ariaCloseButtonLabel' | 'closeButton' | 'visible' | 'onVisibleChange'>>;
let {children, closeOnOutsideClick, visible = $bindable(), ...props}: DaisyModalProps = $props();
export const {
stores: {visible$, closeButton$},
directives: {closeButtonDirective, dialogDirective},
patchChangedProps,
patch,
api,
} = callWidgetFactory({
const widget = callWidgetFactory({
factory: createModal,
widgetName: 'modal',
$$props,
props: {visible, closeOnOutsideClick, ...props},
defaultConfig: {closeButton: true},
events: {
onVisibleChange: (event) => {
visible = event;
},
},
});
export let visible: boolean | undefined = undefined;
export let closeOnOutsideClick: boolean | undefined = undefined;
export const api = widget.api;
const {
stores: {closeButton$},
directives: {closeButtonDirective, dialogDirective},
patchChangedProps,
} = widget;
$: patchChangedProps($$props);
$effect(() => patchChangedProps({visible, closeOnOutsideClick, ...props}));
</script>

<dialog class="modal modal-bottom sm:modal-middle" on:close={api.close} use:dialogDirective>
<dialog class="modal modal-bottom sm:modal-middle" onclose={api.close} use:dialogDirective>
<div class="modal-box">
<slot />
{@render children()}
{#if $closeButton$}
<form method="dialog">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" use:closeButtonDirective> ✕ </button>
Expand All @@ -39,7 +37,7 @@
</div>
{#if closeOnOutsideClick}
<form method="dialog" class="modal-backdrop">
<button on:click={api.close}>Close</button>
<button onclick={api.close}>Close</button>
</form>
{/if}
</dialog>
22 changes: 22 additions & 0 deletions svelte/demo/src/daisyui/samples/modal/modal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type {ModalProps} from '@agnos-ui/svelte-headless/components/modal';
import Modal from './Modal.svelte';
import {mount, unmount, type Snippet} from 'svelte';

export type DaisyModalProps = Partial<
Pick<ModalProps, 'closeOnOutsideClick' | 'ariaCloseButtonLabel' | 'closeButton' | 'visible' | 'onVisibleChange'>
> & {children: Snippet};

export async function openModal(options: DaisyModalProps) {
const target = document.createElement('div');
document.body.append(target);
const component = mount(Modal, {
target,
props: options,
});
try {
return await component.api.open();
} finally {
target.remove();
unmount(component);
}
}
26 changes: 10 additions & 16 deletions svelte/demo/src/daisyui/samples/pagination/Pagination.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@
import {createPagination} from '@agnos-ui/svelte-headless/components/pagination';
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
type $$Props = Partial<PaginationProps>;
/**
* The current page.
*
* Page numbers start with `1`.
*/
export let page: $$Props['page'] = undefined;
let {page = $bindable(), ...props}: Partial<PaginationProps> = $props();
const widget = callWidgetFactory({
factory: createPagination,
widgetName: 'pagination',
$$props,
props: {...props, page},
events: {
onPageChange: (value: number) => {
page = value;
Expand All @@ -40,7 +33,8 @@
state$,
actions: {first, previous, next, last},
} = widget;
$: widget.patchChangedProps($$props);
$effect(() => widget.patchChangedProps({...props, page}));
</script>

<nav aria-label={$ariaLabel$}>
Expand All @@ -49,7 +43,7 @@
<button
class="join-item btn btn-outline"
aria-label={$ariaFirstLabel$}
on:click={() => first()}
onclick={() => first()}
disabled={$previousDisabled$}
aria-disabled={$previousDisabled$ ? 'true' : null}
tabindex={$previousDisabled$ ? -1 : undefined}
Expand All @@ -62,20 +56,20 @@
class="join-item btn btn-outline"
disabled={$previousDisabled$}
aria-label={$ariaPreviousLabel$}
on:click={() => previous()}
onclick={() => previous()}
tabindex={$previousDisabled$ ? -1 : undefined}
aria-disabled={$previousDisabled$ ? 'true' : null}
>
<span aria-hidden="true"> ‹ </span>
</button>
{/if}
{#each $state$.pages as page, i}
{#each $state$.pages as page}
<button
class="join-item btn btn-outline"
class:btn-active={page === $state$.page}
aria-current={page === $state$.page ? 'page' : null}
tabindex={page === -1 ? -1 : $state$.disabled ? -1 : undefined}
on:click={page === -1 ? () => {} : () => widget.actions.select(page)}
onclick={page === -1 ? () => {} : () => widget.actions.select(page)}
disabled={page === -1 || $state$.disabled}
>{page}
{#if $state$.page === page}<span class="sr-only">{$state$.activeLabel}</span>{/if}
Expand All @@ -86,7 +80,7 @@
class="join-item btn btn-outline"
disabled={$nextDisabled$}
aria-label={$ariaNextLabel$}
on:click={() => next()}
onclick={() => next()}
tabindex={$nextDisabled$ ? -1 : undefined}
aria-disabled={$nextDisabled$ ? 'true' : null}
>
Expand All @@ -97,7 +91,7 @@
<button
class="join-item btn btn-outline"
aria-label={$ariaLastLabel$}
on:click={() => last()}
onclick={() => last()}
disabled={$nextDisabled$}
tabindex={$nextDisabled$ ? -1 : undefined}
aria-disabled={$nextDisabled$ ? 'true' : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import {createProgressbar, type ProgressbarProps} from '@agnos-ui/svelte-headless/components/progressbar';
import {callWidgetFactory} from '@agnos-ui/svelte-headless/config';
type $$Props = Partial<Omit<ProgressbarProps, 'min'>>;
let props: Partial<Omit<ProgressbarProps, 'min'>> = $props();
const {
stores: {value$, max$, className$},
directives: {ariaDirective},
patchChangedProps,
} = callWidgetFactory({factory: createProgressbar, widgetName: 'progressbar', $$props});
$: patchChangedProps($$props);
} = callWidgetFactory({factory: createProgressbar, widgetName: 'progressbar', props});
$effect(() => patchChangedProps({...props}));
</script>

<progress use:ariaDirective class="progress {$className$}" value={$value$} max={$max$} />
<progress use:ariaDirective class="progress {$className$}" value={$value$} max={$max$}></progress>
Loading

0 comments on commit 526b694

Please sign in to comment.