mirror of
				https://github.com/Blah-IM/Weblah.git
				synced 2025-11-03 19:31:38 +00:00 
			
		
		
		
	refactor: migrate to svelte 5, vite 6 and bits-ui 1.
This commit is contained in:
		
							parent
							
								
									0bb201636a
								
							
						
					
					
						commit
						1e95dc0830
					
				
					 45 changed files with 1069 additions and 793 deletions
				
			
		| 
						 | 
				
			
			@ -2,10 +2,15 @@
 | 
			
		|||
	import { tw } from '$lib/tw';
 | 
			
		||||
	import { patterns, type PatternName } from './BgPattern';
 | 
			
		||||
 | 
			
		||||
	export let pattern: PatternName = 'rain';
 | 
			
		||||
 | 
			
		||||
	let className: string = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		pattern?: PatternName;
 | 
			
		||||
		class?: string;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { pattern = 'rain', class: className = '', children }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
| 
						 | 
				
			
			@ -15,5 +20,5 @@
 | 
			
		|||
	)}
 | 
			
		||||
	style:--pattern-image={`url("${patterns[pattern]}")`}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,42 +1,44 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
	import type { HTMLAnchorAttributes, HTMLButtonAttributes } from 'svelte/elements';
 | 
			
		||||
 | 
			
		||||
	type HTMLButtonOrAnchorAttributes = Partial<HTMLAnchorAttributes> & Partial<HTMLButtonAttributes>;
 | 
			
		||||
 | 
			
		||||
	interface $$Props extends HTMLButtonOrAnchorAttributes {
 | 
			
		||||
	interface Props {
 | 
			
		||||
		variant?: 'primary' | 'secondary';
 | 
			
		||||
		class?: string | null;
 | 
			
		||||
		href?: string | null;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
		[key: string]: unknown;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	export let variant: $$Props['variant'] = 'secondary';
 | 
			
		||||
	let className: string | null = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
 | 
			
		||||
	export let href: string | null = null;
 | 
			
		||||
	let {
 | 
			
		||||
		variant = 'secondary',
 | 
			
		||||
		class: className = '',
 | 
			
		||||
		href = null,
 | 
			
		||||
		children,
 | 
			
		||||
		...rest
 | 
			
		||||
	}: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<svelte:element
 | 
			
		||||
	this={href ? 'a' : 'button'}
 | 
			
		||||
	{href}
 | 
			
		||||
	class={tw(
 | 
			
		||||
		'inline-flex cursor-default items-center justify-center rounded-md px-2 py-1 text-sf-secondary shadow-xs ring-1 ring-ss-secondary',
 | 
			
		||||
		'font-normal transition-shadow duration-200 hover:ring-ss-primary active:shadow-inner',
 | 
			
		||||
		'text-sf-secondary ring-ss-secondary inline-flex cursor-default items-center justify-center rounded-md px-2 py-1 shadow-xs ring-1',
 | 
			
		||||
		'hover:ring-ss-primary font-normal transition-shadow duration-200 active:shadow-inner',
 | 
			
		||||
		variant === 'primary' && [
 | 
			
		||||
			'relative text-slate-50 ring-0 duration-200',
 | 
			
		||||
			'before:absolute before:-inset-px before:rounded-[7px]',
 | 
			
		||||
			'before:bg-linear-to-b before:from-accent-400 before:from-40% before:to-accent-500 before:ring-1 before:ring-inset before:ring-black/10',
 | 
			
		||||
			'before:transition-shadow active:before:shadow-inner dark:before:from-accent-500 dark:before:to-accent-600'
 | 
			
		||||
			'before:from-accent-400 before:to-accent-500 before:bg-linear-to-b before:from-40% before:ring-1 before:ring-black/10 before:ring-inset',
 | 
			
		||||
			'dark:before:from-accent-500 dark:before:to-accent-600 before:transition-shadow active:before:shadow-inner'
 | 
			
		||||
		],
 | 
			
		||||
		className
 | 
			
		||||
	)}
 | 
			
		||||
	{...$$restProps}
 | 
			
		||||
	on:click
 | 
			
		||||
	role="button"
 | 
			
		||||
	tabindex="0"
 | 
			
		||||
	{...rest}
 | 
			
		||||
>
 | 
			
		||||
	{#if variant === 'primary'}
 | 
			
		||||
		<div class="z-10 drop-shadow-[0_-1px_0_--theme(--color-black/0.2)]"><slot /></div>
 | 
			
		||||
		<div class="z-10 drop-shadow-[0_-1px_0_--theme(--color-black/0.2)]">{@render children?.()}</div>
 | 
			
		||||
	{:else}
 | 
			
		||||
		<slot />
 | 
			
		||||
		{@render children?.()}
 | 
			
		||||
	{/if}
 | 
			
		||||
</svelte:element>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,9 +4,15 @@
 | 
			
		|||
	import { expoOut } from 'svelte/easing';
 | 
			
		||||
	import { scale } from 'svelte/transition';
 | 
			
		||||
 | 
			
		||||
	interface $$Props extends DropdownMenuContentProps {}
 | 
			
		||||
	let className: $$Props['class'] = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	
 | 
			
		||||
	interface Props {
 | 
			
		||||
		class?: $$Props['class'];
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
		[key: string]: any
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { class: className = '', children, ...rest }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<DropdownMenu.Content
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +23,7 @@
 | 
			
		|||
	sideOffset={4}
 | 
			
		||||
	transition={scale}
 | 
			
		||||
	transitionConfig={{ start: 0.96, duration: 300, easing: expoOut }}
 | 
			
		||||
	{...$$restProps}
 | 
			
		||||
	{...rest}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</DropdownMenu.Content>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,15 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { DropdownMenu, type DropdownMenuItemProps } from 'bits-ui';
 | 
			
		||||
	interface Props extends DropdownMenuItemProps {
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type $$Props = DropdownMenuItemProps;
 | 
			
		||||
	let { children, ...rest }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<DropdownMenu.Item
 | 
			
		||||
	class="cursor-default rounded-sm px-1.5 py-0.5 text-sf-primary transition-colors duration-200 hover:bg-accent-50 group-has-data-melt-dropdown-menu-radio-group:ps-6 dark:hover:bg-white/5"
 | 
			
		||||
	on:click
 | 
			
		||||
	{...$$restProps}
 | 
			
		||||
	class="text-sf-primary hover:bg-accent-50 cursor-default rounded-sm px-1.5 py-0.5 transition-colors duration-200 group-has-data-melt-dropdown-menu-radio-group:ps-6 dark:hover:bg-white/5"
 | 
			
		||||
	{...rest}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</DropdownMenu.Item>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,17 +3,21 @@
 | 
			
		|||
	import { DropdownMenu } from 'bits-ui';
 | 
			
		||||
	import { Check, Icon } from 'svelte-hero-icons';
 | 
			
		||||
 | 
			
		||||
	type $$Props = DropdownMenuRadioItemProps;
 | 
			
		||||
	export let value: string;
 | 
			
		||||
	interface Props extends DropdownMenuRadioItemProps {
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { children: componentChildren, ...props }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<DropdownMenu.RadioItem
 | 
			
		||||
	class="flex cursor-default items-center gap-1 rounded-sm px-1.5 py-0.5 text-sf-primary transition-colors duration-200 hover:bg-accent-50 dark:hover:bg-white/5"
 | 
			
		||||
	{value}
 | 
			
		||||
	{...$$props}
 | 
			
		||||
	class="text-sf-primary hover:bg-accent-50 flex cursor-default items-center gap-1 rounded-sm px-1.5 py-0.5 transition-colors duration-200 dark:hover:bg-white/5"
 | 
			
		||||
	{...props}
 | 
			
		||||
>
 | 
			
		||||
	<DropdownMenu.RadioIndicator class="relative size-4">
 | 
			
		||||
		<Icon src={Check} class="size-full" micro />
 | 
			
		||||
	</DropdownMenu.RadioIndicator>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{#snippet children(itemProps)}
 | 
			
		||||
		{#if itemProps.checked}
 | 
			
		||||
			<Icon src={Check} class="size-full" micro />
 | 
			
		||||
		{/if}
 | 
			
		||||
		{@render componentChildren?.()}
 | 
			
		||||
	{/snippet}
 | 
			
		||||
</DropdownMenu.RadioItem>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,14 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { DropdownMenu, type DropdownMenuTriggerProps } from 'bits-ui';
 | 
			
		||||
	interface Props {
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
		[key: string]: any
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { children, ...rest }: Props = $props();
 | 
			
		||||
	type $$Props = DropdownMenuTriggerProps;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<DropdownMenu.Trigger class="cursor-default" {...$$restProps}>
 | 
			
		||||
	<slot />
 | 
			
		||||
<DropdownMenu.Trigger class="cursor-default" {...rest}>
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</DropdownMenu.Trigger>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +1,9 @@
 | 
			
		|||
<div class="mx-auto max-w-3xl"><slot /></div>
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	interface Props {
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { children }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="mx-auto max-w-3xl">{@render children?.()}</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,13 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	interface Props {
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { children }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<label
 | 
			
		||||
	class="flex gap-2 px-4 py-3 font-medium text-sf-primary [align-items:first_baseline] [&>input]:flex-1 [&>input]:bg-transparent [&>input]:text-end [&>input]:outline-hidden [&>input]:placeholder:opacity-50"
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</label>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,23 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { createBubbler } from 'svelte/legacy';
 | 
			
		||||
 | 
			
		||||
	const bubble = createBubbler();
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
	import { Icon, type IconSource } from 'svelte-hero-icons';
 | 
			
		||||
 | 
			
		||||
	export let href: string | undefined = undefined;
 | 
			
		||||
	export let icon: IconSource | undefined = undefined;
 | 
			
		||||
	export let selected: boolean = false;
 | 
			
		||||
	interface Props {
 | 
			
		||||
		href?: string | undefined;
 | 
			
		||||
		icon?: IconSource | undefined;
 | 
			
		||||
		selected?: boolean;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let {
 | 
			
		||||
		href = undefined,
 | 
			
		||||
		icon = undefined,
 | 
			
		||||
		selected = false,
 | 
			
		||||
		children
 | 
			
		||||
	}: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<svelte:element
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +29,7 @@
 | 
			
		|||
	)}
 | 
			
		||||
	tabindex="0"
 | 
			
		||||
	role="button"
 | 
			
		||||
	on:click
 | 
			
		||||
	onclick={bubble('click')}
 | 
			
		||||
>
 | 
			
		||||
	{#if icon}
 | 
			
		||||
		<Icon
 | 
			
		||||
| 
						 | 
				
			
			@ -25,5 +38,5 @@
 | 
			
		|||
			mini
 | 
			
		||||
		/>
 | 
			
		||||
	{/if}
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</svelte:element>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,27 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	interface Props {
 | 
			
		||||
		header?: import('svelte').Snippet;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
		footer?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { header, children, footer }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<section class="my-6 cursor-default px-4">
 | 
			
		||||
	{#if $$slots.header}
 | 
			
		||||
	{#if header}
 | 
			
		||||
		<h3 class="mb-1 truncate px-4 text-sm font-medium uppercase text-sf-tertiary">
 | 
			
		||||
			<slot name="header" />
 | 
			
		||||
			{@render header?.()}
 | 
			
		||||
		</h3>
 | 
			
		||||
	{/if}
 | 
			
		||||
	<div
 | 
			
		||||
		class="divide-y-[0.5px] divide-ss-secondary overflow-hidden rounded-lg border-[0.5px] border-ss-secondary bg-sb-primary shadow-xs"
 | 
			
		||||
	>
 | 
			
		||||
		<slot />
 | 
			
		||||
		{@render children?.()}
 | 
			
		||||
	</div>
 | 
			
		||||
	{#if $$slots.footer}
 | 
			
		||||
	{#if footer}
 | 
			
		||||
		<div class="mt-1 px-4 text-sm text-sf-tertiary">
 | 
			
		||||
			<slot name="footer" />
 | 
			
		||||
			{@render footer?.()}
 | 
			
		||||
		</div>
 | 
			
		||||
	{/if}
 | 
			
		||||
</section>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,13 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	let className = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		class?: string;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { class: className = '', children }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<label
 | 
			
		||||
| 
						 | 
				
			
			@ -11,5 +16,5 @@
 | 
			
		|||
		className
 | 
			
		||||
	)}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</label>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,13 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	export let href: string;
 | 
			
		||||
	export let variant: 'primary' | 'secondary' = 'primary';
 | 
			
		||||
	interface Props {
 | 
			
		||||
		href: string;
 | 
			
		||||
		variant?: 'primary' | 'secondary';
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { href, variant = 'primary', children }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<a
 | 
			
		||||
| 
						 | 
				
			
			@ -12,5 +17,5 @@
 | 
			
		|||
		variant === 'primary'
 | 
			
		||||
			? 'text-accent-600 dark:text-accent-500'
 | 
			
		||||
			: 'text-accent-400 dark:text-accent-500'
 | 
			
		||||
	)}><slot /></a
 | 
			
		||||
	)}>{@render children?.()}</a
 | 
			
		||||
>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,12 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	let className = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		class?: string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { class: className = '' }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class={tw('loading-indicator relative inline-block size-5 [&>div]:bg-sf-tertiary', className)}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,13 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	let className = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		class?: string;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { class: className = '', children }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<header
 | 
			
		||||
| 
						 | 
				
			
			@ -11,5 +16,5 @@
 | 
			
		|||
		className
 | 
			
		||||
	)}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</header>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,12 @@
 | 
			
		|||
	import type { Account } from '$lib/accounts/accountStore';
 | 
			
		||||
	import { AvatarBeam } from 'svelte-boring-avatars';
 | 
			
		||||
 | 
			
		||||
	export let account: Account | undefined;
 | 
			
		||||
	export let size: number = 32;
 | 
			
		||||
	interface Props {
 | 
			
		||||
		account: Account | undefined;
 | 
			
		||||
		size?: number;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { account, size = 32 }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#if account}
 | 
			
		||||
| 
						 | 
				
			
			@ -13,9 +17,9 @@
 | 
			
		|||
	<span class="sr-only">{account.profile.signee.payload.name}</span>
 | 
			
		||||
{:else}
 | 
			
		||||
	<div
 | 
			
		||||
		class="box-border size-(--weblah-profile-pic-size) rounded-full border-2 border-dashed border-ss-primary"
 | 
			
		||||
		class="border-ss-primary box-border size-(--weblah-profile-pic-size) rounded-full border-2 border-dashed"
 | 
			
		||||
		style:--weblah-profile-pic-size={`${size}px`}
 | 
			
		||||
		aria-hidden
 | 
			
		||||
	/>
 | 
			
		||||
		aria-hidden="true"
 | 
			
		||||
	></div>
 | 
			
		||||
	<span class="sr-only">Account Unavailable</span>
 | 
			
		||||
{/if}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,14 +4,27 @@
 | 
			
		|||
	import InputFrame from '$lib/components/InputFrame.svelte';
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	export let delta: Delta | null = null;
 | 
			
		||||
	export let plainText: string | undefined = undefined;
 | 
			
		||||
	export let keyboardSubmitMethod: 'enter' | 'shiftEnter' | undefined = undefined;
 | 
			
		||||
	export let placeholder: string = '';
 | 
			
		||||
	export let editor: Editor | undefined;
 | 
			
		||||
 | 
			
		||||
	let className = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		delta?: Delta | null;
 | 
			
		||||
		plainText?: string | undefined;
 | 
			
		||||
		keyboardSubmitMethod?: 'enter' | 'shiftEnter' | undefined;
 | 
			
		||||
		placeholder?: string;
 | 
			
		||||
		editor: Editor | undefined;
 | 
			
		||||
		class?: string;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let {
 | 
			
		||||
		delta = $bindable(null),
 | 
			
		||||
		plainText = $bindable(undefined),
 | 
			
		||||
		keyboardSubmitMethod = undefined,
 | 
			
		||||
		placeholder = '',
 | 
			
		||||
		editor = $bindable(),
 | 
			
		||||
		class: className = '',
 | 
			
		||||
		children
 | 
			
		||||
	}: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	const loadClientComponent = async () => {
 | 
			
		||||
		if (!browser) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,8 +39,7 @@
 | 
			
		|||
			<p>{placeholder}</p>
 | 
			
		||||
		</div>
 | 
			
		||||
	{:then Input}
 | 
			
		||||
		<svelte:component
 | 
			
		||||
			this={Input}
 | 
			
		||||
		<Input
 | 
			
		||||
			bind:delta
 | 
			
		||||
			bind:plainText
 | 
			
		||||
			{placeholder}
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +47,7 @@
 | 
			
		|||
			{keyboardSubmitMethod}
 | 
			
		||||
			on:keyboardSubmit
 | 
			
		||||
		>
 | 
			
		||||
			<slot />
 | 
			
		||||
		</svelte:component>
 | 
			
		||||
			{@render children?.()}
 | 
			
		||||
		</Input>
 | 
			
		||||
	{/await}
 | 
			
		||||
</InputFrame>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,24 +1,37 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { createEventDispatcher } from 'svelte';
 | 
			
		||||
	import { Delta, Editor, asRoot, h } from 'typewriter-editor';
 | 
			
		||||
	import { keyboardSubmit } from './keyboardSubmitModule';
 | 
			
		||||
 | 
			
		||||
	export let delta: Delta = new Delta();
 | 
			
		||||
	export let plainText: string | undefined = undefined;
 | 
			
		||||
	export let placeholder: string = '';
 | 
			
		||||
	export let keyboardSubmitMethod: 'enter' | 'shiftEnter' | undefined = undefined;
 | 
			
		||||
	interface Props {
 | 
			
		||||
		delta?: Delta;
 | 
			
		||||
		plainText?: string | undefined;
 | 
			
		||||
		placeholder?: string;
 | 
			
		||||
		keyboardSubmitMethod?: 'enter' | 'shiftEnter' | undefined;
 | 
			
		||||
		onKeyboardSubmit?: () => void;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const dispatch = createEventDispatcher<{
 | 
			
		||||
		keyboardSubmit: void;
 | 
			
		||||
	}>();
 | 
			
		||||
	let {
 | 
			
		||||
		delta = $bindable(new Delta()),
 | 
			
		||||
		plainText = $bindable(undefined),
 | 
			
		||||
		placeholder = '',
 | 
			
		||||
		keyboardSubmitMethod = undefined,
 | 
			
		||||
		onKeyboardSubmit,
 | 
			
		||||
		children
 | 
			
		||||
	}: Props = $props();
 | 
			
		||||
 | 
			
		||||
	let editor: Editor;
 | 
			
		||||
	let editor: Editor = $state(initEditor());
 | 
			
		||||
 | 
			
		||||
	function initEditor() {
 | 
			
		||||
		const modules = keyboardSubmitMethod
 | 
			
		||||
			? { keyboardSubmit: keyboardSubmit(() => dispatch('keyboardSubmit'), keyboardSubmitMethod) }
 | 
			
		||||
			? {
 | 
			
		||||
					keyboardSubmit: keyboardSubmit(
 | 
			
		||||
						() => onKeyboardSubmit && onKeyboardSubmit(),
 | 
			
		||||
						keyboardSubmitMethod
 | 
			
		||||
					)
 | 
			
		||||
				}
 | 
			
		||||
			: undefined;
 | 
			
		||||
		editor = new Editor({ modules });
 | 
			
		||||
		const editor = new Editor({ modules });
 | 
			
		||||
		editor.typeset.formats.add({
 | 
			
		||||
			name: 'underline',
 | 
			
		||||
			selector: 'span[data-weblah-brt=underline]',
 | 
			
		||||
| 
						 | 
				
			
			@ -41,12 +54,20 @@
 | 
			
		|||
			delta = editor.getDelta();
 | 
			
		||||
			if (typeof plainText === 'string') plainText = editor.getText();
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return editor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	$: if (keyboardSubmitMethod || typeof keyboardSubmitMethod === 'undefined') initEditor();
 | 
			
		||||
	$effect.pre(() => {
 | 
			
		||||
		if (keyboardSubmitMethod || typeof keyboardSubmitMethod === 'undefined') editor = initEditor();
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	$: editor.setDelta(delta ?? new Delta());
 | 
			
		||||
	$: if (typeof plainText === 'string' && plainText !== editor.getText()) editor.setText(plainText);
 | 
			
		||||
	$effect.pre(() => {
 | 
			
		||||
		editor.setDelta(delta ?? new Delta());
 | 
			
		||||
	});
 | 
			
		||||
	$effect.pre(() => {
 | 
			
		||||
		if (typeof plainText === 'string' && plainText !== editor.getText()) editor.setText(plainText);
 | 
			
		||||
	});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
| 
						 | 
				
			
			@ -59,5 +80,5 @@
 | 
			
		|||
	role="textbox"
 | 
			
		||||
	tabindex="0"
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,9 +4,13 @@
 | 
			
		|||
	import RichTextSpan from './RichTextRenderer/RichTextSpan.svelte';
 | 
			
		||||
	import PlainTextRenderer from './RichTextRenderer/PlainTextRenderer.svelte';
 | 
			
		||||
 | 
			
		||||
	export let content: BlahRichText;
 | 
			
		||||
	let className = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		content: BlahRichText;
 | 
			
		||||
		class?: string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { content, class: className = '' }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class={tw('rich-text', className)}>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,9 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	export let text: string;
 | 
			
		||||
	interface Props {
 | 
			
		||||
		text: string;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { text }: Props = $props();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#each text.split('\n') as segment, idx}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
<!-- @migration-task Error while migrating Svelte code: $$props is used together with named props in a way that cannot be automatically migrated. -->
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
	import type { BlahRichTextSpanAttributes } from '$lib/richText';
 | 
			
		||||
	import PlainTextRenderer from './PlainTextRenderer.svelte';
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,13 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
	import { tw } from '$lib/tw';
 | 
			
		||||
 | 
			
		||||
	let className: string = '';
 | 
			
		||||
	export { className as class };
 | 
			
		||||
	interface Props {
 | 
			
		||||
		class?: string;
 | 
			
		||||
		children?: import('svelte').Snippet;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	let { class: className = '', children }: Props = $props();
 | 
			
		||||
	
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div
 | 
			
		||||
| 
						 | 
				
			
			@ -11,5 +16,5 @@
 | 
			
		|||
		className
 | 
			
		||||
	)}
 | 
			
		||||
>
 | 
			
		||||
	<slot />
 | 
			
		||||
	{@render children?.()}
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue