@fibery/ui-kit 2.1.0 → 2.1.1

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 (61) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/package.json +6 -3
  3. package/src/@types/react-color.d.ts +36 -0
  4. package/src/antd/{Tabs.js → Tabs.tsx} +5 -2
  5. package/src/color-filter.test.ts +24 -65
  6. package/src/color-filter.ts +62 -93
  7. package/src/color-picker/{ColorPickerOrLoader.js → ColorPickerOrLoader.tsx} +1 -1
  8. package/src/color-picker/{index.js → index.tsx} +32 -6
  9. package/src/color-utils.ts +3 -9
  10. package/src/design-system/colors-css.ts +16 -0
  11. package/src/design-system/colors.ts +23 -45
  12. package/src/design-system/def.ts +17 -0
  13. package/src/design-system/theme.ts +6 -2
  14. package/src/design-system/types.ts +102 -0
  15. package/src/design-system/vars.test.ts +9 -2
  16. package/src/design-system/vars.ts +4 -2
  17. package/src/design-system.ts +9 -1
  18. package/src/emoji-picker/emoji-picker-content-with-color.tsx +3 -3
  19. package/src/heat.ts +8 -0
  20. package/src/highlight-colors.test.ts +68 -0
  21. package/src/highlight-colors.ts +91 -0
  22. package/src/link-input/components/{AntTextAreaWithCustomReadState.js → AntTextAreaWithCustomReadState.tsx} +19 -8
  23. package/src/link-input/index.tsx +94 -0
  24. package/src/link-input/{utils.js → utils.ts} +1 -6
  25. package/src/number-input/decimal.ts +50 -0
  26. package/src/number-input/utils.ts +2 -2
  27. package/src/palette-generator.test.ts +2 -1
  28. package/src/palette-generator.ts +8 -26
  29. package/src/palettes/_.ts +2 -2
  30. package/src/palettes/common.ts +31 -0
  31. package/src/palettes/diff-colors.ts +29 -12
  32. package/src/palettes/inspect.defs.colors.neutral-arch.test.ts +72 -36
  33. package/src/palettes/inspect.defs.colors.neutral-user.test.ts +72 -36
  34. package/src/palettes/inspect.defs.colors.warm-arch.test.ts +226 -190
  35. package/src/palettes/inspect.defs.colors.warm-user.test.ts +226 -190
  36. package/src/palettes/neutral-arch.ts +3 -3
  37. package/src/palettes/neutral-user.ts +3 -3
  38. package/src/palettes/neutral.ts +4 -2
  39. package/src/palettes/warm-arch.ts +3 -3
  40. package/src/palettes/warm-user.ts +3 -3
  41. package/src/palettes/warm.ts +4 -3
  42. package/src/pretty-size.ts +5 -2
  43. package/src/root-theme-provider.test.tsx +1 -1
  44. package/src/scale-generator.ts +1 -32
  45. package/src/select/components/menu-list-virtua.tsx +127 -0
  46. package/src/select/index.tsx +1 -1
  47. package/src/select/reflection.ts +22 -0
  48. package/src/select/select.tsx +1 -0
  49. package/src/static-palettes.ts +2 -1
  50. package/src/thematic-color-picker.tsx +8 -1
  51. package/src/thematic-constants.tsx +2 -0
  52. package/src/thematic-controls.tsx +9 -1
  53. package/src/thematic-cvd.tsx +73 -0
  54. package/src/thematic-highlights.tsx +49 -0
  55. package/src/thematic-scales.tsx +8 -6
  56. package/src/thematic-state.ts +37 -16
  57. package/src/thematic.tsx +298 -305
  58. package/src/theme-provider.tsx +9 -3
  59. package/src/theme-styles.ts +2 -1
  60. package/src/link-input/index.js +0 -89
  61. package/src/number-input/decimal.js +0 -61
@@ -1,8 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
2
- import {neutralBase} from "./neutral";
1
+ import {neutralCore} from "./neutral";
2
+ import type {ThemePalette} from "../design-system/types";
3
3
 
