feat(forms): add useMaskedField and useMaskedInput composables for input masking

This commit is contained in:
2026-06-09 13:54:52 +07:00
parent 6de7c72fb3
commit 07937e26db
426 changed files with 12981 additions and 311 deletions
@@ -1,6 +1,11 @@
<script lang="ts">
import type { PrimitiveProps } from '../primitive';
/**
* The button that confirms the alert and closes the dialog. Use it for the
* action being warned about (e.g. "Delete"); wire your own handler to perform
* the work, the part only handles closing.
*/
export interface AlertDialogActionProps extends PrimitiveProps {}
</script>
@@ -1,6 +1,11 @@
<script lang="ts">
import type { PrimitiveProps } from '../primitive';
/**
* The button that dismisses the alert without acting and closes the dialog.
* Receives focus automatically when the alert opens, making it the safe default
* choice; always include one so the user has a non-destructive way out.
*/
export interface AlertDialogCancelProps extends PrimitiveProps {}
</script>
@@ -1,6 +1,12 @@
<script lang="ts">
import type { DialogContentEmits, DialogContentProps } from '../dialog';
/**
* The container for the alert's content, rendered into the portal with
* `role="alertdialog"`. Hosts the Title, Description, Cancel, and Action parts,
* moves focus to Cancel on open, and disables dismissal via outside clicks or
* loss of focus so the alert can only be resolved by an explicit choice.
*/
export interface AlertDialogContentProps extends Omit<DialogContentProps, 'role'> {}
export type AlertDialogContentEmits = DialogContentEmits;
</script>
@@ -1,6 +1,16 @@
<script lang="ts">
import type { DialogRootProps } from '../dialog';
/**
* A modal dialog that interrupts the user with important content and expects a
* deliberate response. Built on top of Dialog, but always modal and rendered
* with `role="alertdialog"` — focus moves to the Cancel button on open and
* outside clicks are ignored, so the user must explicitly confirm or cancel.
*
* Use it for destructive or irreversible actions (deleting data, discarding
* changes); for non-blocking content prefer Dialog instead. Manages open state
* and provides context to all parts. Bind `v-model:open` to control it.
*/
export interface AlertDialogRootProps extends Omit<DialogRootProps, 'modal'> {}
</script>
+86
View File
@@ -0,0 +1,86 @@
<script setup lang="ts">
import { ref } from 'vue';
import {
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogOverlay,
AlertDialogPortal,
AlertDialogRoot,
AlertDialogTitle,
AlertDialogTrigger,
} from '@robonen/primitives';
const open = ref(false);
const deleted = ref(false);
function confirmDelete() {
deleted.value = true;
}
function restore() {
deleted.value = false;
}
</script>
<template>
<div class="flex flex-col items-start gap-3 text-(--fg)">
<p v-if="!deleted" class="text-sm text-(--fg-muted)">
Project <span class="font-medium text-(--fg)">"acme-web"</span> is live.
</p>
<p
v-else
class="text-sm text-red-600 dark:text-red-400"
>
Project deleted.
<button
type="button"
class="ml-1 underline underline-offset-2 hover:text-red-700 dark:hover:text-red-300"
@click="restore"
>
Undo
</button>
</p>
<AlertDialogRoot v-model:open="open">
<AlertDialogTrigger
:disabled="deleted"
class="inline-flex items-center rounded-md border border-red-300 bg-(--bg) px-3 py-1.5 text-sm font-medium text-red-600 transition-colors hover:bg-red-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-400 disabled:cursor-not-allowed disabled:opacity-50 dark:border-red-900 dark:text-red-400 dark:hover:bg-red-950/40"
>
Delete project
</AlertDialogTrigger>
<AlertDialogPortal>
<AlertDialogOverlay
class="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm"
/>
<AlertDialogContent
class="fixed left-1/2 top-1/2 z-50 w-[min(92vw,26rem)] -translate-x-1/2 -translate-y-1/2 rounded-xl border border-(--border) bg-(--bg-elevated) p-5 shadow-xl"
>
<AlertDialogTitle class="text-base font-semibold text-(--fg)">
Delete this project?
</AlertDialogTitle>
<AlertDialogDescription class="mt-1.5 text-sm text-(--fg-muted)">
This permanently removes "acme-web" and all of its deployments.
This action cannot be undone.
</AlertDialogDescription>
<div class="mt-5 flex justify-end gap-2">
<AlertDialogCancel
class="inline-flex items-center rounded-md border border-(--border) bg-(--bg) px-3 py-1.5 text-sm font-medium text-(--fg) transition-colors hover:bg-(--bg-subtle) focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-(--ring)"
>
Cancel
</AlertDialogCancel>
<AlertDialogAction
class="inline-flex items-center rounded-md bg-red-600 px-3 py-1.5 text-sm font-medium text-white transition-colors hover:bg-red-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-400"
@click="confirmDelete"
>
Delete
</AlertDialogAction>
</div>
</AlertDialogContent>
</AlertDialogPortal>
</AlertDialogRoot>
</div>
</template>