@aircall/blocks 0.10.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aircall/blocks",
3
- "version": "0.10.1",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "private": false,
6
6
  "sideEffects": [
@@ -81,7 +81,7 @@
81
81
  "vite": "7.3.1",
82
82
  "vitest": "4.0.17",
83
83
  "zod": "4.4.3",
84
- "@aircall/ds": "0.17.1",
84
+ "@aircall/ds": "0.18.0",
85
85
  "@aircall/hooks": "0.5.1"
86
86
  },
87
87
  "keywords": [
@@ -169,15 +169,34 @@ cross-step validation.
169
169
 
170
170
  | `FormFieldProps` | After |
171
171
  |---|---|
172
- | `name` / `label` | `name` / `label` on the `Form*Field` |
172
+ | `name` | `name` on the `Form*Field` |
173
+ | `label` | `label` — a string, or `{ content, aside?, info? }` (see below) |
174
+ | helper/description text | `description` — a string, or `{ content, variant? }` (see below) |
173
175
  | `validate` | `validators.onChange` / `onSubmit` on the `Form*Field` |
174
176
  | `defaultValue` | `defaultValues[name]` in `useForm` |
175
177
  | `getErrorMessage(e)` | return the translated string from the validator |
176
178
 
179
+ **`label`** — a string is the label text. The object form adds label-row affordances:
180
+ - `label={{ content, info }}` — `info` is an `(i)` icon opening a popover of purely additive context
181
+ (hide it when ~90% of users don't need it).
182
+ - `label={{ content, aside }}` — `aside` is free-form content pinned to the **right** of the row (a
183
+ "Where do I find this?" link, a popover, plain text, …). You pass the node — an `Anchor`, a
184
+ `Popover`, whatever — and blocks wraps it in `FieldLabelAside` for alignment + typography, forcing
185
+ no styling of its own.
186
+
187
+ **`description`** — a string renders as the **`instructional`** variant (under the label, always
188
+ visible — the default). Pass `{ content, variant: 'contextual' }` to move it **below the control**,
189
+ where it is **hidden when the field is invalid** (the error takes its slot). Never mix both kinds on
190
+ one field.
191
+
192
+ **`necessityIndicator="required" | "optional"`** — mark only the exceptions (the few optional fields
193
+ in a mostly-required form, or vice versa); never mix both markers in one form.
194
+
177
195
  ## Fields reference
178
196
 
179
197
  `@aircall/blocks` ships typed wrappers for all common DS controls; each takes `form`,
180
- `name`, `label`, optional `validators`, and a render-prop `(field, control) => …` —
198
+ `name`, `label`, optional `validators`, optional `description` / `necessityIndicator`
199
+ (see Prop mapping above), and a render-prop `(field, control) => …` —
181
200
  spread the control bundle onto the matching DS primitive.
182
201
 
183
202
  | Input | Block | Input | Block |
@@ -5,7 +5,8 @@ description: >
5
5
  Load when wiring blocks compositions (DashboardPage, DashboardPageHeader,
6
6
  DashboardSidebar, empty states, form fields) into a project: installing the
7
7
  package, importing its precompiled globals.css after the DS bundle, and the DS
8
- providers it relies on.
8
+ providers it relies on. Covers both standalone apps and module-federation
9
+ consumers where the host already loads DS globals.
9
10
  type: core
10
11
  library: aircall-blocks
11
12
  library_version: "0.5.1"
@@ -29,8 +30,27 @@ Install blocks alongside DS:
29
30
  pnpm add @aircall/blocks @aircall/ds @aircall/react-icons
30
31
  ```
31
32
 
32
- Import the blocks bundle **after** the DS bundle from your JS/TS entry. It carries
33
- the page-layout grid and block-only tokens on top of DS:
33
+ How you import the CSS depends on whether your app is standalone or a
34
+ **module-federation consumer** whose host already loads DS globals.
35
+
36
+ ### Standalone app (owns its own Preflight)
37
+
38
+ `@aircall/blocks/globals.css` is a **delta build** — it contains only blocks-specific tokens
39
+ and utility classes; it does NOT bundle DS. Import DS globals first (Preflight + DS tokens +
40
+ DS utilities), then blocks globals (blocks-specific delta). Always import in this order.
41
+
42
+ ```css
43
+ /* style.css */
44
+ @layer theme, base, components, utilities;
45
+ @import 'tailwindcss/theme.css' layer(theme);
46
+ @import 'tailwindcss/utilities.css' layer(utilities);
47
+ @import '@aircall/ds/globals.css';
48
+ @import '@aircall/blocks/globals.css';
49
+
50
+ @source './src/**/*.{ts,tsx}';
51
+ ```
52
+
53
+ Or from a JS/TS entry (no custom Tailwind classes of your own):
34
54
 
35
55
  ```tsx
36
56
  // main.tsx
@@ -38,6 +58,28 @@ import '@aircall/ds/globals.css';
38
58
  import '@aircall/blocks/globals.css';
39
59
  ```
40
60
 
61
+ ### Module-federation consumer (host already owns the Preflight)
62
+
63
+ When your app is a remote loaded inside a host that already imports DS globals
64
+ (e.g. `dashboard-v4`), **do not re-import DS or blocks globals** in your own
65
+ CSS. The host's single Preflight applies to the whole document — re-importing
66
+ it duplicates the base reset and causes cascade conflicts (see Common Mistakes
67
+ below).
68
+
69
+ Import only the Tailwind layers you need for your own authored utility classes:
70
+
71
+ ```css
72
+ /* style.css */
73
+ @layer theme, base, components, utilities;
74
+ @import 'tailwindcss/theme.css' layer(theme);
75
+ @import 'tailwindcss/utilities.css' layer(utilities);
76
+
77
+ @source './**/*.{ts,tsx}';
78
+ ```
79
+
80
+ > **Note on the `.css` extension**: `@import "tailwindcss/theme"` (no `.css`)
81
+ > silently fails in webpack/Rsbuild PostCSS pipelines — the extension is required.
82
+
41
83
  Blocks render under the same DS providers — there is no blocks-specific provider; mount the
42
84
  DS root providers from `aircall-ds/setup` as needed (`ThemeProvider` / `TooltipProvider` /
43
85
  `Toaster`). Two DS providers matter specifically once you use blocks:
@@ -78,26 +120,82 @@ function CampaignsHeader() {
78
120
 
79
121
  ## Common Mistakes
80
122
 
123
+ ### HIGH — Re-importing DS/blocks globals in a module-federation consumer
124
+
125
+ Wrong — in a consumer whose host already loads DS globals:
126
+
127
+ ```css
128
+ @import 'tailwindcss';
129
+ @import '@aircall/ds/globals.css';
130
+ @import '@aircall/blocks/globals.css';
131
+ ```
132
+
133
+ Correct — consumer owns only its own utilities, no Preflight:
134
+
135
+ ```css
136
+ @layer theme, base, components, utilities;
137
+ @import 'tailwindcss/theme.css' layer(theme);
138
+ @import 'tailwindcss/utilities.css' layer(utilities);
139
+ @source './**/*.{ts,tsx}';
140
+ ```
141
+
142
+ In a module-federation setup, CSS from each remote lands in the **same document**
143
+ as the host. DS globals ships a Preflight (`@layer base { * { border-color: var(--color-border); } }`)
144
+ that sets the token-based border color globally. If the consumer also imports DS globals
145
+ (or the full `@import 'tailwindcss'`), it emits a second `@layer base` reset. Because
146
+ webpack/Rsbuild emits deep dependencies first and the consumer's own CSS last, the
147
+ consumer's Preflight (`border-color: currentColor`) ends up later in the output — and
148
+ later wins. DS component borders (Card, etc.) lose their token color and become invisible.
149
+
81
150
  ### HIGH — Importing blocks globals before DS globals (or omitting DS globals)
82
151
 
83
- Wrong:
152
+ Wrong — wrong order, or omitting DS globals:
84
153
 
85
- ```tsx
86
- import '@aircall/blocks/globals.css';
87
- import '@aircall/ds/globals.css';
154
+ ```css
155
+ @import '@aircall/blocks/globals.css';
156
+ @import '@aircall/ds/globals.css';
88
157
  ```
89
158
 
90
- Correct:
159
+ ```css
160
+ /* missing DS globals entirely */
161
+ @import '@aircall/blocks/globals.css';
162
+ ```
91
163
 
92
- ```tsx
93
- import '@aircall/ds/globals.css';
94
- import '@aircall/blocks/globals.css';
164
+ Correct — DS globals first, then blocks globals:
165
+
166
+ ```css
167
+ @import '@aircall/ds/globals.css';
168
+ @import '@aircall/blocks/globals.css';
95
169
  ```
96
170
 
97
- The blocks bundle layers page-layout tokens on top of the DS reset/tokens; loading it first (or without DS) leaves block compositions with missing base tokens and broken layout.
171
+ `@aircall/blocks/globals.css` is a delta build it contains only blocks-specific tokens
172
+ and utility classes. It depends on DS globals being loaded first to provide Preflight and
173
+ DS token definitions. Loading blocks before DS means DS's base reset (`border-color:
174
+ var(--color-border)`) lands after blocks and within the same `@layer base`, and component
175
+ tokens like `--background` and `--border` may not be defined when blocks tries to use them.
98
176
 
99
177
  Source: aircall/hydra:docs/migration-guides/tractor-to-ds/00-setup.md (§3)
100
178
 
179
+ ### MEDIUM — Using bare specifiers without `.css` in Rsbuild/webpack
180
+
181
+ Wrong:
182
+
183
+ ```css
184
+ @import 'tailwindcss/theme';
185
+ @import 'tailwindcss/utilities';
186
+ ```
187
+
188
+ Correct:
189
+
190
+ ```css
191
+ @import 'tailwindcss/theme.css';
192
+ @import 'tailwindcss/utilities.css';
193
+ ```
194
+
195
+ The bare form (no `.css`) silently produces no output in webpack/Rsbuild PostCSS
196
+ pipelines — classes like `flex`, `gap-4`, `text-sm` are never generated. Always
197
+ use the `.css` extension when splitting Tailwind imports.
198
+
101
199
  ### MEDIUM — Installing @aircall/blocks without @aircall/ds
102
200
 
103
201
  Wrong: