From b9d780c22fd23853bed96cdb4ddfe1e90a223db8 Mon Sep 17 00:00:00 2001 From: bestaxbot <300268469+bestaxbot@users.noreply.github.com> Date: Wed, 2 Sep 2026 02:58:20 +0000 Subject: [PATCH 1/3] feat(bulma-ui): add touch/-only responsive viewports and grid display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bulma 1.0.4 generates display/hidden/invisible helpers for nine breakpoints (mobile, tablet, tablet-only, touch, desktop, desktop-only, widescreen, widescreen-only, fullhd) and six display values, but bestax only typed five breakpoints and five display values — so is-hidden-touch, is-flex-desktop-only and is-grid were only reachable through className. Extends validViewports and validDisplays, adds the matching display*/visibility* props to useVisibilityClasses (and gates useFlexboxClasses' container helpers on the new display props too), and updates the helper docs, skills MCP index and a new Storybook story to cover them. Fixes #621 Co-authored-by: Alex Smith --- bestax-mcp/data/catalog.json | 2 +- .../components/Valid value constants.json | 2 +- .../data/components/useBulmaClasses.json | 14 +- .../__tests__/useVisibilityClasses.test.tsx | 90 +++++++++- bulma-ui/src/helpers/bulmaClassHelpers.ts | 13 ++ .../src/helpers/useBulmaClasses.stories.tsx | 91 +++++++++- bulma-ui/src/helpers/useBulmaClasses.tsx | 20 +++ bulma-ui/src/helpers/useFlexboxClasses.tsx | 16 ++ bulma-ui/src/helpers/useVisibilityClasses.tsx | 39 ++++ docs/docs/api/helpers/usebulmaclasses.md | 168 +++++++++++++----- docs/docs/api/helpers/valid-values.md | 4 +- 11 files changed, 408 insertions(+), 51 deletions(-) diff --git a/bestax-mcp/data/catalog.json b/bestax-mcp/data/catalog.json index 1a3e06f2c..f14685e0e 100644 --- a/bestax-mcp/data/catalog.json +++ b/bestax-mcp/data/catalog.json @@ -1064,7 +1064,7 @@ "import": "import { useBulmaClasses } from '@allxsmith/bestax-bulma';", "compound": false, "propCount": 0, - "exampleCount": 40 + "exampleCount": 43 }, { "name": "usePrefixedClassNames", diff --git a/bestax-mcp/data/components/Valid value constants.json b/bestax-mcp/data/components/Valid value constants.json index 8fe47eb6a..50a1ca975 100644 --- a/bestax-mcp/data/components/Valid value constants.json +++ b/bestax-mcp/data/components/Valid value constants.json @@ -10,7 +10,7 @@ "storybook": null, "summary": "The `valid*` tuples enumerate the core accepted values for the shared Bulma helper props — public API for building prop types and validation.", "import": "import { Valid value constants } from '@allxsmith/bestax-bulma';", - "doc": "# Valid value constants\n\n## Overview\n\nThe `valid*` tuples enumerate the core accepted values for the shared Bulma helper props — public API for building prop types and validation. Each is a readonly `as const` tuple, so `(typeof validColors)[number]` gives you the exact string-literal union. `useBulmaClasses` (and the per-concern hooks) silently ignore unrecognized values, and every tuple member produces a helper class except `validSchemeColors`, whose values instead produce the `bulmaHelperStyles` inline style (no class). A few props accept documented extras beyond their tuple, noted in the table below: the `display*` props also take `'none'` (rendering the `is-hidden*` visibility class), and the color props also take `'inherit'` and `'current'` — so validate against the prop's TypeScript union, not the tuple alone, when you need the full contract.\n\n---\n\n## Import\n\n```tsx\nimport {\n validColors,\n validSizes,\n validViewports,\n} from '@allxsmith/bestax-bulma';\n```\n\nAll 19 constants are importable the same way.\n\n---\n\n## Constants\n\n| Constant | Values | Used by prop family |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `validColors` | `'primary'`, `'link'`, `'info'`, `'success'`, `'warning'`, `'danger'`, `'black'` … `'white'`, `'light'`, `'dark'` (17 values) | `color`, `backgroundColor` helper props. Component `color` modifier unions are narrower and component-specific; some `validColors` members ship no `is-` CSS (deprecated, warned in dev). See each component's Props table. Scheme-aware components extend their `bgColor` unions with `validSchemeColors` (below). |\n| `validColorShades` | `'00'`, `'05'` … `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `colorShade`, `backgroundColorShade` |\n| `validSchemeColors` | `'scheme-main'`, `'scheme-main-bis'`, `'scheme-main-ter'`, `'scheme-invert'`, `'scheme-invert-bis'`, `'scheme-invert-ter'` | Scheme-aware `bgColor`/`backgroundColor` values. Emit no class — components render them as a dark-mode-safe inline `background-color: var(--bulma-)` style (Bulma ships no `has-background-scheme-*` helpers). |\n| `validSizes` | `'0'`–`'6'`, `'auto'` | Spacing: `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, … `px`, `py` |\n| `validTextSizes` | `'1'`–`'7'` | `textSize` (+ `textSizeMobile` … `textSizeFullhd`) |\n| `validAlignments` | `'centered'`, `'justified'`, `'left'`, `'right'` | `textAlign` (+ viewport variants) |\n| `validTextTransforms` | `'capitalized'`, `'lowercase'`, `'uppercase'`, `'italic'` | `textTransform` |\n| `validTextWeights` | `'light'`, `'normal'`, `'medium'`, `'semibold'`, `'bold'` | `textWeight` |\n| `validFontFamilies` | `'sans-serif'`, `'monospace'`, `'primary'`, `'secondary'`, `'code'` | `fontFamily` |\n| `validDisplays` | `'block'`, `'flex'`, `'inline'`, `'inline-block'`, `'inline-flex'` — the `display*` props additionally accept `'none'` | `display` (+ `displayMobile` … `displayFullhd`) |\n| `validVisibilities` | `'hidden'`, `'sr-only'`, `'invisible'` | `visibility` (+ viewport variants) |\n| `validFlexDirections` | `'row'`, `'row-reverse'`, `'column'`, `'column-reverse'` | `flexDirection` |\n| `validFlexWraps` | `'nowrap'`, `'wrap'`, `'wrap-reverse'` | `flexWrap` |\n| `validJustifyContents` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'start'`, `'end'`, `'left'`, `'right'` | `justifyContent` |\n| `validAlignContents` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'stretch'` | `alignContent` |\n| `validAlignItems` | `'stretch'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'start'`, `'end'` | `alignItems` |\n| `validAlignSelfs` | `'auto'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'stretch'` | `alignSelf` |\n| `validFlexGrowShrink` | `'0'`–`'5'` | `flexGrow`, `flexShrink` |\n| `validViewports` | `'mobile'`, `'tablet'`, `'desktop'`, `'widescreen'`, `'fullhd'` | `viewport` (responsive modifier) |\n\n---\n\n## Typing with `(typeof …)[number]`\n\nBecause the arrays are `as const`, indexing them with `number` yields the union of their literal values — the same idiom the library uses internally for its prop types:\n\n```ts\nimport { validColors, validSizes } from '@allxsmith/bestax-bulma';\n\ntype Color = (typeof validColors)[number]; // 'primary' | 'link' | … | 'dark'\ntype Spacing = (typeof validSizes)[number]; // '0' | '1' | … | '6' | 'auto'\n\ninterface MyComponentProps {\n color?: Color;\n m?: Spacing;\n}\n```\n\nThey also work as runtime validators:\n\n```ts\nfunction isColor(value: string): value is (typeof validColors)[number] {\n return (validColors as readonly string[]).includes(value);\n}\n```\n\n:::warning `validSizes` is for spacing, not element sizes\n\n`validSizes` (`'0'`–`'6'` | `'auto'`) enumerates the **spacing helper** scale — the values for `m`/`p` props like `m=\"4\"` (→ `m-4`). Element `size` props are a different axis: `Button`, `Icon`, and friends declare an inline union such as `'small' | 'medium' | 'large'` (Button adds `'normal'`), **not** `validSizes`. Don't use `validSizes` to type a component's `size` prop.\n\n:::\n\n---\n\n## See Also\n\n- [`useBulmaClasses`](./usebulmaclasses.md): The hook that consumes these values and generates the helper classes.\n- [Helper guides](../../guides/helpers/color.md): Task-oriented walkthroughs of the helper-prop system (color, spacing, typography, flex, visibility).", + "doc": "# Valid value constants\n\n## Overview\n\nThe `valid*` tuples enumerate the core accepted values for the shared Bulma helper props — public API for building prop types and validation. Each is a readonly `as const` tuple, so `(typeof validColors)[number]` gives you the exact string-literal union. `useBulmaClasses` (and the per-concern hooks) silently ignore unrecognized values, and every tuple member produces a helper class except `validSchemeColors`, whose values instead produce the `bulmaHelperStyles` inline style (no class). A few props accept documented extras beyond their tuple, noted in the table below: the `display*` props also take `'none'` (rendering the `is-hidden*` visibility class), and the color props also take `'inherit'` and `'current'` — so validate against the prop's TypeScript union, not the tuple alone, when you need the full contract.\n\n---\n\n## Import\n\n```tsx\nimport {\n validColors,\n validSizes,\n validViewports,\n} from '@allxsmith/bestax-bulma';\n```\n\nAll 19 constants are importable the same way.\n\n---\n\n## Constants\n\n| Constant | Values | Used by prop family |\n| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `validColors` | `'primary'`, `'link'`, `'info'`, `'success'`, `'warning'`, `'danger'`, `'black'` … `'white'`, `'light'`, `'dark'` (17 values) | `color`, `backgroundColor` helper props. Component `color` modifier unions are narrower and component-specific; some `validColors` members ship no `is-` CSS (deprecated, warned in dev). See each component's Props table. Scheme-aware components extend their `bgColor` unions with `validSchemeColors` (below). |\n| `validColorShades` | `'00'`, `'05'` … `'95'`, `'invert'`, `'light'`, `'dark'`, `'soft'`, `'bold'`, `'on-scheme'` | `colorShade`, `backgroundColorShade` |\n| `validSchemeColors` | `'scheme-main'`, `'scheme-main-bis'`, `'scheme-main-ter'`, `'scheme-invert'`, `'scheme-invert-bis'`, `'scheme-invert-ter'` | Scheme-aware `bgColor`/`backgroundColor` values. Emit no class — components render them as a dark-mode-safe inline `background-color: var(--bulma-)` style (Bulma ships no `has-background-scheme-*` helpers). |\n| `validSizes` | `'0'`–`'6'`, `'auto'` | Spacing: `m`, `mt`, `mr`, `mb`, `ml`, `mx`, `my`, `p`, `pt`, … `px`, `py` |\n| `validTextSizes` | `'1'`–`'7'` | `textSize` (+ `textSizeMobile` … `textSizeFullhd`) |\n| `validAlignments` | `'centered'`, `'justified'`, `'left'`, `'right'` | `textAlign` (+ viewport variants) |\n| `validTextTransforms` | `'capitalized'`, `'lowercase'`, `'uppercase'`, `'italic'` | `textTransform` |\n| `validTextWeights` | `'light'`, `'normal'`, `'medium'`, `'semibold'`, `'bold'` | `textWeight` |\n| `validFontFamilies` | `'sans-serif'`, `'monospace'`, `'primary'`, `'secondary'`, `'code'` | `fontFamily` |\n| `validDisplays` | `'block'`, `'flex'`, `'inline'`, `'inline-block'`, `'inline-flex'`, `'grid'` — the `display*` props additionally accept `'none'` | `display` (+ `displayMobile` … `displayFullhd`) |\n| `validVisibilities` | `'hidden'`, `'sr-only'`, `'invisible'` | `visibility` (+ viewport variants) |\n| `validFlexDirections` | `'row'`, `'row-reverse'`, `'column'`, `'column-reverse'` | `flexDirection` |\n| `validFlexWraps` | `'nowrap'`, `'wrap'`, `'wrap-reverse'` | `flexWrap` |\n| `validJustifyContents` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'start'`, `'end'`, `'left'`, `'right'` | `justifyContent` |\n| `validAlignContents` | `'flex-start'`, `'flex-end'`, `'center'`, `'space-between'`, `'space-around'`, `'space-evenly'`, `'stretch'` | `alignContent` |\n| `validAlignItems` | `'stretch'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'start'`, `'end'` | `alignItems` |\n| `validAlignSelfs` | `'auto'`, `'flex-start'`, `'flex-end'`, `'center'`, `'baseline'`, `'stretch'` | `alignSelf` |\n| `validFlexGrowShrink` | `'0'`–`'5'` | `flexGrow`, `flexShrink` |\n| `validViewports` | `'mobile'`, `'tablet'`, `'tablet-only'`, `'touch'`, `'desktop'`, `'desktop-only'`, `'widescreen'`, `'widescreen-only'`, `'fullhd'` | `viewport` (responsive modifier) |\n\n---\n\n## Typing with `(typeof …)[number]`\n\nBecause the arrays are `as const`, indexing them with `number` yields the union of their literal values — the same idiom the library uses internally for its prop types:\n\n```ts\nimport { validColors, validSizes } from '@allxsmith/bestax-bulma';\n\ntype Color = (typeof validColors)[number]; // 'primary' | 'link' | … | 'dark'\ntype Spacing = (typeof validSizes)[number]; // '0' | '1' | … | '6' | 'auto'\n\ninterface MyComponentProps {\n color?: Color;\n m?: Spacing;\n}\n```\n\nThey also work as runtime validators:\n\n```ts\nfunction isColor(value: string): value is (typeof validColors)[number] {\n return (validColors as readonly string[]).includes(value);\n}\n```\n\n:::warning `validSizes` is for spacing, not element sizes\n\n`validSizes` (`'0'`–`'6'` | `'auto'`) enumerates the **spacing helper** scale — the values for `m`/`p` props like `m=\"4\"` (→ `m-4`). Element `size` props are a different axis: `Button`, `Icon`, and friends declare an inline union such as `'small' | 'medium' | 'large'` (Button adds `'normal'`), **not** `validSizes`. Don't use `validSizes` to type a component's `size` prop.\n\n:::\n\n---\n\n## See Also\n\n- [`useBulmaClasses`](./usebulmaclasses.md): The hook that consumes these values and generates the helper classes.\n- [Helper guides](../../guides/helpers/color.md): Task-oriented walkthroughs of the helper-prop system (color, spacing, typography, flex, visibility).", "parts": [], "cssVars": [] } diff --git a/bestax-mcp/data/components/useBulmaClasses.json b/bestax-mcp/data/components/useBulmaClasses.json index 675679818..85726d4dc 100644 --- a/bestax-mcp/data/components/useBulmaClasses.json +++ b/bestax-mcp/data/components/useBulmaClasses.json @@ -17,6 +17,18 @@ "title": "Responsive Props", "code": "function example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n m: '2',\n textAlign: 'centered',\n viewport: 'mobile',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'has-text-link-mobile m-2-mobile has-text-centered-mobile'\n}" }, + { + "title": "Touch and `-only` Viewports", + "code": "function example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n displayTouch: 'none',\n displayDesktopOnly: 'flex',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'is-hidden-touch is-flex-desktop-only'\n}" + }, + { + "title": "Touch and `-only` Viewports", + "code": "\n \n \n \n" + }, + { + "title": "Grid Display", + "code": "\n \n Cell 1\n \n \n Cell 2\n \n" + }, { "title": "With Flexbox Helpers", "code": "function example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'is-flex is-flex-direction-column is-align-items-center is-justify-content-center'\n}" @@ -171,7 +183,7 @@ "storybook": null, "summary": "`useBulmaClasses` is a custom React hook that generates Bulma helper class strings from a set of props.", "import": "import { useBulmaClasses } from '@allxsmith/bestax-bulma';", - "doc": "# useBulmaClasses\n\n## Overview\n\n`useBulmaClasses` is a custom React hook that generates Bulma helper class strings from a set of props. It makes it easy to apply color, spacing, alignment, typography, flexbox, and other Bulma utility classes to your components in a type-safe, composable way. It also separates out any non-helper props for direct use on elements.\n\n---\n\n## Import\n\n```tsx\nimport { useBulmaClasses } from '@allxsmith/bestax-bulma';\n```\n\n---\n\n## Usage\n\n:::info Container components pad themselves\nContainer components like `Box`, `Notification`, `Message`, and `Card` ship with Bulma's standard, pleasant padding and stack with sensible default spacing. The examples below only add margin or padding props when spacing itself is what's being demonstrated.\n:::\n\n### Basic Example\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n p: '4',\n textAlign: 'centered',\n id: 'card1',\n });\n\n return JSON.stringify({ bulmaHelperClasses, rest });\n // bulmaHelperClasses: 'has-text-link has-background-primary p-4 has-text-centered'\n // rest: { id: 'card1' }\n}\n```\n\nApply to your component:\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n p: '4',\n textAlign: 'centered',\n id: 'card1',\n });\n\n return (\n
\n Card content\n
\n );\n}\n```\n\n---\n\n### Responsive Props\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n color: 'link',\n backgroundColor: 'primary',\n m: '2',\n textAlign: 'centered',\n viewport: 'mobile',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'has-text-link-mobile m-2-mobile has-text-centered-mobile'\n}\n```\n\n---\n\n### With Flexbox Helpers\n\nFlexbox properties are divided into two categories:\n\n#### Container Properties\n\nThese properties apply to elements with `display: flex` or `display: inline-flex`:\n\n- `flexDirection` - Direction of flex items\n- `flexWrap` - Whether items wrap\n- `justifyContent` - Alignment along main axis\n- `alignContent` - Alignment of wrapped lines\n- `alignItems` - Alignment along cross axis\n\n#### Item Properties\n\nThese properties apply to flex items (children of flex containers) and **do not require** the element itself to have `display: flex`:\n\n- `alignSelf` - Override container's alignItems for this item\n- `flexGrow` - How much the item should grow\n- `flexShrink` - How much the item should shrink\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses } = useBulmaClasses({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: '4',\n });\n return JSON.stringify({ bulmaHelperClasses });\n // bulmaHelperClasses: 'is-flex is-flex-direction-column is-align-items-center is-justify-content-center'\n}\n```\n\nExample with flex items:\n\n```tsx\n// Container with display flex\n\n {/* Items don't need display flex to use alignSelf, flexGrow, flexShrink */}\n \n \n \n\n```\n\n---\n\n### Using with Components\n\n:::note These are illustrations, not replacements\nThe snippets below rebuild simplified components by hand purely to show how `useBulmaClasses` fits inside one. In a real app, use the library's own [Columns / Column](../columns/columns.md) and [Card](../components/card.md) components — they already wire up `useBulmaClasses` (plus prefixes, modifiers, and more) for you.\n:::\n\n#### Columns\n\n`MyColumns` forwards all of its props to `useBulmaClasses` — the `textAlign` and `textTransform` helper props below flow through `props` into the hook (producing `has-text-centered is-uppercase`), while anything the hook doesn't recognize comes back in `rest` and lands on the `
`:\n\n```tsx live\nfunction example() {\n function MyColumns({ children, ...props }) {\n const { bulmaHelperClasses, rest } = useBulmaClasses(props);\n return (\n
\n {children}\n
\n );\n }\n\n return (\n \n
\n Left\n
\n
\n Right\n
\n
\n );\n}\n```\n\n#### Card\n\n```tsx live\nfunction example() {\n const props = {};\n\n const textColor = 'white';\n const bgColor = 'primary';\n const hasShadow = true;\n const className = 'custom-card';\n const children =

Making a custom card

;\n const p = '4';\n\n const { bulmaHelperClasses, rest } = useBulmaClasses({\n color: textColor,\n backgroundColor: bgColor,\n p,\n ...props,\n });\n const cardClasses = classNames('card', className, bulmaHelperClasses, {\n 'is-shadowless': !hasShadow,\n });\n return (\n
\n {children}\n
\n );\n}\n```\n\n---\n\n### Colors\n\nUse the `color` prop to apply Bulma color classes. Here, each button demonstrates a different color:\n\n```tsx live\n\n \n \n \n \n \n \n \n \n\n```\n\n### Background Color\n\nUse the `backgroundColor` prop to set the background color. Pair it with a text color that keeps the label readable on each background:\n\n```tsx live\n\n \n \n Primary\n \n \n \n \n Link\n \n \n \n \n Info\n \n \n \n \n Success\n \n \n \n \n Warning\n \n \n \n \n Danger\n \n \n \n \n Black\n \n \n \n \n White\n \n \n\n```\n\n### Scheme Backgrounds and `bulmaHelperStyles`\n\nThe hook returns a third member, `bulmaHelperStyles`, alongside `bulmaHelperClasses` and `rest`. It is `undefined` for every input except a scheme `backgroundColor` (`scheme-main`, `scheme-main-bis`, `scheme-main-ter`, `scheme-invert`, `scheme-invert-bis`, `scheme-invert-ter`): Bulma ships no `has-background-scheme-*` classes, so those values emit no class and instead surface here as a dark-mode-safe inline style tracking Bulma's scheme CSS variables.\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n color: 'primary',\n backgroundColor: 'scheme-main-bis',\n id: 'band1',\n });\n\n return JSON.stringify({ bulmaHelperClasses, bulmaHelperStyles, rest });\n // bulmaHelperClasses: 'has-text-primary'\n // bulmaHelperStyles: { backgroundColor: 'var(--bulma-scheme-main-bis)' }\n // rest: { id: 'band1' }\n}\n```\n\nPut it on your element with `mergeBulmaStyles`, which merges the helper style with a user-supplied `style` prop (the user style wins, and the result is `undefined` when both are absent so the DOM stays untouched):\n\n```tsx live\nfunction example() {\n const { bulmaHelperClasses, bulmaHelperStyles, rest } = useBulmaClasses({\n backgroundColor: 'scheme-main-bis',\n p: '4',\n });\n\n return (\n \n A dark-mode-safe surface with zero custom CSS\n
\n );\n}\n```\n\nIn a real component, destructure `style` out of your own props and pass it as `mergeBulmaStyles`'s second argument (as `Section` does) — if `style` stays in the object you spread, whichever comes later in JSX silently replaces the other instead of merging.\n\n### Color Shade\n\n`colorShade` refines the **text color** — it pairs with the hook's `color` prop (exposed as `textColor` on components, where `color` is the component's own modifier). Here, each line steps through the primary palette:\n\n```tsx live\n<>\n \n Primary 10\n \n \n Primary 30\n \n \n Primary 60\n \n \n Primary 90\n \n \n Primary Invert\n \n\n```\n\n### Background Color Shade\n\nBackground shades use their own prop: `backgroundColorShade` pairs with `backgroundColor`, independently of `colorShade` (which pairs with the text color). Low shade numbers are dark and high numbers are light, so dark shades get light text and light shades get dark text to keep each label readable:\n\n```tsx live\n\n \n \n Primary 10\n \n \n \n \n Primary 30\n \n \n \n \n Primary 60\n \n \n \n \n Primary 90\n \n \n \n \n Primary Invert\n \n \n\n```\n\nBecause the two shade props are independent, you can shade the text and the background at the same time — a dark background shade with a light text shade of the same color reads well in both themes:\n\n```tsx live\n\n Primary text shade 85 on a primary background shade 15\n\n```\n\n### Margin\n\nUse margin props to add spacing. Here, margin is applied to buttons, and to a row of buttons using the `Buttons` component:\n\n```tsx live\n<>\n \n \n \n \n \n \n \n \n \n\n```\n\n### Text Size\n\nApply `textSize` to Notifications to illustrate different sizes:\n\n```tsx live\n<>\n Size 1\n Size 3\n Size 5\n Size 7\n\n```\n\n### Text Align\n\nApply `textAlign` to a Box to illustrate text alignment:\n\n```tsx live\n<>\n Centered text\n Right aligned text\n Left aligned text\n\n```\n\n### Text Transform\n\nApply `textTransform` to a Content tag with a paragraph of the Declaration of Independence:\n\n```tsx live\n<>\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n\n```\n\n### Text Weight\n\nApply `textWeight` to Content tags to illustrate different font weights:\n\n```tsx live\n<>\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n\n```\n\n### Font Family\n\nUse Content blocks with different font families:\n\n```tsx live\n<>\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n \n \n

\n We hold these truths to be self-evident, that all men are created\n equal...\n

\n
\n
\n\n```\n\n### Visibility\n\nShow three buttons, one hidden, one screen-reader only:\n\n```tsx live\n\n \n \n \n\n```\n\n### Overflow\n\nShow a Box with clipped overflow:\n\n```tsx live\n\n This is a very long line of text that will be clipped and not overflow the\n box.\n\n```\n\n### Overlay\n\nShow an overlay (toggle with button click):\n\n```tsx\nfunction OverlayExample() {\n const [show, setShow] = useState(false);\n return (\n \n \n \n );\n}\n```\n\n### Interaction\n\nShow text in a Box with `unselectable`, and another Box with `clickable`:\n\n```tsx live\n<>\n This text cannot be selected.\n This box is clickable.\n\n```\n\n### Cursor\n\nUse the `cursor` prop to set the cursor style. `'pointer'` reuses Bulma's `is-clickable` class, while `'help'` uses the project-level `is-cursor-help` class:\n\n```tsx live\n<>\n Cursor: pointer (uses is-clickable)\n Cursor: help\n\n```\n\n### Radius\n\nShow buttons with `radiusless`:\n\n```tsx live\n\n \n \n\n```\n\n### Shadowless\n\nShow a Box with `shadowless`:\n\n```tsx live\nThis box has no shadow.\n```\n\n### ClassName\n\nShow a Message with a custom className:\n\n```tsx live\n\n This message uses a custom className.\n\n```\n\n### Clearfix\n\nShow containers with and without clearfix to demonstrate the importance of clearing floated elements:\n\n```tsx live\n<>\n \n Without clearfix (container collapses)\n \n \n \n \n \n\n \n With clearfix (container wraps its floats)\n \n \n \n \n \n\n```\n\n### Relative Position\n\nShow a container with relative positioning that provides context for absolutely positioned children:\n\nBulma only ships an `is-relative` helper — absolute positioning itself has no helper class, so the child keeps a minimal `position/top/right` inline style while everything visual comes from props:\n\n```tsx live\n\n This container has position: relative\n \n Absolutely positioned child\n \n\n```\n\n---\n\n### Skeleton Examples\n\nThe `skeleton` prop applies Bulma's skeleton loading effect. Here are examples for each component:\n\n#### Skeleton Button\n\n```tsx live\n\n```\n\n#### Skeleton Buttons Group\n\n```tsx live\n\n \n \n \n\n```\n\n#### Skeleton Icon\n\n```tsx live\n\n```\n\n#### Skeleton Image\n\n```tsx live\n\"Skeleton\n```\n\n#### Skeleton Notification\n\n```tsx live\nSkeleton notification message.\n```\n\n#### Skeleton Tag\n\n```tsx live\nSkeleton Tag\n```\n\n#### Skeleton Title\n\n```tsx live\n\n Skeleton Title\n\n```\n\n#### Skeleton SubTitle\n\n```tsx live\n\n Skeleton SubTitle\n\n```\n\n#### Skeleton Input\n\n```tsx live\n\n```\n\n#### Skeleton TextArea\n\n```tsx live\n