@sproutsocial/seeds-react-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/.eslintignore +6 -0
- package/.eslintrc.js +4 -0
- package/.turbo/turbo-build.log +21 -0
- package/CHANGELOG.md +7 -0
- package/dist/esm/index.js +140 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +177 -0
- package/dist/index.js.map +1 -0
- package/jest.config.js +9 -0
- package/package.json +44 -0
- package/src/Stack.stories.tsx +102 -0
- package/src/Stack.tsx +116 -0
- package/src/StackTypes.ts +32 -0
- package/src/__tests__/Stack.test.tsx +26 -0
- package/src/__tests__/Stack.typetest.tsx +18 -0
- package/src/index.ts +5 -0
- package/src/styled.d.ts +7 -0
- package/src/utils.ts +42 -0
- package/tsconfig.json +9 -0
- package/tsup.config.ts +12 -0
package/.eslintignore
ADDED
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
yarn run v1.22.22
|
|
2
|
+
$ tsup --dts
|
|
3
|
+
CLI Building entry: src/index.ts
|
|
4
|
+
CLI Using tsconfig: tsconfig.json
|
|
5
|
+
CLI tsup v8.0.2
|
|
6
|
+
CLI Using tsup config: /home/runner/work/seeds/seeds/seeds-react/seeds-react-stack/tsup.config.ts
|
|
7
|
+
CLI Target: es2022
|
|
8
|
+
CLI Cleaning output folder
|
|
9
|
+
CJS Build start
|
|
10
|
+
ESM Build start
|
|
11
|
+
CJS dist/index.js 5.54 KB
|
|
12
|
+
CJS dist/index.js.map 8.36 KB
|
|
13
|
+
CJS ⚡️ Build success in 108ms
|
|
14
|
+
ESM dist/esm/index.js 3.75 KB
|
|
15
|
+
ESM dist/esm/index.js.map 8.25 KB
|
|
16
|
+
ESM ⚡️ Build success in 115ms
|
|
17
|
+
DTS Build start
|
|
18
|
+
DTS ⚡️ Build success in 25718ms
|
|
19
|
+
DTS dist/index.d.ts 1.02 KB
|
|
20
|
+
DTS dist/index.d.mts 1.02 KB
|
|
21
|
+
Done in 34.50s.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// src/Stack.tsx
|
|
2
|
+
import "react";
|
|
3
|
+
import { Children } from "react";
|
|
4
|
+
|
|
5
|
+
// src/utils.ts
|
|
6
|
+
import { theme } from "@sproutsocial/seeds-react-theme";
|
|
7
|
+
var breakpoints = theme.breakpoints;
|
|
8
|
+
var LENGTH = breakpoints.length + 1;
|
|
9
|
+
var normalizeResponsiveProp = (value) => {
|
|
10
|
+
if (["string", "number"].includes(typeof value)) {
|
|
11
|
+
return Array(LENGTH).fill(value);
|
|
12
|
+
}
|
|
13
|
+
if (value.length) {
|
|
14
|
+
switch (value.length) {
|
|
15
|
+
case 1:
|
|
16
|
+
return Array(LENGTH).fill(value[0]);
|
|
17
|
+
case 2:
|
|
18
|
+
return [value[0], ...Array(LENGTH - 1).fill(value[1])];
|
|
19
|
+
case 3:
|
|
20
|
+
return [value[0], value[1], ...Array(LENGTH - 2).fill(value[2])];
|
|
21
|
+
case 4:
|
|
22
|
+
return [
|
|
23
|
+
value[0],
|
|
24
|
+
value[1],
|
|
25
|
+
value[2],
|
|
26
|
+
...Array(LENGTH - 3).fill(value[3])
|
|
27
|
+
];
|
|
28
|
+
case 5:
|
|
29
|
+
return value;
|
|
30
|
+
default:
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Invalid responsive prop length: ${JSON.stringify(value)}`
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
throw new Error(`Invalid responsive prop type: ${JSON.stringify(value)}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/Stack.tsx
|
|
41
|
+
import Box from "@sproutsocial/seeds-react-box";
|
|
42
|
+
import { jsx } from "react/jsx-runtime";
|
|
43
|
+
import { createElement } from "react";
|
|
44
|
+
var stackStyles = {
|
|
45
|
+
horizontal: {
|
|
46
|
+
left: {
|
|
47
|
+
alignItems: "center"
|
|
48
|
+
},
|
|
49
|
+
center: {
|
|
50
|
+
alignItems: "center",
|
|
51
|
+
justifyContent: "center"
|
|
52
|
+
},
|
|
53
|
+
right: {
|
|
54
|
+
alignItems: "center",
|
|
55
|
+
justifyContent: "flex-end"
|
|
56
|
+
},
|
|
57
|
+
stretch: {
|
|
58
|
+
alignItems: "center"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
vertical: {
|
|
62
|
+
left: {
|
|
63
|
+
flexDirection: "column",
|
|
64
|
+
alignItems: "flex-start"
|
|
65
|
+
},
|
|
66
|
+
center: {
|
|
67
|
+
flexDirection: "column",
|
|
68
|
+
alignItems: "center"
|
|
69
|
+
},
|
|
70
|
+
right: {
|
|
71
|
+
flexDirection: "column",
|
|
72
|
+
alignItems: "flex-end"
|
|
73
|
+
},
|
|
74
|
+
stretch: {
|
|
75
|
+
flexDirection: "column",
|
|
76
|
+
alignItems: "stretch"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var Stack = ({
|
|
81
|
+
children,
|
|
82
|
+
space = 300,
|
|
83
|
+
align = "left",
|
|
84
|
+
direction = "vertical",
|
|
85
|
+
...rest
|
|
86
|
+
}) => {
|
|
87
|
+
const stackItems = Children.toArray(children);
|
|
88
|
+
const responsiveAlignment = normalizeResponsiveProp(align);
|
|
89
|
+
const responsiveDirection = normalizeResponsiveProp(direction);
|
|
90
|
+
const responsiveSpace = normalizeResponsiveProp(space);
|
|
91
|
+
const initialValue = ["initial", "initial", "initial", "initial", "initial"];
|
|
92
|
+
const styleProps = {
|
|
93
|
+
alignItems: [...initialValue],
|
|
94
|
+
flexDirection: [...initialValue],
|
|
95
|
+
justifyContent: [...initialValue]
|
|
96
|
+
};
|
|
97
|
+
const childFlexBasis = [...initialValue];
|
|
98
|
+
const childMarginProps = {
|
|
99
|
+
marginLeft: [...initialValue],
|
|
100
|
+
marginTop: [...initialValue]
|
|
101
|
+
};
|
|
102
|
+
initialValue.forEach((_, i) => {
|
|
103
|
+
const currentDirection = responsiveDirection[i];
|
|
104
|
+
const currentAlignment = responsiveAlignment[i];
|
|
105
|
+
const currentSpace = responsiveSpace[i];
|
|
106
|
+
if (currentDirection && currentAlignment) {
|
|
107
|
+
const styles = stackStyles[currentDirection][currentAlignment];
|
|
108
|
+
Object.keys(styleProps).forEach((key) => {
|
|
109
|
+
styleProps[key][i] = styles[key] || "initial";
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const flexBasis = currentAlignment === "stretch" && currentDirection === "horizontal" ? "100%" : null;
|
|
113
|
+
childFlexBasis[i] = flexBasis;
|
|
114
|
+
const margin = currentDirection === "horizontal" ? "marginLeft" : "marginTop";
|
|
115
|
+
const opposite = currentDirection === "horizontal" ? "marginTop" : "marginLeft";
|
|
116
|
+
childMarginProps[margin][i] = currentSpace;
|
|
117
|
+
childMarginProps[opposite][i] = 0;
|
|
118
|
+
});
|
|
119
|
+
return /* @__PURE__ */ jsx(Box, { display: "flex", ...styleProps, ...rest, children: stackItems.map((item, i) => /* @__PURE__ */ createElement(
|
|
120
|
+
Box,
|
|
121
|
+
{
|
|
122
|
+
flexBasis: childFlexBasis,
|
|
123
|
+
...i !== 0 ? childMarginProps : {},
|
|
124
|
+
key: i
|
|
125
|
+
},
|
|
126
|
+
item
|
|
127
|
+
)) });
|
|
128
|
+
};
|
|
129
|
+
var Stack_default = Stack;
|
|
130
|
+
|
|
131
|
+
// src/StackTypes.ts
|
|
132
|
+
import "react";
|
|
133
|
+
|
|
134
|
+
// src/index.ts
|
|
135
|
+
var src_default = Stack_default;
|
|
136
|
+
export {
|
|
137
|
+
Stack_default as Stack,
|
|
138
|
+
src_default as default
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/Stack.tsx","../../src/utils.ts","../../src/StackTypes.ts","../../src/index.ts"],"sourcesContent":["import * as React from \"react\";\nimport { Children } from \"react\";\nimport { normalizeResponsiveProp } from \"./utils\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeStackProps } from \"./StackTypes\";\n\nconst stackStyles = {\n horizontal: {\n left: {\n alignItems: \"center\",\n },\n center: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n right: {\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n },\n stretch: {\n alignItems: \"center\",\n },\n },\n vertical: {\n left: {\n flexDirection: \"column\",\n alignItems: \"flex-start\",\n },\n center: {\n flexDirection: \"column\",\n alignItems: \"center\",\n },\n right: {\n flexDirection: \"column\",\n alignItems: \"flex-end\",\n },\n stretch: {\n flexDirection: \"column\",\n alignItems: \"stretch\",\n },\n },\n};\n\nconst Stack = ({\n children,\n space = 300,\n align = \"left\",\n direction = \"vertical\",\n ...rest\n}: TypeStackProps) => {\n const stackItems = Children.toArray(children);\n const responsiveAlignment = normalizeResponsiveProp(align);\n const responsiveDirection = normalizeResponsiveProp(direction);\n const responsiveSpace = normalizeResponsiveProp(space);\n const initialValue = [\"initial\", \"initial\", \"initial\", \"initial\", \"initial\"];\n\n // TODO: rely on styled system to solve this during the refactor\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const styleProps: any = {\n alignItems: [...initialValue],\n flexDirection: [...initialValue],\n justifyContent: [...initialValue],\n };\n const childFlexBasis: (string | null)[] = [...initialValue];\n const childMarginProps = {\n marginLeft: [...initialValue],\n marginTop: [...initialValue],\n };\n\n initialValue.forEach((_, i) => {\n const currentDirection = responsiveDirection[i] as keyof typeof stackStyles;\n const currentAlignment = responsiveAlignment[\n i\n ] as keyof (typeof stackStyles)[\"horizontal\"];\n const currentSpace = responsiveSpace[i];\n\n if (currentDirection && currentAlignment) {\n const styles: { [key: string]: string } =\n stackStyles[currentDirection][currentAlignment];\n Object.keys(styleProps).forEach((key: string) => {\n styleProps[key][i] = styles[key] || \"initial\";\n });\n }\n\n const flexBasis =\n currentAlignment === \"stretch\" && currentDirection === \"horizontal\"\n ? \"100%\"\n : null;\n childFlexBasis[i] = flexBasis;\n\n const margin =\n currentDirection === \"horizontal\" ? \"marginLeft\" : \"marginTop\";\n\n const opposite =\n currentDirection === \"horizontal\" ? \"marginTop\" : \"marginLeft\";\n childMarginProps[margin][i] = currentSpace;\n // styled system can pass numbers that map to theme values and TS doesn't like it\n childMarginProps[opposite][i] = 0 as unknown as string;\n });\n\n return (\n <Box display=\"flex\" {...styleProps} {...rest}>\n {stackItems.map((item, i) => (\n <Box\n flexBasis={childFlexBasis}\n {...(i !== 0 ? childMarginProps : {})}\n key={i}\n >\n {item}\n </Box>\n ))}\n </Box>\n );\n};\n\nexport default Stack;\n","import { theme } from \"@sproutsocial/seeds-react-theme\";\n\nimport type { TypeResponsive } from \"@sproutsocial/seeds-react-system-props\";\n\nconst breakpoints = theme.breakpoints;\nconst LENGTH = breakpoints.length + 1;\n\nexport const normalizeResponsiveProp = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: TypeResponsive<any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): TypeResponsive<any> => {\n if ([\"string\", \"number\"].includes(typeof value)) {\n return Array(LENGTH).fill(value);\n }\n\n if (value.length) {\n switch (value.length) {\n case 1:\n return Array(LENGTH).fill(value[0]);\n case 2:\n return [value[0], ...Array(LENGTH - 1).fill(value[1])];\n case 3:\n return [value[0], value[1], ...Array(LENGTH - 2).fill(value[2])];\n case 4:\n return [\n value[0],\n value[1],\n value[2],\n ...Array(LENGTH - 3).fill(value[3]),\n ];\n case 5:\n return value;\n default:\n throw new Error(\n `Invalid responsive prop length: ${JSON.stringify(value)}`\n );\n }\n } else {\n throw new Error(`Invalid responsive prop type: ${JSON.stringify(value)}`);\n }\n};\n","import * as React from \"react\";\n\nimport type { TypeResponsive } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport type TypeSpaceLiterals =\n | 0\n | 100\n | 200\n | 300\n | 350\n | 400\n | 450\n | 500\n | 600\n | string;\n\ntype TypeDirection = \"vertical\" | \"horizontal\";\n\ntype TypeAlignment = \"left\" | \"center\" | \"right\" | \"stretch\";\n\nexport interface TypeStackProps extends TypeBoxProps {\n /** Amount of space between items in the stack */\n space?: TypeResponsive<TypeSpaceLiterals>;\n\n /** Alignment of the items in the stack (horizontal or vertical) */\n align?: TypeResponsive<TypeAlignment>;\n\n /** Axis upon which the stack is laid out (left, center, right, or stretch) */\n direction?: TypeResponsive<TypeDirection>;\n children: React.ReactNode;\n}\n","import Stack from \"./Stack\";\n\nexport default Stack;\nexport { Stack };\nexport * from \"./StackTypes\";\n"],"mappings":"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","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { TypeResponsive } from '@sproutsocial/seeds-react-system-props';
|
|
4
|
+
import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
|
|
5
|
+
|
|
6
|
+
type TypeSpaceLiterals = 0 | 100 | 200 | 300 | 350 | 400 | 450 | 500 | 600 | string;
|
|
7
|
+
type TypeDirection = "vertical" | "horizontal";
|
|
8
|
+
type TypeAlignment = "left" | "center" | "right" | "stretch";
|
|
9
|
+
interface TypeStackProps extends TypeBoxProps {
|
|
10
|
+
/** Amount of space between items in the stack */
|
|
11
|
+
space?: TypeResponsive<TypeSpaceLiterals>;
|
|
12
|
+
/** Alignment of the items in the stack (horizontal or vertical) */
|
|
13
|
+
align?: TypeResponsive<TypeAlignment>;
|
|
14
|
+
/** Axis upon which the stack is laid out (left, center, right, or stretch) */
|
|
15
|
+
direction?: TypeResponsive<TypeDirection>;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare const Stack: ({ children, space, align, direction, ...rest }: TypeStackProps) => react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
export { Stack, type TypeSpaceLiterals, type TypeStackProps, Stack as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { TypeResponsive } from '@sproutsocial/seeds-react-system-props';
|
|
4
|
+
import { TypeBoxProps } from '@sproutsocial/seeds-react-box';
|
|
5
|
+
|
|
6
|
+
type TypeSpaceLiterals = 0 | 100 | 200 | 300 | 350 | 400 | 450 | 500 | 600 | string;
|
|
7
|
+
type TypeDirection = "vertical" | "horizontal";
|
|
8
|
+
type TypeAlignment = "left" | "center" | "right" | "stretch";
|
|
9
|
+
interface TypeStackProps extends TypeBoxProps {
|
|
10
|
+
/** Amount of space between items in the stack */
|
|
11
|
+
space?: TypeResponsive<TypeSpaceLiterals>;
|
|
12
|
+
/** Alignment of the items in the stack (horizontal or vertical) */
|
|
13
|
+
align?: TypeResponsive<TypeAlignment>;
|
|
14
|
+
/** Axis upon which the stack is laid out (left, center, right, or stretch) */
|
|
15
|
+
direction?: TypeResponsive<TypeDirection>;
|
|
16
|
+
children: React.ReactNode;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare const Stack: ({ children, space, align, direction, ...rest }: TypeStackProps) => react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
export { Stack, type TypeSpaceLiterals, type TypeStackProps, Stack as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var src_exports = {};
|
|
32
|
+
__export(src_exports, {
|
|
33
|
+
Stack: () => Stack_default,
|
|
34
|
+
default: () => src_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(src_exports);
|
|
37
|
+
|
|
38
|
+
// src/Stack.tsx
|
|
39
|
+
var React = require("react");
|
|
40
|
+
var import_react = require("react");
|
|
41
|
+
|
|
42
|
+
// src/utils.ts
|
|
43
|
+
var import_seeds_react_theme = require("@sproutsocial/seeds-react-theme");
|
|
44
|
+
var breakpoints = import_seeds_react_theme.theme.breakpoints;
|
|
45
|
+
var LENGTH = breakpoints.length + 1;
|
|
46
|
+
var normalizeResponsiveProp = (value) => {
|
|
47
|
+
if (["string", "number"].includes(typeof value)) {
|
|
48
|
+
return Array(LENGTH).fill(value);
|
|
49
|
+
}
|
|
50
|
+
if (value.length) {
|
|
51
|
+
switch (value.length) {
|
|
52
|
+
case 1:
|
|
53
|
+
return Array(LENGTH).fill(value[0]);
|
|
54
|
+
case 2:
|
|
55
|
+
return [value[0], ...Array(LENGTH - 1).fill(value[1])];
|
|
56
|
+
case 3:
|
|
57
|
+
return [value[0], value[1], ...Array(LENGTH - 2).fill(value[2])];
|
|
58
|
+
case 4:
|
|
59
|
+
return [
|
|
60
|
+
value[0],
|
|
61
|
+
value[1],
|
|
62
|
+
value[2],
|
|
63
|
+
...Array(LENGTH - 3).fill(value[3])
|
|
64
|
+
];
|
|
65
|
+
case 5:
|
|
66
|
+
return value;
|
|
67
|
+
default:
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Invalid responsive prop length: ${JSON.stringify(value)}`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
throw new Error(`Invalid responsive prop type: ${JSON.stringify(value)}`);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// src/Stack.tsx
|
|
78
|
+
var import_seeds_react_box = __toESM(require("@sproutsocial/seeds-react-box"));
|
|
79
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
80
|
+
var import_react2 = require("react");
|
|
81
|
+
var stackStyles = {
|
|
82
|
+
horizontal: {
|
|
83
|
+
left: {
|
|
84
|
+
alignItems: "center"
|
|
85
|
+
},
|
|
86
|
+
center: {
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
justifyContent: "center"
|
|
89
|
+
},
|
|
90
|
+
right: {
|
|
91
|
+
alignItems: "center",
|
|
92
|
+
justifyContent: "flex-end"
|
|
93
|
+
},
|
|
94
|
+
stretch: {
|
|
95
|
+
alignItems: "center"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
vertical: {
|
|
99
|
+
left: {
|
|
100
|
+
flexDirection: "column",
|
|
101
|
+
alignItems: "flex-start"
|
|
102
|
+
},
|
|
103
|
+
center: {
|
|
104
|
+
flexDirection: "column",
|
|
105
|
+
alignItems: "center"
|
|
106
|
+
},
|
|
107
|
+
right: {
|
|
108
|
+
flexDirection: "column",
|
|
109
|
+
alignItems: "flex-end"
|
|
110
|
+
},
|
|
111
|
+
stretch: {
|
|
112
|
+
flexDirection: "column",
|
|
113
|
+
alignItems: "stretch"
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
var Stack = ({
|
|
118
|
+
children,
|
|
119
|
+
space = 300,
|
|
120
|
+
align = "left",
|
|
121
|
+
direction = "vertical",
|
|
122
|
+
...rest
|
|
123
|
+
}) => {
|
|
124
|
+
const stackItems = import_react.Children.toArray(children);
|
|
125
|
+
const responsiveAlignment = normalizeResponsiveProp(align);
|
|
126
|
+
const responsiveDirection = normalizeResponsiveProp(direction);
|
|
127
|
+
const responsiveSpace = normalizeResponsiveProp(space);
|
|
128
|
+
const initialValue = ["initial", "initial", "initial", "initial", "initial"];
|
|
129
|
+
const styleProps = {
|
|
130
|
+
alignItems: [...initialValue],
|
|
131
|
+
flexDirection: [...initialValue],
|
|
132
|
+
justifyContent: [...initialValue]
|
|
133
|
+
};
|
|
134
|
+
const childFlexBasis = [...initialValue];
|
|
135
|
+
const childMarginProps = {
|
|
136
|
+
marginLeft: [...initialValue],
|
|
137
|
+
marginTop: [...initialValue]
|
|
138
|
+
};
|
|
139
|
+
initialValue.forEach((_, i) => {
|
|
140
|
+
const currentDirection = responsiveDirection[i];
|
|
141
|
+
const currentAlignment = responsiveAlignment[i];
|
|
142
|
+
const currentSpace = responsiveSpace[i];
|
|
143
|
+
if (currentDirection && currentAlignment) {
|
|
144
|
+
const styles = stackStyles[currentDirection][currentAlignment];
|
|
145
|
+
Object.keys(styleProps).forEach((key) => {
|
|
146
|
+
styleProps[key][i] = styles[key] || "initial";
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const flexBasis = currentAlignment === "stretch" && currentDirection === "horizontal" ? "100%" : null;
|
|
150
|
+
childFlexBasis[i] = flexBasis;
|
|
151
|
+
const margin = currentDirection === "horizontal" ? "marginLeft" : "marginTop";
|
|
152
|
+
const opposite = currentDirection === "horizontal" ? "marginTop" : "marginLeft";
|
|
153
|
+
childMarginProps[margin][i] = currentSpace;
|
|
154
|
+
childMarginProps[opposite][i] = 0;
|
|
155
|
+
});
|
|
156
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_seeds_react_box.default, { display: "flex", ...styleProps, ...rest, children: stackItems.map((item, i) => /* @__PURE__ */ (0, import_react2.createElement)(
|
|
157
|
+
import_seeds_react_box.default,
|
|
158
|
+
{
|
|
159
|
+
flexBasis: childFlexBasis,
|
|
160
|
+
...i !== 0 ? childMarginProps : {},
|
|
161
|
+
key: i
|
|
162
|
+
},
|
|
163
|
+
item
|
|
164
|
+
)) });
|
|
165
|
+
};
|
|
166
|
+
var Stack_default = Stack;
|
|
167
|
+
|
|
168
|
+
// src/StackTypes.ts
|
|
169
|
+
var React2 = require("react");
|
|
170
|
+
|
|
171
|
+
// src/index.ts
|
|
172
|
+
var src_default = Stack_default;
|
|
173
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
174
|
+
0 && (module.exports = {
|
|
175
|
+
Stack
|
|
176
|
+
});
|
|
177
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Stack.tsx","../src/utils.ts","../src/StackTypes.ts"],"sourcesContent":["import Stack from \"./Stack\";\n\nexport default Stack;\nexport { Stack };\nexport * from \"./StackTypes\";\n","import * as React from \"react\";\nimport { Children } from \"react\";\nimport { normalizeResponsiveProp } from \"./utils\";\nimport Box from \"@sproutsocial/seeds-react-box\";\nimport type { TypeStackProps } from \"./StackTypes\";\n\nconst stackStyles = {\n horizontal: {\n left: {\n alignItems: \"center\",\n },\n center: {\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n right: {\n alignItems: \"center\",\n justifyContent: \"flex-end\",\n },\n stretch: {\n alignItems: \"center\",\n },\n },\n vertical: {\n left: {\n flexDirection: \"column\",\n alignItems: \"flex-start\",\n },\n center: {\n flexDirection: \"column\",\n alignItems: \"center\",\n },\n right: {\n flexDirection: \"column\",\n alignItems: \"flex-end\",\n },\n stretch: {\n flexDirection: \"column\",\n alignItems: \"stretch\",\n },\n },\n};\n\nconst Stack = ({\n children,\n space = 300,\n align = \"left\",\n direction = \"vertical\",\n ...rest\n}: TypeStackProps) => {\n const stackItems = Children.toArray(children);\n const responsiveAlignment = normalizeResponsiveProp(align);\n const responsiveDirection = normalizeResponsiveProp(direction);\n const responsiveSpace = normalizeResponsiveProp(space);\n const initialValue = [\"initial\", \"initial\", \"initial\", \"initial\", \"initial\"];\n\n // TODO: rely on styled system to solve this during the refactor\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const styleProps: any = {\n alignItems: [...initialValue],\n flexDirection: [...initialValue],\n justifyContent: [...initialValue],\n };\n const childFlexBasis: (string | null)[] = [...initialValue];\n const childMarginProps = {\n marginLeft: [...initialValue],\n marginTop: [...initialValue],\n };\n\n initialValue.forEach((_, i) => {\n const currentDirection = responsiveDirection[i] as keyof typeof stackStyles;\n const currentAlignment = responsiveAlignment[\n i\n ] as keyof (typeof stackStyles)[\"horizontal\"];\n const currentSpace = responsiveSpace[i];\n\n if (currentDirection && currentAlignment) {\n const styles: { [key: string]: string } =\n stackStyles[currentDirection][currentAlignment];\n Object.keys(styleProps).forEach((key: string) => {\n styleProps[key][i] = styles[key] || \"initial\";\n });\n }\n\n const flexBasis =\n currentAlignment === \"stretch\" && currentDirection === \"horizontal\"\n ? \"100%\"\n : null;\n childFlexBasis[i] = flexBasis;\n\n const margin =\n currentDirection === \"horizontal\" ? \"marginLeft\" : \"marginTop\";\n\n const opposite =\n currentDirection === \"horizontal\" ? \"marginTop\" : \"marginLeft\";\n childMarginProps[margin][i] = currentSpace;\n // styled system can pass numbers that map to theme values and TS doesn't like it\n childMarginProps[opposite][i] = 0 as unknown as string;\n });\n\n return (\n <Box display=\"flex\" {...styleProps} {...rest}>\n {stackItems.map((item, i) => (\n <Box\n flexBasis={childFlexBasis}\n {...(i !== 0 ? childMarginProps : {})}\n key={i}\n >\n {item}\n </Box>\n ))}\n </Box>\n );\n};\n\nexport default Stack;\n","import { theme } from \"@sproutsocial/seeds-react-theme\";\n\nimport type { TypeResponsive } from \"@sproutsocial/seeds-react-system-props\";\n\nconst breakpoints = theme.breakpoints;\nconst LENGTH = breakpoints.length + 1;\n\nexport const normalizeResponsiveProp = (\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n value: TypeResponsive<any>\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): TypeResponsive<any> => {\n if ([\"string\", \"number\"].includes(typeof value)) {\n return Array(LENGTH).fill(value);\n }\n\n if (value.length) {\n switch (value.length) {\n case 1:\n return Array(LENGTH).fill(value[0]);\n case 2:\n return [value[0], ...Array(LENGTH - 1).fill(value[1])];\n case 3:\n return [value[0], value[1], ...Array(LENGTH - 2).fill(value[2])];\n case 4:\n return [\n value[0],\n value[1],\n value[2],\n ...Array(LENGTH - 3).fill(value[3]),\n ];\n case 5:\n return value;\n default:\n throw new Error(\n `Invalid responsive prop length: ${JSON.stringify(value)}`\n );\n }\n } else {\n throw new Error(`Invalid responsive prop type: ${JSON.stringify(value)}`);\n }\n};\n","import * as React from \"react\";\n\nimport type { TypeResponsive } from \"@sproutsocial/seeds-react-system-props\";\nimport type { TypeBoxProps } from \"@sproutsocial/seeds-react-box\";\n\nexport type TypeSpaceLiterals =\n | 0\n | 100\n | 200\n | 300\n | 350\n | 400\n | 450\n | 500\n | 600\n | string;\n\ntype TypeDirection = \"vertical\" | \"horizontal\";\n\ntype TypeAlignment = \"left\" | \"center\" | \"right\" | \"stretch\";\n\nexport interface TypeStackProps extends TypeBoxProps {\n /** Amount of space between items in the stack */\n space?: TypeResponsive<TypeSpaceLiterals>;\n\n /** Alignment of the items in the stack (horizontal or vertical) */\n align?: TypeResponsive<TypeAlignment>;\n\n /** Axis upon which the stack is laid out (left, center, right, or stretch) */\n direction?: TypeResponsive<TypeDirection>;\n children: React.ReactNode;\n}\n"],"mappings":"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","names":["import_react","Box","React"]}
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sproutsocial/seeds-react-stack",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Seeds React Stack",
|
|
5
|
+
"author": "Sprout Social, Inc.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/esm/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup --dts",
|
|
12
|
+
"build:debug": "tsup --dts --metafile",
|
|
13
|
+
"dev": "tsup --watch --dts",
|
|
14
|
+
"clean": "rm -rf .turbo dist",
|
|
15
|
+
"clean:modules": "rm -rf node_modules",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"test:watch": "jest --watch --coverage=false"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@sproutsocial/seeds-react-theme": "*",
|
|
22
|
+
"@sproutsocial/seeds-react-system-props": "*",
|
|
23
|
+
"@sproutsocial/seeds-react-box": "*"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/react": "^18.0.0",
|
|
27
|
+
"@types/styled-components": "^5.1.26",
|
|
28
|
+
"@sproutsocial/eslint-config-seeds": "*",
|
|
29
|
+
"react": "^18.0.0",
|
|
30
|
+
"styled-components": "^5.2.3",
|
|
31
|
+
"tsup": "^8.0.2",
|
|
32
|
+
"typescript": "^5.6.2",
|
|
33
|
+
"@sproutsocial/seeds-tsconfig": "*",
|
|
34
|
+
"@sproutsocial/seeds-testing": "*",
|
|
35
|
+
"@sproutsocial/seeds-react-testing-library": "*",
|
|
36
|
+
"@sproutsocial/seeds-react-text": "*"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"styled-components": "^5.2.3"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
3
|
+
import Text from "@sproutsocial/seeds-react-text";
|
|
4
|
+
import Stack from "./Stack";
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Stack> = {
|
|
7
|
+
title: "Components/Stack",
|
|
8
|
+
component: Stack,
|
|
9
|
+
argTypes: {
|
|
10
|
+
align: {
|
|
11
|
+
options: ["left", "center", "right", "stretch"],
|
|
12
|
+
control: {
|
|
13
|
+
type: "select",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
direction: {
|
|
17
|
+
options: ["horizontal", "vertical"],
|
|
18
|
+
control: {
|
|
19
|
+
type: "select",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
args: {
|
|
24
|
+
align: undefined,
|
|
25
|
+
direction: undefined,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
export default meta;
|
|
29
|
+
|
|
30
|
+
interface ItemProps {
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const Item: React.FC<ItemProps> = (props) => (
|
|
35
|
+
<Text as="p" color="text.body" {...props} />
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
type Story = StoryObj<typeof Stack>;
|
|
39
|
+
|
|
40
|
+
export const DefaultStory: Story = {
|
|
41
|
+
name: "Default (Vertical)",
|
|
42
|
+
args: {
|
|
43
|
+
// ...existing code...
|
|
44
|
+
},
|
|
45
|
+
render: (args) => (
|
|
46
|
+
<Stack p={400} {...args}>
|
|
47
|
+
<Item>This</Item>
|
|
48
|
+
<Item>is</Item>
|
|
49
|
+
<Item>the</Item>
|
|
50
|
+
<Item>stack</Item>
|
|
51
|
+
<Item>component</Item>
|
|
52
|
+
</Stack>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const ResponsiveDirection: Story = {
|
|
57
|
+
name: "Responsive direction",
|
|
58
|
+
args: {
|
|
59
|
+
direction: ["vertical", "horizontal", "vertical"],
|
|
60
|
+
},
|
|
61
|
+
render: (args) => (
|
|
62
|
+
<Stack p={400} {...args}>
|
|
63
|
+
<Item>Stack</Item>
|
|
64
|
+
<Item>is</Item>
|
|
65
|
+
<Item>a</Item>
|
|
66
|
+
<Item>layout</Item>
|
|
67
|
+
<Item>utility</Item>
|
|
68
|
+
</Stack>
|
|
69
|
+
),
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const ResponsiveAlignment: Story = {
|
|
73
|
+
name: "Responsive alignment",
|
|
74
|
+
args: {
|
|
75
|
+
align: ["left", "center", "stretch"],
|
|
76
|
+
},
|
|
77
|
+
render: (args) => (
|
|
78
|
+
<Stack p={400} {...args}>
|
|
79
|
+
<Item>Stack</Item>
|
|
80
|
+
<Item>is</Item>
|
|
81
|
+
<Item>a</Item>
|
|
82
|
+
<Item>layout</Item>
|
|
83
|
+
<Item>utility</Item>
|
|
84
|
+
</Stack>
|
|
85
|
+
),
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const ResponsiveSpace: Story = {
|
|
89
|
+
name: "Responsive space",
|
|
90
|
+
args: {
|
|
91
|
+
space: [300, 450, 600],
|
|
92
|
+
},
|
|
93
|
+
render: (args) => (
|
|
94
|
+
<Stack p={400} {...args}>
|
|
95
|
+
<Item>Stack</Item>
|
|
96
|
+
<Item>is</Item>
|
|
97
|
+
<Item>a</Item>
|
|
98
|
+
<Item>layout</Item>
|
|
99
|
+
<Item>utility</Item>
|
|
100
|
+
</Stack>
|
|
101
|
+
),
|
|
102
|
+
};
|
package/src/Stack.tsx
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Children } from "react";
|
|
3
|
+
import { normalizeResponsiveProp } from "./utils";
|
|
4
|
+
import Box from "@sproutsocial/seeds-react-box";
|
|
5
|
+
import type { TypeStackProps } from "./StackTypes";
|
|
6
|
+
|
|
7
|
+
const stackStyles = {
|
|
8
|
+
horizontal: {
|
|
9
|
+
left: {
|
|
10
|
+
alignItems: "center",
|
|
11
|
+
},
|
|
12
|
+
center: {
|
|
13
|
+
alignItems: "center",
|
|
14
|
+
justifyContent: "center",
|
|
15
|
+
},
|
|
16
|
+
right: {
|
|
17
|
+
alignItems: "center",
|
|
18
|
+
justifyContent: "flex-end",
|
|
19
|
+
},
|
|
20
|
+
stretch: {
|
|
21
|
+
alignItems: "center",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
vertical: {
|
|
25
|
+
left: {
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
alignItems: "flex-start",
|
|
28
|
+
},
|
|
29
|
+
center: {
|
|
30
|
+
flexDirection: "column",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
},
|
|
33
|
+
right: {
|
|
34
|
+
flexDirection: "column",
|
|
35
|
+
alignItems: "flex-end",
|
|
36
|
+
},
|
|
37
|
+
stretch: {
|
|
38
|
+
flexDirection: "column",
|
|
39
|
+
alignItems: "stretch",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const Stack = ({
|
|
45
|
+
children,
|
|
46
|
+
space = 300,
|
|
47
|
+
align = "left",
|
|
48
|
+
direction = "vertical",
|
|
49
|
+
...rest
|
|
50
|
+
}: TypeStackProps) => {
|
|
51
|
+
const stackItems = Children.toArray(children);
|
|
52
|
+
const responsiveAlignment = normalizeResponsiveProp(align);
|
|
53
|
+
const responsiveDirection = normalizeResponsiveProp(direction);
|
|
54
|
+
const responsiveSpace = normalizeResponsiveProp(space);
|
|
55
|
+
const initialValue = ["initial", "initial", "initial", "initial", "initial"];
|
|
56
|
+
|
|
57
|
+
// TODO: rely on styled system to solve this during the refactor
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
59
|
+
const styleProps: any = {
|
|
60
|
+
alignItems: [...initialValue],
|
|
61
|
+
flexDirection: [...initialValue],
|
|
62
|
+
justifyContent: [...initialValue],
|
|
63
|
+
};
|
|
64
|
+
const childFlexBasis: (string | null)[] = [...initialValue];
|
|
65
|
+
const childMarginProps = {
|
|
66
|
+
marginLeft: [...initialValue],
|
|
67
|
+
marginTop: [...initialValue],
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
initialValue.forEach((_, i) => {
|
|
71
|
+
const currentDirection = responsiveDirection[i] as keyof typeof stackStyles;
|
|
72
|
+
const currentAlignment = responsiveAlignment[
|
|
73
|
+
i
|
|
74
|
+
] as keyof (typeof stackStyles)["horizontal"];
|
|
75
|
+
const currentSpace = responsiveSpace[i];
|
|
76
|
+
|
|
77
|
+
if (currentDirection && currentAlignment) {
|
|
78
|
+
const styles: { [key: string]: string } =
|
|
79
|
+
stackStyles[currentDirection][currentAlignment];
|
|
80
|
+
Object.keys(styleProps).forEach((key: string) => {
|
|
81
|
+
styleProps[key][i] = styles[key] || "initial";
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const flexBasis =
|
|
86
|
+
currentAlignment === "stretch" && currentDirection === "horizontal"
|
|
87
|
+
? "100%"
|
|
88
|
+
: null;
|
|
89
|
+
childFlexBasis[i] = flexBasis;
|
|
90
|
+
|
|
91
|
+
const margin =
|
|
92
|
+
currentDirection === "horizontal" ? "marginLeft" : "marginTop";
|
|
93
|
+
|
|
94
|
+
const opposite =
|
|
95
|
+
currentDirection === "horizontal" ? "marginTop" : "marginLeft";
|
|
96
|
+
childMarginProps[margin][i] = currentSpace;
|
|
97
|
+
// styled system can pass numbers that map to theme values and TS doesn't like it
|
|
98
|
+
childMarginProps[opposite][i] = 0 as unknown as string;
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<Box display="flex" {...styleProps} {...rest}>
|
|
103
|
+
{stackItems.map((item, i) => (
|
|
104
|
+
<Box
|
|
105
|
+
flexBasis={childFlexBasis}
|
|
106
|
+
{...(i !== 0 ? childMarginProps : {})}
|
|
107
|
+
key={i}
|
|
108
|
+
>
|
|
109
|
+
{item}
|
|
110
|
+
</Box>
|
|
111
|
+
))}
|
|
112
|
+
</Box>
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
export default Stack;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import type { TypeResponsive } from "@sproutsocial/seeds-react-system-props";
|
|
4
|
+
import type { TypeBoxProps } from "@sproutsocial/seeds-react-box";
|
|
5
|
+
|
|
6
|
+
export type TypeSpaceLiterals =
|
|
7
|
+
| 0
|
|
8
|
+
| 100
|
|
9
|
+
| 200
|
|
10
|
+
| 300
|
|
11
|
+
| 350
|
|
12
|
+
| 400
|
|
13
|
+
| 450
|
|
14
|
+
| 500
|
|
15
|
+
| 600
|
|
16
|
+
| string;
|
|
17
|
+
|
|
18
|
+
type TypeDirection = "vertical" | "horizontal";
|
|
19
|
+
|
|
20
|
+
type TypeAlignment = "left" | "center" | "right" | "stretch";
|
|
21
|
+
|
|
22
|
+
export interface TypeStackProps extends TypeBoxProps {
|
|
23
|
+
/** Amount of space between items in the stack */
|
|
24
|
+
space?: TypeResponsive<TypeSpaceLiterals>;
|
|
25
|
+
|
|
26
|
+
/** Alignment of the items in the stack (horizontal or vertical) */
|
|
27
|
+
align?: TypeResponsive<TypeAlignment>;
|
|
28
|
+
|
|
29
|
+
/** Axis upon which the stack is laid out (left, center, right, or stretch) */
|
|
30
|
+
direction?: TypeResponsive<TypeDirection>;
|
|
31
|
+
children: React.ReactNode;
|
|
32
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@sproutsocial/seeds-react-testing-library";
|
|
3
|
+
import { Text } from "@sproutsocial/seeds-react-text";
|
|
4
|
+
import Stack from "../Stack";
|
|
5
|
+
|
|
6
|
+
interface ItemProps {
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const Item = (props: ItemProps) => (
|
|
11
|
+
<Text as="div" color="text.body" bg="container.background.base" {...props}>
|
|
12
|
+
{props.children}
|
|
13
|
+
</Text>
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
describe("Stack", () => {
|
|
17
|
+
it("should render properly", async () => {
|
|
18
|
+
const { container, runA11yCheck } = render(
|
|
19
|
+
<Stack>
|
|
20
|
+
<Item>Hello world!</Item>
|
|
21
|
+
</Stack>
|
|
22
|
+
);
|
|
23
|
+
expect(container).toBeTruthy();
|
|
24
|
+
await runA11yCheck();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Box } from "@sproutsocial/seeds-react-box";
|
|
3
|
+
import Stack from "../Stack";
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6
|
+
function StackTypes() {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<Stack space={300} align="center" direction="horizontal">
|
|
10
|
+
<Box>Seeds</Box>
|
|
11
|
+
<Box>Design</Box>
|
|
12
|
+
<Box>System</Box>
|
|
13
|
+
</Stack>
|
|
14
|
+
{/* @ts-expect-error - test that invalid children are rejected */}
|
|
15
|
+
<Stack />
|
|
16
|
+
</>
|
|
17
|
+
);
|
|
18
|
+
}
|
package/src/index.ts
ADDED
package/src/styled.d.ts
ADDED
package/src/utils.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { theme } from "@sproutsocial/seeds-react-theme";
|
|
2
|
+
|
|
3
|
+
import type { TypeResponsive } from "@sproutsocial/seeds-react-system-props";
|
|
4
|
+
|
|
5
|
+
const breakpoints = theme.breakpoints;
|
|
6
|
+
const LENGTH = breakpoints.length + 1;
|
|
7
|
+
|
|
8
|
+
export const normalizeResponsiveProp = (
|
|
9
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10
|
+
value: TypeResponsive<any>
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
12
|
+
): TypeResponsive<any> => {
|
|
13
|
+
if (["string", "number"].includes(typeof value)) {
|
|
14
|
+
return Array(LENGTH).fill(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (value.length) {
|
|
18
|
+
switch (value.length) {
|
|
19
|
+
case 1:
|
|
20
|
+
return Array(LENGTH).fill(value[0]);
|
|
21
|
+
case 2:
|
|
22
|
+
return [value[0], ...Array(LENGTH - 1).fill(value[1])];
|
|
23
|
+
case 3:
|
|
24
|
+
return [value[0], value[1], ...Array(LENGTH - 2).fill(value[2])];
|
|
25
|
+
case 4:
|
|
26
|
+
return [
|
|
27
|
+
value[0],
|
|
28
|
+
value[1],
|
|
29
|
+
value[2],
|
|
30
|
+
...Array(LENGTH - 3).fill(value[3]),
|
|
31
|
+
];
|
|
32
|
+
case 5:
|
|
33
|
+
return value;
|
|
34
|
+
default:
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Invalid responsive prop length: ${JSON.stringify(value)}`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
throw new Error(`Invalid responsive prop type: ${JSON.stringify(value)}`);
|
|
41
|
+
}
|
|
42
|
+
};
|
package/tsconfig.json
ADDED
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { defineConfig } from "tsup";
|
|
2
|
+
|
|
3
|
+
export default defineConfig((options) => ({
|
|
4
|
+
entry: ["src/index.ts"],
|
|
5
|
+
format: ["cjs", "esm"],
|
|
6
|
+
clean: true,
|
|
7
|
+
legacyOutput: true,
|
|
8
|
+
dts: options.dts,
|
|
9
|
+
external: ["react"],
|
|
10
|
+
sourcemap: true,
|
|
11
|
+
metafile: options.metafile,
|
|
12
|
+
}));
|