@puzzle-ui/core 0.2.0 → 0.4.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.
package/README.md CHANGED
@@ -1,70 +1,99 @@
1
- # @puzzle-ui/core
1
+ ---
2
+ title: Getting Started
3
+ description: Install Puzzle in your React app, build your first interface, and customize the theme.
4
+ ---
2
5
 
3
- Framework-independent utilities shared by the Puzzle UI packages. Use them
4
- directly without React, a theme provider, or CSS.
6
+ > \[!WARNING\] **Puzzle is not ready for production use.**
7
+ >
8
+ > This project is under active development. APIs, component props,
9
+ > package exports, styling, and internal implementation may change
10
+ > without notice. Components may be incomplete, and testing,
11
+ > accessibility, documentation, and framework compatibility are not yet
12
+ > guaranteed. Use it for experimentation and evaluation only---not for
13
+ > production applications.
5
14
 
6
- > Puzzle is under active development. APIs may change without notice; use it
7
- > for experimentation and evaluation rather than production applications.
15
+ Puzzle is a TypeScript and React UI component library built around reusable components and shared design tokens. Its components are composable and router-independent, with styling supplied by `"@puzzle-ui/theme`. The framework is setup to be compatible with `Next.js`, `Tanstack Start` and `react-router`.
8
16
 
9
- ## Installation
17
+ **Puzzle is under active development and is not ready for production use.** APIs, props, exports, and styling may change without notice. Accessibility and framework compatibility are still being tested. Use the project for experimentation and evaluation.
10
18
 
11
- Use your preferred package manager:
19
+ ## Prerequisites
12
20
 
13
- ```sh
14
- npm install @puzzle-ui/core
15
- # or
16
- bun add @puzzle-ui/core
17
- # or
18
- pnpm add @puzzle-ui/core
19
- # or
20
- yarn add @puzzle-ui/core
21
- ```
21
+ - A package manager: npm, Bun, pnpm, or Yarn.
22
+ - An existing React application with a bundler that supports CSS imports, such as Vite.
23
+ - Familiarity with React and TypeScript. The UI and theme packages require React and React DOM 19 or later within the supported React 19 range.
24
+
25
+ ## Set up a new project
26
+
27
+ Simple run our @puzzle-ui/create project template to get started.
28
+
29
+ npm:
22
30
 
23
- ## Usage
31
+ ```bash
32
+ npx @puzzle-ui/create
33
+ ```
24
34
 
25
- ```ts
26
- import { cn, isHexColor } from "@puzzle-ui/core";
35
+ bun:
27
36
 
28
- const selected = true;
29
- const className = cn("navigation-item", selected && "selected");
30
- const validColor = isHexColor("#0284C7");
37
+ ```bash
38
+ bunx @puzzle-ui/create
31
39
  ```
32
40
 
33
- ## Public utilities
41
+ Puzzle can set up a new project for you with the following framework options:
42
+
43
+ - Basic React app
44
+ - Tanstack start
45
+ - Next.js
34
46
 
35
- | Area | Exports |
36
- | --- | --- |
37
- | Class names | `cn`, `ClassnameArg` |
38
- | Strings | `stringWithCasing`, `normalizeSearchString`, `withSafeCharacters`, `nameToInitials` |
39
- | CSS values | `assertSafeCssValue`, `escapeCssString` |
40
- | Colors | `isHexColor`, `isDarkColor`, `hexToRgb`, `rgbToHex` |
41
- | Responsive values | `BREAKPOINTS`, `resolveResponsiveValue`, `resolveResponsiveValueForBreakpoint` |
42
- | Timing | `debounce` |
43
- | Types | `DeepPartial`, `ResponsiveConfig`, `ResponsiveValue`, `Breakpoint` |
47
+ Furthermore you can choose to install tailwindcss or not.
48
+ It directly installs all dependencies and sets up the project for you.
44
49
 
45
- Import from the package root; internal source paths are not public entry
46
- points. The package ships ESM and CommonJS builds with matching TypeScript
47
- declarations and has no React peer dependency.
50
+ ## Set up in an existing project:
48
51
 
49
- ## Development
52
+ Install the UI library and theme package in your application's directory. Choose your package manager below:
50
53
 
51
- From an installed repository checkout:
54
+ npm:
52
55
 
53
- ```sh
54
- npm run build --workspace=@puzzle-ui/core
56
+ ```bash
57
+ npm install @puzzle-ui/ui --save
55
58
  ```
56
59
 
57
- From this package directory, run the configured test script:
60
+ bun:
58
61
 
59
- ```sh
60
- bun run vitest
62
+ ```bash
63
+ bun add @puzzle-ui/create
61
64
  ```
62
65
 
63
- `prepack` rebuilds the package before packing or publishing. See the root
64
- [publishing guide](../../README.md#publishing-packages) for release order and
65
- validation commands.
66
+ pnpm:
67
+
68
+ ```bash
69
+ pnpm add @puzzle-ui/ui
70
+ ```
66
71
 
67
- ## License
72
+ yarn:
68
73
 
69
- MIT. See the repository [LICENSE](../../LICENSE); published packages include
70
- the same license at `dist/LICENSE`.
74
+ ```bash
75
+ yarn add @puzzle-ui/ui
76
+ ```
77
+
78
+ These commands install published packages; they do not clone the repository or build its workspaces. Puzzle does not require Bun in your application. React and React DOM are peer dependencies and should already be installed in your app.
79
+
80
+ ## Your first interface
81
+
82
+ Import components from `"@puzzle-ui/ui` and wrap your application in `Theme` from `"@puzzle-ui/theme`:
83
+
84
+ ```tsx
85
+ import { Theme } from "@puzzle-ui/theme";
86
+ import { Button } from "@puzzle-ui/ui";
87
+
88
+ export const App = () => (
89
+ <Theme>
90
+ <main>
91
+ <h1>Hello, Puzzle</h1>
92
+ <p>Build your interface with reusable components and shared tokens.</p>
93
+ <Button onClick={() => window.alert("Welcome to Puzzle!")}>
94
+ Get started
95
+ </Button>
96
+ </main>
97
+ </Theme>
98
+ );
99
+ ```
package/dist/index.cjs CHANGED
@@ -146,51 +146,310 @@ const getFirstLetter = (part) => {
146
146
  };
147
147
  const nameToInitials = (name) => {
148
148
  const parts = name.trim().split(/\s+/u).filter(Boolean);
149
- if (parts.length === 0) return "?";
150
- while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))) parts.pop();
151
- const firstInitial = getFirstLetter(parts[0]);
149
+ const [firstPart] = parts;
150
+ if (firstPart === void 0) return "?";
151
+ while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts.at(-1)))) parts.pop();
152
+ const firstInitial = getFirstLetter(firstPart);
152
153
  if (parts.length === 1) return firstInitial;
153
154
  const surname = [...parts.slice(1)].reverse().find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));
154
- return firstInitial + getFirstLetter(surname ?? parts[parts.length - 1]);
155
+ return firstInitial + getFirstLetter(surname ?? parts.at(-1));
155
156
  };
156
- // src/color/to-color.ts
157
- const hexToRgb = (hex) => {
158
- if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) throw new Error("Invalid hex color");
159
- let r, g, b;
160
- if (hex.length === 4) {
161
- r = parseInt(hex[1] + hex[1], 16);
162
- g = parseInt(hex[2] + hex[2], 16);
163
- b = parseInt(hex[3] + hex[3], 16);
164
- } else {
165
- r = parseInt(hex.slice(1, 3), 16);
166
- g = parseInt(hex.slice(3, 5), 16);
167
- b = parseInt(hex.slice(5, 7), 16);
157
+ // src/color/color.utils.ts
158
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
159
+ const normalizeHue = (hue) => (hue % 360 + 360) % 360;
160
+ const normalizeAlpha = (value) => {
161
+ if (value === void 0) return 1;
162
+ const alpha = value.endsWith("%") ? Number.parseFloat(value) / 100 : Number.parseFloat(value);
163
+ return clamp(alpha, 0, 1);
164
+ };
165
+ const CSS_NAMED_COLORS = /* @__PURE__ */ new Set([
166
+ "aliceblue",
167
+ "antiquewhite",
168
+ "aqua",
169
+ "aquamarine",
170
+ "azure",
171
+ "beige",
172
+ "bisque",
173
+ "black",
174
+ "blanchedalmond",
175
+ "blue",
176
+ "blueviolet",
177
+ "brown",
178
+ "burlywood",
179
+ "cadetblue",
180
+ "chartreuse",
181
+ "chocolate",
182
+ "coral",
183
+ "cornflowerblue",
184
+ "cornsilk",
185
+ "crimson",
186
+ "cyan",
187
+ "darkblue",
188
+ "darkcyan",
189
+ "darkgoldenrod",
190
+ "darkgray",
191
+ "darkgreen",
192
+ "darkgrey",
193
+ "darkkhaki",
194
+ "darkmagenta",
195
+ "darkolivegreen",
196
+ "darkorange",
197
+ "darkorchid",
198
+ "darkred",
199
+ "darksalmon",
200
+ "darkseagreen",
201
+ "darkslateblue",
202
+ "darkslategray",
203
+ "darkslategrey",
204
+ "darkturquoise",
205
+ "darkviolet",
206
+ "deeppink",
207
+ "deepskyblue",
208
+ "dimgray",
209
+ "dimgrey",
210
+ "dodgerblue",
211
+ "firebrick",
212
+ "floralwhite",
213
+ "forestgreen",
214
+ "fuchsia",
215
+ "gainsboro",
216
+ "ghostwhite",
217
+ "gold",
218
+ "goldenrod",
219
+ "gray",
220
+ "green",
221
+ "greenyellow",
222
+ "grey",
223
+ "honeydew",
224
+ "hotpink",
225
+ "indianred",
226
+ "indigo",
227
+ "ivory",
228
+ "khaki",
229
+ "lavender",
230
+ "lavenderblush",
231
+ "lawngreen",
232
+ "lemonchiffon",
233
+ "lightblue",
234
+ "lightcoral",
235
+ "lightcyan",
236
+ "lightgoldenrodyellow",
237
+ "lightgray",
238
+ "lightgreen",
239
+ "lightgrey",
240
+ "lightpink",
241
+ "lightsalmon",
242
+ "lightseagreen",
243
+ "lightskyblue",
244
+ "lightslategray",
245
+ "lightslategrey",
246
+ "lightsteelblue",
247
+ "lightyellow",
248
+ "lime",
249
+ "limegreen",
250
+ "linen",
251
+ "magenta",
252
+ "maroon",
253
+ "mediumaquamarine",
254
+ "mediumblue",
255
+ "mediumorchid",
256
+ "mediumpurple",
257
+ "mediumseagreen",
258
+ "mediumslateblue",
259
+ "mediumspringgreen",
260
+ "mediumturquoise",
261
+ "mediumvioletred",
262
+ "midnightblue",
263
+ "mintcream",
264
+ "mistyrose",
265
+ "moccasin",
266
+ "navajowhite",
267
+ "navy",
268
+ "oldlace",
269
+ "olive",
270
+ "olivedrab",
271
+ "orange",
272
+ "orangered",
273
+ "orchid",
274
+ "palegoldenrod",
275
+ "palegreen",
276
+ "paleturquoise",
277
+ "palevioletred",
278
+ "papayawhip",
279
+ "peachpuff",
280
+ "peru",
281
+ "pink",
282
+ "plum",
283
+ "powderblue",
284
+ "purple",
285
+ "rebeccapurple",
286
+ "red",
287
+ "rosybrown",
288
+ "royalblue",
289
+ "saddlebrown",
290
+ "salmon",
291
+ "sandybrown",
292
+ "seagreen",
293
+ "seashell",
294
+ "sienna",
295
+ "silver",
296
+ "skyblue",
297
+ "slateblue",
298
+ "slategray",
299
+ "slategrey",
300
+ "snow",
301
+ "springgreen",
302
+ "steelblue",
303
+ "tan",
304
+ "teal",
305
+ "thistle",
306
+ "tomato",
307
+ "turquoise",
308
+ "violet",
309
+ "wheat",
310
+ "white",
311
+ "whitesmoke",
312
+ "yellow",
313
+ "yellowgreen",
314
+ "transparent",
315
+ "currentcolor"
316
+ ]);
317
+ const normalizeChannel = (value) => {
318
+ const channel = value.endsWith("%") ? Number.parseFloat(value) / 100 * 255 : Number.parseFloat(value);
319
+ return clamp(channel, 0, 255);
320
+ };
321
+ const getColorType = (color) => {
322
+ const value = color.trim().toLowerCase();
323
+ if (/^var\(\s*--[\w-]+(?:\s*,\s*.+)?\)$/.test(value)) return "css-variable";
324
+ if (/^#[\da-f]{8}$/.test(value) || /^#[\da-f]{4}$/.test(value)) return "hexa";
325
+ if (/^#[\da-f]{6}$/.test(value) || /^#[\da-f]{3}$/.test(value)) return "hex";
326
+ if (/^rgba\(/.test(value)) return "rgba";
327
+ if (/^rgb\(/.test(value)) return "rgb";
328
+ if (/^hsla\(/.test(value)) return "hsla";
329
+ if (/^hsl\(/.test(value)) return "hsl";
330
+ if (/^[a-z]+$/.test(value)) return "named";
331
+ return "unknown";
332
+ };
333
+ const isCssVariable = (color) => getColorType(color) === "css-variable";
334
+ const isColor = (color) => {
335
+ const type = getColorType(color);
336
+ return type === "named" ? CSS_NAMED_COLORS.has(color.trim().toLowerCase()) : type !== "unknown";
337
+ };
338
+ const hexToRgba = (hex) => {
339
+ const value = hex.trim().replace(/^#/, "");
340
+ if (!/^(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i.test(value)) throw new Error(`Invalid HEX color: ${hex}`);
341
+ const expanded = value.length <= 4 ? [...value].map((channel) => channel + channel).join("") : value;
342
+ return {
343
+ r: Number.parseInt(expanded.slice(0, 2), 16),
344
+ g: Number.parseInt(expanded.slice(2, 4), 16),
345
+ b: Number.parseInt(expanded.slice(4, 6), 16),
346
+ a: expanded.length === 8 ? Number.parseInt(expanded.slice(6, 8), 16) / 255 : 1
347
+ };
348
+ };
349
+ const parseRgb = (color) => {
350
+ const match = color.trim().match(/^rgba?\(\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/i);
351
+ if (!match) return null;
352
+ const [, r, g, b, alpha] = match;
353
+ if (r === void 0 || g === void 0 || b === void 0) return null;
354
+ return {
355
+ r: normalizeChannel(r),
356
+ g: normalizeChannel(g),
357
+ b: normalizeChannel(b),
358
+ a: normalizeAlpha(alpha)
359
+ };
360
+ };
361
+ const hslToRgb = ({ h, s, l, a = 1 }) => {
362
+ const hue = normalizeHue(h) / 360;
363
+ const saturation = clamp(s / 100, 0, 1);
364
+ const lightness = clamp(l / 100, 0, 1);
365
+ const channel = (n) => {
366
+ const k = (n + hue * 12) % 12;
367
+ const chroma = saturation * Math.min(lightness, 1 - lightness);
368
+ return Math.round((lightness - chroma * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255);
369
+ };
370
+ return {
371
+ r: channel(0),
372
+ g: channel(8),
373
+ b: channel(4),
374
+ a: clamp(a, 0, 1)
375
+ };
376
+ };
377
+ const rgbToHsl = ({ r, g, b, a = 1 }) => {
378
+ const red = r / 255;
379
+ const green = g / 255;
380
+ const blue = b / 255;
381
+ const max = Math.max(red, green, blue);
382
+ const min = Math.min(red, green, blue);
383
+ const delta = max - min;
384
+ const l = (max + min) / 2;
385
+ let h = 0;
386
+ let s = 0;
387
+ if (delta !== 0) {
388
+ s = delta / (1 - Math.abs(2 * l - 1));
389
+ if (max === red) h = 60 * ((green - blue) / delta % 6);
390
+ else if (max === green) h = 60 * ((blue - red) / delta + 2);
391
+ else h = 60 * ((red - green) / delta + 4);
168
392
  }
169
393
  return {
170
- r,
171
- g,
172
- b
394
+ h: normalizeHue(h),
395
+ s: s * 100,
396
+ l: l * 100,
397
+ a
173
398
  };
174
399
  };
175
- const rgbToHex = (r, g, b) => {
176
- const toHex = (value) => {
177
- const hex = value.toString(16);
178
- return hex.length === 1 ? "0" + hex : hex;
400
+ const parseHsl = (color) => {
401
+ const match = color.trim().match(/^hsla?\(\s*([\d.]+)(?:deg)?\s*[, ]\s*([\d.]+)%\s*[, ]\s*([\d.]+)%(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/i);
402
+ if (!match) return null;
403
+ const [, h, s, l, alpha] = match;
404
+ return hslToRgb({
405
+ h: Number(h),
406
+ s: Number(s),
407
+ l: Number(l),
408
+ a: normalizeAlpha(alpha)
409
+ });
410
+ };
411
+ const parseColor = (color) => {
412
+ const type = getColorType(color);
413
+ if (type === "hex" || type === "hexa") return hexToRgba(color);
414
+ if (type === "rgb" || type === "rgba") return parseRgb(color);
415
+ if (type === "hsl" || type === "hsla") return parseHsl(color);
416
+ return null;
417
+ };
418
+ const rgbToCss = ({ r, g, b, a }) => a < 1 ? `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(a.toFixed(3))})` : `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
419
+ const hslToCss = ({ h, s, l, a }) => a < 1 ? `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${Number(a.toFixed(3))})` : `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;
420
+ const getColorLuminance = (color) => {
421
+ const rgb = parseColor(color);
422
+ if (!rgb) return null;
423
+ const linearize = (value) => {
424
+ const channel = value / 255;
425
+ return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
179
426
  };
180
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
427
+ return .2126 * linearize(rgb.r) + .7152 * linearize(rgb.g) + .0722 * linearize(rgb.b);
428
+ };
429
+ const isColorDark = (color) => {
430
+ const luminance = getColorLuminance(color);
431
+ return luminance === null ? null : luminance < .179;
181
432
  };
182
433
  // src/color/is-color.ts
183
- const isHexColor = (color) => {
184
- return /^#([0-9A-F]{3}){1,2}$/i.test(color);
434
+ const isHexColor = (color) => /^#(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i.test(color.trim());
435
+ const isDarkColor = (color) => {
436
+ const result = isColorDark(color);
437
+ if (result === null) throw new Error(`Unsupported color: ${color}`);
438
+ return result;
185
439
  };
186
- const linearize = (value) => {
187
- const channel = value / 255;
188
- return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
440
+ // src/color/to-color.ts
441
+ const hexToRgb = (hex) => {
442
+ const { r, g, b } = hexToRgba(hex);
443
+ return {
444
+ r,
445
+ g,
446
+ b
447
+ };
189
448
  };
190
- /** Returns whether a color is dark based on WCAG relative luminance. */
191
- const isDarkColor = (color) => {
192
- const { r, g, b } = hexToRgb(color);
193
- return .2126 * linearize(r) + .7152 * linearize(g) + .0722 * linearize(b) < .179;
449
+ const rgbToHex = (r, g, b, a) => {
450
+ const channel = (value) => Math.round(Math.min(255, Math.max(0, value))).toString(16).padStart(2, "0");
451
+ const alpha = a !== void 0 && a < 1 ? channel(Math.min(1, Math.max(0, a)) * 255) : "";
452
+ return `#${channel(r)}${channel(g)}${channel(b)}${alpha}`;
194
453
  };
