Skip to content

Commit 762041e

Browse files
itspradeclaude
andcommitted
fix(ci): RSC-safe initial-appearance subpath; refresh base-ui snapshots
Two CI failures, two fixes. **RSC build (publish job)** The Next.js example's `app/layout.tsx` is a Server Component. Importing `getInitialAppearanceScript` from the package root pulled in the full client barrel, transitively `react-router`, which exports `useRouteError` that doesn't exist in the React Server Components build of react-router — Turbopack RSC bailed with "Export useRouteError doesn't exist in target module". Fix: ship `getInitialAppearanceScript` as a leaf subpath `@tailor-platform/app-shell/initial-appearance`. The source already has no React / react-router imports (only `type` imports from `theme-context` that are erased at compile time), so it's a 1KB zero-runtime-dep entry — safe to call from any RSC layout. Added to `vite.config.ts` build entries and `package.json` exports. Top-level export still works for non-RSC consumers. **Snapshot tests (ci job)** base-ui's runtime emits inline `style` attributes with slightly different ordering than what was captured in the snapshots after the previous post-rebase refresh (commit 8372c7b). The drift hit 14 tests across autocomplete / autocomplete-standalone / combobox / menu / select. Regenerated with `pnpm vitest run -u`. Three consecutive local runs: `1031 passed (1031)`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4d4e84d commit 762041e

9 files changed

Lines changed: 24 additions & 121 deletions

docs/api/use-theme.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,11 @@ Use **`AppShell`**’s **`defaultFont`** prop for the initial value when nothing
181181

182182
`ThemeProvider` writes **`data-theme`** / **`data-font`** to **`<html>`** from a **post-mount effect**. On SSR'd apps that creates a flash of the default palette before the stored preference is applied, plus a React hydration warning.
183183

184-
The package exports **`getInitialAppearanceScript()`** which returns a tiny script string consumers inline in **`<head>`** so the stored preference is applied **before first paint**:
184+
The package exports **`getInitialAppearanceScript()`** which returns a tiny script string consumers inline in **`<head>`** so the stored preference is applied **before first paint**. Import from the leaf subpath **`@tailor-platform/app-shell/initial-appearance`** — it's a zero-React-dep entry, safe to call from Next.js Server Components / RSC.
185185

186186
```tsx
187187
// app/layout.tsx (Next.js App Router)
188-
import { getInitialAppearanceScript } from "@tailor-platform/app-shell";
188+
import { getInitialAppearanceScript } from "@tailor-platform/app-shell/initial-appearance";
189189

190190
export default function RootLayout({ children }) {
191191
return (

examples/nextjs-app/src/app/layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Metadata } from "next";
22
import { Geist, Geist_Mono } from "next/font/google";
3-
import { getInitialAppearanceScript } from "@tailor-platform/app-shell";
3+
import { getInitialAppearanceScript } from "@tailor-platform/app-shell/initial-appearance";
44
import "@tailor-platform/app-shell/styles";
55
import "./globals.css";
66

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

3-
exports[`Autocomplete (standalone) > snapshots > default with string items 1`] = `"<div><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_0_" data-slot="autocomplete-input" placeholder="Type a fruit" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" data-placeholder="" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_0_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;
3+
exports[`Autocomplete (standalone) > snapshots > default with string items 1`] = `"<div><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_0_" data-slot="autocomplete-input" placeholder="Type a fruit" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_0_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;
44

5-
exports[`Autocomplete (standalone) > snapshots > with custom className 1`] = `"<div class="custom-class"><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_4_" data-slot="autocomplete-input" placeholder="Styled" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" data-placeholder="" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_4_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;
5+
exports[`Autocomplete (standalone) > snapshots > with custom className 1`] = `"<div class="custom-class"><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_4_" data-slot="autocomplete-input" placeholder="Styled" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_4_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;
66

7-
exports[`Autocomplete (standalone) > snapshots > with custom mapItem 1`] = `"<div><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_8_" data-slot="autocomplete-input" placeholder="Pick" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" data-placeholder="" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_8_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;
7+
exports[`Autocomplete (standalone) > snapshots > with custom mapItem 1`] = `"<div><div data-slot="autocomplete-input-group" class="astw:relative astw:flex astw:items-center"><input autocomplete="off" spellcheck="false" autocorrect="off" autocapitalize="none" role="combobox" aria-expanded="false" aria-haspopup="listbox" aria-autocomplete="list" id="base-ui-_r_8_" data-slot="autocomplete-input" placeholder="Pick" class="astw:border-input astw:bg-transparent astw:dark:bg-input/30 astw:transition-[color,box-shadow] astw:text-foreground astw:placeholder:text-muted-foreground astw:flex astw:h-9 astw:w-full astw:rounded-md astw:border astw:px-3 astw:py-1 astw:text-sm astw:shadow-xs astw:outline-none astw:focus-visible:border-ring astw:focus-visible:ring-ring/50 astw:focus-visible:ring-[3px] astw:disabled:cursor-not-allowed astw:disabled:opacity-50" type="text" value=""><button type="button" tabindex="-1" aria-expanded="false" aria-haspopup="listbox" data-slot="autocomplete-trigger" class="astw:absolute astw:inset-y-0 astw:right-0 astw:flex astw:items-center astw:px-2 astw:text-muted-foreground astw:outline-none astw:hover:text-foreground astw:disabled:pointer-events-none astw:disabled:opacity-50"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down astw:size-4" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></span></button></div><input id="base-ui-_r_8_-hidden-input" style="clip-path: inset(50%); overflow: hidden; white-space: nowrap; border: 0px; padding: 0px; width: 1px; height: 1px; margin: -1px; position: fixed; top: 0px; left: 0px;" tabindex="-1" aria-hidden="true" value=""></div>"`;

0 commit comments

Comments
 (0)