@scalewing/react 1.4.1 → 1.5.0
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/CHANGELOG.md +24 -0
- package/README.md +14 -1
- package/dist/column-span-classes.d.ts +9 -0
- package/dist/column-span-classes.js +8 -0
- package/dist/components/Box.d.ts +3 -2
- package/dist/components/Box.js +3 -2
- package/dist/components/Grid.js +4 -7
- package/dist/css/css-components.js +2 -0
- package/dist/css/css-grid-span.d.ts +7 -0
- package/dist/css/css-grid-span.js +35 -0
- package/dist/css/stylesheet.js +2 -0
- package/dist/grid-counts.d.ts +3 -0
- package/dist/grid-counts.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/styles.css +37 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @scalewing/react
|
|
2
2
|
|
|
3
|
+
## 1.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7b51094: Add `columnSpan` to `Box` and every component built on it (`Stack`, `Inline`,
|
|
8
|
+
`Card`, `Grid`, …), so a direct child of a `Grid` can cover 1, 2, 3, 4 or 6
|
|
9
|
+
columns (see `docs/requests/teisoro-grid-column-span.md`). Three columns with a
|
|
10
|
+
two-column child give a two-to-one page:
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
<Grid columns={3} columnsBelow={{ md: 1 }} gap={4}>
|
|
14
|
+
<Stack columnSpan={2} gap={4}>
|
|
15
|
+
{form}
|
|
16
|
+
</Stack>
|
|
17
|
+
<Card variant="outlined">{panel}</Card>
|
|
18
|
+
</Grid>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The generated `sw-grid-span-{1,2,3,4,6}` classes are capped at the
|
|
22
|
+
columns the grid has at the current width, so a span never adds an implicit
|
|
23
|
+
column and `columnsBelow` still stacks the page on a phone. A span outside the
|
|
24
|
+
catalog throws a `RangeError`. New exported types: `GridColumnSpan`,
|
|
25
|
+
`ColumnSpanProps`. Additive; no existing class or prop changes.
|
|
26
|
+
|
|
3
27
|
## 1.4.1
|
|
4
28
|
|
|
5
29
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -68,7 +68,20 @@ Import the CSS once at the application entry. Do not copy it into your source tr
|
|
|
68
68
|
|
|
69
69
|
`Text` takes an optional `align` (`start`, `center`, `end`) mapped to generated `sw-text-align-*` classes, for a heading that must stay centered when it wraps.
|
|
70
70
|
|
|
71
|
-
`Grid` places children in one to four equal-width columns with a token `gap` step. `columnsBelow={{ md: 2 }}` drops to fewer columns below the `md` breakpoint so tiles and stat cards stay readable on a phone. It accepts every `Box` prop.
|
|
71
|
+
`Grid` places children in one to four (or six) equal-width columns with a token `gap` step. `columnsBelow={{ md: 2 }}` drops to fewer columns below the `md` breakpoint so tiles and stat cards stay readable on a phone. It accepts every `Box` prop.
|
|
72
|
+
|
|
73
|
+
Every `Box`-based component (`Box`, `Stack`, `Inline`, `Card`, `Grid`, …) takes `columnSpan` (1, 2, 3, 4 or 6) to cover several columns of the `Grid` it sits in directly, through the generated `sw-grid-span-*` classes. A span is capped at the columns the grid has at the current width, so it never adds an implicit column, and `columnsBelow` still decides the phone layout. A form about twice the width of a side panel, stacking below `md`:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<Grid columns={3} columnsBelow={{ md: 1 }} gap={4}>
|
|
77
|
+
<Stack columnSpan={2} gap={4}>
|
|
78
|
+
{form}
|
|
79
|
+
</Stack>
|
|
80
|
+
<Card variant="outlined">{panel}</Card>
|
|
81
|
+
</Grid>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Values outside the catalog throw a `RangeError`. There is no per-breakpoint span and no arbitrary column template.
|
|
72
85
|
|
|
73
86
|
`DenominationGrid` shows integer counts per unit across a fixed set of columns. The `strip` layout is a captioned table: each row has a toned label with an icon slot, muted zero cells, optional signed deltas toned by sign, and an optional consumer-formatted `total` that moves under the label on a phone. The `tiles` layout stacks the column label, the count, and an optional `subtotal` string per column. The primitive does no arithmetic and no currency formatting; tones reuse the Badge vocabulary. Invalid columns, rows, or cells throw.
|
|
74
87
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type GridColumnSpan } from './css/css-grid-span.js';
|
|
2
|
+
export type ColumnSpanProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Columns this box spans when it is a direct child of a `Grid`, capped at
|
|
5
|
+
* the grid's column count at the current width.
|
|
6
|
+
*/
|
|
7
|
+
columnSpan?: GridColumnSpan;
|
|
8
|
+
};
|
|
9
|
+
export declare function columnSpanClassNames({ columnSpan, }: ColumnSpanProps): string[];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { gridSpanClass } from './css/css-grid-span.js';
|
|
2
|
+
import { assertGridCount } from './grid-counts.js';
|
|
3
|
+
export function columnSpanClassNames({ columnSpan, }) {
|
|
4
|
+
if (columnSpan === undefined)
|
|
5
|
+
return [];
|
|
6
|
+
assertGridCount('columnSpan', columnSpan);
|
|
7
|
+
return [gridSpanClass(columnSpan)];
|
|
8
|
+
}
|
package/dist/components/Box.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { type RadiusStep, type SemanticColorKey } from '@scalewing/tokens';
|
|
2
2
|
import { type AnchorHTMLAttributes, type HTMLAttributes } from 'react';
|
|
3
|
+
import { type ColumnSpanProps } from '../column-span-classes.js';
|
|
3
4
|
import { type SpacingProps } from '../spacing-classes.js';
|
|
4
5
|
import { type VisibilityProps } from '../visibility-classes.js';
|
|
5
6
|
export type BoxElement = 'div' | 'section' | 'article' | 'header' | 'footer' | 'main' | 'nav' | 'aside' | 'span' | 'a' | 'label';
|
|
6
|
-
export type BoxProps = SpacingProps & VisibilityProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, 'download' | 'href' | 'rel' | 'target'> & {
|
|
7
|
+
export type BoxProps = SpacingProps & VisibilityProps & ColumnSpanProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, 'download' | 'href' | 'rel' | 'target'> & {
|
|
7
8
|
as?: BoxElement;
|
|
8
9
|
background?: Extract<SemanticColorKey, 'background' | 'surface'>;
|
|
9
10
|
radius?: RadiusStep;
|
|
10
11
|
border?: boolean;
|
|
11
12
|
};
|
|
12
|
-
export declare const Box: import("react").ForwardRefExoticComponent<SpacingProps & VisibilityProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, "download" | "href" | "rel" | "target"> & {
|
|
13
|
+
export declare const Box: import("react").ForwardRefExoticComponent<SpacingProps & VisibilityProps & ColumnSpanProps & HTMLAttributes<HTMLElement> & Pick<AnchorHTMLAttributes<HTMLAnchorElement>, "download" | "href" | "rel" | "target"> & {
|
|
13
14
|
as?: BoxElement;
|
|
14
15
|
background?: Extract<SemanticColorKey, "background" | "surface">;
|
|
15
16
|
radius?: RadiusStep;
|
package/dist/components/Box.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef, } from 'react';
|
|
3
3
|
import { cx } from '../class-names.js';
|
|
4
|
+
import { columnSpanClassNames, } from '../column-span-classes.js';
|
|
4
5
|
import { spacingClassNames } from '../spacing-classes.js';
|
|
5
6
|
import { visibilityClassNames, } from '../visibility-classes.js';
|
|
6
|
-
export const Box = forwardRef(function Box({ as = 'div', background, border, className, hideBelow, hideFrom, padding, paddingBottom, paddingLeft, paddingRight, paddingTop, paddingX, paddingY, radius, style, ...rest }, ref) {
|
|
7
|
+
export const Box = forwardRef(function Box({ as = 'div', background, border, className, columnSpan, hideBelow, hideFrom, padding, paddingBottom, paddingLeft, paddingRight, paddingTop, paddingX, paddingY, radius, style, ...rest }, ref) {
|
|
7
8
|
const Component = as;
|
|
8
9
|
return (_jsx(Component, { ref: ref, className: cx(...spacingClassNames({
|
|
9
10
|
padding,
|
|
@@ -13,7 +14,7 @@ export const Box = forwardRef(function Box({ as = 'div', background, border, cla
|
|
|
13
14
|
paddingTop,
|
|
14
15
|
paddingX,
|
|
15
16
|
paddingY,
|
|
16
|
-
}), ...visibilityClassNames({ hideBelow, hideFrom }), className), style: {
|
|
17
|
+
}), ...visibilityClassNames({ hideBelow, hideFrom }), ...columnSpanClassNames({ columnSpan }), className), style: {
|
|
17
18
|
backgroundColor: background
|
|
18
19
|
? `var(--sw-color-${background})`
|
|
19
20
|
: undefined,
|
package/dist/components/Grid.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { cx } from '../class-names.js';
|
|
3
3
|
import { breakpoints } from '../css/breakpoints.js';
|
|
4
|
-
import {
|
|
4
|
+
import { gridColumnsBelowClass, gridColumnsClass, } from '../css/css-grid.js';
|
|
5
5
|
import { spacingClass } from '../css/spacing-classes.js';
|
|
6
|
+
import { assertGridCount } from '../grid-counts.js';
|
|
6
7
|
import { Box } from './Box.js';
|
|
7
|
-
function assertColumns(columns) {
|
|
8
|
-
if (!gridColumnCounts.includes(columns))
|
|
9
|
-
throw new RangeError(`columns must be one of ${gridColumnCounts.join(', ')}`);
|
|
10
|
-
}
|
|
11
8
|
export function Grid({ className, columns = 1, columnsBelow, gap = 0, ...rest }) {
|
|
12
|
-
|
|
9
|
+
assertGridCount('columns', columns);
|
|
13
10
|
const belowClasses = breakpoints.flatMap((breakpoint) => {
|
|
14
11
|
const count = columnsBelow?.[breakpoint];
|
|
15
12
|
if (count === undefined)
|
|
16
13
|
return [];
|
|
17
|
-
|
|
14
|
+
assertGridCount('columnsBelow', count);
|
|
18
15
|
return [gridColumnsBelowClass(breakpoint, count)];
|
|
19
16
|
});
|
|
20
17
|
return (_jsx(Box, { className: cx('sw-grid', gridColumnsClass(columns), ...belowClasses, spacingClass('gap', 'all', gap), className), ...rest }));
|
|
@@ -22,6 +22,7 @@ import { cssTabsClasses } from './css-tabs.js';
|
|
|
22
22
|
import { cssResponsiveClasses } from './css-responsive.js';
|
|
23
23
|
import { cssFilterChipsClasses } from './css-filter-chips.js';
|
|
24
24
|
import { cssGridClasses } from './css-grid.js';
|
|
25
|
+
import { cssGridSpanClasses } from './css-grid-span.js';
|
|
25
26
|
import { cssDenominationGridClasses } from './css-denomination-grid.js';
|
|
26
27
|
import { cssFieldClasses } from './css-field.js';
|
|
27
28
|
import { cssToastClasses } from './css-toast.js';
|
|
@@ -149,6 +150,7 @@ ${cssTabsClasses()}
|
|
|
149
150
|
${cssFilterChipsClasses()}
|
|
150
151
|
|
|
151
152
|
${cssGridClasses()}
|
|
153
|
+
${cssGridSpanClasses()}
|
|
152
154
|
${cssDenominationGridClasses()}
|
|
153
155
|
|
|
154
156
|
${cssFieldClasses()}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type GridColumns } from './css-grid.js';
|
|
2
|
+
/** A child spans one of the same bounded counts a `Grid` can have. */
|
|
3
|
+
export type GridColumnSpan = GridColumns;
|
|
4
|
+
export declare const gridColumnSpans: readonly [1, 2, 3, 4, 6];
|
|
5
|
+
export declare function gridSpanClass(span: GridColumnSpan): string;
|
|
6
|
+
export declare function cssGridSpanClasses(): string;
|
|
7
|
+
export declare function gridSpanClassCatalog(): string[];
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { breakpointQuery, breakpoints } from './breakpoints.js';
|
|
2
|
+
import { gridColumnCounts, gridColumnsBelowClass, gridColumnsClass, } from './css-grid.js';
|
|
3
|
+
export const gridColumnSpans = gridColumnCounts;
|
|
4
|
+
export function gridSpanClass(span) {
|
|
5
|
+
return `sw-grid-span-${span}`;
|
|
6
|
+
}
|
|
7
|
+
function spanRule(selector, span) {
|
|
8
|
+
return `${selector} { grid-column: span ${span}; }`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Caps a span at the columns its grid has at the current width, so a wide
|
|
12
|
+
* child never adds an implicit column. `:where()` keeps the cap at one class
|
|
13
|
+
* of specificity; source order lets it override the plain span rule.
|
|
14
|
+
*/
|
|
15
|
+
function capRule(gridClass, columns, span) {
|
|
16
|
+
return spanRule(`:where(.${gridClass}) > .${gridSpanClass(span)}`, Math.min(span, columns));
|
|
17
|
+
}
|
|
18
|
+
function widerSpans(columns) {
|
|
19
|
+
return gridColumnSpans.filter((span) => span > columns);
|
|
20
|
+
}
|
|
21
|
+
export function cssGridSpanClasses() {
|
|
22
|
+
const spans = gridColumnSpans.map((span) => spanRule(`.${gridSpanClass(span)}`, span));
|
|
23
|
+
const caps = gridColumnCounts.flatMap((columns) => widerSpans(columns).map((span) => capRule(gridColumnsClass(columns), columns, span)));
|
|
24
|
+
// Below a breakpoint every span wider than one is restated for the phone
|
|
25
|
+
// column count, which also undoes a desktop cap when that count is larger.
|
|
26
|
+
const below = breakpoints.map((breakpoint) => `@media ${breakpointQuery('below', breakpoint)} {
|
|
27
|
+
${gridColumnCounts
|
|
28
|
+
.flatMap((columns) => widerSpans(1).map((span) => ` ${capRule(gridColumnsBelowClass(breakpoint, columns), columns, span)}`))
|
|
29
|
+
.join('\n')}
|
|
30
|
+
}`);
|
|
31
|
+
return [...spans, ...caps, ...below].join('\n');
|
|
32
|
+
}
|
|
33
|
+
export function gridSpanClassCatalog() {
|
|
34
|
+
return gridColumnSpans.map((span) => gridSpanClass(span));
|
|
35
|
+
}
|
package/dist/css/stylesheet.js
CHANGED
|
@@ -14,6 +14,7 @@ import { tabsClassCatalog } from './css-tabs.js';
|
|
|
14
14
|
import { responsiveClassCatalog } from './css-responsive.js';
|
|
15
15
|
import { filterChipsClassCatalog } from './css-filter-chips.js';
|
|
16
16
|
import { gridClassCatalog } from './css-grid.js';
|
|
17
|
+
import { gridSpanClassCatalog } from './css-grid-span.js';
|
|
17
18
|
import { denominationGridClassCatalog } from './css-denomination-grid.js';
|
|
18
19
|
import { fieldClassCatalog } from './css-field.js';
|
|
19
20
|
import { cssComponentClasses } from './css-components.js';
|
|
@@ -63,6 +64,7 @@ export function utilityClassCatalog() {
|
|
|
63
64
|
...tabsClassCatalog(),
|
|
64
65
|
...filterChipsClassCatalog(),
|
|
65
66
|
...gridClassCatalog(),
|
|
67
|
+
...gridSpanClassCatalog(),
|
|
66
68
|
...denominationGridClassCatalog(),
|
|
67
69
|
...fieldClassCatalog(),
|
|
68
70
|
...splitClassCatalog(),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { gridColumnCounts } from './css/css-grid.js';
|
|
2
|
+
/** Fails closed on a column count or span outside the bounded catalog. */
|
|
3
|
+
export function assertGridCount(prop, value) {
|
|
4
|
+
if (!gridColumnCounts.includes(value))
|
|
5
|
+
throw new RangeError(`${prop} must be one of ${gridColumnCounts.join(', ')}`);
|
|
6
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -38,6 +38,8 @@ export { Separator } from './components/Separator.js';
|
|
|
38
38
|
export type { SeparatorOrientation, SeparatorProps, } from './components/Separator.js';
|
|
39
39
|
export { Grid } from './components/Grid.js';
|
|
40
40
|
export type { GridColumns, GridProps } from './components/Grid.js';
|
|
41
|
+
export type { GridColumnSpan } from './css/css-grid-span.js';
|
|
42
|
+
export type { ColumnSpanProps } from './column-span-classes.js';
|
|
41
43
|
export { DenominationGrid } from './components/DenominationGrid.js';
|
|
42
44
|
export type { DenominationGridColumn, DenominationGridLayout, DenominationGridProps, DenominationGridRow, DenominationGridTone, } from './components/DenominationGrid.js';
|
|
43
45
|
export { FilterChips } from './components/FilterChips.js';
|
package/dist/styles.css
CHANGED
|
@@ -2166,6 +2166,43 @@ body {
|
|
|
2166
2166
|
.sw-grid-cols-below-md-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
|
2167
2167
|
.sw-grid-cols-below-md-6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
|
|
2168
2168
|
}
|
|
2169
|
+
.sw-grid-span-1 { grid-column: span 1; }
|
|
2170
|
+
.sw-grid-span-2 { grid-column: span 2; }
|
|
2171
|
+
.sw-grid-span-3 { grid-column: span 3; }
|
|
2172
|
+
.sw-grid-span-4 { grid-column: span 4; }
|
|
2173
|
+
.sw-grid-span-6 { grid-column: span 6; }
|
|
2174
|
+
:where(.sw-grid-cols-1) > .sw-grid-span-2 { grid-column: span 1; }
|
|
2175
|
+
:where(.sw-grid-cols-1) > .sw-grid-span-3 { grid-column: span 1; }
|
|
2176
|
+
:where(.sw-grid-cols-1) > .sw-grid-span-4 { grid-column: span 1; }
|
|
2177
|
+
:where(.sw-grid-cols-1) > .sw-grid-span-6 { grid-column: span 1; }
|
|
2178
|
+
:where(.sw-grid-cols-2) > .sw-grid-span-3 { grid-column: span 2; }
|
|
2179
|
+
:where(.sw-grid-cols-2) > .sw-grid-span-4 { grid-column: span 2; }
|
|
2180
|
+
:where(.sw-grid-cols-2) > .sw-grid-span-6 { grid-column: span 2; }
|
|
2181
|
+
:where(.sw-grid-cols-3) > .sw-grid-span-4 { grid-column: span 3; }
|
|
2182
|
+
:where(.sw-grid-cols-3) > .sw-grid-span-6 { grid-column: span 3; }
|
|
2183
|
+
:where(.sw-grid-cols-4) > .sw-grid-span-6 { grid-column: span 4; }
|
|
2184
|
+
@media not all and (min-width: 48rem) {
|
|
2185
|
+
:where(.sw-grid-cols-below-md-1) > .sw-grid-span-2 { grid-column: span 1; }
|
|
2186
|
+
:where(.sw-grid-cols-below-md-1) > .sw-grid-span-3 { grid-column: span 1; }
|
|
2187
|
+
:where(.sw-grid-cols-below-md-1) > .sw-grid-span-4 { grid-column: span 1; }
|
|
2188
|
+
:where(.sw-grid-cols-below-md-1) > .sw-grid-span-6 { grid-column: span 1; }
|
|
2189
|
+
:where(.sw-grid-cols-below-md-2) > .sw-grid-span-2 { grid-column: span 2; }
|
|
2190
|
+
:where(.sw-grid-cols-below-md-2) > .sw-grid-span-3 { grid-column: span 2; }
|
|
2191
|
+
:where(.sw-grid-cols-below-md-2) > .sw-grid-span-4 { grid-column: span 2; }
|
|
2192
|
+
:where(.sw-grid-cols-below-md-2) > .sw-grid-span-6 { grid-column: span 2; }
|
|
2193
|
+
:where(.sw-grid-cols-below-md-3) > .sw-grid-span-2 { grid-column: span 2; }
|
|
2194
|
+
:where(.sw-grid-cols-below-md-3) > .sw-grid-span-3 { grid-column: span 3; }
|
|
2195
|
+
:where(.sw-grid-cols-below-md-3) > .sw-grid-span-4 { grid-column: span 3; }
|
|
2196
|
+
:where(.sw-grid-cols-below-md-3) > .sw-grid-span-6 { grid-column: span 3; }
|
|
2197
|
+
:where(.sw-grid-cols-below-md-4) > .sw-grid-span-2 { grid-column: span 2; }
|
|
2198
|
+
:where(.sw-grid-cols-below-md-4) > .sw-grid-span-3 { grid-column: span 3; }
|
|
2199
|
+
:where(.sw-grid-cols-below-md-4) > .sw-grid-span-4 { grid-column: span 4; }
|
|
2200
|
+
:where(.sw-grid-cols-below-md-4) > .sw-grid-span-6 { grid-column: span 4; }
|
|
2201
|
+
:where(.sw-grid-cols-below-md-6) > .sw-grid-span-2 { grid-column: span 2; }
|
|
2202
|
+
:where(.sw-grid-cols-below-md-6) > .sw-grid-span-3 { grid-column: span 3; }
|
|
2203
|
+
:where(.sw-grid-cols-below-md-6) > .sw-grid-span-4 { grid-column: span 4; }
|
|
2204
|
+
:where(.sw-grid-cols-below-md-6) > .sw-grid-span-6 { grid-column: span 6; }
|
|
2205
|
+
}
|
|
2169
2206
|
.sw-denomination-grid {
|
|
2170
2207
|
color: var(--sw-color-text);
|
|
2171
2208
|
font-family: var(--sw-font-sans);
|