@box-kite/react 2.3.0 → 2.3.1
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/.claude/rules/box-kite-rules.md +3 -1
- package/.claude/skills/box-kite/SKILL.md +16 -14
- package/.claude/skills/box-kite/references/styling.md +2 -2
- package/.cursor/rules/box-kite.mdc +4 -2
- package/AGENTS.md +4 -2
- package/BOX_AI_CONTEXT.md +43 -40
- package/BOX_KITE_AI_CONTEXT.md +43 -40
- package/README.md +13 -7
- package/catalog.cjs +1 -1
- package/catalog.mjs +3 -0
- package/components/dataGrid/components/dataGridFooter.d.ts +6 -2
- package/components/dataGrid/models/gridModel.d.ts +21 -2
- package/components/dataGrid/models/groupRowModel.d.ts +1 -1
- package/components/dataGrid/models/rowModel.d.ts +1 -1
- package/components/dataGrid/models/sourceGroupRowModel.d.ts +5 -1
- package/components/dataGrid/models/sourceRowModel.d.ts +5 -1
- package/components/dataGrid.cjs +3 -3
- package/components/dataGrid.mjs +815 -765
- package/components/sortableList.cjs +1 -1
- package/components/sortableList.mjs +1 -1
- package/components/svg.d.ts +2 -2
- package/components/swipeItem.cjs +1 -1
- package/components/swipeItem.mjs +1 -1
- package/dataGridList.cjs +1 -1
- package/dataGridList.mjs +3 -5
- package/docs/props.md +43 -19
- package/package.json +5 -5
package/BOX_KITE_AI_CONTEXT.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @box-kite/react - AI Assistant Context
|
|
2
2
|
|
|
3
|
-
Runtime CSS-in-JS library. `Box` component accepts
|
|
3
|
+
Runtime CSS-in-JS library. `Box` component accepts CSS properties as typed props and generates CSS classes at runtime. Same prop values share a single class.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -191,7 +191,7 @@ All sizing, spacing, and positioning props also accept percentage strings: `p="5
|
|
|
191
191
|
| `fieldSizing` | field-sizing | `'content'` — a control that grows with what is typed into it, no JavaScript measuring anything — or `'fixed'` |
|
|
192
192
|
| `scrollbarGutter` / `scrollbarWidth` / `scrollbarColor` | scrollbar-gutter / -width / -color | `'stable'` / `'stable both-edges'` reserve the scrollbar's space before there is one, so nothing shifts when content overflows. `scrollbarWidth`: `'auto'`/`'thin'`/`'none'`; `scrollbarColor`: `[thumb, track]`, each a token, a `Box.extend()` colour or either with `/50` |
|
|
193
193
|
| `willChange` | will-change | `'transform'`, `'opacity'`, `'filter'`, `'scroll-position'`, `'contents'`, `'auto'`. A hint with a real cost (a promoted layer holds memory), so it belongs on the few elements that animate, not on a list |
|
|
194
|
-
| `cursor` / `pointerEvents` / `userSelect`
|
|
194
|
+
| `cursor` / `pointerEvents` / `userSelect` / `touchAction` | misc | string values. For `transition`, `animation` and the transform props see _Animation and transitions_ below |
|
|
195
195
|
|
|
196
196
|
### Anchor positioning — a floating layer with no JavaScript
|
|
197
197
|
|
|
@@ -468,26 +468,27 @@ one, nested wherever a prop nests, rendered on a server.
|
|
|
468
468
|
|
|
469
469
|
Twenty-three SVG properties, on any Box, plus twenty element components in `components/svg` — `Svg`, `G`, `Defs`, `Path`, `Circle`, `Ellipse`, `Rect`, `Line`, `Polyline`, `Polygon`, `SvgText`, `TSpan`, `LinearGradient`, `RadialGradient`, `Stop`, `ClipPath`, `Mask`, `Use`, `SvgSymbol`, `Marker`. **Never `<Box tag="path">`.** For an icon from somebody else's set, `<Icon>` (`components/icon`) — see below. (`BaseSvg` is deprecated: it is `Svg` with a 24×24 preset.)
|
|
470
470
|
|
|
471
|
-
| Prop | CSS Property | Accepts
|
|
472
|
-
| ------------------------------- | ----------------------------- |
|
|
473
|
-
| `fill` / `stroke` | fill / stroke | any colour variable, or `'none'`
|
|
474
|
-
| `fillOpacity` / `strokeOpacity` | fill-opacity / stroke-opacity | `0`–`1` in tenths, same scale as `opacity`
|
|
475
|
-
| `fillRule` | fill-rule | `'nonzero'`, `'evenodd'`
|
|
476
|
-
| `strokeWidth` | stroke-width | number, **user units — no divider** (`strokeWidth={2}` → `2`)
|
|
477
|
-
| `strokeLinecap` | stroke-linecap | `'butt'`, `'round'`, `'square'`
|
|
478
|
-
| `strokeLinejoin` | stroke-linejoin | `'miter'`, `'round'`, `'bevel'`
|
|
479
|
-
| `strokeMiterlimit` | stroke-miterlimit | number, 1 or greater
|
|
480
|
-
| `strokeDasharray` | stroke-dasharray | number (`{12}` = dash 12, gap 12)
|
|
481
|
-
| `strokeDashoffset` | stroke-dashoffset | number, or a percentage of the path length (`'40%'`)
|
|
482
|
-
| `paintOrder` | paint-order | `'normal'`, `'fill'
|
|
483
|
-
| `
|
|
484
|
-
| `
|
|
485
|
-
| `
|
|
486
|
-
| `
|
|
487
|
-
| `
|
|
488
|
-
| `
|
|
489
|
-
| `
|
|
490
|
-
| `
|
|
471
|
+
| Prop | CSS Property | Accepts |
|
|
472
|
+
| ------------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
473
|
+
| `fill` / `stroke` | fill / stroke | any colour variable, or `'none'` |
|
|
474
|
+
| `fillOpacity` / `strokeOpacity` | fill-opacity / stroke-opacity | `0`–`1` in tenths, same scale as `opacity` |
|
|
475
|
+
| `fillRule` | fill-rule | `'nonzero'`, `'evenodd'` |
|
|
476
|
+
| `strokeWidth` | stroke-width | number, **user units — no divider** (`strokeWidth={2}` → `2`) |
|
|
477
|
+
| `strokeLinecap` | stroke-linecap | `'butt'`, `'round'`, `'square'` |
|
|
478
|
+
| `strokeLinejoin` | stroke-linejoin | `'miter'`, `'round'`, `'bevel'` |
|
|
479
|
+
| `strokeMiterlimit` | stroke-miterlimit | number, 1 or greater |
|
|
480
|
+
| `strokeDasharray` | stroke-dasharray | number (`{12}` = dash 12, gap 12), the pattern as a string (`"12 4"`), or `'dashed'`/`'dotted'`, which scale with `strokeWidth` |
|
|
481
|
+
| `strokeDashoffset` | stroke-dashoffset | number, or a percentage of the path length (`'40%'`) |
|
|
482
|
+
| `paintOrder` | paint-order | `'normal'`, or up to three of `'fill'`/`'stroke'`/`'markers'` in paint order (`'stroke fill markers'`) |
|
|
483
|
+
| `pointerEvents` | pointer-events | `'none'`, `'auto'`, `'all'`, and which part of a shape takes the press: `'visiblePainted'`, `'visibleFill'`, `'visibleStroke'`, `'visible'`, `'painted'`, `'fill'`, `'stroke'`, `'bounding-box'` (not in Firefox) |
|
|
484
|
+
| `vectorEffect` | vector-effect | `'none'`, `'non-scaling-stroke'` |
|
|
485
|
+
| `shapeRendering` | shape-rendering | `'auto'`, `'optimizeSpeed'`, `'crispEdges'`, `'geometricPrecision'` |
|
|
486
|
+
| `textAnchor` | text-anchor | `'start'`, `'middle'`, `'end'` — which part of a label sits on its `x` |
|
|
487
|
+
| `dominantBaseline` | dominant-baseline | `'auto'`, `'alphabetic'`, `'central'`, `'middle'`, `'hanging'`, `'text-top'`, `'text-bottom'`, `'ideographic'`, `'mathematical'` |
|
|
488
|
+
| `cx` / `cy` | cx / cy | number in user units, or a percentage — `<circle>`, `<ellipse>` |
|
|
489
|
+
| `r` | r | number in user units, or a percentage — `<circle>` |
|
|
490
|
+
| `rx` / `ry` | rx / ry | number, a percentage, or `'auto'` — `<ellipse>` radii, `<rect>` corners |
|
|
491
|
+
| `x` / `y` | x / y | number in user units, or a percentage — `<rect>`, `<image>`, `<use>`, `<foreignObject>`, nested `<svg>`. NOT `<text>` |
|
|
491
492
|
|
|
492
493
|
```tsx
|
|
493
494
|
import { Circle, Path, Rect, Svg, SvgText } from '@box-kite/react/components/svg';
|
|
@@ -515,17 +516,18 @@ import { Circle, Path, Rect, Svg, SvgText } from '@box-kite/react/components/svg
|
|
|
515
516
|
<Rect x={16} y={32} width={24} height={64} rx={3} fill="sky-600" />
|
|
516
517
|
```
|
|
517
518
|
|
|
518
|
-
**
|
|
519
|
+
**Ten things to get right:**
|
|
519
520
|
|
|
520
|
-
1. **No divider on SVG lengths.** `strokeWidth`, `strokeDasharray`, `strokeDashoffset` and `strokeMiterlimit` pass the number through unchanged — they are measured in the coordinate system the `viewBox` sets up.
|
|
521
|
+
1. **No divider on SVG lengths.** `strokeWidth`, `strokeDasharray`, `strokeDashoffset` and `strokeMiterlimit` pass the number through unchanged — they are measured in the coordinate system the `viewBox` sets up. The geometry props (`cx`/`cy`/`r`/`rx`/`ry`/`x`/`y`) write that number as `px` — a user unit in SVG — because Firefox and Safari drop a bare number in them.
|
|
521
522
|
2. **Inheritance does the work.** Put `fill`/`stroke`/`strokeWidth` on the `<svg>`, not on every shape. The exception is a shape carrying its own `fill=` attribute — a presentation attribute on an element beats a value inherited from its parent, so style that shape directly.
|
|
522
523
|
3. **`vectorEffect` and `dominantBaseline` are not inherited**, so their rules target the element _and_ its descendants (`.cls, .cls *`). `vectorEffect="non-scaling-stroke"` on the `<svg>` keeps a hairline one pixel wide at any scale; `dominantBaseline="central"` on the `<svg>` reaches every label inside it.
|
|
523
524
|
4. **Geometry belongs to the shape, and it transitions.** `cx`/`cy`/`r`/`rx`/`ry`/`x`/`y` are real CSS in SVG 2, so a gauge or a growing bar is a pseudo-class and no JavaScript. They are not inherited and should not be — set them on the shape.
|
|
524
|
-
5. **Each component settles the names SVG and Box both use, for its own element.** On `Path`, `d` is path data (not `flexDirection`); on `Rect`, `width`/`height` are user units (not the ÷4 layout scale); on `SvgText` and `TSpan`, `x`/`y`/`dx`/`dy` are attributes, because the CSS geometry properties do not apply to text; on `RadialGradient`, `cx`/`cy`/`r` are attributes, because they do not apply to a gradient either — while on `Circle` the same names stay CSS and transition. `transform` is a prop on every shape and group (`transform="rotate(-90 48 48)"`
|
|
525
|
+
5. **Each component settles the names SVG and Box both use, for its own element.** On `Path`, `d` is path data (not `flexDirection`); on `Rect`, `width`/`height` are user units (not the ÷4 layout scale); on `SvgText` and `TSpan`, `x`/`y`/`dx`/`dy` are attributes, because the CSS geometry properties do not apply to text; on `RadialGradient`, `cx`/`cy`/`r` are attributes, because they do not apply to a gradient either — while on `Circle` the same names stay CSS and transition. `transform` is a prop on every shape and group, for a matrix or an angle that is data (`transform="rotate(-90 48 48)"`); a fixed turn about the shape's own centre is CSS (item 10).
|
|
525
526
|
6. **`Svg` sizes with attributes and names itself with `label`.** `viewBox`, `preserveAspectRatio`, `width` and `height` are the SVG attributes (`width="100%"`, `width={200}`), so the ÷4 layout `width`/`height` are not available on it. No `label` means `aria-hidden` — decoration, which is what most SVG is; `label` makes it `role="img"` with that name. A role or `aria-*` of your own in `props` wins over both.
|
|
526
527
|
7. **An icon from a set is not SVG you draw — it is `<Icon>`.** `<Icon size={5} color="amber-500" label="Sunny"><Sun /></Icon>` from `components/icon`, wrapping one element from lucide, Tabler, react-icons, or a raw `<svg>`. `size` is the ÷4 scale (`size={6}` is 24px, the default) and lands in the _class_, where a CSS declaration outranks the `width`/`height` attributes the icon set writes — which is why `Icon` needs to know no set's API. `strokeWidth` is the same: an ordinary Box prop, so it can change on hover. No `label` means `aria-hidden`; a `label` means `role="img"`. **Reach for `Svg` rather than wrapping one in `Icon`** — `Svg` takes these props directly. (Wrapping one does work: `Icon` asks the child which convention it follows and routes `role`/`aria-label` into `props` for a component of ours. It is still a layer nobody needs.)
|
|
527
528
|
8. **A paint server is a value, not an attribute.** `fill`, `stroke` and `clipPath` take `url(#id)` (a `<LinearGradient>`, a pattern, a `<ClipPath>` the document defines) and `var(--name)` (a variable somebody else declared) beside the colour tokens — so `fill="url(#sky)"` and `clipPath="url(#frame)"`, and both can differ per theme, on `hover` and per breakpoint. Only those two shapes are accepted: anything else emits no rule at all rather than a broken declaration. A gradient stop is still themed the same way — `<Stop stopColor="currentColor" color="amber-300" />`.
|
|
528
529
|
9. **An icon outside lucide comes through the same `<Icon>`.** Iconify carries 300,000+ icons in 200-plus sets, and the choice is only about _when_ the icon becomes markup. One icon: copy its SVG and paste it into an `<Icon>` — no dependency, renders on a server. A set: `unplugin-icons` compiles `~icons/<set>/<name>` into a component at build time from an `@iconify-json/<set>` devDependency (`npm i -D unplugin-icons @iconify-json/<set> @svgr/core @svgr/plugin-jsx`, the plugin with `{ compiler: 'jsx', jsx: 'react' }`, and `/// <reference types="unplugin-icons/types/react" />` in a `.d.ts`) — nothing fetched at runtime, server-renders. A name that is data (from a CMS, from a user): `@iconify/react`'s `<Icon icon="set:name"/>` inside our `<Icon>` — it fetches in the browser, so it is a client component and the server sends no icon. **Turbopack runs no unplugin**, so under Next.js 16 the build-time recipe needs `next build --webpack`; the other two work as they are.
|
|
530
|
+
10. **A shape turns about the viewBox's corner unless told otherwise.** An SVG element's `transform-box` is `view-box`, so `rotate={45}` alone swings a shape round `0 0`. `<G rotate={45} transformBox="fill-box" transformOrigin="center">` turns it about its own centre (measured in Chrome, Firefox and WebKit). `transformOrigin` takes a keyword (`'center'`, `'top left'`), a fraction or a percentage, a number on the ÷4 scale, or two or three positions as CSS writes them (`'48px 48px'` — in SVG a px is a user unit). An edge you can press is `pointerEvents="visibleStroke"` over a wide transparent stroke, and a drag on a touch screen needs `touchAction="none"` on the element pressed, or the page pans instead.
|
|
529
531
|
|
|
530
532
|
---
|
|
531
533
|
|
|
@@ -534,20 +536,21 @@ import { Circle, Path, Rect, Svg, SvgText } from '@box-kite/react/components/svg
|
|
|
534
536
|
Every Box already transitions `all` its properties over `--transitionTime` (0.25s), which is why a
|
|
535
537
|
`hover` colour fades without being asked. On top of that:
|
|
536
538
|
|
|
537
|
-
| Prop | CSS Property
|
|
538
|
-
| ----------------------------------------------------------------- |
|
|
539
|
-
| `animation` | animation
|
|
540
|
-
| `animationName` | animation-name
|
|
541
|
-
| `animationDuration` / `animationDelay` | ms
|
|
542
|
-
| `animationIterationCount` | number
|
|
543
|
-
| `animationDirection` / `animationFillMode` / `animationPlayState` | keywords
|
|
544
|
-
| `animationTimingFunction` / `transitionTimingFunction` | timing function
|
|
545
|
-
| `transition` | transition-property
|
|
546
|
-
| `transitionDuration` / `transitionDelay` | ms
|
|
547
|
-
| `transitionBehavior` | transition-behavior
|
|
548
|
-
| `interpolateSize` | interpolate-size
|
|
549
|
-
| `startingStyle` | `@starting-style`
|
|
550
|
-
| `translateX` / `translateY` / `rotate` / `scale` / `flip` | transform longhands
|
|
539
|
+
| Prop | CSS Property | Notes |
|
|
540
|
+
| ----------------------------------------------------------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
541
|
+
| `animation` | animation | One of four presets: `'spin'`, `'pulse'`, `'bounce'`, `'ping'`, or `'none'`. Keyframes come with the engine |
|
|
542
|
+
| `animationName` | animation-name | A sequence registered with `Box.keyframes()`, a preset name, or a name from any stylesheet |
|
|
543
|
+
| `animationDuration` / `animationDelay` | ms | **Milliseconds, no divider**: `animationDuration={1100}` → `1100ms` |
|
|
544
|
+
| `animationIterationCount` | number | A number or `'infinite'` |
|
|
545
|
+
| `animationDirection` / `animationFillMode` / `animationPlayState` | keywords | `'normal'`/`'reverse'`/`'alternate'`/`'alternate-reverse'`; `'none'`/`'forwards'`/`'backwards'`/`'both'`; `'running'`/`'paused'` |
|
|
546
|
+
| `animationTimingFunction` / `transitionTimingFunction` | timing function | Keywords, the four springs (`'spring'`, `'spring-gentle'`, `'spring-bouncy'`, `'spring-snappy'`), or a curve: `'cubic-bezier(0.4, 0, 0.6, 1)'`, `'steps(4, end)'`, `'linear(0, 0.5, 1)'` |
|
|
547
|
+
| `transition` | transition-property | `'all'`, `'none'`, or a group: `'colors'`, `'opacity'`, `'shadow'`, `'transform'`, `'size'`, `'filter'` |
|
|
548
|
+
| `transitionDuration` / `transitionDelay` | ms | Milliseconds, same as the animation pair. Both duration props also take a spring name — that spring's settling time |
|
|
549
|
+
| `transitionBehavior` | transition-behavior | `'normal'` or `'allow-discrete'`, which lets `display`, `overlay` and `content-visibility` transition — the property that makes an element animate _out_ without unmounting |
|
|
550
|
+
| `interpolateSize` | interpolate-size | `'numeric-only'` or `'allow-keywords'`, which is what makes `height: auto` animate. Inherited, so it belongs on a container. Chromium-only; elsewhere the size snaps |
|
|
551
|
+
| `startingStyle` | `@starting-style` | A nested block of plain props: what they start from the first time the element is styled. `startingStyle={{ opacity: 0, translateY: 2 }}` is an entrance with no JavaScript |
|
|
552
|
+
| `translateX` / `translateY` / `rotate` / `scale` / `flip` | transform longhands | Each writes its own CSS property, so they compose. `scale={1.05}` is unitless; `rotate={45}` is degrees |
|
|
553
|
+
| `transformOrigin` / `transformBox` | transform-origin / transform-box | The point `rotate`/`scale` turn about (`'center'`, `'top left'`, `'1/2 1/4'`, `'48px 48px'`, a ÷4 number) and the box it is measured in (`'fill-box'` for an SVG shape's own) |
|
|
551
554
|
|
|
552
555
|
```tsx
|
|
553
556
|
// A preset: no registration, and it stops under prefers-reduced-motion on its own
|
|
@@ -3830,7 +3833,7 @@ allowed.tokens; // the colours, the @keyframes names and the style-tree nodes a
|
|
|
3830
3833
|
`DataGrid`'s `def` (required — the columns and the grid-wide flags) and `data`, `DashboardGrid`'s
|
|
3831
3834
|
`layout`/`defaultLayout`/`columns`, `Widget`'s `empty`, `ChartContainer`'s `series`. A column's nested
|
|
3832
3835
|
`columns`, and `dataSource`/`onCellEdit`/`rowDetail`/`treeData`, stay out — they are the app's to pass.
|
|
3833
|
-
- **The allow-list is the app's.** `catalog()` with no options is
|
|
3836
|
+
- **The allow-list is the app's.** `catalog()` with no options is every component and every prop —
|
|
3834
3837
|
~4.6 MB serialized. `include`, `exclude` and `styleProps` are how an app narrows it.
|
|
3835
3838
|
|
|
3836
3839
|
Full reference: `docs/catalog.md`.
|
package/README.md
CHANGED
|
@@ -5,11 +5,16 @@
|
|
|
5
5
|
[](https://github.com/box-kite/box-kite/actions/workflows/test.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
-
`Box` is a single React component
|
|
8
|
+
`Box` is a single React component that takes CSS properties as typed props. It generates the CSS for the values you
|
|
9
9
|
pass at runtime and caches every rule by its content, so the same value anywhere in the app reuses
|
|
10
10
|
one class — a project styles itself in TypeScript, with no CSS files to write and no class-name
|
|
11
11
|
convention to remember.
|
|
12
12
|
|
|
13
|
+
**It renders in React Server Components** with no `'use client'`, no provider and no compiler: each
|
|
14
|
+
rule travels with the markup as a `<style href precedence>` element, which React 19 hoists and
|
|
15
|
+
dedupes — [how](#react-server-components-react-19) ·
|
|
16
|
+
[what it costs, measured against CSS modules](https://www.box-kite.dev/blog/styling-server-components/).
|
|
17
|
+
|
|
13
18
|
[Docs and live demos](https://www.box-kite.dev) · [Blog](https://www.box-kite.dev/blog/) · [Contributing](CONTRIBUTING.md) ·
|
|
14
19
|
[Support](SUPPORT.md) · [Security](SECURITY.md) ·
|
|
15
20
|
[Releases](https://github.com/box-kite/box-kite/releases)
|
|
@@ -46,10 +51,10 @@ target lives with the prop registry it extends, not with a binding.
|
|
|
46
51
|
Spacing counts in quarters of a rem: `p={3}` is `0.75rem`, `m={2}` is `0.5rem`. The example below is
|
|
47
52
|
a box with `margin: 0.5rem` and `padding: 1.75rem`.
|
|
48
53
|
|
|
49
|
-
```
|
|
50
|
-
import Box from
|
|
54
|
+
```tsx
|
|
55
|
+
import Box from '@box-kite/react';
|
|
51
56
|
|
|
52
|
-
export default function Component(
|
|
57
|
+
export default function Component() {
|
|
53
58
|
return (
|
|
54
59
|
<Box className="custom-class" m={2} p={7}>
|
|
55
60
|
basic example
|
|
@@ -69,8 +74,9 @@ are generated by running the engine, so the editor cannot tell you a scale the l
|
|
|
69
74
|
## Colours
|
|
70
75
|
|
|
71
76
|
The palette is Tailwind's, in OKLCH: twenty-six families of eleven steps — `slate-50` through
|
|
72
|
-
`rose-950`, the four Tailwind 4.3 added (`mauve`, `mist`, `olive`, `taupe`) included —
|
|
73
|
-
|
|
77
|
+
`rose-950`, the four Tailwind 4.3 added (`mauve`, `mist`, `olive`, `taupe`) included — each one a CSS
|
|
78
|
+
variable written with its own value as the fallback, so a page declares none of them in `:root` and
|
|
79
|
+
any stylesheet can override one. Any colour value takes an opacity modifier:
|
|
74
80
|
|
|
75
81
|
```JS
|
|
76
82
|
<Box bgColor="blue-500/40" borderColor="black/10" hover={{ bgColor: 'blue-500/60' }} />
|
|
@@ -687,7 +693,7 @@ A complete page — props, pseudo-classes, breakpoints, themes, `extend`, `compo
|
|
|
687
693
|
|
|
688
694
|
## Architecture
|
|
689
695
|
|
|
690
|
-
The styling engine is framework-free. Everything that generates CSS — the
|
|
696
|
+
The styling engine is framework-free. Everything that generates CSS — the prop definitions,
|
|
691
697
|
the value formatters, class-name generation, rule ordering, the style sinks (CSSOM, `textContent`,
|
|
692
698
|
string for SSR, style elements for React 19), the flush scheduler, CSS variables and the theme
|
|
693
699
|
runtime — lives in `src/core/` and imports no React at all. CI fails the build if it ever does
|