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
60 changes: 31 additions & 29 deletions bulma-ui/src/columns/Columns.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { BulmaGapSize, Columns } from './Columns';
import { Columns } from './Columns';
import type { BulmaGapValue } from '../grid/Grid';
import { Column } from './Column';
import { Notification } from '../elements/Notification';

Expand Down Expand Up @@ -158,34 +159,35 @@ export const GapSizes: StoryObj = {
render: () => (
<>
<p style={{ marginBottom: 16 }}>
You can control the gap between columns using <code>gapSize</code> and
responsive gap props.
You can control the gap between columns using <code>gap</code> and
responsive gap props (the same 0-8 scale as <code>Grid</code>&apos;s{' '}
<code>gap</code> prop).
</p>
<Columns gapSize={0}>
<Columns gap={0}>
<Column>
<Notification color="primary">gapSize=0</Notification>
<Notification color="primary">gap=0</Notification>
</Column>
<Column>
<Notification color="primary">gapSize=0</Notification>
<Notification color="primary">gap=0</Notification>
</Column>
</Columns>
<Columns gapSize={3}>
<Columns gap={3}>
<Column>
<Notification color="primary">gapSize=3</Notification>
<Notification color="primary">gap=3</Notification>
</Column>
<Column>
<Notification color="primary">gapSize=3</Notification>
<Notification color="primary">gap=3</Notification>
</Column>
</Columns>
<Columns gapSizeMobile={1} gapSizeTablet={3} gapSizeDesktop={6}>
<Columns gapMobile={1} gapTablet={3} gapDesktop={6}>
<Column>
<Notification color="primary">
gapSizeMobile=1 gapSizeTablet=3 gapSizeDesktop=6
gapMobile=1 gapTablet=3 gapDesktop=6
</Notification>
</Column>
<Column>
<Notification color="primary">
gapSizeMobile=1 gapSizeTablet=3 gapSizeDesktop=6
gapMobile=1 gapTablet=3 gapDesktop=6
</Notification>
</Column>
</Columns>
Expand Down Expand Up @@ -323,24 +325,24 @@ export const MultilineGapless: StoryObj = {
};

// --- VARIABLE GAP STORY ---
export const VariableGap: StoryObj<{ gapSize: number }> = {
export const VariableGap: StoryObj<{ gap: number }> = {
args: {
gapSize: 2,
gap: 2,
},
argTypes: {
gapSize: {
gap: {
control: { type: 'number', min: 0, max: 8, step: 1 },
description: 'Bulma gap size (0-8)',
},
},
render: ({ gapSize }) => (
render: ({ gap }) => (
<>
<p style={{ marginBottom: 16 }}>
The <code>gapSize</code> property controls the variable gap between
columns. Change the value of the storybook control for{' '}
<code>gapSize</code> to adjust spacing.
The <code>gap</code> property controls the variable gap between columns.
Change the value of the storybook control for <code>gap</code> to adjust
spacing.
</p>
<Columns gapSize={gapSize as BulmaGapSize}>
<Columns gap={gap as BulmaGapValue}>
<Column size={3}>
<Notification color="primary" className="has-text-centered">
Side
Expand All @@ -352,7 +354,7 @@ export const VariableGap: StoryObj<{ gapSize: number }> = {
</Notification>
</Column>
</Columns>
<Columns gapSize={gapSize as BulmaGapSize}>
<Columns gap={gap as BulmaGapValue}>
<Column size={4}>
<Notification color="primary" className="has-text-centered">
Three columns
Expand All @@ -369,7 +371,7 @@ export const VariableGap: StoryObj<{ gapSize: number }> = {
</Notification>
</Column>
</Columns>
<Columns gapSize={gapSize as BulmaGapSize}>
<Columns gap={gap as BulmaGapValue}>
{Array.from({ length: 12 }).map((_, i) => (
<Column key={i + 1}>
<Notification color="primary" className="has-text-centered">
Expand All @@ -391,16 +393,16 @@ export const BreakpointBasedColumnGaps: StoryObj = {
to see this in action
<br />
<code>
gapSizeMobile={1} gapSizeTablet={4} gapSizeDesktop={3}{' '}
gapSizeWidescreen={8} gapSizeFullhd={2}
gapMobile={1} gapTablet={4} gapDesktop={3} gapWidescreen={8}{' '}
gapFullhd={2}
</code>
</p>
<Columns
gapSizeMobile={1}
gapSizeTablet={4}
gapSizeDesktop={3}
gapSizeWidescreen={8}
gapSizeFullhd={2}
gapMobile={1}
gapTablet={4}
gapDesktop={3}
gapWidescreen={8}
gapFullhd={2}
>
{[...Array(6)].map((_, idx) => (
<Column key={idx}>
Expand Down
89 changes: 53 additions & 36 deletions bulma-ui/src/columns/Columns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,14 @@ import {
BulmaClassesProps,
validColors,
} from '../helpers/useBulmaClasses';
import type { BulmaGapValue } from '../grid/Grid';

/**
* Possible values for the Bulma columns gap size.
* @deprecated Use {@link BulmaGapValue} instead — `gapSize*` and `gap*` share
* the same 0-8 scale.
*/
export type BulmaGapSize =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| '0'
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8';
export type BulmaGapSize = BulmaGapValue;

/**
* Props for the Columns component.
Expand All @@ -42,12 +27,18 @@ export type BulmaGapSize =
* @property {boolean} [isVCentered] - Vertically center columns.
* @property {boolean} [isMobile] - Only apply columns styles on mobile.
* @property {boolean} [isDesktop] - Only apply columns styles on desktop.
* @property {BulmaGapSize} [gapSize] - Gap size for all breakpoints.
* @property {BulmaGapSize} [gapSizeMobile] - Gap size for mobile.
* @property {BulmaGapSize} [gapSizeTablet] - Gap size for tablet.
* @property {BulmaGapSize} [gapSizeDesktop] - Gap size for desktop.
* @property {BulmaGapSize} [gapSizeWidescreen] - Gap size for widescreen.
* @property {BulmaGapSize} [gapSizeFullhd] - Gap size for fullhd.
* @property {BulmaGapValue} [gap] - Gap size for all breakpoints. Wins over `gapSize` if both are set.
* @property {BulmaGapValue} [gapMobile] - Gap size for mobile. Wins over `gapSizeMobile` if both are set.
* @property {BulmaGapValue} [gapTablet] - Gap size for tablet. Wins over `gapSizeTablet` if both are set.
* @property {BulmaGapValue} [gapDesktop] - Gap size for desktop. Wins over `gapSizeDesktop` if both are set.
* @property {BulmaGapValue} [gapWidescreen] - Gap size for widescreen. Wins over `gapSizeWidescreen` if both are set.
* @property {BulmaGapValue} [gapFullhd] - Gap size for fullhd. Wins over `gapSizeFullhd` if both are set.
* @property {BulmaGapSize} [gapSize] - Gap size for all breakpoints. @deprecated Use `gap` instead.
* @property {BulmaGapSize} [gapSizeMobile] - Gap size for mobile. @deprecated Use `gapMobile` instead.
* @property {BulmaGapSize} [gapSizeTablet] - Gap size for tablet. @deprecated Use `gapTablet` instead.
* @property {BulmaGapSize} [gapSizeDesktop] - Gap size for desktop. @deprecated Use `gapDesktop` instead.
* @property {BulmaGapSize} [gapSizeWidescreen] - Gap size for widescreen. @deprecated Use `gapWidescreen` instead.
* @property {BulmaGapSize} [gapSizeFullhd] - Gap size for fullhd. @deprecated Use `gapFullhd` instead.
* @property {React.ReactNode} [children] - Columns to render within the container.
*/
export interface ColumnsProps
Expand All @@ -65,11 +56,24 @@ export interface ColumnsProps
isMobile?: boolean;
isDesktop?: boolean;

gap?: BulmaGapValue;
gapMobile?: BulmaGapValue;
gapTablet?: BulmaGapValue;
gapDesktop?: BulmaGapValue;
gapWidescreen?: BulmaGapValue;
gapFullhd?: BulmaGapValue;

/** @deprecated Use `gap` instead — `gap` wins if both are set. */
gapSize?: BulmaGapSize;
/** @deprecated Use `gapMobile` instead — `gapMobile` wins if both are set. */
gapSizeMobile?: BulmaGapSize;
/** @deprecated Use `gapTablet` instead — `gapTablet` wins if both are set. */
gapSizeTablet?: BulmaGapSize;
/** @deprecated Use `gapDesktop` instead — `gapDesktop` wins if both are set. */
gapSizeDesktop?: BulmaGapSize;
/** @deprecated Use `gapWidescreen` instead — `gapWidescreen` wins if both are set. */
gapSizeWidescreen?: BulmaGapSize;
/** @deprecated Use `gapFullhd` instead — `gapFullhd` wins if both are set. */
gapSizeFullhd?: BulmaGapSize;

children?: React.ReactNode;
Expand All @@ -94,6 +98,12 @@ export const Columns: React.FC<ColumnsProps> = ({
isVCentered,
isMobile,
isDesktop,
gap,
gapMobile,
gapTablet,
gapDesktop,
gapWidescreen,
gapFullhd,
gapSize,
gapSizeMobile,
gapSizeTablet,
Expand All @@ -103,6 +113,13 @@ export const Columns: React.FC<ColumnsProps> = ({
children,
...props
}) => {
const resolvedGap = gap ?? gapSize;
const resolvedGapMobile = gapMobile ?? gapSizeMobile;
const resolvedGapTablet = gapTablet ?? gapSizeTablet;
const resolvedGapDesktop = gapDesktop ?? gapSizeDesktop;
const resolvedGapWidescreen = gapWidescreen ?? gapSizeWidescreen;
const resolvedGapFullhd = gapFullhd ?? gapSizeFullhd;

const { bulmaHelperClasses, rest } = useBulmaClasses({
color: textColor,
backgroundColor: bgColor,
Expand All @@ -113,17 +130,17 @@ export const Columns: React.FC<ColumnsProps> = ({

// Build gap classes with prefixes
const gapClasses = usePrefixedClassNames('', {
[`is-${gapSize}`]: gapSize !== undefined && gapSize !== null,
[`is-${gapSizeMobile}-mobile`]:
gapSizeMobile !== undefined && gapSizeMobile !== null,
[`is-${gapSizeTablet}-tablet`]:
gapSizeTablet !== undefined && gapSizeTablet !== null,
[`is-${gapSizeDesktop}-desktop`]:
gapSizeDesktop !== undefined && gapSizeDesktop !== null,
[`is-${gapSizeWidescreen}-widescreen`]:
gapSizeWidescreen !== undefined && gapSizeWidescreen !== null,
[`is-${gapSizeFullhd}-fullhd`]:
gapSizeFullhd !== undefined && gapSizeFullhd !== null,
[`is-${resolvedGap}`]: resolvedGap !== undefined && resolvedGap !== null,
[`is-${resolvedGapMobile}-mobile`]:
resolvedGapMobile !== undefined && resolvedGapMobile !== null,
[`is-${resolvedGapTablet}-tablet`]:
resolvedGapTablet !== undefined && resolvedGapTablet !== null,
[`is-${resolvedGapDesktop}-desktop`]:
resolvedGapDesktop !== undefined && resolvedGapDesktop !== null,
[`is-${resolvedGapWidescreen}-widescreen`]:
resolvedGapWidescreen !== undefined && resolvedGapWidescreen !== null,
[`is-${resolvedGapFullhd}-fullhd`]:
resolvedGapFullhd !== undefined && resolvedGapFullhd !== null,
'is-centered': !!isCentered,
'is-gapless': !!isGapless,
'is-multiline': !!isMultiline,
Expand Down
82 changes: 82 additions & 0 deletions bulma-ui/src/columns/__tests__/Columns.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,88 @@ describe('Columns', () => {
);
});

it('applies custom gap classes via the preferred gap* props', () => {
const { container } = render(
<Columns
gap={2}
gapMobile={1}
gapTablet={0}
gapDesktop={3}
gapWidescreen={8}
gapFullhd={2}
/>
);
expect(container.firstChild).toHaveClass(
'is-2',
'is-1-mobile',
'is-0-tablet',
'is-3-desktop',
'is-8-widescreen',
'is-2-fullhd'
);
});

it('accepts gap values as strings, matching BulmaGapValue', () => {
const { container } = render(<Columns gap="4" gapMobile="1" />);
expect(container.firstChild).toHaveClass('is-4', 'is-1-mobile');
});

it('prefers gap* props over the deprecated gapSize* props when both are set', () => {
const { container } = render(
<Columns
gap={5}
gapSize={1}
gapMobile={6}
gapSizeMobile={2}
gapTablet={7}
gapSizeTablet={3}
gapDesktop={8}
gapSizeDesktop={4}
gapWidescreen={0}
gapSizeWidescreen={5}
gapFullhd={1}
gapSizeFullhd={6}
/>
);
expect(container.firstChild).toHaveClass(
'is-5',
'is-6-mobile',
'is-7-tablet',
'is-8-desktop',
'is-0-widescreen',
'is-1-fullhd'
);
expect(container.firstChild).not.toHaveClass(
'is-1',
'is-2-mobile',
'is-3-tablet',
'is-4-desktop',
'is-5-widescreen',
'is-6-fullhd'
);
});

it('falls back to the deprecated gapSize* props when gap* is not set', () => {
const { container } = render(
<Columns
gapSize={4}
gapSizeMobile={3}
gapSizeTablet={2}
gapSizeDesktop={1}
gapSizeWidescreen={0}
gapSizeFullhd={4}
/>
);
expect(container.firstChild).toHaveClass(
'is-4',
'is-3-mobile',
'is-2-tablet',
'is-1-desktop',
'is-0-widescreen',
'is-4-fullhd'
);
});

it('applies custom className', () => {
const { container } = render(<Columns className="custom-class" />);
expect(container.firstChild).toHaveClass('custom-class');
Expand Down
23 changes: 21 additions & 2 deletions bulma-ui/src/grid/Grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,28 @@ import {
} from '../helpers/useBulmaClasses';

/**
* Allowed gap values for Bulma grid.
* Allowed gap values for Bulma's 0-8 spacing scale, shared by `Grid` and
* `Columns`. Accepts the value as a number or a numeric string.
*/
export type BulmaGapValue = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export type BulmaGapValue =
| 0
| 1
| 2
| 3
| 4
| 5
| 6
| 7
| 8
| '0'
| '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8';
/**
* Allowed minimum column values for Bulma grid.
*/
Expand Down
Loading
Loading