@spark-web/row 1.0.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 ADDED
@@ -0,0 +1,18 @@
1
+ # @spark-web/row
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#27](https://github.com/brighte-labs/spark-web/pull/27)
8
+ [`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)
9
+ Thanks [@JedWatson](https://github.com/JedWatson)! - Initial Version
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ [[`4c8e398`](https://github.com/brighte-labs/spark-web/commit/4c8e3988f8a59d3dab60a6b67b1128b6ff2a5f2c)]:
15
+ - @spark-web/box@1.0.0
16
+ - @spark-web/divider@1.0.0
17
+ - @spark-web/theme@1.0.0
18
+ - @spark-web/utils@1.0.0
package/README.md ADDED
@@ -0,0 +1,130 @@
1
+ ---
2
+ title: Row
3
+ storybookPath: page-layout-row--default
4
+ ---
5
+
6
+ Used to distribute children horizontally, with even spacing between each child.
7
+
8
+ ```jsx live
9
+ <Row gap="large">
10
+ <Placeholder />
11
+ <Placeholder />
12
+ <Placeholder />
13
+ </Row>
14
+ ```
15
+
16
+ ## Examples
17
+
18
+ ### Gap
19
+
20
+ The spacing between children can be adjusted using the `gap` prop.
21
+
22
+ ```jsx live
23
+ <Inline gap="xxlarge">
24
+ <Row gap="small">
25
+ <Placeholder />
26
+ <Placeholder />
27
+ <Placeholder />
28
+ </Row>
29
+ <Row gap="medium">
30
+ <Placeholder />
31
+ <Placeholder />
32
+ <Placeholder />
33
+ </Row>
34
+ <Row gap="large">
35
+ <Placeholder />
36
+ <Placeholder />
37
+ <Placeholder />
38
+ </Row>
39
+ <Row gap="xlarge">
40
+ <Placeholder />
41
+ <Placeholder />
42
+ <Placeholder />
43
+ </Row>
44
+ </Inline>
45
+ ```
46
+
47
+ ### Vertical alignment
48
+
49
+ Items can be aligned vertically using the `alignY` prop.
50
+
51
+ ```jsx live
52
+ <Stack gap="medium" align="center" dividers>
53
+ <Row gap="small" alignY="top">
54
+ <Placeholder />
55
+ <Placeholder label="top" height={64} width={128} />
56
+ <Placeholder />
57
+ </Row>
58
+ <Row gap="small" alignY="center">
59
+ <Placeholder />
60
+ <Placeholder label="center" height={64} width={128} />
61
+ <Placeholder />
62
+ </Row>
63
+ <Row gap="small" alignY="bottom">
64
+ <Placeholder />
65
+ <Placeholder label="bottom" height={64} width={128} />
66
+ <Placeholder />
67
+ </Row>
68
+ <Row gap="small" alignY="stretch">
69
+ <Placeholder />
70
+ <Placeholder label="stretch" height={64} width={128} />
71
+ <Placeholder />
72
+ </Row>
73
+ </Stack>
74
+ ```
75
+
76
+ ### Horizontal alignment
77
+
78
+ Items can be aligned horizontally using the `align` prop.
79
+
80
+ ```jsx live
81
+ <Stack gap="medium" dividers>
82
+ <Row gap="small" align="left">
83
+ <Placeholder label="left" width={128} />
84
+ <Placeholder />
85
+ <Placeholder />
86
+ </Row>
87
+ <Row gap="small" align="center">
88
+ <Placeholder />
89
+ <Placeholder label="center" width={128} />
90
+ <Placeholder />
91
+ </Row>
92
+ <Row gap="small" align="right">
93
+ <Placeholder />
94
+ <Placeholder />
95
+ <Placeholder label="right" width={128} />
96
+ </Row>
97
+ </Stack>
98
+ ```
99
+
100
+ ### Dividers
101
+
102
+ Use the `dividers` property to render a [Divider](/package/divider) between each
103
+ element in the Row.
104
+
105
+ ```jsx live
106
+ <Row gap="medium" dividers>
107
+ <Text>First item</Text>
108
+ <Text>Second item</Text>
109
+ <Text>Third item</Text>
110
+ </Row>
111
+ ```
112
+
113
+ ## Props
114
+
115
+ | Prop | Type | Default | Description |
116
+ | --------- | ---------------------------------- | --------- | ----------------------------------------------------- |
117
+ | align? | [ResponsiveProp<Align\>][align] | 'left' | Horizontally align items within the container. |
118
+ | alignY? | [ResponsiveProp<AlignY\>][align-y] | 'stretch' | Vertically align items within the container. |
119
+ | dividers? | boolean | | Sets whether to place a divider between each element. |
120
+
121
+ `Row` props also include [`Box`](/package/box) props and are not listed here
122
+ (excludes `display`, `alignItems`, `flexDirection`, `justifyContent` and
123
+ `flexWrap`).
124
+
125
+ Extra props are also passed into the underlying [`Box`](/package/box) component.
126
+
127
+ [align]:
128
+ https://bitbucket.org/brighte-energy/energy/src/537c678a81090af545969504776c6b3d2e67743e/spark-web/packages/inline/src/Inline.tsx#spark-web/packages/inline/src/Inline.tsx-20
129
+ [align-y]:
130
+ https://bitbucket.org/brighte-energy/energy/src/537c678a81090af545969504776c6b3d2e67743e/spark-web/packages/inline/src/Inline.tsx#spark-web/packages/inline/src/Inline.tsx-22
@@ -0,0 +1,25 @@
1
+ import type { BoxProps } from '@spark-web/box';
2
+ import type { ResponsiveProp } from '@spark-web/theme';
3
+ import type { ReactElement } from 'react';
4
+ import type { Align, AlignY } from './alignment';
5
+ declare type ValidBoxProps = Omit<BoxProps, 'display' | 'alignItems' | 'flexDirection' | 'justifyContent' | 'flexWrap'>;
6
+ export declare type RowProps = {
7
+ /** Horizontally align items within the container. */
8
+ align?: ResponsiveProp<Align>;
9
+ /** Vertically align items within the container. */
10
+ alignY?: ResponsiveProp<AlignY>;
11
+ /** Place a divider between each element. */
12
+ dividers?: boolean;
13
+ } & ValidBoxProps;
14
+ export declare const Row: <Comp extends import("react").ElementType<any> = "div">(props: {
15
+ as?: Comp | undefined;
16
+ ref?: import("react").Ref<Comp extends "symbol" | "clipPath" | "filter" | "mask" | "marker" | "text" | "circle" | "svg" | "animate" | "animateMotion" | "animateTransform" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view" | keyof HTMLElementTagNameMap | "set" ? (HTMLElementTagNameMap & Pick<SVGElementTagNameMap, "symbol" | "clipPath" | "filter" | "mask" | "marker" | "text" | "circle" | "svg" | "animate" | "animateMotion" | "animateTransform" | "defs" | "desc" | "ellipse" | "feBlend" | "feColorMatrix" | "feComponentTransfer" | "feComposite" | "feConvolveMatrix" | "feDiffuseLighting" | "feDisplacementMap" | "feDistantLight" | "feDropShadow" | "feFlood" | "feFuncA" | "feFuncB" | "feFuncG" | "feFuncR" | "feGaussianBlur" | "feImage" | "feMerge" | "feMergeNode" | "feMorphology" | "feOffset" | "fePointLight" | "feSpecularLighting" | "feSpotLight" | "feTile" | "feTurbulence" | "foreignObject" | "g" | "image" | "line" | "linearGradient" | "metadata" | "mpath" | "path" | "pattern" | "polygon" | "polyline" | "radialGradient" | "rect" | "stop" | "switch" | "textPath" | "tspan" | "use" | "view" | "set">)[Comp] : Comp extends new (...args: any) => any ? InstanceType<Comp> : undefined> | undefined;
17
+ } & Omit<import("react").PropsWithoutRef<import("react").ComponentProps<Comp>>, "as"> & {
18
+ /** Horizontally align items within the container. */
19
+ align?: ResponsiveProp<"left" | "right" | "center"> | undefined;
20
+ /** Vertically align items within the container. */
21
+ alignY?: ResponsiveProp<"bottom" | "top" | "stretch" | "center"> | undefined;
22
+ /** Place a divider between each element. */
23
+ dividers?: boolean | undefined;
24
+ } & ValidBoxProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;
25
+ export {};
@@ -0,0 +1,26 @@
1
+ declare const alignLookup: {
2
+ readonly left: "start";
3
+ readonly center: "center";
4
+ readonly right: "end";
5
+ };
6
+ declare const alignYLookup: {
7
+ readonly top: "start";
8
+ readonly center: "center";
9
+ readonly bottom: "end";
10
+ readonly stretch: "stretch";
11
+ };
12
+ export declare type Align = keyof typeof alignLookup;
13
+ export declare type AlignY = keyof typeof alignYLookup;
14
+ export declare const alignToJustifyContent: (prop?: import("@spark-web/theme").ResponsiveProp<"left" | "right" | "center"> | undefined) => "center" | "end" | "start" | {
15
+ mobile: "center" | "end" | "start" | undefined;
16
+ tablet: "center" | "end" | "start" | undefined;
17
+ desktop: "center" | "end" | "start" | undefined;
18
+ wide: "center" | "end" | "start" | undefined;
19
+ } | undefined;
20
+ export declare const alignYToAlignItems: (prop?: import("@spark-web/theme").ResponsiveProp<"bottom" | "top" | "stretch" | "center"> | undefined) => "stretch" | "center" | "end" | "start" | {
21
+ mobile: "stretch" | "center" | "end" | "start" | undefined;
22
+ tablet: "stretch" | "center" | "end" | "start" | undefined;
23
+ desktop: "stretch" | "center" | "end" | "start" | undefined;
24
+ wide: "stretch" | "center" | "end" | "start" | undefined;
25
+ } | undefined;
26
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Row } from './Row';
2
+ export type { RowProps } from './Row';
@@ -0,0 +1 @@
1
+ export * from "./declarations/src/index";
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _defineProperty = require('@babel/runtime/helpers/esm/defineProperty');
6
+ var _objectWithoutProperties = require('@babel/runtime/helpers/esm/objectWithoutProperties');
7
+ var React = require('react');
8
+ var box = require('@spark-web/box');
9
+ var divider = require('@spark-web/divider');
10
+ var ts = require('@spark-web/utils/ts');
11
+ var theme = require('@spark-web/theme');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
14
+
15
+ var React__default = /*#__PURE__*/_interopDefault(React);
16
+
17
+ var alignLookup = {
18
+ left: 'start',
19
+ center: 'center',
20
+ right: 'end'
21
+ };
22
+ var alignYLookup = {
23
+ top: 'start',
24
+ center: 'center',
25
+ bottom: 'end',
26
+ stretch: 'stretch'
27
+ };
28
+ var alignToJustifyContent = theme.createResponsiveMapFn(alignLookup);
29
+ var alignYToAlignItems = theme.createResponsiveMapFn(alignYLookup);
30
+
31
+ var _excluded = ["align", "alignY", "children", "dividers"];
32
+ var __jsx = React__default["default"].createElement;
33
+
34
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
35
+
36
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
37
+ var Row = ts.forwardRefWithAs(function (_ref, forwardedRef) {
38
+ var _ref$align = _ref.align,
39
+ align = _ref$align === void 0 ? 'left' : _ref$align,
40
+ _ref$alignY = _ref.alignY,
41
+ alignY = _ref$alignY === void 0 ? 'stretch' : _ref$alignY,
42
+ children = _ref.children,
43
+ dividers = _ref.dividers,
44
+ props = _objectWithoutProperties(_ref, _excluded);
45
+
46
+ var justifyContent = alignToJustifyContent(align);
47
+ var alignItems = alignYToAlignItems(alignY);
48
+
49
+ var rootProps = _objectSpread({
50
+ ref: forwardedRef,
51
+ display: 'flex',
52
+ alignItems: alignItems,
53
+ justifyContent: justifyContent
54
+ }, props); // bail early w/o dividers to avoid unnecessary map
55
+
56
+
57
+ if (!dividers) {
58
+ return __jsx(box.Box, rootProps, children);
59
+ } // map over children to insert dividers
60
+ // remove falsy values before mapping, keeps the index in sync
61
+
62
+
63
+ var childArray = React.Children.toArray(children);
64
+ return __jsx(box.Box, rootProps, childArray.map(function (child, idx) {
65
+ return __jsx(React.Fragment, {
66
+ key: child.key || idx
67
+ }, dividers && idx ? __jsx(divider.Divider, {
68
+ vertical: true
69
+ }) : null, child);
70
+ }));
71
+ });
72
+
73
+ exports.Row = Row;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./spark-web-row.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./spark-web-row.cjs.dev.js");
7
+ }
@@ -0,0 +1,73 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var _defineProperty = require('@babel/runtime/helpers/esm/defineProperty');
6
+ var _objectWithoutProperties = require('@babel/runtime/helpers/esm/objectWithoutProperties');
7
+ var React = require('react');
8
+ var box = require('@spark-web/box');
9
+ var divider = require('@spark-web/divider');
10
+ var ts = require('@spark-web/utils/ts');
11
+ var theme = require('@spark-web/theme');
12
+
13
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
14
+
15
+ var React__default = /*#__PURE__*/_interopDefault(React);
16
+
17
+ var alignLookup = {
18
+ left: 'start',
19
+ center: 'center',
20
+ right: 'end'
21
+ };
22
+ var alignYLookup = {
23
+ top: 'start',
24
+ center: 'center',
25
+ bottom: 'end',
26
+ stretch: 'stretch'
27
+ };
28
+ var alignToJustifyContent = theme.createResponsiveMapFn(alignLookup);
29
+ var alignYToAlignItems = theme.createResponsiveMapFn(alignYLookup);
30
+
31
+ var _excluded = ["align", "alignY", "children", "dividers"];
32
+ var __jsx = React__default["default"].createElement;
33
+
34
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
35
+
36
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
37
+ var Row = ts.forwardRefWithAs(function (_ref, forwardedRef) {
38
+ var _ref$align = _ref.align,
39
+ align = _ref$align === void 0 ? 'left' : _ref$align,
40
+ _ref$alignY = _ref.alignY,
41
+ alignY = _ref$alignY === void 0 ? 'stretch' : _ref$alignY,
42
+ children = _ref.children,
43
+ dividers = _ref.dividers,
44
+ props = _objectWithoutProperties(_ref, _excluded);
45
+
46
+ var justifyContent = alignToJustifyContent(align);
47
+ var alignItems = alignYToAlignItems(alignY);
48
+
49
+ var rootProps = _objectSpread({
50
+ ref: forwardedRef,
51
+ display: 'flex',
52
+ alignItems: alignItems,
53
+ justifyContent: justifyContent
54
+ }, props); // bail early w/o dividers to avoid unnecessary map
55
+
56
+
57
+ if (!dividers) {
58
+ return __jsx(box.Box, rootProps, children);
59
+ } // map over children to insert dividers
60
+ // remove falsy values before mapping, keeps the index in sync
61
+
62
+
63
+ var childArray = React.Children.toArray(children);
64
+ return __jsx(box.Box, rootProps, childArray.map(function (child, idx) {
65
+ return __jsx(React.Fragment, {
66
+ key: child.key || idx
67
+ }, dividers && idx ? __jsx(divider.Divider, {
68
+ vertical: true
69
+ }) : null, child);
70
+ }));
71
+ });
72
+
73
+ exports.Row = Row;
@@ -0,0 +1,65 @@
1
+ import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
2
+ import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
3
+ import React, { Children, Fragment } from 'react';
4
+ import { Box } from '@spark-web/box';
5
+ import { Divider } from '@spark-web/divider';
6
+ import { forwardRefWithAs } from '@spark-web/utils/ts';
7
+ import { createResponsiveMapFn } from '@spark-web/theme';
8
+
9
+ var alignLookup = {
10
+ left: 'start',
11
+ center: 'center',
12
+ right: 'end'
13
+ };
14
+ var alignYLookup = {
15
+ top: 'start',
16
+ center: 'center',
17
+ bottom: 'end',
18
+ stretch: 'stretch'
19
+ };
20
+ var alignToJustifyContent = createResponsiveMapFn(alignLookup);
21
+ var alignYToAlignItems = createResponsiveMapFn(alignYLookup);
22
+
23
+ var _excluded = ["align", "alignY", "children", "dividers"];
24
+ var __jsx = React.createElement;
25
+
26
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
27
+
28
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
29
+ var Row = forwardRefWithAs(function (_ref, forwardedRef) {
30
+ var _ref$align = _ref.align,
31
+ align = _ref$align === void 0 ? 'left' : _ref$align,
32
+ _ref$alignY = _ref.alignY,
33
+ alignY = _ref$alignY === void 0 ? 'stretch' : _ref$alignY,
34
+ children = _ref.children,
35
+ dividers = _ref.dividers,
36
+ props = _objectWithoutProperties(_ref, _excluded);
37
+
38
+ var justifyContent = alignToJustifyContent(align);
39
+ var alignItems = alignYToAlignItems(alignY);
40
+
41
+ var rootProps = _objectSpread({
42
+ ref: forwardedRef,
43
+ display: 'flex',
44
+ alignItems: alignItems,
45
+ justifyContent: justifyContent
46
+ }, props); // bail early w/o dividers to avoid unnecessary map
47
+
48
+
49
+ if (!dividers) {
50
+ return __jsx(Box, rootProps, children);
51
+ } // map over children to insert dividers
52
+ // remove falsy values before mapping, keeps the index in sync
53
+
54
+
55
+ var childArray = Children.toArray(children);
56
+ return __jsx(Box, rootProps, childArray.map(function (child, idx) {
57
+ return __jsx(Fragment, {
58
+ key: child.key || idx
59
+ }, dividers && idx ? __jsx(Divider, {
60
+ vertical: true
61
+ }) : null, child);
62
+ }));
63
+ });
64
+
65
+ export { Row };
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@spark-web/row",
3
+ "license": "MIT",
4
+ "version": "1.0.0",
5
+ "main": "dist/spark-web-row.cjs.js",
6
+ "module": "dist/spark-web-row.esm.js",
7
+ "devDependencies": {
8
+ "@types/react": "^17.0.12"
9
+ },
10
+ "dependencies": {
11
+ "@babel/runtime": "^7.14.6",
12
+ "@emotion/css": "^11.7.1",
13
+ "@spark-web/box": "^1.0.0",
14
+ "@spark-web/divider": "^1.0.0",
15
+ "@spark-web/theme": "^1.0.0",
16
+ "@spark-web/utils": "^1.0.0",
17
+ "react": "^17.0.2"
18
+ },
19
+ "engines": {
20
+ "node": ">= 14.13"
21
+ }
22
+ }
@@ -0,0 +1,27 @@
1
+ import type { ComponentMeta, ComponentStory } from '@storybook/react';
2
+
3
+ import { Placeholder } from '../../../docs/components/example-helpers';
4
+ import type { RowProps } from './Row';
5
+ import { Row } from './Row';
6
+
7
+ export default {
8
+ title: 'Page & Layout / Row',
9
+ component: Row,
10
+ } as ComponentMeta<typeof Row>;
11
+
12
+ const RowStory: ComponentStory<typeof Row> = (
13
+ args: Omit<RowProps, 'className'>
14
+ ) => <Row {...args} />;
15
+
16
+ export const Default = RowStory.bind({});
17
+
18
+ Default.args = {
19
+ gap: 'large',
20
+ children: (
21
+ <>
22
+ <Placeholder height={40} />
23
+ <Placeholder height={40} />
24
+ <Placeholder height={40} />
25
+ </>
26
+ ),
27
+ } as RowProps;
package/src/Row.tsx ADDED
@@ -0,0 +1,60 @@
1
+ import type { BoxProps } from '@spark-web/box';
2
+ import { Box } from '@spark-web/box';
3
+ import { Divider } from '@spark-web/divider';
4
+ import type { ResponsiveProp } from '@spark-web/theme';
5
+ import { forwardRefWithAs } from '@spark-web/utils/ts';
6
+ import type { ReactElement } from 'react';
7
+ import { Children, Fragment } from 'react';
8
+
9
+ import type { Align, AlignY } from './alignment';
10
+ import { alignToJustifyContent, alignYToAlignItems } from './alignment';
11
+
12
+ type ValidBoxProps = Omit<
13
+ BoxProps,
14
+ 'display' | 'alignItems' | 'flexDirection' | 'justifyContent' | 'flexWrap'
15
+ >;
16
+
17
+ export type RowProps = {
18
+ /** Horizontally align items within the container. */
19
+ align?: ResponsiveProp<Align>;
20
+ /** Vertically align items within the container. */
21
+ alignY?: ResponsiveProp<AlignY>;
22
+ /** Place a divider between each element. */
23
+ dividers?: boolean;
24
+ } & ValidBoxProps;
25
+
26
+ export const Row = forwardRefWithAs<'div', RowProps>(
27
+ (
28
+ { align = 'left', alignY = 'stretch', children, dividers, ...props },
29
+ forwardedRef
30
+ ) => {
31
+ const justifyContent = alignToJustifyContent(align);
32
+ const alignItems = alignYToAlignItems(alignY);
33
+ const rootProps = {
34
+ ref: forwardedRef,
35
+ display: 'flex',
36
+ alignItems,
37
+ justifyContent,
38
+ ...props,
39
+ } as const;
40
+
41
+ // bail early w/o dividers to avoid unnecessary map
42
+ if (!dividers) {
43
+ return <Box {...rootProps}>{children}</Box>;
44
+ }
45
+
46
+ // map over children to insert dividers
47
+ // remove falsy values before mapping, keeps the index in sync
48
+ const childArray = Children.toArray(children) as ReactElement[];
49
+ return (
50
+ <Box {...rootProps}>
51
+ {childArray.map((child, idx) => (
52
+ <Fragment key={child.key || idx}>
53
+ {dividers && idx ? <Divider vertical /> : null}
54
+ {child}
55
+ </Fragment>
56
+ ))}
57
+ </Box>
58
+ );
59
+ }
60
+ );
@@ -0,0 +1,15 @@
1
+ import { createResponsiveMapFn } from '@spark-web/theme';
2
+
3
+ const alignLookup = { left: 'start', center: 'center', right: 'end' } as const;
4
+ const alignYLookup = {
5
+ top: 'start',
6
+ center: 'center',
7
+ bottom: 'end',
8
+ stretch: 'stretch',
9
+ } as const;
10
+
11
+ export type Align = keyof typeof alignLookup;
12
+ export type AlignY = keyof typeof alignYLookup;
13
+
14
+ export const alignToJustifyContent = createResponsiveMapFn(alignLookup);
15
+ export const alignYToAlignItems = createResponsiveMapFn(alignYLookup);
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { Row } from './Row';
2
+
3
+ // types
4
+
5
+ export type { RowProps } from './Row';