mirror of
https://github.com/temetro/temetro.git
synced 2026-08-22 07:56:38 +00:00
929bec8f31
Stop blocking AI imports/proposals on missing non-critical fields. Records the chat agent drafts now save with safe placeholders, auto-generated file numbers, and a source="ai" marker that surfaces an "Added by AI" badge so a clinician can review/edit them later. Backend: - add `source` (manual|ai) column to patients/appointments/prescriptions (migration 0014) + canonical types, services, validation schemas - relax patient/appointment validation: empty file number allowed, demographic + type/provider/initials fall back to placeholders (initials derived from name) - patients.generateFileNumber() auto-assigns an MRN when one is missing - proposeAppointment accepts a name when no file number resolves; AI commits + /api/ai/import stamp source="ai" Frontend: - `source` on Appointment/Patient/Prescription types; AI commits send source="ai" - reusable <AiBadge> shown on the Patients table/detail and prescriptions list Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.0 KiB
5.0 KiB
coss vs shadcn/Radix assumptions
Use this guide when adapting snippets that were originally written with shadcn/Radix mental models.
Core idea
coss is close to shadcn ergonomically, but its primitives and composition model are aligned to Base UI patterns.
High-impact differences
- Do not assume every shadcn pattern translates 1:1.
- Verify trigger and popup composition from coss docs before coding.
- Apply
asChild->renderonly on coss parts that explicitly supportrender. - Prefer coss component names and exports as documented (
DialogPopup,MenuPopup,SelectPopup, etc.). - Some legacy aliases may exist, but primary coss names should be preferred in new examples.
- Prefer styled coss exports by default (for example
Slider,SliderValue) and use*Primitiveonly for advanced/custom composition. - When only Base UI helpers are needed (
useRender,mergeProps,CSPProvider,DirectionProvider), prefer@coss/ui/base-ui/*re-exports over direct@base-ui/reactdependency. - For Select migration, replace children-only option derivation with an
items-first pattern where possible, then map options consistently inSelectPopup. - For OTP fields, migrate off the
input-otppackage to coss@coss/otp-field: rename components (OTPField,OTPFieldInput,OTPFieldSeparator), uselengthandonValueChange, and dropInputOTPGroup/ slotindex(see example below).
Practical migration examples
Use these snippets as fast conversion templates when migrating shadcn/Radix code.
Composition: asChild -> render
// shadcn/Radix
<DialogTrigger asChild>
<Button variant="outline">Open</Button>
</DialogTrigger>
// coss/Base UI
<DialogTrigger render={<Button variant="outline" />}>Open</DialogTrigger>
Menu actions: onSelect -> onClick
// shadcn/Radix
<DropdownMenuItem onSelect={handleOpen}>Open</DropdownMenuItem>
// coss/Base UI
<MenuItem onClick={handleOpen}>Open</MenuItem>
Select: items-first + placeholder on SelectValue
// shadcn/Radix
<Select>
<SelectTrigger>
<SelectValue placeholder="Select a framework" />
</SelectTrigger>
<SelectContent>
<SelectItem value="next">Next.js</SelectItem>
<SelectItem value="vite">Vite</SelectItem>
</SelectContent>
</Select>
// coss/Base UI
const items = [
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
];
<Select items={items}>
<SelectTrigger>
<SelectValue placeholder="Select a framework" />
</SelectTrigger>
<SelectPopup alignItemWithTrigger={false}>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectPopup>
</Select>
Toggle Group: type -> multiple
// shadcn/Radix
<ToggleGroup type="single" defaultValue="daily">
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
</ToggleGroup>
// coss/Base UI
<ToggleGroup defaultValue={["daily"]}>
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
</ToggleGroup>
Slider: scalar single-value usage in coss
// shadcn/Radix
<Slider defaultValue={[50]} max={100} step={1} />
// coss/Base UI
<Slider defaultValue={50} max={100} step={1} />
Accordion: type/collapsible -> coss defaults
// shadcn/Radix
<Accordion type="single" collapsible defaultValue="item-1">
<AccordionItem value="item-1">...</AccordionItem>
</Accordion>
// coss/Base UI
<Accordion defaultValue={["item-1"]}>
<AccordionItem value="item-1">...</AccordionItem>
</Accordion>
OTP Field: input-otp package → @coss/otp-field
coss wraps Base UI OTP Field (OTPFieldPreview). Remove the input-otp dependency and align with the new names and root props.
// shadcn / input-otp
<InputOTP maxLength={6} value={value} onChange={setValue}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
</InputOTPGroup>
</InputOTP>
// coss
<OTPField length={6} value={value} onValueChange={setValue}>
<OTPFieldInput aria-label="Character 1 of 6" />
<OTPFieldInput aria-label="Character 2 of 6" />
</OTPField>
InputOTPGroupis not used; optionalsize="lg"lives onOTPField.- Render one
OTPFieldInputper character in order; do not passindex.
Migration checklist
- Confirm the exact coss imports from docs.
- Confirm child structure requirements (trigger/header/panel/footer/items/groups).
- Confirm prop names and semantics from the coss docs page.
- Validate with at least one coss particle example.
Per-component migration notes
For the full component registry, see ../component-registry.md.
Anti-patterns
- Copy/paste shadcn examples and only change import path.
- Using undocumented props because they exist in other ecosystems.
- Omitting required subcomponents in overlays/forms because the source snippet did.