@sakaniui/react 0.8.7 → 0.8.9

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/AGENTS.md CHANGED
@@ -16,8 +16,20 @@ import manifest from '@sakaniui/react/manifest.json';
16
16
  const button = manifest.components.find((c) => c.name === 'Button'); // props[], contract.requiredProps
17
17
  ```
18
18
  Editors can query the same data through the bundled MCP server
19
- (`npx -y -p @sakaniui/react sakaniui-mcp`): `get_component`, `check_usage`, `get_tokens`, `get_guide`.
20
- If it is connected, call `check_usage` on every component you write.
19
+ (`npx -y -p @sakaniui/react sakaniui-mcp`): `search_components`, `get_component`, `search_icons`,
20
+ `check_code`, `check_usage`, `get_tokens`, `get_guide`, `check_compatibility`, `get_changelog`.
21
+
22
+ **Start from the example, check before you answer.** Every component has `example`: its imports and the
23
+ element with each required prop filled in, type-checked against the release. Start from it instead of
24
+ writing the element from memory. Never guess an icon name: find it with `search_icons` (icons are
25
+ `IconTrash`, `IconSettings`, ... from `@sakaniui/react/icons`, passed as `icon={IconTrash}`, not
26
+ `icon={<IconTrash />}`). If the server is connected, run `check_code` on every snippet you write.
27
+
28
+ **Versions.** Every component has `since`, the first release that contained it. The project may have an
29
+ older `@sakaniui/react` installed than the one the manifest describes: if an entry is marked
30
+ `availableInInstalled: false`, or `check_compatibility` lists it under `missingInInstalled`, it does not
31
+ exist in that project, so do not use it without upgrading. The server reads the project's installed
32
+ version itself; if it cannot, run `npm ls @sakaniui/react` and pass the result as `installedVersion`.
21
33
  If a prop, value or token is not in the manifest, it does not exist. If `contract.requiresAccessibleName`
22
34
  is true, the required `aria-label` / alt prop is the only thing that names the control. Do not drop it.
23
35
 
package/CHANGELOG.md ADDED
@@ -0,0 +1,495 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@sakaniui/react` are documented here.
4
+
5
+ ## 0.8.9
6
+
7
+ Stops assistants from inventing code. Found by testing the MCP server in Claude Code: it validated a
8
+ snippet correctly, then wrote its own example as `icon={<TrashIcon />}` -- an icon that does not exist,
9
+ passed as an element instead of a component.
10
+
11
+ - **Examples.** Every component and block in `manifest.json` has `example`: the import lines and the
12
+ element with each required prop filled in with a value of the right shape (an array of `BreadcrumbItem`
13
+ gets one real item). Prop types are read from the shipped `.d.ts`, and every example is type-checked
14
+ against the built package; the build fails if one does not compile.
15
+ - **Icon index.** `@sakaniui/react/icon-index.json` lists all 5,184 icons (and their 1,054 filled
16
+ variants) with Tabler's category and search tags. The build fails if it differs from the exports.
17
+ - **MCP: `search_icons`.** Finds real icon names by meaning ("delete" -> `IconTrash`); common UI intents
18
+ rank the conventional icon first.
19
+ - **MCP: `check_code`.** Checks a whole snippet as text (it is never run): imports must exist and come
20
+ from the right entry point, every SakaniUI element needs its required props, values must be allowed,
21
+ and icon props must be real icon components passed as `icon={IconTrash}`. Errors carry line numbers
22
+ and suggestions ("TrashIcon is not exported... Did you mean: IconTrash?").
23
+ - **MCP: `check_usage`** now validates icon props too, and `get_component` points at the example and
24
+ at `search_icons`.
25
+ - Fixed a type error in `KanbanBoardBlock` (drag attributes when dragging is disabled) that was printed
26
+ during every build.
27
+
28
+ ## 0.8.8
29
+
30
+ Audit of the agent contract and MCP server (accuracy, security, versioning).
31
+
32
+ - **Manifest accuracy.** `FaqBlock.columns` is now `1 | 2` (numbers), not `"1" | "2"`; prop `values`
33
+ keep their real type. All 231 design tokens are listed (the 49 `glass-*`, `surface-*` and `liquid-*`
34
+ tokens were missing). `LiquidGlass`, `LiquidBackdrop` and `HoverGroup` are described, and hooks and
35
+ helpers are listed under `utilities`. Defaults that are code (`createIcon(...)`, arrow functions) are
36
+ no longer shown. The build now fails if a public component is exported but not described, so the
37
+ manifest cannot silently fall behind.
38
+ - **Manifest content.** Design-tool (Figma) notes, source paths and a sample e-mail address are no longer
39
+ shipped in the manifest.
40
+ - **Versioning.** Every component has `since`, the first release that contained it. `CHANGELOG.md` now
41
+ ships in the package. The MCP server finds the project's own installed `@sakaniui/react` (working
42
+ directory, or `--project <dir>`) and answers from that copy; when the project is older it flags
43
+ components it does not have yet. New tools `check_compatibility` and `get_changelog`.
44
+ - **Summaries.** Component summaries were rewritten where the source notes were maintainer-only text
45
+ (garbled or empty summaries, design-tool node ids); blocks get a name-and-group summary.
46
+ - **Verified on every build.** `npm run build:lib` now also runs `scripts/manifest/verify.mjs`, which fails
47
+ the build (and so `npm publish`) if an entry is not a real export, a prop is not in the type
48
+ definitions, a token disagrees with `tokens.css`, `since` is newer than the package, or anything that
49
+ looks like a private reference (design-file link or node id, e-mail address, local path, key) or any
50
+ write / network / exec code in the server appears.
51
+ - **Server hardening.** Every tool argument is type- and length-checked, tools are marked read-only, and
52
+ the server reads only four fixed files from an install (package.json, manifest, AGENTS.md, CHANGELOG.md).
53
+
54
+ ## 0.8.7
55
+
56
+ - **Machine-readable contract for AI agents and tooling.** The package now ships
57
+ `@sakaniui/react/manifest.json`: every exported component and block (123 + 42) with its import
58
+ path, summary, props, types, enum values, defaults, required props and a
59
+ `requiresAccessibleName` flag, plus all 182 design tokens. It is generated from the TypeScript
60
+ source on every `build:lib` (react-docgen-typescript), so it cannot drift from the code, and it only
61
+ lists names that are really exported. AGENTS.md now points agents at it first.
62
+ - **MCP server.** `npx -y -p @sakaniui/react sakaniui-mcp` starts a local, dependency-free Model
63
+ Context Protocol server over stdio that answers from the shipped manifest and AGENTS.md. Tools:
64
+ `search_components`, `get_component`, `list_components`, `get_tokens`, `check_usage` (reports
65
+ missing required props, values outside an enum and props that do not exist) and `get_guide`.
66
+ - `IconButton`'s `icon` prop description no longer says "Lucide icon component" (it takes Tabler or Lucide).
67
+
68
+ ## 0.8.6
69
+
70
+ - **Social icons are now exported.** The glyphs the Figma ProfileCard and TeamCard use --
71
+ `XIcon`, `GithubIcon` (ProfileCard) and `InstagramIcon`, `FacebookIcon`, `LinkedinIcon`
72
+ (TeamCard) -- can be imported from `@sakaniui/react`, so an app's `socialLinks` can use the exact
73
+ same icons as the design system instead of copying them. They draw in `currentColor`.
74
+
75
+ ## 0.8.5
76
+
77
+ - **Sidebar: 8px corners.** To match the Figma file (where the sidebar components now use
78
+ `radius/md`), `SidebarItem`, `SidebarSubItem`, `SidebarSearch` (field, command and collapsed),
79
+ `SidebarHeader` (workspace card and brand button) and the `SidebarFooter` action button go from
80
+ 6px to 8px. Small icon buttons (the header toggle and footer menu) and the keyboard-shortcut
81
+ badge keep their size, as in Figma.
82
+
83
+ ## 0.8.4
84
+
85
+ - **Switch: new `stretch` variant.** `<Switch variant="stretch" />` adds a liquid motion: on every
86
+ toggle the thumb stretches (16 -> about 22px) as it travels -- the edge it is heading toward moves
87
+ first, the tail follows a beat later -- then relaxes into a circle. One smooth motion with no
88
+ overshoot, it stays inside the track, a click mid-travel reverses from where the thumb visibly is,
89
+ and it is off with reduced motion. `variant="default"` (the default) is the plain switch,
90
+ unchanged. Figma: Switch gains a *Type* axis (Default | Stretch).
91
+
92
+ ## 0.8.3
93
+
94
+ - **SakaniUI.** The design system is now called SakaniUI, and the GitHub repository moved to
95
+ github.com/samzydd/Sakaniui (the old URL redirects). The package name, `@sakaniui/react`, is
96
+ unchanged; this release updates the repository, homepage and issues links shown on npm.
97
+
98
+ ## 0.8.2
99
+
100
+ - **Kanban Board: calmer motion.** The dragged card's tilt and its settle on drop are now
101
+ near-critically damped (overshoot down from about 30% to 2%), and the cards that slide out of the
102
+ way ease in without overshooting.
103
+
104
+ ## 0.8.1
105
+
106
+ - **Kanban Board: smooth drag and drop.** The block's native HTML5 drag is replaced by pointer-based
107
+ dragging (mouse, pen and touch). While you drag, the card lifts and swings from the grab point
108
+ with its movement; a drop slot -- the card itself at 20% with a 12/4 dashed outline -- opens
109
+ exactly where it will land and the other cards slide out of the way; on release the card glides
110
+ into place. Drops land at the slot's position instead of the end of the column. Touch drags start
111
+ with a press-and-hold, the board auto-scrolls at its edges, a card dropped outside every column
112
+ springs back, and reduced motion turns off the swing and glide.
113
+ - The sample board has photo avatars and five or six cards per column. Figma: Board Column gains a
114
+ *Drop target* variant, and the Kanban *Dragging* state shows the new slot.
115
+
116
+ ## 0.8.0
117
+
118
+ - **Removed:** Glass Icons (`@sakaniui/react/glass-icons`). The glass versions couldn't stay faithful
119
+ to every Tabler icon, so the set is gone from the package, the docs and the Figma file (with its
120
+ `glass-icon/*` variables and `--glass-icon-*` tokens). Use the regular icons from
121
+ `@sakaniui/react/icons` instead (`GlassHeart` -> `IconHeart`). Glass and liquid glass *surfaces*
122
+ are unchanged.
123
+ - `lucide-react` is gone entirely, and so is its licence notice: every icon is Tabler (MIT).
124
+
125
+ ## 0.7.0
126
+
127
+ - **Tabler Icons is now the icon set.** New entry point `@sakaniui/react/icons` with all 5,184 Tabler
128
+ outline icons (`IconHome`, `IconCalendar` ...) and 1,054 filled ones (`IconHomeFilled` ...),
129
+ generated from `@tabler/icons` and matching the Figma *↳ Icons (Tabler)* page. One component per
130
+ icon, tree-shaken individually (one icon is about 1 kB). Props follow lucide-react (`size`,
131
+ `color`, `strokeWidth`, `absoluteStrokeWidth`) plus `title`; default stroke 1.5, the Figma stroke.
132
+ - **Every component now renders Tabler icons.** The 125 Lucide icons used inside components and
133
+ blocks were swapped for their Tabler equivalents, with the same mapping as the Figma file (house
134
+ -> home, triangle-alert -> alert-triangle, panel-left -> layout-sidebar ...). `lucide-react` is no
135
+ longer a dependency of the package.
136
+ - Icon props are typed `IconComponent` (exported from the main entry) instead of Lucide's
137
+ `LucideIcon`; Lucide and Tabler React icons still fit, so existing apps keep working.
138
+ - **Removed:** `@sakaniui/react/sicons` (the rounded Lucide set from 0.6.x), replaced by
139
+ `@sakaniui/react/icons`. Swap `SiconHeart` for `IconHeart`; names follow Tabler.
140
+ - `THIRD_PARTY_NOTICES.md` now carries Tabler's MIT licence (icons) as well as Lucide's ISC licence
141
+ (Glass Icons, still Lucide-based).
142
+
143
+ ## 0.6.1
144
+
145
+ - **Sicons: crisp chevrons and checks.** Icons with short, sharp corners (chevrons, checks, small
146
+ arrows, list ticks) now use a 1px corner radius instead of 3.7 or 4; a 4px radius blunted their
147
+ points into curves. The rule: if a 4px radius would use more than 30% of the shorter edge at the
148
+ icon's tightest corner, the whole icon gets 1px (274 icons); every other icon keeps 4px. The
149
+ Figma Sicons set uses the same rule (307 icons there, where Figma joins some lines differently).
150
+
151
+ ## 0.6.0
152
+
153
+ - **Sicons: Sakani's own icon set, `@sakaniui/react/sicons`.** The same 1,626 icons as the Figma
154
+ *Icons* component set: Lucide's shapes at a 1.5 stroke with softened corners (a 4px radius, 3.7px
155
+ on icons whose short corners can't take 4). One component per icon (`SiconHeart`,
156
+ `SiconCalendar`, ...), each tree-shaken on its own (one icon is under 1 kB).
157
+ - Props follow lucide-react (`size`, `color`, `strokeWidth`, `absoluteStrokeWidth`), plus `title`,
158
+ so swapping a Lucide icon is a find-and-replace. Colour is `currentColor`.
159
+ - Figma first: the *Icons* set itself has the same rounded corners, so every icon instance in the
160
+ file matches.
161
+ - Corner rounding is baked into the path data at build time (`scripts/sicons/`), with the same
162
+ rule the Figma set was built with. A few percent of icons can get the 3.7 radius in one and the
163
+ 4 in the other where Figma joins lines differently. Where two lines meet at a shared point (an
164
+ arrow head on its shaft) the corner is left as is, as in Figma.
165
+ - Naming: the icon set is now called Sicons everywhere (Figma page *↳ Sicons*, component set
166
+ *Sicons*), credited as based on Lucide. The package now ships `THIRD_PARTY_NOTICES.md` with
167
+ Lucide's ISC licence, which covers Sicons and Glass Icons.
168
+ - Storybook: *Foundations -> Sicons* (overview, close-up, props, searchable gallery).
169
+ - Not changed: the built-in components still render lucide-react icons; moving them onto Sicons is
170
+ a separate step.
171
+
172
+ ## 0.5.0
173
+
174
+ - **Glass icons: all 1,626 icons in the Sakani icon set, as monochrome frosted glass.** New entry
175
+ point `@sakaniui/react/glass-icons`, one component per icon (`GlassHeart`, `GlassCalendar`, ...),
176
+ each tree-shaken on its own. Each icon's main shape is one charcoal glass solid (top-to-bottom
177
+ gradient, bright rim, soft shadow), a disc tucked behind its corner glows through the glass
178
+ blurred, and inner lines sit on the glass in white (lines off the glass stay solid). Line-only
179
+ icons (arrows, a checkmark) become a single thick glass stroke. Props: `size` (default 24, any CSS
180
+ length), `surface`, `title`.
181
+ - Charcoal on purpose: brand-neutral, so any team can use them. Colours are the new
182
+ `--glass-icon-*` tokens on `:root` and `.dark` (accent, glass-top, glass-bottom, rim, detail,
183
+ detail-off), so light and dark follow the nearest theme scope.
184
+ - Figma first: the file has the matching *Glass Icons* component set (page *↳ Glass Icons*, 1,626
185
+ 24x24 `type=` variants mirroring *Icons*, layers scale with the instance), coloured by the
186
+ `glass-icon/*` variables in the Semantic collection (Light/Dark).
187
+ - Which parts are glass and which are lines is decided at build time
188
+ (`scripts/glass-icons/decompose.mjs`), with the same rules the Figma set was built with.
189
+ - The set: 1,603 icons from lucide-react's shape data, 23 from the Figma file (brand logos Lucide
190
+ removed, plus icons Lucide merged into a sibling).
191
+ - Pure SVG on a 24x24 grid (masks, gradients, blur), no backdrop-filter: sharp at any size and the
192
+ same in every browser.
193
+ - `<GlassIcon icon={AnyLucideIcon} />` covers Lucide icons added later (drawn as one glass stroke).
194
+ - Storybook: *Foundations -> Glass Icons* (overview light/dark, sizes, searchable gallery).
195
+
196
+ ## 0.4.11
197
+
198
+ - **ProductCard matches Figma to the pixel.** Measured against the Figma set (320 x 536), the code
199
+ card was 546px tall and its text column 294px instead of 296px. Fixed: the title-to-description
200
+ gap is 8px (it was the body's 12px), the swatches are the 28px Figma uses (circle 21, check 10)
201
+ instead of 32px, the five stars are 91px wide (2.68px apart, not 4px), and the 1px border is taken
202
+ out of the padding and the image height so the stroke sits "inside" the frame as in Figma. The
203
+ standalone `ColorSwatch` is unchanged: it now sizes from `--swatch-size` (default 32px), which
204
+ the card sets to 28px.
205
+
206
+ ## 0.4.10
207
+
208
+ - **CRMDashboardBlock is responsive.** It was hard-wired to the viewport (`100vw` x `100vh`) with
209
+ media queries, so inside a frame, a split view or a phone it overflowed and clipped. It now fills
210
+ its container (`--crm-block-height` sets the height; default `100vh`) and its breakpoints are
211
+ container queries. Tablet (<= 880px): the filter panel steps aside and the toolbar wraps. Phone
212
+ (<= 640px): the icon rail becomes a slide-in navigation drawer opened from the top bar's menu
213
+ button (Escape or the scrim closes it), the toolbar stacks, tabs scroll, and padding tightens. The
214
+ table now stacks into cards based on its own width (<= 720px) instead of the window's, so it never
215
+ crams eight columns into a narrow frame. No prop changes.
216
+ - **TeamCard matches Figma's text width.** The card's 1px border was added on top of Figma's 12px
217
+ padding (Figma's stroke sits inside the frame), leaving a 378px text column instead of 380px. That
218
+ was enough to wrap the *Card details* bio onto a third line, making the card 20px taller than
219
+ Figma's. The border is now taken out of the padding, so the column is 380px and the bio wraps
220
+ exactly as in Figma.
221
+ - **KanbanBoardBlock works on phones.** The toolbar was one non-wrapping row, so the search field,
222
+ filter chips and buttons overlapped below ~700px. The block is now a size container: below 760px
223
+ the toolbar stacks (search, filters, then the actions sharing the row), and the board scrolls edge to
224
+ edge with columns snapping into place as you swipe. Wider layouts are unchanged.
225
+
226
+ ## 0.4.9
227
+
228
+ - **ProgressItem titles line up with their numbers.** In the vertical layout a title with no
229
+ description sat at the top of the 32px circle, 6px above its centre; it is now centred on the circle.
230
+ A title with a description stays top-aligned so the pair reads as one block. The horizontal layout
231
+ is left-aligned on purpose (the label starts at the circle's left edge) and that is now explicit in
232
+ the CSS.
233
+
234
+ ## 0.4.8
235
+
236
+ - **AI-readable design system.** The package now ships `AGENTS.md`: the *why* behind the system for
237
+ AI agents and new teammates — setup that must be right, eight principles, what to do when nothing
238
+ fits, when to use (and not use) each component and why it behaves as it does, glass/liquid usage rules,
239
+ the behaviour you must supply yourself, and recipes for AI-product moments (uncertain answers, sources,
240
+ declined requests, partial responses). The docs site serves an index at `/llms.txt` and the full
241
+ text at `/llms-full.txt`.
242
+
243
+ ## 0.4.7
244
+
245
+ - **SidebarPromo uses the real Button.** Its CTA was a hand-styled `<button>` too. It now renders
246
+ `<Button variant="primary" size="sm">` stretched full width, so it gets the updated hover,
247
+ press and focus effects. Liquid surfaces keep the outlined, see-through look. No prop changes.
248
+
249
+ ## 0.4.6
250
+
251
+ - **EmptyState uses the real Button.** The action was a hand-styled `<button>` that missed the
252
+ updated Button's hover, press and focus effects. It now renders `<Button variant="outline"
253
+ size="sm">`, so it stays in step with every Button change. No prop changes.
254
+
255
+ ## 0.4.5
256
+
257
+ - **BlogListingFeaturedCard is responsive.** The horizontal card (a fixed 400px image plus
258
+ text) squeezed its text column to a sliver whenever its container was narrower than ~640px.
259
+ It now measures its own container: side by side when there's room, stacked (image on top,
260
+ full width) below 640px, with the footer wrapping below 360px. Nothing changes at the
261
+ card's designed width (874px), and `BlogListingBlock` is unchanged. New story:
262
+ *Marketing → Blog Listing Featured Card → Responsive*.
263
+
264
+ ## 0.4.4
265
+
266
+ - **Stepper: the bar animates between steps.** Going forward, the connector fills from the
267
+ step you leave toward the next one and that circle activates when the bar arrives (its ring
268
+ ripples once and the previous circle's check draws in). Going back plays it in reverse,
269
+ draining the bar. Jumping several steps hands the fill from bar to bar. Horizontal and
270
+ vertical. No animation on first render; `prefers-reduced-motion` makes every change
271
+ instant. New stories: *Composite / Stepper → Animated* and *Animated vertical*.
272
+
273
+ ## 0.4.3
274
+
275
+ - **Faster sidebar toggle in the dashboard.** Collapsing or expanding the sidebar used
276
+ to drop frames (a 367ms frame and 200ms+ tasks on expand): the main glass panel
277
+ rebuilt its megapixel displacement map on every animation frame and the charts
278
+ re-rendered with it. Lens maps are now built only along the edges, big lenses settle
279
+ before re-measuring, and the dashboard content is memoized. Worst frame: 33ms, no
280
+ long tasks. Output is pixel-identical.
281
+ - **Collapsed rail:** hovering anywhere on the rail turns the logo into the "open
282
+ sidebar" button (it cross-fades), not only hovering the logo itself.
283
+
284
+ ## 0.4.2
285
+
286
+ **Liquid glass speaks Figma: the same Glass properties, the same values, the same result.**
287
+
288
+ - **`LiquidGlass` now takes Figma's Glass effect properties directly**, in
289
+ Figma's units: refraction, depth, dispersion, frost, light intensity and
290
+ light angle. The tokens are the liquid/regular and liquid/clear effect
291
+ styles as they are in Figma:
292
+ `--liquid-refraction-regular|clear` (0.55 | 0.8), `--liquid-depth-*`
293
+ (16 | 20), `--liquid-dispersion-*` (0.3 | 0.4), `--liquid-frost-*` (4 | 1),
294
+ `--liquid-light-intensity-*` (0.7 | 0.8) and `--liquid-light-angle` (-45).
295
+ Per element: `<LiquidGlass effect={{ refraction: 0.8, depth: 20, dispersion: 0.4, frost: 1 }}>`.
296
+ - **Measured, property by property.** Each Figma property was swept on its
297
+ own over gradient, step and flat-grey backdrops, and the code reproduces
298
+ every probe: the bend within 0.3px on average (all refraction, depth and
299
+ dispersion values), the frost blur within 0.3px, the light within half a
300
+ brightness level. How each property behaves:
301
+ - Refraction × depth sets the bend; depth also sets how far in it reaches
302
+ (0.8 × depth px). The steep fall near the rim folds the content just
303
+ inside into the magnified band along the edges and round the corners.
304
+ - Dispersion splits the color: red bends more, blue less.
305
+ - Frost blurs the backdrop before it is bent.
306
+ - Light is added on top: a 1px rim, strongest on edges that face the
307
+ light (none on edges side-on to it), plus a shade inside the lit edges
308
+ and a glow inside the far ones. It is drawn in the filter now, so it adds
309
+ light like Figma instead of laying white over the backdrop.
310
+ - **Correction to 0.4.1:** Figma's lens never samples outside the element, and
311
+ every edge bends the same way (with the light off). The 0.4.1 note about an
312
+ approximate clear rim no longer applies.
313
+ - **Breaking (tokens published in 0.4.1):** `--liquid-bezel-*`,
314
+ `--liquid-shift-*`, `--liquid-profile-*` and `--liquid-saturate-*` are gone
315
+ (Figma has no such properties); `--liquid-depth` is now Figma's Depth, and the
316
+ old inset-shadow token is `--liquid-edge-shade` (Safari/Firefox fallback
317
+ only). `--liquid-light-angle` is Figma's angle in degrees (-45), not a CSS
318
+ gradient angle.
319
+ - **New: `LiquidBackdrop`.** Wrap a liquid-glass UI in
320
+ `<LiquidBackdrop src={photo}>` and every lens inside refracts the photo itself
321
+ (an aligned copy, kept aligned while lenses glide, scroll or squish) instead of
322
+ whatever the browser painted below it. Like Figma, glass stacked on glass now
323
+ bends the sharp original: real refraction and color fringing on nested lenses,
324
+ not a blur of the lens below. `veil` lays a color over the image for every lens
325
+ (Figma's 5% overlay fill; a scrim in dark mode). `source={false}` on a lens
326
+ bends the UI below instead (slider knobs, selection droplets).
327
+ - **Fast at full-screen sizes.** A live SVG filter over a full-screen lens is
328
+ re-evaluated whenever anything near it repaints (the dashboard ran at ~15fps
329
+ while hovering the sidebar). Inside a `LiquidBackdrop`, lenses bigger than
330
+ 300×300 now run the same filter once into a canvas and re-bake only when their
331
+ size, position, theme or properties change: 60fps, pixel-identical. Small
332
+ lenses that move stay live; `bake={false}` keeps a big moving lens live.
333
+ - **`LiquidDashboardBlock`** sits on a `LiquidBackdrop`: the promo card and the
334
+ sidebar lenses refract the sharp photo like the Figma frame; the active lens
335
+ springs and stretches as it glides; item labels are fg/default as in Figma.
336
+ - **`LiquidDashboardBlock` is responsive.** It reflows to the width of its panel
337
+ (container queries): four stat cards become 2×2, then a column; the charts go
338
+ from three across to two, then one; Recent orders and Recent activity stack.
339
+ Below 900px the sidebar collapses to its rail by itself (until you toggle it).
340
+ The collapsed rail is fixed: lenses hug the 32px buttons, items are centered,
341
+ groups are separated by a hairline, and the lens lands exactly where the
342
+ rail's width animation ends. Search closes on Esc and shows a focus ring.
343
+ Collapsed tooltips are portaled to the page (the rail clipped them and the main
344
+ panel covered them), and hovering a nav item changes nothing but the glass: the
345
+ library's own icon darkening, which fired before the lens faded in, is off.
346
+ The opened search field is a glass pill: its icon and text were white on a white
347
+ box (the top bar is in on-photo mode), so they vanished.
348
+ - **Storybook:** *Foundations / Liquid Glass* is now a showcase (sidebar, tab bar
349
+ with a sliding droplet, Now Playing card whose slider knobs turn into lenses,
350
+ a lens you can drag over the photo), a dark version, and a Playground with
351
+ Figma's six Glass properties as controls. The calibration and measurement
352
+ tools moved to *Foundations / Liquid Glass / Lab*.
353
+
354
+ ## 0.4.1
355
+
356
+ **Liquid glass matches the Figma file.**
357
+
358
+ - **`tint` prop on `LiquidGlass`** — `"regular" | "clear" | "subtle" | "none"`.
359
+ `subtle` is Figma's `glass/bg-subtle` (5% ink; 8% white in dark), the fill of
360
+ a full-bleed overlay over a photo. Defaults to the variant's own tint.
361
+ - **One lens per variant.** `--liquid-refraction`, `-shift`, `-bezel`, `-profile`,
362
+ `-dispersion`, `-frost` and `-saturate` now have `-regular` and `-clear`
363
+ versions (Figma's two `liquid/*` effect styles), fitted against Figma's own
364
+ render. Set the unprefixed name on one element to override just that one.
365
+ - **Directional lens, rim and depth.** The bend, the rim light and the inner
366
+ shading follow `--liquid-light-angle` (Figma's light, -45 degrees), so the lit
367
+ edges differ from the far edges as in Figma. New `--liquid-shift-*`
368
+ and `--liquid-profile-*` tokens.
369
+ - **Figma's shadows** for both variants (`--liquid-shadow-regular|clear`) and
370
+ Figma's glass tint values (`.64 / .76 / .52`).
371
+ - **New `--surface-fg-muted` token** (solid, glass and liquid), and
372
+ `data-on-photo`: light text for any subtree that sits straight on a photo.
373
+ - Liquid scope defaults: the `Menu` is frosted, the active `SidebarItem` is flat
374
+ and `SidebarPromo` is transparent with an outlined button, so the dashboard
375
+ block no longer needs overrides for them.
376
+ - Known difference: Figma's clear lens samples *outside* the element at its lit
377
+ edges. CSS `backdrop-filter` cannot read outside its own box, so the clear
378
+ variant's rim is an approximation.
379
+
380
+ ## 0.4.0
381
+
382
+ **Glass and liquid glass.**
383
+
384
+ - **New theme axis: Surface (Solid · Glass · Liquid).** Components read
385
+ `--surface-*` tokens; `data-surface="glass" | "liquid" | "solid"` on any
386
+ ancestor re-themes everything inside it. Solid is pixel-identical to
387
+ before (checked story by story). Menus, modals and selects carry the
388
+ setting through their portals. `prefers-reduced-transparency` falls back
389
+ to opaque surfaces.
390
+ - **New: `LiquidGlass` and `useLiquidGlass`.** Apple-style liquid glass: an
391
+ SVG displacement filter bends the backdrop at the element's edge (with a
392
+ per-channel color fringe), plus tint, rim light, depth and a pointer-
393
+ following glare. Chromium renders the refraction; Safari and Firefox get
394
+ a frosted fallback with the same rim. Tunable through `--liquid-*` tokens
395
+ (tint, refraction, bezel, dispersion, frost, saturate, overlay and panel tints).
396
+ - **New block: `LiquidDashboardBlock`** (`@sakaniui/react/blocks`, Storybook
397
+ *Blocks / Application / Liquid Glass Dashboard*). A full dashboard on a
398
+ photo: one glass overlay, transparent chrome, solid data cards, an active
399
+ sidebar lens that only moves on click and a softer hover lens.
400
+ - Interaction polish: Switch spring, Slider fling bounce, chip/tag fade-out,
401
+ ListItem hover glide, ghost Button without shadow, Menu radius 8px,
402
+ `Switch` `description` prop, `bg/canvas` hover fill on surface components.
403
+ - Fix: the swatch checkmark could render invisible on light swatches in
404
+ server-rendered pages.
405
+
406
+ ## 0.3.5
407
+
408
+ - Replaces the Sakani mark (`PlaceholderLogo`'s default fill) with the new
409
+ logo, brand-orange background.
410
+ - Fix: `vite.lib.config.ts` has no `publicDir` override, so Vite's default
411
+ behaviour was copying this repo's `public/` folder into the published
412
+ package as a side effect — `dist/favicon.svg` shipped inside every install
413
+ of `@sakaniui/react` for no reason connected to the library itself. Still
414
+ ships (removing it isn't this release's job), but now carries the current
415
+ brand mark rather than a leftover unrelated asset.
416
+
417
+ ## 0.3.4
418
+
419
+ 0.3.3 was never actually published — a publish got stuck mid-flight on the
420
+ registry (staged but never finalized) and had to be abandoned rather than
421
+ retried, so this carries everything that would have shipped as 0.3.3:
422
+
423
+ - **Fix: `Popover` and `Modal` had no entrance/exit animation at all.** They
424
+ appeared and vanished on a single frame, unlike `Select` and `Combobox`,
425
+ which already ease their panels in and out. Both now animate over 180ms on
426
+ the same curve, kept mounted past `open` so the exit has something to play
427
+ on, and fall back to a timeout if `animationend` never fires (a
428
+ backgrounded tab, or anything suppressing animations) — without it, a
429
+ dismissed popover, or worse a full-screen modal backdrop, could be left
430
+ mounted and invisible over the page while still able to take focus.
431
+ - **Fix: charts read colour tokens from `document.documentElement`, ignoring
432
+ any `.dark`/`.force-light` scope between it and the chart.** A chart
433
+ rendered inside a themed container painted the *outer* theme's colours on
434
+ the *inner* theme's background. Tokens now resolve from the chart's own
435
+ element, and the reader re-renders when any ancestor's class changes, not
436
+ just `<html>`'s.
437
+ - **Fix: server-rendered charts never picked up real tokens at all.**
438
+ `useThemeTick` only bumped on theme *changes*; under SSR there is no
439
+ `getComputedStyle`, so a server-rendered chart kept its hardcoded fallback
440
+ colours forever once hydrated (React won't patch a hydration mismatch). It
441
+ now also bumps once on mount. Several of those fallbacks were themselves
442
+ stale values from an older palette and are corrected.
443
+ - **Fix: `Select`'s floating listbox and `Modal`'s backdrop ignored the
444
+ `.dark`/`.force-light` scope of whatever they were opened from.** Both
445
+ portal to `<body>` to position with `fixed`, which moves them out from
446
+ under any themed container; they now carry that container's theme class
447
+ onto the portaled element.
448
+ - `Table` gained a drag handle: a grip icon at the left edge of a
449
+ `reorderable` row, hidden until hover, and the sole drag origin (dragging
450
+ no longer starts from clicking anywhere in the row).
451
+ - `CRMDashboardBlock`, `KanbanBoardBlock` and `DataTableBlock` gained
452
+ `fillPlaceholders`, which extends the table to fill a taller container with
453
+ placeholder rows instead of leaving blank canvas below it.
454
+ - `Calendar` now exports its `DateRange` type.
455
+
456
+ ## 0.3.2
457
+
458
+ - **Fix: `@sakaniui/react/tokens.css` was never actually published.** The `exports` map pointed it at `./src/styles/tokens.css`, but `files: ["dist"]` only ever publishes the `dist` folder — so that path never existed in the installed package, and `import '@sakaniui/react/tokens.css'` (exactly as documented in the README) failed to resolve for every consumer. Without it, every component would have rendered completely unstyled: the CSS ships only the `var(--color-fg-default)` *references*, not the `:root { --color-fg-default: ... }` *definitions*. Fixed by copying `tokens.css` into `dist/` as part of the build and pointing the export there instead.
459
+
460
+ ## 0.3.1
461
+
462
+ - Fix: `Combobox`'s `loading` prop (the panel's loading state) was declared on `ComboboxOption` instead of `ComboboxProps`, so passing it to `<Combobox loading />` as documented was a type error and the prop was unreachable in a type-checked consumer. Moved to `ComboboxProps`, where the component was already reading it from at runtime.
463
+
464
+ ## 0.3.0
465
+
466
+ The library has grown substantially since the last published release —
467
+ five new categories of primitives and dozens of new blocks, all matching
468
+ their Figma source 1:1 and shipping with full light/dark support.
469
+
470
+ **New component categories:**
471
+ - **E-commerce** — Cart Item, Checkout Steps, Color Swatch, Price Display, Product Card, Product Gallery, Quantity Selector, Size Selector, Star Rating, Stock Status, Wishlist Button
472
+ - **Marketing** — Blog Blockquote, Blog Feature Text, Blog Image, Blog Listing Card, Blog Listing Featured Card, Featured Icon, First Page Heading, Job Listing, List, Location Dot, Marquee, Metric, Mobile Navigation Menu, Placeholder Logo, Profile Card, Rich Text Heading, Rich Text Paragraph, Section Heading, Sub Feature, Team Card
473
+
474
+ **New blocks:**
475
+ - **Authentication** — Email Verification, Forgot Password, Login, Reset Password, Sign Up, Two-Factor Authentication
476
+ - **Billing** — Add Card Form, Billing Address, Billing History, Current Plan, Payment Method
477
+ - **E-commerce** — Checkout Flow, Order Confirmation, Product Detail, Product Grid, Shopping Cart
478
+ - **Marketing** — Blog Listing, Careers, CTA Banner, FAQ, Feature Grid, Hero, Logo Cloud, Pricing Table, Team Section, Testimonial
479
+ - **Application** — Account Overview, Activity Log, App Header, Data Table + Toolbar, File Upload Panel, Form Modal, Inline CTA, Multistep Modal, Notification Panel, Onboarding Progress, Profile Settings, Section Footer
480
+
481
+ **Other:**
482
+ - `StarRating` gained a full `orientation` axis (horizontal / horizontal-reverse / vertical), shared between the E-commerce Product Detail block and Marketing's own Star Rating usage.
483
+ - Every component and block's Storybook Docs page now renders a real, written explanation (previously blank) — what it does, what it maps to in Figma, and key implementation notes, sourced from each component's own doc comments.
484
+ - The Storybook landing page now introduces the Sakani Design System itself instead of Storybook's generic default onboarding content.
485
+ - README's component/block inventory brought up to date with the actual library (114+ components, 41 blocks).
486
+
487
+ ## 0.2.0
488
+
489
+ - Blocks are now published from a separate subpath, `@sakaniui/react/blocks`, kept out of the main `@sakaniui/react` entry point so importing them is a deliberate choice.
490
+ - Added Funnel and Heatmap charts.
491
+ - The library now auto-builds (`prepare` script) on install.
492
+
493
+ ## 0.1.0
494
+
495
+ - First published release of `@sakaniui/react`.
package/README.md CHANGED
@@ -115,9 +115,19 @@ up instead of guessing prop names.
115
115
 
116
116
  Claude Code: `claude mcp add sakaniui -- npx -y -p @sakaniui/react sakaniui-mcp`
117
117
 
118
- Tools: `search_components`, `get_component`, `list_components`, `get_tokens`, `check_usage`
119
- (validates props against the contract) and `get_guide`. It runs locally, has no dependencies and
120
- answers from the installed version.
118
+ Tools: `search_components`, `get_component` (with a type-checked `example`), `search_icons`,
119
+ `check_code` (checks a whole snippet: imports, required props, values, icon names), `check_usage`,
120
+ `list_components`, `get_tokens`, `get_guide`, `check_compatibility` and `get_changelog`.
121
+
122
+ - **Read-only.** It reads five fixed files from a `@sakaniui/react` install (package.json, the
123
+ manifest, the icon index, AGENTS.md, CHANGELOG.md). Code given to `check_code` is read as text, never run. It writes nothing, runs nothing, opens no network connection and
124
+ takes no file paths. Every tool is marked read-only.
125
+ - **Matches your version.** It finds the `@sakaniui/react` installed in your project (working directory,
126
+ or `--project <dir>`) and flags components your version does not have yet, with the release notes for
127
+ the versions in between (`get_changelog`).
128
+ - **Accurate by construction.** `npm run build:lib` fails if the manifest disagrees with the real build:
129
+ an export that is not described, a prop that is not declared, an example that does not type-check, an
130
+ icon name that does not exist, a token that is not defined, or anything that looks like a private reference.
121
131
 
122
132
  ## Glass & liquid glass
123
133