195
454
  // src/timing/debounce.ts
196
455
  /**
@@ -209,17 +468,30 @@ const debounce = (func, wait) => {
209
468
  };
210
469
  exports.BREAKPOINTS = BREAKPOINTS;
211
470
  exports.assertSafeCssValue = assertSafeCssValue;
471
+ exports.clamp = clamp;
212
472
  exports.cn = cn;
213
473
  exports.debounce = debounce;
214
474
  exports.escapeCssString = escapeCssString;
475
+ exports.getColorLuminance = getColorLuminance;
476
+ exports.getColorType = getColorType;
215
477
  exports.hexToRgb = hexToRgb;
478
+ exports.hexToRgba = hexToRgba;
479
+ exports.hslToCss = hslToCss;
480
+ exports.hslToRgb = hslToRgb;
481
+ exports.isColor = isColor;
482
+ exports.isColorDark = isColorDark;
483
+ exports.isCssVariable = isCssVariable;
216
484
  exports.isDarkColor = isDarkColor;
217
485
  exports.isHexColor = isHexColor;
218
486
  exports.nameToInitials = nameToInitials;
219
487
  exports.normalizeSearchString = normalizeSearchString;
488
+ exports.parseColor = parseColor;
489
+ exports.parseRgb = parseRgb;
220
490
  exports.resolveResponsiveValue = resolveResponsiveValue;
221
491
  exports.resolveResponsiveValueForBreakpoint = resolveResponsiveValueForBreakpoint;
492
+ exports.rgbToCss = rgbToCss;
222
493
  exports.rgbToHex = rgbToHex;
494
+ exports.rgbToHsl = rgbToHsl;
223
495
  exports.stringWithCasing = stringWithCasing;
224
496
  exports.withSafeCharacters = withSafeCharacters;
225
497
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/responsive/constants.ts","../src/responsive/index.ts","../src/string/assert.ts","../src/string/normalize.ts","../src/string/casing.ts","../src/string/class-names.ts","../src/string/name-to-initials.ts","../src/color/to-color.ts","../src/color/is-color.ts","../src/timing/debounce.ts"],"sourcesContent":["export const BREAKPOINTS = [\"mobile\", \"tablet\", \"desktop\"] as const;\n","import type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n\nconst resolveResponsiveValueForBreakpoint = <T>(\n breakpoint: Breakpoint,\n value: ResponsiveValue<T>,\n fallback?: T,\n): T => {\n if (value === undefined || value === null) {\n return fallback as T;\n }\n const isNonResponsive = typeof value !== \"object\" || !(breakpoint in value);\n const resolved = isNonResponsive\n ? ((value ?? fallback) as T)\n : ((value as ResponsiveConfig<T>)[breakpoint] ?? (fallback as T));\n return resolved;\n};\n\nconst resolveResponsiveValue = <T>(\n value: ResponsiveValue<T>,\n fallback?: T,\n): Required<ResponsiveConfig<T>> => {\n const mobile = resolveResponsiveValueForBreakpoint(\"mobile\", value, fallback);\n const tablet = resolveResponsiveValueForBreakpoint(\"tablet\", value, mobile);\n const desktop = resolveResponsiveValueForBreakpoint(\"desktop\", value, tablet);\n\n return {\n mobile,\n tablet,\n desktop,\n };\n};\n\nexport { resolveResponsiveValue, resolveResponsiveValueForBreakpoint };\nexport { BREAKPOINTS } from \"./constants\";\nexport type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n","export const assertSafeCssValue = (value: unknown, label: string) => {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n throw new TypeError(`${label} must be a string or number.`);\n }\n\n const serialized = String(value).trim();\n if (\n serialized.length === 0 ||\n /[;{}<>\\u0000-\\u001f\\u007f]/.test(serialized)\n ) {\n throw new TypeError(\n `${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`,\n );\n }\n return serialized;\n};\n","/** Normalizes a search string by removing diacritics and converting to lowercase */\nexport const normalizeSearchString = (value: string): string =>\n value\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLocaleLowerCase();\n\n/** Removes unsafe characters from a string */\nexport const withSafeCharacters = (input: string): string =>\n input\n .trim()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-zA-Z0-9\\s-]/g, \"\")\n .replace(\n /([A-Z].*[^\\s][A-Z])/g,\n \"$1\".slice(0, 1).toUpperCase() + \"$1\".slice(1).toLowerCase(),\n );\n\n/** Escapes special characters in a string for use in CSS strings */\nexport const escapeCssString = (value: string): string => {\n return value.replace(/[\"\\\\\\n\\r\\f]/g, (character) => {\n switch (character) {\n case '\"':\n return '\\\\\"';\n case \"\\\\\":\n return \"\\\\\\\\\";\n case \"\\n\":\n return \"\\\\a \";\n case \"\\r\":\n return \"\\\\d \";\n case \"\\f\":\n return \"\\\\c \";\n default:\n return character;\n }\n });\n};\n","import { withSafeCharacters } from \"./normalize\";\n\n/**\n * Represents the casing options for strings.\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport type StringCasing =\n | \"lowercase\"\n | \"uppercase\"\n | \"snakecase\"\n | \"kebabcase\"\n | \"camelcase\"\n | \"pascalcase\"\n | \"sentencecase\"\n | \"headercase\";\n\n/**\n * Transforms the input string into the specified casing.\n * Casing can be one of the following:\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport const stringWithCasing = (\n input: string,\n casing: StringCasing,\n): string => {\n const trimmedInput = input.trim();\n const cleanedInput = withSafeCharacters(trimmedInput);\n\n switch (casing) {\n case \"lowercase\":\n return trimmedInput.toLowerCase();\n case \"uppercase\":\n return trimmedInput.toUpperCase();\n case \"snakecase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => a + \"_\" + b.toLowerCase())\n .replace(/[^A-Za-z0-9]+|_+/g, \"_\")\n .toLowerCase();\n case \"kebabcase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \"-\")\n .toLowerCase();\n case \"camelcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w)/g, (_m, _a, b) => b.toUpperCase());\n case \"pascalcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"$\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w?)/g, (_m, a, b) => b.toUpperCase());\n case \"sentencecase\": {\n const textcase = trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase();\n\n return textcase.charAt(0).toUpperCase() + textcase.slice(1);\n }\n case \"headercase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase()\n .replace(\n /( ?)(\\w+)( ?)/g,\n (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c,\n );\n }\n};\n","/**\n * Represents a valid argument for the `classNames` function.\n * It can be a string, an array of strings, undefined, null, or false.\n */\nexport type ClassnameArg = string | string[] | undefined | null | false;\n\n/**\n * Concatenates and trims the given arguments into a single string of class names.\n *\n * @param args - The arguments to be concatenated.\n * @returns A string of class names.\n */\nexport const cn = (...args: ClassnameArg[]): string => {\n const notNullUndefinedOrFalse = args.filter((v) => !!v).flat() as string[];\n return notNullUndefinedOrFalse\n .flatMap((v) => v.split(\" \"))\n .filter((v) => v.length > 0)\n .join(\" \")\n .trim();\n};\n","const NAME_PARTICLES = new Set([\n // Dutch\n \"van\",\n \"den\",\n \"der\",\n \"de\",\n \"ter\",\n \"ten\",\n \"te\",\n \"het\",\n \"'t\",\n\n // German\n \"von\",\n \"vom\",\n \"zum\",\n \"zur\",\n \"zu\",\n\n // French\n \"du\",\n \"des\",\n \"le\",\n \"la\",\n \"les\",\n\n // Spanish and Portuguese\n \"del\",\n \"los\",\n \"las\",\n \"da\",\n \"das\",\n \"do\",\n \"dos\",\n\n // Italian\n \"di\",\n \"della\",\n \"delle\",\n \"dello\",\n \"dei\",\n \"degli\",\n\n // Other common particles\n \"al\",\n \"el\",\n \"bin\",\n \"ibn\",\n \"bint\",\n \"af\",\n \"av\",\n \"ap\",\n \"ab\",\n]);\n\nconst NAME_SUFFIXES = new Set([\n \"jr\",\n \"sr\",\n \"ii\",\n \"iii\",\n \"iv\",\n \"v\",\n \"phd\",\n \"md\",\n]);\n\nconst normalizeNamePart = (part: string): string => {\n return part.toLocaleLowerCase().replace(/[\\p{P}\\p{S}]/gu, \"\");\n};\n\nconst getFirstLetter = (part: string): string => {\n return part.match(/\\p{L}/u)?.[0].toLocaleUpperCase() ?? \"\";\n};\n\nexport const nameToInitials = (name: string) => {\n const parts = name.trim().split(/\\s+/u).filter(Boolean);\n if (parts.length === 0) {\n return \"?\";\n }\n\n // Ignore suffixes such as Jr., Sr. and III.\n while (\n parts.length > 1 &&\n NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))\n ) {\n parts.pop();\n }\n\n const firstInitial = getFirstLetter(parts[0]);\n\n if (parts.length === 1) {\n return firstInitial;\n }\n\n // Find the last meaningful surname part, ignoring particles.\n const surname = [...parts.slice(1)]\n .reverse()\n .find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));\n\n // Fallback for unusual names consisting only of particles.\n const lastInitial = getFirstLetter(surname ?? parts[parts.length - 1]);\n\n return firstInitial + lastInitial;\n};\n","export const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) {\n throw new Error(\"Invalid hex color\");\n }\n let r: number, g: number, b: number;\n if (hex.length === 4) {\n r = parseInt(hex[1] + hex[1], 16);\n g = parseInt(hex[2] + hex[2], 16);\n b = parseInt(hex[3] + hex[3], 16);\n } else {\n r = parseInt(hex.slice(1, 3), 16);\n g = parseInt(hex.slice(3, 5), 16);\n b = parseInt(hex.slice(5, 7), 16);\n }\n return { r, g, b };\n};\n\nexport const rgbToHex = (r: number, g: number, b: number): string => {\n const toHex = (value: number) => {\n const hex = value.toString(16);\n return hex.length === 1 ? \"0\" + hex : hex;\n };\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n};\n","export const isHexColor = (color: string): boolean => {\n return /^#([0-9A-F]{3}){1,2}$/i.test(color);\n};\n\nimport { hexToRgb } from \"./to-color\";\n\nconst linearize = (value: number): number => {\n const channel = value / 255;\n\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n};\n\n/** Returns whether a color is dark based on WCAG relative luminance. */\nexport const isDarkColor = (color: string): boolean => {\n const { r, g, b } = hexToRgb(color);\n\n const luminance =\n 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);\n\n return luminance < 0.179;\n};\n","/**\n * Call the original function, but applying the debounce rules.\n *\n * Only the last call to the function shall be executed after the timeout has been reached.\n * @returns the debounced function with a cancel function property to clear the timeout.\n */\nconst debounce = <T extends unknown[]>(\n func: (...args: T) => void,\n wait: number,\n) => {\n let timeout: ReturnType<typeof setTimeout>;\n\n const cancel = () => clearTimeout(timeout);\n\n return Object.assign(\n (...args: T) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n },\n { cancel },\n );\n};\n\nexport { debounce };\n"],"mappings":";;AAAA,MAAa,cAAc;CAAC;CAAU;CAAU;AAAS;;ACEzD,MAAM,uCACJ,YACA,OACA,aACM;CACN,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAMT,OAJwB,OAAO,UAAU,YAAY,EAAE,cAAc,SAE/D,SAAS,WACT,MAA8B,eAAgB;AAEtD;AAEA,MAAM,0BACJ,OACA,aACkC;CAClC,MAAM,SAAS,oCAAoC,UAAU,OAAO,QAAQ;CAC5E,MAAM,SAAS,oCAAoC,UAAU,OAAO,MAAM;CAG1E,OAAO;EACL;EACA;EACA,SALc,oCAAoC,WAAW,OAAO,MAK9D;CACR;AACF;;AC9BA,MAAa,sBAAsB,OAAgB,UAAkB;CACnE,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAChD,MAAM,IAAI,UAAU,GAAG,MAAM,6BAA6B;CAG5D,MAAM,aAAa,OAAO,KAAK,CAAC,CAAC,KAAK;CACtC,IACE,WAAW,WAAW,KACtB,6BAA6B,KAAK,UAAU,GAE5C,MAAM,IAAI,UACR,GAAG,MAAM,+GACX;CAEF,OAAO;AACT;;;ACdA,MAAa,yBAAyB,UACpC,MACG,UAAU,KAAK,CAAC,CAChB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,kBAAkB;;AAGvB,MAAa,sBAAsB,UACjC,MACG,KAAK,CAAC,CACN,UAAU,KAAK,CAAC,CAChB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QACC,wBACA,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAC7D;;AAGJ,MAAa,mBAAmB,UAA0B;CACxD,OAAO,MAAM,QAAQ,iBAAiB,cAAc;EAClD,QAAQ,WAAR;GACE,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,SACE,OAAO;EACX;CACF,CAAC;AACH;;;;;;;;;;;;;;ACFA,MAAa,oBACX,OACA,WACW;CACX,MAAM,eAAe,MAAM,KAAK;CAChC,MAAM,eAAe,mBAAmB,YAAY;CAEpD,QAAQ,QAAR;EACE,KAAK,aACH,OAAO,aAAa,YAAY;EAClC,KAAK,aACH,OAAO,aAAa,YAAY;EAClC,KAAK,aACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,IAAI,MAAM,EAAE,YAAY,CAAC,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;EACjB,KAAK,aACH,OAAO,aACJ,QAAQ,sCAAsC,EAAE,CAAC,CACjD,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;EACjB,KAAK,aACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC,CACrD,YAAY,CAAC,CACb,QAAQ,cAAc,IAAI,IAAI,MAAM,EAAE,YAAY,CAAC;EACxD,KAAK,cACH,OAAO,aACJ,QAAQ,kCAAkC,GAAG,CAAC,CAC9C,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC,CACrD,YAAY,CAAC,CACb,QAAQ,eAAe,IAAI,GAAG,MAAM,EAAE,YAAY,CAAC;EACxD,KAAK,gBAAgB;GACnB,MAAM,WAAW,aACd,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;GAEf,OAAO,SAAS,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,SAAS,MAAM,CAAC;EAC5D;EACA,KAAK,cACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY,CAAC,CACb,QACC,mBACC,GAAG,GAAG,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,MAAM,CAAC,IAAI,CAC/D;CACN;AACF;;;;;;;;ACjFA,MAAa,MAAM,GAAG,SAAiC;CAErD,OADgC,KAAK,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAC3B,CAAC,CAC3B,SAAS,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAC5B,QAAQ,MAAM,EAAE,SAAS,CAAC,CAAC,CAC3B,KAAK,GAAG,CAAC,CACT,KAAK;AACV;;ACnBA,MAAM,iCAAiB,IAAI,IAAI;CAE7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,gCAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,qBAAqB,SAAyB;CAClD,OAAO,KAAK,kBAAkB,CAAC,CAAC,QAAQ,kBAAkB,EAAE;AAC9D;AAEA,MAAM,kBAAkB,SAAyB;CAC/C,OAAO,KAAK,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,kBAAkB,KAAK;AAC1D;AAEA,MAAa,kBAAkB,SAAiB;CAC9C,MAAM,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,OAAO,OAAO;CACtD,IAAI,MAAM,WAAW,GACnB,OAAO;CAIT,OACE,MAAM,SAAS,KACf,cAAc,IAAI,kBAAkB,MAAM,MAAM,SAAS,EAAE,CAAC,GAE5D,MAAM,IAAI;CAGZ,MAAM,eAAe,eAAe,MAAM,EAAE;CAE5C,IAAI,MAAM,WAAW,GACnB,OAAO;CAIT,MAAM,UAAU,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,CAAC,CAChC,QAAQ,CAAC,CACT,MAAM,SAAS,CAAC,eAAe,IAAI,kBAAkB,IAAI,CAAC,CAAC;CAK9D,OAAO,eAFa,eAAe,WAAW,MAAM,MAAM,SAAS,EAEnC;AAClC;;ACvGA,MAAa,YAAY,QAAqD;CAC5E,IAAI,CAAC,yBAAyB,KAAK,GAAG,GACpC,MAAM,IAAI,MAAM,mBAAmB;CAErC,IAAI,GAAW,GAAW;CAC1B,IAAI,IAAI,WAAW,GAAG;EACpB,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,EAAE;EAChC,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,EAAE;EAChC,IAAI,SAAS,IAAI,KAAK,IAAI,IAAI,EAAE;CAClC,OAAO;EACL,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAChC,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;EAChC,IAAI,SAAS,IAAI,MAAM,GAAG,CAAC,GAAG,EAAE;CAClC;CACA,OAAO;EAAE;EAAG;EAAG;CAAE;AACnB;AAEA,MAAa,YAAY,GAAW,GAAW,MAAsB;CACnE,MAAM,SAAS,UAAkB;EAC/B,MAAM,MAAM,MAAM,SAAS,EAAE;EAC7B,OAAO,IAAI,WAAW,IAAI,MAAM,MAAM;CACxC;CACA,OAAO,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,CAAC;AAC1C;;ACvBA,MAAa,cAAc,UAA2B;CACpD,OAAO,yBAAyB,KAAK,KAAK;AAC5C;AAIA,MAAM,aAAa,UAA0B;CAC3C,MAAM,UAAU,QAAQ;CAExB,OAAO,WAAW,SACd,UAAU,UACR,UAAU,QAAS,UAAU;AACrC;;AAGA,MAAa,eAAe,UAA2B;CACrD,MAAM,EAAE,GAAG,GAAG,MAAM,SAAS,KAAK;CAKlC,OAFE,QAAS,UAAU,CAAC,IAAI,QAAS,UAAU,CAAC,IAAI,QAAS,UAAU,CAAC,IAEnD;AACrB;;;;;;;;AChBA,MAAM,YACJ,MACA,SACG;CACH,IAAI;CAEJ,MAAM,eAAe,aAAa,OAAO;CAEzC,OAAO,OAAO,QACX,GAAG,SAAY;EACd,aAAa,OAAO;EACpB,UAAU,iBAAiB,KAAK,MAAA,KAAA,GAAY,IAAI,GAAG,IAAI;CACzD,GACA,EAAE,OAAO,CACX;AACF"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/responsive/constants.ts","../src/responsive/index.ts","../src/string/assert.ts","../src/string/normalize.ts","../src/string/casing.ts","../src/string/class-names.ts","../src/string/name-to-initials.ts","../src/color/color.utils.ts","../src/color/is-color.ts","../src/color/to-color.ts","../src/timing/debounce.ts"],"sourcesContent":["export const BREAKPOINTS = [\"mobile\", \"tablet\", \"desktop\"] as const;\n","import type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n\nconst resolveResponsiveValueForBreakpoint = <T>(\n breakpoint: Breakpoint,\n value: ResponsiveValue<T>,\n fallback?: T,\n): T => {\n if (value === undefined || value === null) {\n return fallback as T;\n }\n const isNonResponsive = typeof value !== \"object\" || !(breakpoint in value);\n const resolved = isNonResponsive\n ? ((value ?? fallback) as T)\n : ((value as ResponsiveConfig<T>)[breakpoint] ?? (fallback as T));\n return resolved;\n};\n\nconst resolveResponsiveValue = <T>(\n value: ResponsiveValue<T>,\n fallback?: T,\n): Required<ResponsiveConfig<T>> => {\n const mobile = resolveResponsiveValueForBreakpoint(\"mobile\", value, fallback);\n const tablet = resolveResponsiveValueForBreakpoint(\"tablet\", value, mobile);\n const desktop = resolveResponsiveValueForBreakpoint(\"desktop\", value, tablet);\n\n return {\n mobile,\n tablet,\n desktop,\n };\n};\n\nexport { resolveResponsiveValue, resolveResponsiveValueForBreakpoint };\nexport { BREAKPOINTS } from \"./constants\";\nexport type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n","export const assertSafeCssValue = (value: unknown, label: string) => {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n throw new TypeError(`${label} must be a string or number.`);\n }\n\n const serialized = String(value).trim();\n if (\n serialized.length === 0 ||\n /[;{}<>\\u0000-\\u001f\\u007f]/.test(serialized)\n ) {\n throw new TypeError(\n `${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`,\n );\n }\n return serialized;\n};\n","/** Normalizes a search string by removing diacritics and converting to lowercase */\nexport const normalizeSearchString = (value: string): string =>\n value\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLocaleLowerCase();\n\n/** Removes unsafe characters from a string */\nexport const withSafeCharacters = (input: string): string =>\n input\n .trim()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-zA-Z0-9\\s-]/g, \"\")\n .replace(\n /([A-Z].*[^\\s][A-Z])/g,\n \"$1\".slice(0, 1).toUpperCase() + \"$1\".slice(1).toLowerCase(),\n );\n\n/** Escapes special characters in a string for use in CSS strings */\nexport const escapeCssString = (value: string): string => {\n return value.replace(/[\"\\\\\\n\\r\\f]/g, (character) => {\n switch (character) {\n case '\"':\n return '\\\\\"';\n case \"\\\\\":\n return \"\\\\\\\\\";\n case \"\\n\":\n return \"\\\\a \";\n case \"\\r\":\n return \"\\\\d \";\n case \"\\f\":\n return \"\\\\c \";\n default:\n return character;\n }\n });\n};\n","import { withSafeCharacters } from \"./normalize\";\n\n/**\n * Represents the casing options for strings.\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport type StringCasing =\n | \"lowercase\"\n | \"uppercase\"\n | \"snakecase\"\n | \"kebabcase\"\n | \"camelcase\"\n | \"pascalcase\"\n | \"sentencecase\"\n | \"headercase\";\n\n/**\n * Transforms the input string into the specified casing.\n * Casing can be one of the following:\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport const stringWithCasing = (\n input: string,\n casing: StringCasing,\n): string => {\n const trimmedInput = input.trim();\n const cleanedInput = withSafeCharacters(trimmedInput);\n\n switch (casing) {\n case \"lowercase\":\n return trimmedInput.toLowerCase();\n case \"uppercase\":\n return trimmedInput.toUpperCase();\n case \"snakecase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => a + \"_\" + b.toLowerCase())\n .replace(/[^A-Za-z0-9]+|_+/g, \"_\")\n .toLowerCase();\n case \"kebabcase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \"-\")\n .toLowerCase();\n case \"camelcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w)/g, (_m, _a, b) => b.toUpperCase());\n case \"pascalcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"$\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w?)/g, (_m, a, b) => b.toUpperCase());\n case \"sentencecase\": {\n const textcase = trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase();\n\n return textcase.charAt(0).toUpperCase() + textcase.slice(1);\n }\n case \"headercase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase()\n .replace(\n /( ?)(\\w+)( ?)/g,\n (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c,\n );\n }\n};\n","/**\n * Represents a valid argument for the `classNames` function.\n * It can be a string, an array of strings, undefined, null, or false.\n */\nexport type ClassnameArg = string | string[] | undefined | null | false;\n\n/**\n * Concatenates and trims the given arguments into a single string of class names.\n *\n * @param args - The arguments to be concatenated.\n * @returns A string of class names.\n */\nexport const cn = (...args: ClassnameArg[]): string => {\n const notNullUndefinedOrFalse = args.filter((v) => !!v).flat() as string[];\n return notNullUndefinedOrFalse\n .flatMap((v) => v.split(\" \"))\n .filter((v) => v.length > 0)\n .join(\" \")\n .trim();\n};\n","const NAME_PARTICLES = new Set([\n // Dutch\n \"van\",\n \"den\",\n \"der\",\n \"de\",\n \"ter\",\n \"ten\",\n \"te\",\n \"het\",\n \"'t\",\n\n // German\n \"von\",\n \"vom\",\n \"zum\",\n \"zur\",\n \"zu\",\n\n // French\n \"du\",\n \"des\",\n \"le\",\n \"la\",\n \"les\",\n\n // Spanish and Portuguese\n \"del\",\n \"los\",\n \"las\",\n \"da\",\n \"das\",\n \"do\",\n \"dos\",\n\n // Italian\n \"di\",\n \"della\",\n \"delle\",\n \"dello\",\n \"dei\",\n \"degli\",\n\n // Other common particles\n \"al\",\n \"el\",\n \"bin\",\n \"ibn\",\n \"bint\",\n \"af\",\n \"av\",\n \"ap\",\n \"ab\",\n]);\n\nconst NAME_SUFFIXES = new Set([\n \"jr\",\n \"sr\",\n \"ii\",\n \"iii\",\n \"iv\",\n \"v\",\n \"phd\",\n \"md\",\n]);\n\nconst normalizeNamePart = (part: string): string => {\n return part.toLocaleLowerCase().replace(/[\\p{P}\\p{S}]/gu, \"\");\n};\n\nconst getFirstLetter = (part: string): string => {\n return part.match(/\\p{L}/u)?.[0].toLocaleUpperCase() ?? \"\";\n};\n\nexport const nameToInitials = (name: string) => {\n const parts = name.trim().split(/\\s+/u).filter(Boolean);\n const [firstPart] = parts;\n if (firstPart === undefined) {\n return \"?\";\n }\n\n // Ignore suffixes such as Jr., Sr. and III.\n while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts.at(-1)!))) {\n parts.pop();\n }\n\n const firstInitial = getFirstLetter(firstPart);\n\n if (parts.length === 1) {\n return firstInitial;\n }\n\n // Find the last meaningful surname part, ignoring particles.\n const surname = [...parts.slice(1)]\n .reverse()\n .find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));\n\n // Fallback for unusual names consisting only of particles.\n const lastInitial = getFirstLetter(surname ?? parts.at(-1)!);\n\n return firstInitial + lastInitial;\n};\n","import type { ColorType, HSLColor, RGBColor } from \"./color.types\";\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\nconst normalizeHue = (hue: number): number => ((hue % 360) + 360) % 360;\n\nconst normalizeAlpha = (value?: string): number => {\n if (value === undefined) return 1;\n\n const alpha = value.endsWith(\"%\")\n ? Number.parseFloat(value) / 100\n : Number.parseFloat(value);\n\n return clamp(alpha, 0, 1);\n};\n\nconst CSS_NAMED_COLORS = new Set([\n \"aliceblue\",\n \"antiquewhite\",\n \"aqua\",\n \"aquamarine\",\n \"azure\",\n \"beige\",\n \"bisque\",\n \"black\",\n \"blanchedalmond\",\n \"blue\",\n \"blueviolet\",\n \"brown\",\n \"burlywood\",\n \"cadetblue\",\n \"chartreuse\",\n \"chocolate\",\n \"coral\",\n \"cornflowerblue\",\n \"cornsilk\",\n \"crimson\",\n \"cyan\",\n \"darkblue\",\n \"darkcyan\",\n \"darkgoldenrod\",\n \"darkgray\",\n \"darkgreen\",\n \"darkgrey\",\n \"darkkhaki\",\n \"darkmagenta\",\n \"darkolivegreen\",\n \"darkorange\",\n \"darkorchid\",\n \"darkred\",\n \"darksalmon\",\n \"darkseagreen\",\n \"darkslateblue\",\n \"darkslategray\",\n \"darkslategrey\",\n \"darkturquoise\",\n \"darkviolet\",\n \"deeppink\",\n \"deepskyblue\",\n \"dimgray\",\n \"dimgrey\",\n \"dodgerblue\",\n \"firebrick\",\n \"floralwhite\",\n \"forestgreen\",\n \"fuchsia\",\n \"gainsboro\",\n \"ghostwhite\",\n \"gold\",\n \"goldenrod\",\n \"gray\",\n \"green\",\n \"greenyellow\",\n \"grey\",\n \"honeydew\",\n \"hotpink\",\n \"indianred\",\n \"indigo\",\n \"ivory\",\n \"khaki\",\n \"lavender\",\n \"lavenderblush\",\n \"lawngreen\",\n \"lemonchiffon\",\n \"lightblue\",\n \"lightcoral\",\n \"lightcyan\",\n \"lightgoldenrodyellow\",\n \"lightgray\",\n \"lightgreen\",\n \"lightgrey\",\n \"lightpink\",\n \"lightsalmon\",\n \"lightseagreen\",\n \"lightskyblue\",\n \"lightslategray\",\n \"lightslategrey\",\n \"lightsteelblue\",\n \"lightyellow\",\n \"lime\",\n \"limegreen\",\n \"linen\",\n \"magenta\",\n \"maroon\",\n \"mediumaquamarine\",\n \"mediumblue\",\n \"mediumorchid\",\n \"mediumpurple\",\n \"mediumseagreen\",\n \"mediumslateblue\",\n \"mediumspringgreen\",\n \"mediumturquoise\",\n \"mediumvioletred\",\n \"midnightblue\",\n \"mintcream\",\n \"mistyrose\",\n \"moccasin\",\n \"navajowhite\",\n \"navy\",\n \"oldlace\",\n \"olive\",\n \"olivedrab\",\n \"orange\",\n \"orangered\",\n \"orchid\",\n \"palegoldenrod\",\n \"palegreen\",\n \"paleturquoise\",\n \"palevioletred\",\n \"papayawhip\",\n \"peachpuff\",\n \"peru\",\n \"pink\",\n \"plum\",\n \"powderblue\",\n \"purple\",\n \"rebeccapurple\",\n \"red\",\n \"rosybrown\",\n \"royalblue\",\n \"saddlebrown\",\n \"salmon\",\n \"sandybrown\",\n \"seagreen\",\n \"seashell\",\n \"sienna\",\n \"silver\",\n \"skyblue\",\n \"slateblue\",\n \"slategray\",\n \"slategrey\",\n \"snow\",\n \"springgreen\",\n \"steelblue\",\n \"tan\",\n \"teal\",\n \"thistle\",\n \"tomato\",\n \"turquoise\",\n \"violet\",\n \"wheat\",\n \"white\",\n \"whitesmoke\",\n \"yellow\",\n \"yellowgreen\",\n \"transparent\",\n \"currentcolor\",\n]);\n\nconst normalizeChannel = (value: string): number => {\n const channel = value.endsWith(\"%\")\n ? (Number.parseFloat(value) / 100) * 255\n : Number.parseFloat(value);\n\n return clamp(channel, 0, 255);\n};\n\nconst getColorType = (color: string): ColorType => {\n const value = color.trim().toLowerCase();\n\n if (/^var\\(\\s*--[\\w-]+(?:\\s*,\\s*.+)?\\)$/.test(value)) {\n return \"css-variable\";\n }\n\n if (/^#[\\da-f]{8}$/.test(value) || /^#[\\da-f]{4}$/.test(value)) {\n return \"hexa\";\n }\n\n if (/^#[\\da-f]{6}$/.test(value) || /^#[\\da-f]{3}$/.test(value)) {\n return \"hex\";\n }\n\n if (/^rgba\\(/.test(value)) return \"rgba\";\n if (/^rgb\\(/.test(value)) return \"rgb\";\n if (/^hsla\\(/.test(value)) return \"hsla\";\n if (/^hsl\\(/.test(value)) return \"hsl\";\n\n if (/^[a-z]+$/.test(value)) return \"named\";\n\n return \"unknown\";\n};\n\nconst isCssVariable = (color: string): boolean =>\n getColorType(color) === \"css-variable\";\n\nconst isColor = (color: string): boolean => {\n const type = getColorType(color);\n\n return type === \"named\"\n ? CSS_NAMED_COLORS.has(color.trim().toLowerCase())\n : type !== \"unknown\";\n};\n\nconst hexToRgba = (hex: string): RGBColor => {\n const value = hex.trim().replace(/^#/, \"\");\n\n if (!/^(?:[\\da-f]{3}|[\\da-f]{4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(value)) {\n throw new Error(`Invalid HEX color: ${hex}`);\n }\n\n const expanded =\n value.length <= 4\n ? [...value].map((channel) => channel + channel).join(\"\")\n : value;\n\n const r = Number.parseInt(expanded.slice(0, 2), 16);\n const g = Number.parseInt(expanded.slice(2, 4), 16);\n const b = Number.parseInt(expanded.slice(4, 6), 16);\n const a =\n expanded.length === 8 ? Number.parseInt(expanded.slice(6, 8), 16) / 255 : 1;\n\n return { r, g, b, a };\n};\n\nconst rgbToHex = (r: number, g: number, b: number, a?: number): string => {\n const channelToHex = (channel: number): string =>\n Math.round(clamp(channel, 0, 255))\n .toString(16)\n .padStart(2, \"0\");\n\n const alpha =\n a !== undefined && a < 1 ? channelToHex(clamp(a, 0, 1) * 255) : \"\";\n\n return `#${channelToHex(r)}${channelToHex(g)}${channelToHex(b)}${alpha}`;\n};\n\nconst parseRgb = (color: string): RGBColor | null => {\n const match = color\n .trim()\n .match(\n /^rgba?\\(\\s*([\\d.]+%?)\\s*[, ]\\s*([\\d.]+%?)\\s*[, ]\\s*([\\d.]+%?)(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/i,\n );\n\n if (!match) return null;\n\n const [, r, g, b, alpha] = match;\n if (r === undefined || g === undefined || b === undefined) return null;\n\n return {\n r: normalizeChannel(r),\n g: normalizeChannel(g),\n b: normalizeChannel(b),\n a: normalizeAlpha(alpha),\n };\n};\n\nconst hslToRgb = ({ h, s, l, a = 1 }: HSLColor): RGBColor => {\n const hue = normalizeHue(h) / 360;\n const saturation = clamp(s / 100, 0, 1);\n const lightness = clamp(l / 100, 0, 1);\n\n const channel = (n: number): number => {\n const k = (n + hue * 12) % 12;\n const chroma = saturation * Math.min(lightness, 1 - lightness);\n\n return Math.round(\n (lightness - chroma * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255,\n );\n };\n\n return {\n r: channel(0),\n g: channel(8),\n b: channel(4),\n a: clamp(a, 0, 1),\n };\n};\n\nconst rgbToHsl = ({ r, g, b, a = 1 }: RGBColor): HSLColor => {\n const red = r / 255;\n const green = g / 255;\n const blue = b / 255;\n\n const max = Math.max(red, green, blue);\n const min = Math.min(red, green, blue);\n const delta = max - min;\n\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n\n if (max === red) {\n h = 60 * (((green - blue) / delta) % 6);\n } else if (max === green) {\n h = 60 * ((blue - red) / delta + 2);\n } else {\n h = 60 * ((red - green) / delta + 4);\n }\n }\n\n return {\n h: normalizeHue(h),\n s: s * 100,\n l: l * 100,\n a,\n };\n};\n\nconst parseHsl = (color: string): RGBColor | null => {\n const match = color\n .trim()\n .match(\n /^hsla?\\(\\s*([\\d.]+)(?:deg)?\\s*[, ]\\s*([\\d.]+)%\\s*[, ]\\s*([\\d.]+)%(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/i,\n );\n\n if (!match) return null;\n\n const [, h, s, l, alpha] = match;\n\n return hslToRgb({\n h: Number(h),\n s: Number(s),\n l: Number(l),\n a: normalizeAlpha(alpha),\n });\n};\n\nconst parseColor = (color: string): RGBColor | null => {\n const type = getColorType(color);\n\n if (type === \"hex\" || type === \"hexa\") {\n return hexToRgba(color);\n }\n\n if (type === \"rgb\" || type === \"rgba\") {\n return parseRgb(color);\n }\n\n if (type === \"hsl\" || type === \"hsla\") {\n return parseHsl(color);\n }\n\n return null;\n};\n\nconst rgbToCss = ({ r, g, b, a }: RGBColor): string =>\n a < 1\n ? `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(a.toFixed(3))})`\n : `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;\n\nconst hslToCss = ({ h, s, l, a }: HSLColor): string =>\n a < 1\n ? `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${Number(a.toFixed(3))})`\n : `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;\n\nconst getColorLuminance = (color: string): number | null => {\n const rgb = parseColor(color);\n\n if (!rgb) return null;\n\n const linearize = (value: number): number => {\n const channel = value / 255;\n\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n };\n\n return (\n 0.2126 * linearize(rgb.r) +\n 0.7152 * linearize(rgb.g) +\n 0.0722 * linearize(rgb.b)\n );\n};\n\nconst isColorDark = (color: string): boolean | null => {\n const luminance = getColorLuminance(color);\n\n return luminance === null ? null : luminance < 0.179;\n};\n\nexport {\n clamp,\n getColorType,\n isCssVariable,\n isColor,\n hexToRgba,\n rgbToHex,\n parseRgb,\n parseColor,\n hslToRgb,\n rgbToHsl,\n rgbToCss,\n hslToCss,\n getColorLuminance,\n isColorDark,\n};\n","import {\n getColorType,\n isColor,\n isColorDark,\n isCssVariable,\n} from \"./color.utils\";\n\nexport const isHexColor = (color: string): boolean =>\n /^#(?:[\\da-f]{3}|[\\da-f]{4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(color.trim());\n\nexport const isDarkColor = (color: string): boolean => {\n const result = isColorDark(color);\n\n if (result === null) {\n throw new Error(`Unsupported color: ${color}`);\n }\n\n return result;\n};\n\nexport { getColorType, isColor, isCssVariable, isColorDark };\n","import { hexToRgba } from \"./color.utils\";\n\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const { r, g, b } = hexToRgba(hex);\n\n return { r, g, b };\n};\n\nexport const rgbToHex = (\n r: number,\n g: number,\n b: number,\n a?: number,\n): string => {\n const channel = (value: number): string =>\n Math.round(Math.min(255, Math.max(0, value)))\n .toString(16)\n .padStart(2, \"0\");\n\n const alpha =\n a !== undefined && a < 1 ? channel(Math.min(1, Math.max(0, a)) * 255) : \"\";\n\n return `#${channel(r)}${channel(g)}${channel(b)}${alpha}`;\n};\n","/**\n * Call the original function, but applying the debounce rules.\n *\n * Only the last call to the function shall be executed after the timeout has been reached.\n * @returns the debounced function with a cancel function property to clear the timeout.\n */\nconst debounce = <T extends unknown[]>(\n func: (...args: T) => void,\n wait: number,\n) => {\n let timeout: ReturnType<typeof setTimeout>;\n\n const cancel = () => clearTimeout(timeout);\n\n return Object.assign(\n (...args: T) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n },\n { cancel },\n );\n};\n\nexport { debounce };\n"],"mappings":"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E,CAEzB;AAClC;;ACnGA,MAAM,SAAS,OAAe,KAAa,QACzC,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAEpC,MAAM,gBAAgB,SAA0B,MAAM,MAAO,OAAO;AAEpE,MAAM,kBAAkB,UAA2B;CACjD,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,MAAM,QAAQ,MAAM,SAAS,GAAG,IAC5B,OAAO,WAAW,KAAK,IAAI,MAC3B,OAAO,WAAW,KAAK;CAE3B,OAAO,MAAM,OAAO,GAAG,CAAC;AAC1B;AAEA,MAAM,mCAAmB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ,CAAC;AAED,MAAM,oBAAoB,UAA0B;CAClD,MAAM,UAAU,MAAM,SAAS,GAAG,IAC7B,OAAO,WAAW,KAAK,IAAI,MAAO,MACnC,OAAO,WAAW,KAAK;CAE3B,OAAO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"}
package/dist/index.d.cts CHANGED
@@ -52,15 +52,40 @@ type ClassnameArg = string | string[] | undefined | null | false;
52
52
  */
