@synerise/ds-color-picker 1.3.49 → 1.3.51

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 (3) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/CLAUDE.md +116 -0
  3. package/package.json +12 -11
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [1.3.51](https://github.com/Synerise/synerise-design/compare/@synerise/ds-color-picker@1.3.50...@synerise/ds-color-picker@1.3.51) (2026-07-23)
7
+
8
+ **Note:** Version bump only for package @synerise/ds-color-picker
9
+
10
+ ## [1.3.50](https://github.com/Synerise/synerise-design/compare/@synerise/ds-color-picker@1.3.49...@synerise/ds-color-picker@1.3.50) (2026-07-16)
11
+
12
+ **Note:** Version bump only for package @synerise/ds-color-picker
13
+
6
14
  ## [1.3.49](https://github.com/Synerise/synerise-design/compare/@synerise/ds-color-picker@1.3.48...@synerise/ds-color-picker@1.3.49) (2026-07-09)
7
15
 
8
16
  **Note:** Version bump only for package @synerise/ds-color-picker
package/CLAUDE.md ADDED
@@ -0,0 +1,116 @@
1
+ # ColorPicker (`@synerise/ds-color-picker`)
2
+
3
+ > An input-triggered dropdown color picker built on `react-colorful`, with hex input, copy-to-clipboard, and optional saved color swatches.
4
+
5
+ ## Package structure
6
+
7
+ ```
8
+ src/
9
+ ColorPicker.tsx — main component; all state, dropdown, and trigger logic
10
+ ColorPicker.types.ts — ColorPickerProps, ColorPickerSize enum, ColorHookType
11
+ ColorPicker.styles.ts — all styled-components + createGlobalStyle for maxWidth
12
+ utils.ts — color validation and conversion utilities
13
+ index.tsx — default export + ColorPickerProps type export
14
+ __specs__/
15
+ ColorPicker.spec.tsx — component + utility unit tests (Vitest)
16
+ ```
17
+
18
+ ## Public exports
19
+
20
+ ### `ColorPicker` (default)
21
+
22
+ | Prop | Type | Default | Description |
23
+ |------|------|---------|-------------|
24
+ | `value` | `string` | `undefined` | Controlled color value. Accepts hex (`#fff`, `#ffffff`) or CSS named colors (`red`). |
25
+ | `onChange` | `(color: string) => void` | `undefined` | Called with a normalised 6-digit hex string on every valid change. |
26
+ | `colors` | `string[]` | `[]` | Initial saved color swatches. Local copy is maintained in component state. |
27
+ | `onSaveColors` | `(colors: string[]) => void` | `undefined` | Called when the user saves a new swatch. Receives the full updated array. |
28
+ | `maxSavedColors` | `number` | `9` | Maximum number of swatches. Older entries are dropped from the front. |
29
+ | `isShownSavedColors` | `boolean` | `undefined` | Shows the divider + swatch section below the hex input. |
30
+ | `infix` | `(colorHooks?: Partial<ColorHookType>) => JSX.Element` | `() => <></>` | Render slot between the save button and the swatches (e.g. color-format converter). Receives `{ color, setColor }`. |
31
+ | `size` | `'S' \| 'M' \| 'L'` | `'M'` | Height of the `react-colorful` picker: S=136px, M=168px, L=200px. |
32
+ | `maxWidth` | `number` | `undefined` | When `>= 228`, injects a `createGlobalStyle` to constrain `.color-picker-overlay` to this width. |
33
+ | `placeholder` | `string` | `undefined` | Input placeholder text. |
34
+ | `tooltip` | `{ copy: string; copied: string }` | `undefined` | Tooltips for the copy-to-clipboard icon inside the dropdown hex input. |
35
+ | `error` | `boolean` | `undefined` | Error state on the trigger input. |
36
+ | `errorText` | `string` | `undefined` | Error message below the trigger (from `FormFieldCommonProps`). |
37
+ | `description` | `string` | `undefined` | Description text below the trigger (from `FormFieldCommonProps`). |
38
+ | `disabled` | `boolean` | `undefined` | Disables the input. **Dropdown is not rendered at all** when `true`. |
39
+ | `readOnly` | `boolean` | `undefined` | Makes the input read-only. **Dropdown is not rendered at all** when `true`. |
40
+ | `inputProps` | `Omit<InputProps, 'value'\|'onChange'\|'defaultValue'\|'placeholder'\|'disabled'\|'readOnly'\|'prefix'\|keyof FormFieldCommonProps>` | `undefined` | Extra props forwarded to the trigger `Input`. |
41
+ | `getPopupContainer` | `(triggerNode: HTMLElement) => HTMLElement` | `defaultGetPopupContainer` from `@synerise/ds-utils` | Portal target for the dropdown. |
42
+
43
+ ### `ColorPickerProps`
44
+
45
+ Type exported from `index.tsx`.
46
+
47
+ ### `ColorHookType` _(not in index.tsx)_
48
+
49
+ Type used for the `infix` render prop: `{ color: string; setColor: (color: string) => void }`. Not exported from `index.tsx` — import from `@synerise/ds-color-picker/dist/ColorPicker.types` if needed, or declare inline.
50
+
51
+ ## Usage patterns
52
+
53
+ ```tsx
54
+ import ColorPicker from '@synerise/ds-color-picker';
55
+
56
+ // Controlled basic usage
57
+ const [color, setColor] = useState('#00ffff');
58
+ <ColorPicker value={color} onChange={setColor} />
59
+
60
+ // With saved swatches and copy tooltip
61
+ const [color, setColor] = useState('#00ffff');
62
+ const [savedColors, setSavedColors] = useState<string[]>([]);
63
+ <ColorPicker
64
+ value={color}
65
+ onChange={setColor}
66
+ colors={savedColors}
67
+ onSaveColors={setSavedColors}
68
+ isShownSavedColors
69
+ maxSavedColors={9}
70
+ tooltip={{ copy: 'Copy', copied: 'Copied!' }}
71
+ size="S"
72
+ description="Brand colour"
73
+ />
74
+
75
+ // With infix slot (e.g. format converter between save button and swatches)
76
+ <ColorPicker
77
+ value={color}
78
+ onChange={setColor}
79
+ isShownSavedColors
80
+ infix={({ color, setColor }) => (
81
+ <Select ... onChange={setColor} />
82
+ )}
83
+ />
84
+ ```
85
+
86
+ ## Styling
87
+
88
+ All styles are in `ColorPicker.styles.ts`. Uses `theme.palette` tokens for borders, backgrounds, and text. `react-colorful` internal class names (`.react-colorful__*`) are overridden directly inside the `Container` styled-component.
89
+
90
+ `ColorPickerModalStyle` is a `createGlobalStyle` that targets `.color-picker-overlay` — it is only injected into the DOM when `maxWidth >= 228`. This is a **global CSS side-effect**.
91
+
92
+ The saved-colour **swatch section** is built from plain styled elements matching the Figma spec (16×16, `border-radius: 3px`): `SwatchCreatorButton` (the "+" button, `<button>` — hover shows a `grey-200` background), `Swatch` (a filled `<button>` whose `background-color` is the saved colour; the selected one renders a centred `SwatchDot`), and `SwatchPlaceholder` (an empty `<div>` slot with a `grey-300` border, `grey-400` on hover). It does **not** use `ds-tags`/`ds-button` for swatches. Filled swatches carry `.ds-color-swatch`; empty slots carry `.ds-color-swatch-placeholder`.
93
+
94
+ ## Key dependencies
95
+
96
+ - `react-colorful` (`HexColorPicker`) — the core colour-gradient picker UI
97
+ - `@synerise/ds-dropdown` — popover/overlay shell for the picker panel
98
+ - `@synerise/ds-input` — trigger text input and the hex input inside the dropdown
99
+ - `@synerise/ds-tags` — `Tag` for the colour preview swatch (trigger `innerPrefix` + the dropdown preview square); **not** used for saved-colour swatches
100
+ - `@synerise/ds-copy-icon` — copy-to-clipboard button in the dropdown hex input
101
+ - `@synerise/ds-icon` — the `FormulaPlusM` plus glyph inside the swatch creator button
102
+ - `@synerise/ds-form-field` — `FormFieldCommonProps` for `description`/`errorText`
103
+ - `@synerise/ds-utils` (`useOnClickOutside`, `getPopupContainer`) — click-outside close, default portal target
104
+
105
+ ## Implementation notes
106
+
107
+ - **`disabled`/`readOnly` bypass the Dropdown entirely** — when either is set, the component returns just the trigger `Input` directly (no `Dropdown` wrapper). Opening the picker is impossible.
108
+ - **Dual color state** — `colorTextInput` (what the user typed / named color) and `colorHexInput` (the normalised hex shown in the dropdown) are kept in sync. `lastValidHexColor` drives the `react-colorful` picker and the preview tag — it only updates on valid input.
109
+ - **`onBlur` resets to last valid** — if the user types an invalid color in the trigger input and blurs, both inputs revert to `lastValidHexColor`.
110
+ - **Initial sync is one-time** — `useEffect` with empty deps `[]` runs only on mount to initialise local state from `value`. After that, `value` changes are **not** automatically reflected (the component is semi-controlled). Pass `value` and handle `onChange` consistently.
111
+ - **`standardizeColor` uses `document.createElement('canvas')`** — browser-only. Will throw in SSR/Node environments.
112
+ - **`isValidTextColor` uses `new Option().style`** — also browser-only.
113
+ - **`maxWidth` threshold** — the prop only takes effect when `>= 228` (the default picker width). Values below 228 are silently ignored.
114
+ - **Swatch grid renders `maxSavedColors` slots** — saved colours fill the leading slots (`Swatch`); the remainder render as empty `SwatchPlaceholder` slots (Figma shows the full grid). The grid wraps (`flex-wrap`) if `maxSavedColors` exceeds what fits the 196px content width.
115
+ - **Selected swatch** — `pressed` holds the index of the last-clicked swatch (its `SwatchDot` shows); it resets to `-1` on any text/hex input change, so typing a colour clears the selection highlight.
116
+ - **`savedColors` is local state** — `colors` prop initialises the local `savedColors` state on mount only. Subsequent `colors` prop changes are not reflected unless the component remounts.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synerise/ds-color-picker",
3
- "version": "1.3.49",
3
+ "version": "1.3.51",
4
4
  "description": "Color-Picker Component for the Synerise Design System",
5
5
  "license": "ISC",
6
6
  "repository": "Synerise/synerise-design",
@@ -17,6 +17,7 @@
17
17
  "files": [
18
18
  "/dist",
19
19
  "CHANGELOG.md",
20
+ "CLAUDE.md",
20
21
  "README.md",
21
22
  "package.json",
22
23
  "LICENSE.md"
@@ -41,15 +42,15 @@
41
42
  ],
42
43
  "types": "dist/index.d.ts",
43
44
  "dependencies": {
44
- "@synerise/ds-copy-icon": "^1.2.15",
45
- "@synerise/ds-divider": "^1.3.15",
46
- "@synerise/ds-dropdown": "^1.3.18",
47
- "@synerise/ds-form-field": "^1.3.23",
48
- "@synerise/ds-icon": "^1.18.4",
49
- "@synerise/ds-input": "^1.7.12",
50
- "@synerise/ds-tags": "^1.5.49",
51
- "@synerise/ds-tooltip": "^1.5.3",
52
- "@synerise/ds-utils": "^1.10.1",
45
+ "@synerise/ds-copy-icon": "^1.2.16",
46
+ "@synerise/ds-divider": "^1.3.16",
47
+ "@synerise/ds-dropdown": "^1.3.20",
48
+ "@synerise/ds-form-field": "^1.3.24",
49
+ "@synerise/ds-icon": "^1.18.5",
50
+ "@synerise/ds-input": "^1.7.13",
51
+ "@synerise/ds-tags": "^1.5.51",
52
+ "@synerise/ds-tooltip": "^1.5.4",
53
+ "@synerise/ds-utils": "^1.10.2",
53
54
  "react-colorful": "^5.2.0"
54
55
  },
55
56
  "devDependencies": {
@@ -61,5 +62,5 @@
61
62
  "react": ">=16.9.0 <= 18.3.1",
62
63
  "styled-components": "^5.3.3"
63
64
  },
64
- "gitHead": "5c90008871be36fb52553a2ed3a633acf5db5b3b"
65
+ "gitHead": "d0a43cc43d8528a36f105aceea52ab470edb71d9"
65
66
  }