@spark-web/stack 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/stack
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,118 @@
1
+ ---
2
+ title: Stack
3
+ storybookPath: page-layout-stack--default
4
+ ---
5
+
6
+ Used to distribute children vertically, with even spacing between each child.
7
+
8
+ ```jsx live
9
+ <Stack gap="large">
10
+ <Placeholder />
11
+ <Placeholder />
12
+ <Placeholder />
13
+ </Stack>
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
+ <Columns gap="xxlarge">
24
+ <Stack gap="small">
25
+ <Placeholder />
26
+ <Placeholder />
27
+ <Placeholder />
28
+ </Stack>
29
+ <Stack gap="medium">
30
+ <Placeholder />
31
+ <Placeholder />
32
+ <Placeholder />
33
+ </Stack>
34
+ <Stack gap="large">
35
+ <Placeholder />
36
+ <Placeholder />
37
+ <Placeholder />
38
+ </Stack>
39
+ <Stack gap="xlarge">
40
+ <Placeholder />
41
+ <Placeholder />
42
+ <Placeholder />
43
+ </Stack>
44
+ </Columns>
45
+ ```
46
+
47
+ ### Horizontal alignment
48
+
49
+ Items can be aligned horizontally using the `align` prop.
50
+
51
+ ```jsx live
52
+ <Stack gap="medium" dividers>
53
+ <Stack gap="small" align="left">
54
+ <Placeholder />
55
+ <Placeholder label="left" width={128} />
56
+ <Placeholder />
57
+ </Stack>
58
+ <Stack gap="small" align="center">
59
+ <Placeholder />
60
+ <Placeholder label="center" width={128} />
61
+ <Placeholder />
62
+ </Stack>
63
+ <Stack gap="small" align="right">
64
+ <Placeholder />
65
+ <Placeholder label="right" width={128} />
66
+ <Placeholder />
67
+ </Stack>
68
+ </Stack>
69
+ ```
70
+
71
+ ### Dividers
72
+
73
+ Use the `dividers` property to render a [Divider](/package/divider) between each
74
+ element in the Stack.
75
+
76
+ ```jsx live
77
+ <Stack gap="medium" dividers>
78
+ <Text>First item</Text>
79
+ <Text>Second item</Text>
80
+ <Text>Third item</Text>
81
+ </Stack>
82
+ ```
83
+
84
+ ### Nesting
85
+
86
+ Nest Stack components to create more complex white space rules.
87
+
88
+ ```jsx live
89
+ <Stack gap="xlarge">
90
+ <Heading level="4">Heading</Heading>
91
+ <Stack gap="small">
92
+ <Text>Line 1</Text>
93
+ <Text>Line 2</Text>
94
+ <Text>Line 3</Text>
95
+ </Stack>
96
+ <Stack gap="small">
97
+ <Text>Line 1</Text>
98
+ <Text>Line 2</Text>
99
+ <Text>Line 3</Text>
100
+ </Stack>
101
+ </Stack>
102
+ ```
103
+
104
+ ## Props
105
+
106
+ | Prop | Type | Default | Description |
107
+ | --------- | ------------------------------- | --------- | ----------------------------------------------------- |
108
+ | align? | [ResponsiveProp<Align\>][align] | 'stretch' | Horizontally align items within the container. |
109
+ | dividers? | boolean | | Sets whether to place a divider between each element. |
110
+
111
+ `Stack` props also include [`Box`](/package/box) props and are not listed here
112
+ (excludes `display`, `className`, `alignItems`, `flexDirection`,
113
+ `justifyContent` and `flexWrap`).
114
+
115
+ Extra props are also passed into the underlying [`Box`](/package/box) component.
116
+
117
+ [align]:
118
+ https://bitbucket.org/brighte-energy/energy/src/537c678a81090af545969504776c6b3d2e67743e/spark-web/packages/stack/src/Stack.tsx#spark-web/packages/stack/src/Stack.tsx-21
@@ -0,0 +1,21 @@
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 } from './alignment';
5
+ declare type ValidBoxProps = Omit<BoxProps, 'display' | 'className' | 'alignItems' | 'flexDirection' | 'justifyContent' | 'flexWrap'>;
6
+ export declare type StackProps = {
7
+ /** Horizontally align items within the stack. */
8
+ align?: ResponsiveProp<Align>;
9
+ /** Place a divider between each element. */
10
+ dividers?: boolean;
11
+ } & ValidBoxProps;
12
+ export declare const Stack: <Comp extends import("react").ElementType<any> = "div">(props: {
13
+ as?: Comp | undefined;
14
+ 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;
15
+ } & Omit<import("react").PropsWithoutRef<import("react").ComponentProps<Comp>>, "as"> & {
16
+ /** Horizontally align items within the stack. */
17
+ align?: ResponsiveProp<"left" | "right" | "stretch" | "center"> | undefined;
18
+ /** Place a divider between each element. */
19
+ dividers?: boolean | undefined;
20
+ } & ValidBoxProps) => ReactElement<any, string | import("react").JSXElementConstructor<any>>;
21
+ export {};
@@ -0,0 +1,14 @@
1
+ declare const alignLookup: {
2
+ readonly left: "start";
3
+ readonly center: "center";
4
+ readonly right: "end";
5
+ readonly stretch: "stretch";
6
+ };
7
+ export declare type Align = keyof typeof alignLookup;
8
+ export declare const alignToAlignItems: (prop?: import("@spark-web/theme").ResponsiveProp<"left" | "right" | "stretch" | "center"> | undefined) => "stretch" | "center" | "end" | "start" | {
9
+ mobile: "stretch" | "center" | "end" | "start" | undefined;
10
+ tablet: "stretch" | "center" | "end" | "start" | undefined;
11
+ desktop: "stretch" | "center" | "end" | "start" | undefined;
12
+ wide: "stretch" | "center" | "end" | "start" | undefined;
13
+ } | undefined;
14
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Stack } from './Stack';
2
+ export type { StackProps } from './Stack';
@@ -0,0 +1 @@
1
+ export * from "./declarations/src/index";
@@ -0,0 +1,62 @@
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
+ stretch: 'stretch'
22
+ };
23
+ var alignToAlignItems = theme.createResponsiveMapFn(alignLookup);
24
+
25
+ var _excluded = ["align", "children", "dividers"];
26
+ var __jsx = React__default["default"].createElement;
27
+
28
+ 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; }
29
+
30
+ 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; }
31
+ var Stack = ts.forwardRefWithAs(function (_ref, forwardedRef) {
32
+ var _ref$align = _ref.align,
33
+ align = _ref$align === void 0 ? 'stretch' : _ref$align,
34
+ children = _ref.children,
35
+ dividers = _ref.dividers,
36
+ props = _objectWithoutProperties(_ref, _excluded);
37
+
38
+ var alignItems = alignToAlignItems(align);
39
+
40
+ var rootProps = _objectSpread({
41
+ ref: forwardedRef,
42
+ alignItems: alignItems,
43
+ display: 'flex',
44
+ flexDirection: 'column'
45
+ }, props); // bail early w/o dividers to avoid unnecessary map
46
+
47
+
48
+ if (!dividers) {
49
+ return __jsx(box.Box, rootProps, children);
50
+ } // map over children to insert dividers
51
+ // remove falsy values before mapping, keeps the index in sync
52
+
53
+
54
+ var childArray = React.Children.toArray(children);
55
+ return __jsx(box.Box, rootProps, childArray.map(function (child, idx) {
56
+ return __jsx(React.Fragment, {
57
+ key: child.key || idx
58
+ }, dividers && idx ? __jsx(divider.Divider, null) : null, child);
59
+ }));
60
+ });
61
+
62
+ exports.Stack = Stack;
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./spark-web-stack.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./spark-web-stack.cjs.dev.js");
7
+ }
@@ -0,0 +1,62 @@
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
+ stretch: 'stretch'
22
+ };
23
+ var alignToAlignItems = theme.createResponsiveMapFn(alignLookup);
24
+
25
+ var _excluded = ["align", "children", "dividers"];
26
+ var __jsx = React__default["default"].createElement;
27
+
28
+ 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; }
29
+
30
+ 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; }
31
+ var Stack = ts.forwardRefWithAs(function (_ref, forwardedRef) {
32
+ var _ref$align = _ref.align,
33
+ align = _ref$align === void 0 ? 'stretch' : _ref$align,
34
+ children = _ref.children,
35
+ dividers = _ref.dividers,
36
+ props = _objectWithoutProperties(_ref, _excluded);
37
+
38
+ var alignItems = alignToAlignItems(align);
39
+
40
+ var rootProps = _objectSpread({
41
+ ref: forwardedRef,
42
+ alignItems: alignItems,
43
+ display: 'flex',
44
+ flexDirection: 'column'
45
+ }, props); // bail early w/o dividers to avoid unnecessary map
46
+
47
+
48
+ if (!dividers) {
49
+ return __jsx(box.Box, rootProps, children);
50
+ } // map over children to insert dividers
51
+ // remove falsy values before mapping, keeps the index in sync
52
+
53
+
54
+ var childArray = React.Children.toArray(children);
55
+ return __jsx(box.Box, rootProps, childArray.map(function (child, idx) {
56
+ return __jsx(React.Fragment, {
57
+ key: child.key || idx
58
+ }, dividers && idx ? __jsx(divider.Divider, null) : null, child);
59
+ }));
60
+ });
61
+
62
+ exports.Stack = Stack;
@@ -0,0 +1,54 @@
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
+ stretch: 'stretch'
14
+ };
15
+ var alignToAlignItems = createResponsiveMapFn(alignLookup);
16
+
17
+ var _excluded = ["align", "children", "dividers"];
18
+ var __jsx = React.createElement;
19
+
20
+ 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; }
21
+
22
+ 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; }
23
+ var Stack = forwardRefWithAs(function (_ref, forwardedRef) {
24
+ var _ref$align = _ref.align,
25
+ align = _ref$align === void 0 ? 'stretch' : _ref$align,
26
+ children = _ref.children,
27
+ dividers = _ref.dividers,
28
+ props = _objectWithoutProperties(_ref, _excluded);
29
+
30
+ var alignItems = alignToAlignItems(align);
31
+
32
+ var rootProps = _objectSpread({
33
+ ref: forwardedRef,
34
+ alignItems: alignItems,
35
+ display: 'flex',
36
+ flexDirection: 'column'
37
+ }, props); // bail early w/o dividers to avoid unnecessary map
38
+
39
+
40
+ if (!dividers) {
41
+ return __jsx(Box, rootProps, children);
42
+ } // map over children to insert dividers
43
+ // remove falsy values before mapping, keeps the index in sync
44
+
45
+
46
+ var childArray = Children.toArray(children);
47
+ return __jsx(Box, rootProps, childArray.map(function (child, idx) {
48
+ return __jsx(Fragment, {
49
+ key: child.key || idx
50
+ }, dividers && idx ? __jsx(Divider, null) : null, child);
51
+ }));
52
+ });
53
+
54
+ export { Stack };
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@spark-web/stack",
3
+ "license": "MIT",
4
+ "version": "1.0.0",
5
+ "main": "dist/spark-web-stack.cjs.js",
6
+ "module": "dist/spark-web-stack.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 { StackProps } from './Stack';
5
+ import { Stack } from './Stack';
6
+
7
+ export default {
8
+ title: 'Page & Layout / Stack',
9
+ component: Stack,
10
+ } as ComponentMeta<typeof Stack>;
11
+
12
+ const StackStory: ComponentStory<typeof Stack> = (args: StackProps) => (
13
+ <Stack {...args} />
14
+ );
15
+
16
+ export const Default = StackStory.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 StackProps;
package/src/Stack.tsx ADDED
@@ -0,0 +1,59 @@
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 } from './alignment';
10
+ import { alignToAlignItems } from './alignment';
11
+
12
+ type ValidBoxProps = Omit<
13
+ BoxProps,
14
+ | 'display'
15
+ | 'className'
16
+ | 'alignItems'
17
+ | 'flexDirection'
18
+ | 'justifyContent'
19
+ | 'flexWrap'
20
+ >;
21
+
22
+ export type StackProps = {
23
+ /** Horizontally align items within the stack. */
24
+ align?: ResponsiveProp<Align>;
25
+ /** Place a divider between each element. */
26
+ dividers?: boolean;
27
+ } & ValidBoxProps;
28
+
29
+ export const Stack = forwardRefWithAs<'div', StackProps>(
30
+ ({ align = 'stretch', children, dividers, ...props }, forwardedRef) => {
31
+ const alignItems = alignToAlignItems(align);
32
+ const rootProps = {
33
+ ref: forwardedRef,
34
+ alignItems,
35
+ display: 'flex',
36
+ flexDirection: 'column',
37
+ ...props,
38
+ } as const;
39
+
40
+ // bail early w/o dividers to avoid unnecessary map
41
+ if (!dividers) {
42
+ return <Box {...rootProps}>{children}</Box>;
43
+ }
44
+
45
+ // map over children to insert dividers
46
+ // remove falsy values before mapping, keeps the index in sync
47
+ const childArray = Children.toArray(children) as ReactElement[];
48
+ return (
49
+ <Box {...rootProps}>
50
+ {childArray.map((child, idx) => (
51
+ <Fragment key={child.key || idx}>
52
+ {dividers && idx ? <Divider /> : null}
53
+ {child}
54
+ </Fragment>
55
+ ))}
56
+ </Box>
57
+ );
58
+ }
59
+ );
@@ -0,0 +1,12 @@
1
+ import { createResponsiveMapFn } from '@spark-web/theme';
2
+
3
+ const alignLookup = {
4
+ left: 'start',
5
+ center: 'center',
6
+ right: 'end',
7
+ stretch: 'stretch',
8
+ } as const;
9
+
10
+ export type Align = keyof typeof alignLookup;
11
+
12
+ export const alignToAlignItems = createResponsiveMapFn(alignLookup);
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { Stack } from './Stack';
2
+
3
+ // types
4
+
5
+ export type { StackProps } from './Stack';