53
53
  export declare const cn: (...args: ClassnameArg[]) => string;
54
54
  export declare const nameToInitials: (name: string) => string;
55
+ type ColorType = "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla" | "named" | "css-variable" | "unknown";
56
+ type RGBColor = {
57
+ r: number;
58
+ g: number;
59
+ b: number;
60
+ a: number;
61
+ };
62
+ type HSLColor = {
63
+ h: number;
64
+ s: number;
65
+ l: number;
66
+ a: number;
67
+ };
68
+ declare const clamp: (value: number, min: number, max: number) => number;
69
+ declare const getColorType: (color: string) => ColorType;
70
+ declare const isCssVariable: (color: string) => boolean;
71
+ declare const isColor: (color: string) => boolean;
72
+ declare const hexToRgba: (hex: string) => RGBColor;
73
+ declare const parseRgb: (color: string) => RGBColor | null;
74
+ declare const hslToRgb: ({ h, s, l, a }: HSLColor) => RGBColor;
75
+ declare const rgbToHsl: ({ r, g, b, a }: RGBColor) => HSLColor;
76
+ declare const parseColor: (color: string) => RGBColor | null;
77
+ declare const rgbToCss: ({ r, g, b, a }: RGBColor) => string;
78
+ declare const hslToCss: ({ h, s, l, a }: HSLColor) => string;
79
+ declare const getColorLuminance: (color: string) => number | null;
80
+ declare const isColorDark: (color: string) => boolean | null;
55
81
  export declare const isHexColor: (color: string) => boolean;
