UNPKG

12.5 kBJavaScriptView Raw
1import { useTheme } from '@spark-web/theme';
2import { createContext, useContext } from 'react';
3import { jsx } from 'react/jsx-runtime';
4import _objectSpread from '@babel/runtime/helpers/esm/objectSpread2';
5import _objectWithoutProperties from '@babel/runtime/helpers/esm/objectWithoutProperties';
6import { cx, css } from '@emotion/css';
7import { resetElementStyles, buildDataAttributes } from '@spark-web/utils/internal';
8import { forwardRefWithAs } from '@spark-web/utils/ts';
9
10// prepare context
11
12var backgroundContext = /*#__PURE__*/createContext('body');
13var InternalBackgroundProvider = backgroundContext.Provider;
14var useBackground = function useBackground() {
15 return useContext(backgroundContext);
16};
17
18// conditional provider
19
20function renderBackgroundProvider(background, element) {
21 return background ? /*#__PURE__*/jsx(InternalBackgroundProvider, {
22 value: background,
23 children: element
24 }) : element;
25}
26
27// a11y contrast utility
28
29var useBackgroundLightness = function useBackgroundLightness(backgroundOverride) {
30 var backgroundFromContext = useBackground();
31 var background = backgroundOverride || backgroundFromContext;
32 var theme = useTheme();
33 var defaultLightness = theme.backgroundLightness.body;
34
35 // used by the consumer-facing/external BackgroundProvider
36 if (background === 'UNKNOWN_DARK') {
37 return 'dark';
38 }
39 if (background === 'UNKNOWN_LIGHT') {
40 return 'light';
41 }
42 return background ? theme.backgroundLightness[background] || defaultLightness : defaultLightness;
43};
44
45/** Enforce background "lightness" without applying a background color. */
46var BackgroundProvider = function BackgroundProvider(_ref) {
47 var type = _ref.type,
48 children = _ref.children;
49 return renderBackgroundProvider(type === 'dark' ? 'UNKNOWN_DARK' : 'UNKNOWN_LIGHT', children);
50};
51
52// TODO perf review
53// TODO: review responsive props! Now that we're using object syntax, un-mapped properties don't behave as expected
54
55// types
56
57// Hook
58// ------------------------------
59
60var useBoxStyles = function useBoxStyles(_ref) {
61 var alignItems = _ref.alignItems,
62 alignSelf = _ref.alignSelf,
63 background = _ref.background,
64 border = _ref.border,
65 borderTop = _ref.borderTop,
66 borderBottom = _ref.borderBottom,
67 borderLeft = _ref.borderLeft,
68 borderRight = _ref.borderRight,
69 borderRadius = _ref.borderRadius,
70 _ref$borderWidth = _ref.borderWidth,
71 borderWidth = _ref$borderWidth === void 0 ? 'standard' : _ref$borderWidth,
72 bottom = _ref.bottom,
73 cursor = _ref.cursor,
74 display = _ref.display,
75 flex = _ref.flex,
76 flexDirection = _ref.flexDirection,
77 flexGrow = _ref.flexGrow,
78 flexShrink = _ref.flexShrink,
79 flexWrap = _ref.flexWrap,
80 gap = _ref.gap,
81 height = _ref.height,
82 justifyContent = _ref.justifyContent,
83 left = _ref.left,
84 margin = _ref.margin,
85 marginBottom = _ref.marginBottom,
86 marginLeft = _ref.marginLeft,
87 marginRight = _ref.marginRight,
88 marginTop = _ref.marginTop,
89 marginX = _ref.marginX,
90 marginY = _ref.marginY,
91 minHeight = _ref.minHeight,
92 minWidth = _ref.minWidth,
93 opacity = _ref.opacity,
94 overflow = _ref.overflow,
95 padding = _ref.padding,
96 paddingBottom = _ref.paddingBottom,
97 paddingLeft = _ref.paddingLeft,
98 paddingRight = _ref.paddingRight,
99 paddingTop = _ref.paddingTop,
100 paddingX = _ref.paddingX,
101 paddingY = _ref.paddingY,
102 position = _ref.position,
103 right = _ref.right,
104 shadow = _ref.shadow,
105 top = _ref.top,
106 userSelect = _ref.userSelect,
107 width = _ref.width,
108 zIndex = _ref.zIndex;
109 var theme = useTheme();
110 var unresponsiveProps = {
111 background: background ? theme.color.background[background] : undefined,
112 boxShadow: shadow ? theme.shadow[shadow] : undefined,
113 cursor: cursor,
114 minHeight: minHeight,
115 minWidth: minWidth,
116 opacity: opacity,
117 overflow: overflow,
118 userSelect: userSelect
119 };
120 var conditionalBorderStyles = _objectSpread(_objectSpread(_objectSpread(_objectSpread(_objectSpread({}, border ? {
121 borderStyle: 'solid',
122 borderColor: theme.utils.mapResponsiveScale(border, theme.border.color),
123 borderWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width)
124 } : {}), borderTop ? {
125 borderTopStyle: 'solid',
126 borderTopColor: theme.utils.mapResponsiveScale(borderTop, theme.border.color),
127 borderTopWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width)
128 } : {}), borderBottom ? {
129 borderBottomStyle: 'solid',
130 borderBottomColor: theme.utils.mapResponsiveScale(borderBottom, theme.border.color),
131 borderBottomWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width)
132 } : {}), borderLeft ? {
133 borderLeftStyle: 'solid',
134 borderLeftColor: theme.utils.mapResponsiveScale(borderLeft, theme.border.color),
135 borderLeftWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width)
136 } : {}), borderRight ? {
137 borderRightStyle: 'solid',
138 borderRightColor: theme.utils.mapResponsiveScale(borderRight, theme.border.color),
139 borderRightWidth: theme.utils.mapResponsiveScale(borderWidth, theme.border.width)
140 } : {});
141 return theme.utils.resolveResponsiveProps(_objectSpread(_objectSpread(_objectSpread({}, unresponsiveProps), conditionalBorderStyles), {}, {
142 // allow padding and height/width props to play nice
143 display: theme.utils.mapResponsiveProp(display),
144 // margin
145 marginBottom: theme.utils.mapResponsiveScale(marginBottom || marginY || margin, theme.spacing),
146 marginTop: theme.utils.mapResponsiveScale(marginTop || marginY || margin, theme.spacing),
147 marginLeft: theme.utils.mapResponsiveScale(marginLeft || marginX || margin, theme.spacing),
148 marginRight: theme.utils.mapResponsiveScale(marginRight || marginX || margin, theme.spacing),
149 // padding
150 paddingBottom: theme.utils.mapResponsiveScale(paddingBottom || paddingY || padding, theme.spacing),
151 paddingTop: theme.utils.mapResponsiveScale(paddingTop || paddingY || padding, theme.spacing),
152 paddingLeft: theme.utils.mapResponsiveScale(paddingLeft || paddingX || padding, theme.spacing),
153 paddingRight: theme.utils.mapResponsiveScale(paddingRight || paddingX || padding, theme.spacing),
154 // border
155 borderRadius: theme.utils.mapResponsiveScale(borderRadius, theme.border.radius),
156 // flex: parent
157 alignItems: theme.utils.mapResponsiveScale(alignItems, flexMap.alignItems),
158 gap: theme.utils.mapResponsiveScale(gap, theme.spacing),
159 flexDirection: theme.utils.mapResponsiveScale(flexDirection, flexMap.flexDirection),
160 justifyContent: theme.utils.mapResponsiveScale(justifyContent, flexMap.justifyContent),
161 flexWrap: theme.utils.mapResponsiveProp(flexWrap),
162 // flex: child
163 alignSelf: theme.utils.mapResponsiveScale(alignSelf, flexMap.alignItems),
164 flex: theme.utils.mapResponsiveProp(flex),
165 flexGrow: theme.utils.mapResponsiveProp(flexGrow),
166 flexShrink: theme.utils.mapResponsiveProp(flexShrink),
167 // dimension
168 height: theme.utils.mapResponsiveScale(height, theme.sizing),
169 width: theme.utils.mapResponsiveScale(width, theme.sizing),
170 // position
171 position: theme.utils.mapResponsiveProp(position),
172 bottom: theme.utils.mapResponsiveProp(bottom),
173 left: theme.utils.mapResponsiveProp(left),
174 right: theme.utils.mapResponsiveProp(right),
175 top: theme.utils.mapResponsiveProp(top),
176 zIndex: theme.utils.mapResponsiveScale(zIndex, theme.elevation)
177 }));
178};
179
180// Flex shorthand / adjustments
181// ------------------------------
182
183var flexMap = {
184 alignItems: {
185 start: 'flex-start',
186 center: 'center',
187 end: 'flex-end',
188 stretch: 'stretch'
189 },
190 justifyContent: {
191 start: 'flex-start',
192 center: 'center',
193 end: 'flex-end',
194 spaceBetween: 'space-between',
195 stretch: 'stretch'
196 },
197 flexDirection: {
198 row: 'row',
199 rowReverse: 'row-reverse',
200 column: 'column',
201 columnReverse: 'column-reverse'
202 }
203};
204
205var _excluded$1 = ["alignItems", "alignSelf", "background", "border", "borderRadius", "borderWidth", "borderTop", "borderBottom", "borderLeft", "borderRight", "bottom", "cursor", "display", "flex", "flexDirection", "flexGrow", "flexShrink", "flexWrap", "gap", "height", "justifyContent", "left", "margin", "marginBottom", "marginLeft", "marginRight", "marginTop", "marginX", "marginY", "minHeight", "minWidth", "opacity", "overflow", "padding", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "paddingX", "paddingY", "position", "right", "shadow", "top", "userSelect", "width", "zIndex"];
206
207/** Separate the style properties from the element attributes. */
208function useBoxProps(props) {
209 var alignItems = props.alignItems,
210 alignSelf = props.alignSelf,
211 background = props.background,
212 border = props.border,
213 borderRadius = props.borderRadius,
214 borderWidth = props.borderWidth,
215 borderTop = props.borderTop,
216 borderBottom = props.borderBottom,
217 borderLeft = props.borderLeft,
218 borderRight = props.borderRight,
219 bottom = props.bottom,
220 cursor = props.cursor,
221 display = props.display,
222 flex = props.flex,
223 flexDirection = props.flexDirection,
224 flexGrow = props.flexGrow,
225 flexShrink = props.flexShrink,
226 flexWrap = props.flexWrap,
227 gap = props.gap,
228 height = props.height,
229 justifyContent = props.justifyContent,
230 left = props.left,
231 margin = props.margin,
232 marginBottom = props.marginBottom,
233 marginLeft = props.marginLeft,
234 marginRight = props.marginRight,
235 marginTop = props.marginTop,
236 marginX = props.marginX,
237 marginY = props.marginY,
238 minHeight = props.minHeight,
239 minWidth = props.minWidth,
240 opacity = props.opacity,
241 overflow = props.overflow,
242 padding = props.padding,
243 paddingBottom = props.paddingBottom,
244 paddingLeft = props.paddingLeft,
245 paddingRight = props.paddingRight,
246 paddingTop = props.paddingTop,
247 paddingX = props.paddingX,
248 paddingY = props.paddingY,
249 position = props.position,
250 right = props.right,
251 shadow = props.shadow,
252 top = props.top,
253 userSelect = props.userSelect,
254 width = props.width,
255 zIndex = props.zIndex,
256 attributes = _objectWithoutProperties(props, _excluded$1);
257 var styles = useBoxStyles({
258 alignItems: alignItems,
259 alignSelf: alignSelf,
260 background: background,
261 border: border,
262 borderRadius: borderRadius,
263 borderWidth: borderWidth,
264 borderBottom: borderBottom,
265 borderLeft: borderLeft,
266 borderRight: borderRight,
267 borderTop: borderTop,
268 bottom: bottom,
269 cursor: cursor,
270 display: display,
271 flex: flex,
272 flexDirection: flexDirection,
273 flexGrow: flexGrow,
274 flexShrink: flexShrink,
275 flexWrap: flexWrap,
276 gap: gap,
277 height: height,
278 justifyContent: justifyContent,
279 left: left,
280 margin: margin,
281 marginBottom: marginBottom,
282 marginLeft: marginLeft,
283 marginRight: marginRight,
284 marginTop: marginTop,
285 marginX: marginX,
286 marginY: marginY,
287 minHeight: minHeight,
288 minWidth: minWidth,
289 opacity: opacity,
290 overflow: overflow,
291 padding: padding,
292 paddingBottom: paddingBottom,
293 paddingLeft: paddingLeft,
294 paddingRight: paddingRight,
295 paddingTop: paddingTop,
296 paddingX: paddingX,
297 paddingY: paddingY,
298 position: position,
299 right: right,
300 shadow: shadow,
301 top: top,
302 userSelect: userSelect,
303 width: width,
304 zIndex: zIndex
305 });
306 return {
307 styles: styles,
308 attributes: attributes
309 };
310}
311
312var _excluded = ["as", "asElement", "className", "data", "id"];
313/** Exposes a prop-based API for adding styles to a view, within the constraints of the theme. */
314var Box = forwardRefWithAs(function (_ref, forwardedRef) {
315 var _ref$as = _ref.as,
316 Tag = _ref$as === void 0 ? 'div' : _ref$as,
317 asElement = _ref.asElement,
318 className = _ref.className,
319 data = _ref.data,
320 id = _ref.id,
321 props = _objectWithoutProperties(_ref, _excluded);
322 var _useBoxProps = useBoxProps(props),
323 styles = _useBoxProps.styles,
324 attributes = _useBoxProps.attributes;
325 var resetStyles = resetElementStyles(asElement !== null && asElement !== void 0 ? asElement : Tag);
326 var element = /*#__PURE__*/jsx(Tag, _objectSpread(_objectSpread({}, data ? buildDataAttributes(data) : undefined), {}, {
327 ref: forwardedRef,
328 id: id,
329 className: cx(css(resetStyles), css(styles), className)
330 }, attributes));
331 return renderBackgroundProvider(props.background, element);
332});
333
334export { BackgroundProvider, Box, useBackground, useBackgroundLightness };