///
/**
* Email Module - Pattern for a single email address with customizable label
*
* A composable pattern that can be used standalone or embedded in containers
* like Record. Stores one email with a label (Personal, Work, School, etc.)
*/
import { computed, type Default, NAME, recipe, UI } from "commontools";
import type { ModuleMetadata } from "./container-protocol.ts";
// ===== Standard Labels =====
export const STANDARD_LABELS = ["Personal", "Work", "School", "Other"];
// ===== Self-Describing Metadata =====
export const MODULE_METADATA: ModuleMetadata = {
type: "email",
label: "Email",
icon: "\u{1F4E7}", // 📧 envelope emoji
allowMultiple: true, // Show "add another" button for multiple emails
schema: {
email: { type: "string", format: "email", description: "Email address" },
emailLabel: {
type: "string",
enum: STANDARD_LABELS,
description: "Email label (Personal, Work, etc.)",
},
},
fieldMapping: ["email", "emailAddress"],
};
// ===== Types =====
export interface EmailModuleInput {
/** Label for this email (Personal, Work, School, etc.) */
label: Default;
/** Email address */
address: Default;
}
// ===== The Pattern =====
export const EmailModule = recipe(
"EmailModule",
({ label, address }) => {
// Build display text
const displayText = computed(() => {
const addr = address?.trim();
return addr || "Not set";
});
// Build autocomplete items from standard labels
const labelItems = STANDARD_LABELS.map((l) => ({ value: l, label: l }));
return {
[NAME]: computed(
() => `${MODULE_METADATA.icon} ${label}: ${displayText}`,
),
[UI]: (
),
label,
address,
};
},
);
export default EmailModule;