56
- /** Returns whether a color is dark based on WCAG relative luminance. */
57
82
  export declare const isDarkColor: (color: string) => boolean;
58
83
  export declare const hexToRgb: (hex: string) => {
59
84
  r: number;
60
85
  g: number;
61
86
  b: number;
62
87
  };
63
- export declare const rgbToHex: (r: number, g: number, b: number) => string;
88
+ export declare const rgbToHex: (r: number, g: number, b: number, a?: number) => string;
64
89
  /**
65
90
  * Call the original function, but applying the debounce rules.
66
91
  *
@@ -70,4 +95,4 @@ export declare const rgbToHex: (r: number, g: number, b: number) => string;
70
95
  declare const debounce: <T extends unknown[]>(func: (...args: T) => void, wait: number) => ((...args: T) => void) & {
71
96
  cancel: () => void;
72
97
  };
73
- export { type Breakpoint, type ClassnameArg, type DeepPartial, type ResponsiveConfig, type ResponsiveValue, debounce, resolveResponsiveValue, resolveResponsiveValueForBreakpoint };
98
+ export { type Breakpoint, type ClassnameArg, type ColorType, type DeepPartial, type HSLColor, type RGBColor, type ResponsiveConfig, type ResponsiveValue, clamp, debounce, getColorLuminance, getColorType, hexToRgba, hslToCss, hslToRgb, isColor, isColorDark, isCssVariable, parseColor, parseRgb, resolveResponsiveValue, resolveResponsiveValueForBreakpoint, rgbToCss, rgbToHsl };
package/dist/index.d.ts CHANGED
@@ -52,15 +52,40 @@ type ClassnameArg = string | string[] | undefined | null | false;
52
52
  */
