@puzzle-ui/core 0.3.0 → 0.5.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 +76 -48
- package/dist/index.cjs +305 -33
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -3
- package/dist/index.d.ts +28 -3
- package/dist/index.js +293 -34
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -1,70 +1,98 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Getting Started
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
directly without React, a theme provider, or CSS.
|
|
3
|
+
Install Puzzle in your React app, build your first interface, and customize the theme.
|
|
5
4
|
|
|
6
|
-
> Puzzle is
|
|
7
|
-
>
|
|
5
|
+
> \[!WARNING\] **Puzzle is not ready for production use.**
|
|
6
|
+
>
|
|
7
|
+
> This project is under active development. APIs, component props,
|
|
8
|
+
> package exports, styling, and internal implementation may change
|
|
9
|
+
> without notice. Components may be incomplete, and testing,
|
|
10
|
+
> accessibility, documentation, and framework compatibility are not yet
|
|
11
|
+
> guaranteed. Use it for experimentation and evaluation only---not for
|
|
12
|
+
> production applications.
|
|
8
13
|
|
|
9
|
-
|
|
14
|
+
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`.
|
|
10
15
|
|
|
11
|
-
Use
|
|
16
|
+
**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.
|
|
12
17
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- A package manager: npm, Bun, pnpm, or Yarn.
|
|
21
|
+
- An existing React application with a bundler that supports CSS imports, such as Vite.
|
|
22
|
+
- Familiarity with React and TypeScript. The UI and theme packages require React and React DOM 19 or later within the supported React 19 range.
|
|
23
|
+
|
|
24
|
+
## Set up a new project
|
|
25
|
+
|
|
26
|
+
Simple run our @puzzle-ui/create project template to get started.
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
npm:
|
|
24
29
|
|
|
25
|
-
```
|
|
26
|
-
|
|
30
|
+
```bash
|
|
31
|
+
npx @puzzle-ui/create
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
bun:
|
|
27
35
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const validColor = isHexColor("#0284C7");
|
|
36
|
+
```bash
|
|
37
|
+
bunx @puzzle-ui/create
|
|
31
38
|
```
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
Puzzle can set up a new project for you with the following framework options:
|
|
41
|
+
|
|
42
|
+
- Basic React app
|
|
43
|
+
- Tanstack start
|
|
44
|
+
- Next.js
|
|
45
|
+
|
|
46
|
+
Furthermore you can choose to install tailwindcss or not.
|
|
47
|
+
It directly installs all dependencies and sets up the project for you.
|
|
34
48
|
|
|
35
|
-
|
|
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` |
|
|
49
|
+
## Set up in an existing project:
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
points. The package ships ESM and CommonJS builds with matching TypeScript
|
|
47
|
-
declarations and has no React peer dependency.
|
|
51
|
+
Install the UI library and theme package in your application's directory. Choose your package manager below:
|
|
48
52
|
|
|
49
|
-
|
|
53
|
+
npm:
|
|
50
54
|
|
|
51
|
-
|
|
55
|
+
```bash
|
|
56
|
+
npm install @puzzle-ui/ui --save
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
bun:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
bun add @puzzle-ui/create
|
|
63
|
+
```
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
pnpm:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pnpm add @puzzle-ui/ui
|
|
55
69
|
```
|
|
56
70
|
|
|
57
|
-
|
|
71
|
+
yarn:
|
|
58
72
|
|
|
59
|
-
```
|
|
60
|
-
|
|
73
|
+
```bash
|
|
74
|
+
yarn add @puzzle-ui/ui
|
|
61
75
|
```
|
|
62
76
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
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.
|
|
78
|
+
|
|
79
|
+
## Your first interface
|
|
66
80
|
|
|
67
|
-
|
|
81
|
+
Import components from `"@puzzle-ui/ui` and wrap your application in `Theme` from `"@puzzle-ui/theme`:
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
83
|
+
```tsx
|
|
84
|
+
import { Theme } from "@puzzle-ui/theme";
|
|
85
|
+
import { Button } from "@puzzle-ui/ui";
|
|
86
|
+
|
|
87
|
+
export const App = () => (
|
|
88
|
+
<Theme>
|
|
89
|
+
<main>
|
|
90
|
+
<h1>Hello, Puzzle</h1>
|
|
91
|
+
<p>Build your interface with reusable components and shared tokens.</p>
|
|
92
|
+
<Button onClick={() => window.alert("Welcome to Puzzle!")}>
|
|
93
|
+
Get started
|
|
94
|
+
</Button>
|
|
95
|
+
</main>
|
|
96
|
+
</Theme>
|
|
97
|
+
);
|
|
98
|
+
```
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
|
155
|
+
return firstInitial + getFirstLetter(surname ?? parts.at(-1));
|
|
155
156
|
};
|
|
156
|
-
// src/color/
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
394
|
+
h: normalizeHue(h),
|
|
395
|
+
s: s * 100,
|
|
396
|
+
l: l * 100,
|
|
397
|
+
a
|
|
173
398
|
};
|
|
174
399
|
};
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
191
|
-
const
|
|
192
|
-
const
|
|
193
|
-
return
|
|
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
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
154
|
+
return firstInitial + getFirstLetter(surname ?? parts.at(-1));
|
|
154
155
|
};
|
|
155
|
-
// src/color/
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
393
|
+
h: normalizeHue(h),
|
|
394
|
+
s: s * 100,
|
|
395
|
+
l: l * 100,
|
|
396
|
+
a
|
|
172
397
|
};
|
|
173
398
|
};
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
190
|
-
const
|
|
191
|
-
const
|
|
192
|
-
return
|
|
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":"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,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.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Framework-independent utilities",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,6 +29,7 @@
|
|
|
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
35
|
"vitest:watch": "bunx vitest run --watch --passWithNoTests"
|
|
@@ -36,6 +37,7 @@
|
|
|
36
37
|
"devDependencies": {
|
|
37
38
|
"tsdown": "^0.23.1",
|
|
38
39
|
"tsup": "latest",
|
|
39
|
-
"typescript": "^
|
|
40
|
+
"typescript": "^7.0.2",
|
|
41
|
+
"vitest": "^5.1.0"
|
|
40
42
|
}
|
|
41
43
|
}
|