@basiclines/rampa-sdk 1.5.2 → 1.6.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,4 +1,19 @@
1
- import type { ColorResult } from './types';
1
+ import type { ColorFormat, ColorResult, ColorAccessor } from './types';
2
+ /**
3
+ * Detect the format of a color string.
4
+ */
5
+ export declare function detectColorFormat(color: string): ColorFormat;
6
+ /**
7
+ * Validate that all colors in an array share the same format.
8
+ * Returns the detected format.
9
+ */
10
+ export declare function validateSameFormat(colors: string[]): ColorFormat;
11
+ /**
12
+ * Create a ColorAccessor from a hex string with a given output format.
13
+ * Returns a String object with conversion methods so it acts as a string
14
+ * in template literals, comparisons, and concatenation.
15
+ */
16
+ export declare function createColorAccessor(hex: string, outputFormat: ColorFormat): ColorAccessor;
2
17
  /**
3
18
  * Create a ColorResult from a hex string.
4
19
  * Acts as a string (hex) by default, supports .format() for conversions.
@@ -1,9 +1,10 @@
1
- import type { InterpolationMode, CubeColorSpaceResult } from './types';
1
+ import type { ColorFormat, InterpolationMode, CubeColorSpaceResult } from './types';
2
2
  /**
3
3
  * Create a 3D color cube from 8 named corner colors.
4
4
  *
5
5
  * The constructor keys become shortcut function names and tint() aliases.
6
6
  * Key order determines cube position (see CORNER_MASKS above).
7
+ * All input colors must use the same format.
7
8
  *
8
9
  * @example
9
10
  * ```ts
@@ -12,13 +13,14 @@ import type { InterpolationMode, CubeColorSpaceResult } from './types';
12
13
  * y: '#f9e2af', m: '#cba6f7', c: '#94e2d5', w: '#cdd6f4',
13
14
  * }).size(6);
14
15
  *
15
- * // With different interpolation:
16
- * const space2 = new CubeColorSpace({ ... }).interpolation('lab').size(6);
16
+ * // With different interpolation or output format:
17
+ * const space2 = new CubeColorSpace({ ... }).interpolation('lab').format('rgb').size(6);
17
18
  *
18
- * space.r(4) // → ColorResult (single-axis shortcut)
19
- * space.tint({ r: 3, b: 2 }) // ColorResult (multi-axis)
20
- * space.cube(3, 0, 2) // → ColorResult (raw coordinates)
21
- * space.palette // → string[216]
19
+ * space.r(4) // → "f38ba8" (string in output format)
20
+ * space.r(4).hsl() // "hsl(...)" (convert to another format)
21
+ * space.tint({ r: 3, b: 2 }) // → string in output format
22
+ * space.cube(3, 0, 2) // → string in output format
23
+ * space.palette // → string[216]
22
24
  *
23
25
  * // Destructure for convenience:
24
26
  * const { r, w, tint, cube } = space;
@@ -27,6 +29,7 @@ import type { InterpolationMode, CubeColorSpaceResult } from './types';
27
29
  export declare class CubeColorSpace {
28
30
  private _corners;
29
31
  private _interpolation;
32
+ private _format;
30
33
  constructor(corners: Record<string, string>, options?: {
31
34
  interpolation?: InterpolationMode;
32
35
  });
@@ -34,6 +37,10 @@ export declare class CubeColorSpace {
34
37
  * Set the interpolation mode.
35
38
  */
36
39
  interpolation(mode: InterpolationMode): this;
40
+ /**
41
+ * Set the output color format (default: 'hex').
42
+ */
43
+ format(fmt: ColorFormat): this;
37
44
  /**
38
45
  * Set the steps per axis and return the color space accessor object.
39
46
  */
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import { RampaBuilder } from './builder';
2
2
  import { ReadOnlyBuilder } from './read-only';
3
3
  import { LinearColorSpace } from './linear-color-space';
4
4
  import { CubeColorSpace } from './cube-color-space';
5
- import type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, ColorSpaceOptions } from './types';
5
+ import type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, ColorAccessor, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, ColorSpaceOptions } from './types';
6
6
  /**
7
7
  * Create a new color ramp builder from a base color.
8
8
  *
@@ -35,4 +35,4 @@ export declare namespace rampa {
35
35
  */
