newspack-components 4.9.2 → 4.10.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.
Files changed (103) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/DEVELOPMENT.md +13 -14
  3. package/dist/cjs/_mixins.scss +0 -2
  4. package/dist/cjs/card/core-card.js +6 -3
  5. package/dist/cjs/card/core-card.test.js +76 -5
  6. package/dist/cjs/card/style-core.scss +12 -3
  7. package/dist/cjs/card/style.scss +4 -7
  8. package/dist/cjs/card-feature/index.js +2 -1
  9. package/dist/cjs/card-feature/index.test.js +13 -0
  10. package/dist/cjs/card-feature/style.scss +5 -0
  11. package/dist/cjs/color-picker/index.js +26 -15
  12. package/dist/cjs/color-picker/index.test.js +47 -0
  13. package/dist/cjs/color-picker/style.scss +13 -10
  14. package/dist/cjs/debug-badge/style.scss +1 -1
  15. package/dist/cjs/divider/index.js +2 -2
  16. package/dist/cjs/divider/style.scss +7 -5
  17. package/dist/cjs/grid/style.scss +4 -16
  18. package/dist/cjs/image-upload/index.js +9 -3
  19. package/dist/cjs/image-upload/style.scss +3 -0
  20. package/dist/cjs/index.js +0 -7
  21. package/dist/cjs/info-button/style.scss +1 -1
  22. package/dist/cjs/modal/style.scss +7 -8
  23. package/dist/cjs/page/style.scss +2 -4
  24. package/dist/cjs/plugin-settings/style.scss +1 -1
  25. package/dist/cjs/section-header/index.js +5 -2
  26. package/dist/cjs/section-header/style.scss +3 -3
  27. package/dist/cjs/settings/style.scss +1 -1
  28. package/dist/cjs/style-card/index.js +5 -6
  29. package/dist/cjs/style-card/style.scss +6 -10
  30. package/dist/cjs/style.scss +3 -2
  31. package/dist/cjs/tabbed-navigation/style.scss +0 -1
  32. package/dist/cjs/with-wizard-screen/style.scss +3 -2
  33. package/dist/cjs/wizard/index.js +2 -0
  34. package/dist/esm/_mixins.scss +0 -2
  35. package/dist/esm/card/core-card.js +6 -3
  36. package/dist/esm/card/core-card.test.js +76 -1
  37. package/dist/esm/card/style-core.scss +12 -3
  38. package/dist/esm/card/style.scss +4 -7
  39. package/dist/esm/card-feature/index.js +2 -1
  40. package/dist/esm/card-feature/index.test.js +13 -0
  41. package/dist/esm/card-feature/style.scss +5 -0
  42. package/dist/esm/color-picker/index.js +25 -8
  43. package/dist/esm/color-picker/index.test.js +47 -0
  44. package/dist/esm/color-picker/style.scss +13 -10
  45. package/dist/esm/debug-badge/style.scss +1 -1
  46. package/dist/esm/divider/index.js +2 -2
  47. package/dist/esm/divider/style.scss +7 -5
  48. package/dist/esm/grid/style.scss +4 -16
  49. package/dist/esm/image-upload/index.js +9 -3
  50. package/dist/esm/image-upload/style.scss +3 -0
  51. package/dist/esm/index.js +0 -1
  52. package/dist/esm/info-button/style.scss +1 -1
  53. package/dist/esm/modal/style.scss +7 -8
  54. package/dist/esm/page/style.scss +2 -4
  55. package/dist/esm/plugin-settings/style.scss +1 -1
  56. package/dist/esm/section-header/index.js +5 -2
  57. package/dist/esm/section-header/style.scss +3 -3
  58. package/dist/esm/settings/style.scss +1 -1
  59. package/dist/esm/style-card/index.js +6 -7
  60. package/dist/esm/style-card/style.scss +6 -10
  61. package/dist/esm/style.scss +3 -2
  62. package/dist/esm/tabbed-navigation/style.scss +0 -1
  63. package/dist/esm/with-wizard-screen/style.scss +3 -2
  64. package/dist/esm/wizard/index.js +2 -0
  65. package/package.json +7 -7
  66. package/src/_mixins.scss +0 -2
  67. package/src/card/core-card.js +5 -1
  68. package/src/card/core-card.test.js +28 -1
  69. package/src/card/style-core.scss +12 -3
  70. package/src/card/style.scss +4 -7
  71. package/src/card-feature/index.test.js +7 -0
  72. package/src/card-feature/index.tsx +1 -0
  73. package/src/card-feature/style.scss +5 -0
  74. package/src/color-picker/index.js +20 -6
  75. package/src/color-picker/index.test.js +25 -0
  76. package/src/color-picker/style.scss +13 -10
  77. package/src/debug-badge/style.scss +1 -1
  78. package/src/divider/README.md +2 -2
  79. package/src/divider/index.js +1 -1
  80. package/src/divider/style.scss +7 -5
  81. package/src/grid/style.scss +4 -16
  82. package/src/image-upload/index.js +7 -3
  83. package/src/image-upload/style.scss +3 -0
  84. package/src/index.js +0 -1
  85. package/src/info-button/style.scss +1 -1
  86. package/src/modal/style.scss +7 -8
  87. package/src/page/style.scss +2 -4
  88. package/src/plugin-settings/style.scss +1 -1
  89. package/src/section-header/index.js +4 -1
  90. package/src/section-header/style.scss +3 -3
  91. package/src/settings/style.scss +1 -1
  92. package/src/style-card/index.js +5 -6
  93. package/src/style-card/style.scss +6 -10
  94. package/src/style.scss +3 -2
  95. package/src/tabbed-navigation/style.scss +0 -1
  96. package/src/with-wizard-screen/style.scss +3 -2
  97. package/src/wizard/index.js +2 -0
  98. package/dist/cjs/box-contrast/index.js +0 -53
  99. package/dist/cjs/utils/color.js +0 -35
  100. package/dist/esm/box-contrast/index.js +0 -48
  101. package/dist/esm/utils/color.js +0 -29
  102. package/src/box-contrast/index.tsx +0 -44
  103. package/src/utils/color.ts +0 -32
