///
/**
* Phone Module - Pattern for a single phone number with customizable label
*
* A composable pattern that can be used standalone or embedded in containers
* like Record. Stores one phone number with a label (Mobile, Home, Work, etc.)
*/
import { computed, type Default, NAME, recipe, UI } from "commontools";
import type { ModuleMetadata } from "./container-protocol.ts";
// ===== Standard Labels =====
export const STANDARD_LABELS = ["Mobile", "Home", "Work", "Other"];
// ===== Self-Describing Metadata =====
export const MODULE_METADATA: ModuleMetadata = {
type: "phone",
label: "Phone",
icon: "\u{1F4F1}", // 📱 mobile phone emoji
allowMultiple: true, // Show "add another" button for multiple phones
schema: {
phone: { type: "string", description: "Phone number" },
phoneLabel: {
type: "string",
enum: STANDARD_LABELS,
description: "Phone label (Mobile, Home, Work, etc.)",
},
},
fieldMapping: ["phone", "phoneNumber"],
};
// ===== Types =====
export interface PhoneModuleInput {
/** Label for this phone (Mobile, Home, Work, etc.) */
label: Default;
/** Phone number (preserve original formatting) */
number: Default;
}
// ===== The Pattern =====
export const PhoneModule = recipe(
"PhoneModule",
({ label, number }) => {
// Build display text
const displayText = computed(() => {
const num = number?.trim();
return num || "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,
number,
};
},
);
export default PhoneModule;