53
53
  export declare const cn: (...args: ClassnameArg[]) => string;
54
54
  export declare const nameToInitials: (name: string) => string;
55
+ type ColorType = "hex" | "hexa" | "rgb" | "rgba" | "hsl" | "hsla" | "named" | "css-variable" | "unknown";
56
+ type RGBColor = {
57
+ r: number;
58
+ g: number;
59
+ b: number;
60
+ a: number;
61
+ };
62
+ type HSLColor = {
63
+ h: number;
64
+ s: number;
65
+ l: number;
66
+ a: number;
67
+ };
68
+ declare const clamp: (value: number, min: number, max: number) => number;
69
+ declare const getColorType: (color: string) => ColorType;
70
+ declare const isCssVariable: (color: string) => boolean;
71
+ declare const isColor: (color: string) => boolean;
72
+ declare const hexToRgba: (hex: string) => RGBColor;
73
+ declare const parseRgb: (color: string) => RGBColor | null;
74
+ declare const hslToRgb: ({ h, s, l, a }: HSLColor) => RGBColor;
75
+ declare const rgbToHsl: ({ r, g, b, a }: RGBColor) => HSLColor;
76
+ declare const parseColor: (color: string) => RGBColor | null;
77
+ declare const rgbToCss: ({ r, g, b, a }: RGBColor) => string;
78
+ declare const hslToCss: ({ h, s, l, a }: HSLColor) => string;
79
+ declare const getColorLuminance: (color: string) => number | null;
80
+ declare const isColorDark: (color: string) => boolean | null;
55
81
  export declare const isHexColor: (color: string) => boolean;
56
- /** Returns whether a color is dark based on WCAG relative luminance. */
57
82
  export declare const isDarkColor: (color: string) => boolean;
58
83
  export declare const hexToRgb: (hex: string) => {
59
84
  r: number;
60
85
  g: number;
61
86
  b: number;
62
87
  };