@@ -1,6 +1,6 @@
1
1
  .newspack-card:not(.newspack-settings__no-border) {
2
2
  .newspack-action-card__region-children {
3
- > .newspack-grid {
3
+ > .newspack-grid:not(.newspack-grid--no-margin) {
4
4
  margin: 32px 0 0 !important;
5
5
  }
6
6
  }
@@ -32,6 +32,7 @@ import classnames from 'classnames';
32
32
  * @property {boolean} [centered=false] - Indicates if the header is centered.
33
33
  * @property {?string} [className=null] - Additional CSS class name, applied to the outer container.
34
34
  * @property {string|Function|*} [description] - Description of the section.
35
+ * @property {boolean} [fullWidthText] - Lets the title and description span the full header width. With a back nav they are otherwise capped at half, which suits a page-wide header but not one already sitting in a column.
35
36
  * @property {number} [heading=2] - HTML heading level, e.g., 1 for h1, 2 for h2, etc.
36
37
  * @property {string|Function|*} [icon] - Icon to display in the header.
37
38
  * @property {boolean} [isWhite=false] - Indicates if the header should use a white theme.
@@ -57,6 +58,7 @@ const SectionHeader = ( {
57
58
  centered = false,
58
59
  className = null,
59
60
  description = '',
61
+ fullWidthText = false,
60
62
  heading = 2,
61
63
  icon = null,
62
64
  isWhite = false,
@@ -71,7 +73,7 @@ const SectionHeader = ( {
71
73
  children = null,
72
74
  } ) => {
73
75
  // If id is in the URL as a scrollTo param, scroll to it on render.
74
- const ref = useRef();
76
+ const ref = useRef( undefined );
75
77
  useEffect( () => {
76
78
  const params = new Proxy( new URLSearchParams( window.location.search ), {
77
79
  get: ( searchParams, prop ) => searchParams.get( prop ),
@@ -154,6 +156,7 @@ const SectionHeader = ( {
154
156
  className={ classnames(
155
157
  'newspack-section-header__container',
156
158
  backNav && 'newspack-section-header--has-back-nav',
159
+ fullWidthText && 'newspack-section-header--full-width-text',
157
160
  primaryAction && 'newspack-section-header--has-primary-action',
158
161
  className
159
162
  ) }
@@ -9,7 +9,7 @@
9
9
 
10
10
  .newspack-section-header {
11
11
  flex: 1;
12
- margin: 64px 0 32px;
12
+ margin: wp-vars.$grid-unit-60 0 wp-vars.$grid-unit-40;
13
13
 
14
14
  &__container {
15
15
  position: relative;
@@ -17,7 +17,7 @@
17
17
  text-wrap: balance;
18
18
  }
19
19
  &:not(:first-child) {
20
- margin-top: 48px;
20
+ margin-top: wp-vars.$grid-unit-60;
21
21
  }
22
22
  &:has(> .newspack-section-header--no-margin) {
23
23
  margin-top: 0;
@@ -34,7 +34,7 @@
34
34
  flex-direction: row;
35
35
  }
36
36
  }
37
- &.newspack-section-header--has-back-nav {
37
+ &.newspack-section-header--has-back-nav:not(.newspack-section-header--full-width-text) {
38
38
  @include wp-mixins.break-wide {
39
39
  .newspack-section-header__title-container,
40
40
  p {
@@ -145,7 +145,7 @@
145
145
  }
146
146
 
147
147
  & + & {
148
- margin-top: 64px;
148
+ margin-top: wp-vars.$grid-unit-60;
149
149
  }
150
150
  }
151
151
  }
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Component } from '@wordpress/element';
9
9
  import { __ } from '@wordpress/i18n';
10
- import { Button } from '@wordpress/components';
10
+ import { Button, VisuallyHidden } from '@wordpress/components';
11
11
 
12
12
  /**
13
13
  * Internal dependencies
@@ -35,12 +35,11 @@ class StyleCard extends Component {
35
35
  ) : (
36
36
  <img src={ image } alt={ cardTitle + ' ' + __( 'Thumbnail', 'newspack-plugin' ) } />
37
37
  ) }
38
+ { isActive && <VisuallyHidden>{ __( 'Selected', 'newspack-plugin' ) }</VisuallyHidden> }
38
39
  <div className="newspack-style-card__actions">
39
- { isActive ? (
40
- <span className="newspack-style-card__actions__badge">{ __( 'Selected', 'newspack-plugin' ) }</span>
41
- ) : (
40
+ { ! isActive && (
42
41
  <Button
43
- variant="link"
42
+ variant="tertiary"
44
43
  onClick={ onClick }
45
44
  aria-label={ ariaLabel ? ariaLabel : __( 'Select', 'newspack-plugin' ) + ' ' + cardTitle }
46
45
  tabIndex="0"
@@ -48,7 +47,7 @@ class StyleCard extends Component {
48
47
  { __( 'Select', 'newspack-plugin' ) }
49
48
  </Button>
50
49
  ) }
51
- { url && <WebPreview url={ url } label={ __( 'View Demo', 'newspack-plugin' ) } variant="link" /> }
50
+ { url && <WebPreview url={ url } label={ __( 'View Demo', 'newspack-plugin' ) } variant="tertiary" /> }
52
51
  </div>
53
52
  </div>
54
53
  { cardTitle && <div className="newspack-style-card__title">{ cardTitle }</div> }
@@ -48,11 +48,13 @@
48
48
 
49
49
  .newspack-style-card__is-active & {
50
50
  border-color: var(--wp-admin-theme-color);
51
- box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color);
52
51
 
53
- img {
54
- position: relative;
55
- z-index: -1;
52
+ &::after {
53
+ box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color);
54
+ content: "";
55
+ inset: 0;
56
+ pointer-events: none;
57
+ position: absolute;
56
58
  }
57
59
  }
58
60
  }
@@ -74,18 +76,12 @@
74
76
  display: none;
75
77
  }
76
78
 
77
- &__badge,
78
79
  .components-button {
79
80
  margin: 4px;
80
81
  opacity: 0;
81
82
  transition: opacity 125ms ease-in-out;
82
83
  }
83
84
 
84
- &__badge {
85
- color: var(--wp-admin-theme-color);
86
- font-weight: bold;
87
- }
88
-
89
85
  .newspack-style-card__is-active & {
90
86
  box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color);
91
87
  }
package/src/style.scss CHANGED
@@ -1,4 +1,5 @@
1
1
  @use "~@wordpress/base-styles/colors" as wp-colors;
2
+ @use "~@wordpress/base-styles/variables" as wp-vars;
2
3
  @use "../../colors/colors.module" as np-colors;
3
4
 
4
5
  :root {
@@ -21,14 +22,14 @@
21
22
  gap: 16px;
22
23
  justify-content: flex-start;
23
24
  align-items: center;
24
- margin: 64px 0 32px;
25
+ margin: wp-vars.$grid-unit-60 0 wp-vars.$grid-unit-40;
25
26
 
26
27
  &:empty {
27
28
  display: none;
28
29
  }
29
30
 
30
31
  + .newspack-card {
31
- margin-top: 64px;
32
+ margin-top: wp-vars.$grid-unit-60;
32
33
  }
33
34
  }
34
35
 
@@ -54,7 +54,6 @@
54
54
 
55
55
  &[data-disabled],
56
56
  &[aria-disabled="true"] {
57
- /* stylelint-disable-next-line plugin-wpds/no-unknown-ds-tokens -- the plugin's token list lags the prebuilt design-tokens.css names. */
58
57
  color: var( --wpds-color-foreground-interactive-neutral-disabled, #{wp-colors.$gray-600} );
59
58
  pointer-events: none;
60
59
  }
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  @use "~@wordpress/base-styles/colors" as wp-colors;
6
+ @use "~@wordpress/base-styles/variables" as wp-vars;
6
7
  @use "../../../colors/colors.module" as np-colors;
7
8
 
8
9
  .newspack-wizard {
@@ -94,10 +95,10 @@
94
95
  background: wp-colors.$gray-300;
95
96
  border: 0;
96
97
  height: 1px;
97
- margin: 32px 0;
98
+ margin: wp-vars.$grid-unit-40 0;
98
99
 
99
100
  @media screen and ( min-width: 744px ) {
100
- margin: 64px 0;
101
+ margin: wp-vars.$grid-unit-60 0;
101
102
  }
102
103
  }
103
104
  &:not(.newspack-wizard__content--full-width) {
@@ -371,6 +371,7 @@ const Wizard = (
371
371
  { mainActions.map( ( action, index ) => (
372
372
  <Button
373
373
  key={ index }
374
+ aria-label={ action.ariaLabel }
374
375
  className="newspack-wizard__actions__main"
375
376
  href={ action.href }
376
377
  icon={ resolveIcon( action.icon ) }
@@ -404,6 +405,7 @@ const Wizard = (
404
405
  { group.map( ( action, index ) => (
405
406
  <MenuItem
406
407
  key={ index }
408
+ aria-label={ action.ariaLabel }
407
409
  className={
408
410
  action.type === 'primary' || action.type === 'secondary'
409
411
  ? 'newspack-wizard__actions__more__main'
@@ -1,53 +0,0 @@
1
- "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
- Object.defineProperty(exports, "__esModule", {
5
- value: true
6
- });
7
- exports["default"] = void 0;
8
- var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
9
- var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
10
- var _color = require("../utils/color");
11
- var _jsxRuntime = require("react/jsx-runtime");
12
- var _excluded = ["hexColor", "isInverted", "children"];
13
- /**
14
- * Box Contrast
15
- *
16
- * can be used to dynamically assign black or white color/background-color based on a hex color.
17
- * Black/white can be assigned to either text or background-color.
18
- */
19
- /**
20
- * Dependencies
21
- */
22
- /**
23
- * Box Contrast component
24
- *
25
- * @return JSX.Element
26
- */
27
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
28
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
29
- var BoxContrast = function BoxContrast(_ref) {
30
- var hexColor = _ref.hexColor,
31
- _ref$isInverted = _ref.isInverted,
32
- isInverted = _ref$isInverted === void 0 ? false : _ref$isInverted,
33
- children = _ref.children,
34
- props = (0, _objectWithoutProperties2["default"])(_ref, _excluded);
35
- var contrastColor;
36
- if (hexColor === '#f0f0f0') {
37
- contrastColor = '#1e1e1e';
38
- } else {
39
- contrastColor = (0, _color.getContrast)(hexColor);
40
- }
41
- var style = isInverted ? {
42
- color: hexColor,
43
- backgoundColor: contrastColor
44
- } : {
45
- backgroundColor: hexColor,
46
- color: contrastColor
47
- };
48
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", _objectSpread(_objectSpread({}, props), {}, {
49
- style: style,
50
- children: children
51
- }));
52
- };
53
- var _default = exports["default"] = BoxContrast;
@@ -1,35 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.getContrast = getContrast;
7
- /**
8
- * Determine if black or white should be used based on a contrast ratio.
9
- *
10
- * @param hexcolor Hex code for determining contrast
11
- * @return black or white string
12
- */
13
- function getContrast(hexcolor) {
14
- if (hexcolor.charAt(0) === '#') {
15
- hexcolor = hexcolor.slice(1);
16
- }
17
-
18
- // Normalize to 6 character hex code if needed
19
- if (hexcolor.length === 3) {
20
- hexcolor = hexcolor.split('').map(function (hex) {
21
- return hex + hex;
22
- }).join('');
23
- }
24
-
25
- // Convert to RGB value
26
- var r = parseInt(hexcolor.substring(0, 2), 16);
27
- var g = parseInt(hexcolor.substring(2, 4), 16);
28
- var b = parseInt(hexcolor.substring(4), 16);
29
-
30
- // Get YIQ ratio
31
- var yiq = (r * 299 + g * 587 + b * 114) / 1000;
32
-
33
- // Check contrast
34
- return yiq >= 128 ? 'black' : 'white';
35
- }
@@ -1,48 +0,0 @@
1
- import _defineProperty from "@babel/runtime/helpers/defineProperty";
2
- import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
- var _excluded = ["hexColor", "isInverted", "children"];
4
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
6
- /**
7
- * Box Contrast
8
- *
9
- * can be used to dynamically assign black or white color/background-color based on a hex color.
10
- * Black/white can be assigned to either text or background-color.
11
- */
12
-
13
- /**
14
- * Dependencies
15
- */
16
- import { getContrast } from '../utils/color';
17
-
18
- /**
19
- * Box Contrast component
20
- *
21
- * @return JSX.Element
22
- */
23
- import { jsx as _jsx } from "react/jsx-runtime";
24
- var BoxContrast = function BoxContrast(_ref) {
25
- var hexColor = _ref.hexColor,
26
- _ref$isInverted = _ref.isInverted,
27
- isInverted = _ref$isInverted === void 0 ? false : _ref$isInverted,
28
- children = _ref.children,
29
- props = _objectWithoutProperties(_ref, _excluded);
30
- var contrastColor;
31
- if (hexColor === '#f0f0f0') {
32
- contrastColor = '#1e1e1e';
33
- } else {
34
- contrastColor = getContrast(hexColor);
35
- }
36
- var style = isInverted ? {
37
- color: hexColor,
38
- backgoundColor: contrastColor
39
- } : {
40
- backgroundColor: hexColor,
41
- color: contrastColor
42
- };
43
- return /*#__PURE__*/_jsx("div", _objectSpread(_objectSpread({}, props), {}, {
44
- style: style,
45
- children: children
46
- }));
47
- };
48
- export default BoxContrast;
@@ -1,29 +0,0 @@
1
- /**
2
- * Determine if black or white should be used based on a contrast ratio.
3
- *
4
- * @param hexcolor Hex code for determining contrast
5
- * @return black or white string
6
- */
7
- export function getContrast(hexcolor) {
8
- if (hexcolor.charAt(0) === '#') {
9
- hexcolor = hexcolor.slice(1);
10
- }
11
-
12
- // Normalize to 6 character hex code if needed
13
- if (hexcolor.length === 3) {
14
- hexcolor = hexcolor.split('').map(function (hex) {
15
- return hex + hex;
16
- }).join('');
17
- }
18
-
19
- // Convert to RGB value
20
- var r = parseInt(hexcolor.substring(0, 2), 16);
21
- var g = parseInt(hexcolor.substring(2, 4), 16);
22
- var b = parseInt(hexcolor.substring(4), 16);
23
-
24
- // Get YIQ ratio
25
- var yiq = (r * 299 + g * 587 + b * 114) / 1000;
26
-
27
- // Check contrast
28
- return yiq >= 128 ? 'black' : 'white';
29
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * Box Contrast
3
- *
4
- * can be used to dynamically assign black or white color/background-color based on a hex color.
5
- * Black/white can be assigned to either text or background-color.
6
- */
7
-
8
- /**
9
- * Dependencies
10
- */
11
- import { getContrast } from '../utils/color';
12
-
13
- /**
14
- * Box Contrast component
15
- *
16
- * @return JSX.Element
17
- */
18
- const BoxContrast = ( {
19
- hexColor,
20
- isInverted = false,
21
- children,
22
- ...props
23
- }: {
24
- children: string | JSX.Element;
25
- hexColor: string;
26
- isInverted?: boolean;
27
- className?: string;
28
- } ) => {
29
- let contrastColor;
30
- if ( hexColor === '#f0f0f0' ) {
31
- contrastColor = '#1e1e1e';
32
- } else {
33
- contrastColor = getContrast( hexColor );
34
- }
35
- const style = isInverted ? { color: hexColor, backgoundColor: contrastColor } : { backgroundColor: hexColor, color: contrastColor };
36
-
37
- return (
38
- <div { ...props } style={ style }>
39
- { children }
40
- </div>
41
- );
42
- };
43
-
44
- export default BoxContrast;
@@ -1,32 +0,0 @@
1
- /**
2
- * Determine if black or white should be used based on a contrast ratio.
3
- *
4
- * @param hexcolor Hex code for determining contrast
5
- * @return black or white string
6
- */
7
- export function getContrast( hexcolor: string ) {
8
- if ( hexcolor.charAt( 0 ) === '#' ) {
9
- hexcolor = hexcolor.slice( 1 );
10
- }
11
-
12
- // Normalize to 6 character hex code if needed
13
- if ( hexcolor.length === 3 ) {
14
- hexcolor = hexcolor
15
- .split( '' )
16
- .map( function ( hex ) {
17
- return hex + hex;
18
- } )
19
- .join( '' );
20
- }
21
-
22
- // Convert to RGB value
23
- const r = parseInt( hexcolor.substring( 0, 2 ), 16 );
24
- const g = parseInt( hexcolor.substring( 2, 4 ), 16 );
25
- const b = parseInt( hexcolor.substring( 4 ), 16 );
26
-
27
- // Get YIQ ratio
28
- const yiq = ( r * 299 + g * 587 + b * 114 ) / 1000;
29
-
30
- // Check contrast
31
- return yiq >= 128 ? 'black' : 'white';
32
- }