@zendeskgarden/react-theming 9.0.0-next.8 → 9.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.
@@ -5,60 +5,49 @@
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
7
  import { css, keyframes } from 'styled-components';
8
- import { math } from 'polished';
8
+ import { stripUnit } from 'polished';
9
9
 
10
- const exponentialSymbols = {
11
- symbols: {
12
- sqrt: {
13
- func: {
14
- symbol: 'sqrt',
15
- f: a => Math.sqrt(a),
16
- notation: 'func',
17
- precedence: 0,
18
- rightToLeft: 0,
19
- argCount: 1
20
- },
21
- symbol: 'sqrt',
22
- regSymbol: 'sqrt\\b'
23
- }
24
- }
25
- };
26
10
  const animationStyles = (position, modifier) => {
27
11
  const property = position.split('-')[0];
28
12
  const animationName = keyframes(["0%,66%{", ":2px;border:transparent;}"], property);
29
13
  return css(["&", "::before,&", "::after{animation:0.3s ease-in-out ", ";}"], modifier, modifier, animationName);
30
14
  };
31
- const positionStyles = (position, size, inset) => {
32
- const margin = math(`${size} / -2`);
33
- const placement = math(`${margin} + ${inset}`);
34
- let clipPath;
15
+ const positionStyles = (position, size, inset, shift) => {
16
+ const defaultInset = 0.3;
17
+ const margin = size / -2;
18
+ const placement = Math.round((margin + inset + defaultInset) * 100) / 100;
19
+ const marginPx = `${margin}px`;
20
+ const placementPx = `${placement}px`;
21
+ const offsetPx = `${size + shift}px`;
35
22
  let positionCss;
36
- let propertyRadius;
23
+ let transform;
37
24
  if (position.startsWith('top')) {
38
- propertyRadius = 'border-bottom-right-radius';
39
- clipPath = 'polygon(100% 0, 100% 1px, 1px 100%, 0 100%, 0 0)';
40
- positionCss = css(["top:", ";right:", ";left:", ";margin-left:", ";"], placement, position === 'top-right' && size, position === 'top' ? '50%' : position === 'top-left' && size, position === 'top' && margin);
25
+ transform = 'rotate(-135deg)';
26
+ positionCss = css(["top:", ";right:", ";left:", ";margin-left:", ";"], placementPx, position === 'top-right' && offsetPx, position === 'top' ? '50%' : position === 'top-left' && offsetPx, position === 'top' && marginPx);
41
27
  } else if (position.startsWith('right')) {
42
- propertyRadius = 'border-bottom-left-radius';
43
- clipPath = 'polygon(100% 0, 100% 100%, calc(100% - 1px) 100%, 0 1px, 0 0)';
44
- positionCss = css(["top:", ";right:", ";bottom:", ";margin-top:", ";"], position === 'right' ? '50%' : position === 'right-top' && size, placement, position === 'right-bottom' && size, position === 'right' && margin);
28
+ transform = 'rotate(-45deg)';
29
+ positionCss = css(["top:", ";right:", ";bottom:", ";margin-top:", ";"], position === 'right' ? '50%' : position === 'right-top' && offsetPx, placementPx, position === 'right-bottom' && offsetPx, position === 'right' && marginPx);
45
30
  } else if (position.startsWith('bottom')) {
46
- propertyRadius = 'border-top-left-radius';
47
- clipPath = 'polygon(100% 0, calc(100% - 1px) 0, 0 calc(100% - 1px), 0 100%, 100% 100%)';
48
- positionCss = css(["right:", ";bottom:", ";left:", ";margin-left:", ";"], position === 'bottom-right' && size, placement, position === 'bottom' ? '50%' : position === 'bottom-left' && size, position === 'bottom' && margin);
31
+ transform = 'rotate(45deg)';
32
+ positionCss = css(["right:", ";bottom:", ";left:", ";margin-left:", ";"], position === 'bottom-right' && offsetPx, placementPx, position === 'bottom' ? '50%' : position === 'bottom-left' && offsetPx, position === 'bottom' && marginPx);
49
33
  } else if (position.startsWith('left')) {
50
- propertyRadius = 'border-top-right-radius';
51
- clipPath = 'polygon(0 100%, 100% 100%, 100% calc(100% - 1px), 1px 0, 0 0)';
52
- positionCss = css(["top:", ";bottom:", ";left:", ";margin-top:", ";"], position === 'left' ? '50%' : position === 'left-top' && size, size, placement, position === 'left' && margin);
34
+ transform = 'rotate(135deg)';
35
+ positionCss = css(["top:", ";bottom:", ";left:", ";margin-top:", ";"], position === 'left' ? '50%' : position === 'left-top' && offsetPx, offsetPx, placementPx, position === 'left' && marginPx);
53
36
  }
54
- return css(["&::before{", ":100%;clip-path:", ";}&::before,&::after{", "}"], propertyRadius, clipPath, positionCss);
37
+ return css(["&::before,&::after{transform:", ";", ";}"], transform, positionCss);
55
38
  };
56
39
  function arrowStyles(position) {
57
40
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
58
- const size = options.size || '6px';
59
- const inset = options.inset || '0';
60
- const squareSize = math(`${size} * 2 / sqrt(2)`, exponentialSymbols);
61
- return css(["position:relative;&::before{border-width:inherit;border-style:inherit;border-color:transparent;background-clip:content-box;}&::after{z-index:-1;border:inherit;box-shadow:inherit;}&::before,&::after{position:absolute;transform:rotate(45deg);background-color:inherit;box-sizing:inherit;width:", ";height:", ";content:'';}", ";", ";"], squareSize, squareSize, positionStyles(position, squareSize, inset), options.animationModifier && animationStyles(position, options.animationModifier));
41
+ const inset = stripUnit(options.inset || '0');
42
+ const size = stripUnit(options.size || '6');
43
+ const shift = stripUnit(options.shift || '0');
44
+ const sizeOffset = 2;
45
+ const squareSize = size * 2 / Math.sqrt(2) + sizeOffset;
46
+ const squareSizeRounded = Math.round(squareSize * 100) / 100;
47
+ const squareSizePx = `${squareSizeRounded}px`;
48
+ const afterOffset = 0;
49
+ const beforeOffset = afterOffset + 2;
50
+ return css(["position:relative;&::before,&::after{position:absolute;border-width:inherit;border-style:inherit;background-color:inherit;width:", ";height:", ";content:'';box-sizing:inherit;}&::before{border-color:inherit;clip-path:polygon(100% ", "px,", "px 100%,100% 100%);}&::after{border-color:transparent;background-clip:content-box;clip-path:polygon(100% ", "px,", "px 100%,100% 100%);}", ";", ";"], squareSizePx, squareSizePx, beforeOffset, beforeOffset, afterOffset, afterOffset, positionStyles(position, squareSizeRounded, inset, shift), options.animationModifier && animationStyles(position, options.animationModifier));
62
51
  }
63
52
 
64
- export { arrowStyles as default, exponentialSymbols };
53
+ export { arrowStyles as default };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright Zendesk, Inc.
3
+ *
4
+ * Use of this source code is governed under the Apache License, Version 2.0
5
+ * found at http://www.apache.org/licenses/LICENSE-2.0.
6
+ */
7
+ import { getColor } from './getColor.js';
8
+
9
+ const getCheckeredBackground = _ref => {
10
+ let {
11
+ theme,
12
+ size,
13
+ overlay,
14
+ positionY = 0,
15
+ repeat = 'repeat'
16
+ } = _ref;
17
+ const color = getColor({
18
+ theme,
19
+ variable: 'border.default'
20
+ });
21
+ const dimensions = `${size}px ${size}px`;
22
+ const positionX1 = theme.rtl ? '100%' : '0';
23
+ const positionX2 = theme.rtl ? `calc(100% - ${size / 2}px)` : `${size / 2}px`;
24
+ const position1 = `${positionX1} ${positionY}px`;
25
+ const position2 = `${positionX2} ${size / 2 + positionY}px`;
26
+ const position3 = `${positionX2} ${positionY}px`;
27
+ const position4 = `${positionX1} ${size / -2 + positionY}px`;
28
+ let retVal = `
29
+ linear-gradient(45deg, ${color} 25%, transparent 25%) ${position1} / ${dimensions} ${repeat},
30
+ linear-gradient(45deg, transparent 75%, ${color} 75%) ${position2} / ${dimensions} ${repeat},
31
+ linear-gradient(135deg, ${color} 25%, transparent 25%) ${position3} / ${dimensions} ${repeat},
32
+ linear-gradient(135deg, transparent 75%, ${color} 75%) ${position4} / ${dimensions} ${repeat}
33
+ `;
34
+ if (overlay) {
35
+ retVal = overlay.startsWith('linear-gradient') ? `${overlay}, ${retVal}` : `linear-gradient(${overlay}, ${overlay}), ${retVal}`;
36
+ }
37
+ return retVal;
38
+ };
39
+
40
+ export { getCheckeredBackground };
@@ -4,14 +4,12 @@
4
4
  * Use of this source code is governed under the Apache License, Version 2.0
5
5
  * found at http://www.apache.org/licenses/LICENSE-2.0.
6
6
  */
7
- import { valid, scale } from 'chroma-js';
8
- import { rgba, darken, lighten } from 'polished';
7
+ import { getScale, parseToRgba } from 'color2k';
8
+ import { getContrast, rgba, darken, lighten } from 'polished';
9
9
  import get from 'lodash.get';
10
10
  import memoize from 'lodash.memoize';
11
11
  import DEFAULT_THEME from '../elements/theme/index.js';
12
- import PALETTE from '../elements/palette/index.js';
13
12
 
14
- const PALETTE_SIZE = Object.keys(PALETTE.blue).length;
15
13
  const adjust = (color, expected, actual) => {
16
14
  if (expected !== actual) {
17
15
  const amount = Math.abs(expected - actual) / 100 * 0.05;
@@ -42,7 +40,79 @@ const toHex = (hue, shade, offset, scheme) => {
42
40
  }
43
41
  return retVal;
44
42
  };
45
- const toColor = (colors, palette, scheme, hue, shade, offset, transparency) => {
43
+ const isValidColor = maybeColor => {
44
+ let retVal = ['currentcolor', 'inherit', 'transparent'].includes(maybeColor);
45
+ if (!retVal) {
46
+ try {
47
+ retVal = !!parseToRgba(maybeColor);
48
+ } catch {
49
+ retVal = false;
50
+ }
51
+ }
52
+ return retVal;
53
+ };
54
+ function findNearestIndex(target, arr) {
55
+ let startIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
56
+ if (typeof target !== 'number' || isNaN(target)) {
57
+ throw new Error('Target must be a number.');
58
+ }
59
+ if (!Array.isArray(arr)) {
60
+ throw new Error('Second argument must be an array.');
61
+ }
62
+ let left = startIndex;
63
+ let right = arr.length - 1;
64
+ if (target < arr[left]) return left;
65
+ if (target > arr[right]) return right;
66
+ while (left <= right) {
67
+ const mid = Math.floor((left + right) / 2);
68
+ if (arr[mid] === target) {
69
+ return mid;
70
+ } else if (arr[mid] < target) {
71
+ left = mid + 1;
72
+ } else {
73
+ right = mid - 1;
74
+ }
75
+ }
76
+ return arr[left] - target < target - arr[right] ? left : right;
77
+ }
78
+ const OFFSET_TO_TARGET_RATIO = {
79
+ 100: 1.08,
80
+ 200: 1.2,
81
+ 300: 1.35,
82
+ 400: 2,
83
+ 500: 2.8,
84
+ 600: 3.3,
85
+ 700: 5,
86
+ 800: 10,
87
+ 900: 13,
88
+ 1000: 16,
89
+ 1100: 17.5,
90
+ 1200: 19
91
+ };
92
+ const generateColorScale = memoize(color => {
93
+ const scaleSize = 200;
94
+ const _scale = getScale('#FFF', color, '#000');
95
+ const scale = x => _scale(x / scaleSize);
96
+ const colors = [];
97
+ const contrastRatios = [];
98
+ for (let i = 0; i <= scaleSize; i++) {
99
+ const _color = scale(i);
100
+ colors.push(_color);
101
+ contrastRatios.push(getContrast('#FFF', _color));
102
+ }
103
+ const palette = {};
104
+ let startIndex = 0;
105
+ for (const offset in OFFSET_TO_TARGET_RATIO) {
106
+ if (Object.prototype.hasOwnProperty.call(OFFSET_TO_TARGET_RATIO, offset)) {
107
+ const ratio = OFFSET_TO_TARGET_RATIO[offset];
108
+ const nearestIndex = findNearestIndex(ratio, contrastRatios, startIndex);
109
+ startIndex = nearestIndex + 1;
110
+ palette[offset] = colors[nearestIndex];
111
+ }
112
+ }
113
+ return palette;
114
+ });
115
+ const toColor = (colors, palette, opacity, scheme, hue, shade, offset, transparency) => {
46
116
  let retVal;
47
117
  let _hue = colors[hue] || hue;
48
118
  if (Object.hasOwn(palette, _hue)) {
@@ -50,22 +120,20 @@ const toColor = (colors, palette, scheme, hue, shade, offset, transparency) => {
50
120
  }
51
121
  if (typeof _hue === 'object') {
52
122
  retVal = toHex(_hue, shade, offset, scheme);
53
- } else if (_hue === 'transparent' || valid(_hue)) {
123
+ } else if (isValidColor(_hue)) {
54
124
  if (shade === undefined) {
55
125
  retVal = _hue;
56
126
  } else {
57
- const _colors = scale([PALETTE.white, _hue, PALETTE.black]).correctLightness().colors(PALETTE_SIZE + 2);
58
- _hue = _colors.reduce((_retVal, color, index) => {
59
- if (index > 0 && index <= PALETTE_SIZE) {
60
- _retVal[index * 100] = color;
61
- }
62
- return _retVal;
63
- }, {});
127
+ _hue = generateColorScale(_hue);
64
128
  retVal = toHex(_hue, shade, offset, scheme);
65
129
  }
66
130
  }
67
131
  if (retVal && transparency) {
68
- retVal = rgba(retVal, transparency);
132
+ const alpha = transparency > 1 ? opacity[transparency] : transparency;
133
+ if (alpha === undefined) {
134
+ throw new Error('Error: invalid `transparency` parameter');
135
+ }
136
+ retVal = rgba(retVal, alpha);
69
137
  }
70
138
  return retVal;
71
139
  };
@@ -79,6 +147,41 @@ const toProperty = (object, path) => {
79
147
  throw new TypeError(`Error: unexpected '${typeof retVal}' type for color variable "${path}"`);
80
148
  }
81
149
  };
150
+ const fromRgba = value => {
151
+ let retVal;
152
+ const regex = /rgba\s*\(\s*(?<property>[#\w.]+)\s*,\s*(?<alpha>[\w.]+)\s*\)/gu;
153
+ const _rgba = regex.exec(value);
154
+ if (_rgba && _rgba.groups) {
155
+ const property = _rgba.groups.property;
156
+ const transparency = parseFloat(_rgba.groups.alpha);
157
+ retVal = {
158
+ property,
159
+ transparency
160
+ };
161
+ } else {
162
+ throw new Error(`Error: invalid \`rgba\` value "${value}"`);
163
+ }
164
+ return retVal;
165
+ };
166
+ const fromVariable = (variable, variables, palette) => {
167
+ const retVal = {};
168
+ let property = toProperty(variables, variable);
169
+ if (property.startsWith('rgba')) {
170
+ const value = fromRgba(property);
171
+ property = value.property;
172
+ retVal.transparency = value.transparency;
173
+ }
174
+ const [key, value] = property.split(/\.(?<value>.*)/u);
175
+ if (key === 'palette') {
176
+ retVal.hue = toProperty(palette, value);
177
+ } else {
178
+ retVal.hue = key;
179
+ if (value !== undefined) {
180
+ retVal.shade = parseInt(value, 10);
181
+ }
182
+ }
183
+ return retVal;
184
+ };
82
185
  const getColor = memoize(_ref => {
83
186
  let {
84
187
  dark,
@@ -102,20 +205,17 @@ const getColor = memoize(_ref => {
102
205
  let _hue = mode?.hue || hue;
103
206
  let _shade = mode?.shade === undefined ? shade : mode.shade;
104
207
  const _offset = mode?.offset === undefined ? offset : mode.offset;
105
- const _transparency = mode?.transparency === undefined ? transparency : mode.transparency;
208
+ let _transparency = mode?.transparency === undefined ? transparency : mode.transparency;
106
209
  if (variable) {
107
210
  const _variables = variables?.[scheme] ? variables[scheme] : DEFAULT_THEME.colors.variables[scheme];
108
- const property = toProperty(_variables, variable);
109
- const [key, value] = property.split(/\.(?<value>.*)/u);
110
- if (key === 'palette') {
111
- _hue = toProperty(palette, value);
112
- } else {
113
- _hue = key;
114
- _shade = parseInt(value, 10);
115
- }
211
+ const value = fromVariable(variable, _variables, palette);
212
+ _hue = value.hue;
213
+ _shade = value.shade;
214
+ _transparency = _transparency === undefined ? value.transparency : _transparency;
116
215
  }
117
216
  if (_hue) {
118
- retVal = toColor(colors, palette, scheme, _hue, _shade, _offset, _transparency);
217
+ const opacity = theme.opacity && Object.keys(theme.opacity).length > 0 ? theme.opacity : DEFAULT_THEME.opacity;
218
+ retVal = toColor(colors, palette, opacity, scheme, _hue, _shade, _offset, _transparency);
119
219
  }
120
220
  if (retVal === undefined) {
121
221
  throw new Error('Error: invalid `getColor` parameters');
@@ -140,6 +240,7 @@ const getColor = memoize(_ref => {
140
240
  shade,
141
241
  colors: theme.colors,
142
242
  palette: theme.palette,
243
+ opacity: theme.opacity,
143
244
  transparency,
144
245
  variable
145
246
  });
@@ -23,9 +23,30 @@ const animationStyles = (position, options) => {
23
23
  } else {
24
24
  transformFunction = 'translateX';
25
25
  }
26
- const animationName = keyframes(["0%{transform:", "(", ");}"], transformFunction, translateValue);
26
+ const animationName = keyframes(["0%{transform:", "(", ");pointer-events:none;}100%{pointer-events:auto;}"], transformFunction, translateValue);
27
27
  return css(["&", " ", "{animation:0.2s cubic-bezier(0.15,0.85,0.35,1.2) ", ";}"], options.animationModifier, options.childSelector || '> *', animationName);
28
28
  };
29
+ const colorStyles = theme => {
30
+ const backgroundColor = getColor({
31
+ theme,
32
+ variable: 'background.raised'
33
+ });
34
+ const borderColor = getColor({
35
+ theme,
36
+ variable: 'border.default'
37
+ });
38
+ const boxShadowColor = getColor({
39
+ variable: 'shadow.medium',
40
+ theme
41
+ });
42
+ const boxShadowBlurRadius = `${theme.space.base * (theme.colors.base === 'dark' ? 5 : 6)}px`;
43
+ const boxShadowOffsetY = `${theme.space.base * (theme.colors.base === 'dark' ? 4 : 5)}px`;
44
+ const foregroundColor = getColor({
45
+ theme,
46
+ variable: 'foreground.default'
47
+ });
48
+ return css(["border-color:", ";box-shadow:", ";background-color:", ";color:", ";"], borderColor, theme.shadows.lg(boxShadowOffsetY, boxShadowBlurRadius, boxShadowColor), backgroundColor, foregroundColor);
49
+ };
29
50
  const hiddenStyles = options => {
30
51
  const transition = 'opacity 0.2s ease-in-out, 0.2s visibility 0s linear';
31
52
  return css(["transition:", ";visibility:hidden;opacity:0;"], options.animationModifier && transition);
@@ -43,21 +64,7 @@ function menuStyles(position) {
43
64
  } else {
44
65
  marginProperty = 'margin-right';
45
66
  }
46
- return css(["position:absolute;z-index:", ";", ":", ";line-height:0;font-size:0.01px;& ", "{display:inline-block;position:relative;margin:0;box-sizing:border-box;border:", " ", ";border-radius:", ";box-shadow:", ";background-color:", ";cursor:default;padding:0;text-align:", ";white-space:normal;color:", ";font-size:", ";font-weight:", ";direction:", ";:focus{outline:none;}}", ";", ";"], options.zIndex || 0, marginProperty, options.margin, options.childSelector || '> *', theme.borders.sm, getColor({
47
- theme,
48
- variable: 'border.default'
49
- }), theme.borderRadii.md, theme.shadows.lg(`${theme.space.base * 5}px`, `${theme.space.base * 7.5}px`, getColor({
50
- theme,
51
- hue: 'chromeHue',
52
- shade: 600,
53
- transparency: 0.15
54
- })), getColor({
55
- theme,
56
- variable: 'background.raised'
57
- }), theme.rtl ? 'right' : 'left', getColor({
58
- theme,
59
- variable: 'foreground.default'
60
- }), theme.fontSizes.md, theme.fontWeights.regular, theme.rtl && 'rtl', options.animationModifier && animationStyles(position, options), options.hidden && hiddenStyles(options));
67
+ return css(["position:absolute;z-index:", ";", ":", ";line-height:0;font-size:0.01px;color-scheme:only ", ";& ", "{display:inline-block;position:relative;margin:0;box-sizing:border-box;border:", ";border-radius:", ";cursor:default;padding:0;text-align:", ";white-space:normal;font-size:", ";font-weight:", ";direction:", ";", ";:focus{outline:none;}}", ";", ";"], options.zIndex || 0, marginProperty, options.margin, p => p.theme.colors.base, options.childSelector || '> *', theme.borders.sm, theme.borderRadii.md, theme.rtl ? 'right' : 'left', theme.fontSizes.md, theme.fontWeights.regular, theme.rtl && 'rtl', colorStyles(theme), options.animationModifier && animationStyles(position, options), options.hidden && hiddenStyles(options));
61
68
  }
62
69
 
63
70
  export { menuStyles as default };