36
36
  export declare function color(hex: string): ColorResult;
37
37
  export { RampaBuilder, ReadOnlyBuilder, LinearColorSpace, CubeColorSpace };
38
- export type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, ColorSpaceOptions, };
38
+ export type { ColorFormat, ScaleType, BlendMode, HarmonyType, RampResult, RampaResult, ColorInfo, InterpolationMode, ColorResult, ColorAccessor, RgbComponents, LinearColorSpaceFn, CubeColorSpaceResult, ColorSpaceOptions, };
package/dist/index.js CHANGED
@@ -7941,6 +7941,60 @@ function generateCubeSpace(corners, stepsPerAxis, mode = "oklch") {
7941
7941
  }
7942
7942
 
7943
7943
  // src/color-result.ts
7944
+ function detectColorFormat(color) {
7945
+ const trimmed = color.trim();
7946
+ if (/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(trimmed))
7947
+ return "hex";
7948
+ if (/^rgb\s*\(/.test(trimmed))
7949
+ return "rgb";
7950
+ if (/^hsl\s*\(/.test(trimmed))
7951
+ return "hsl";
7952
+ if (/^oklch\s*\(/.test(trimmed))
7953
+ return "oklch";
7954
+ throw new Error(`Unknown color format: ${color}`);
7955
+ }
7956
+ function validateSameFormat(colors) {
7957
+ const formats = colors.map((c2) => detectColorFormat(c2));
7958
+ const first = formats[0];
7959
+ for (let i = 1;i < formats.length; i++) {
7960
+ if (formats[i] !== first) {
7961
+ throw new Error(`All colors must use the same format. Found '${first}' and '${formats[i]}': ${colors[0]} vs ${colors[i]}`);
7962
+ }
7963
+ }
7964
+ return first;
7965
+ }
7966
+ function createColorAccessor(hex6, outputFormat) {
7967
+ const c2 = chroma_js_default(hex6);
7968
+ const [l] = c2.oklch();
7969
+ const formatColor2 = (fmt) => {
7970
+ switch (fmt) {
7971
+ case "hsl": {
7972
+ const [h, s, l2] = c2.hsl();
7973
+ return `hsl(${Math.round(h || 0)}, ${Math.round(s * 100)}%, ${Math.round(l2 * 100)}%)`;
7974
+ }
7975
+ case "rgb": {
7976
+ const [r2, g, b] = c2.rgb();
7977
+ return `rgb(${r2}, ${g}, ${b})`;
7978
+ }
7979
+ case "oklch": {
7980
+ const [l2, ch, h] = c2.oklch();
7981
+ return `oklch(${(l2 * 100).toFixed(1)}% ${ch.toFixed(3)} ${Math.round(h || 0)})`;
7982
+ }
7983
+ default:
7984
+ return hex6;
7985
+ }
7986
+ };
7987
+ const value = formatColor2(outputFormat);
7988
+ const accessor = new String(value);
7989
+ Object.defineProperties(accessor, {
7990
+ hex: { value: () => hex6, enumerable: false },
7991
+ hsl: { value: () => formatColor2("hsl"), enumerable: false },
7992
+ rgb: { value: () => formatColor2("rgb"), enumerable: false },
7993
+ oklch: { value: () => formatColor2("oklch"), enumerable: false },
7994
+ luminance: { value: l, enumerable: false }
7995
+ });
7996
+ return accessor;
7997
+ }
7944
7998
  function createColorResult(hex6) {
7945
7999
  const c2 = chroma_js_default(hex6);
7946
8000
  const [r2, g, b] = c2.rgb();
@@ -7978,30 +8032,39 @@ function createColorResult(hex6) {
7978
8032
  class LinearColorSpace {
7979
8033
  _colors;
7980
8034
  _interpolation = "oklch";
8035
+ _format = "hex";
7981
8036
  constructor(...colors) {
7982
8037
  if (colors.length < 2) {
7983
8038
  throw new Error("LinearColorSpace requires at least 2 colors");
7984
8039
  }
8040
+ validateSameFormat(colors);
7985
8041
  this._colors = colors;
7986
8042
  }
7987
8043
  interpolation(mode) {
7988
8044
  this._interpolation = mode;
7989
8045
  return this;
7990
8046
  }
8047
+ format(fmt) {
8048
+ this._format = fmt;
8049
+ return this;
8050
+ }
7991
8051
  size(steps) {
7992
8052
  let palette;
8053
+ const outputFormat = this._format;
7993
8054
  if (this._interpolation === false) {
7994
- palette = [...this._colors];
8055
+ palette = this._colors.map((c2) => chroma_js_default(c2).hex());
7995
8056
  } else {
7996
- palette = generateLinearSpace(this._colors[0], this._colors[this._colors.length - 1], steps, this._interpolation);
8057
+ const firstHex = chroma_js_default(this._colors[0]).hex();
8058
+ const lastHex = chroma_js_default(this._colors[this._colors.length - 1]).hex();
8059
+ palette = generateLinearSpace(firstHex, lastHex, steps, this._interpolation);
7997
8060
  }
7998
- return buildFn(palette);
8061
+ return buildFn(palette, outputFormat);
7999
8062
  }
8000
8063
  }
8001
- function buildFn(palette) {
8064
+ function buildFn(palette, outputFormat) {
8002
8065
  const fn4 = (index) => {
8003
8066
  const i = Math.max(1, Math.min(palette.length, index)) - 1;
8004
- return createColorResult(palette[i]);
8067
+ return createColorAccessor(palette[i], outputFormat);
8005
8068
  };
8006
8069
  fn4.palette = palette;
8007
8070
  fn4.size = palette.length;
@@ -8023,11 +8086,13 @@ var CORNER_MASKS = [
8023
8086
  class CubeColorSpace {
8024
8087
  _corners;
8025
8088
  _interpolation;
8089
+ _format = "hex";
8026
8090
  constructor(corners, options) {
8027
8091
  const keys = Object.keys(corners);
8028
8092
  if (keys.length !== 8) {
8029
8093
  throw new Error(`CubeColorSpace requires exactly 8 corner colors, got ${keys.length}`);
8030
8094
  }
8095
+ validateSameFormat(Object.values(corners));
8031
8096
  this._corners = corners;
8032
8097
  this._interpolation = options?.interpolation ?? "oklch";
8033
8098
  }
@@ -8035,9 +8100,14 @@ class CubeColorSpace {
8035
8100
  this._interpolation = mode;
8036
8101
  return this;
8037
8102
  }
8103
+ format(fmt) {
8104
+ this._format = fmt;
8105
+ return this;
8106
+ }
8038
8107
  size(stepsPerAxis) {
8039
8108
  const keys = Object.keys(this._corners);
8040
- const cornerColors = keys.map((k3) => this._corners[k3]);
8109
+ const cornerColors = keys.map((k3) => chroma_js_default(this._corners[k3]).hex());
8110
+ const outputFormat = this._format;
8041
8111
  const aliases = {};
8042
8112
  for (let i = 0;i < 8; i++) {
8043
8113
  aliases[keys[i]] = CORNER_MASKS[i];
@@ -8049,7 +8119,7 @@ class CubeColorSpace {
8049
8119
  cy = Math.max(0, Math.min(max11, Math.round(cy)));
8050
8120
  cz = Math.max(0, Math.min(max11, Math.round(cz)));
8051
8121
  const index = cx * stepsPerAxis * stepsPerAxis + cy * stepsPerAxis + cz;
8052
- return createColorResult(palette[index]);
8122
+ return createColorAccessor(palette[index], outputFormat);
8053
8123
  };
8054
8124
  const tint = (query) => {
8055
8125
  let cx = 0, cy = 0, cz = 0;
@@ -1,16 +1,18 @@
1
- import type { InterpolationMode, LinearColorSpaceFn } from './types';
1
+ import type { ColorFormat, InterpolationMode, LinearColorSpaceFn } from './types';
2
2
  /**
3
3
  * Create a linear color space.
4
+ * All input colors must use the same format.
4
5
  *
5
6
  * @example
6
7
  * ```ts
7
8
  * // Interpolated (default: oklch)
8
9
  * const neutral = new LinearColorSpace('#ffffff', '#000000').size(24);
9
- * neutral(12) // → ColorResult (mid gray)
10
- * neutral(12).format('hsl') // → 'hsl(...)'
10
+ * neutral(12) // → "#808080" (string in output format)
11
+ * neutral(12).hsl() // → "hsl(...)" (convert to another format)
11
12
  *
12
- * // Different interpolation
13
- * const ramp = new LinearColorSpace('#ff0000', '#0000ff').interpolation('lab').size(10);
13
+ * // Different interpolation and output format:
14
+ * const ramp = new LinearColorSpace('#ff0000', '#0000ff').interpolation('lab').format('rgb').size(10);
15
+ * ramp(5) // → "rgb(128, 0, 128)"
14
16
  *
15
17
  * // Lookup table — no interpolation, just a plain color array
16
18
  * const base = new LinearColorSpace('#000', '#f00', '#0f0', '#ff0', '#00f', '#f0f', '#0ff', '#fff')
@@ -23,12 +25,17 @@ import type { InterpolationMode, LinearColorSpaceFn } from './types';
23
25
  export declare class LinearColorSpace {
24
26
  private _colors;
25
27
  private _interpolation;
28
+ private _format;
26
29
  constructor(...colors: string[]);
27
30
  /**
28
31
  * Set the interpolation mode.
29
32
  * Pass false for a plain lookup table (no interpolation).
30
33
  */
31
34
  interpolation(mode: InterpolationMode | false): this;
35
+ /**
36
+ * Set the output color format (default: 'hex').
37
+ */
38
+ format(fmt: ColorFormat): this;
32
39
  /**
33
40
  * Set the number of color steps and return the color accessor function.
34
41
  */
package/dist/types.d.ts CHANGED
@@ -55,12 +55,33 @@ export interface ColorResult {
55
55
  /** String coercion returns hex */
56
56
  toString(): string;
57
57
  }
58
+ /**
59
+ * A color accessor returned by color space functions.
60
+ * Acts as a string via toString()/valueOf() in the color space's output format.
61
+ * Has .hex(), .hsl(), .rgb(), .oklch() methods for format conversion.
62
+ */
63
+ export interface ColorAccessor {
64
+ /** Convert to hex string */
65
+ hex(): string;
66
+ /** Convert to hsl string */
67
+ hsl(): string;
68
+ /** Convert to rgb string */
69
+ rgb(): string;
70
+ /** Convert to oklch string */
71
+ oklch(): string;
72
+ /** Perceptual luminance (0-1) using OKLCH lightness */
73
+ luminance: number;
74
+ /** String coercion returns color in the space's output format */
75
+ toString(): string;
76
+ /** Primitive coercion returns the formatted string */
77
+ valueOf(): string;
78
+ }
58
79
  /**
59
80
  * The function signature returned by LinearColorSpace.
60
81
  * Call it with a 1-based index to get a color.
61
82
  */
62
83
  export interface LinearColorSpaceFn {
63
- (index: number): ColorResult;
84
+ (index: number): ColorAccessor;
64
85
  palette: string[];
65
86
  size: number;
66
87
  }
@@ -74,13 +95,13 @@ export interface LinearColorSpaceFn {
74
95
  */
75
96
  export interface CubeColorSpaceResult {
76
97
  /** Multi-axis lookup: tint({ r: 3, b: 2 }) */
77
- tint(query: Record<string, number>): ColorResult;
98
+ tint(query: Record<string, number>): ColorAccessor;
78
99
  /** Raw 3D coordinate lookup: cube(x, y, z) */
79
- cube(x: number, y: number, z: number): ColorResult;
100
+ cube(x: number, y: number, z: number): ColorAccessor;
80
101
  /** Full palette array */
81
102
  palette: string[];
82
103
  /** Steps per axis */
83
104
  size: number;
84
105
  /** Per-corner shortcut functions, keyed by constructor key names */
85
- [key: string]: ((index: number) => ColorResult) | string[] | number | ((query: Record<string, number>) => ColorResult) | ((x: number, y: number, z: number) => ColorResult);
106
+ [key: string]: ((index: number) => ColorAccessor) | string[] | number | ((query: Record<string, number>) => ColorAccessor) | ((x: number, y: number, z: number) => ColorAccessor);
86
107
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@basiclines/rampa-sdk",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "Programmatic JavaScript SDK for generating color palettes with rampa",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",