UNPKG

@aircall/blocks

Version:

Aircall Blocks — higher-level UI compositions built on @aircall/ds

247 lines (184 loc) 8.97 kB
--- name: aircall-blocks/setup description: > Set up @aircall/blocks in an app already (or simultaneously) adopting @aircall/ds. Load when wiring blocks compositions (DashboardPage, DashboardPageHeader, DashboardSidebar, empty states, form fields) into a project: installing the package, importing its precompiled globals.css after the DS bundle, and the DS providers it relies on. Covers both standalone apps and module-federation consumers where the host already loads DS globals. type: core library: aircall-blocks requires: - aircall-ds/setup sources: - "aircall/hydra:docs/migration-guides/tractor-to-ds/00-setup.md" - "aircall/hydra:packages/blocks/package.json" --- # Setting up @aircall/blocks This skill builds on aircall-ds/setup. Read it first: blocks compose `@aircall/ds` primitives and depend on DS being installed and its `globals.css` imported. ## Setup Install blocks alongside DS: ```bash pnpm add @aircall/blocks @aircall/ds @aircall/react-icons ``` How you import the CSS depends on whether your app is standalone or a **module-federation consumer** whose host already loads DS globals. ### Standalone app (owns its own Preflight) `@aircall/blocks/globals.css` is a **delta build** — it contains only blocks-specific tokens and utility classes; it does NOT bundle DS. Import DS globals first (Preflight + DS tokens + DS utilities), then blocks globals (blocks-specific delta). Always import in this order. ```css /* style.css */ @layer theme, base, components, utilities; @import 'tailwindcss/theme.css' layer(theme); @import 'tailwindcss/utilities.css' layer(utilities); @import '@aircall/ds/globals.css'; @import '@aircall/blocks/globals.css'; @source './src/**/*.{ts,tsx}'; ``` Or from a JS/TS entry (no custom Tailwind classes of your own): ```tsx // main.tsx import '@aircall/ds/globals.css'; import '@aircall/blocks/globals.css'; ``` #### Single-compilation via `theme.css` (recommended for DS + blocks) The two precompiled bundles above each re-emit the same Tailwind utilities into `@layer utilities`; at equal specificity the last-loaded bundle can clobber the other's responsive variants (e.g. blocks' plain `.text-base` beating DS's `md:text-sm` on `Textarea`), and **no import order fixes it**. To avoid this, import the directive-preserving `theme.css` artifacts (tokens + dark variant + reset + keyframes only — **no** Preflight, **no** utilities) and let a single Tailwind pass generate the utilities by `@source`-scanning the library dist: ```css /* style.css */ @import 'tailwindcss'; /* consumer owns the single Preflight + engine */ @import '@aircall/ds/theme.css'; @import '@aircall/blocks/theme.css'; @source '../node_modules/@aircall/ds/dist/index.js'; @source '../node_modules/@aircall/blocks/dist/index.js'; ``` Here the full `@import 'tailwindcss'` is **correct** (unlike the `globals.css` case) because `theme.css` ships no Preflight/utilities. `globals.css` still ships unchanged for precompiled- bundle consumers. Full rationale: `packages/ds/docs/single-compilation-theme-css.md`. ### Module-federation consumer (host already owns the Preflight) When your app is a remote loaded inside a host that already imports DS globals (e.g. `dashboard-v4`), **do not re-import DS or blocks globals** in your own CSS. The host's single Preflight applies to the whole document — re-importing it duplicates the base reset and causes cascade conflicts (see Common Mistakes below). Import only the Tailwind layers you need for your own authored utility classes: ```css /* style.css */ @layer theme, base, components, utilities; @import 'tailwindcss/theme.css' layer(theme); @import 'tailwindcss/utilities.css' layer(utilities); @source './**/*.{ts,tsx}'; ``` > **Note on the `.css` extension**: `@import "tailwindcss/theme"` (no `.css`) > silently fails in webpack/Rsbuild PostCSS pipelines — the extension is required. Blocks render under the same DS providers — there is no blocks-specific provider; mount the DS root providers from `aircall-ds/setup` as needed (`ThemeProvider` / `TooltipProvider` / `Toaster`). Two DS providers matter specifically once you use blocks: - **`DsI18nProvider`** (from `@aircall/ds`) — importing `@aircall/blocks` runs `import './i18n/register'` at module load (`packages/blocks/src/index.ts`), which registers a `blocks` namespace on DS's shared i18next instance. Block strings render localized off the self-initialized DS singleton even without a provider; to make DS + blocks strings follow the **user's** language (and track switches), mount `DsI18nProvider` **as a descendant of your react-i18next `I18nextProvider`** and pass the active language (`language={i18n.language}`). Use **either** `DsI18nProvider` **or** `syncDsLanguage(i18n)`, never both. See `aircall-ds/setup` for the full provider tree and nesting order. - **`NotificationQueueProvider` + `NotificationSlot`** (from `@aircall/ds`) — needed only if your block compositions surface notifications/banners: wrap `NotificationQueueProvider` (props `{ children }`) above any notification caller, and render a `NotificationSlot slot="page"` (props `{ slot: string; className? }`) inside it. Source: `packages/blocks/src/index.ts`; `@aircall/ds` `DsI18nProvider` / `NotificationQueueProvider`. ## Core Patterns ### Use a block composition ```tsx import { DashboardPageHeader, DashboardPageHeaderTitle, } from '@aircall/blocks'; function CampaignsHeader() { return ( <DashboardPageHeader> <DashboardPageHeaderTitle size="lg">Campaigns</DashboardPageHeaderTitle> </DashboardPageHeader> ); } ``` ## Common Mistakes ### HIGH — Re-importing DS/blocks globals in a module-federation consumer Wrong — in a consumer whose host already loads DS globals: ```css @import 'tailwindcss'; @import '@aircall/ds/globals.css'; @import '@aircall/blocks/globals.css'; ``` Correct — consumer owns only its own utilities, no Preflight: ```css @layer theme, base, components, utilities; @import 'tailwindcss/theme.css' layer(theme); @import 'tailwindcss/utilities.css' layer(utilities); @source './**/*.{ts,tsx}'; ``` In a module-federation setup, CSS from each remote lands in the **same document** as the host. DS globals ships a Preflight (`@layer base { * { border-color: var(--color-border); } }`) that sets the token-based border color globally. If the consumer also imports DS globals (or the full `@import 'tailwindcss'`), it emits a second `@layer base` reset. Because webpack/Rsbuild emits deep dependencies first and the consumer's own CSS last, the consumer's Preflight (`border-color: currentColor`) ends up later in the output — and later wins. DS component borders (Card, etc.) lose their token color and become invisible. ### HIGH — Importing blocks globals before DS globals (or omitting DS globals) Wrong — wrong order, or omitting DS globals: ```css @import '@aircall/blocks/globals.css'; @import '@aircall/ds/globals.css'; ``` ```css /* missing DS globals entirely */ @import '@aircall/blocks/globals.css'; ``` Correct — DS globals first, then blocks globals: ```css @import '@aircall/ds/globals.css'; @import '@aircall/blocks/globals.css'; ``` `@aircall/blocks/globals.css` is a delta build — it contains only blocks-specific tokens and utility classes. It depends on DS globals being loaded first to provide Preflight and DS token definitions. Loading blocks before DS means DS's base reset (`border-color: var(--color-border)`) lands after blocks and within the same `@layer base`, and component tokens like `--background` and `--border` may not be defined when blocks tries to use them. Source: aircall/hydra:docs/migration-guides/tractor-to-ds/00-setup.md (§3) ### MEDIUM — Using bare specifiers without `.css` in Rsbuild/webpack Wrong: ```css @import 'tailwindcss/theme'; @import 'tailwindcss/utilities'; ``` Correct: ```css @import 'tailwindcss/theme.css'; @import 'tailwindcss/utilities.css'; ``` The bare form (no `.css`) silently produces no output in webpack/Rsbuild PostCSS pipelines — classes like `flex`, `gap-4`, `text-sm` are never generated. Always use the `.css` extension when splitting Tailwind imports. ### MEDIUM — Installing @aircall/blocks without @aircall/ds Wrong: ```bash pnpm add @aircall/blocks ``` Correct: ```bash pnpm add @aircall/blocks @aircall/ds ``` Blocks import from `@aircall/ds` at runtime; without it the blocks barrel fails to resolve its peer and the build breaks. Source: aircall/hydra:packages/blocks/package.json (peerDependencies) ### MEDIUM — Expecting a separate BlocksProvider Wrong: searching for a `BlocksProvider` to mount. Correct: blocks render under the DS providers from aircall-ds/setup; mount those, not a blocks-specific provider. There is no blocks-specific provider; assuming one wastes time and produces dead wiring. Source: aircall/hydra:docs/migration-guides/tractor-to-ds/00-setup.md (§4)