4
4
  export const neutralArchPalette: ThemePalette = {
5
- ...neutralBase,
5
+ ...neutralCore,
6
6
  key: "neutral-arch",
7
7
  accent: [
8
8
  null,
@@ -1,8 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
2
- import {neutralBase} from "./neutral";
1
+ import {neutralCore} from "./neutral";
2
+ import type {ThemePalette} from "../design-system/types";
3
3
 
4
4
  export const neutralUserPalette: ThemePalette = {
5
- ...neutralBase,
5
+ ...neutralCore,
6
6
  key: "neutral-user",
7
7
  accent: [
8
8
  null,
@@ -1,6 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
1
+ import {common} from "./common";
2
+ import type {ThemePaletteCore} from "../design-system/types";
2
3
 
3
- export const neutralBase: Omit<ThemePalette, "accent" | "accentDark" | "key"> = {
4
+ export const neutralCore: ThemePaletteCore = {
5
+ ...common,
4
6
  // warm-dark no-applied:
5
7
  // "white": "rgb(255,252,247)",
6
8
  // "black": "rgb(5,4,4)",
@@ -1,8 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
2
- import {warmBase} from "./warm";
1
+ import {warmCore} from "./warm";
2
+ import type {ThemePalette} from "../design-system/types";
3
3
 
4
4
  export const warmArchPalette: ThemePalette = {
5
- ...warmBase,
5
+ ...warmCore,
6
6
  key: "warm-arch",
7
7
  accent: [
8
8
  null,
@@ -1,8 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
2
- import {warmBase} from "./warm";
1
+ import {warmCore} from "./warm";
2
+ import type {ThemePalette} from "../design-system/types";
3
3
 
4
4
  export const warmUserPalette: ThemePalette = {
5
- ...warmBase,
5
+ ...warmCore,
6
6
  key: "warm-user",
7
7
  accent: [
8
8
  null,
@@ -1,7 +1,8 @@
1
- import {ThemePalette} from "../palette-generator";
1
+ import {common} from "./common";
2
+ import type {ThemePaletteCore} from "../design-system/types";
2
3
 
3
- export const warmBase: Omit<ThemePalette, "accent" | "accentDark" | "key"> = {
4
- deneutralize: {sepia: 0.1, oklchL: 0.98},
4
+ export const warmCore: ThemePaletteCore = {
5
+ ...common,
5
6
  white: "rgb(255,253,250)",
6
7
  whiteA: [
7
8
  null,
@@ -2,7 +2,10 @@ const UNITS = ["byte", "kilobyte", "megabyte", "gigabyte", "terabyte", "petabyte
2
2
  const BYTES_PER_KB = 1000;
3
3
 
4
4
  // ref: https://stackoverflow.com/a/72596863/4280642
5
- export function prettySize(sizeBytes: number | bigint): string {
5
+ export function prettySize(
6
+ sizeBytes: number | bigint,
7
+ unitDisplay: "short" | "long" | "narrow" | undefined = "narrow"
8
+ ): string {
6
9
  let size = Math.abs(Number(sizeBytes));
7
10
 
8
11
  let unitIdx = 0;
@@ -14,7 +17,7 @@ export function prettySize(sizeBytes: number | bigint): string {
14
17
  return new Intl.NumberFormat([], {
15
18
  style: "unit",
16
19
  unit: UNITS[unitIdx],
17
- unitDisplay: "narrow",
20
+ unitDisplay,
18
21
  notation: "standard",
19
22
  maximumFractionDigits: 1,
20
23
  })
@@ -8,10 +8,10 @@ import {
8
8
  useThemeMode,
9
9
  useThemePreference,
10
10
  } from "./theme-provider";
11
- import {ThemePalette} from "./palette-generator";
12
11
  import {locateThemeBundle} from "./theme-styles";
13
12
  import {stylesFromTheme, themeFromPalette} from "./design-system";
14
13
  import {storeWarmPreference} from "./theme-settings";
14
+ import type {ThemePalette} from "./design-system/types";
15
15
 
16
16
  const {
17
17
  palette,
@@ -1,36 +1,5 @@
1
1
  import {fromOKLCH} from "./color-utils";
2
- import type {ColorScale} from "./palette-generator";
3
-
4
- export type OneBasedScale<T> = readonly [
5
- base00: null,
6
- step01: T,
7
- step02: T,
8
- step03: T,
9
- step04: T,
10
- step05: T,
11
- step06: T,
12
- step07: T,
13
- step08: T,
14
- step09: T,
15
- step10: T,
16
- step11: T,
17
- step12: T,
18
- ];
19
-
20
- export type ZeroBasedScale<T> = readonly [
21
- step01: T,
22
- step02: T,
23
- step03: T,
24
- step04: T,
25
- step05: T,
26
- step06: T,
27
- step07: T,
28
- step08: T,
29
- step09: T,
30
- step10: T,
31
- step11: T,
32
- step12: T,
33
- ];
2
+ import type {ColorScale, OneBasedScale, ZeroBasedScale} from "./design-system/types";
34
3
 
35
4
  export function zeroBasedFromOneBased<T>(scale: OneBasedScale<T>) {
36
5
  return scale.slice(1) as unknown as ZeroBasedScale<T>;
@@ -0,0 +1,127 @@
1
+ import compact from "lodash/compact";
2
+ import {
3
+ Children,
4
+ ComponentType,
5
+ CSSProperties,
6
+ ReactNode,
7
+ useContext,
8
+ useEffect,
9
+ useMemo,
10
+ useRef,
11
+ useState,
12
+ } from "react";
13
+ import type {GroupHeadingProps, GroupProps, MenuListProps} from "react-select";
14
+ import {VList, VListHandle} from "virtua";
15
+ import {GroupBase, ReactSelectRefContext} from "../util";
16
+ import {isGroupChild, isReactElementWithProps} from "../reflection";
17
+
18
+ const DEFAULT_ITEM_SIZE_ESTIMATE = 48;
19
+
20
+ function flattenGroupChildren(
21
+ children: ReactNode,
22
+ renderGroup: (Component: ComponentType<GroupHeadingProps>, props: GroupProps["headingProps"]) => ReactNode
23
+ ): ReactNode[] {
24
+ return compact(
25
+ Children.toArray(children)
26
+ .map((child) => {
27
+ if (isReactElementWithProps(child) && isGroupChild(child)) {
28
+ const {props} = child;
29
+ const groupChildren = compact(Children.toArray(props.children));
30
+ if (!groupChildren.length) {
31
+ return [];
32
+ }
33
+ const heading = renderGroup(props.Heading, props.headingProps);
34
+ return [heading, ...groupChildren];
35
+ }
36
+ return child;
37
+ })
38
+ .flat()
39
+ );
40
+ }
41
+
42
+ /**
43
+ * Virtualized MenuList using virtua — supports dynamic item heights.
44
+ * Use with `virtualized={false}` + `components={{ MenuList: MenuListVirtua }}`.
45
+ */
46
+ export function MenuListVirtua<
47
+ Option,
48
+ IsMulti extends boolean = boolean,
49
+ Group extends GroupBase<Option> = GroupBase<Option>,
50
+ >(props: MenuListProps<Option, IsMulti, Group>) {
51
+ const {children, focusedOption, maxHeight, getStyles, selectProps, cx, theme} = props;
52
+ const vlistRef = useRef<VListHandle>(null);
53
+ const select = useContext(ReactSelectRefContext);
54
+ const [initialized, setInitialized] = useState(false);
55
+
56
+ const renderGroup = useMemo(
57
+ () => (Component: ComponentType<GroupHeadingProps>, headingProps: GroupProps["headingProps"]) => {
58
+ const content = selectProps.formatGroupLabel
59
+ ? selectProps.formatGroupLabel(headingProps.data as Group)
60
+ : headingProps.data.label;
61
+ return content ? (
62
+ <Component
63
+ cx={cx}
64
+ selectProps={selectProps as unknown as GroupHeadingProps["selectProps"]}
65
+ theme={theme}
66
+ getStyles={getStyles}
67
+ {...headingProps}
68
+ >
69
+ {content}
70
+ </Component>
71
+ ) : null;
72
+ },
73
+ [cx, getStyles, selectProps, theme]
74
+ );
75
+
76
+ const items = useMemo(() => flattenGroupChildren(children, renderGroup), [children, renderGroup]);
77
+ const estimatedHeight = Math.min(items.length * DEFAULT_ITEM_SIZE_ESTIMATE, maxHeight);
78
+
79
+ const focusedIndex = useMemo(() => {
80
+ if (!focusedOption) {
81
+ return -1;
82
+ }
83
+ return items.findIndex((child) => {
84
+ return isReactElementWithProps(child) && "data" in child.props && child.props.data === focusedOption;
85
+ });
86
+ }, [focusedOption, items]);
87
+
88
+ useEffect(() => {
89
+ if (!select.current || !items.length || initialized) {
90
+ return;
91
+ }
92
+ let firstOption: unknown;
93
+ let selectedOption: unknown;
94
+ for (const child of items) {
95
+ if (isReactElementWithProps(child) && "type" in child.props && child.props.type === "option") {
96
+ if (!firstOption && "data" in child.props) {
97
+ firstOption = child.props.data;
98
+ }
99
+ if ("isSelected" in child.props && child.props.isSelected && "data" in child.props) {
100
+ selectedOption = child.props.data;
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ const target = selectedOption || firstOption;
106
+ if (target) {
107
+ setInitialized(true);
108
+ select.current.setState({focusedOption: target});
109
+ }
110
+ }, [items, initialized, select]);
111
+
112
+ useEffect(() => {
113
+ if (focusedIndex >= 0 && vlistRef.current) {
114
+ vlistRef.current.scrollToIndex(focusedIndex, {align: "nearest"});
115
+ }
116
+ }, [focusedIndex]);
117
+
118
+ return (
119
+ <div style={{height: estimatedHeight, ...(getStyles("menuList", props) as CSSProperties), overflow: "hidden"}}>
120
+ <VList ref={vlistRef} style={{height: "100%"}} itemSize={DEFAULT_ITEM_SIZE_ESTIMATE}>
121
+ {items.map((child, i) => (
122
+ <div key={i}>{child}</div>
123
+ ))}
124
+ </VList>
125
+ </div>
126
+ );
127
+ }
@@ -27,7 +27,7 @@ export type {
27
27
  SelectProps,
28
28
  } from "./select";
29
29
 
30
- export {components, MenuListVirtualized, createFilter} from "./select";
30
+ export {components, MenuListVirtualized, MenuListVirtua, createFilter} from "./select";
31
31
 
32
32
  export {combineStyles} from "./select";
33
33
 
@@ -0,0 +1,22 @@
1
+ import isObject from "lodash/isObject";
2
+ import {GroupBase} from "./util";
3
+ import type {GroupProps} from "react-select/dist/declarations/src";
4
+ import isFunction from "lodash/isFunction";
5
+
6
+ type ReactElementWithProps<P = object> = {props: P};
7
+
8
+ export function isReactElementWithProps(node: unknown): node is ReactElementWithProps {
9
+ return isObject(node) && "props" in node && isObject(node.props);
10
+ }
11
+
12
+ export function isGroupChild<Option, IsMulti extends boolean, Group extends GroupBase<Option> = GroupBase<Option>>(
13
+ node: ReactElementWithProps
14
+ ): node is ReactElementWithProps<GroupProps<Option, IsMulti, Group>> {
15
+ return (
16
+ "options" in node.props &&
17
+ "Heading" in node.props &&
18
+ isFunction(node.props.Heading) &&
19
+ "headingProps" in node.props &&
20
+ isObject(node.props.headingProps)
21
+ );
22
+ }
@@ -54,6 +54,7 @@ export type {
54
54
  };
55
55
 
56
56
  export {reactSelectComponents as components, MenuListVirtualized, createFilter};
57
+ export {MenuListVirtua} from "./components/menu-list-virtua";
57
58
 
58
59
  function GroupVirtualized() {
59
60
  return null;
@@ -1,4 +1,5 @@
1
- import {selectPalette, type ThemePalette} from "./palette-generator";
1
+ import {selectPalette} from "./palette-generator";
2
+ import type {ThemePalette} from "./design-system/types";
2
3
 
3
4
  export interface LabPalettes {
4
5
  make: () => ThemePalette;
@@ -58,6 +58,11 @@ export const miniSwatchCss = css`
58
58
  height: 11px;
59
59
  `;
60
60
 
61
+ export const tinySwatchCss = css`
62
+ width: 16px;
63
+ height: 16px;
64
+ `;
65
+
61
66
  const splitSwatchCss = css`
62
67
  width: 22px;
63
68
  height: 22px;
@@ -107,6 +112,7 @@ export function SwatchWithPicker({
107
112
  splitBg,
108
113
  altColor,
109
114
  mini,
115
+ tiny,
110
116
  inspectChannel,
111
117
  }: {
112
118
  color: string;
@@ -118,9 +124,10 @@ export function SwatchWithPicker({
118
124
  splitBg?: boolean;
119
125
  altColor?: string;
120
126
  mini?: boolean;
127
+ tiny?: boolean;
121
128
  inspectChannel?: InspectChannel;
122
129
  }) {
123
- const baseCls = mini ? miniSwatchCss : swatchCss;
130
+ const baseCls = tiny ? tinySwatchCss : mini ? miniSwatchCss : swatchCss;
124
131
  const splitCls = mini ? miniSplitSwatchCss : splitSwatchCss;
125
132
 
126
133
  const overlay = inspectChannel
@@ -3,12 +3,14 @@ import type {ThemePreference} from "./theme-settings";
3
3
  import AppearanceLight from "./icons/react/AppearanceLight";
4
4
  import AppearanceDark from "./icons/react/AppearanceDark";
5
5
  import AppearanceAuto from "./icons/react/AppearanceAuto";
6
+ import {common} from "./palettes/common";
6
7
 
7
8
  export const defaultPrefs: ThematicPrefs = {
8
9
  baseHue: 0,
9
10
  baseChroma: 0,
10
11
  accentHue: 264,
11
12
  accentChroma: 0.16,
13
+ highlight: common.highlight,
12
14
  };
13
15
 
14
16
  export const HIGHLIGHT_COLOR = "#ff00ff";
@@ -219,6 +219,7 @@ export function Slider({
219
219
  color,
220
220
  onLabelHover,
221
221
  onLabelLeave,
222
+ onLabelClick,
222
223
  }: {
223
224
  label: string;
224
225
  value: number;
@@ -231,10 +232,17 @@ export function Slider({
231
232
  color?: string;
232
233
  onLabelHover?: () => void;
233
234
  onLabelLeave?: () => void;
235
+ onLabelClick?: () => void;
234
236
  }) {
235
237
  return (
236
238
  <div className={controlRowCss}>
237
- <span className={controlLabelCss} onMouseEnter={onLabelHover} onMouseLeave={onLabelLeave}>
239
+ <span
240
+ className={controlLabelCss}
241
+ style={onLabelClick ? {cursor: "pointer"} : undefined}
242
+ onMouseEnter={onLabelHover}
243
+ onMouseLeave={onLabelLeave}
244
+ onClick={onLabelClick}
245
+ >
238
246
  {label}
239
247
  </span>
240
248
  <input
@@ -0,0 +1,73 @@
1
+ import {useState} from "react";
2
+ import {useThematicState} from "./thematic-state";
3
+ import {sectionLabelCss, sectionSeparatorCss} from "./thematic-scales";
4
+ import {Slider} from "./thematic-controls";
5
+ import {cvdChannels} from "./color-filter";
6
+
7
+ const types = [null, ...cvdChannels] as const;
8
+
9
+ const activeKey = (dn: ReturnType<typeof useThematicState>["deneutralizeSpec"]) => {
10
+ for (const {key} of cvdChannels) {
11
+ if (dn?.[key]) {
12
+ return key;
13
+ }
14
+ }
15
+ return null;
16
+ };
17
+
18
+ export function CvdSection({state}: {state: ReturnType<typeof useThematicState>}) {
19
+ const dn = state.deneutralizeSpec;
20
+ const current = activeKey(dn);
21
+ const currentChannel = current ? cvdChannels.find((c) => c.key === current) : null;
22
+ const liveSeverity = current ? (dn?.[current] ?? 0) : 0;
23
+ const [savedAmount, setSavedAmount] = useState(0.8);
24
+
25
+ const amount = current ? liveSeverity : savedAmount;
26
+
27
+ if (liveSeverity > 0 && liveSeverity !== savedAmount) {
28
+ setSavedAmount(liveSeverity);
29
+ }
30
+
31
+ const onCycle = () => {
32
+ const currentIdx = current ? types.findIndex((t) => t && t.key === current) : 0;
33
+ const next = types[(currentIdx + 1) % types.length];
34
+
35
+ const update: Record<string, number> = {};
36
+ for (const {key} of cvdChannels) {
37
+ update[key] = 0;
38
+ }
39
+ if (next) {
40
+ update[next.key] = amount;
41
+ }
42
+ state.updateFilter(update);
43
+ };
44
+
45
+ return (
46
+ <>
47
+ <div className={sectionSeparatorCss} />
48
+ <div className={sectionLabelCss} style={{fontWeight: 700, cursor: "pointer"}} onClick={onCycle}>
49
+ cvd: {currentChannel?.label ?? "none"}
50
+ </div>
51
+ <Slider
52
+ label="amount"
53
+ value={amount}
54
+ min={0}
55
+ max={1}
56
+ step={0.05}
57
+ onChange={(v) => {
58
+ setSavedAmount(v);
59
+ if (current) {
60
+ state.updateFilter({[current]: v});
61
+ }
62
+ }}
63
+ onLabelClick={() => {
64
+ const next = amount > 0 ? 0 : 1;
65
+ setSavedAmount(next);
66
+ if (current) {
67
+ state.updateFilter({[current]: next});
68
+ }
69
+ }}
70
+ />
71
+ </>
72
+ );
73
+ }
@@ -0,0 +1,49 @@
1
+ import {useThematicState} from "./thematic-state";
2
+ import {sectionLabelCss, sectionSeparatorCss} from "./thematic-scales";
3
+ import {Slider} from "./thematic-controls";
4
+
5
+ export function HighlightSection({state}: {state: ReturnType<typeof useThematicState>}) {
6
+ const side = state.showDark ? 1 : 0;
7
+ const h = state.palette.highlight;
8
+
9
+ const update = ({bgLc, bgC, fgC, fgLc}: {bgLc?: number; bgC?: number; fgC?: number; fgLc?: number}) => {
10
+ const newBg = [...h.bg] as typeof h.bg;
11
+ const newFg = [...h.fg] as typeof h.fg;
12
+ if (bgLc !== undefined) {
13
+ newBg[side] = {...newBg[side], Lc: bgLc};
14
+ }
15
+ if (bgC !== undefined) {
16
+ newBg[side] = {...newBg[side], c: bgC};
17
+ }
18
+ if (fgC !== undefined) {
19
+ newFg[side] = {...newFg[side], c: fgC};
20
+ }
21
+ if (fgLc !== undefined) {
22
+ newFg[side] = {...newFg[side], Lc: fgLc};
23
+ }
24
+ state.updateHighlight({...h, bg: newBg, fg: newFg});
25
+ };
26
+ return (
27
+ <>
28
+ <div className={sectionSeparatorCss} />
29
+ <div className={sectionLabelCss} style={{fontWeight: 700}}>
30
+ highlight ({state.showDark ? "dark" : "light"})
31
+ </div>
32
+ <Slider
33
+ label="bg Lc"
34
+ value={h.bg[side].Lc}
35
+ min={0}
36
+ max={30}
37
+ step={0.01}
38
+ onChange={(bgLc) => {
39
+ // oxlint-disable-next-line no-console
40
+ console.log(`[slider] bgLc=${bgLc} t=${performance.now().toFixed(0)}`);
41
+ update({bgLc});
42
+ }}
43
+ />
44
+ <Slider label="bg Ch" value={h.bg[side].c} min={0} max={0.4} step={0.001} onChange={(bgC) => update({bgC})} />
45
+ <Slider label="fg Lc" value={h.fg[side].Lc} min={0} max={90} step={0.01} onChange={(fgLc) => update({fgLc})} />
46
+ <Slider label="fg Ch" value={h.fg[side].c} min={0} max={0.4} step={0.001} onChange={(fgC) => update({fgC})} />
47
+ </>
48
+ );
49
+ }
@@ -1,7 +1,6 @@
1
1
  import {css} from "@linaria/core";
2
- import {type ColorScale} from "./palette-generator";
3
2
  import {space, themeVars} from "./design-system";
4
- import {type InspectChannel, SwatchWithPicker, miniSwatchCss, swatchCss} from "./thematic-color-picker";
3
+ import {type InspectChannel, SwatchWithPicker, miniSwatchCss, swatchCss, tinySwatchCss} from "./thematic-color-picker";
5
4
 
6
5
  export const scaleCss = css`
7
6
  display: flex;
@@ -42,9 +41,9 @@ const gridCss = css`
42
41
  overflow-x: auto;
43
42
  `;
44
43
 
45
- type ScaleEntry = {
44
+ export type ScaleEntry = {
46
45
  name: string;
47
- scale: ColorScale;
46
+ scale: readonly (string | null)[];
48
47
  onColorChange?: (index: number, color: string) => void;
49
48
  onHover?: (color: string, name: string) => void;
50
49
  onHoverEnd?: () => void;
@@ -52,6 +51,7 @@ type ScaleEntry = {
52
51
  splitBg?: boolean;
53
52
  altColors?: (string | null)[];
54
53
  mini?: boolean;
54
+ tiny?: boolean;
55
55
  };
56
56
 
57
57
  export function ScaleGrid({
@@ -64,11 +64,11 @@ export function ScaleGrid({
64
64
  }) {
65
65
  return (
66
66
  <div className={gridCss}>
67
- {scales.map(({name, scale, onColorChange, onHover, onHoverEnd, extra, splitBg, altColors, mini}) => (
67
+ {scales.map(({name, scale, onColorChange, onHover, onHoverEnd, extra, splitBg, altColors, mini, tiny}) => (
68
68
  <div key={name} className={columnCss}>
69
69
  {scale.map((color, i) =>
70
70
  color === null ? null : (color as unknown) === SPACER ? (
71
- <div key={i} className={`${mini ? miniSwatchCss : swatchCss} ${emptySwatchCss}`} />
71
+ <div key={i} className={`${tiny ? tinySwatchCss : mini ? miniSwatchCss : swatchCss} ${emptySwatchCss}`} />
72
72
  ) : (
73
73
  <SwatchWithPicker
74
74
  key={i}
@@ -80,6 +80,7 @@ export function ScaleGrid({
80
80
  splitBg={splitBg}
81
81
  altColor={altColors?.[i] ?? undefined}
82
82
  mini={mini}
83
+ tiny={tiny}
83
84
  inspectChannel={inspectChannel}
84
85
  />
85
86
  )
@@ -92,6 +93,7 @@ export function ScaleGrid({
92
93
  onHover={onHover}
93
94
  onHoverEnd={onHoverEnd}
94
95
  mini={mini}
96
+ tiny={tiny}
95
97
  inspectChannel={inspectChannel}
96
98
  />
97
99
  )}