63
- export declare const rgbToHex: (r: number, g: number, b: number) => string;
88
+ export declare const rgbToHex: (r: number, g: number, b: number, a?: number) => string;
64
89
  /**
65
90
  * Call the original function, but applying the debounce rules.
66
91
  *
@@ -70,4 +95,4 @@ export declare const rgbToHex: (r: number, g: number, b: number) => string;
70
95
  declare const debounce: <T extends unknown[]>(func: (...args: T) => void, wait: number) => ((...args: T) => void) & {
71
96
  cancel: () => void;
72
97
  };
73
- export { type Breakpoint, type ClassnameArg, type DeepPartial, type ResponsiveConfig, type ResponsiveValue, debounce, resolveResponsiveValue, resolveResponsiveValueForBreakpoint };
98
+ export { type Breakpoint, type ClassnameArg, type ColorType, type DeepPartial, type HSLColor, type RGBColor, type ResponsiveConfig, type ResponsiveValue, clamp, debounce, getColorLuminance, getColorType, hexToRgba, hslToCss, hslToRgb, isColor, isColorDark, isCssVariable, parseColor, parseRgb, resolveResponsiveValue, resolveResponsiveValueForBreakpoint, rgbToCss, rgbToHsl };
package/dist/index.js CHANGED
@@ -145,51 +145,310 @@ const getFirstLetter = (part) => {
145
145
  };
146
146
  const nameToInitials = (name) => {
147
147
  const parts = name.trim().split(/\s+/u).filter(Boolean);
148
- if (parts.length === 0) return "?";
149
- while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))) parts.pop();
150
- const firstInitial = getFirstLetter(parts[0]);
148
+ const [firstPart] = parts;
149
+ if (firstPart === void 0) return "?";
150
+ while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts.at(-1)))) parts.pop();
151
+ const firstInitial = getFirstLetter(firstPart);
151
152
  if (parts.length === 1) return firstInitial;
152
153
  const surname = [...parts.slice(1)].reverse().find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));
153
- return firstInitial + getFirstLetter(surname ?? parts[parts.length - 1]);
154
+ return firstInitial + getFirstLetter(surname ?? parts.at(-1));
154
155
  };
155
- // src/color/to-color.ts
156
- const hexToRgb = (hex) => {
157
- if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) throw new Error("Invalid hex color");
158
- let r, g, b;
159
- if (hex.length === 4) {
160
- r = parseInt(hex[1] + hex[1], 16);
161
- g = parseInt(hex[2] + hex[2], 16);
162
- b = parseInt(hex[3] + hex[3], 16);
163
- } else {
164
- r = parseInt(hex.slice(1, 3), 16);
165
- g = parseInt(hex.slice(3, 5), 16);
166
- b = parseInt(hex.slice(5, 7), 16);
156
+ // src/color/color.utils.ts
157
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
158
+ const normalizeHue = (hue) => (hue % 360 + 360) % 360;
159
+ const normalizeAlpha = (value) => {
160
+ if (value === void 0) return 1;
161
+ const alpha = value.endsWith("%") ? Number.parseFloat(value) / 100 : Number.parseFloat(value);
162
+ return clamp(alpha, 0, 1);
163
+ };
164
+ const CSS_NAMED_COLORS = /* @__PURE__ */ new Set([
165
+ "aliceblue",
166
+ "antiquewhite",
167
+ "aqua",
168
+ "aquamarine",
169
+ "azure",
170
+ "beige",
171
+ "bisque",
172
+ "black",
173
+ "blanchedalmond",
174
+ "blue",
175
+ "blueviolet",
176
+ "brown",
177
+ "burlywood",
178
+ "cadetblue",
179
+ "chartreuse",
180
+ "chocolate",
181
+ "coral",
182
+ "cornflowerblue",
183
+ "cornsilk",
184
+ "crimson",
185
+ "cyan",
186
+ "darkblue",
187
+ "darkcyan",
188
+ "darkgoldenrod",
189
+ "darkgray",
190
+ "darkgreen",
191
+ "darkgrey",
192
+ "darkkhaki",
193
+ "darkmagenta",
194
+ "darkolivegreen",
195
+ "darkorange",
196
+ "darkorchid",
197
+ "darkred",
198
+ "darksalmon",
199
+ "darkseagreen",
200
+ "darkslateblue",
201
+ "darkslategray",
202
+ "darkslategrey",
203
+ "darkturquoise",
204
+ "darkviolet",
205
+ "deeppink",
206
+ "deepskyblue",
207
+ "dimgray",
208
+ "dimgrey",
209
+ "dodgerblue",
210
+ "firebrick",
211
+ "floralwhite",
212
+ "forestgreen",
213
+ "fuchsia",
214
+ "gainsboro",
215
+ "ghostwhite",
216
+ "gold",
217
+ "goldenrod",
218
+ "gray",
219
+ "green",
220
+ "greenyellow",
221
+ "grey",
222
+ "honeydew",
223
+ "hotpink",
224
+ "indianred",
225
+ "indigo",
226
+ "ivory",
227
+ "khaki",
228
+ "lavender",
229
+ "lavenderblush",
230
+ "lawngreen",
231
+ "lemonchiffon",
232
+ "lightblue",
233
+ "lightcoral",
234
+ "lightcyan",
235
+ "lightgoldenrodyellow",
236
+ "lightgray",
237
+ "lightgreen",
238
+ "lightgrey",
239
+ "lightpink",
240
+ "lightsalmon",
241
+ "lightseagreen",
242
+ "lightskyblue",
243
+ "lightslategray",
244
+ "lightslategrey",
245
+ "lightsteelblue",
246
+ "lightyellow",
247
+ "lime",
248
+ "limegreen",
249
+ "linen",
250
+ "magenta",
251
+ "maroon",
252
+ "mediumaquamarine",
253
+ "mediumblue",
254
+ "mediumorchid",
255
+ "mediumpurple",
256
+ "mediumseagreen",
257
+ "mediumslateblue",
258
+ "mediumspringgreen",
259
+ "mediumturquoise",
260
+ "mediumvioletred",
261
+ "midnightblue",
262
+ "mintcream",
263
+ "mistyrose",
264
+ "moccasin",
265
+ "navajowhite",
266
+ "navy",
267
+ "oldlace",
268
+ "olive",
269
+ "olivedrab",
270
+ "orange",
271
+ "orangered",
272
+ "orchid",
273
+ "palegoldenrod",
274
+ "palegreen",
275
+ "paleturquoise",
276
+ "palevioletred",
277
+ "papayawhip",
278
+ "peachpuff",
279
+ "peru",
280
+ "pink",
281
+ "plum",
282
+ "powderblue",
283
+ "purple",
284
+ "rebeccapurple",
285
+ "red",
286
+ "rosybrown",
287
+ "royalblue",
288
+ "saddlebrown",
289
+ "salmon",
290
+ "sandybrown",
291
+ "seagreen",
292
+ "seashell",
293
+ "sienna",
294
+ "silver",
295
+ "skyblue",
296
+ "slateblue",
297
+ "slategray",
298
+ "slategrey",
299
+ "snow",
300
+ "springgreen",
301
+ "steelblue",
302
+ "tan",
303
+ "teal",
304
+ "thistle",
305
+ "tomato",
306
+ "turquoise",
307
+ "violet",
308
+ "wheat",
309
+ "white",
310
+ "whitesmoke",
311
+ "yellow",
312
+ "yellowgreen",
313
+ "transparent",
314
+ "currentcolor"
315
+ ]);
316
+ const normalizeChannel = (value) => {
317
+ const channel = value.endsWith("%") ? Number.parseFloat(value) / 100 * 255 : Number.parseFloat(value);
318
+ return clamp(channel, 0, 255);
319
+ };
320
+ const getColorType = (color) => {
321
+ const value = color.trim().toLowerCase();
322
+ if (/^var\(\s*--[\w-]+(?:\s*,\s*.+)?\)$/.test(value)) return "css-variable";
323
+ if (/^#[\da-f]{8}$/.test(value) || /^#[\da-f]{4}$/.test(value)) return "hexa";
324
+ if (/^#[\da-f]{6}$/.test(value) || /^#[\da-f]{3}$/.test(value)) return "hex";
325
+ if (/^rgba\(/.test(value)) return "rgba";
326
+ if (/^rgb\(/.test(value)) return "rgb";
327
+ if (/^hsla\(/.test(value)) return "hsla";
328
+ if (/^hsl\(/.test(value)) return "hsl";
329
+ if (/^[a-z]+$/.test(value)) return "named";
330
+ return "unknown";
331
+ };
332
+ const isCssVariable = (color) => getColorType(color) === "css-variable";
333
+ const isColor = (color) => {
334
+ const type = getColorType(color);
335
+ return type === "named" ? CSS_NAMED_COLORS.has(color.trim().toLowerCase()) : type !== "unknown";
336
+ };
337
+ const hexToRgba = (hex) => {
338
+ const value = hex.trim().replace(/^#/, "");
339
+ if (!/^(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i.test(value)) throw new Error(`Invalid HEX color: ${hex}`);
340
+ const expanded = value.length <= 4 ? [...value].map((channel) => channel + channel).join("") : value;
341
+ return {
342
+ r: Number.parseInt(expanded.slice(0, 2), 16),
343
+ g: Number.parseInt(expanded.slice(2, 4), 16),
344
+ b: Number.parseInt(expanded.slice(4, 6), 16),
345
+ a: expanded.length === 8 ? Number.parseInt(expanded.slice(6, 8), 16) / 255 : 1
346
+ };
347
+ };
348
+ const parseRgb = (color) => {
349
+ const match = color.trim().match(/^rgba?\(\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)\s*[, ]\s*([\d.]+%?)(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/i);
350
+ if (!match) return null;
351
+ const [, r, g, b, alpha] = match;
352
+ if (r === void 0 || g === void 0 || b === void 0) return null;
353
+ return {
354
+ r: normalizeChannel(r),
355
+ g: normalizeChannel(g),
356
+ b: normalizeChannel(b),
357
+ a: normalizeAlpha(alpha)
358
+ };
359
+ };
360
+ const hslToRgb = ({ h, s, l, a = 1 }) => {
361
+ const hue = normalizeHue(h) / 360;
362
+ const saturation = clamp(s / 100, 0, 1);
363
+ const lightness = clamp(l / 100, 0, 1);
364
+ const channel = (n) => {
365
+ const k = (n + hue * 12) % 12;
366
+ const chroma = saturation * Math.min(lightness, 1 - lightness);
367
+ return Math.round((lightness - chroma * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255);
368
+ };
369
+ return {
370
+ r: channel(0),
371
+ g: channel(8),
372
+ b: channel(4),
373
+ a: clamp(a, 0, 1)
374
+ };
375
+ };
376
+ const rgbToHsl = ({ r, g, b, a = 1 }) => {
377
+ const red = r / 255;
378
+ const green = g / 255;
379
+ const blue = b / 255;
380
+ const max = Math.max(red, green, blue);
381
+ const min = Math.min(red, green, blue);
382
+ const delta = max - min;
383
+ const l = (max + min) / 2;
384
+ let h = 0;
385
+ let s = 0;
386
+ if (delta !== 0) {
387
+ s = delta / (1 - Math.abs(2 * l - 1));
388
+ if (max === red) h = 60 * ((green - blue) / delta % 6);
389
+ else if (max === green) h = 60 * ((blue - red) / delta + 2);
390
+ else h = 60 * ((red - green) / delta + 4);
167
391
  }
168
392
  return {
169
- r,
170
- g,
171
- b
393
+ h: normalizeHue(h),
394
+ s: s * 100,
395
+ l: l * 100,
396
+ a
172
397
  };
173
398
  };
174
- const rgbToHex = (r, g, b) => {
175
- const toHex = (value) => {
176
- const hex = value.toString(16);
177
- return hex.length === 1 ? "0" + hex : hex;
399
+ const parseHsl = (color) => {
400
+ const match = color.trim().match(/^hsla?\(\s*([\d.]+)(?:deg)?\s*[, ]\s*([\d.]+)%\s*[, ]\s*([\d.]+)%(?:\s*[,/]\s*([\d.]+%?))?\s*\)$/i);
401
+ if (!match) return null;
402
+ const [, h, s, l, alpha] = match;
403
+ return hslToRgb({
404
+ h: Number(h),
405
+ s: Number(s),
406
+ l: Number(l),
407
+ a: normalizeAlpha(alpha)
408
+ });
409
+ };
410
+ const parseColor = (color) => {
411
+ const type = getColorType(color);
412
+ if (type === "hex" || type === "hexa") return hexToRgba(color);
413
+ if (type === "rgb" || type === "rgba") return parseRgb(color);
414
+ if (type === "hsl" || type === "hsla") return parseHsl(color);
415
+ return null;
416
+ };
417
+ const rgbToCss = ({ r, g, b, a }) => a < 1 ? `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(a.toFixed(3))})` : `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;
418
+ const hslToCss = ({ h, s, l, a }) => a < 1 ? `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${Number(a.toFixed(3))})` : `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;
419
+ const getColorLuminance = (color) => {
420
+ const rgb = parseColor(color);
421
+ if (!rgb) return null;
422
+ const linearize = (value) => {
423
+ const channel = value / 255;
424
+ return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
178
425
  };
179
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
426
+ return .2126 * linearize(rgb.r) + .7152 * linearize(rgb.g) + .0722 * linearize(rgb.b);
427
+ };
428
+ const isColorDark = (color) => {
429
+ const luminance = getColorLuminance(color);
430
+ return luminance === null ? null : luminance < .179;
180
431
  };
181
432
  // src/color/is-color.ts
182
- const isHexColor = (color) => {
183
- return /^#([0-9A-F]{3}){1,2}$/i.test(color);
433
+ const isHexColor = (color) => /^#(?:[\da-f]{3}|[\da-f]{4}|[\da-f]{6}|[\da-f]{8})$/i.test(color.trim());
434
+ const isDarkColor = (color) => {
435
+ const result = isColorDark(color);
436
+ if (result === null) throw new Error(`Unsupported color: ${color}`);
437
+ return result;
184
438
  };
185
- const linearize = (value) => {
186
- const channel = value / 255;
187
- return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
439
+ // src/color/to-color.ts
440
+ const hexToRgb = (hex) => {
441
+ const { r, g, b } = hexToRgba(hex);
442
+ return {
443
+ r,
444
+ g,
445
+ b
446
+ };
188
447
  };
189
- /** Returns whether a color is dark based on WCAG relative luminance. */
190
- const isDarkColor = (color) => {
191
- const { r, g, b } = hexToRgb(color);
192
- return .2126 * linearize(r) + .7152 * linearize(g) + .0722 * linearize(b) < .179;
448
+ const rgbToHex = (r, g, b, a) => {
449
+ const channel = (value) => Math.round(Math.min(255, Math.max(0, value))).toString(16).padStart(2, "0");
450
+ const alpha = a !== void 0 && a < 1 ? channel(Math.min(1, Math.max(0, a)) * 255) : "";
451
+ return `#${channel(r)}${channel(g)}${channel(b)}${alpha}`;
193
452
  };
194
453
  // src/timing/debounce.ts
195
454
  /**
@@ -206,6 +465,6 @@ const debounce = (func, wait) => {
206
465
  timeout = setTimeout(() => func.apply(void 0, args), wait);
207
466
  }, { cancel });
208
467
  };
209
- export { BREAKPOINTS, assertSafeCssValue, cn, debounce, escapeCssString, hexToRgb, isDarkColor, isHexColor, nameToInitials, normalizeSearchString, resolveResponsiveValue, resolveResponsiveValueForBreakpoint, rgbToHex, stringWithCasing, withSafeCharacters };
468
+ export { BREAKPOINTS, assertSafeCssValue, clamp, cn, debounce, escapeCssString, getColorLuminance, getColorType, hexToRgb, hexToRgba, hslToCss, hslToRgb, isColor, isColorDark, isCssVariable, isDarkColor, isHexColor, nameToInitials, normalizeSearchString, parseColor, parseRgb, resolveResponsiveValue, resolveResponsiveValueForBreakpoint, rgbToCss, rgbToHex, rgbToHsl, stringWithCasing, withSafeCharacters };
210
469
 
211
470
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/responsive/constants.ts","../src/responsive/index.ts","../src/string/assert.ts","../src/string/normalize.ts","../src/string/casing.ts","../src/string/class-names.ts","../src/string/name-to-initials.ts","../src/color/to-color.ts","../src/color/is-color.ts","../src/timing/debounce.ts"],"sourcesContent":["export const BREAKPOINTS = [\"mobile\", \"tablet\", \"desktop\"] as const;\n","import type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n\nconst resolveResponsiveValueForBreakpoint = <T>(\n breakpoint: Breakpoint,\n value: ResponsiveValue<T>,\n fallback?: T,\n): T => {\n if (value === undefined || value === null) {\n return fallback as T;\n }\n const isNonResponsive = typeof value !== \"object\" || !(breakpoint in value);\n const resolved = isNonResponsive\n ? ((value ?? fallback) as T)\n : ((value as ResponsiveConfig<T>)[breakpoint] ?? (fallback as T));\n return resolved;\n};\n\nconst resolveResponsiveValue = <T>(\n value: ResponsiveValue<T>,\n fallback?: T,\n): Required<ResponsiveConfig<T>> => {\n const mobile = resolveResponsiveValueForBreakpoint(\"mobile\", value, fallback);\n const tablet = resolveResponsiveValueForBreakpoint(\"tablet\", value, mobile);\n const desktop = resolveResponsiveValueForBreakpoint(\"desktop\", value, tablet);\n\n return {\n mobile,\n tablet,\n desktop,\n };\n};\n\nexport { resolveResponsiveValue, resolveResponsiveValueForBreakpoint };\nexport { BREAKPOINTS } from \"./constants\";\nexport type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n","export const assertSafeCssValue = (value: unknown, label: string) => {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n throw new TypeError(`${label} must be a string or number.`);\n }\n\n const serialized = String(value).trim();\n if (\n serialized.length === 0 ||\n /[;{}<>\\u0000-\\u001f\\u007f]/.test(serialized)\n ) {\n throw new TypeError(\n `${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`,\n );\n }\n return serialized;\n};\n","/** Normalizes a search string by removing diacritics and converting to lowercase */\nexport const normalizeSearchString = (value: string): string =>\n value\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLocaleLowerCase();\n\n/** Removes unsafe characters from a string */\nexport const withSafeCharacters = (input: string): string =>\n input\n .trim()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-zA-Z0-9\\s-]/g, \"\")\n .replace(\n /([A-Z].*[^\\s][A-Z])/g,\n \"$1\".slice(0, 1).toUpperCase() + \"$1\".slice(1).toLowerCase(),\n );\n\n/** Escapes special characters in a string for use in CSS strings */\nexport const escapeCssString = (value: string): string => {\n return value.replace(/[\"\\\\\\n\\r\\f]/g, (character) => {\n switch (character) {\n case '\"':\n return '\\\\\"';\n case \"\\\\\":\n return \"\\\\\\\\\";\n case \"\\n\":\n return \"\\\\a \";\n case \"\\r\":\n return \"\\\\d \";\n case \"\\f\":\n return \"\\\\c \";\n default:\n return character;\n }\n });\n};\n","import { withSafeCharacters } from \"./normalize\";\n\n/**\n * Represents the casing options for strings.\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport type StringCasing =\n | \"lowercase\"\n | \"uppercase\"\n | \"snakecase\"\n | \"kebabcase\"\n | \"camelcase\"\n | \"pascalcase\"\n | \"sentencecase\"\n | \"headercase\";\n\n/**\n * Transforms the input string into the specified casing.\n * Casing can be one of the following:\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport const stringWithCasing = (\n input: string,\n casing: StringCasing,\n): string => {\n const trimmedInput = input.trim();\n const cleanedInput = withSafeCharacters(trimmedInput);\n\n switch (casing) {\n case \"lowercase\":\n return trimmedInput.toLowerCase();\n case \"uppercase\":\n return trimmedInput.toUpperCase();\n case \"snakecase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => a + \"_\" + b.toLowerCase())\n .replace(/[^A-Za-z0-9]+|_+/g, \"_\")\n .toLowerCase();\n case \"kebabcase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \"-\")\n .toLowerCase();\n case \"camelcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w)/g, (_m, _a, b) => b.toUpperCase());\n case \"pascalcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"$\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w?)/g, (_m, a, b) => b.toUpperCase());\n case \"sentencecase\": {\n const textcase = trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase();\n\n return textcase.charAt(0).toUpperCase() + textcase.slice(1);\n }\n case \"headercase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase()\n .replace(\n /( ?)(\\w+)( ?)/g,\n (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c,\n );\n }\n};\n","/**\n * Represents a valid argument for the `classNames` function.\n * It can be a string, an array of strings, undefined, null, or false.\n */\nexport type ClassnameArg = string | string[] | undefined | null | false;\n\n/**\n * Concatenates and trims the given arguments into a single string of class names.\n *\n * @param args - The arguments to be concatenated.\n * @returns A string of class names.\n */\nexport const cn = (...args: ClassnameArg[]): string => {\n const notNullUndefinedOrFalse = args.filter((v) => !!v).flat() as string[];\n return notNullUndefinedOrFalse\n .flatMap((v) => v.split(\" \"))\n .filter((v) => v.length > 0)\n .join(\" \")\n .trim();\n};\n","const NAME_PARTICLES = new Set([\n // Dutch\n \"van\",\n \"den\",\n \"der\",\n \"de\",\n \"ter\",\n \"ten\",\n \"te\",\n \"het\",\n \"'t\",\n\n // German\n \"von\",\n \"vom\",\n \"zum\",\n \"zur\",\n \"zu\",\n\n // French\n \"du\",\n \"des\",\n \"le\",\n \"la\",\n \"les\",\n\n // Spanish and Portuguese\n \"del\",\n \"los\",\n \"las\",\n \"da\",\n \"das\",\n \"do\",\n \"dos\",\n\n // Italian\n \"di\",\n \"della\",\n \"delle\",\n \"dello\",\n \"dei\",\n \"degli\",\n\n // Other common particles\n \"al\",\n \"el\",\n \"bin\",\n \"ibn\",\n \"bint\",\n \"af\",\n \"av\",\n \"ap\",\n \"ab\",\n]);\n\nconst NAME_SUFFIXES = new Set([\n \"jr\",\n \"sr\",\n \"ii\",\n \"iii\",\n \"iv\",\n \"v\",\n \"phd\",\n \"md\",\n]);\n\nconst normalizeNamePart = (part: string): string => {\n return part.toLocaleLowerCase().replace(/[\\p{P}\\p{S}]/gu, \"\");\n};\n\nconst getFirstLetter = (part: string): string => {\n return part.match(/\\p{L}/u)?.[0].toLocaleUpperCase() ?? \"\";\n};\n\nexport const nameToInitials = (name: string) => {\n const parts = name.trim().split(/\\s+/u).filter(Boolean);\n if (parts.length === 0) {\n return \"?\";\n }\n\n // Ignore suffixes such as Jr., Sr. and III.\n while (\n parts.length > 1 &&\n NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))\n ) {\n parts.pop();\n }\n\n const firstInitial = getFirstLetter(parts[0]);\n\n if (parts.length === 1) {\n return firstInitial;\n }\n\n // Find the last meaningful surname part, ignoring particles.\n const surname = [...parts.slice(1)]\n .reverse()\n .find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));\n\n // Fallback for unusual names consisting only of particles.\n const lastInitial = getFirstLetter(surname ?? parts[parts.length - 1]);\n\n return firstInitial + lastInitial;\n};\n","export const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) {\n throw new Error(\"Invalid hex color\");\n }\n let r: number, g: number, b: number;\n if (hex.length === 4) {\n r = parseInt(hex[1] + hex[1], 16);\n g = parseInt(hex[2] + hex[2], 16);\n b = parseInt(hex[3] + hex[3], 16);\n } else {\n r = parseInt(hex.slice(1, 3), 16);\n g = parseInt(hex.slice(3, 5), 16);\n b = parseInt(hex.slice(5, 7), 16);\n }\n return { r, g, b };\n};\n\nexport const rgbToHex = (r: number, g: number, b: number): string => {\n const toHex = (value: number) => {\n const hex = value.toString(16);\n return hex.length === 1 ? \"0\" + hex : hex;\n };\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n};\n","export const isHexColor = (color: string): boolean => {\n return /^#([0-9A-F]{3}){1,2}$/i.test(color);\n};\n\nimport { hexToRgb } from \"./to-color\";\n\nconst linearize = (value: number): number => {\n const channel = value / 255;\n\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n};\n\n/** Returns whether a color is dark based on WCAG relative luminance. */\nexport const isDarkColor = (color: string): boolean => {\n const { r, g, b } = hexToRgb(color);\n\n const luminance =\n 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);\n\n return luminance < 0.179;\n};\n","/**\n * Call the original function, but applying the debounce rules.\n *\n * Only the last call to the function shall be executed after the timeout has been reached.\n * @returns the debounced function with a cancel function property to clear the timeout.\n */\nconst debounce = <T extends unknown[]>(\n func: (...args: T) => void,\n wait: number,\n) => {\n let timeout: ReturnType<typeof setTimeout>;\n\n const cancel = () => clearTimeout(timeout);\n\n return Object.assign(\n (...args: T) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n },\n { cancel },\n );\n};\n\nexport { debounce };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/responsive/constants.ts","../src/responsive/index.ts","../src/string/assert.ts","../src/string/normalize.ts","../src/string/casing.ts","../src/string/class-names.ts","../src/string/name-to-initials.ts","../src/color/color.utils.ts","../src/color/is-color.ts","../src/color/to-color.ts","../src/timing/debounce.ts"],"sourcesContent":["export const BREAKPOINTS = [\"mobile\", \"tablet\", \"desktop\"] as const;\n","import type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n\nconst resolveResponsiveValueForBreakpoint = <T>(\n breakpoint: Breakpoint,\n value: ResponsiveValue<T>,\n fallback?: T,\n): T => {\n if (value === undefined || value === null) {\n return fallback as T;\n }\n const isNonResponsive = typeof value !== \"object\" || !(breakpoint in value);\n const resolved = isNonResponsive\n ? ((value ?? fallback) as T)\n : ((value as ResponsiveConfig<T>)[breakpoint] ?? (fallback as T));\n return resolved;\n};\n\nconst resolveResponsiveValue = <T>(\n value: ResponsiveValue<T>,\n fallback?: T,\n): Required<ResponsiveConfig<T>> => {\n const mobile = resolveResponsiveValueForBreakpoint(\"mobile\", value, fallback);\n const tablet = resolveResponsiveValueForBreakpoint(\"tablet\", value, mobile);\n const desktop = resolveResponsiveValueForBreakpoint(\"desktop\", value, tablet);\n\n return {\n mobile,\n tablet,\n desktop,\n };\n};\n\nexport { resolveResponsiveValue, resolveResponsiveValueForBreakpoint };\nexport { BREAKPOINTS } from \"./constants\";\nexport type { Breakpoint, ResponsiveConfig, ResponsiveValue } from \"./types\";\n","export const assertSafeCssValue = (value: unknown, label: string) => {\n if (typeof value !== \"string\" && typeof value !== \"number\") {\n throw new TypeError(`${label} must be a string or number.`);\n }\n\n const serialized = String(value).trim();\n if (\n serialized.length === 0 ||\n /[;{}<>\\u0000-\\u001f\\u007f]/.test(serialized)\n ) {\n throw new TypeError(\n `${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`,\n );\n }\n return serialized;\n};\n","/** Normalizes a search string by removing diacritics and converting to lowercase */\nexport const normalizeSearchString = (value: string): string =>\n value\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .toLocaleLowerCase();\n\n/** Removes unsafe characters from a string */\nexport const withSafeCharacters = (input: string): string =>\n input\n .trim()\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .replace(/[^a-zA-Z0-9\\s-]/g, \"\")\n .replace(\n /([A-Z].*[^\\s][A-Z])/g,\n \"$1\".slice(0, 1).toUpperCase() + \"$1\".slice(1).toLowerCase(),\n );\n\n/** Escapes special characters in a string for use in CSS strings */\nexport const escapeCssString = (value: string): string => {\n return value.replace(/[\"\\\\\\n\\r\\f]/g, (character) => {\n switch (character) {\n case '\"':\n return '\\\\\"';\n case \"\\\\\":\n return \"\\\\\\\\\";\n case \"\\n\":\n return \"\\\\a \";\n case \"\\r\":\n return \"\\\\d \";\n case \"\\f\":\n return \"\\\\c \";\n default:\n return character;\n }\n });\n};\n","import { withSafeCharacters } from \"./normalize\";\n\n/**\n * Represents the casing options for strings.\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport type StringCasing =\n | \"lowercase\"\n | \"uppercase\"\n | \"snakecase\"\n | \"kebabcase\"\n | \"camelcase\"\n | \"pascalcase\"\n | \"sentencecase\"\n | \"headercase\";\n\n/**\n * Transforms the input string into the specified casing.\n * Casing can be one of the following:\n * - \"lowercase\" -> hello world\n * - \"uppercase\" -> HELLO WORLD\n * - \"snakecase\" -> hello_world\n * - \"kebabcase\" -> hello-world\n * - \"camelcase\" -> helloWorld\n * - \"pascalcase\" -> HelloWorld\n * - \"sentencecase\" -> Hello world\n * - \"headercase\" -> Hello World\n **/\nexport const stringWithCasing = (\n input: string,\n casing: StringCasing,\n): string => {\n const trimmedInput = input.trim();\n const cleanedInput = withSafeCharacters(trimmedInput);\n\n switch (casing) {\n case \"lowercase\":\n return trimmedInput.toLowerCase();\n case \"uppercase\":\n return trimmedInput.toUpperCase();\n case \"snakecase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => a + \"_\" + b.toLowerCase())\n .replace(/[^A-Za-z0-9]+|_+/g, \"_\")\n .toLowerCase();\n case \"kebabcase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \"-\")\n .toLowerCase();\n case \"camelcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w)/g, (_m, _a, b) => b.toUpperCase());\n case \"pascalcase\":\n return cleanedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"$\")\n .replace(/[^A-Za-z0-9]+/g, \"$\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`)\n .toLowerCase()\n .replace(/(\\$)(\\w?)/g, (_m, a, b) => b.toUpperCase());\n case \"sentencecase\": {\n const textcase = trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase();\n\n return textcase.charAt(0).toUpperCase() + textcase.slice(1);\n }\n case \"headercase\":\n return trimmedInput\n .replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, \"\")\n .replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`)\n .replace(/[^A-Za-z0-9]+|_+/g, \" \")\n .toLowerCase()\n .replace(\n /( ?)(\\w+)( ?)/g,\n (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c,\n );\n }\n};\n","/**\n * Represents a valid argument for the `classNames` function.\n * It can be a string, an array of strings, undefined, null, or false.\n */\nexport type ClassnameArg = string | string[] | undefined | null | false;\n\n/**\n * Concatenates and trims the given arguments into a single string of class names.\n *\n * @param args - The arguments to be concatenated.\n * @returns A string of class names.\n */\nexport const cn = (...args: ClassnameArg[]): string => {\n const notNullUndefinedOrFalse = args.filter((v) => !!v).flat() as string[];\n return notNullUndefinedOrFalse\n .flatMap((v) => v.split(\" \"))\n .filter((v) => v.length > 0)\n .join(\" \")\n .trim();\n};\n","const NAME_PARTICLES = new Set([\n // Dutch\n \"van\",\n \"den\",\n \"der\",\n \"de\",\n \"ter\",\n \"ten\",\n \"te\",\n \"het\",\n \"'t\",\n\n // German\n \"von\",\n \"vom\",\n \"zum\",\n \"zur\",\n \"zu\",\n\n // French\n \"du\",\n \"des\",\n \"le\",\n \"la\",\n \"les\",\n\n // Spanish and Portuguese\n \"del\",\n \"los\",\n \"las\",\n \"da\",\n \"das\",\n \"do\",\n \"dos\",\n\n // Italian\n \"di\",\n \"della\",\n \"delle\",\n \"dello\",\n \"dei\",\n \"degli\",\n\n // Other common particles\n \"al\",\n \"el\",\n \"bin\",\n \"ibn\",\n \"bint\",\n \"af\",\n \"av\",\n \"ap\",\n \"ab\",\n]);\n\nconst NAME_SUFFIXES = new Set([\n \"jr\",\n \"sr\",\n \"ii\",\n \"iii\",\n \"iv\",\n \"v\",\n \"phd\",\n \"md\",\n]);\n\nconst normalizeNamePart = (part: string): string => {\n return part.toLocaleLowerCase().replace(/[\\p{P}\\p{S}]/gu, \"\");\n};\n\nconst getFirstLetter = (part: string): string => {\n return part.match(/\\p{L}/u)?.[0].toLocaleUpperCase() ?? \"\";\n};\n\nexport const nameToInitials = (name: string) => {\n const parts = name.trim().split(/\\s+/u).filter(Boolean);\n const [firstPart] = parts;\n if (firstPart === undefined) {\n return \"?\";\n }\n\n // Ignore suffixes such as Jr., Sr. and III.\n while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts.at(-1)!))) {\n parts.pop();\n }\n\n const firstInitial = getFirstLetter(firstPart);\n\n if (parts.length === 1) {\n return firstInitial;\n }\n\n // Find the last meaningful surname part, ignoring particles.\n const surname = [...parts.slice(1)]\n .reverse()\n .find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));\n\n // Fallback for unusual names consisting only of particles.\n const lastInitial = getFirstLetter(surname ?? parts.at(-1)!);\n\n return firstInitial + lastInitial;\n};\n","import type { ColorType, HSLColor, RGBColor } from \"./color.types\";\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(max, Math.max(min, value));\n\nconst normalizeHue = (hue: number): number => ((hue % 360) + 360) % 360;\n\nconst normalizeAlpha = (value?: string): number => {\n if (value === undefined) return 1;\n\n const alpha = value.endsWith(\"%\")\n ? Number.parseFloat(value) / 100\n : Number.parseFloat(value);\n\n return clamp(alpha, 0, 1);\n};\n\nconst CSS_NAMED_COLORS = new Set([\n \"aliceblue\",\n \"antiquewhite\",\n \"aqua\",\n \"aquamarine\",\n \"azure\",\n \"beige\",\n \"bisque\",\n \"black\",\n \"blanchedalmond\",\n \"blue\",\n \"blueviolet\",\n \"brown\",\n \"burlywood\",\n \"cadetblue\",\n \"chartreuse\",\n \"chocolate\",\n \"coral\",\n \"cornflowerblue\",\n \"cornsilk\",\n \"crimson\",\n \"cyan\",\n \"darkblue\",\n \"darkcyan\",\n \"darkgoldenrod\",\n \"darkgray\",\n \"darkgreen\",\n \"darkgrey\",\n \"darkkhaki\",\n \"darkmagenta\",\n \"darkolivegreen\",\n \"darkorange\",\n \"darkorchid\",\n \"darkred\",\n \"darksalmon\",\n \"darkseagreen\",\n \"darkslateblue\",\n \"darkslategray\",\n \"darkslategrey\",\n \"darkturquoise\",\n \"darkviolet\",\n \"deeppink\",\n \"deepskyblue\",\n \"dimgray\",\n \"dimgrey\",\n \"dodgerblue\",\n \"firebrick\",\n \"floralwhite\",\n \"forestgreen\",\n \"fuchsia\",\n \"gainsboro\",\n \"ghostwhite\",\n \"gold\",\n \"goldenrod\",\n \"gray\",\n \"green\",\n \"greenyellow\",\n \"grey\",\n \"honeydew\",\n \"hotpink\",\n \"indianred\",\n \"indigo\",\n \"ivory\",\n \"khaki\",\n \"lavender\",\n \"lavenderblush\",\n \"lawngreen\",\n \"lemonchiffon\",\n \"lightblue\",\n \"lightcoral\",\n \"lightcyan\",\n \"lightgoldenrodyellow\",\n \"lightgray\",\n \"lightgreen\",\n \"lightgrey\",\n \"lightpink\",\n \"lightsalmon\",\n \"lightseagreen\",\n \"lightskyblue\",\n \"lightslategray\",\n \"lightslategrey\",\n \"lightsteelblue\",\n \"lightyellow\",\n \"lime\",\n \"limegreen\",\n \"linen\",\n \"magenta\",\n \"maroon\",\n \"mediumaquamarine\",\n \"mediumblue\",\n \"mediumorchid\",\n \"mediumpurple\",\n \"mediumseagreen\",\n \"mediumslateblue\",\n \"mediumspringgreen\",\n \"mediumturquoise\",\n \"mediumvioletred\",\n \"midnightblue\",\n \"mintcream\",\n \"mistyrose\",\n \"moccasin\",\n \"navajowhite\",\n \"navy\",\n \"oldlace\",\n \"olive\",\n \"olivedrab\",\n \"orange\",\n \"orangered\",\n \"orchid\",\n \"palegoldenrod\",\n \"palegreen\",\n \"paleturquoise\",\n \"palevioletred\",\n \"papayawhip\",\n \"peachpuff\",\n \"peru\",\n \"pink\",\n \"plum\",\n \"powderblue\",\n \"purple\",\n \"rebeccapurple\",\n \"red\",\n \"rosybrown\",\n \"royalblue\",\n \"saddlebrown\",\n \"salmon\",\n \"sandybrown\",\n \"seagreen\",\n \"seashell\",\n \"sienna\",\n \"silver\",\n \"skyblue\",\n \"slateblue\",\n \"slategray\",\n \"slategrey\",\n \"snow\",\n \"springgreen\",\n \"steelblue\",\n \"tan\",\n \"teal\",\n \"thistle\",\n \"tomato\",\n \"turquoise\",\n \"violet\",\n \"wheat\",\n \"white\",\n \"whitesmoke\",\n \"yellow\",\n \"yellowgreen\",\n \"transparent\",\n \"currentcolor\",\n]);\n\nconst normalizeChannel = (value: string): number => {\n const channel = value.endsWith(\"%\")\n ? (Number.parseFloat(value) / 100) * 255\n : Number.parseFloat(value);\n\n return clamp(channel, 0, 255);\n};\n\nconst getColorType = (color: string): ColorType => {\n const value = color.trim().toLowerCase();\n\n if (/^var\\(\\s*--[\\w-]+(?:\\s*,\\s*.+)?\\)$/.test(value)) {\n return \"css-variable\";\n }\n\n if (/^#[\\da-f]{8}$/.test(value) || /^#[\\da-f]{4}$/.test(value)) {\n return \"hexa\";\n }\n\n if (/^#[\\da-f]{6}$/.test(value) || /^#[\\da-f]{3}$/.test(value)) {\n return \"hex\";\n }\n\n if (/^rgba\\(/.test(value)) return \"rgba\";\n if (/^rgb\\(/.test(value)) return \"rgb\";\n if (/^hsla\\(/.test(value)) return \"hsla\";\n if (/^hsl\\(/.test(value)) return \"hsl\";\n\n if (/^[a-z]+$/.test(value)) return \"named\";\n\n return \"unknown\";\n};\n\nconst isCssVariable = (color: string): boolean =>\n getColorType(color) === \"css-variable\";\n\nconst isColor = (color: string): boolean => {\n const type = getColorType(color);\n\n return type === \"named\"\n ? CSS_NAMED_COLORS.has(color.trim().toLowerCase())\n : type !== \"unknown\";\n};\n\nconst hexToRgba = (hex: string): RGBColor => {\n const value = hex.trim().replace(/^#/, \"\");\n\n if (!/^(?:[\\da-f]{3}|[\\da-f]{4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(value)) {\n throw new Error(`Invalid HEX color: ${hex}`);\n }\n\n const expanded =\n value.length <= 4\n ? [...value].map((channel) => channel + channel).join(\"\")\n : value;\n\n const r = Number.parseInt(expanded.slice(0, 2), 16);\n const g = Number.parseInt(expanded.slice(2, 4), 16);\n const b = Number.parseInt(expanded.slice(4, 6), 16);\n const a =\n expanded.length === 8 ? Number.parseInt(expanded.slice(6, 8), 16) / 255 : 1;\n\n return { r, g, b, a };\n};\n\nconst rgbToHex = (r: number, g: number, b: number, a?: number): string => {\n const channelToHex = (channel: number): string =>\n Math.round(clamp(channel, 0, 255))\n .toString(16)\n .padStart(2, \"0\");\n\n const alpha =\n a !== undefined && a < 1 ? channelToHex(clamp(a, 0, 1) * 255) : \"\";\n\n return `#${channelToHex(r)}${channelToHex(g)}${channelToHex(b)}${alpha}`;\n};\n\nconst parseRgb = (color: string): RGBColor | null => {\n const match = color\n .trim()\n .match(\n /^rgba?\\(\\s*([\\d.]+%?)\\s*[, ]\\s*([\\d.]+%?)\\s*[, ]\\s*([\\d.]+%?)(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/i,\n );\n\n if (!match) return null;\n\n const [, r, g, b, alpha] = match;\n if (r === undefined || g === undefined || b === undefined) return null;\n\n return {\n r: normalizeChannel(r),\n g: normalizeChannel(g),\n b: normalizeChannel(b),\n a: normalizeAlpha(alpha),\n };\n};\n\nconst hslToRgb = ({ h, s, l, a = 1 }: HSLColor): RGBColor => {\n const hue = normalizeHue(h) / 360;\n const saturation = clamp(s / 100, 0, 1);\n const lightness = clamp(l / 100, 0, 1);\n\n const channel = (n: number): number => {\n const k = (n + hue * 12) % 12;\n const chroma = saturation * Math.min(lightness, 1 - lightness);\n\n return Math.round(\n (lightness - chroma * Math.max(-1, Math.min(k - 3, 9 - k, 1))) * 255,\n );\n };\n\n return {\n r: channel(0),\n g: channel(8),\n b: channel(4),\n a: clamp(a, 0, 1),\n };\n};\n\nconst rgbToHsl = ({ r, g, b, a = 1 }: RGBColor): HSLColor => {\n const red = r / 255;\n const green = g / 255;\n const blue = b / 255;\n\n const max = Math.max(red, green, blue);\n const min = Math.min(red, green, blue);\n const delta = max - min;\n\n const l = (max + min) / 2;\n\n let h = 0;\n let s = 0;\n\n if (delta !== 0) {\n s = delta / (1 - Math.abs(2 * l - 1));\n\n if (max === red) {\n h = 60 * (((green - blue) / delta) % 6);\n } else if (max === green) {\n h = 60 * ((blue - red) / delta + 2);\n } else {\n h = 60 * ((red - green) / delta + 4);\n }\n }\n\n return {\n h: normalizeHue(h),\n s: s * 100,\n l: l * 100,\n a,\n };\n};\n\nconst parseHsl = (color: string): RGBColor | null => {\n const match = color\n .trim()\n .match(\n /^hsla?\\(\\s*([\\d.]+)(?:deg)?\\s*[, ]\\s*([\\d.]+)%\\s*[, ]\\s*([\\d.]+)%(?:\\s*[,/]\\s*([\\d.]+%?))?\\s*\\)$/i,\n );\n\n if (!match) return null;\n\n const [, h, s, l, alpha] = match;\n\n return hslToRgb({\n h: Number(h),\n s: Number(s),\n l: Number(l),\n a: normalizeAlpha(alpha),\n });\n};\n\nconst parseColor = (color: string): RGBColor | null => {\n const type = getColorType(color);\n\n if (type === \"hex\" || type === \"hexa\") {\n return hexToRgba(color);\n }\n\n if (type === \"rgb\" || type === \"rgba\") {\n return parseRgb(color);\n }\n\n if (type === \"hsl\" || type === \"hsla\") {\n return parseHsl(color);\n }\n\n return null;\n};\n\nconst rgbToCss = ({ r, g, b, a }: RGBColor): string =>\n a < 1\n ? `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${Number(a.toFixed(3))})`\n : `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`;\n\nconst hslToCss = ({ h, s, l, a }: HSLColor): string =>\n a < 1\n ? `hsla(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%, ${Number(a.toFixed(3))})`\n : `hsl(${Math.round(h)}, ${Math.round(s)}%, ${Math.round(l)}%)`;\n\nconst getColorLuminance = (color: string): number | null => {\n const rgb = parseColor(color);\n\n if (!rgb) return null;\n\n const linearize = (value: number): number => {\n const channel = value / 255;\n\n return channel <= 0.04045\n ? channel / 12.92\n : ((channel + 0.055) / 1.055) ** 2.4;\n };\n\n return (\n 0.2126 * linearize(rgb.r) +\n 0.7152 * linearize(rgb.g) +\n 0.0722 * linearize(rgb.b)\n );\n};\n\nconst isColorDark = (color: string): boolean | null => {\n const luminance = getColorLuminance(color);\n\n return luminance === null ? null : luminance < 0.179;\n};\n\nexport {\n clamp,\n getColorType,\n isCssVariable,\n isColor,\n hexToRgba,\n rgbToHex,\n parseRgb,\n parseColor,\n hslToRgb,\n rgbToHsl,\n rgbToCss,\n hslToCss,\n getColorLuminance,\n isColorDark,\n};\n","import {\n getColorType,\n isColor,\n isColorDark,\n isCssVariable,\n} from \"./color.utils\";\n\nexport const isHexColor = (color: string): boolean =>\n /^#(?:[\\da-f]{3}|[\\da-f]{4}|[\\da-f]{6}|[\\da-f]{8})$/i.test(color.trim());\n\nexport const isDarkColor = (color: string): boolean => {\n const result = isColorDark(color);\n\n if (result === null) {\n throw new Error(`Unsupported color: ${color}`);\n }\n\n return result;\n};\n\nexport { getColorType, isColor, isCssVariable, isColorDark };\n","import { hexToRgba } from \"./color.utils\";\n\nexport const hexToRgb = (hex: string): { r: number; g: number; b: number } => {\n const { r, g, b } = hexToRgba(hex);\n\n return { r, g, b };\n};\n\nexport const rgbToHex = (\n r: number,\n g: number,\n b: number,\n a?: number,\n): string => {\n const channel = (value: number): string =>\n Math.round(Math.min(255, Math.max(0, value)))\n .toString(16)\n .padStart(2, \"0\");\n\n const alpha =\n a !== undefined && a < 1 ? channel(Math.min(1, Math.max(0, a)) * 255) : \"\";\n\n return `#${channel(r)}${channel(g)}${channel(b)}${alpha}`;\n};\n","/**\n * Call the original function, but applying the debounce rules.\n *\n * Only the last call to the function shall be executed after the timeout has been reached.\n * @returns the debounced function with a cancel function property to clear the timeout.\n */\nconst debounce = <T extends unknown[]>(\n func: (...args: T) => void,\n wait: number,\n) => {\n let timeout: ReturnType<typeof setTimeout>;\n\n const cancel = () => clearTimeout(timeout);\n\n return Object.assign(\n (...args: T) => {\n clearTimeout(timeout);\n timeout = setTimeout(() => func.apply(this, args), wait);\n },\n { cancel },\n );\n};\n\nexport { debounce };\n"],"mappings":";AAAA,MAAa,cAAc;CAAC;CAAU;CAAU;AAAS;;ACEzD,MAAM,uCACJ,YACA,OACA,aACM;CACN,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAMT,OAJwB,OAAO,UAAU,YAAY,EAAE,cAAc,SAE/D,SAAS,WACT,MAA8B,eAAgB;AAEtD;AAEA,MAAM,0BACJ,OACA,aACkC;CAClC,MAAM,SAAS,oCAAoC,UAAU,OAAO,QAAQ;CAC5E,MAAM,SAAS,oCAAoC,UAAU,OAAO,MAAM;CAG1E,OAAO;EACL;EACA;EACA,SALc,oCAAoC,WAAW,OAAO,MAK9D;CACR;AACF;;AC9BA,MAAa,sBAAsB,OAAgB,UAAkB;CACnE,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,UAChD,MAAM,IAAI,UAAU,GAAG,MAAM,6BAA6B;CAG5D,MAAM,aAAa,OAAO,KAAK,CAAC,CAAC,KAAK;CACtC,IACE,WAAW,WAAW,KACtB,6BAA6B,KAAK,UAAU,GAE5C,MAAM,IAAI,UACR,GAAG,MAAM,+GACX;CAEF,OAAO;AACT;;;ACdA,MAAa,yBAAyB,UACpC,MACG,UAAU,KAAK,CAAC,CAChB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,kBAAkB;;AAGvB,MAAa,sBAAsB,UACjC,MACG,KAAK,CAAC,CACN,UAAU,KAAK,CAAC,CAChB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,QACC,wBACA,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAC7D;;AAGJ,MAAa,mBAAmB,UAA0B;CACxD,OAAO,MAAM,QAAQ,iBAAiB,cAAc;EAClD,QAAQ,WAAR;GACE,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,KAAK,MACH,OAAO;GACT,SACE,OAAO;EACX;CACF,CAAC;AACH;;;;;;;;;;;;;;ACFA,MAAa,oBACX,OACA,WACW;CACX,MAAM,eAAe,MAAM,KAAK;CAChC,MAAM,eAAe,mBAAmB,YAAY;CAEpD,QAAQ,QAAR;EACE,KAAK,aACH,OAAO,aAAa,YAAY;EAClC,KAAK,aACH,OAAO,aAAa,YAAY;EAClC,KAAK,aACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,IAAI,MAAM,EAAE,YAAY,CAAC,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;EACjB,KAAK,aACH,OAAO,aACJ,QAAQ,sCAAsC,EAAE,CAAC,CACjD,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;EACjB,KAAK,aACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC,CACrD,YAAY,CAAC,CACb,QAAQ,cAAc,IAAI,IAAI,MAAM,EAAE,YAAY,CAAC;EACxD,KAAK,cACH,OAAO,aACJ,QAAQ,kCAAkC,GAAG,CAAC,CAC9C,QAAQ,kBAAkB,GAAG,CAAC,CAC9B,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,GAAG,CAAC,CACrD,YAAY,CAAC,CACb,QAAQ,eAAe,IAAI,GAAG,MAAM,EAAE,YAAY,CAAC;EACxD,KAAK,gBAAgB;GACnB,MAAM,WAAW,aACd,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY;GAEf,OAAO,SAAS,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,SAAS,MAAM,CAAC;EAC5D;EACA,KAAK,cACH,OAAO,aACJ,QAAQ,kCAAkC,EAAE,CAAC,CAC7C,QAAQ,oBAAoB,IAAI,GAAG,MAAM,GAAG,EAAE,GAAG,EAAE,YAAY,GAAG,CAAC,CACnE,QAAQ,qBAAqB,GAAG,CAAC,CACjC,YAAY,CAAC,CACb,QACC,mBACC,GAAG,GAAG,GAAG,MAAM,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,MAAM,CAAC,IAAI,CAC/D;CACN;AACF;;;;;;;;ACjFA,MAAa,MAAM,GAAG,SAAiC;CAErD,OADgC,KAAK,QAAQ,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,KAC3B,CAAC,CAC3B,SAAS,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAC5B,QAAQ,MAAM,EAAE,SAAS,CAAC,CAAC,CAC3B,KAAK,GAAG,CAAC,CACT,KAAK;AACV;;ACnBA,MAAM,iCAAiB,IAAI,IAAI;CAE7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CAGA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,gCAAgB,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,MAAM,qBAAqB,SAAyB;CAClD,OAAO,KAAK,kBAAkB,CAAC,CAAC,QAAQ,kBAAkB,EAAE;AAC9D;AAEA,MAAM,kBAAkB,SAAyB;CAC/C,OAAO,KAAK,MAAM,QAAQ,CAAC,GAAG,EAAE,CAAC,kBAAkB,KAAK;AAC1D;AAEA,MAAa,kBAAkB,SAAiB;CAC9C,MAAM,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,OAAO,OAAO;CACtD,MAAM,CAAC,aAAa;CACpB,IAAI,cAAc,KAAA,GAChB,OAAO;CAIT,OAAO,MAAM,SAAS,KAAK,cAAc,IAAI,kBAAkB,MAAM,GAAG,EAAE,CAAE,CAAC,GAC3E,MAAM,IAAI;CAGZ,MAAM,eAAe,eAAe,SAAS;CAE7C,IAAI,MAAM,WAAW,GACnB,OAAO;CAIT,MAAM,UAAU,CAAC,GAAG,MAAM,MAAM,CAAC,CAAC,CAAC,CAChC,QAAQ,CAAC,CACT,MAAM,SAAS,CAAC,eAAe,IAAI,kBAAkB,IAAI,CAAC,CAAC;CAK9D,OAAO,eAFa,eAAe,WAAW,MAAM,GAAG,EAAE,CAEzB;AAClC;;ACnGA,MAAM,SAAS,OAAe,KAAa,QACzC,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,CAAC;AAEpC,MAAM,gBAAgB,SAA0B,MAAM,MAAO,OAAO;AAEpE,MAAM,kBAAkB,UAA2B;CACjD,IAAI,UAAU,KAAA,GAAW,OAAO;CAEhC,MAAM,QAAQ,MAAM,SAAS,GAAG,IAC5B,OAAO,WAAW,KAAK,IAAI,MAC3B,OAAO,WAAW,KAAK;CAE3B,OAAO,MAAM,OAAO,GAAG,CAAC;AAC1B;AAEA,MAAM,mCAAmB,IAAI,IAAI;CAC7B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACJ,CAAC;AAED,MAAM,oBAAoB,UAA0B;CAClD,MAAM,UAAU,MAAM,SAAS,GAAG,IAC7B,OAAO,WAAW,KAAK,IAAI,MAAO,MACnC,OAAO,WAAW,KAAK;CAE3B,OAAO,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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@puzzle-ui/core",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Framework-independent utilities",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -29,13 +29,15 @@
29
29
  "sideEffects": false,
30
30
  "scripts": {
31
31
  "build": "tsdown",
32
+ "typecheck": "tsc --noEmit -p .",
32
33
  "prepack": "tsdown",
33
34
  "vitest": "bunx vitest run --passWithNoTests",
34
- "vitest:watch": "bunx vitest"
35
+ "vitest:watch": "bunx vitest run --watch --passWithNoTests"
35
36
  },
36
37
  "devDependencies": {
37
38
  "tsdown": "^0.23.1",
38
39
  "tsup": "latest",
39
- "typescript": "^6.0.3"
40
+ "typescript": "^6.0.3",
41
+ "vitest": "^5.1.0"
40
42
  }
41
43
  }