diff --git a/apps/server/package.json b/apps/server/package.json index bfe64cbe7..10a7484fa 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -17,11 +17,11 @@ "#react-pdf-renderer": "@react-pdf/renderer" }, "dependencies": { - "@ai-sdk/anthropic": "^3.0.79", - "@ai-sdk/google": "^3.0.79", + "@ai-sdk/anthropic": "^3.0.80", + "@ai-sdk/google": "^3.0.80", "@ai-sdk/openai": "^3.0.65", "@ai-sdk/openai-compatible": "^2.0.48", - "@aws-sdk/client-s3": "^3.1054.0", + "@aws-sdk/client-s3": "^3.1055.0", "@better-auth/api-key": "^1.6.11", "@better-auth/drizzle-adapter": "^1.6.11", "@better-auth/infra": "^0.2.10", @@ -51,7 +51,7 @@ "better-auth": "1.6.11", "cjk-regex": "^3.4.0", "deepmerge-ts": "^7.1.5", - "dompurify": "^3.4.6", + "dompurify": "^3.4.7", "dotenv": "^17.4.2", "drizzle-orm": "1.0.0-rc.3", "drizzle-zod": "1.0.0-beta.14-a36c63d", @@ -65,7 +65,7 @@ "pg": "^8.21.0", "phosphor-icons-react-pdf": "^0.1.3", "react": "^19.2.6", - "react-email": "^6.4.0", + "react-email": "^6.5.0", "react-pdf-html": "^2.1.5", "resumable-stream": "^2.2.12", "sharp": "^0.34.5", diff --git a/apps/web/src/components/ui/combobox.test.tsx b/apps/web/src/components/ui/combobox.test.tsx index 8af90edd2..461fde40f 100644 --- a/apps/web/src/components/ui/combobox.test.tsx +++ b/apps/web/src/components/ui/combobox.test.tsx @@ -32,6 +32,14 @@ describe("Combobox", () => { expect(screen.getAllByText("Beta").length).toBeGreaterThan(0); }); + it("places the clear action inside the trigger footprint", () => { + const { container } = wrap(); + + expect(screen.getByRole("button", { name: "Clear selection" })).toHaveClass("absolute", "end-7"); + expect(screen.getByRole("combobox")).not.toHaveClass("pe-14"); + expect(container.querySelector("[data-slot='combobox-trigger'] > span")).toHaveClass("pe-7"); + }); + it("renders all option labels for the multi-select default values", () => { wrap(); expect(screen.getAllByText(/Alpha/).length).toBeGreaterThan(0); diff --git a/apps/web/src/components/ui/combobox.tsx b/apps/web/src/components/ui/combobox.tsx index 506614a55..c24221252 100644 --- a/apps/web/src/components/ui/combobox.tsx +++ b/apps/web/src/components/ui/combobox.tsx @@ -147,6 +147,10 @@ function Combobox(props: ComboboxProps< [contains], ); + const hasSelectedValue = multiple + ? Array.isArray(selectedValue) && selectedValue.length > 0 + : selectedValue !== null && selectedValue !== undefined; + const listContent = (item: ComboboxOption) => ( {item.label} @@ -166,7 +170,7 @@ function Combobox(props: ComboboxProps< ) } > - + @@ -185,9 +189,15 @@ function Combobox(props: ComboboxProps< {...(multiple ? { multiple: true } : {})} > {showClear ? ( -
+
{triggerNode} - + {hasSelectedValue && ( + + )}
) : ( triggerNode diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/index.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/index.tsx index 0957a200f..cc2aff0eb 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/right/index.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/index.tsx @@ -8,6 +8,7 @@ import { Copyright } from "@/components/ui/copyright"; import { getSectionIcon, getSectionTitle, rightSidebarSections } from "@/libs/resume/section"; import { BuilderSidebarEdge } from "../../-components/edge"; import { useBuilderSidebar } from "../../-store/sidebar"; +import { CustomStylesSectionBuilder } from "./sections/custom-styles"; import { DesignSectionBuilder } from "./sections/design"; import { ExportSectionBuilder } from "./sections/export"; import { InformationSectionBuilder } from "./sections/information"; @@ -17,7 +18,6 @@ import { PageSectionBuilder } from "./sections/page"; import { ResumeAnalysisSectionBuilder } from "./sections/resume-analysis"; import { SharingSectionBuilder } from "./sections/sharing"; import { StatisticsSectionBuilder } from "./sections/statistics"; -import { StylesSectionBuilder } from "./sections/styles"; import { TemplateSectionBuilder } from "./sections/template"; import { TypographySectionBuilder } from "./sections/typography"; @@ -27,7 +27,7 @@ function getSectionComponent(type: RightSidebarSection) { .with("layout", () => ) .with("typography", () => ) .with("design", () => ) - .with("styles", () => ) + .with("styles", () => ) .with("page", () => ) .with("notes", () => ) .with("sharing", () => ) diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.test.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.test.tsx similarity index 75% rename from apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.test.tsx rename to apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.test.tsx index af5a01318..5fe12f8b8 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.test.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.test.tsx @@ -1,13 +1,14 @@ // @vitest-environment happy-dom -import { fireEvent, render, screen, within } from "@testing-library/react"; +import type { StyleRule } from "@reactive-resume/schema/resume/data"; +import { fireEvent, render, screen } from "@testing-library/react"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { i18n } from "@lingui/core"; import { I18nProvider } from "@lingui/react"; import { isValidElement } from "react"; const updateResumeData = vi.hoisted(() => vi.fn()); -const styleRules = vi.hoisted(() => [ +const styleRules = vi.hoisted(() => [ { id: "style-global-heading", label: "All sections: Section heading", @@ -35,7 +36,7 @@ vi.mock("@/features/resume/builder/draft", () => ({ useUpdateResumeData: () => updateResumeData, })); -const { StylesSectionBuilder } = await import("./styles"); +const { CustomStylesSectionBuilder } = await import("./custom-styles"); const { getSectionIcon, getSectionTitle } = await import("@/libs/resume/section"); beforeAll(() => { @@ -46,14 +47,19 @@ beforeEach(() => { updateResumeData.mockClear(); }); -const renderStyles = () => +const renderCustomStyles = () => render( - + , ); -describe("StylesSectionBuilder", () => { +const chooseComboboxOption = async (label: string, option: string) => { + fireEvent.click(screen.getByLabelText(label)); + fireEvent.click(await screen.findByRole("option", { name: option })); +}; + +describe("CustomStylesSectionBuilder", () => { beforeEach(() => { styleRules.splice(0, styleRules.length); styleRules.push({ @@ -65,8 +71,8 @@ describe("StylesSectionBuilder", () => { }); }); - it("renders structured style rule controls", () => { - renderStyles(); + it("renders structured style rule controls", async () => { + renderCustomStyles(); expect(screen.getByLabelText("Target Scope")).toBeInTheDocument(); expect(screen.getByLabelText("Style Slot")).toBeInTheDocument(); @@ -91,18 +97,18 @@ describe("StylesSectionBuilder", () => { expect(screen.getByLabelText("Row Gap")).toBeInTheDocument(); expect(screen.getByLabelText("Column Gap")).toBeInTheDocument(); expect(screen.getByLabelText("Border Style")).toBeInTheDocument(); - expect(screen.getByRole("option", { name: "Section heading" })).toBeInTheDocument(); + fireEvent.click(screen.getByLabelText("Style Slot")); + expect(await screen.findByRole("option", { name: "Section heading" })).toBeInTheDocument(); expect(screen.getByRole("option", { name: "List" })).toBeInTheDocument(); expect(screen.getByRole("option", { name: "List item content" })).toBeInTheDocument(); expect(screen.queryByRole("option", { name: "Bullet or number" })).not.toBeInTheDocument(); }); it("labels the empty font weight option as default", () => { - renderStyles(); + renderCustomStyles(); - const fontWeightSelect = screen.getByLabelText("Font Weight"); - expect(within(fontWeightSelect).getByRole("option", { name: "Default" })).toBeInTheDocument(); - expect(within(fontWeightSelect).queryByRole("option", { name: "Template default" })).not.toBeInTheDocument(); + expect(screen.getByLabelText("Font Weight")).toHaveTextContent("Default"); + expect(screen.queryByText("Template default")).not.toBeInTheDocument(); }); it("renames the sidebar entry and uses a distinct icon from design", () => { @@ -117,7 +123,7 @@ describe("StylesSectionBuilder", () => { it("upserts one style rule for the selected target and slot", () => { styleRules.splice(0, styleRules.length); - renderStyles(); + renderCustomStyles(); fireEvent.change(screen.getByLabelText("Text Color"), { target: { value: "rgba(220, 38, 38, 1)" } }); @@ -139,13 +145,16 @@ describe("StylesSectionBuilder", () => { it("stores padding as per-side values", () => { styleRules.splice(0, styleRules.length); - renderStyles(); + renderCustomStyles(); expect(screen.queryByLabelText("Padding")).not.toBeInTheDocument(); expect(screen.getByLabelText("Padding Top")).toBeInTheDocument(); expect(screen.getByLabelText("Padding Right")).toBeInTheDocument(); expect(screen.getByLabelText("Padding Bottom")).toBeInTheDocument(); expect(screen.getByLabelText("Padding Left")).toBeInTheDocument(); + expect(screen.getByLabelText("Padding Top").closest("div")?.parentElement).toHaveClass( + "grid-cols-[repeat(auto-fit,minmax(7rem,1fr))]", + ); fireEvent.change(screen.getByLabelText("Padding Top"), { target: { value: "12" } }); @@ -165,11 +174,11 @@ describe("StylesSectionBuilder", () => { ]); }); - it("stores text decoration intent", () => { + it("stores text decoration intent", async () => { styleRules.splice(0, styleRules.length); - renderStyles(); + renderCustomStyles(); - fireEvent.change(screen.getByLabelText("Text Decoration"), { target: { value: "underline" } }); + await chooseComboboxOption("Text Decoration", "Underline"); expect(updateResumeData).toHaveBeenCalledTimes(1); const recipe = updateResumeData.mock.calls[0]?.[0] as (draft: { metadata: { styleRules: unknown[] } }) => void; @@ -189,7 +198,7 @@ describe("StylesSectionBuilder", () => { it("stores margin and gap intent", () => { styleRules.splice(0, styleRules.length); - renderStyles(); + renderCustomStyles(); expect(screen.getByLabelText("Margin Bottom")).toHaveAttribute("min", "-72"); expect(screen.getByLabelText("Row Gap")).toHaveAttribute("min", "-72"); @@ -230,11 +239,11 @@ describe("StylesSectionBuilder", () => { ]); }); - it("stores list slot rules for rich text lists", () => { + it("stores list slot rules for rich text lists", async () => { styleRules.splice(0, styleRules.length); - renderStyles(); + renderCustomStyles(); - fireEvent.change(screen.getByLabelText("Style Slot"), { target: { value: "richList" } }); + await chooseComboboxOption("Style Slot", "List"); fireEvent.change(screen.getByLabelText("Row Gap"), { target: { value: "8" } }); expect(updateResumeData).toHaveBeenCalledTimes(1); @@ -254,7 +263,7 @@ describe("StylesSectionBuilder", () => { }); it("can reset the selected style rule", () => { - renderStyles(); + renderCustomStyles(); fireEvent.click(screen.getByRole("button", { name: "Reset Style" })); @@ -288,12 +297,25 @@ describe("StylesSectionBuilder", () => { }); it("lists applied style rules and toggles individual rules", () => { - renderStyles(); + styleRules.push({ + id: "style-global-section", + label: "All sections: Section container", + enabled: false, + target: { scope: "global" }, + slots: { section: { paddingTop: 4 } }, + }); + renderCustomStyles(); expect(screen.getByText("Applied Rules")).toBeInTheDocument(); - expect(screen.getByText("All sections: Section heading")).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: "Manage Rules" })).not.toBeInTheDocument(); + expect(screen.queryByText("All sections: Section heading")).not.toBeInTheDocument(); + expect(screen.queryByText("Off")).not.toBeInTheDocument(); + expect(screen.getAllByText("All sections").length).toBeGreaterThan(0); + expect(screen.getAllByText("Section heading").length).toBeGreaterThan(0); + expect(screen.queryByRole("switch")).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Enable All sections: Section container" })).toBeInTheDocument(); - fireEvent.click(screen.getByLabelText("Toggle All sections: Section heading")); + fireEvent.click(screen.getByRole("button", { name: "Disable All sections: Section heading" })); expect(updateResumeData).toHaveBeenCalledTimes(1); const recipe = updateResumeData.mock.calls[0]?.[0] as (draft: { @@ -305,18 +327,21 @@ describe("StylesSectionBuilder", () => { expect(draft.metadata.styleRules[0]?.enabled).toBe(false); }); - it("opens a manage rules dialog with editable rule fields", () => { - renderStyles(); + it("loads a selected applied rule into the editor form", () => { + styleRules.push({ + id: "style-section-type-experience-richListItemContent", + label: "Experience: List item content", + enabled: true, + target: { scope: "sectionType", sectionType: "experience" }, + slots: { richListItemContent: { lineHeight: 1.4 } }, + }); + renderCustomStyles(); - fireEvent.click(screen.getByRole("button", { name: "Manage Rules" })); + fireEvent.click(screen.getByRole("button", { name: "Edit Experience: List item content" })); - expect(screen.getByRole("dialog")).toBeInTheDocument(); - expect(screen.getByText("Manage Style Rules")).toBeInTheDocument(); - expect(screen.getByLabelText("Rule Label")).toHaveValue("All sections: Section heading"); - expect(screen.getByLabelText("Dialog Text Color")).toHaveValue("rgba(220, 38, 38, 1)"); - expect(screen.getByLabelText("Dialog Padding Top")).toBeInTheDocument(); - expect(screen.getByLabelText("Dialog Padding Right")).toBeInTheDocument(); - expect(screen.getByLabelText("Dialog Padding Bottom")).toBeInTheDocument(); - expect(screen.getByLabelText("Dialog Padding Left")).toBeInTheDocument(); + expect(screen.getByLabelText("Target Scope")).toHaveTextContent("Section type"); + expect(screen.getByLabelText("Section Type")).toHaveTextContent("Experience"); + expect(screen.getByLabelText("Style Slot")).toHaveTextContent("List item content"); + expect(screen.getByLabelText("Line Height")).toHaveValue(1.4); }); }); diff --git a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.tsx b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.tsx similarity index 72% rename from apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.tsx rename to apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.tsx index 6c5d7af27..b736d47d1 100644 --- a/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/styles.tsx +++ b/apps/web/src/routes/builder/$resumeId/-sidebar/right/sections/custom-styles.tsx @@ -5,26 +5,19 @@ import type { StyleRuleTarget, StyleSlot, } from "@reactive-resume/schema/resume/data"; -import type { ComponentProps, ReactNode } from "react"; +import type { ReactNode } from "react"; +import type { ComboboxOption } from "@/components/ui/combobox"; import { Trans } from "@lingui/react/macro"; -import { SlidersHorizontalIcon, TrashSimpleIcon } from "@phosphor-icons/react"; +import { EyeIcon, EyeSlashIcon, PencilSimpleIcon, TrashSimpleIcon } from "@phosphor-icons/react"; import { useMemo, useState } from "react"; import { sectionTypeSchema } from "@reactive-resume/schema/resume/data"; -import { Badge } from "@reactive-resume/ui/components/badge"; import { Button } from "@reactive-resume/ui/components/button"; -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTitle, -} from "@reactive-resume/ui/components/dialog"; import { Input } from "@reactive-resume/ui/components/input"; import { Label } from "@reactive-resume/ui/components/label"; import { Separator } from "@reactive-resume/ui/components/separator"; -import { Switch } from "@reactive-resume/ui/components/switch"; import { cn } from "@reactive-resume/utils/style"; import { ColorPicker } from "@/components/input/color-picker"; +import { Combobox } from "@/components/ui/combobox"; import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft"; import { getSectionTitle } from "@/libs/resume/section"; import { SectionBase } from "../shared/section-base"; @@ -37,6 +30,12 @@ type StyleSlotOption = { group: "Section" | "Rich text"; }; +const targetScopeOptions: ComboboxOption[] = [ + { value: "global", label: "All sections" }, + { value: "sectionType", label: "Section type" }, + { value: "sectionId", label: "Specific section" }, +]; + const styleSlotOptions: StyleSlotOption[] = [ { value: "section", label: "Section container", group: "Section" }, { value: "heading", label: "Section heading", group: "Section" }, @@ -55,10 +54,11 @@ const styleSlotOptions: StyleSlotOption[] = [ { value: "richMark", label: "Highlight", group: "Rich text" }, ]; -const groupedStyleSlotOptions: [StyleSlotOption["group"], StyleSlotOption[]][] = [ - ["Section", styleSlotOptions.filter((option) => option.group === "Section")], - ["Rich text", styleSlotOptions.filter((option) => option.group === "Rich text")], -]; +const styleSlotComboboxOptions: ComboboxOption[] = styleSlotOptions.map((option) => ({ + value: option.value, + label: option.label, + keywords: [option.group], +})); const fontWeightOptions = ["100", "200", "300", "400", "500", "600", "700", "800", "900"] as const; const fontStyleOptions = [ @@ -93,26 +93,32 @@ const borderStyleOptions = [ { value: "dotted", label: "Dotted" }, ] as const satisfies readonly { value: NonNullable; label: string }[]; -export function StylesSectionBuilder() { +const controlGridClassName = "grid grid-cols-[repeat(auto-fit,minmax(8rem,1fr))] gap-3"; +const compactControlGridClassName = "grid grid-cols-[repeat(auto-fit,minmax(7rem,1fr))] gap-3"; + +export function CustomStylesSectionBuilder() { return ( - + ); } -function StylesSectionForm() { +function CustomStylesSectionForm() { const resume = useCurrentResume(); const data = resume.data; const updateResumeData = useUpdateResumeData(); - const sectionOptions = useMemo(() => getSectionIdOptions(data), [data]); + const sectionOptions = useMemo[]>(() => getSectionIdOptions(data), [data]); + const sectionTypeOptions = useMemo[]>( + () => sectionTypeSchema.options.map((type) => ({ value: type, label: getSectionTitle(type) })), + [], + ); const styleRules = data.metadata.styleRules ?? []; const [targetScope, setTargetScope] = useState("global"); const [sectionType, setSectionType] = useState("summary"); const [sectionId, setSectionId] = useState("summary"); const [slot, setSlot] = useState("heading"); - const [isManageDialogOpen, setManageDialogOpen] = useState(false); const target = createTarget({ targetScope, sectionType, sectionId }); const ruleId = getStyleRuleId(target, slot); @@ -161,26 +167,14 @@ function StylesSectionForm() { }); }; - const updateRuleLabel = (ruleId: string, label: string) => { - updateResumeData((draft) => { - const rule = (draft.metadata.styleRules ?? []).find((rule) => rule.id === ruleId); - if (rule) rule.label = label; - }); - }; + const editRule = (rule: StyleRule) => { + const nextSlot = getConfiguredSlots(rule)[0]; + if (!nextSlot) return; - const updateRuleIntent = (ruleId: string, slot: StyleSlot, patch: Partial) => { - updateResumeData((draft) => { - const rules = draft.metadata.styleRules ?? []; - const ruleIndex = rules.findIndex((rule) => rule.id === ruleId); - const rule = rules[ruleIndex]; - if (!rule) return; - - const nextIntent = compactIntent({ ...(rule.slots[slot] ?? {}), ...patch }); - if (Object.keys(nextIntent).length === 0) delete rule.slots[slot]; - else rule.slots[slot] = nextIntent; - - if (getConfiguredSlots(rule).length === 0) rules.splice(ruleIndex, 1); - }); + setTargetScope(rule.target.scope); + if (rule.target.scope === "sectionType") setSectionType(rule.target.sectionType); + if (rule.target.scope === "sectionId") setSectionId(rule.target.sectionId); + setSlot(nextSlot); }; const deleteRule = (ruleId: string) => { @@ -191,59 +185,65 @@ function StylesSectionForm() { return (
-
+
- + onValueChange={(value) => { + if (value) setTargetScope(value); + }} + className="w-full" + placeholder="Target scope" + searchPlaceholder="Search scopes..." + /> {targetScope === "sectionType" && ( - + onValueChange={(value) => { + if (value) setSectionType(value); + }} + className="w-full" + placeholder="Section type" + searchPlaceholder="Search section types..." + /> )} {targetScope === "sectionId" && ( - + { + if (value) setSectionId(value); + }} + className="w-full" + placeholder="Section" + searchPlaceholder="Search sections..." + /> )} - + { + if (value) setSlot(value); + }} + className="w-full" + placeholder="Style slot" + searchPlaceholder="Search style slots..." + />
@@ -263,18 +263,7 @@ function StylesSectionForm() { data={data} rules={styleRules} onToggleRule={updateRuleEnabled} - onDeleteRule={deleteRule} - onManageRules={() => setManageDialogOpen(true)} - /> - -
@@ -283,26 +272,15 @@ function StylesSectionForm() { function Field({ label, id, children }: { label: string; id: string; children: ReactNode }) { return ( -
- +
+ {children}
); } -function Select({ className, ...props }: ComponentProps<"select">) { - return ( - onChange(event.target.value.trim() || undefined)} @@ -356,6 +335,7 @@ function NumberInput({ void; + onEditRule: (rule: StyleRule) => void; onDeleteRule: (ruleId: string) => void; - onManageRules: () => void; }) { return (
-
-
-

- Applied Rules -

-

- {rules.length} {rules.length === 1 ? rule : rules} -

-
- - +
+

+ Applied Rules +

+

+ {rules.length} {rules.length === 1 ? rule : rules} +

{rules.length === 0 ? ( @@ -413,6 +386,7 @@ function AppliedRulesList({ data={data} rule={rule} onToggleRule={onToggleRule} + onEditRule={onEditRule} onDeleteRule={onDeleteRule} /> ))} @@ -426,54 +400,58 @@ function AppliedRuleCard({ data, rule, onToggleRule, + onEditRule, onDeleteRule, }: { data: ResumeData; rule: StyleRule; onToggleRule: (ruleId: string, enabled: boolean) => void; + onEditRule: (rule: StyleRule) => void; onDeleteRule: (ruleId: string) => void; }) { const slots = getConfiguredSlots(rule); const primaryIntent = slots[0] ? rule.slots[slots[0]] : undefined; const fallbackLabel = getRuleFallbackLabel(data, rule); + const ruleLabel = rule.label || fallbackLabel; + const targetLabel = getTargetLabel(data, rule.target); + const slotLabel = slots.length > 0 ? slots.map(getSlotLabel).join(", ") : "No slot"; return (
-
- {rule.label || fallbackLabel} - {!rule.enabled && ( - - Off - - )} -
- -
- {getTargetLabel(data, rule.target)} - {slots.map((slot) => ( - - {getSlotLabel(slot)} - - ))} +
+
{primaryIntent && }
- onToggleRule(rule.id, checked)} - /> + + -
-
- - {slots.map((slot) => ( - onUpdateRuleIntent(rule.id, slot, patch)} - /> - ))} +
+ + {target} + + {slot}
); } @@ -628,7 +489,7 @@ function RuleIntentEditor({ return (
-
+
-
+
-
+
-
+
({ label: string; id: string; value: TValue | undefined; - options: readonly { value: TValue; label: string }[]; + options: readonly ComboboxOption[]; onChange: (value: TValue | undefined) => void; }) { return ( - + options={[...options]} + value={value ?? null} + onValueChange={(nextValue) => onChange(nextValue ?? undefined)} + className="w-full" + showClear + placeholder="Default" + searchPlaceholder={`Search ${label.toLowerCase()}...`} + /> ); } @@ -867,20 +726,23 @@ function FontWeightField({ value: StyleIntent["fontWeight"] | undefined; onChange: (value: StyleIntent["fontWeight"] | undefined) => void; }) { + const options: ComboboxOption>[] = fontWeightOptions.map((weight) => ({ + value: weight, + label: weight, + })); + return ( - + options={options} + value={value ?? null} + onValueChange={(nextValue) => onChange(nextValue ?? undefined)} + className="w-full" + showClear + placeholder="Default" + searchPlaceholder="Search font weights..." + /> ); } @@ -917,7 +779,7 @@ function PaddingSideInputs({ const labelStart = labelPrefix ? `${labelPrefix} ` : ""; return ( -
+
{paddingSideOptions.map((side) => ( +
{marginSideOptions.map((side) => ( { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/bronzor/BronzorPage.tsx b/packages/pdf/src/templates/bronzor/BronzorPage.tsx index bf6501278..e4e0347bd 100644 --- a/packages/pdf/src/templates/bronzor/BronzorPage.tsx +++ b/packages/pdf/src/templates/bronzor/BronzorPage.tsx @@ -206,7 +206,6 @@ const useBronzorTemplate = (): BronzorTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/chikorita/ChikoritaPage.tsx b/packages/pdf/src/templates/chikorita/ChikoritaPage.tsx index 77bf791c1..da6baf691 100644 --- a/packages/pdf/src/templates/chikorita/ChikoritaPage.tsx +++ b/packages/pdf/src/templates/chikorita/ChikoritaPage.tsx @@ -220,7 +220,6 @@ const useChikoritaTemplate = (): ChikoritaTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/ditgar/DitgarPage.tsx b/packages/pdf/src/templates/ditgar/DitgarPage.tsx index 2f3a62344..9d5caee93 100644 --- a/packages/pdf/src/templates/ditgar/DitgarPage.tsx +++ b/packages/pdf/src/templates/ditgar/DitgarPage.tsx @@ -248,7 +248,6 @@ const useDitgarTemplate = (): DitgarTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/ditto/DittoPage.tsx b/packages/pdf/src/templates/ditto/DittoPage.tsx index fff1fe046..393d109f6 100644 --- a/packages/pdf/src/templates/ditto/DittoPage.tsx +++ b/packages/pdf/src/templates/ditto/DittoPage.tsx @@ -216,7 +216,6 @@ const useDittoTemplate = (): DittoTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/gengar/GengarPage.tsx b/packages/pdf/src/templates/gengar/GengarPage.tsx index 15a2275cc..a8e8d00f0 100644 --- a/packages/pdf/src/templates/gengar/GengarPage.tsx +++ b/packages/pdf/src/templates/gengar/GengarPage.tsx @@ -245,7 +245,6 @@ const useGengarTemplate = (): GengarTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/glalie/GlaliePage.tsx b/packages/pdf/src/templates/glalie/GlaliePage.tsx index 395f75991..073248881 100644 --- a/packages/pdf/src/templates/glalie/GlaliePage.tsx +++ b/packages/pdf/src/templates/glalie/GlaliePage.tsx @@ -225,7 +225,6 @@ const useGlalieTemplate = (): GlalieTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/kakuna/KakunaPage.tsx b/packages/pdf/src/templates/kakuna/KakunaPage.tsx index 625b15022..160621453 100644 --- a/packages/pdf/src/templates/kakuna/KakunaPage.tsx +++ b/packages/pdf/src/templates/kakuna/KakunaPage.tsx @@ -188,7 +188,6 @@ const useKakunaTemplate = (): KakunaTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/lapras/LaprasPage.tsx b/packages/pdf/src/templates/lapras/LaprasPage.tsx index 40adf901b..be5dd2871 100644 --- a/packages/pdf/src/templates/lapras/LaprasPage.tsx +++ b/packages/pdf/src/templates/lapras/LaprasPage.tsx @@ -190,7 +190,6 @@ const useLaprasTemplate = (): LaprasTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/leafish/LeafishPage.tsx b/packages/pdf/src/templates/leafish/LeafishPage.tsx index 686ffef2a..26060c7f6 100644 --- a/packages/pdf/src/templates/leafish/LeafishPage.tsx +++ b/packages/pdf/src/templates/leafish/LeafishPage.tsx @@ -216,7 +216,6 @@ const useLeafishTemplate = (): LeafishTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/meowth/MeowthPage.tsx b/packages/pdf/src/templates/meowth/MeowthPage.tsx index 185756aed..35e1d3513 100644 --- a/packages/pdf/src/templates/meowth/MeowthPage.tsx +++ b/packages/pdf/src/templates/meowth/MeowthPage.tsx @@ -191,7 +191,6 @@ const useMeowthTemplate = (): MeowthTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/onyx/OnyxPage.tsx b/packages/pdf/src/templates/onyx/OnyxPage.tsx index ca953a4c4..ad2275949 100644 --- a/packages/pdf/src/templates/onyx/OnyxPage.tsx +++ b/packages/pdf/src/templates/onyx/OnyxPage.tsx @@ -186,7 +186,6 @@ const useOnyxTemplate = (): OnyxTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/pikachu/PikachuPage.tsx b/packages/pdf/src/templates/pikachu/PikachuPage.tsx index bb40de482..cf1f8d3b7 100644 --- a/packages/pdf/src/templates/pikachu/PikachuPage.tsx +++ b/packages/pdf/src/templates/pikachu/PikachuPage.tsx @@ -223,7 +223,6 @@ const usePikachuTemplate = (): PikachuTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/rhyhorn/RhyhornPage.tsx b/packages/pdf/src/templates/rhyhorn/RhyhornPage.tsx index bf68bdee9..96f105bfb 100644 --- a/packages/pdf/src/templates/rhyhorn/RhyhornPage.tsx +++ b/packages/pdf/src/templates/rhyhorn/RhyhornPage.tsx @@ -236,7 +236,6 @@ const useRhyhornTemplate = (): RhyhornTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/scizor/ScizorPage.tsx b/packages/pdf/src/templates/scizor/ScizorPage.tsx index 2d1a06a7e..21b164750 100644 --- a/packages/pdf/src/templates/scizor/ScizorPage.tsx +++ b/packages/pdf/src/templates/scizor/ScizorPage.tsx @@ -183,7 +183,6 @@ const useScizorTemplate = (): ScizorTemplate => { richListItemContent: { ...bodyText, flex: 1, - lineHeight: metadata.typography.body.lineHeight * 0.5, }, splitRow: { flexDirection: r.row, diff --git a/packages/pdf/src/templates/shared/rich-text-template-styles.test.ts b/packages/pdf/src/templates/shared/rich-text-template-styles.test.ts new file mode 100644 index 000000000..3190d919a --- /dev/null +++ b/packages/pdf/src/templates/shared/rich-text-template-styles.test.ts @@ -0,0 +1,28 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { basename, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { describe, expect, it } from "vitest"; + +const templatesDir = fileURLToPath(new URL("../", import.meta.url)); + +const templatePageFiles = readdirSync(templatesDir, { withFileTypes: true }).flatMap((entry) => { + if (!entry.isDirectory() || entry.name === "shared") return []; + + const templateDir = join(templatesDir, entry.name); + const pageFile = readdirSync(templateDir).find((file) => file.endsWith("Page.tsx")); + + return pageFile ? [join(templateDir, pageFile)] : []; +}); + +describe("rich text template styles", () => { + it.each( + templatePageFiles.map((file) => [basename(file), file]), + )("%s keeps list item rich text on the global body line height", (_name, file) => { + const source = readFileSync(file, "utf8"); + const richListItemContentBlock = source.match(/richListItemContent:\s*{(?[\s\S]*?)^\s*},/m); + + expect(richListItemContentBlock?.groups?.body).toBeDefined(); + expect(richListItemContentBlock?.groups?.body).toContain("...bodyText"); + expect(richListItemContentBlock?.groups?.body).not.toMatch(/\blineHeight:/); + }); +}); diff --git a/packages/ui/package.json b/packages/ui/package.json index d85f1a78f..9202a85fe 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -30,7 +30,7 @@ "react": "^19.2.6", "react-dom": "^19.2.6", "react-resizable-panels": "^4.11.2", - "shadcn": "^4.8.1", + "shadcn": "^4.8.2", "sonner": "^2.0.7", "tw-animate-css": "^1.4.0" }, diff --git a/packages/ui/src/components/button.tsx b/packages/ui/src/components/button.tsx index 5db119871..1267eb0fa 100644 --- a/packages/ui/src/components/button.tsx +++ b/packages/ui/src/components/button.tsx @@ -10,7 +10,7 @@ const buttonVariants = cva( variant: { default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", outline: - "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground", + "border-border bg-transparent hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", ghost: "hover:bg-muted hover:text-foreground", diff --git a/packages/ui/src/components/combobox.tsx b/packages/ui/src/components/combobox.tsx index be8985f0e..ad47e9cfe 100644 --- a/packages/ui/src/components/combobox.tsx +++ b/packages/ui/src/components/combobox.tsx @@ -194,7 +194,7 @@ function ComboboxChips({ =18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -1161,8 +1161,8 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/google@3.0.79': - resolution: {integrity: sha512-QWVAvYeA7JzEX2wkSyXOWv/I9PD9kvTzdykkSTLi+Eu8RyJ6gA0tdPIGa8esEtOcHE//G5vy6FTB70qQw8l/uw==} + '@ai-sdk/google@3.0.80': + resolution: {integrity: sha512-5ORbm/yFUPO0MEvZsxBMN0cdKw2+lwU/wVn5KN3KF8Dmk1LughuDuUohMh/7iU/XFTiyB0OvmTW/tdV/J7O9zg==} engines: {node: '>=18'} peerDependencies: zod: ^3.25.76 || ^4.1.8 @@ -1226,8 +1226,8 @@ packages: '@aws-crypto/util@5.2.0': resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - '@aws-sdk/client-s3@3.1054.0': - resolution: {integrity: sha512-2ue7uVqaHYX4rytkcrLySYU/m/ZlRbL8KojWefbR24B0/TcFkqN2IovpBFrnmla/dtZAn9eVSlhHeEddOghZ5w==} + '@aws-sdk/client-s3@3.1055.0': + resolution: {integrity: sha512-FxVwuw86c2Mw4p+0tOtoE+1sDTk+eOBZD/NwwK+wwx1gHkdO/EYSv231O9A1YM8HPjUrI0vZ/hP/szckBxHW0A==} engines: {node: '>=20.0.0'} '@aws-sdk/core@3.974.14': @@ -1660,62 +1660,65 @@ packages: '@better-auth/utils@0.4.0': resolution: {integrity: sha512-RpMtLUIQAEWMgdPLNVbIF5ON2mm+CH0U3rCdUCU1VyeAUui4m38DyK7/aXMLZov2YDjG684pS1D0MBllrmgjQA==} + '@better-auth/utils@0.4.1': + resolution: {integrity: sha512-SZBPRPF3z0nBvE5ygOkxae35wnnXPRShmqFo78S+qslLeFoPu/pMgnXAuNKFMMybac3tiLaVg1e3MQW5MC+1iA==} + '@better-fetch/fetch@1.1.21': resolution: {integrity: sha512-/ImESw0sskqlVR94jB+5+Pxjf+xBwDZF/N5+y2/q4EqD7IARUTSpPfIo8uf39SYpCxyOCtbyYpUrZ3F/k0zT4A==} - '@biomejs/biome@2.4.15': - resolution: {integrity: sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==} + '@biomejs/biome@2.4.16': + resolution: {integrity: sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==} engines: {node: '>=14.21.3'} hasBin: true - '@biomejs/cli-darwin-arm64@2.4.15': - resolution: {integrity: sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==} + '@biomejs/cli-darwin-arm64@2.4.16': + resolution: {integrity: sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [darwin] - '@biomejs/cli-darwin-x64@2.4.15': - resolution: {integrity: sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==} + '@biomejs/cli-darwin-x64@2.4.16': + resolution: {integrity: sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [darwin] - '@biomejs/cli-linux-arm64-musl@2.4.15': - resolution: {integrity: sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==} + '@biomejs/cli-linux-arm64-musl@2.4.16': + resolution: {integrity: sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [musl] - '@biomejs/cli-linux-arm64@2.4.15': - resolution: {integrity: sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==} + '@biomejs/cli-linux-arm64@2.4.16': + resolution: {integrity: sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] libc: [glibc] - '@biomejs/cli-linux-x64-musl@2.4.15': - resolution: {integrity: sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==} + '@biomejs/cli-linux-x64-musl@2.4.16': + resolution: {integrity: sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [musl] - '@biomejs/cli-linux-x64@2.4.15': - resolution: {integrity: sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==} + '@biomejs/cli-linux-x64@2.4.16': + resolution: {integrity: sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] libc: [glibc] - '@biomejs/cli-win32-arm64@2.4.15': - resolution: {integrity: sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==} + '@biomejs/cli-win32-arm64@2.4.16': + resolution: {integrity: sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [win32] - '@biomejs/cli-win32-x64@2.4.15': - resolution: {integrity: sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==} + '@biomejs/cli-win32-x64@2.4.16': + resolution: {integrity: sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw==} engines: {node: '>=14.21.3'} cpu: [x64] os: [win32] @@ -2904,6 +2907,9 @@ packages: '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@oxc-resolver/binding-android-arm-eabi@11.19.1': resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} cpu: [arm] @@ -3265,8 +3271,8 @@ packages: react: ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/ui@6.4.0': - resolution: {integrity: sha512-M9AD/Jvx0+SFjRS6kP69UgvPw2dvfKU4nqdEf7E4EeLY6Bh7i3gMVXTNVWKgRMid9tGmiqnynPib1NnZ+uvzNg==} + '@react-email/ui@6.5.0': + resolution: {integrity: sha512-WWPwCW5B0ouZ0GFtpKJLF2DBptJannXUO1VOncOIg5WsTJQ/4tEnbf300i4vWFnzI83L4n3ObfEods75cOsp3w==} '@react-pdf/fns@3.1.3': resolution: {integrity: sha512-0I7pApDr1/RLAKbizuLy/IHTEa93LSPy/bEwYniboC3Xqnp6Od8xFJKbKEzGw2wh/5zKFFwl00g4t9RwgIMc3w==} @@ -3317,30 +3323,60 @@ packages: cpu: [arm64] os: [android] + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + '@rolldown/binding-darwin-arm64@1.0.2': resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + '@rolldown/binding-darwin-x64@1.0.2': resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + '@rolldown/binding-freebsd-x64@1.0.2': resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + '@rolldown/binding-linux-arm64-gnu@1.0.2': resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3348,6 +3384,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-arm64-musl@1.0.2': resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3355,6 +3398,13 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + '@rolldown/binding-linux-ppc64-gnu@1.0.2': resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3362,6 +3412,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.2': resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3369,6 +3426,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.2': resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3376,6 +3440,13 @@ packages: os: [linux] libc: [glibc] + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + '@rolldown/binding-linux-x64-musl@1.0.2': resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3383,29 +3454,59 @@ packages: os: [linux] libc: [musl] + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + '@rolldown/binding-openharmony-arm64@1.0.2': resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + '@rolldown/binding-wasm32-wasi@1.0.2': resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + '@rolldown/binding-win32-arm64-msvc@1.0.2': resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.2': resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/plugin-babel@0.2.3': resolution: {integrity: sha512-+zEk16yGlz1F9STiRr6uG9hmIXb6nprjLczV/htGptYuLoCuxb+itZ03RKCEeOhBpDDd1NU7qF6x1VLMUp62bw==} engines: {node: '>=22.12.0 || ^24.0.0'} @@ -3443,8 +3544,8 @@ packages: '@simplewebauthn/browser@13.3.0': resolution: {integrity: sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==} - '@simplewebauthn/server@13.3.0': - resolution: {integrity: sha512-MLHYFrYG8/wK2i+86XMhiecK72nMaHKKt4bo+7Q1TbuG9iGjlSdfkPWKO5ZFE/BX+ygCJ7pr8H/AJeyAj1EaTQ==} + '@simplewebauthn/server@13.3.1': + resolution: {integrity: sha512-GV/oM/qeycWn8p42JZIMJBsXWQcNFg+nJFzeQTnMA4gN8mXg0+HZFWJerHg8ZN/zlveMS3iV1wzuFpOVWS/46w==} engines: {node: '>=20.0.0'} '@sinclair/typebox@0.27.10': @@ -3462,28 +3563,28 @@ packages: resolution: {integrity: sha512-gVaaGtKYMYAMmI8buULVH3A2TXVJ98QiwGwI7ddrWGuGidGC2uRt4FHs22+8iROJ0QTzju9CuMjlVsrvpqsdhA==} engines: {node: '>=20'} - '@smithy/core@3.24.4': - resolution: {integrity: sha512-3UNRKEyQyAgVgM0LGlerCLm+ChZWZ1GPfde+jBEW6bm6bSBGU1p0EbblaUV3unbhwvidjLA5Zs3sOs7mnZwvAw==} + '@smithy/core@3.24.5': + resolution: {integrity: sha512-Kt8phUg45M15EjhYAbZ+fFikYneijLu9Liugz8ZsYz2i8j0hzGv27LWKpEHYRfvj+LyCOSijpcR/2i8RouV+cA==} engines: {node: '>=18.0.0'} - '@smithy/credential-provider-imds@4.3.4': - resolution: {integrity: sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA==} + '@smithy/credential-provider-imds@4.3.5': + resolution: {integrity: sha512-yiF8xHpdkaTfzLVqFzsP6WvNghEK+qZzLYWFD13L2SsFhbXwBGlxdocKF95qjr7s5lE5NRage+EJFK4mAsx88Q==} engines: {node: '>=18.0.0'} - '@smithy/fetch-http-handler@5.4.4': - resolution: {integrity: sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ==} + '@smithy/fetch-http-handler@5.4.5': + resolution: {integrity: sha512-SK3VMeH0fibgdTg2QeB+O4p7Yy/2E5HBOHJeC58FshkDdeuX8lOgO7PfjYfLyPLP1ch55j91cQqKBzDS0mRjSQ==} engines: {node: '>=18.0.0'} '@smithy/is-array-buffer@2.2.0': resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} - '@smithy/node-http-handler@4.7.4': - resolution: {integrity: sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ==} + '@smithy/node-http-handler@4.7.5': + resolution: {integrity: sha512-3dA9TQ+ybRSZ/m0wnbZhiBy4Dezjgq1Ib/ZZrYTpJDBgpoLLU/SDzZc/g0x0MNAdOJe1wPcM+x2PBRmoOur+Sw==} engines: {node: '>=18.0.0'} - '@smithy/signature-v4@5.4.4': - resolution: {integrity: sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==} + '@smithy/signature-v4@5.4.5': + resolution: {integrity: sha512-QBJKWGqIknH0dc9LWpfH1mkdokAx6iXYN3UcQ3eY6uIEyScuoQAhfl94ge7ozUy9WgFUdE8xsvwBjaYBbWmPNA==} engines: {node: '>=18.0.0'} '@smithy/types@4.14.2': @@ -4839,8 +4940,8 @@ packages: resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} - docx@9.7.0: - resolution: {integrity: sha512-saDn+8rAtW9nPlWxDs31Kbb/hL+AhHQN2gktHkWwkj59u9htUXtpVMN1Z+cSoLGCAaeYpW7Qe9F5sU3aPdiy9w==} + docx@9.7.1: + resolution: {integrity: sha512-ilXFf9Moz47ABjFpDiA5s1w9lpb4EFSp7+5iiJSbfyYDM+bpZdAgLlSr7fW4aXhVe/E+F6QCv0EvRVFEd5CsWg==} engines: {node: '>=10'} dom-accessibility-api@0.5.16: @@ -4859,8 +4960,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.4.6: - resolution: {integrity: sha512-+7gzEI8trIIQkVCvQ3ucGtNfH3nOmDgVTzc62rAAOlMxLth78pwpPoZCPc7CyRzAQF89MqcfPdEWkDwnjgqktg==} + dompurify@3.4.7: + resolution: {integrity: sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -5887,8 +5988,8 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - lru-cache@11.5.0: - resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} engines: {node: 20 || >=22} lru-cache@5.1.1: @@ -6592,8 +6693,8 @@ packages: peerDependencies: react: ^19.2.6 - react-email@6.4.0: - resolution: {integrity: sha512-WDS6zl60zPllvNj14xj9nOB2uJwhyNWB+PI+YpXukpAhIsc6zo3QcAVreZ7chZLMZRM2X/dzF1d6rRrZ7TGKmw==} + react-email@6.5.0: + resolution: {integrity: sha512-WrJ+XPW87O1dabF4RJNGnTr7VTGsNa+BlMiinAZdH5fg8Kepwk++ZzX+LEieTlk+a3r13TaTJ4DfI9gv++y02g==} engines: {node: '>=20.0.0'} hasBin: true peerDependencies: @@ -6783,6 +6884,11 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rope-sequence@1.3.4: resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} @@ -6861,8 +6967,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@4.8.1: - resolution: {integrity: sha512-B2J63uYwqfLJPNzZk2AAlonXG1aJhwv8xmXlUag8OZdV61CQB6570nkXLjU1u9XN1qXm0LpJhSFQ0ZhlOruA4Q==} + shadcn@4.8.2: + resolution: {integrity: sha512-pt3KneOg6LGYKNAdoTVf/lpVcf7t2MlV+Ll2Xc3lIIYN3ph4ajrjU+CcG6OVSgO5ubbLZj+9j5oMA9Lqg7o8KA==} hasBin: true sharp@0.34.5: @@ -7628,7 +7734,7 @@ snapshots: '@adobe/css-tools@4.5.0': {} - '@ai-sdk/anthropic@3.0.79(zod@4.4.3)': + '@ai-sdk/anthropic@3.0.80(zod@4.4.3)': dependencies: '@ai-sdk/provider': 3.0.10 '@ai-sdk/provider-utils': 4.0.27(zod@4.4.3) @@ -7641,7 +7747,7 @@ snapshots: '@vercel/oidc': 3.2.0 zod: 4.4.3 - '@ai-sdk/google@3.0.79(zod@4.4.3)': + '@ai-sdk/google@3.0.80(zod@4.4.3)': dependencies: '@ai-sdk/provider': 3.0.10 '@ai-sdk/provider-utils': 4.0.27(zod@4.4.3) @@ -7735,7 +7841,7 @@ snapshots: '@smithy/util-utf8': 2.3.0 tslib: 2.8.1 - '@aws-sdk/client-s3@3.1054.0': + '@aws-sdk/client-s3@3.1055.0': dependencies: '@aws-crypto/sha1-browser': 5.2.0 '@aws-crypto/sha256-browser': 5.2.0 @@ -7750,9 +7856,9 @@ snapshots: '@aws-sdk/middleware-ssec': 3.972.11 '@aws-sdk/signature-v4-multi-region': 3.996.29 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 - '@smithy/fetch-http-handler': 5.4.4 - '@smithy/node-http-handler': 4.7.4 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7761,8 +7867,8 @@ snapshots: '@aws-sdk/types': 3.973.9 '@aws-sdk/xml-builder': 3.972.26 '@aws/lambda-invoke-store': 0.2.4 - '@smithy/core': 3.24.4 - '@smithy/signature-v4': 5.4.4 + '@smithy/core': 3.24.5 + '@smithy/signature-v4': 5.4.5 '@smithy/types': 4.14.2 bowser: 2.14.1 tslib: 2.8.1 @@ -7776,7 +7882,7 @@ snapshots: dependencies: '@aws-sdk/core': 3.974.14 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7784,9 +7890,9 @@ snapshots: dependencies: '@aws-sdk/core': 3.974.14 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 - '@smithy/fetch-http-handler': 5.4.4 - '@smithy/node-http-handler': 4.7.4 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7801,8 +7907,8 @@ snapshots: '@aws-sdk/credential-provider-web-identity': 3.972.44 '@aws-sdk/nested-clients': 3.997.12 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 - '@smithy/credential-provider-imds': 4.3.4 + '@smithy/core': 3.24.5 + '@smithy/credential-provider-imds': 4.3.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7811,7 +7917,7 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/nested-clients': 3.997.12 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7824,8 +7930,8 @@ snapshots: '@aws-sdk/credential-provider-sso': 3.972.44 '@aws-sdk/credential-provider-web-identity': 3.972.44 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 - '@smithy/credential-provider-imds': 4.3.4 + '@smithy/core': 3.24.5 + '@smithy/credential-provider-imds': 4.3.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7833,7 +7939,7 @@ snapshots: dependencies: '@aws-sdk/core': 3.974.14 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7843,7 +7949,7 @@ snapshots: '@aws-sdk/nested-clients': 3.997.12 '@aws-sdk/token-providers': 3.1054.0 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7852,7 +7958,7 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/nested-clients': 3.997.12 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7860,14 +7966,14 @@ snapshots: dependencies: '@aws-sdk/core': 3.974.14 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 '@aws-sdk/middleware-expect-continue@3.972.13': dependencies: '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7879,7 +7985,7 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/crc64-nvme': 3.972.9 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7894,7 +8000,7 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/signature-v4-multi-region': 3.996.29 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7911,16 +8017,16 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/signature-v4-multi-region': 3.996.29 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 - '@smithy/fetch-http-handler': 5.4.4 - '@smithy/node-http-handler': 4.7.4 + '@smithy/core': 3.24.5 + '@smithy/fetch-http-handler': 5.4.5 + '@smithy/node-http-handler': 4.7.5 '@smithy/types': 4.14.2 tslib: 2.8.1 '@aws-sdk/signature-v4-multi-region@3.996.29': dependencies: '@aws-sdk/types': 3.973.9 - '@smithy/signature-v4': 5.4.4 + '@smithy/signature-v4': 5.4.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -7929,7 +8035,7 @@ snapshots: '@aws-sdk/core': 3.974.14 '@aws-sdk/nested-clients': 3.997.12 '@aws-sdk/types': 3.973.9 - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -8279,7 +8385,7 @@ snapshots: '@better-auth/utils': 0.4.0 '@better-fetch/fetch': 1.1.21 '@simplewebauthn/browser': 13.3.0 - '@simplewebauthn/server': 13.3.0 + '@simplewebauthn/server': 13.3.1 better-auth: 1.6.11(@opentelemetry/api@1.9.1)(drizzle-orm@1.0.0-rc.3(@opentelemetry/api@1.9.1)(@types/pg@8.20.0)(pg@8.21.0)(zod@4.4.3))(next@16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(pg@8.21.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vitest@4.1.7) better-call: 1.3.5(zod@4.4.3) nanostores: 1.3.0 @@ -8313,41 +8419,45 @@ snapshots: dependencies: '@noble/hashes': 2.2.0 + '@better-auth/utils@0.4.1': + dependencies: + '@noble/hashes': 2.2.0 + '@better-fetch/fetch@1.1.21': {} - '@biomejs/biome@2.4.15': + '@biomejs/biome@2.4.16': optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.15 - '@biomejs/cli-darwin-x64': 2.4.15 - '@biomejs/cli-linux-arm64': 2.4.15 - '@biomejs/cli-linux-arm64-musl': 2.4.15 - '@biomejs/cli-linux-x64': 2.4.15 - '@biomejs/cli-linux-x64-musl': 2.4.15 - '@biomejs/cli-win32-arm64': 2.4.15 - '@biomejs/cli-win32-x64': 2.4.15 + '@biomejs/cli-darwin-arm64': 2.4.16 + '@biomejs/cli-darwin-x64': 2.4.16 + '@biomejs/cli-linux-arm64': 2.4.16 + '@biomejs/cli-linux-arm64-musl': 2.4.16 + '@biomejs/cli-linux-x64': 2.4.16 + '@biomejs/cli-linux-x64-musl': 2.4.16 + '@biomejs/cli-win32-arm64': 2.4.16 + '@biomejs/cli-win32-x64': 2.4.16 - '@biomejs/cli-darwin-arm64@2.4.15': + '@biomejs/cli-darwin-arm64@2.4.16': optional: true - '@biomejs/cli-darwin-x64@2.4.15': + '@biomejs/cli-darwin-x64@2.4.16': optional: true - '@biomejs/cli-linux-arm64-musl@2.4.15': + '@biomejs/cli-linux-arm64-musl@2.4.16': optional: true - '@biomejs/cli-linux-arm64@2.4.15': + '@biomejs/cli-linux-arm64@2.4.16': optional: true - '@biomejs/cli-linux-x64-musl@2.4.15': + '@biomejs/cli-linux-x64-musl@2.4.16': optional: true - '@biomejs/cli-linux-x64@2.4.15': + '@biomejs/cli-linux-x64@2.4.16': optional: true - '@biomejs/cli-win32-arm64@2.4.15': + '@biomejs/cli-win32-arm64@2.4.16': optional: true - '@biomejs/cli-win32-x64@2.4.15': + '@biomejs/cli-win32-x64@2.4.16': optional: true '@colors/colors@1.5.0': @@ -8955,7 +9065,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@lingui/vite-plugin@6.1.0(@babel/core@7.29.7)(@lingui/babel-plugin-lingui-macro@6.1.0)(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': + '@lingui/vite-plugin@6.1.0(@babel/core@7.29.7)(@lingui/babel-plugin-lingui-macro@6.1.0)(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)))(babel-plugin-macros@3.1.0)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': dependencies: '@lingui/cli': 6.1.0(babel-plugin-macros@3.1.0) '@lingui/conf': 6.1.0 @@ -8963,8 +9073,8 @@ snapshots: optionalDependencies: '@babel/core': 7.29.7 '@lingui/babel-plugin-lingui-macro': 6.1.0 - '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) - rolldown: 1.0.2 + '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) + rolldown: 1.0.3 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -9385,6 +9495,8 @@ snapshots: '@oxc-project/types@0.132.0': {} + '@oxc-project/types@0.133.0': {} + '@oxc-resolver/binding-android-arm-eabi@11.19.1': optional: true @@ -9727,7 +9839,7 @@ snapshots: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - '@react-email/ui@6.4.0(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@react-email/ui@6.5.0(@opentelemetry/api@1.9.1)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: esbuild: 0.28.0 next: 16.2.6(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(babel-plugin-macros@3.1.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -9848,39 +9960,75 @@ snapshots: '@rolldown/binding-android-arm64@1.0.2': optional: true + '@rolldown/binding-android-arm64@1.0.3': + optional: true + '@rolldown/binding-darwin-arm64@1.0.2': optional: true + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + '@rolldown/binding-darwin-x64@1.0.2': optional: true + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + '@rolldown/binding-freebsd-x64@1.0.2': optional: true + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + '@rolldown/binding-linux-x64-musl@1.0.2': optional: true + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + '@rolldown/binding-openharmony-arm64@1.0.2': optional: true + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + '@rolldown/binding-wasm32-wasi@1.0.2': dependencies: '@emnapi/core': 1.10.0 @@ -9888,17 +10036,30 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true - '@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': dependencies: '@babel/core': 7.29.7 picomatch: 4.0.4 - rolldown: 1.0.2 + rolldown: 1.0.3 optionalDependencies: '@babel/runtime': 7.29.7 vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0) @@ -9920,7 +10081,7 @@ snapshots: '@simplewebauthn/browser@13.3.0': {} - '@simplewebauthn/server@13.3.0': + '@simplewebauthn/server@13.3.1': dependencies: '@hexagon/base64': 1.1.28 '@levischuck/tiny-cbor': 0.2.11 @@ -9942,21 +10103,21 @@ snapshots: '@sindresorhus/transliterate@2.3.1': {} - '@smithy/core@3.24.4': + '@smithy/core@3.24.5': dependencies: '@aws-crypto/crc32': 5.2.0 '@smithy/types': 4.14.2 tslib: 2.8.1 - '@smithy/credential-provider-imds@4.3.4': + '@smithy/credential-provider-imds@4.3.5': dependencies: - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 - '@smithy/fetch-http-handler@5.4.4': + '@smithy/fetch-http-handler@5.4.5': dependencies: - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -9964,15 +10125,15 @@ snapshots: dependencies: tslib: 2.8.1 - '@smithy/node-http-handler@4.7.4': + '@smithy/node-http-handler@4.7.5': dependencies: - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 - '@smithy/signature-v4@5.4.4': + '@smithy/signature-v4@5.4.5': dependencies: - '@smithy/core': 3.24.4 + '@smithy/core': 3.24.5 '@smithy/types': 4.14.2 tslib: 2.8.1 @@ -10669,12 +10830,12 @@ snapshots: '@vercel/oidc@3.2.0': {} - '@vitejs/plugin-react@6.0.2(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': + '@vitejs/plugin-react@6.0.2(@rolldown/plugin-babel@0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)))(babel-plugin-react-compiler@1.0.0)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0))': dependencies: '@rolldown/pluginutils': 1.0.1 vite: 8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0) optionalDependencies: - '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.2)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) + '@rolldown/plugin-babel': 0.2.3(@babel/core@7.29.7)(@babel/runtime@7.29.7)(rolldown@1.0.3)(vite@8.0.14(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.3)(yaml@2.9.0)) babel-plugin-react-compiler: 1.0.0 '@vitest/coverage-v8@4.1.7(vitest@4.1.7)': @@ -10901,7 +11062,7 @@ snapshots: better-call@1.3.5(zod@4.4.3): dependencies: - '@better-auth/utils': 0.4.0 + '@better-auth/utils': 0.4.1 '@better-fetch/fetch': 1.1.21 rou3: 0.7.12 set-cookie-parser: 3.1.0 @@ -11252,7 +11413,7 @@ snapshots: diff@8.0.4: {} - docx@9.7.0: + docx@9.7.1: dependencies: '@types/node': 25.9.1 hash.js: 1.1.7 @@ -11277,7 +11438,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.4.6: + dompurify@3.4.7: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -12211,7 +12372,7 @@ snapshots: dependencies: js-tokens: 4.0.0 - lru-cache@11.5.0: {} + lru-cache@11.5.1: {} lru-cache@5.1.1: dependencies: @@ -12821,7 +12982,7 @@ snapshots: path-scurry@2.0.2: dependencies: - lru-cache: 11.5.0 + lru-cache: 11.5.1 minipass: 7.1.3 path-to-regexp@6.3.0: {} @@ -13075,7 +13236,7 @@ snapshots: react: 19.2.6 scheduler: 0.27.0 - react-email@6.4.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-email@6.5.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@babel/parser': 7.27.0 '@babel/traverse': 7.27.0 @@ -13267,7 +13428,7 @@ snapshots: reusify@1.1.0: {} - rolldown-plugin-dts@0.25.1(@typescript/native-preview@7.0.0-dev.20260527.1)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@1.0.2)(typescript@6.0.3): + rolldown-plugin-dts@0.25.1(@typescript/native-preview@7.0.0-dev.20260527.1)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@1.0.3)(typescript@6.0.3): dependencies: '@babel/generator': 8.0.0-rc.5 '@babel/helper-validator-identifier': 8.0.0-rc.5 @@ -13277,7 +13438,7 @@ snapshots: dts-resolver: 3.0.0(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)) get-tsconfig: 5.0.0-beta.5 obug: 2.1.1 - rolldown: 1.0.2 + rolldown: 1.0.3 optionalDependencies: '@typescript/native-preview': 7.0.0-dev.20260527.1 typescript: 6.0.3 @@ -13305,6 +13466,27 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.2 '@rolldown/binding-win32-x64-msvc': 1.0.2 + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + rope-sequence@1.3.4: {} rou3@0.7.12: {} @@ -13396,7 +13578,7 @@ snapshots: setprototypeof@1.2.0: {} - shadcn@4.8.1(@types/node@25.9.1)(babel-plugin-macros@3.1.0)(typescript@6.0.3): + shadcn@4.8.2(@types/node@25.9.1)(babel-plugin-macros@3.1.0)(typescript@6.0.3): dependencies: '@babel/core': 7.29.7 '@babel/parser': 7.29.7 @@ -13745,8 +13927,8 @@ snapshots: import-without-cache: 0.4.0 obug: 2.1.1 picomatch: 4.0.4 - rolldown: 1.0.2 - rolldown-plugin-dts: 0.25.1(@typescript/native-preview@7.0.0-dev.20260527.1)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@1.0.2)(typescript@6.0.3) + rolldown: 1.0.3 + rolldown-plugin-dts: 0.25.1(@typescript/native-preview@7.0.0-dev.20260527.1)(oxc-resolver@11.19.1(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0))(rolldown@1.0.3)(typescript@6.0.3) semver: 7.8.1 tinyexec: 1.2.2 tinyglobby: 0.2.16