@puzzle-ui/core 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,70 @@
1
- # Temporary Holding Version
1
+ # @puzzle-ui/core
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Framework-independent utilities shared by the Puzzle UI packages. Use them
4
+ directly without React, a theme provider, or CSS.
5
+
6
+ > Puzzle is under active development. APIs may change without notice; use it
7
+ > for experimentation and evaluation rather than production applications.
8
+
9
+ ## Installation
10
+
11
+ Use your preferred package manager:
12
+
13
+ ```sh
14
+ npm install @puzzle-ui/core
15
+ # or
16
+ bun add @puzzle-ui/core
17
+ # or
18
+ pnpm add @puzzle-ui/core
19
+ # or
20
+ yarn add @puzzle-ui/core
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ```ts
26
+ import { cn, isHexColor } from "@puzzle-ui/core";
27
+
28
+ const selected = true;
29
+ const className = cn("navigation-item", selected && "selected");
30
+ const validColor = isHexColor("#0284C7");
31
+ ```
32
+
33
+ ## Public utilities
34
+
35
+ | Area | Exports |
36
+ | --- | --- |
37
+ | Class names | `cn`, `ClassnameArg` |
38
+ | Strings | `stringWithCasing`, `normalizeSearchString`, `withSafeCharacters`, `nameToInitials` |
39
+ | CSS values | `assertSafeCssValue`, `escapeCssString` |
40
+ | Colors | `isHexColor`, `isDarkColor`, `hexToRgb`, `rgbToHex` |
41
+ | Responsive values | `BREAKPOINTS`, `resolveResponsiveValue`, `resolveResponsiveValueForBreakpoint` |
42
+ | Timing | `debounce` |
43
+ | Types | `DeepPartial`, `ResponsiveConfig`, `ResponsiveValue`, `Breakpoint` |
44
+
45
+ Import from the package root; internal source paths are not public entry
46
+ points. The package ships ESM and CommonJS builds with matching TypeScript
47
+ declarations and has no React peer dependency.
48
+
49
+ ## Development
50
+
51
+ From an installed repository checkout:
52
+
53
+ ```sh
54
+ npm run build --workspace=@puzzle-ui/core
55
+ ```
56
+
57
+ From this package directory, run the configured test script:
58
+
59
+ ```sh
60
+ bun run vitest
61
+ ```
62
+
63
+ `prepack` rebuilds the package before packing or publishing. See the root
64
+ [publishing guide](../../README.md#publishing-packages) for release order and
65
+ validation commands.
66
+
67
+ ## License
68
+
69
+ MIT. See the repository [LICENSE](../../LICENSE); published packages include
70
+ the same license at `dist/LICENSE`.
package/dist/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sjoerd van Den Berg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,226 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ // src/responsive/constants.ts
3
+ const BREAKPOINTS = [
4
+ "mobile",
5
+ "tablet",
6
+ "desktop"
7
+ ];
8
+ // src/responsive/index.ts
9
+ const resolveResponsiveValueForBreakpoint = (breakpoint, value, fallback) => {
10
+ if (value === void 0 || value === null) return fallback;
11
+ return typeof value !== "object" || !(breakpoint in value) ? value ?? fallback : value[breakpoint] ?? fallback;
12
+ };
13
+ const resolveResponsiveValue = (value, fallback) => {
14
+ const mobile = resolveResponsiveValueForBreakpoint("mobile", value, fallback);
15
+ const tablet = resolveResponsiveValueForBreakpoint("tablet", value, mobile);
16
+ return {
17
+ mobile,
18
+ tablet,
19
+ desktop: resolveResponsiveValueForBreakpoint("desktop", value, tablet)
20
+ };
21
+ };
22
+ // src/string/assert.ts
23
+ const assertSafeCssValue = (value, label) => {
24
+ if (typeof value !== "string" && typeof value !== "number") throw new TypeError(`${label} must be a string or number.`);
25
+ const serialized = String(value).trim();
26
+ if (serialized.length === 0 || /[;{}<>\u0000-\u001f\u007f]/.test(serialized)) throw new TypeError(`${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`);
27
+ return serialized;
28
+ };
29
+ // src/string/normalize.ts
30
+ /** Normalizes a search string by removing diacritics and converting to lowercase */
31
+ const normalizeSearchString = (value) => value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase();
32
+ /** Removes unsafe characters from a string */
33
+ const withSafeCharacters = (input) => input.trim().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zA-Z0-9\s-]/g, "").replace(/([A-Z].*[^\s][A-Z])/g, "$1".slice(0, 1).toUpperCase() + "$1".slice(1).toLowerCase());
34
+ /** Escapes special characters in a string for use in CSS strings */
35
+ const escapeCssString = (value) => {
36
+ return value.replace(/["\\\n\r\f]/g, (character) => {
37
+ switch (character) {
38
+ case "\"": return "\\\"";
39
+ case "\\": return "\\\\";
40
+ case "\n": return "\\a ";
41
+ case "\r": return "\\d ";
42
+ case "\f": return "\\c ";
43
+ default: return character;
44
+ }
45
+ });
46
+ };
47
+ // src/string/casing.ts
48
+ /**
49
+ * Transforms the input string into the specified casing.
50
+ * Casing can be one of the following:
51
+ * - "lowercase" -> hello world
52
+ * - "uppercase" -> HELLO WORLD
53
+ * - "snakecase" -> hello_world
54
+ * - "kebabcase" -> hello-world
55
+ * - "camelcase" -> helloWorld
56
+ * - "pascalcase" -> HelloWorld
57
+ * - "sentencecase" -> Hello world
58
+ * - "headercase" -> Hello World
59
+ **/
60
+ const stringWithCasing = (input, casing) => {
61
+ const trimmedInput = input.trim();
62
+ const cleanedInput = withSafeCharacters(trimmedInput);
63
+ switch (casing) {
64
+ case "lowercase": return trimmedInput.toLowerCase();
65
+ case "uppercase": return trimmedInput.toUpperCase();
66
+ case "snakecase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => a + "_" + b.toLowerCase()).replace(/[^A-Za-z0-9]+|_+/g, "_").toLowerCase();
67
+ case "kebabcase": return trimmedInput.replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, "-").toLowerCase();
68
+ case "camelcase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/[^A-Za-z0-9]+/g, "$").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`).toLowerCase().replace(/(\$)(\w)/g, (_m, _a, b) => b.toUpperCase());
69
+ case "pascalcase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "$").replace(/[^A-Za-z0-9]+/g, "$").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`).toLowerCase().replace(/(\$)(\w?)/g, (_m, a, b) => b.toUpperCase());
70
+ case "sentencecase": {
71
+ const textcase = trimmedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, " ").toLowerCase();
72
+ return textcase.charAt(0).toUpperCase() + textcase.slice(1);
73
+ }
74
+ case "headercase": return trimmedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, " ").toLowerCase().replace(/( ?)(\w+)( ?)/g, (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c);
75
+ }
76
+ };
77
+ // src/string/class-names.ts
78
+ /**
79
+ * Concatenates and trims the given arguments into a single string of class names.
80
+ *
81
+ * @param args - The arguments to be concatenated.
82
+ * @returns A string of class names.
83
+ */
84
+ const cn = (...args) => {
85
+ return args.filter((v) => !!v).flat().flatMap((v) => v.split(" ")).filter((v) => v.length > 0).join(" ").trim();
86
+ };
87
+ // src/string/name-to-initials.ts
88
+ const NAME_PARTICLES = /* @__PURE__ */ new Set([
89
+ "van",
90
+ "den",
91
+ "der",
92
+ "de",
93
+ "ter",
94
+ "ten",
95
+ "te",
96
+ "het",
97
+ "'t",
98
+ "von",
99
+ "vom",
100
+ "zum",
101
+ "zur",
102
+ "zu",
103
+ "du",
104
+ "des",
105
+ "le",
106
+ "la",
107
+ "les",
108
+ "del",
109
+ "los",
110
+ "las",
111
+ "da",
112
+ "das",
113
+ "do",
114
+ "dos",
115
+ "di",
116
+ "della",
117
+ "delle",
118
+ "dello",
119
+ "dei",
120
+ "degli",
121
+ "al",
122
+ "el",
123
+ "bin",
124
+ "ibn",
125
+ "bint",
126
+ "af",
127
+ "av",
128
+ "ap",
129
+ "ab"
130
+ ]);
131
+ const NAME_SUFFIXES = /* @__PURE__ */ new Set([
132
+ "jr",
133
+ "sr",
134
+ "ii",
135
+ "iii",
136
+ "iv",
137
+ "v",
138
+ "phd",
139
+ "md"
140
+ ]);
141
+ const normalizeNamePart = (part) => {
142
+ return part.toLocaleLowerCase().replace(/[\p{P}\p{S}]/gu, "");
143
+ };
144
+ const getFirstLetter = (part) => {
145
+ return part.match(/\p{L}/u)?.[0].toLocaleUpperCase() ?? "";
146
+ };
147
+ const nameToInitials = (name) => {
148
+ const parts = name.trim().split(/\s+/u).filter(Boolean);
149
+ if (parts.length === 0) return "?";
150
+ while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))) parts.pop();
151
+ const firstInitial = getFirstLetter(parts[0]);
152
+ if (parts.length === 1) return firstInitial;
153
+ const surname = [...parts.slice(1)].reverse().find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));
154
+ return firstInitial + getFirstLetter(surname ?? parts[parts.length - 1]);
155
+ };
156
+ // src/color/to-color.ts
157
+ const hexToRgb = (hex) => {
158
+ if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) throw new Error("Invalid hex color");
159
+ let r, g, b;
160
+ if (hex.length === 4) {
161
+ r = parseInt(hex[1] + hex[1], 16);
162
+ g = parseInt(hex[2] + hex[2], 16);
163
+ b = parseInt(hex[3] + hex[3], 16);
164
+ } else {
165
+ r = parseInt(hex.slice(1, 3), 16);
166
+ g = parseInt(hex.slice(3, 5), 16);
167
+ b = parseInt(hex.slice(5, 7), 16);
168
+ }
169
+ return {
170
+ r,
171
+ g,
172
+ b
173
+ };
174
+ };
175
+ const rgbToHex = (r, g, b) => {
176
+ const toHex = (value) => {
177
+ const hex = value.toString(16);
178
+ return hex.length === 1 ? "0" + hex : hex;
179
+ };
180
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
181
+ };
182
+ // src/color/is-color.ts
183
+ const isHexColor = (color) => {
184
+ return /^#([0-9A-F]{3}){1,2}$/i.test(color);
185
+ };
186
+ const linearize = (value) => {
187
+ const channel = value / 255;
188
+ return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
189
+ };
190
+ /** Returns whether a color is dark based on WCAG relative luminance. */
191
+ const isDarkColor = (color) => {
192
+ const { r, g, b } = hexToRgb(color);
193
+ return .2126 * linearize(r) + .7152 * linearize(g) + .0722 * linearize(b) < .179;
194
+ };
195
+ // src/timing/debounce.ts
196
+ /**
197
+ * Call the original function, but applying the debounce rules.
198
+ *
199
+ * Only the last call to the function shall be executed after the timeout has been reached.
200
+ * @returns the debounced function with a cancel function property to clear the timeout.
201
+ */
202
+ const debounce = (func, wait) => {
203
+ let timeout;
204
+ const cancel = () => clearTimeout(timeout);
205
+ return Object.assign((...args) => {
206
+ clearTimeout(timeout);
207
+ timeout = setTimeout(() => func.apply(void 0, args), wait);
208
+ }, { cancel });
209
+ };
210
+ exports.BREAKPOINTS = BREAKPOINTS;
211
+ exports.assertSafeCssValue = assertSafeCssValue;
212
+ exports.cn = cn;
213
+ exports.debounce = debounce;
214
+ exports.escapeCssString = escapeCssString;
215
+ exports.hexToRgb = hexToRgb;
216
+ exports.isDarkColor = isDarkColor;
217
+ exports.isHexColor = isHexColor;
218
+ exports.nameToInitials = nameToInitials;
219
+ exports.normalizeSearchString = normalizeSearchString;
220
+ exports.resolveResponsiveValue = resolveResponsiveValue;
221
+ exports.resolveResponsiveValueForBreakpoint = resolveResponsiveValueForBreakpoint;
222
+ exports.rgbToHex = rgbToHex;
223
+ exports.stringWithCasing = stringWithCasing;
224
+ exports.withSafeCharacters = withSafeCharacters;
225
+
226
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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":"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"}
@@ -0,0 +1,73 @@
1
+ type DeepPartial<T> = { [K in keyof T]?: T[K] extends readonly unknown[] ? T[K] : T[K] extends object ? DeepPartial<T[K]> : T[K]; };
2
+ export declare const BREAKPOINTS: readonly ["mobile", "tablet", "desktop"];
3
+ type Breakpoint = (typeof BREAKPOINTS)[number];
4
+ type ResponsiveConfig<T> = Omit<Partial<Record<(typeof BREAKPOINTS)[number], T>>, "mobile"> & {
5
+ mobile: T;
6
+ };
7
+ type ResponsiveValue<T> = T | ResponsiveConfig<T> | undefined;
8
+ declare const resolveResponsiveValueForBreakpoint: <T>(breakpoint: Breakpoint, value: ResponsiveValue<T>, fallback?: T) => T;
9
+ declare const resolveResponsiveValue: <T>(value: ResponsiveValue<T>, fallback?: T) => Required<ResponsiveConfig<T>>;
10
+ export declare const assertSafeCssValue: (value: unknown, label: string) => string;
11
+ /**
12
+ * Represents the casing options for strings.
13
+ * - "lowercase" -> hello world
14
+ * - "uppercase" -> HELLO WORLD
15
+ * - "snakecase" -> hello_world
16
+ * - "kebabcase" -> hello-world
17
+ * - "camelcase" -> helloWorld
18
+ * - "pascalcase" -> HelloWorld
19
+ * - "sentencecase" -> Hello world
20
+ * - "headercase" -> Hello World
21
+ **/
22
+ type StringCasing = "lowercase" | "uppercase" | "snakecase" | "kebabcase" | "camelcase" | "pascalcase" | "sentencecase" | "headercase";
23
+ /**
24
+ * Transforms the input string into the specified casing.
25
+ * Casing can be one of the following:
26
+ * - "lowercase" -> hello world
27
+ * - "uppercase" -> HELLO WORLD
28
+ * - "snakecase" -> hello_world
29
+ * - "kebabcase" -> hello-world
30
+ * - "camelcase" -> helloWorld
31
+ * - "pascalcase" -> HelloWorld
32
+ * - "sentencecase" -> Hello world
33
+ * - "headercase" -> Hello World
34
+ **/
35
+ export declare const stringWithCasing: (input: string, casing: StringCasing) => string;
36
+ /** Normalizes a search string by removing diacritics and converting to lowercase */
37
+ export declare const normalizeSearchString: (value: string) => string;
38
+ /** Removes unsafe characters from a string */
39
+ export declare const withSafeCharacters: (input: string) => string;
40
+ /** Escapes special characters in a string for use in CSS strings */
41
+ export declare const escapeCssString: (value: string) => string;
42
+ /**
43
+ * Represents a valid argument for the `classNames` function.
44
+ * It can be a string, an array of strings, undefined, null, or false.
45
+ */
46
+ type ClassnameArg = string | string[] | undefined | null | false;
47
+ /**
48
+ * Concatenates and trims the given arguments into a single string of class names.
49
+ *
50
+ * @param args - The arguments to be concatenated.
51
+ * @returns A string of class names.
52
+ */
53
+ export declare const cn: (...args: ClassnameArg[]) => string;
54
+ export declare const nameToInitials: (name: string) => string;
55
+ export declare const isHexColor: (color: string) => boolean;
56
+ /** Returns whether a color is dark based on WCAG relative luminance. */
57
+ export declare const isDarkColor: (color: string) => boolean;
58
+ export declare const hexToRgb: (hex: string) => {
59
+ r: number;
60
+ g: number;
61
+ b: number;
62
+ };
63
+ export declare const rgbToHex: (r: number, g: number, b: number) => string;
64
+ /**
65
+ * Call the original function, but applying the debounce rules.
66
+ *
67
+ * Only the last call to the function shall be executed after the timeout has been reached.
68
+ * @returns the debounced function with a cancel function property to clear the timeout.
69
+ */
70
+ declare const debounce: <T extends unknown[]>(func: (...args: T) => void, wait: number) => ((...args: T) => void) & {
71
+ cancel: () => void;
72
+ };
73
+ export { type Breakpoint, type ClassnameArg, type DeepPartial, type ResponsiveConfig, type ResponsiveValue, debounce, resolveResponsiveValue, resolveResponsiveValueForBreakpoint };
@@ -0,0 +1,73 @@
1
+ type DeepPartial<T> = { [K in keyof T]?: T[K] extends readonly unknown[] ? T[K] : T[K] extends object ? DeepPartial<T[K]> : T[K]; };
2
+ export declare const BREAKPOINTS: readonly ["mobile", "tablet", "desktop"];
3
+ type Breakpoint = (typeof BREAKPOINTS)[number];
4
+ type ResponsiveConfig<T> = Omit<Partial<Record<(typeof BREAKPOINTS)[number], T>>, "mobile"> & {
5
+ mobile: T;
6
+ };
7
+ type ResponsiveValue<T> = T | ResponsiveConfig<T> | undefined;
8
+ declare const resolveResponsiveValueForBreakpoint: <T>(breakpoint: Breakpoint, value: ResponsiveValue<T>, fallback?: T) => T;
9
+ declare const resolveResponsiveValue: <T>(value: ResponsiveValue<T>, fallback?: T) => Required<ResponsiveConfig<T>>;
10
+ export declare const assertSafeCssValue: (value: unknown, label: string) => string;
11
+ /**
12
+ * Represents the casing options for strings.
13
+ * - "lowercase" -> hello world
14
+ * - "uppercase" -> HELLO WORLD
15
+ * - "snakecase" -> hello_world
16
+ * - "kebabcase" -> hello-world
17
+ * - "camelcase" -> helloWorld
18
+ * - "pascalcase" -> HelloWorld
19
+ * - "sentencecase" -> Hello world
20
+ * - "headercase" -> Hello World
21
+ **/
22
+ type StringCasing = "lowercase" | "uppercase" | "snakecase" | "kebabcase" | "camelcase" | "pascalcase" | "sentencecase" | "headercase";
23
+ /**
24
+ * Transforms the input string into the specified casing.
25
+ * Casing can be one of the following:
26
+ * - "lowercase" -> hello world
27
+ * - "uppercase" -> HELLO WORLD
28
+ * - "snakecase" -> hello_world
29
+ * - "kebabcase" -> hello-world
30
+ * - "camelcase" -> helloWorld
31
+ * - "pascalcase" -> HelloWorld
32
+ * - "sentencecase" -> Hello world
33
+ * - "headercase" -> Hello World
34
+ **/
35
+ export declare const stringWithCasing: (input: string, casing: StringCasing) => string;
36
+ /** Normalizes a search string by removing diacritics and converting to lowercase */
37
+ export declare const normalizeSearchString: (value: string) => string;
38
+ /** Removes unsafe characters from a string */
39
+ export declare const withSafeCharacters: (input: string) => string;
40
+ /** Escapes special characters in a string for use in CSS strings */
41
+ export declare const escapeCssString: (value: string) => string;
42
+ /**
43
+ * Represents a valid argument for the `classNames` function.
44
+ * It can be a string, an array of strings, undefined, null, or false.
45
+ */
46
+ type ClassnameArg = string | string[] | undefined | null | false;
47
+ /**
48
+ * Concatenates and trims the given arguments into a single string of class names.
49
+ *
50
+ * @param args - The arguments to be concatenated.
51
+ * @returns A string of class names.
52
+ */
53
+ export declare const cn: (...args: ClassnameArg[]) => string;
54
+ export declare const nameToInitials: (name: string) => string;
55
+ export declare const isHexColor: (color: string) => boolean;
56
+ /** Returns whether a color is dark based on WCAG relative luminance. */
57
+ export declare const isDarkColor: (color: string) => boolean;
58
+ export declare const hexToRgb: (hex: string) => {
59
+ r: number;
60
+ g: number;
61
+ b: number;
62
+ };
63
+ export declare const rgbToHex: (r: number, g: number, b: number) => string;
64
+ /**
65
+ * Call the original function, but applying the debounce rules.
66
+ *
67
+ * Only the last call to the function shall be executed after the timeout has been reached.
68
+ * @returns the debounced function with a cancel function property to clear the timeout.
69
+ */
70
+ declare const debounce: <T extends unknown[]>(func: (...args: T) => void, wait: number) => ((...args: T) => void) & {
71
+ cancel: () => void;
72
+ };
73
+ export { type Breakpoint, type ClassnameArg, type DeepPartial, type ResponsiveConfig, type ResponsiveValue, debounce, resolveResponsiveValue, resolveResponsiveValueForBreakpoint };
package/dist/index.js ADDED
@@ -0,0 +1,211 @@
1
+ // src/responsive/constants.ts
2
+ const BREAKPOINTS = [
3
+ "mobile",
4
+ "tablet",
5
+ "desktop"
6
+ ];
7
+ // src/responsive/index.ts
8
+ const resolveResponsiveValueForBreakpoint = (breakpoint, value, fallback) => {
9
+ if (value === void 0 || value === null) return fallback;
10
+ return typeof value !== "object" || !(breakpoint in value) ? value ?? fallback : value[breakpoint] ?? fallback;
11
+ };
12
+ const resolveResponsiveValue = (value, fallback) => {
13
+ const mobile = resolveResponsiveValueForBreakpoint("mobile", value, fallback);
14
+ const tablet = resolveResponsiveValueForBreakpoint("tablet", value, mobile);
15
+ return {
16
+ mobile,
17
+ tablet,
18
+ desktop: resolveResponsiveValueForBreakpoint("desktop", value, tablet)
19
+ };
20
+ };
21
+ // src/string/assert.ts
22
+ const assertSafeCssValue = (value, label) => {
23
+ if (typeof value !== "string" && typeof value !== "number") throw new TypeError(`${label} must be a string or number.`);
24
+ const serialized = String(value).trim();
25
+ if (serialized.length === 0 || /[;{}<>\u0000-\u001f\u007f]/.test(serialized)) throw new TypeError(`${label} must be a non-empty CSS value and must not contain semicolons, braces, angle brackets, or control characters.`);
26
+ return serialized;
27
+ };
28
+ // src/string/normalize.ts
29
+ /** Normalizes a search string by removing diacritics and converting to lowercase */
30
+ const normalizeSearchString = (value) => value.normalize("NFD").replace(/[\u0300-\u036f]/g, "").toLocaleLowerCase();
31
+ /** Removes unsafe characters from a string */
32
+ const withSafeCharacters = (input) => input.trim().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-zA-Z0-9\s-]/g, "").replace(/([A-Z].*[^\s][A-Z])/g, "$1".slice(0, 1).toUpperCase() + "$1".slice(1).toLowerCase());
33
+ /** Escapes special characters in a string for use in CSS strings */
34
+ const escapeCssString = (value) => {
35
+ return value.replace(/["\\\n\r\f]/g, (character) => {
36
+ switch (character) {
37
+ case "\"": return "\\\"";
38
+ case "\\": return "\\\\";
39
+ case "\n": return "\\a ";
40
+ case "\r": return "\\d ";
41
+ case "\f": return "\\c ";
42
+ default: return character;
43
+ }
44
+ });
45
+ };
46
+ // src/string/casing.ts
47
+ /**
48
+ * Transforms the input string into the specified casing.
49
+ * Casing can be one of the following:
50
+ * - "lowercase" -> hello world
51
+ * - "uppercase" -> HELLO WORLD
52
+ * - "snakecase" -> hello_world
53
+ * - "kebabcase" -> hello-world
54
+ * - "camelcase" -> helloWorld
55
+ * - "pascalcase" -> HelloWorld
56
+ * - "sentencecase" -> Hello world
57
+ * - "headercase" -> Hello World
58
+ **/
59
+ const stringWithCasing = (input, casing) => {
60
+ const trimmedInput = input.trim();
61
+ const cleanedInput = withSafeCharacters(trimmedInput);
62
+ switch (casing) {
63
+ case "lowercase": return trimmedInput.toLowerCase();
64
+ case "uppercase": return trimmedInput.toUpperCase();
65
+ case "snakecase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => a + "_" + b.toLowerCase()).replace(/[^A-Za-z0-9]+|_+/g, "_").toLowerCase();
66
+ case "kebabcase": return trimmedInput.replace(/^[^A-Za-z0-9]*-?|[^A-Za-z0-9]*-?$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, "-").toLowerCase();
67
+ case "camelcase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/[^A-Za-z0-9]+/g, "$").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`).toLowerCase().replace(/(\$)(\w)/g, (_m, _a, b) => b.toUpperCase());
68
+ case "pascalcase": return cleanedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "$").replace(/[^A-Za-z0-9]+/g, "$").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}$${b}`).toLowerCase().replace(/(\$)(\w?)/g, (_m, a, b) => b.toUpperCase());
69
+ case "sentencecase": {
70
+ const textcase = trimmedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, " ").toLowerCase();
71
+ return textcase.charAt(0).toUpperCase() + textcase.slice(1);
72
+ }
73
+ case "headercase": return trimmedInput.replace(/^[^A-Za-z0-9]*|[^A-Za-z0-9]*$/g, "").replace(/([a-z])([A-Z])/g, (_m, a, b) => `${a}_${b.toLowerCase()}`).replace(/[^A-Za-z0-9]+|_+/g, " ").toLowerCase().replace(/( ?)(\w+)( ?)/g, (m, a, b, c) => a + b.charAt(0).toUpperCase() + b.slice(1) + c);
74
+ }
75
+ };
76
+ // src/string/class-names.ts
77
+ /**
78
+ * Concatenates and trims the given arguments into a single string of class names.
79
+ *
80
+ * @param args - The arguments to be concatenated.
81
+ * @returns A string of class names.
82
+ */
83
+ const cn = (...args) => {
84
+ return args.filter((v) => !!v).flat().flatMap((v) => v.split(" ")).filter((v) => v.length > 0).join(" ").trim();
85
+ };
86
+ // src/string/name-to-initials.ts
87
+ const NAME_PARTICLES = /* @__PURE__ */ new Set([
88
+ "van",
89
+ "den",
90
+ "der",
91
+ "de",
92
+ "ter",
93
+ "ten",
94
+ "te",
95
+ "het",
96
+ "'t",
97
+ "von",
98
+ "vom",
99
+ "zum",
100
+ "zur",
101
+ "zu",
102
+ "du",
103
+ "des",
104
+ "le",
105
+ "la",
106
+ "les",
107
+ "del",
108
+ "los",
109
+ "las",
110
+ "da",
111
+ "das",
112
+ "do",
113
+ "dos",
114
+ "di",
115
+ "della",
116
+ "delle",
117
+ "dello",
118
+ "dei",
119
+ "degli",
120
+ "al",
121
+ "el",
122
+ "bin",
123
+ "ibn",
124
+ "bint",
125
+ "af",
126
+ "av",
127
+ "ap",
128
+ "ab"
129
+ ]);
130
+ const NAME_SUFFIXES = /* @__PURE__ */ new Set([
131
+ "jr",
132
+ "sr",
133
+ "ii",
134
+ "iii",
135
+ "iv",
136
+ "v",
137
+ "phd",
138
+ "md"
139
+ ]);
140
+ const normalizeNamePart = (part) => {
141
+ return part.toLocaleLowerCase().replace(/[\p{P}\p{S}]/gu, "");
142
+ };
143
+ const getFirstLetter = (part) => {
144
+ return part.match(/\p{L}/u)?.[0].toLocaleUpperCase() ?? "";
145
+ };
146
+ const nameToInitials = (name) => {
147
+ const parts = name.trim().split(/\s+/u).filter(Boolean);
148
+ if (parts.length === 0) return "?";
149
+ while (parts.length > 1 && NAME_SUFFIXES.has(normalizeNamePart(parts[parts.length - 1]))) parts.pop();
150
+ const firstInitial = getFirstLetter(parts[0]);
151
+ if (parts.length === 1) return firstInitial;
152
+ const surname = [...parts.slice(1)].reverse().find((part) => !NAME_PARTICLES.has(normalizeNamePart(part)));
153
+ return firstInitial + getFirstLetter(surname ?? parts[parts.length - 1]);
154
+ };
155
+ // src/color/to-color.ts
156
+ const hexToRgb = (hex) => {
157
+ if (!/^#([0-9A-F]{3}){1,2}$/i.test(hex)) throw new Error("Invalid hex color");
158
+ let r, g, b;
159
+ if (hex.length === 4) {
160
+ r = parseInt(hex[1] + hex[1], 16);
161
+ g = parseInt(hex[2] + hex[2], 16);
162
+ b = parseInt(hex[3] + hex[3], 16);
163
+ } else {
164
+ r = parseInt(hex.slice(1, 3), 16);
165
+ g = parseInt(hex.slice(3, 5), 16);
166
+ b = parseInt(hex.slice(5, 7), 16);
167
+ }
168
+ return {
169
+ r,
170
+ g,
171
+ b
172
+ };
173
+ };
174
+ const rgbToHex = (r, g, b) => {
175
+ const toHex = (value) => {
176
+ const hex = value.toString(16);
177
+ return hex.length === 1 ? "0" + hex : hex;
178
+ };
179
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
180
+ };
181
+ // src/color/is-color.ts
182
+ const isHexColor = (color) => {
183
+ return /^#([0-9A-F]{3}){1,2}$/i.test(color);
184
+ };
185
+ const linearize = (value) => {
186
+ const channel = value / 255;
187
+ return channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
188
+ };
189
+ /** Returns whether a color is dark based on WCAG relative luminance. */
190
+ const isDarkColor = (color) => {
191
+ const { r, g, b } = hexToRgb(color);
192
+ return .2126 * linearize(r) + .7152 * linearize(g) + .0722 * linearize(b) < .179;
193
+ };
194
+ // src/timing/debounce.ts
195
+ /**
196
+ * Call the original function, but applying the debounce rules.
197
+ *
198
+ * Only the last call to the function shall be executed after the timeout has been reached.
199
+ * @returns the debounced function with a cancel function property to clear the timeout.
200
+ */
201
+ const debounce = (func, wait) => {
202
+ let timeout;
203
+ const cancel = () => clearTimeout(timeout);
204
+ return Object.assign((...args) => {
205
+ clearTimeout(timeout);
206
+ timeout = setTimeout(() => func.apply(void 0, args), wait);
207
+ }, { cancel });
208
+ };
209
+ export { BREAKPOINTS, assertSafeCssValue, cn, debounce, escapeCssString, hexToRgb, isDarkColor, isHexColor, nameToInitials, normalizeSearchString, resolveResponsiveValue, resolveResponsiveValueForBreakpoint, rgbToHex, stringWithCasing, withSafeCharacters };
210
+
211
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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":";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"}
package/package.json CHANGED
@@ -1,6 +1,41 @@
1
1
  {
2
2
  "name": "@puzzle-ui/core",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "description": "Framework-independent utilities",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public",
8
+ "registry": "https://registry.npmjs.org/"
9
+ },
10
+ "type": "module",
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
24
+ }
25
+ },
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "sideEffects": false,
30
+ "scripts": {
31
+ "build": "tsdown",
32
+ "prepack": "tsdown",
33
+ "vitest": "bunx vitest run --passWithNoTests",
34
+ "vitest:watch": "bunx vitest"
35
+ },
36
+ "devDependencies": {
37
+ "tsdown": "^0.23.1",
38
+ "tsup": "latest",
39
+ "typescript": "^6.0.3"
40
+ }
41
+ }