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
+4 -1
View File
@@ -19,7 +19,10 @@ const anatomyCode = computed(() => {
const imports = `import {\n${names.map(n => ` ${n},`).join('\n')}\n} from '${importPath.value}';`;
const [root, ...rest] = names;
// Wrap the skeleton in the Root part (not whatever the barrel exports first),
// with the remaining parts nested inside it.
const root = (props.component.parts.find(p => p.role === 'Root') ?? props.component.parts[0]!).name;
const rest = names.filter(n => n !== root);
let tree: string;
if (rest.length === 0) {
tree = `<${root} />`;
+10 -4
View File
@@ -1,19 +1,25 @@
<script setup lang="ts">
import type { Component } from 'vue';
import { demoSources } from '#docs/demo-sources';
const props = defineProps<{
component: Component;
source: string;
/** Key into the lazy demo-source map (`${pkg}/${slug}`). */
sourceKey: string;
}>();
const showSource = ref(false);
const source = ref('');
const { highlighted, highlightReactive } = useShiki();
// Fetch the raw demo source only when the user first opens it, then highlight.
watch(showSource, async (show) => {
if (show && !highlighted.value) {
await highlightReactive(props.source, 'vue');
}
if (!show) return;
if (!source.value)
source.value = (await demoSources[props.sourceKey]?.()) ?? '';
if (source.value && !highlighted.value)
await highlightReactive(source.value, 'vue');
});
</script>
+2 -2
View File
@@ -23,7 +23,7 @@ defineProps<{
</div>
<p v-if="method.description" class="text-sm text-(--fg-muted) mb-3">
{{ method.description }}
<DocsText :text="method.description" />
</p>
<DocsCode
@@ -38,7 +38,7 @@ defineProps<{
<div v-if="method.returns" class="mt-2 text-sm">
<span class="text-(--fg-subtle)">Returns</span>
<code class="ml-1.5 text-xs font-mono bg-(--bg-inset) border border-(--border) px-1.5 py-0.5 rounded">{{ method.returns.type }}</code>
<span v-if="method.returns.description" class="ml-2 text-(--fg-muted)">{{ method.returns.description }}</span>
<DocsText v-if="method.returns.description" :text="method.returns.description" class="ml-2 text-(--fg-muted)" />
</div>
</div>
</div>
+2 -1
View File
@@ -33,7 +33,8 @@ defineProps<{
<span v-else class="text-(--fg-subtle)"></span>
</td>
<td class="py-2.5 px-4 text-(--fg-muted) min-w-48">
{{ param.description || '—' }}
<DocsText v-if="param.description" :text="param.description" />
<span v-else></span>
</td>
</tr>
</tbody>
+2 -1
View File
@@ -36,7 +36,8 @@ defineProps<{
<span v-else class="text-(--fg-subtle)"></span>
</td>
<td class="py-2.5 px-4 text-(--fg-muted) min-w-48">
{{ prop.description || '—' }}
<DocsText v-if="prop.description" :text="prop.description" />
<span v-else></span>
</td>
</tr>
</tbody>
+33
View File
@@ -0,0 +1,33 @@
<script setup lang="ts">
// Renders a short description with inline markdown (bold / `code` / links /
// {@link}). Content is authored by us (JSDoc), so v-html is safe here.
const props = defineProps<{ text?: string | null }>();
const html = computed(() => renderInline(props.text ?? ''));
</script>
<template>
<span class="docs-text" v-html="html" />
</template>
<style scoped>
.docs-text :deep(code) {
font-family: ui-monospace, monospace;
font-size: 0.9em;
background: var(--bg-inset);
border: 1px solid var(--border);
border-radius: 0.25rem;
padding: 0.05em 0.3em;
}
.docs-text :deep(a) {
color: var(--accent-text);
text-decoration: underline;
text-underline-offset: 2px;
}
.docs-text :deep(strong) {
font-weight: 600;
color: var(--fg);
}
</style>