@entry-ui/utilities 0.2.0 → 0.3.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.
@@ -0,0 +1,64 @@
1
+ /**
2
+ * A comprehensive union of all standard event maps available in the browser environment.
3
+ *
4
+ * This type aggregates event definitions from `HTMLElement`, `Document`, and `Window`
5
+ * into a single unified interface. It is used to provide exhaustive type safety and
6
+ * accurate IntelliSense during event registration, ensuring that the event object
7
+ * signature is correctly inferred based on the target and event type.
8
+ */
9
+ type AllEventMaps = HTMLElementEventMap & DocumentEventMap & WindowEventMap;
10
+ /**
11
+ * Configuration object for the `addEventListenerOnce` utility.
12
+ *
13
+ * This interface defines the necessary properties to register a one-time event listener.
14
+ * It uses a generic type `K` constrained to `AllEventMaps` to ensure that the event
15
+ * type and its corresponding listener remain synchronized and type-safe across
16
+ * different DOM targets.
17
+ */
18
+ interface AddEventListenerOnceParams<K extends keyof AllEventMaps> {
19
+ /**
20
+ * The DOM node or global object to which the event listener will be attached.
21
+ * Supports `HTMLElement`, `Document`, and `Window` targets.
22
+ */
23
+ target: HTMLElement | Document | Window;
24
+ /**
25
+ * A case-sensitive string representing the event type to monitor.
26
+ * The available types are dynamically inferred based on the `target` category.
27
+ */
28
+ type: K;
29
+ /**
30
+ * The callback function executed when the event is dispatched.
31
+ * It receives a strictly typed event object corresponding to the provided event `type`.
32
+ */
33
+ listener: (this: HTMLElement | Document | Window, ev: AllEventMaps[K]) => any;
34
+ /**
35
+ * An optional configuration object that specifies characteristics about the event listener.
36
+ * While most native options are supported, the `once` property is internally enforced
37
+ * as `true` and cannot be overridden to ensure the utility's one-time execution behavior.
38
+ */
39
+ options?: Omit<AddEventListenerOptions, 'once'>;
40
+ }
41
+
42
+ /**
43
+ * Registers an event listener that is automatically removed after its first invocation.
44
+ *
45
+ * This utility wraps the native `addEventListener` method and enforces the `once: true`
46
+ * option. It provides a clean way to handle one-time events while returning a manual
47
+ * cleanup function, which can be used to remove the listener before it even fires.
48
+ * It is fully type-safe, supporting event maps for `HTMLElement`, `Document`, and `Window`.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const cleanup = addEventListenerOnce({
53
+ * target: window,
54
+ * type: "scroll",
55
+ * listener: (event) => console.log("First scroll detected!"", event),
56
+ * options: { passive: true },
57
+ * });
58
+ *
59
+ * cleanup(); // If the listener is no longer needed before the first scroll.
60
+ * ```
61
+ */
62
+ declare const addEventListenerOnce: <K extends keyof AllEventMaps>(params: AddEventListenerOnceParams<K>) => () => void;
63
+
64
+ export { type AddEventListenerOnceParams, type AllEventMaps, addEventListenerOnce };
@@ -0,0 +1,2 @@
1
+ export{a as addEventListenerOnce}from'../chunk-GLPQ4KOF.js';//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,2 @@
1
+ var i=Object.freeze({clipPath:"inset(50%)",overflow:"hidden",whiteSpace:"nowrap",border:0,padding:0,width:1,height:1,margin:-1,position:"absolute"});export{i as a};//# sourceMappingURL=chunk-AYHMR4G2.js.map
2
+ //# sourceMappingURL=chunk-AYHMR4G2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/visually-hidden-input-style/visually-hidden-input-style.ts"],"names":["visuallyHiddenInputStyle"],"mappings":"AAoBO,IAAMA,CAAAA,CAA2B,OAAO,MAAA,CAAO,CACpD,SAAU,YAAA,CACV,QAAA,CAAU,QAAA,CACV,UAAA,CAAY,QAAA,CACZ,MAAA,CAAQ,EACR,OAAA,CAAS,CAAA,CACT,MAAO,CAAA,CACP,MAAA,CAAQ,EACR,MAAA,CAAQ,EAAA,CACR,QAAA,CAAU,UACZ,CAAC","file":"chunk-AYHMR4G2.js","sourcesContent":["import type * as CSS from 'csstype';\n\n/**\n * Visually hides an input element while keeping it functional and accessible.\n *\n * Commonly used for styling native checkboxes, radio buttons, or file inputs\n * by hiding the default browser element and replacing it with a custom-styled\n * UI, while ensuring the underlying input remains focusable and reachable\n * by assistive technologies.\n *\n * @example\n * ```tsx\n * const CustomCheckbox = () => (\n * \t<>\n * \t\t<input type=\"checkbox\" id=\"terms\" style={visuallyHiddenInputStyle} />\n * \t\t<label htmlFor=\"terms\">I agree to the terms</label>\n * \t</>\n * );\n * ```\n */\nexport const visuallyHiddenInputStyle = Object.freeze({\n clipPath: 'inset(50%)',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n border: 0,\n padding: 0,\n width: 1,\n height: 1,\n margin: -1,\n position: 'absolute',\n}) satisfies CSS.Properties<string | number>;\n"]}
@@ -0,0 +1,2 @@
1
+ var d=s=>{let{target:e,type:t,listener:n,options:a}=s,r={...a,once:true};return e.addEventListener(t,n,r),()=>{e.removeEventListener(t,n,r);}};export{d as a};//# sourceMappingURL=chunk-GLPQ4KOF.js.map
2
+ //# sourceMappingURL=chunk-GLPQ4KOF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/add-event-listener-once/add-event-listener-once.ts"],"names":["addEventListenerOnce","params","target","type","listener","options","eventOptions"],"mappings":"AAsBO,IAAMA,EAAsDC,CAAAA,EAA0C,CAC3G,GAAM,CAAE,OAAAC,CAAAA,CAAQ,IAAA,CAAAC,CAAAA,CAAM,QAAA,CAAAC,EAAU,OAAA,CAAAC,CAAQ,CAAA,CAAIJ,CAAAA,CAEtCK,EAAe,CAAE,GAAGD,CAAAA,CAAS,IAAA,CAAM,IAAK,CAAA,CAE9C,OAAAH,CAAAA,CAAO,gBAAA,CAAiBC,EAAMC,CAAAA,CAAgDE,CAAY,CAAA,CAE1E,IAAM,CACpBJ,CAAAA,CAAO,mBAAA,CAAoBC,EAAMC,CAAAA,CAAgDE,CAAY,EAC/F,CAGF","file":"chunk-GLPQ4KOF.js","sourcesContent":["import type { AllEventMaps, AddEventListenerOnceParams } from './add-event-listener-once.types';\n\n/**\n * Registers an event listener that is automatically removed after its first invocation.\n *\n * This utility wraps the native `addEventListener` method and enforces the `once: true`\n * option. It provides a clean way to handle one-time events while returning a manual\n * cleanup function, which can be used to remove the listener before it even fires.\n * It is fully type-safe, supporting event maps for `HTMLElement`, `Document`, and `Window`.\n *\n * @example\n * ```ts\n * const cleanup = addEventListenerOnce({\n * \ttarget: window,\n * \ttype: \"scroll\",\n * \tlistener: (event) => console.log(\"First scroll detected!\"\", event),\n * \toptions: { passive: true },\n * });\n *\n * cleanup(); // If the listener is no longer needed before the first scroll.\n * ```\n */\nexport const addEventListenerOnce = <K extends keyof AllEventMaps>(params: AddEventListenerOnceParams<K>) => {\n const { target, type, listener, options } = params;\n\n const eventOptions = { ...options, once: true };\n\n target.addEventListener(type, listener as EventListenerOrEventListenerObject, eventOptions);\n\n const cleanup = () => {\n target.removeEventListener(type, listener as EventListenerOrEventListenerObject, eventOptions);\n };\n\n return cleanup;\n};\n"]}
@@ -1,2 +1,2 @@
1
- var u=f=>f.length===0?{}:f.reduce((l,n)=>{if(!n)return l;let c;if(typeof n=="string"){c={};let s=[],r="",i=0;for(let t=0;t<n.length;t++){let e=n[t];e==="("?(i++,r+=e):e===")"?(i--,r+=e):e===";"&&i===0?(r.trim()&&s.push(r.trim()),r=""):r+=e;}r.trim()&&s.push(r.trim());for(let t of s){let e=t.indexOf(":");if(e===-1)continue;let o=t.slice(0,e).trim(),p=t.slice(e+1).trim();o&&p&&(c[o]=p);}}else c=n;for(let[s,r]of Object.entries(c)){if(s.startsWith("--")){l[s]=r;continue}let i;if(s.startsWith("-")){let t=s.slice(1);if(t.startsWith("ms-")){let e=t.slice(3);i="ms"+e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(o,p)=>p.toUpperCase());}else i=t.charAt(0).toUpperCase()+t.slice(1).replace(/-([a-z])/g,(e,o)=>o.toUpperCase());}else i=s.replace(/-([a-z])/g,(t,e)=>e.toUpperCase());l[i]=r;}return l},{});export{u as a};//# sourceMappingURL=chunk-JLS3437A.js.map
2
- //# sourceMappingURL=chunk-JLS3437A.js.map
1
+ var u=f=>f.length===0?{}:f.reduce((l,n)=>{if(!n)return l;let c;if(typeof n=="string"){c={};let s=[],r="",i=0;for(let t=0;t<n.length;t++){let e=n[t];e==="("?(i++,r+=e):e===")"?(i--,r+=e):e===";"&&i===0?(r.trim()&&s.push(r.trim()),r=""):r+=e;}r.trim()&&s.push(r.trim());for(let t of s){let e=t.indexOf(":");if(e===-1)continue;let o=t.slice(0,e).trim(),p=t.slice(e+1).trim();o&&p&&(c[o]=p);}}else c=n;for(let[s,r]of Object.entries(c)){if(s.startsWith("--")){l[s]=r;continue}let i;if(s.startsWith("-")){let t=s.slice(1);if(t.startsWith("ms-")){let e=t.slice(3);i="ms"+e.charAt(0).toUpperCase()+e.slice(1).replace(/-([a-z])/g,(o,p)=>p.toUpperCase());}else i=t.charAt(0).toUpperCase()+t.slice(1).replace(/-([a-z])/g,(e,o)=>o.toUpperCase());}else i=s.replace(/-([a-z])/g,(t,e)=>e.toUpperCase());l[i]=r;}return l},{});export{u as a};//# sourceMappingURL=chunk-NBN5PUZ6.js.map
2
+ //# sourceMappingURL=chunk-NBN5PUZ6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/merge-styles/merge-styles.ts"],"names":["mergeStyles","styles","acc","style","styleObject","declarations","currentDeclaration","parenDepth","i","char","declaration","colonIndex","property","value","key","normalizedKey","withoutPrefix","rest","_","letter"],"mappings":"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","file":"chunk-NBN5PUZ6.js","sourcesContent":["import type { PossibleStyle } from './merge-styles.types';\n\n/**\n * Merges multiple style values into a single, unified style object.\n *\n * This function consolidates a variety of style formats (inline strings, object records,\n * or undefined) into a single object. It ensures that all property keys are normalized\n * to camelCase or PascalCase where appropriate (e.g., handling vendor prefixes like\n * `-webkit-` as `Webkit` and `-ms-` as `ms`), while preserving CSS custom properties.\n *\n * The parser intelligently handles complex string values like `calc()` or `url()` to\n * ensure semicolons within them do not break the merging process. Following the CSS\n * cascade principle, styles appearing later in the array will override matching\n * properties from earlier ones.\n *\n * @example\n * ```ts\n * mergeStyles([\"color: red; margin-top: 10px;\", { marginTop: \"20px\", \"--spacing-unit\": \"20px\" }]);\n * // Returns: { color: \"red\", marginTop: \"20px\", \"--spacing-unit\": \"20px\" }\n * ```\n */\nexport const mergeStyles = (styles: PossibleStyle[]) => {\n // Short-circuit if no styles are provided to avoid unnecessary processing.\n if (styles.length === 0) return {};\n\n return styles.reduce<Record<string, string | number | undefined>>((acc, style) => {\n // Skip nullish values (`null`, `undefined`) which are common in conditional styling.\n if (!style) return acc;\n\n let styleObject: Record<string, string | number | undefined>;\n\n // Case 1: Handle inline style strings (e.g., `\"color: red; margin-top: 10px\"`).\n if (typeof style === 'string') {\n styleObject = {};\n const declarations: string[] = [];\n let currentDeclaration = '';\n let parenDepth = 0;\n\n // Manual tokenizer that splits declarations by semicolon while respecting\n // parentheses. This ensures that semicolons inside `calc()`, `url()`, or\n // data URIs do not break the parsing logic.\n for (let i = 0; i < style.length; i++) {\n const char = style[i];\n\n if (char === '(') {\n parenDepth++;\n currentDeclaration += char;\n } else if (char === ')') {\n parenDepth--;\n currentDeclaration += char;\n } else if (char === ';' && parenDepth === 0) {\n // Found a valid declaration boundary.\n if (currentDeclaration.trim()) {\n declarations.push(currentDeclaration.trim());\n }\n currentDeclaration = '';\n } else {\n currentDeclaration += char;\n }\n }\n\n // Capture the remaining part if the string doesn't end with a semicolon.\n if (currentDeclaration.trim()) {\n declarations.push(currentDeclaration.trim());\n }\n\n // Convert `\"property: value\"` pairs into object entries.\n for (const declaration of declarations) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex === -1) continue; // Skip malformed declarations.\n\n const property = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n\n if (property && value) {\n styleObject[property] = value;\n }\n }\n } else {\n // Case 2: Style is already an object, use it directly for normalization.\n styleObject = style;\n }\n\n // Normalization Loop:\n // Converts kebab-case keys and vendor prefixes into JS-friendly camelCase/PascalCase.\n for (const [key, value] of Object.entries(styleObject)) {\n // CSS Custom Properties (Variables) should remain in kebab-case.\n if (key.startsWith('--')) {\n acc[key] = value;\n continue;\n }\n\n let normalizedKey: string;\n\n if (key.startsWith('-')) {\n const withoutPrefix = key.slice(1);\n\n // Special handling for Internet Explorer prefix.\n // In JS style objects, `\"-ms-property\"` becomes `\"msProperty\"` (lowercase 'm').\n if (withoutPrefix.startsWith('ms-')) {\n const rest = withoutPrefix.slice(3);\n normalizedKey =\n 'ms' +\n rest.charAt(0).toUpperCase() +\n rest.slice(1).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n } else {\n // Standard vendor prefixes (e.g., `-webkit-`, `-moz-`, `-o-`).\n // These are normalized to PascalCase (e.g., `\"WebkitTransform\"`).\n normalizedKey =\n withoutPrefix.charAt(0).toUpperCase() +\n withoutPrefix.slice(1).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n }\n } else {\n // Standard CSS properties: convert `\"background-color\"` to `\"backgroundColor\"`.\n normalizedKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n }\n\n // Later styles in the array will overwrite earlier ones.\n acc[normalizedKey] = value;\n }\n\n return acc;\n }, {});\n};\n"]}
@@ -0,0 +1,2 @@
1
+ var i=e=>new Promise(t=>setTimeout(t,e));export{i as a};//# sourceMappingURL=chunk-OUZ54COH.js.map
2
+ //# sourceMappingURL=chunk-OUZ54COH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/wait/wait.ts"],"names":["wait","delayMs","resolve"],"mappings":"AAgBO,IAAMA,CAAAA,CAAQC,GACZ,IAAI,OAAA,CAASC,GAAY,UAAA,CAAWA,CAAAA,CAASD,CAAO,CAAC","file":"chunk-OUZ54COH.js","sourcesContent":["/**\n * Pauses the execution of the current asynchronous function for a specified duration.\n *\n * This function utilizes a Promise-based wrapper around `setTimeout` to create\n * a non-blocking delay, allowing for cleaner asynchronous control flows using\n * async/await syntax.\n *\n * @example\n * ```ts\n * const performTask = async () => {\n * \tconsole.log(\"Starting task...\");\n * \tawait wait(2000); // Pauses execution for 2 seconds\n * \tconsole.log(\"Task resumed after 2 seconds.\");\n * };\n * ```\n */\nexport const wait = (delayMs: number) => {\n return new Promise((resolve) => setTimeout(resolve, delayMs));\n};\n"]}
@@ -0,0 +1,2 @@
1
+ var t=Object.freeze({clipPath:"inset(50%)",overflow:"hidden",whiteSpace:"nowrap",border:0,padding:0,width:1,height:1,margin:-1,position:"fixed",top:0,left:0});export{t as a};//# sourceMappingURL=chunk-YRBGPPKC.js.map
2
+ //# sourceMappingURL=chunk-YRBGPPKC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/visually-hidden-style/visually-hidden-style.ts"],"names":["visuallyHiddenStyle"],"mappings":"AAqBO,IAAMA,CAAAA,CAAsB,MAAA,CAAO,MAAA,CAAO,CAC/C,QAAA,CAAU,YAAA,CACV,QAAA,CAAU,QAAA,CACV,UAAA,CAAY,QAAA,CACZ,MAAA,CAAQ,CAAA,CACR,OAAA,CAAS,EACT,KAAA,CAAO,CAAA,CACP,MAAA,CAAQ,CAAA,CACR,MAAA,CAAQ,EAAA,CACR,QAAA,CAAU,OAAA,CACV,GAAA,CAAK,CAAA,CACL,IAAA,CAAM,CACR,CAAC","file":"chunk-YRBGPPKC.js","sourcesContent":["import type * as CSS from 'csstype';\n\n/**\n * A set of CSS properties used to hide an element visually while keeping it\n * accessible to screen readers.\n *\n * This utility is essential for providing additional context to assistive\n * technologies without affecting the visual layout. It uses a combination of\n * clipping, overflow, and absolute positioning to ensure the element has\n * dimensions of 1x1 pixel but remains \"visible\" in the accessibility tree.\n *\n * @example\n * ```tsx\n * const SearchButton = () => (\n * \t<button type=\"button\">\n * \t\t<Icon name=\"search\" />\n * \t\t<span style={visuallyHiddenStyle}>Search</span>\n * \t</button>\n * );\n * ```\n */\nexport const visuallyHiddenStyle = Object.freeze({\n clipPath: 'inset(50%)',\n overflow: 'hidden',\n whiteSpace: 'nowrap',\n border: 0,\n padding: 0,\n width: 1,\n height: 1,\n margin: -1,\n position: 'fixed',\n top: 0,\n left: 0,\n}) satisfies CSS.Properties<string | number>;\n"]}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
+ export { AddEventListenerOnceParams, AllEventMaps, addEventListenerOnce } from './add-event-listener-once/index.js';
1
2
  export { ErrorParams, error } from './error/index.js';
