-
+
{contact.channel === 'phone' || contact.channel === 'whatsapp' ? (
{
if (!e164) {
toast.error('Phone number is required');
@@ -208,42 +223,46 @@ function ContactRow({
- {/* Right: tag + actions */}
-
-
-
{
- await onUpdate({ label: v });
- }}
- />
+ {/* Bottom / right: tag + actions. Hidden while the phone editor is active
+ to keep focus on the form — no chips fighting for space, no noise. */}
+ {!phoneEditing ? (
+
+
+ {
+ await onUpdate({ label: v });
+ }}
+ />
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+ ) : null}
);
}
@@ -330,7 +349,9 @@ function NewContactForm({
const submitDisabled = saving || (isPhoneChannel ? !phoneValue?.e164 : !value.trim());
return (
-
+ // Single row on sm+; wraps onto multiple lines below 640px so the channel
+ // picker, value field, label, and buttons each get their own usable width.
+
{
@@ -353,7 +374,7 @@ function NewContactForm({
{isPhoneChannel ? (
-
+
setPhoneValue(v)}
@@ -365,7 +386,7 @@ function NewContactForm({
value={value}
onChange={(e) => setValue(e.target.value)}
placeholder={channel === 'email' ? 'name@example.com' : 'value'}
- className="h-7 text-sm flex-1 min-w-0"
+ className="h-7 min-w-0 flex-1 basis-full text-sm sm:basis-auto"
autoFocus
disabled={saving}
onKeyDown={(e) => {
@@ -382,7 +403,7 @@ function NewContactForm({
value={label}
onChange={(e) => setLabel(e.target.value)}
placeholder="tag (optional)"
- className="h-7 text-xs w-28"
+ className="h-7 w-28 text-xs"
disabled={saving}
onKeyDown={(e) => {
if (e.key === 'Enter') {
@@ -393,12 +414,14 @@ function NewContactForm({
}}
/>
-
- {saving ? : 'Save'}
-
-
- Cancel
-
+
+
+ {saving ? : 'Save'}
+
+
+ Cancel
+
+
);
}
diff --git a/src/components/shared/inline-phone-field.tsx b/src/components/shared/inline-phone-field.tsx
index bb808ce..a752ad5 100644
--- a/src/components/shared/inline-phone-field.tsx
+++ b/src/components/shared/inline-phone-field.tsx
@@ -17,6 +17,12 @@ interface InlinePhoneFieldProps {
/** Falls back to this country if `country` isn't set. */
defaultCountry?: CountryCode;
onSave: (next: { e164: string | null; country: CountryCode }) => Promise
;
+ /**
+ * Notifies the parent when the field enters/exits edit mode. Lets the row
+ * dim or hide noise (tag chips, action buttons) while the user is focused
+ * on the editor.
+ */
+ onEditingChange?: (editing: boolean) => void;
emptyText?: string;
disabled?: boolean;
className?: string;
@@ -28,12 +34,13 @@ export function InlinePhoneField({
country,
defaultCountry,
onSave,
+ onEditingChange,
emptyText = '—',
disabled,
className,
'data-testid': testId,
}: InlinePhoneFieldProps) {
- const [editing, setEditing] = useState(false);
+ const [editing, setEditingRaw] = useState(false);
const [draft, setDraft] = useState(() => {
if (!e164 && !country) return null;
return {
@@ -43,6 +50,11 @@ export function InlinePhoneField({
});
const [saving, setSaving] = useState(false);
+ function setEditing(next: boolean) {
+ setEditingRaw(next);
+ onEditingChange?.(next);
+ }
+
async function commit() {
const next = draft ?? { e164: null, country: defaultCountry ?? 'US' };
if (next.e164 === (e164 ?? null) && next.country === (country ?? null)) {
@@ -62,39 +74,50 @@ export function InlinePhoneField({
if (editing) {
return (
-
+ // Two clean lines: country picker + number on top, action pair below.
+
setDraft(v)}
defaultCountry={defaultCountry}
data-testid={testId}
/>
- void commit()}
- disabled={saving}
- className="rounded px-2 py-1 text-xs font-medium hover:bg-muted disabled:opacity-50"
- >
- {saving ? : 'Save'}
-
- {
- setDraft(
- e164 || country
- ? {
- e164: e164 ?? null,
- country: (country as CountryCode | null) ?? defaultCountry ?? 'US',
- }
- : null,
- );
- setEditing(false);
- }}
- disabled={saving}
- className="rounded px-2 py-1 text-xs text-muted-foreground hover:bg-muted disabled:opacity-50"
- >
- Cancel
-
+
+ {
+ setDraft(
+ e164 || country
+ ? {
+ e164: e164 ?? null,
+ country: (country as CountryCode | null) ?? defaultCountry ?? 'US',
+ }
+ : null,
+ );
+ setEditing(false);
+ }}
+ disabled={saving}
+ className={cn(
+ 'inline-flex h-8 items-center rounded-md px-3 text-xs font-medium',
+ 'text-muted-foreground transition-colors hover:bg-muted hover:text-foreground',
+ 'disabled:opacity-50',
+ )}
+ >
+ Cancel
+
+ void commit()}
+ disabled={saving}
+ className={cn(
+ 'inline-flex h-8 min-w-[64px] items-center justify-center rounded-md px-3',
+ 'bg-primary text-xs font-semibold text-primary-foreground shadow-sm',
+ 'transition-colors hover:bg-primary/90 disabled:opacity-50',
+ )}
+ >
+ {saving ? : 'Save'}
+
+
);
}