@dash-ui/layout
Version:
A framework-agnostic layout library written in Dash
1,287 lines (1,188 loc) • 27.7 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.default = void 0;
var _compound = /*#__PURE__*/_interopRequireDefault( /*#__PURE__*/require("@dash-ui/compound"));
var _responsive = /*#__PURE__*/_interopRequireDefault( /*#__PURE__*/require("@dash-ui/responsive"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _ref2(width) {
return {
width
};
}
function _ref3(height) {
return {
height
};
}
function _ref4(maxWidth) {
return {
maxWidth
};
}
function _ref5(maxHeight) {
return {
maxHeight
};
}
function _ref6(minWidth) {
return {
minWidth
};
}
function _ref7(minHeight) {
return {
minHeight
};
}
function _ref8(size) {
return {
width: size,
height: size
};
}
function _ref9(value) {
return ({
pad
}) => ({
padding: Array.isArray(value) ? value.map(k => pad[k]).join(" ") : pad[value]
});
}
function _ref10([width, borderColor]) {
return ({
borderWidth,
color
}) => ({
borderWidth: Array.isArray(width) ? width.map(w => borderWidth[w]).join(" ") : borderWidth[width],
borderStyle: "solid",
borderColor: color[borderColor]
});
}
function _ref11(value) {
return ({
radius
}) => ({
borderRadius: Array.isArray(value) ? value.map(k => radius[k]).join(" ") : radius[value]
});
}
function _ref12(value) {
if (Array.isArray(value)) {
var _value$, _value$2, _ref, _value$3;
return {
"@supports (inset: 10px)": {
inset: value.map(unit).join(" ")
},
"@supports not (inset: 10px)": {
top: value[0],
right: (_value$ = value[1]) !== null && _value$ !== void 0 ? _value$ : value[0],
bottom: (_value$2 = value[2]) !== null && _value$2 !== void 0 ? _value$2 : value[0],
left: (_ref = (_value$3 = value[3]) !== null && _value$3 !== void 0 ? _value$3 : value[1]) !== null && _ref !== void 0 ? _ref : value[0]
}
};
}
return {
"@supports (inset: 10px)": {
inset: value
},
"@supports not (inset: 10px)": {
top: value,
right: value,
bottom: value,
left: value
}
};
}
function _ref13(value) {
return {
flexBasis: value
};
}
function _ref14(value) {
return {
flexGrow: Number(value)
};
}
function _ref15(value) {
return {
order: value
};
}
function _ref16(value) {
return {
flexShrink: Number(value)
};
}
function _ref17(value) {
return ({
gap
}) => ({
gridGap: Array.isArray(value) ? value.map(p => gap[p]).join(" ") : gap[value] + " " + gap[value],
gap: Array.isArray(value) ? value.map(p => gap[p]).join(" ") : gap[value] + " " + gap[value]
});
}
function _ref18(row) {
return unit(row);
}
function _ref19(value) {
let rows;
if (Array.isArray(value)) rows = value; // ie doesn't have repeat
else rows = [`repeat(${value},minmax(0,1fr))`];
return {
gridTemplateRows: rows.map(_ref18).join(" ")
};
}
function _ref20(col) {
return unit(col);
}
function _ref21(value) {
let columns;
if (Array.isArray(value)) columns = value; // ie doesn't have repeat
else columns = [`repeat(${value},minmax(0,1fr))`];
return {
gridTemplateColumns: columns.map(_ref20).join(" ")
};
}
function _ref22(gridColumnStart) {
return {
gridColumnStart
};
}
function _ref23(gridColumnEnd) {
return {
gridColumnEnd
};
}
function _ref24(gridRowStart) {
return {
gridRowStart
};
}
function _ref25(gridRowEnd) {
return {
gridRowEnd
};
}
function _ref26(itemWidth) {
return {
gridTemplateColumns: `repeat(auto-fit, minmax(${unit(itemWidth)}, 1fr))`
};
}
function _ref27(margin) {
return {
margin
};
}
function _ref28(value) {
return ({
pad
}) => ({
margin: Array.isArray(value) ? value.map(k => String(k).startsWith("-") ? `${pad[k]}` : `calc(-1 * ${pad[k]})`).join(" ") + "!important" : String(value).startsWith("-") ? `${pad[value]}!important` : `calc(-1 * ${pad[value]})!important`
});
}
/**
* Creates new layout style utilities using an existing Dash `styles` instance.
*
* @param styles - An `styles` instance from `@dash-ui/styles`
* @param mediaQueries - The media queries to use for responsive styles
*/
function layout(styles, mediaQueries) {
const compoundStyles = (0, _compound.default)(styles);
const responsiveStyles = (0, _responsive.default)(styles, mediaQueries || {});
const box = compoundStyles({
/**
* Sets a `display` CSS property on your component
*/
display: responsiveStyles.variants({
flex: {
display: "flex"
},
inlineFlex: {
display: "inline-flex"
},
grid: {
display: "grid"
},
inlineGrid: {
display: "inlineGrid"
},
block: {
display: "block"
},
inlineBlock: {
display: "inline-block"
},
inline: {
display: "inline"
},
table: {
display: "table"
},
tableCell: {
display: "table-cell"
},
tableRowGroup: {
display: "table-row-group"
},
tableRow: {
display: "table-row"
},
tableColumn: {
display: "table-column"
},
tableColumnGroup: {
display: "table-column-group"
},
tableHeader: {
display: "table-header"
},
tableHeaderGroup: {
display: "table-header-group"
},
tableFooterGroup: {
display: "table-footer-group"
},
listItem: {
display: "list-item"
},
contents: {
display: "contents"
},
runIn: {
display: "run-in"
},
none: {
display: "none"
},
inherit: {
display: "inherit"
},
initial: {
display: "initial"
},
unset: {
display: "unset"
},
revert: {
display: "revert"
}
}),
/**
* Sets a `position` CSS property on your component
*/
position: responsiveStyles.variants({
absolute: {
position: "absolute"
},
relative: {
position: "relative"
},
fixed: {
position: "fixed"
},
sticky: {
position: "sticky"
},
static: {
position: "static"
},
inherit: {
position: "inherit"
},
initial: {
position: "initial"
},
unset: {
position: "unset"
},
revert: {
position: "revert"
}
}),
/**
* Sets a `width` CSS property on your component
*/
width: responsiveStyles.lazy(_ref2),
/**
* Sets a `height` CSS property on your component
*/
height: responsiveStyles.lazy(_ref3),
/**
* Sets a `max-width` CSS property on your component
*/
maxWidth: responsiveStyles.lazy(_ref4),
/**
* Sets a `max-height` CSS property on your component
*/
maxHeight: responsiveStyles.lazy(_ref5),
/**
* Sets a `max-width` CSS property on your component
*/
minWidth: responsiveStyles.lazy(_ref6),
/**
* Sets a `max-height` CSS property on your component
*/
minHeight: responsiveStyles.lazy(_ref7),
/**
* Sets a `width` and `height` CSS property on your component
*/
size: responsiveStyles.lazy(_ref8),
/**
* Sets a `padding` CSS property on your component using the "pad"
* token in your theme
*/
pad: responsiveStyles.lazy(_ref9),
/**
* Sets a `background-color` CSS property on your component using the "color"
* token in your theme
*/
bg: responsiveStyles.variants(reduce(styles.tokens.color, (acc, key) => {
acc[key] = {
backgroundColor: styles.tokens.color[key]
};
return acc;
}, {})),
/**
* Sets a `border-color` CSS property on your component using the "color"
* token in your theme and a `border-width` property using the "borderWidth"
* token.
*/
border: responsiveStyles.lazy(_ref10),
/**
* Sets a `box-shadow` CSS property on your component using the "shadow"
* token in your theme
*/
shadow: responsiveStyles.variants(reduce(styles.tokens.shadow, (acc, key) => {
acc[key] = {
boxShadow: styles.tokens.shadow[key]
};
return acc;
}, {})),
/**
* Sets a `border-radius` CSS property on your component using the "radius"
* token in your theme
*/
radius: responsiveStyles.lazy(_ref11),
/**
* Sets the top, right, bottom, left position of the element
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/inset
*/
inset: responsiveStyles.lazy(_ref12),
/**
* Sets a `z-index` CSS property on your component
*/
z: responsiveStyles.variants(reduce(styles.tokens.zIndex, (acc, key) => {
acc[key] = {
zIndex: styles.tokens.zIndex[key]
};
return acc;
}, {}))
}, {
atomic: true
});
const alignItems = responsiveStyles.variants({
start: {
"@supports (align-items: start)": {
alignItems: "start"
},
"@supports not (align-items: start)": {
alignItems: "flex-start"
}
},
end: {
"@supports (align-items: end)": {
alignItems: "end"
},
"@supports not (align-items: end)": {
alignItems: "flex-end"
}
},
center: {
alignItems: "center"
},
baseline: {
alignItems: "baseline"
},
stretch: {
alignItems: "stretch"
},
normal: {
alignItems: "normal"
},
inherit: {
alignItems: "inherit"
},
initial: {
alignItems: "initial"
},
unset: {
alignItems: "unset"
},
revert: {
alignItems: "revert"
}
});
const justifyItems = responsiveStyles.variants({
start: {
"@supports (justify-items: start)": {
justifyItems: "start"
},
"@supports not (justify-items: start)": {
justifyItems: "flex-start"
}
},
end: {
"@supports (justify-items: end)": {
justifyItems: "end"
},
"@supports not (justify-items: end)": {
justifyItems: "flex-end"
}
},
center: {
justifyItems: "center"
},
baseline: {
justifyItems: "baseline"
},
stretch: {
justifyItems: "stretch"
},
normal: {
justifyItems: "normal"
},
inherit: {
justifyItems: "inherit"
},
initial: {
justifyItems: "initial"
},
unset: {
justifyItems: "unset"
},
revert: {
justifyItems: "revert"
}
});
const justifyContent = responsiveStyles.variants({
start: {
"@supports (justify-content: start)": {
justifyContent: "start"
},
"@supports not (justify-content: start)": {
justifyContent: "flex-start"
}
},
end: {
"@supports (justify-content: end)": {
justifyContent: "end"
},
"@supports not (justify-content: end)": {
justifyContent: "flex-end"
}
},
center: {
justifyContent: "center"
},
around: {
justifyContent: "space-around"
},
between: {
justifyContent: "space-between"
},
evenly: {
justifyContent: "space-evenly"
},
baseline: {
justifyContent: "baseline"
},
stretch: {
justifyContent: "stretch"
},
normal: {
justifyContent: "normal"
},
inherit: {
justifyContent: "inherit"
},
initial: {
justifyContent: "initial"
},
unset: {
justifyContent: "unset"
},
revert: {
justifyContent: "revert"
}
});
const alignContent = responsiveStyles.variants({
start: {
"@supports (align-content: start)": {
alignContent: "start"
},
"@supports not (align-content: start)": {
alignContent: "flex-start"
}
},
end: {
"@supports (align-content: end)": {
alignContent: "end"
},
"@supports not (align-content: end)": {
alignContent: "flex-end"
}
},
center: {
alignContent: "center"
},
around: {
alignContent: "space-around"
},
between: {
alignContent: "space-between"
},
evenly: {
alignContent: "space-evenly"
},
baseline: {
alignContent: "baseline"
},
stretch: {
alignContent: "stretch"
},
normal: {
alignContent: "normal"
},
inherit: {
alignContent: "inherit"
},
initial: {
alignContent: "initial"
},
unset: {
alignContent: "unset"
},
revert: {
alignContent: "revert"
}
});
const alignSelf = responsiveStyles.variants({
start: {
"@supports (align-self: start)": {
alignSelf: "start"
},
"@supports not (align-self: start)": {
alignSelf: "flex-start"
}
},
end: {
"@supports (align-self: end)": {
alignSelf: "end"
},
"@supports not (align-self: end)": {
alignSelf: "flex-end"
}
},
center: {
alignSelf: "center"
},
baseline: {
alignSelf: "baseline"
},
stretch: {
alignSelf: "stretch"
},
auto: {
alignSelf: "auto"
},
normal: {
alignSelf: "normal"
},
inherit: {
alignSelf: "inherit"
},
initial: {
alignSelf: "initial"
},
unset: {
alignSelf: "unset"
},
revert: {
alignSelf: "revert"
}
});
const justifySelf = responsiveStyles.variants({
start: {
"@supports (justify-self: start)": {
justifySelf: "start"
},
"@supports not (justify-self: start)": {
justifySelf: "flex-start"
}
},
end: {
"@supports (justify-self: end)": {
justifySelf: "end"
},
"@supports not (justify-self: end)": {
justifySelf: "flex-end"
}
},
center: {
justifySelf: "center"
},
around: {
justifySelf: "space-around"
},
between: {
justifySelf: "space-between"
},
evenly: {
justifySelf: "space-evenly"
},
baseline: {
justifySelf: "baseline"
},
stretch: {
justifySelf: "stretch"
},
auto: {
justifySelf: "auto"
},
normal: {
justifySelf: "normal"
},
inherit: {
justifySelf: "inherit"
},
initial: {
justifySelf: "initial"
},
unset: {
justifySelf: "unset"
},
revert: {
justifySelf: "revert"
}
});
const flexItem = compoundStyles({
/**
* Sets a `align-self` CSS property on your component
*/
align: alignSelf,
/**
* Sets a `justify-self` CSS property on your component
*/
basis: responsiveStyles.lazy(_ref13),
/**
* Sets a `justify-self` CSS property on your component
*/
distribute: justifySelf,
/**
* Sets a `flex-grow` CSS property on your component
*/
grow: responsiveStyles.lazy(_ref14),
/**
* Sets a `order` CSS property on your component
*/
order: responsiveStyles.lazy(_ref15),
/**
* Sets a `flex-shrink` CSS property on your component
*/
shrink: responsiveStyles.lazy(_ref16),
...box.styles
}, {
atomic: true
});
const inline = compoundStyles({
default: responsiveStyles.one({
display: "flex",
flexWrap: "wrap",
justifyContent: "flex-start",
"& > *": {
flexShrink: 0
}
}),
/**
* Sets a vertical and horizontal gap between the child elements in the
* inline using the "gap" token in your theme
*/
gap: responsiveStyles.variants(reduce(styles.tokens.gap, (acc, value) => {
const gap = styles.tokens.gap;
acc[value] = {
"@supports (display: flex) and (gap: 1em)": {
gap: gap[value]
},
"@supports not (display: flex) and (gap: 1em)": {
marginTop: `calc(-1 * ${gap[value]})!important`,
marginLeft: `calc(-1 * ${gap[value]})!important`,
"& > *": {
marginTop: `${gap[value]}!important`,
marginLeft: `${gap[value]}!important`
}
}
};
return acc;
}, {})),
/**
* Distributed alignment properties on the x-axis using `justify-content`
*/
distribute: justifyContent,
/**
* Positional alignment for its child items on the y-axis using `align-items`
*/
align: alignItems,
...box.styles
}, {
atomic: true
});
const sharedGrid = compoundStyles({
default: responsiveStyles.one({
display: "grid"
}),
/**
* Makes the component display as an `inline-grid` rather than `grid`
*/
inline: responsiveStyles.one({
display: "inline-grid"
}),
/**
* Sets a `justify-items` CSS property on your component
*/
alignX: justifyItems,
/**
* Sets an `align-items` CSS property on your component
*/
alignY: alignItems,
/**
* Sets a `justify-content` CSS property on your component
*/
distributeX: justifyContent,
/**
* Sets an `align-content` CSS property on your component
*/
distributeY: alignContent,
/**
* Sets a horizontal and vertical gap between the child elements in the row
* using the "gap" token in your theme
*/
gap: responsiveStyles.lazy(_ref17),
/**
* Sets a `grid-template-rows` CSS property on your component
*/
rows: responsiveStyles.lazy(_ref19)
}, {
atomic: true
});
const grid = compoundStyles({
/**
* Sets a `grid-template-columns` CSS property on your component
*/
cols: responsiveStyles.lazy(_ref21),
...sharedGrid.styles,
...box.styles
}, {
atomic: true
});
const gridItem = compoundStyles({
/**
* Sets a `justify-self` CSS property on your component
*/
distribute: justifySelf,
/**
* Sets an `align-self` CSS property on your component
*/
align: alignSelf,
/**
* Sets a `grid-column-start` CSS property on your component
*/
colStart: responsiveStyles.lazy(_ref22),
/**
* Sets a `grid-column-end` CSS property on your component
*/
colEnd: responsiveStyles.lazy(_ref23),
/**
* Sets a `grid-row-start` CSS property on your component
*/
rowStart: responsiveStyles.lazy(_ref24),
/**
* Sets a `grid-row-end` CSS property on your component
*/
rowEnd: responsiveStyles.lazy(_ref25),
...box.styles
}, {
atomic: true
});
const autoGrid = compoundStyles({
/**
* The minimum width of a grid item
*/
itemWidth: responsiveStyles.lazy(_ref26),
...sharedGrid.styles
}, {
atomic: true
});
const hstack = compoundStyles({
default: responsiveStyles.one({
display: "flex",
flexDirection: "row",
"& > *": {
flexShrink: 0
}
}),
/**
* Reverses the order of the child elements
*/
reversed: responsiveStyles.one({
flexDirection: "row-reverse"
}),
/**
* Sets a horizontal gap between the child elements in the hstack using the "gap"
* token in your theme
*/
gap: responsiveStyles.variants(reduce(styles.tokens.gap, (acc, value) => {
const gap = styles.tokens.gap;
const margin = {
"& > * + *": {
marginLeft: `${gap[value]}!important`
}
};
acc[value] = ("" + value).startsWith("-") ? margin : {
"@supports (display: flex) and (gap: 1em)": {
gap: gap[value]
},
"@supports not (display: flex) and (gap: 1em)": margin
};
return acc;
}, {})),
/**
* Distributed alignment properties on the y-axis using `justify-content`
*/
distribute: justifyContent,
/**
* Positional alignment for its child items on the x-axis using `align-items`
*/
align: alignItems,
...box.styles
}, {
atomic: true
});
const vstack = compoundStyles({
default: responsiveStyles.one({
display: "flex",
flexDirection: "column",
"& > *": {
flexShrink: 0
}
}),
/**
* Reverses the order of the child elements
*/
reversed: responsiveStyles.one({
flexDirection: "column-reverse"
}),
/**
* Sets a vertical gap between the child elements in the vstack using the "gap"
* token in your theme
*/
gap: responsiveStyles.variants(reduce(styles.tokens.gap, (acc, value) => {
const gap = styles.tokens.gap;
const margin = {
"& > * + *": {
marginTop: `${gap[value]}!important`
}
};
acc[value] = (value + "").startsWith("-") ? margin : {
"@supports (display: flex) and (gap: 1em)": {
gap: gap[value]
},
"@supports not (display: flex) and (gap: 1em)": margin
};
return acc;
}, {})),
/**
* Distributed alignment properties on the y-axis using `justify-content`
*/
distribute: justifyContent,
/**
* Positional alignment for its child items on the y-axis using `align-items`
*/
align: alignItems,
...box.styles
}, {
atomic: true
});
const zstack = compoundStyles({
default: responsiveStyles.one({
display: "grid",
"> *": {
gridArea: "1/1/1/1"
}
}),
inline: grid.styles.inline,
alignX: justifyItems,
alignY: alignItems,
distributeX: justifyContent,
distributeY: alignContent,
center: responsiveStyles.one({
alignItems: "center",
justifyItems: "center"
}),
...box.styles
}, {
atomic: true
});
const overlay = compoundStyles({
default: responsiveStyles.one({
position: "absolute"
}),
/**
* Sets a `margin` between the edges of the overlay item's container
*/
offset: responsiveStyles.lazy(_ref27),
/**
* Sets the placement of your overlay item relative to its container
*/
placement: responsiveStyles.variants({
top: {
top: 0,
left: "50%",
transform: "translateX(-50%)"
},
right: {
right: 0,
top: "50%",
transform: "translateY(-50%)"
},
bottom: {
bottom: 0,
left: "50%",
transform: "translateX(-50%)"
},
left: {
left: 0,
top: "50%",
transform: "translateY(-50%)"
},
center: {
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)"
},
topRight: {
top: 0,
right: 0
},
topLeft: {
top: 0,
left: 0
},
bottomRight: {
bottom: 0,
right: 0
},
bottomLeft: {
bottom: 0,
left: 0
}
}),
...box.styles
}, {
atomic: true
});
const bleed = compoundStyles({
/**
* Sets a negative margin on itself using the "pad" token in your theme
*/
amount: responsiveStyles.lazy(_ref28),
...box.styles
}, {
atomic: true
});
return {
/**
* Sets a `align-items` CSS property on your component
*/
alignItems,
/**
* Sets a `justify-items` CSS property on your component
*/
justifyItems,
/**
* Sets a `justify-content` CSS property on your component
*/
justifyContent,
/**
* Sets a `align-content` CSS property on your component
*/
alignContent,
/**
* Sets a `align-self` CSS property on your component
*/
alignSelf,
/**
* Sets a `justify-self` CSS property on your component
*/
justifySelf,
/**
* A layout style for adding size, padding, position, color, and more
* using tokens from your CSS variable theme.
*
* @example
* <div className={box({size: 300, bg: {sm: 'red', md: 'blue'}})} />
*/
box,
/**
* Arranges child nodes horizontally, wrapping to multiple lines if needed,
* with equal spacing between items.
*
* If there is only a single child node, no space will be rendered.
*
* ```
* ☐☐☐☐☐
* ☐☐☐☐☐☐
* ☐☐☐☐☐
* ☐☐☐
* ```
*
* Some use cases include input chips and tags.
*
* @example
* <div className={inline({gap: 'sm})}>
* <Item/>
* <Item/>
* </div>
*/
inline,
/**
* A layout style that can add positioning properties to itself inside
* of a flex container.
*
* @example
* <div className={flexItem({alignSelf: 'center', order: 2})}/>
*/
flexItem,
/**
* A layout style that distributes its children in a grid like so:
*
* ```
* ☐ ☐ ☐
* ☐ ☐ ☐
* ☐ ☐ ☐
* ```
*
* @example
* <div className={grid({rows: 2, cols: 2})}>
* <GridItem/>
* <GridItem/>
* <GridItem/>
* <GridItem/>
* </div>
*/
grid,
/**
* A layout style that can add positioning properties to itself inside
* of a `<Grid>` component.
*
* @example
* <div className={grid({cols: 2, rows: 2})}>
* // Occupies 2 columns
* <div className={gridItem({colStart: 1, colEnd: 2})} />
* <div/>
* <div/>
* </div>
*/
gridItem,
/**
* A grid that automatically chooses a number of columns based on a preferred
* minimum grid item width. The items will grow to fit snugly within the grid
* container, like with flex wrapping, but no item will grow larger than the
* column size, unlike flex wrapping.
*
* ☐ ☐ ☐
* ☐ ☐ ☐
* ☐ ☐
*/
autoGrid,
/**
* A layout style that distributes its items in a row without wrapping
* like so:
*
* ```
* ☐ ☐ ☐ ☐ ☐ ☐ ☐
* ```
*
* @example
* <div className={hstack({gap: 'sm'})}>
* <Item/>
* <Item/>
* </div>
*/
hstack,
/**
* A layout style that distributes its items in a column without wrapping
* like so:
*
* ```
* ☐
* ☐
* ☐
* ☐
* ```
*
* @example
* <div className={vstack({gap: 'sm'})}>
* <Item/>
* <Item/>
* </div>
*/
vstack,
/**
* A layout style that stacks its items on top of one another, like so:
*
* ```
* _____
* | ☐ |
* _____
* ```
*
* @example
* <div className={zstack({center: true})} />
*/
zstack,
/**
* A layout style than positions itself absolutely inside of its
* container in whichever placement you decide.
*
* @example
* <div className={overlay({placement: 'bottomRight', offset: 24})} />
*/
overlay,
/**
* A layout style that sets a negative left/top margin on itself using
* the "pad" token in your theme. This is useful for increasing the
* tap area of a component while maintaining the desired visual padding.
*
* @example
* <div className={bleed({amount: 'sm', pad: 'lg'})}>
* <Item/>
* <Item/>
* </div>
*/
bleed
};
}
var _default = layout;
exports.default = _default;
const keys = Object.keys;
function reduce(obj, fn, init) {
return keys(obj).reduce(fn, init);
}
/**
* Adds a `px` unit to numeric values and returns non-numeric values as
* they are.
*
* @param value - The value you want to maybe add a unit to
*/
function unit(value) {
return !isNaN(value) && value !== 0 ? `${value}px` : value;
}