2
3
  export { FailParams, fail } from './fail/index.js';
3
4
  export { PossibleStyle, mergeStyles } from './merge-styles/index.js';
5
+ export { visuallyHiddenInputStyle } from './visually-hidden-input-style/index.js';
6
+ export { visuallyHiddenStyle } from './visually-hidden-style/index.js';
7
+ export { wait } from './wait/index.js';
4
8
  export { WarnParams, warn } from './warn/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export{a as error}from'./chunk-GG6DRWSS.js';export{a as fail}from'./chunk-O4WYO5SA.js';export{a as warn}from'./chunk-6L6DIP5N.js';export{a as mergeStyles}from'./chunk-JLS3437A.js';//# sourceMappingURL=index.js.map
1
+ export{a as warn}from'./chunk-6L6DIP5N.js';export{a as addEventListenerOnce}from'./chunk-GLPQ4KOF.js';export{a as error}from'./chunk-GG6DRWSS.js';export{a as fail}from'./chunk-O4WYO5SA.js';export{a as visuallyHiddenInputStyle}from'./chunk-AYHMR4G2.js';export{a as mergeStyles}from'./chunk-NBN5PUZ6.js';export{a as visuallyHiddenStyle}from'./chunk-YRBGPPKC.js';export{a as wait}from'./chunk-OUZ54COH.js';//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
@@ -4,9 +4,13 @@
4
4
  * This type allows for flexibility in how styles are defined, supporting:
