@scality/core-ui 0.201.0 → 0.203.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.
@@ -1 +1 @@
1
- {"version":3,"file":"Editor.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/editor/Editor.component.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,wBAAgB,aAAa,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAIvD;AAED,wBAAgB,8BAA8B,IAAI,SAAS,CA4E1D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,MAAM,GAAI,yDAOpB,WAAW,4CAiDb,CAAC"}
1
+ {"version":3,"file":"Editor.component.d.ts","sourceRoot":"","sources":["../../../src/lib/components/editor/Editor.component.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ/C,wBAAgB,aAAa,CAAC,CAAC,EAAE,aAAa,GAAG,OAAO,CAIvD;AAED,wBAAgB,8BAA8B,IAAI,SAAS,CA4E1D;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,CAAC;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,MAAM,GAAI,yDAOpB,WAAW,4CAkDb,CAAC"}
@@ -111,6 +111,7 @@ export const Editor = ({ value, onChange, readOnly = false, language = 'json', h
111
111
  autocompletion: true,
112
112
  highlightActiveLine: true,
113
113
  highlightActiveLineGutter: true,
114
+ highlightSelectionMatches: false,
114
115
  indentOnInput: true,
115
116
  bracketMatching: true,
116
117
  closeBrackets: true,
@@ -1 +1 @@
1
- {"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../../src/lib/components/editor/editorTheme.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAM5D;AAyBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CAsF/D"}
1
+ {"version":3,"file":"editorTheme.d.ts","sourceRoot":"","sources":["../../../src/lib/components/editor/editorTheme.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAM5D;AAyBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CAuF/D"}
@@ -40,11 +40,12 @@ export function createEditorTheme(theme) {
40
40
  '&': {
41
41
  backgroundColor: theme.backgroundLevel1,
42
42
  color: theme.textPrimary,
43
+ fontFamily: "'Courier New', monospace",
44
+ fontSize: '12px',
45
+ lineHeight: '1.6',
43
46
  },
44
47
  '.cm-content': {
45
48
  caretColor: theme.textPrimary,
46
- fontFamily: "'Courier New', monospace",
47
- fontSize: '12px',
48
49
  },
49
50
  '.cm-cursor, .cm-dropCursor': {
50
51
  borderLeftColor: theme.textPrimary,
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAYA;mCACmC;AACnC,eAAO,MAAM,oBAAoB,GAAI,QAAG,MAAM,UAAK,QAGlD,CAAC;AAEF;mCACmC;AACnC,eAAO,MAAM,uBAAuB,SAAU,UAAK,QAIlD,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MACjB,CAAC;AAErC,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAc5D,CAAC;AAmBF,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,aAAa,MAAM,EACnB,aAAa,MAAM,KAClB,MAAM,GAAG,IASX,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,MAahD,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,UAAS,sBAA2B,KACnC,MAoBF,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAcA;mCACmC;AACnC,eAAO,MAAM,oBAAoB,GAAI,QAAG,MAAM,UAAK,QAGlD,CAAC;AAEF;mCACmC;AACnC,eAAO,MAAM,uBAAuB,SAAU,UAAK,QAIlD,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,kBAAkB,GAAI,SAAS,MAAM,KAAG,MACjB,CAAC;AAErC,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAc5D,CAAC;AASF,eAAO,MAAM,eAAe,GAC1B,SAAS,MAAM,EACf,aAAa,MAAM,EACnB,aAAa,MAAM,KAClB,MAAM,GAAG,IAeX,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,KAAK,MAAM,KAAG,MAahD,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,UAAS,sBAA2B,KACnC,MAoBF,CAAC"}
package/dist/utils.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { getLuminance } from 'polished';
1
2
  const RGB_HEX = /^#?(?:([\da-f]{3})[\da-f]?|([\da-f]{6})(?:[\da-f]{2})?)$/i;
2
3
  /** Ensure the consistency of colors between old and new colors */
3
4
  const variantMapping = {
@@ -37,25 +38,19 @@ export const hex2RGB = (str) => {
37
38
  }
38
39
  throw new Error('Invalid hex string provided');
39
40
  };
40
- // WCAG 2.0 relative luminance
41
- const relativeLuminance = (r, g, b) => {
42
- const [rs, gs, bs] = [r, g, b].map((c) => {
43
- const s = c / 255;
44
- return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
45
- });
46
- return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
47
- };
48
41
  const wcagContrastRatio = (l1, l2) => (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
49
- const luminanceOf = (hex) => {
50
- const [r, g, b] = hex2RGB(hex);
51
- return relativeLuminance(r, g, b);
52
- };
42
+ // Minimum WCAG contrast ratio to consider a text color readable on a background.
43
+ // 3.0 corresponds to WCAG AA for large text — same threshold used by MUI.
44
+ const CONTRAST_THRESHOLD = 3;
53
45
  export const getContrastText = (bgColor, textPrimary, textReverse) => {
54
46
  try {
55
- const bgLum = luminanceOf(bgColor);
56
- const primaryContrast = wcagContrastRatio(luminanceOf(textPrimary), bgLum);
57
- const reverseContrast = wcagContrastRatio(luminanceOf(textReverse), bgLum);
58
- return reverseContrast > primaryContrast ? textReverse : textPrimary;
47
+ const bgLum = getLuminance(bgColor);
48
+ const primaryLum = getLuminance(textPrimary);
49
+ const reverseLum = getLuminance(textReverse);
50
+ const lighterText = primaryLum >= reverseLum ? textPrimary : textReverse;
51
+ const darkerText = primaryLum >= reverseLum ? textReverse : textPrimary;
52
+ const lighterContrast = wcagContrastRatio(primaryLum >= reverseLum ? primaryLum : reverseLum, bgLum);
53
+ return lighterContrast >= CONTRAST_THRESHOLD ? lighterText : darkerText;
59
54
  }
60
55
  catch {
61
56
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scality/core-ui",
3
- "version": "0.201.0",
3
+ "version": "0.203.0",
4
4
  "description": "Scality common React component library",
5
5
  "author": "Scality Engineering",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -154,6 +154,7 @@ export const Editor = ({
154
154
  autocompletion: true,
155
155
  highlightActiveLine: true,
156
156
  highlightActiveLineGutter: true,
157
+ highlightSelectionMatches: false,
157
158
  indentOnInput: true,
158
159
  bracketMatching: true,
159
160
  closeBrackets: true,
@@ -46,11 +46,12 @@ export function createEditorTheme(theme: CoreUITheme): Extension {
46
46
  '&': {
47
47
  backgroundColor: theme.backgroundLevel1,
48
48
  color: theme.textPrimary,
49
+ fontFamily: "'Courier New', monospace",
50
+ fontSize: '12px',
51
+ lineHeight: '1.6',
49
52
  },
50
53
  '.cm-content': {
51
54
  caretColor: theme.textPrimary,
52
- fontFamily: "'Courier New', monospace",
53
- fontSize: '12px',
54
55
  },
55
56
  '.cm-cursor, .cm-dropCursor': {
56
57
  borderLeftColor: theme.textPrimary,
@@ -4,22 +4,28 @@ const LIGHT_TEXT = '#EAEAEA';
4
4
  const DARK_TEXT = '#000000';
5
5
 
6
6
  describe('getContrastText', () => {
7
- it('returns textPrimary on dark backgrounds when textPrimary is light', () => {
7
+ it('returns light text on dark backgrounds', () => {
8
8
  expect(getContrastText('#000000', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
9
9
  expect(getContrastText('#1A1A1A', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
10
10
  expect(getContrastText('#121219', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
11
11
  expect(getContrastText('#2F4185', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
12
12
  });
13
13
 
14
- it('returns textReverse on light backgrounds when textPrimary is light', () => {
14
+ it('returns dark text on light backgrounds', () => {
15
15
  expect(getContrastText('#FFFFFF', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
16
16
  expect(getContrastText('#F5F5F5', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
17
17
  expect(getContrastText('#FCFCFC', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
18
18
  });
19
19
 
20
- it('picks the text color with better contrast against a vivid background', () => {
21
- expect(getContrastText('#E9041E', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
22
- expect(getContrastText('#E9041E', '#FFFFFF', '#000000')).toBe('#FFFFFF');
20
+ it('returns light text on saturated colors where WCAG luminance is ambiguous', () => {
21
+ expect(getContrastText('#E60028', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
22
+ expect(getContrastText('#E9041E', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
23
+ expect(getContrastText('#E60028', '#0D0D0D', '#EAEAEA')).toBe('#EAEAEA');
24
+ });
25
+
26
+ it('works regardless of which token is lighter', () => {
27
+ expect(getContrastText('#000000', DARK_TEXT, LIGHT_TEXT)).toBe(LIGHT_TEXT);
28
+ expect(getContrastText('#FFFFFF', DARK_TEXT, LIGHT_TEXT)).toBe(DARK_TEXT);
23
29
  });
24
30
 
25
31
  it('handles 3-character hex shorthand', () => {
@@ -27,12 +33,12 @@ describe('getContrastText', () => {
27
33
  expect(getContrastText('#000', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
28
34
  });
29
35
 
30
- it('handles hex without # prefix', () => {
31
- expect(getContrastText('000000', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
32
- expect(getContrastText('FFFFFF', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
36
+ it('handles rgb color format', () => {
37
+ expect(getContrastText('rgb(0, 0, 0)', LIGHT_TEXT, DARK_TEXT)).toBe(LIGHT_TEXT);
38
+ expect(getContrastText('rgb(255, 255, 255)', LIGHT_TEXT, DARK_TEXT)).toBe(DARK_TEXT);
33
39
  });
34
40
 
35
- it('returns null for non-hex values', () => {
41
+ it('returns null for unparseable values', () => {
36
42
  expect(
37
43
  getContrastText(
38
44
  'linear-gradient(130deg, #9355E7 0%, #2E4AA3 60%)',
@@ -41,8 +47,5 @@ describe('getContrastText', () => {
41
47
  ),
42
48
  ).toBeNull();
43
49
  expect(getContrastText('not-a-color', LIGHT_TEXT, DARK_TEXT)).toBeNull();
44
- expect(
45
- getContrastText('rgb(255, 0, 0)', LIGHT_TEXT, DARK_TEXT),
46
- ).toBeNull();
47
50
  });
48
51
  });
package/src/lib/utils.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { getLuminance } from 'polished';
2
+
1
3
  const RGB_HEX = /^#?(?:([\da-f]{3})[\da-f]?|([\da-f]{6})(?:[\da-f]{2})?)$/i;
2
4
 
3
5
  /** Ensure the consistency of colors between old and new colors */
@@ -45,22 +47,12 @@ export const hex2RGB = (str: string): [number, number, number] => {
45
47
  throw new Error('Invalid hex string provided');
46
48
  };
47
49
 
48
- // WCAG 2.0 relative luminance
49
- const relativeLuminance = (r: number, g: number, b: number): number => {
50
- const [rs, gs, bs] = [r, g, b].map((c) => {
51
- const s = c / 255;
52
- return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
53
- });
54
- return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
55
- };
56
-
57
50
  const wcagContrastRatio = (l1: number, l2: number): number =>
58
51
  (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
59
52
 
60
- const luminanceOf = (hex: string): number => {
61
- const [r, g, b] = hex2RGB(hex);
62
- return relativeLuminance(r, g, b);
63
- };
53
+ // Minimum WCAG contrast ratio to consider a text color readable on a background.
54
+ // 3.0 corresponds to WCAG AA for large text — same threshold used by MUI.
55
+ const CONTRAST_THRESHOLD = 3;
64
56
 
65
57
  export const getContrastText = (
66
58
  bgColor: string,
@@ -68,10 +60,16 @@ export const getContrastText = (
68
60
  textReverse: string,
69
61
  ): string | null => {
70
62
  try {
71
- const bgLum = luminanceOf(bgColor);
72
- const primaryContrast = wcagContrastRatio(luminanceOf(textPrimary), bgLum);
73
- const reverseContrast = wcagContrastRatio(luminanceOf(textReverse), bgLum);
74
- return reverseContrast > primaryContrast ? textReverse : textPrimary;
63
+ const bgLum = getLuminance(bgColor);
64
+ const primaryLum = getLuminance(textPrimary);
65
+ const reverseLum = getLuminance(textReverse);
66
+
67
+ const lighterText = primaryLum >= reverseLum ? textPrimary : textReverse;
68
+ const darkerText = primaryLum >= reverseLum ? textReverse : textPrimary;
69
+
70
+ const lighterContrast = wcagContrastRatio(primaryLum >= reverseLum ? primaryLum : reverseLum, bgLum);
71
+
72
+ return lighterContrast >= CONTRAST_THRESHOLD ? lighterText : darkerText;
75
73
  } catch {
76
74
  return null;
77
75
  }