You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/uix/soma/components/alert-dialog/alert-dialog-provider.svelt...

130 lines
4.0 KiB

import { type WithRefOpts } from '../../provider';
import type { SomaMouseEvent } from '../../types';
import type { ActiveProps } from '$libs/reactive';
import { Soma } from '../../core/soma.svelte';
import { DialogProvider } from '../dialog/dialog-provider.svelte';
import { ALERT_DIALOG_LANGS } from './langs';
/**
* AlertDialog is a thin specialisation of Dialog. The actual dialog state
* (open, nesting, presence, focus scope, scroll lock …) lives entirely in
* `DialogProvider` — the root `<AlertDialog.Provider>` simply forces
* `variant='alertdialog'` and `modal=true` on the underlying Dialog.
*
* The only parts that need their own providers are `Action` and `Cancel` —
* they emit dedicated `data-alert-dialog-action` / `data-alert-dialog-cancel`
* attributes so themes can style the primary/destructive vs safe buttons
* differently, and they wire `onclick` to close the dialog.
*/
import { alertDialogMorfo } from '../../../morfo/components/alert-dialog';
import type { SomaRuntime, SomaRuntimePart } from '../../runtime.svelte';
// ── Action button (primary / destructive) ─────────────────────────────────
interface AlertDialogActionOpts
extends WithRefOpts, ActiveProps<{ ariaLabel: string | undefined }> {}
export class AlertDialogActionProvider {
readonly opts: AlertDialogActionOpts;
readonly runtimePart: SomaRuntimePart;
static create(opts: AlertDialogActionOpts) {
return new AlertDialogActionProvider(opts);
}
readonly dialog: DialogProvider;
readonly soma: Soma;
readonly runtime: SomaRuntime;
private constructor(opts: AlertDialogActionOpts) {
this.opts = opts;
this.dialog = DialogProvider.require();
this.soma = Soma.require();
this.runtime = this.soma.runtime(alertDialogMorfo, {
props: {
ariaLabel: () => this.resolvedAriaLabel
}
});
this.runtimePart = this.runtime.part('action', {
id: opts.id,
ref: opts.ref,
owner: this,
syncAttrs: true
});
}
readonly resolvedAriaLabel = $derived.by(
() => this.opts.ariaLabel.current || this.soma.langs.ts(ALERT_DIALOG_LANGS.ACTION)
);
/**
* Resolved doctrinal intent of the parent AlertDialog. Exposed so the
* eidos `<AlertDialog.Action>` wrapper can forward it to its inner
* `<Button>` — a `risk`-flagged dialog produces a red Action automatically
* without needing a CSS ancestor cascade.
*/
readonly dialogIntent = $derived.by(
() => this.dialog.opts.intent.current ?? 'neutral'
);
readonly onclick = (_e: SomaMouseEvent<HTMLButtonElement>) => {
this.dialog.handleClose();
};
readonly props = $derived.by(() =>
this.runtimePart.assert({
...this.runtimePart.props,
onclick: this.onclick
} as const)
);
}
// ── Cancel button (secondary / safe) ───────────────────────────────────────
interface AlertDialogCancelOpts
extends WithRefOpts, ActiveProps<{ ariaLabel: string | undefined }> {}
export class AlertDialogCancelProvider {
readonly opts: AlertDialogCancelOpts;
readonly runtimePart: SomaRuntimePart;
static create(opts: AlertDialogCancelOpts) {
return new AlertDialogCancelProvider(opts);
}
readonly dialog: DialogProvider;
readonly soma: Soma;
readonly runtime: SomaRuntime;
private constructor(opts: AlertDialogCancelOpts) {
this.opts = opts;
this.dialog = DialogProvider.require();
this.soma = Soma.require();
this.runtime = this.soma.runtime(alertDialogMorfo, {
props: {
ariaLabel: () => this.resolvedAriaLabel
}
});
this.runtimePart = this.runtime.part('cancel', {
id: opts.id,
ref: opts.ref,
owner: this,
syncAttrs: true
});
}
readonly resolvedAriaLabel = $derived.by(
() => this.opts.ariaLabel.current || this.soma.langs.ts(ALERT_DIALOG_LANGS.CANCEL)
);
readonly onclick = (_e: SomaMouseEvent<HTMLButtonElement>) => {
this.dialog.handleClose();
};
readonly props = $derived.by(() =>
this.runtimePart.assert({
...this.runtimePart.props,
onclick: this.onclick
} as const)
);
}

Powered by TurnKey Linux.