Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/tabs-radio-size-alignment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@cube-dev/ui-kit": patch
---

fix(Tabs, RadioGroup): align radio/tabs size mapping

Both `Tabs type="radio"` and `Radio.Tabs` now use the same two API sizes with consistent Item button mappings:
- `large` (default): medium button (32px), 40px total
- `medium`: xsmall button (24px), 32px total
53 changes: 29 additions & 24 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ This document is a comprehensive reference for AI agents maintaining or extendin
## Package Overview

- **Package:** `@cube-dev/ui-kit`
- **Repository:** https://github.com/cube-js/cube-ui-kit
- **Storybook:** https://cube-ui-kit.vercel.app/
- **Repository:** [https://github.com/cube-js/cube-ui-kit](https://github.com/cube-js/cube-ui-kit)
- **Storybook:** [https://cube-ui-kit.vercel.app/](https://cube-ui-kit.vercel.app/)
- **Styling engine:** [Tasty](https://github.com/tenphi/tasty) (`@tenphi/tasty`)

## Tasty Documentation

Tasty documentation is bundled with this package in `docs/tasty/` (symlinked to `node_modules/@tenphi/tasty/docs` during development; copied at pack time by `scripts/prepare-docs.mjs`).

| File | Description |
|------|-------------|
| [usage.md](./docs/tasty/usage.md) | Core API: `tasty()` component creation, state mappings, sub-elements (`data-element`), variants, extending components, and React hooks (`useStyles`, `useGlobalStyles`, `useRawCSS`). |
| [configuration.md](./docs/tasty/configuration.md) | `configure()` options: tokens, recipes, custom units, style handlers, `@keyframes`, `@property`, parser cache, and TypeScript module augmentation. |
| [styles.md](./docs/tasty/styles.md) | Complete reference for all enhanced style properties: `fill`, `flow`, `preset`, `border`, `radius`, `transition`, `scrollbar`, shorthand syntax, and recommended alternatives to raw CSS properties. |
| [debug.md](./docs/tasty/debug.md) | `tastyDebug` runtime API: inspect injected CSS, view cache metrics, chunk breakdowns, and troubleshoot style issues. |
| [injector.md](./docs/tasty/injector.md) | Low-level style injector: `inject()`, `injectGlobal()`, `injectRawCSS()`, `keyframes()`, hash deduplication, reference counting, SSR, and Shadow DOM support. |
| [tasty-static.md](./docs/tasty/tasty-static.md) | Zero-runtime mode: `tastyStatic()`, Babel plugin setup, Next.js/Vite integration, and static extraction limitations. |

| File | Description |
| ------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [usage.md](./docs/tasty/usage.md) | Core API: `tasty()` component creation, state mappings, sub-elements (`data-element`), variants, extending components, and React hooks (`useStyles`, `useGlobalStyles`, `useRawCSS`). |
| [configuration.md](./docs/tasty/configuration.md) | `configure()` options: tokens, recipes, custom units, style handlers, `@keyframes`, `@property`, parser cache, and TypeScript module augmentation. |
| [styles.md](./docs/tasty/styles.md) | Complete reference for all enhanced style properties: `fill`, `flow`, `preset`, `border`, `radius`, `transition`, `scrollbar`, shorthand syntax, and recommended alternatives to raw CSS properties. |
| [debug.md](./docs/tasty/debug.md) | `tastyDebug` runtime API: inspect injected CSS, view cache metrics, chunk breakdowns, and troubleshoot style issues. |
| [injector.md](./docs/tasty/injector.md) | Low-level style injector: `inject()`, `injectGlobal()`, `injectRawCSS()`, `keyframes()`, hash deduplication, reference counting, SSR, and Shadow DOM support. |
| [tasty-static.md](./docs/tasty/tasty-static.md) | Zero-runtime mode: `tastyStatic()`, Babel plugin setup, Next.js/Vite integration, and static extraction limitations. |


## Project Structure

Expand Down Expand Up @@ -66,18 +68,20 @@ ComponentName/

## Commands

| Command | Description |
|---------|-------------|
| `pnpm storybook` | Start Storybook on port 6060 |
| `pnpm build` | Build library (tsdown, unbundled ESM) |
| `pnpm test` | Run all tests (Vitest) |
| `pnpm test -- ComponentName` | Run tests matching a pattern |
| `pnpm test -u -- ComponentName` | Update snapshots for a component |
| `pnpm fix` | Lint + format (ESLint + Prettier) |
| `pnpm size` | Check bundle size limits |
| `pnpm chromatic` | Visual regression tests |
| `pnpm add-icons` | Add new icons from tabler |
| `pnpm audit-docs` | Audit component API ↔ docs ↔ argTypes sync. Uses TS Compiler API for full type resolution. Options: `--component=Name` (single component), `--fix-stories` (auto-add/remove argTypes in `.stories.tsx`), `--fix-docs` (auto-update `### Style Properties` sections in `.docs.mdx`), `--json`, `--verbose`, `--all-props`. **Run after changing a component's API or adding a new component.** |

| Command | Description |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pnpm storybook` | Start Storybook on port 6060 |
| `pnpm build` | Build library (tsdown, unbundled ESM) |
| `pnpm test` | Run all tests (Vitest) |
| `pnpm test -- ComponentName` | Run tests matching a pattern |
| `pnpm test -u -- ComponentName` | Update snapshots for a component |
| `pnpm fix` | Lint + format (ESLint + Prettier) |
| `pnpm size` | Check bundle size limits |
| `pnpm chromatic` | Visual regression tests |
| `pnpm add-icons` | Add new icons from tabler |
| `pnpm audit-docs` | Audit component API ↔ docs ↔ argTypes sync. Uses TS Compiler API for full type resolution. Options: `--component=Name` (single component), `--fix-stories` (auto-add/remove argTypes in `.stories.tsx`), `--fix-docs` (auto-update `### Style Properties` sections in `.docs.mdx`), `--json`, `--verbose`, `--all-props`. **Run after changing a component's API or adding a new component.** |


## Stack

Expand All @@ -91,11 +95,11 @@ ComponentName/

## Creating Components

The full guide for creating components — including style props (`styleProps` vs `extractStyles`), `filterBaseProps`, modifiers, sub-elements, React Aria integration, variants, `useEvent`, and complete examples — is maintained in **`src/stories/CreateComponent.docs.mdx`** (rendered in Storybook under **Getting Started / Create Component**).
The full guide for creating components — including style props (`styleProps` vs `extractStyles`), `filterBaseProps`, modifiers, sub-elements, React Aria integration, variants, `useEvent`, and complete examples — is maintained in `**src/stories/CreateComponent.docs.mdx`** (rendered in Storybook under **Getting Started / Create Component**).

## Design System Reference

The full reference for tokens, presets, colors, modifiers, state syntax, recipes, icons, and the form system is maintained in **`src/stories/Usage.docs.mdx`** (rendered in Storybook under **Getting Started / Usage**).
The full reference for tokens, presets, colors, modifiers, state syntax, recipes, icons, and the form system is maintained in `**src/stories/Usage.docs.mdx`** (rendered in Storybook under **Getting Started / Usage**).

Refer to that file for:

Expand Down Expand Up @@ -133,3 +137,4 @@ Refer to that file for:
- **Barrel exports:** each category has `index.ts` files; everything re-exports through `src/index.ts`.
- **Compound components:** `Object.assign(Button, { Group: ButtonGroup, Split: ButtonSplit })`.
- **Tasty re-exports:** Only types are re-exported from `@tenphi/tasty`. Runtime imports (`tasty`, `extractStyles`, `filterBaseProps`) come directly from `@tenphi/tasty`.

16 changes: 6 additions & 10 deletions src/components/fields/RadioGroup/Radio.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { extractStyles } from '../../../utils/styles';
import { CubeItemProps, Item } from '../../content/Item/Item';
import { INLINE_LABEL_STYLES, useFieldProps, useFormProps } from '../../form';
import { HiddenInput } from '../../HiddenInput';
import { RADIO_SIZE_MAP } from '../../navigation/Tabs/types';

import { useRadioProvider } from './context';
import { RadioGroup } from './RadioGroup';
Expand Down Expand Up @@ -213,18 +214,13 @@ function Radio(props: CubeRadioProps, ref) {
// Determine effective size with priority: prop > context > default
let effectiveSize: CubeItemProps['size'] = (size ??
contextSize ??
(effectiveType === 'tabs' ? 'small' : 'medium')) as CubeItemProps['size'];
'medium') as CubeItemProps['size'];

// Apply size mapping for tabs mode button radios
// Apply size mapping for tabs mode button radios.
// API sizes mapped to Item button sizes: large -> medium (40px), medium -> xsmall (32px).
if (effectiveType === 'tabs' && isButton) {
if (effectiveSize === 'small' || effectiveSize === 'medium') {
effectiveSize = 'xsmall';
} else if (effectiveSize === 'large') {
effectiveSize = 'medium';
} else if (effectiveSize === 'xlarge') {
effectiveSize = 'large';
}
// 'xsmall' stays 'xsmall'
Comment thread
cursor[bot] marked this conversation as resolved.
effectiveSize =
RADIO_SIZE_MAP[effectiveSize === 'large' ? 'large' : 'medium'];
}

// Determine effective button type
Expand Down
39 changes: 2 additions & 37 deletions src/components/fields/RadioGroup/RadioGroup.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -236,47 +236,12 @@ export const ButtonGroupSizes: StoryFn<CubeRadioGroupProps> = () => (

export const TabsGroupSizes: StoryFn<CubeRadioGroupProps> = () => (
<>
<Radio.Tabs
size="xsmall"
defaultValue="yes"
label="XSmall (stays xsmall in tabs mode)"
>
<Radio value="yes">Yes</Radio>
<Radio value="no">No</Radio>
<Radio value="maybe">Maybe</Radio>
</Radio.Tabs>
<Radio.Tabs
size="small"
defaultValue="yes"
label="Small (maps to xsmall in tabs mode)"
>
<Radio value="yes">Yes</Radio>
<Radio value="no">No</Radio>
<Radio value="maybe">Maybe</Radio>
</Radio.Tabs>
<Radio.Tabs
size="medium"
defaultValue="yes"
label="Medium (maps to xsmall in tabs mode)"
>
<Radio.Tabs size="large" defaultValue="yes" label="Large (default, 40px)">
<Radio value="yes">Yes</Radio>
<Radio value="no">No</Radio>
<Radio value="maybe">Maybe</Radio>
</Radio.Tabs>
<Radio.Tabs
size="large"
defaultValue="yes"
label="Large (maps to medium in tabs mode)"
>
<Radio value="yes">Yes</Radio>
<Radio value="no">No</Radio>
<Radio value="maybe">Maybe</Radio>
</Radio.Tabs>
<Radio.Tabs
size="xlarge"
defaultValue="yes"
label="XLarge (maps to large in tabs mode)"
>
<Radio.Tabs size="medium" defaultValue="yes" label="Medium (32px)">
<Radio value="yes">Yes</Radio>
<Radio value="no">No</Radio>
<Radio value="maybe">Maybe</Radio>
Expand Down
4 changes: 2 additions & 2 deletions src/components/navigation/Tabs/Tabs.docs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -126,12 +126,12 @@ For individual tabs:

### Sizes

- `xsmall` - Extra small size with t4 typography (radio type only)
- `xsmall` - Extra small size with t4 typography
- `small` - Small size with t3m typography (default)
- `medium` - Default size with t3m typography
- `large` - Larger tabs with t3m typography

**Note:** Radio type only supports `medium` and `large` sizes, which are mapped to smaller Item sizes internally.
**Note:** Radio type supports `large` (default, 40px total) and `medium` (32px total) sizes, mapped to Item button sizes `medium` (32px) and `xsmall` (24px) respectively.

<Story of={TabsStories.LargeSize} />

Expand Down
20 changes: 20 additions & 0 deletions src/components/navigation/Tabs/Tabs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,26 @@ export const RadioTypeWithPanels: Story = {
),
};

/**
* Radio type sizes — large (default, 40px total) and medium (32px total)
*/
export const RadioTypeSizes: Story = {
render: (args) => (
<Space flow="column" gap="2x">
<Tabs {...args} type="radio" size="large" defaultActiveKey="tab1">
<Tab key="tab1" title="Large (default)" />
<Tab key="tab2" title="Weekly" />
<Tab key="tab3" title="Monthly" />
</Tabs>
<Tabs {...args} type="radio" size="medium" defaultActiveKey="tab1">
<Tab key="tab1" title="Medium" />
<Tab key="tab2" title="Weekly" />
<Tab key="tab3" title="Monthly" />
</Tabs>
</Space>
),
};

/**
* Large size tabs for emphasis
*/
Expand Down
9 changes: 6 additions & 3 deletions src/components/navigation/Tabs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export type TabSize = 'xsmall' | 'small' | 'medium' | 'large';

/**
* Size mapping for radio type tabs.
* Radio type uses smaller sizes similar to RadioGroup tabs mode.
* API sizes mapped to Item button sizes:
* medium (default) -> xsmall (32px total), large -> medium (40px total).
*/
export const RADIO_SIZE_MAP: Record<'medium' | 'large', TabSize> = {
medium: 'xsmall',
Expand Down Expand Up @@ -88,7 +89,8 @@ type OmittedItemProps =
export interface TabStyleProps extends Omit<CubeItemProps, OmittedItemProps> {
/**
* Tab size. Supports 'xsmall', 'small', 'medium', 'large'.
* Radio type only supports 'medium' | 'large' (mapped to smaller Item sizes).
* Radio type supports 'large' (default, 40px) and 'medium' (32px),
* mapped to Item button sizes medium (32px) and xsmall (24px).
*/
size?: TabSize;
/** Visual appearance type. */
Expand Down Expand Up @@ -123,7 +125,8 @@ export interface CubeTabsProps
type?: TabType;
/**
* Tab size. Supports 'xsmall', 'small', 'medium', 'large'.
* Radio type only supports 'medium' | 'large' (mapped to smaller Item sizes).
* Radio type supports 'large' (default, 40px) and 'medium' (32px),
* mapped to Item button sizes medium (32px) and xsmall (24px).
* @default 'medium'
*/
size?: TabSize;
Expand Down
Loading