5
5
  *
6
6
  * - `string`: Standard inline CSS strings (e.g., `"color: red; padding: 10px"`).
7
+ *
7
8
  * - `Record<string, string | number | undefined>`: A structured object of CSS declarations.
8
- * Supports camelCase, kebab-case, and CSS custom properties (e.g., `{ color: 'red', "margin-top": 10, "--spacing-unit": "20px" }`).
9
+ * Supports camelCase, kebab-case, and CSS custom properties (e.g., `{ color: "red", "margin-top": 10, "--spacing-unit": "20px" }`).
10
+ *
9
11
  * - `undefined`: Useful for conditional styling where a style might not be present.
12
+ * Since `boolean` is not accepted, use ternary operators or logical OR
13
+ * to ensure a valid type (e.g., `isActive ? "color: red" : undefined`).
10
14
  */
11
15
  type PossibleStyle = string | Record<string, string | number | undefined> | undefined;
12
16
 
@@ -25,7 +29,7 @@ type PossibleStyle = string | Record<string, string | number | undefined> | unde
25
29
  *
26
30
  * @example
27
31
  * ```ts
28
- * mergeStyles(["color: red; margin-top: 10px;"", { marginTop: "20px", "--spacing-unit": "20px" }]);
32
+ * mergeStyles(["color: red; margin-top: 10px;", { marginTop: "20px", "--spacing-unit": "20px" }]);
29
33
  * // Returns: { color: "red", marginTop: "20px", "--spacing-unit": "20px" }
30
34
  * ```
31
35
  */
@@ -1,2 +1,2 @@
1
- export{a as mergeStyles}from'../chunk-JLS3437A.js';//# sourceMappingURL=index.js.map
1
+ export{a as mergeStyles}from'../chunk-NBN5PUZ6.js';//# sourceMappingURL=index.js.map
2
2
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Visually hides an input element while keeping it functional and accessible.
3
+ *
4
+ * Commonly used for styling native checkboxes, radio buttons, or file inputs
5
+ * by hiding the default browser element and replacing it with a custom-styled
6
+ * UI, while ensuring the underlying input remains focusable and reachable
7
+ * by assistive technologies.
8
+ *
9
+ * @example
10
+ * ```tsx
11
+ * const CustomCheckbox = () => (
12
+ * <>
13
+ * <input type="checkbox" id="terms" style={visuallyHiddenInputStyle} />
14
+ * <label htmlFor="terms">I agree to the terms</label>
15
+ * </>
16
+ * );
17
+ * ```
18
+ */
19
+ declare const visuallyHiddenInputStyle: Readonly<{
20
+ clipPath: "inset(50%)";
21
+ overflow: "hidden";
22
+ whiteSpace: "nowrap";
23
+ border: 0;
24
+ padding: 0;
25
+ width: 1;
26
+ height: 1;
27
+ margin: -1;
28
+ position: "absolute";
29
+ }>;
30
+
31
+ export { visuallyHiddenInputStyle };
@@ -0,0 +1,2 @@
1
+ export{a as visuallyHiddenInputStyle}from'../chunk-AYHMR4G2.js';//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A set of CSS properties used to hide an element visually while keeping it
3
+ * accessible to screen readers.
4
+ *
5
+ * This utility is essential for providing additional context to assistive
6
+ * technologies without affecting the visual layout. It uses a combination of
7
+ * clipping, overflow, and absolute positioning to ensure the element has
8
+ * dimensions of 1x1 pixel but remains "visible" in the accessibility tree.
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * const SearchButton = () => (
13
+ * <button type="button">
14
+ * <Icon name="search" />
15
+ * <span style={visuallyHiddenStyle}>Search</span>
16
+ * </button>
17
+ * );
18
+ * ```
19
+ */
20
+ declare const visuallyHiddenStyle: Readonly<{
21
+ clipPath: "inset(50%)";
22
+ overflow: "hidden";
23
+ whiteSpace: "nowrap";
24
+ border: 0;
25
+ padding: 0;
26
+ width: 1;
27
+ height: 1;
28
+ margin: -1;
29
+ position: "fixed";
30
+ top: 0;
31
+ left: 0;
32
+ }>;
33
+
34
+ export { visuallyHiddenStyle };
@@ -0,0 +1,2 @@
1
+ export{a as visuallyHiddenStyle}from'../chunk-YRBGPPKC.js';//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Pauses the execution of the current asynchronous function for a specified duration.
3
+ *
4
+ * This function utilizes a Promise-based wrapper around `setTimeout` to create
5
+ * a non-blocking delay, allowing for cleaner asynchronous control flows using
6
+ * async/await syntax.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * const performTask = async () => {
11
+ * console.log("Starting task...");
12
+ * await wait(2000); // Pauses execution for 2 seconds
13
+ * console.log("Task resumed after 2 seconds.");
14
+ * };
15
+ * ```
16
+ */
17
+ declare const wait: (delayMs: number) => Promise<unknown>;
18
+
19
+ export { wait };
@@ -0,0 +1,2 @@
1
+ export{a as wait}from'../chunk-OUZ54COH.js';//# sourceMappingURL=index.js.map
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entry-ui/utilities",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "homepage": "https://github.com/ZAHON/entry-ui/tree/main/packages/utilities#readme",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/merge-styles/merge-styles.ts"],"names":["mergeStyles","styles","acc","style","styleObject","declarations","currentDeclaration","parenDepth","i","char","declaration","colonIndex","property","value","key","normalizedKey","withoutPrefix","rest","_","letter"],"mappings":"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","file":"chunk-JLS3437A.js","sourcesContent":["import type { PossibleStyle } from './merge-styles.types';\n\n/**\n * Merges multiple style values into a single, unified style object.\n *\n * This function consolidates a variety of style formats (inline strings, object records,\n * or undefined) into a single object. It ensures that all property keys are normalized\n * to camelCase or PascalCase where appropriate (e.g., handling vendor prefixes like\n * `-webkit-` as `Webkit` and `-ms-` as `ms`), while preserving CSS custom properties.\n *\n * The parser intelligently handles complex string values like `calc()` or `url()` to\n * ensure semicolons within them do not break the merging process. Following the CSS\n * cascade principle, styles appearing later in the array will override matching\n * properties from earlier ones.\n *\n * @example\n * ```ts\n * mergeStyles([\"color: red; margin-top: 10px;\"\", { marginTop: \"20px\", \"--spacing-unit\": \"20px\" }]);\n * // Returns: { color: \"red\", marginTop: \"20px\", \"--spacing-unit\": \"20px\" }\n * ```\n */\nexport const mergeStyles = (styles: PossibleStyle[]) => {\n // Short-circuit if no styles are provided to avoid unnecessary processing.\n if (styles.length === 0) return {};\n\n return styles.reduce<Record<string, string | number | undefined>>((acc, style) => {\n // Skip nullish values (`null`, `undefined`) which are common in conditional styling.\n if (!style) return acc;\n\n let styleObject: Record<string, string | number | undefined>;\n\n // Case 1: Handle inline style strings (e.g., `\"color: red; margin-top: 10px\"`).\n if (typeof style === 'string') {\n styleObject = {};\n const declarations: string[] = [];\n let currentDeclaration = '';\n let parenDepth = 0;\n\n // Manual tokenizer that splits declarations by semicolon while respecting\n // parentheses. This ensures that semicolons inside `calc()`, `url()`, or\n // data URIs do not break the parsing logic.\n for (let i = 0; i < style.length; i++) {\n const char = style[i];\n\n if (char === '(') {\n parenDepth++;\n currentDeclaration += char;\n } else if (char === ')') {\n parenDepth--;\n currentDeclaration += char;\n } else if (char === ';' && parenDepth === 0) {\n // Found a valid declaration boundary.\n if (currentDeclaration.trim()) {\n declarations.push(currentDeclaration.trim());\n }\n currentDeclaration = '';\n } else {\n currentDeclaration += char;\n }\n }\n\n // Capture the remaining part if the string doesn't end with a semicolon.\n if (currentDeclaration.trim()) {\n declarations.push(currentDeclaration.trim());\n }\n\n // Convert `\"property: value\"` pairs into object entries.\n for (const declaration of declarations) {\n const colonIndex = declaration.indexOf(':');\n if (colonIndex === -1) continue; // Skip malformed declarations.\n\n const property = declaration.slice(0, colonIndex).trim();\n const value = declaration.slice(colonIndex + 1).trim();\n\n if (property && value) {\n styleObject[property] = value;\n }\n }\n } else {\n // Case 2: Style is already an object, use it directly for normalization.\n styleObject = style;\n }\n\n // Normalization Loop:\n // Converts kebab-case keys and vendor prefixes into JS-friendly camelCase/PascalCase.\n for (const [key, value] of Object.entries(styleObject)) {\n // CSS Custom Properties (Variables) should remain in kebab-case.\n if (key.startsWith('--')) {\n acc[key] = value;\n continue;\n }\n\n let normalizedKey: string;\n\n if (key.startsWith('-')) {\n const withoutPrefix = key.slice(1);\n\n // Special handling for Internet Explorer prefix.\n // In JS style objects, `\"-ms-property\"` becomes `\"msProperty\"` (lowercase 'm').\n if (withoutPrefix.startsWith('ms-')) {\n const rest = withoutPrefix.slice(3);\n normalizedKey =\n 'ms' +\n rest.charAt(0).toUpperCase() +\n rest.slice(1).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n } else {\n // Standard vendor prefixes (e.g., `-webkit-`, `-moz-`, `-o-`).\n // These are normalized to PascalCase (e.g., `\"WebkitTransform\"`).\n normalizedKey =\n withoutPrefix.charAt(0).toUpperCase() +\n withoutPrefix.slice(1).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n }\n } else {\n // Standard CSS properties: convert `\"background-color\"` to `\"backgroundColor\"`.\n normalizedKey = key.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());\n }\n\n // Later styles in the array will overwrite earlier ones.\n acc[normalizedKey] = value;\n }\n\n return acc;\n }, {});\n};\n"]}