use-auto-width-input 0.0.2 → 0.1.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
@@ -17,6 +17,31 @@ bun add use-auto-width-input
17
17
 
18
18
  ## Usage
19
19
 
20
+ There are two simple overloads for this hook: one that receives only an optional parameter for configuration, and the other that receives the actual reference of the input **and** the the configuration option.
21
+
22
+ #### `useAutoWidthInput(options?: AutoWidthInput)`
23
+
24
+ ```tsx
25
+ import { useRef } from 'react';
26
+ import { useAutoWidthInput } from 'use-auto-width-input';
27
+
28
+ function App() {
29
+ const { callbackRef } = useAutoWidthInput();
30
+
31
+ return (
32
+ <input
33
+ ref={callbackRef}
34
+ type="text"
35
+ placeholder="Type something..."
36
+ style={{ minWidth: "50px", maxWidth: "480px" }}
37
+ />
38
+ );
39
+ }
40
+ ```
41
+
42
+
43
+ #### `useAutoWidthInput(inputRef: RefObject<HTMLElement>, options?: AutoWidthInput)`
44
+
20
45
  ```tsx
21
46
  import { useRef } from 'react';
22
47
  import { useAutoWidthInput } from 'use-auto-width-input';
@@ -38,18 +63,22 @@ function App() {
38
63
 
39
64
  ## API
40
65
 
41
- ### `useAutoWidthInput(inputRef, options?)`
66
+ ### `useAutoWidthInput(inputRef?, options?)`
42
67
 
43
68
  #### Parameters
44
69
 
45
- - `inputRef`: A React ref object for the input element
70
+ - `inputRef` (optional): A React ref object for the input element
46
71
  - `options` (optional):
47
- - `minWidth?: string` - Minimum width for the input
72
+ - `minWidth?: string` - Minimum width for the input (can be overwritten via CSS using `!important`)
73
+ - `maxWidth?: string` - Maximum width for the input (can be overwritten via CSS using `!important`)
74
+ - `ghostElement?: object` - Object with the configuration for the ghost paragraph element
75
+ - `className?: string` - Classes to be added to the ghost element
76
+ - `id?: string` - ID to be given to the ghost element
77
+ - `styles?: Partial<CSSStyleDeclaration>` - Styles to be applied to the ghost element (can be overwritten via CSS using `!important`)
48
78
 
49
79
  #### Returns
50
80
 
51
81
  - `callbackRef`: Callback ref to attach to the input element
52
- - `width`: Current width value
53
82
  - `ref`: The original input ref
54
83
 
55
84
  ## How It Works
@@ -61,13 +90,31 @@ The hook creates an invisible "ghost" element that mirrors the input's text and
61
90
  You can easily control the minimum and maximum width by applying standard CSS styles directly to your input element:
62
91
 
63
92
  ```tsx
64
- <input
65
- ref={callbackRef}
66
- style={{
67
- minWidth: "100px", // Won't shrink below this
68
- maxWidth: "500px" // Won't grow beyond this
69
- }}
70
- />
93
+ ...
94
+ const { callbackRef } = useAutoWidthInput();
95
+
96
+ return
97
+ <input
98
+ ref={callbackRef}
99
+ style={{
100
+ minWidth: "100px", // Won't shrink below this
101
+ maxWidth: "500px" // Won't grow beyond this
102
+ }}
103
+ />
104
+ ...
105
+ ```
106
+
107
+ Or via the `AutoWidthInputOptions` parameter:
108
+
109
+ ```tsx
110
+ ...
111
+ const { callbackRef } = useAutoWidthInput({
112
+ minWidth: '100px',
113
+ maxWidth: '250px'
114
+ });
115
+
116
+ return <input ref={callbackRef} />;
117
+ ...
71
118
  ```
72
119
 
73
120
  This gives you full control over the input's width boundaries without needing additional hook configuration.
package/dist/index.cjs CHANGED
@@ -39,7 +39,7 @@ var applyStyles = (styles, target) => {
39
39
  const key = styleAttr;
40
40
  const value = styles[key];
41
41
  if (typeof value === "string" && typeof key === "string") {
42
- target.style.setProperty(key, value);
42
+ target.style[key] = value;
43
43
  }
44
44
  });
45
45
  };
@@ -74,19 +74,18 @@ var syncWidth = (inputRef, ghostElement) => {
74
74
  };
75
75
 
76
76
  // src/use-auto-width-input.ts
77
- function useAutoWidthInput(inputRef, options) {
78
- const [width, setWidth] = (0, import_react.useState)(options?.minWidth ?? 0);
77
+ function useAutoWidthInput(inputRefOrOptions, opts) {
78
+ const isRefObject = typeof inputRefOrOptions === "object" && "current" in inputRefOrOptions;
79
79
  const ghostElement = (0, import_react.useRef)(null);
80
+ const internalInpuRef = (0, import_react.useRef)(null);
81
+ const inputRef = isRefObject ? inputRefOrOptions : internalInpuRef;
82
+ const options = isRefObject ? opts : inputRefOrOptions;
80
83
  const input = inputRef.current;
81
- const syncWidthToState = (inputRef2, ghostElement2) => {
82
- const currentWidth = syncWidth(inputRef2, ghostElement2);
83
- if (currentWidth) setWidth(currentWidth);
84
- };
85
84
  const handleInput = (event) => {
86
85
  const target = event.target;
87
86
  if (ghostElement.current) {
88
87
  ghostElement.current.innerText = target.value;
89
- syncWidthToState(inputRef, ghostElement);
88
+ syncWidth(inputRef, ghostElement);
90
89
  }
91
90
  };
92
91
  const destroy = () => {
@@ -108,7 +107,7 @@ function useAutoWidthInput(inputRef, options) {
108
107
  applyFontStyles(styles, ghostElement.current);
109
108
  if (options?.ghostElement?.styles)
110
109
  applyStyles(options?.ghostElement?.styles, ghostElement.current);
111
- syncWidthToState(inputRef, ghostElement);
110
+ syncWidth(inputRef, ghostElement);
112
111
  inputRef.current.addEventListener("input", handleInput);
113
112
  };
114
113
  (0, import_react.useEffect)(
@@ -131,7 +130,6 @@ function useAutoWidthInput(inputRef, options) {
131
130
  [inputRef]
132
131
  );
133
132
  return {
134
- width,
135
133
  callbackRef,
136
134
  ref: inputRef
137
135
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/use-auto-width-input.ts","../src/helpers.ts"],"sourcesContent":["export * from \"./use-auto-width-input\";\n\nexport * from \"./types\";\n","import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\nimport {\n applyFontStyles,\n applyStyles,\n createGhostElement,\n syncWidth,\n} from \"./helpers\";\n\ntype UseAutoWidthInputReturn = {\n width: string | number;\n callbackRef: (element: HTMLInputElement | null) => void;\n ref: RefObject<HTMLInputElement | null>;\n};\n\n// export function useAutoWidthInput(\n// inputRef: RefObject<HTMLInputElement | null>,\n// options?: AutWidthInputOptions\n// ): UseAutoWidthInputReturn;\n\n// export function useAutoWidthInput(\n// options?: AutWidthInputOptions\n// ): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n inputRef: RefObject<HTMLInputElement | null>,\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn {\n const [width, setWidth] = useState(options?.minWidth ?? 0);\n const ghostElement = useRef<HTMLElement>(null);\n const input = inputRef.current;\n\n const syncWidthToState = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n ) => {\n const currentWidth = syncWidth(inputRef, ghostElement);\n if (currentWidth) setWidth(currentWidth);\n };\n\n const handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n\n if (ghostElement.current) {\n ghostElement.current.innerText = target.value;\n\n syncWidthToState(inputRef, ghostElement);\n }\n };\n\n const destroy = () => {\n input?.removeEventListener(\"input\", handleInput);\n ghostElement.current?.remove();\n ghostElement.current = null;\n };\n\n const mountBehaviour = () => {\n if (!inputRef.current) return;\n\n // Doesnt make sense to mount an element if the element already exist\n if (ghostElement.current) return;\n\n const styles = window.getComputedStyle(inputRef.current);\n ghostElement.current = createGhostElement(options);\n\n if (options?.ghostElement?.className)\n ghostElement.current.classList.add(options?.ghostElement?.className);\n\n ghostElement.current.id = options?.ghostElement?.id || \"\";\n ghostElement.current.innerText = inputRef.current.value ?? \"\";\n\n if (options?.minWidth) inputRef.current.style.minWidth = options?.minWidth;\n if (options?.maxWidth) inputRef.current.style.maxWidth = options?.maxWidth;\n\n applyFontStyles(styles, ghostElement.current);\n\n // Here I allow you to mess up the styles of the hidden element\n if (options?.ghostElement?.styles)\n // NOTE: this will overwrite anything from the previus `applyFontStyles`\n applyStyles(options?.ghostElement?.styles, ghostElement.current);\n\n syncWidthToState(inputRef, ghostElement);\n\n inputRef.current.addEventListener(\"input\", handleInput);\n };\n\n useEffect(\n () => {\n mountBehaviour();\n return () => destroy();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const callbackRef = useCallback(\n (element: HTMLInputElement | null) => {\n inputRef.current = element;\n\n if (!element) destroy();\n else if (element && inputRef.current) {\n mountBehaviour();\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [inputRef]\n );\n\n return {\n width,\n callbackRef,\n ref: inputRef,\n };\n}\n","import type { RefObject } from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\n\nexport const applyFontStyles = (\n styles: CSSStyleDeclaration,\n target: HTMLElement\n) => {\n target.style.fontFamily = styles.fontFamily;\n target.style.fontSize = styles.fontSize;\n target.style.letterSpacing = styles.letterSpacing;\n target.style.fontWeight = styles.fontWeight;\n};\n\nexport const applyStyles = (\n styles: Partial<CSSStyleDeclaration>,\n target: HTMLElement\n) => {\n Object.keys(styles).forEach((styleAttr: string) => {\n const key = styleAttr as keyof CSSStyleDeclaration;\n\n const value = styles[key];\n\n if (typeof value === \"string\" && typeof key === \"string\") {\n target.style.setProperty(key, value);\n }\n });\n};\n\nexport const createGhostElement = (options?: AutWidthInputOptions) => {\n const tempElement = document.createElement(\"p\");\n\n if (options?.minWidth) {\n tempElement.style.minWidth = options?.minWidth;\n }\n\n Object.assign(tempElement.style, {\n position: \"absolute\",\n whiteSpace: \"pre\",\n top: \"0\",\n left: \"0\",\n visibility: \"hidden\",\n height: \"0\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n zIndex: -1000,\n margin: \"0\", // Reset margin to avoid layout interference\n });\n\n tempElement.innerText = \"\";\n tempElement.setAttribute(\"class\", \"ghost-paragraph-element\");\n\n return document.body.appendChild(tempElement);\n};\n\nexport const syncWidth = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n) => {\n if (inputRef.current) {\n inputRef.current.style.width = `${\n ghostElement.current?.getBoundingClientRect()?.width ?? 0\n }px`;\n return inputRef.current.style.width;\n }\n\n return null;\n};\n"],"mappings":"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","names":["inputRef","ghostElement"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/use-auto-width-input.ts","../src/helpers.ts"],"sourcesContent":["export * from \"./use-auto-width-input\";\n\nexport * from \"./types\";\n","import { useCallback, useEffect, useRef, type RefObject } from \"react\";\nimport type { AutWidthInputOptions, UseAutoWidthInputReturn } from \"./types\";\nimport {\n applyFontStyles,\n applyStyles,\n createGhostElement,\n syncWidth,\n} from \"./helpers\";\n\nexport function useAutoWidthInput(\n inputRef?: RefObject<HTMLInputElement | null>,\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n inputRefOrOptions?: RefObject<HTMLInputElement | null> | AutWidthInputOptions,\n opts?: AutWidthInputOptions\n): UseAutoWidthInputReturn {\n // NOTE: Removed the width state because it inserts a race condition in chrome with the onChange event and setText\n // const [width, setWidth] = useState(options?.minWidth ?? 0);\n const isRefObject =\n typeof inputRefOrOptions === \"object\" && \"current\" in inputRefOrOptions;\n\n const ghostElement = useRef<HTMLElement>(null);\n const internalInpuRef = useRef<HTMLInputElement>(null);\n\n const inputRef = isRefObject ? inputRefOrOptions : internalInpuRef;\n const options: AutWidthInputOptions | undefined = isRefObject\n ? opts\n : inputRefOrOptions;\n\n const input = inputRef.current;\n\n const handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n\n if (ghostElement.current) {\n ghostElement.current.innerText = target.value;\n\n syncWidth(inputRef, ghostElement);\n }\n };\n\n const destroy = () => {\n input?.removeEventListener(\"input\", handleInput);\n ghostElement.current?.remove();\n ghostElement.current = null;\n };\n\n const mountBehaviour = () => {\n if (!inputRef.current) return;\n\n // Doesnt make sense to mount an element if the element already exist\n if (ghostElement.current) return;\n\n const styles = window.getComputedStyle(inputRef.current);\n ghostElement.current = createGhostElement(options);\n\n if (options?.ghostElement?.className)\n ghostElement.current.classList.add(options?.ghostElement?.className);\n\n ghostElement.current.id = options?.ghostElement?.id || \"\";\n // Ensure we capture the current value at mount time\n ghostElement.current.innerText = inputRef.current.value ?? \"\";\n\n if (options?.minWidth) inputRef.current.style.minWidth = options?.minWidth;\n if (options?.maxWidth) inputRef.current.style.maxWidth = options?.maxWidth;\n\n applyFontStyles(styles, ghostElement.current);\n\n // Here I allow you to mess up the styles of the hidden element\n if (options?.ghostElement?.styles)\n // NOTE: this will overwrite anything from the previus `applyFontStyles`\n applyStyles(options?.ghostElement?.styles, ghostElement.current);\n\n syncWidth(inputRef, ghostElement);\n\n inputRef.current.addEventListener(\"input\", handleInput);\n };\n\n useEffect(\n () => {\n mountBehaviour();\n return () => destroy();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const callbackRef = useCallback(\n (element: HTMLInputElement | null) => {\n inputRef.current = element;\n\n if (!element) destroy();\n else if (element && inputRef.current) {\n mountBehaviour();\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [inputRef]\n );\n\n return {\n callbackRef,\n ref: inputRef,\n };\n}\n","import type { RefObject } from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\n\nexport const applyFontStyles = (\n styles: CSSStyleDeclaration,\n target: HTMLElement\n) => {\n target.style.fontFamily = styles.fontFamily;\n target.style.fontSize = styles.fontSize;\n target.style.letterSpacing = styles.letterSpacing;\n target.style.fontWeight = styles.fontWeight;\n};\n\nexport const applyStyles = (\n styles: Partial<CSSStyleDeclaration>,\n target: HTMLElement\n) => {\n Object.keys(styles).forEach((styleAttr: string) => {\n const key = styleAttr as keyof CSSStyleDeclaration;\n\n const value = styles[key];\n\n if (typeof value === \"string\" && typeof key === \"string\") {\n // target.style.setProperty(key, value);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (target.style as any)[key] = value;\n }\n });\n};\n\nexport const createGhostElement = (options?: AutWidthInputOptions) => {\n const tempElement = document.createElement(\"p\");\n\n if (options?.minWidth) {\n tempElement.style.minWidth = options?.minWidth;\n }\n\n Object.assign(tempElement.style, {\n position: \"absolute\",\n whiteSpace: \"pre\",\n top: \"0\",\n left: \"0\",\n visibility: \"hidden\",\n height: \"0\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n zIndex: -1000,\n margin: \"0\", // Reset margin to avoid layout interference\n });\n\n tempElement.innerText = \"\";\n tempElement.setAttribute(\"class\", \"ghost-paragraph-element\");\n\n return document.body.appendChild(tempElement);\n};\n\nexport const syncWidth = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n) => {\n if (inputRef.current) {\n inputRef.current.style.width = `${\n ghostElement.current?.getBoundingClientRect()?.width ?? 0\n }px`;\n return inputRef.current.style.width;\n }\n\n return null;\n};\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -9,12 +9,12 @@ type AutWidthInputOptions = {
9
9
  styles?: Partial<CSSStyleDeclaration>;
10
10
  };
11
11
  };
12
-
13
12
  type UseAutoWidthInputReturn = {
14
- width: string | number;
15
13
  callbackRef: (element: HTMLInputElement | null) => void;
16
14
  ref: RefObject<HTMLInputElement | null>;
17
15
  };
18
- declare function useAutoWidthInput(inputRef: RefObject<HTMLInputElement | null>, options?: AutWidthInputOptions): UseAutoWidthInputReturn;
19
16
 
20
- export { type AutWidthInputOptions, useAutoWidthInput };
17
+ declare function useAutoWidthInput(inputRef?: RefObject<HTMLInputElement | null>, options?: AutWidthInputOptions): UseAutoWidthInputReturn;
18
+ declare function useAutoWidthInput(options?: AutWidthInputOptions): UseAutoWidthInputReturn;
19
+
20
+ export { type AutWidthInputOptions, type UseAutoWidthInputReturn, useAutoWidthInput };
package/dist/index.d.ts CHANGED
@@ -9,12 +9,12 @@ type AutWidthInputOptions = {
9
9
  styles?: Partial<CSSStyleDeclaration>;
10
10
  };
11
11
  };
12
-
13
12
  type UseAutoWidthInputReturn = {
14
- width: string | number;
15
13
  callbackRef: (element: HTMLInputElement | null) => void;
16
14
  ref: RefObject<HTMLInputElement | null>;
17
15
  };
18
- declare function useAutoWidthInput(inputRef: RefObject<HTMLInputElement | null>, options?: AutWidthInputOptions): UseAutoWidthInputReturn;
19
16
 
20
- export { type AutWidthInputOptions, useAutoWidthInput };
17
+ declare function useAutoWidthInput(inputRef?: RefObject<HTMLInputElement | null>, options?: AutWidthInputOptions): UseAutoWidthInputReturn;
18
+ declare function useAutoWidthInput(options?: AutWidthInputOptions): UseAutoWidthInputReturn;
19
+
20
+ export { type AutWidthInputOptions, type UseAutoWidthInputReturn, useAutoWidthInput };
package/dist/index.js CHANGED
@@ -1,10 +1,5 @@
1
1
  // src/use-auto-width-input.ts
2
- import {
3
- useCallback,
4
- useEffect,
5
- useRef,
6
- useState
7
- } from "react";
2
+ import { useCallback, useEffect, useRef } from "react";
8
3
 
9
4
  // src/helpers.ts
10
5
  var applyFontStyles = (styles, target) => {
@@ -18,7 +13,7 @@ var applyStyles = (styles, target) => {
18
13
  const key = styleAttr;
19
14
  const value = styles[key];
20
15
  if (typeof value === "string" && typeof key === "string") {
21
- target.style.setProperty(key, value);
16
+ target.style[key] = value;
22
17
  }
23
18
  });
24
19
  };
@@ -53,19 +48,18 @@ var syncWidth = (inputRef, ghostElement) => {
53
48
  };
54
49
 
55
50
  // src/use-auto-width-input.ts
56
- function useAutoWidthInput(inputRef, options) {
57
- const [width, setWidth] = useState(options?.minWidth ?? 0);
51
+ function useAutoWidthInput(inputRefOrOptions, opts) {
52
+ const isRefObject = typeof inputRefOrOptions === "object" && "current" in inputRefOrOptions;
58
53
  const ghostElement = useRef(null);
54
+ const internalInpuRef = useRef(null);
55
+ const inputRef = isRefObject ? inputRefOrOptions : internalInpuRef;
56
+ const options = isRefObject ? opts : inputRefOrOptions;
59
57
  const input = inputRef.current;
60
- const syncWidthToState = (inputRef2, ghostElement2) => {
61
- const currentWidth = syncWidth(inputRef2, ghostElement2);
62
- if (currentWidth) setWidth(currentWidth);
63
- };
64
58
  const handleInput = (event) => {
65
59
  const target = event.target;
66
60
  if (ghostElement.current) {
67
61
  ghostElement.current.innerText = target.value;
68
- syncWidthToState(inputRef, ghostElement);
62
+ syncWidth(inputRef, ghostElement);
69
63
  }
70
64
  };
71
65
  const destroy = () => {
@@ -87,7 +81,7 @@ function useAutoWidthInput(inputRef, options) {
87
81
  applyFontStyles(styles, ghostElement.current);
88
82
  if (options?.ghostElement?.styles)
89
83
  applyStyles(options?.ghostElement?.styles, ghostElement.current);
90
- syncWidthToState(inputRef, ghostElement);
84
+ syncWidth(inputRef, ghostElement);
91
85
  inputRef.current.addEventListener("input", handleInput);
92
86
  };
93
87
  useEffect(
@@ -110,7 +104,6 @@ function useAutoWidthInput(inputRef, options) {
110
104
  [inputRef]
111
105
  );
112
106
  return {
113
- width,
114
107
  callbackRef,
115
108
  ref: inputRef
116
109
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/use-auto-width-input.ts","../src/helpers.ts"],"sourcesContent":["import {\n useCallback,\n useEffect,\n useRef,\n useState,\n type RefObject,\n} from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\nimport {\n applyFontStyles,\n applyStyles,\n createGhostElement,\n syncWidth,\n} from \"./helpers\";\n\ntype UseAutoWidthInputReturn = {\n width: string | number;\n callbackRef: (element: HTMLInputElement | null) => void;\n ref: RefObject<HTMLInputElement | null>;\n};\n\n// export function useAutoWidthInput(\n// inputRef: RefObject<HTMLInputElement | null>,\n// options?: AutWidthInputOptions\n// ): UseAutoWidthInputReturn;\n\n// export function useAutoWidthInput(\n// options?: AutWidthInputOptions\n// ): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n inputRef: RefObject<HTMLInputElement | null>,\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn {\n const [width, setWidth] = useState(options?.minWidth ?? 0);\n const ghostElement = useRef<HTMLElement>(null);\n const input = inputRef.current;\n\n const syncWidthToState = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n ) => {\n const currentWidth = syncWidth(inputRef, ghostElement);\n if (currentWidth) setWidth(currentWidth);\n };\n\n const handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n\n if (ghostElement.current) {\n ghostElement.current.innerText = target.value;\n\n syncWidthToState(inputRef, ghostElement);\n }\n };\n\n const destroy = () => {\n input?.removeEventListener(\"input\", handleInput);\n ghostElement.current?.remove();\n ghostElement.current = null;\n };\n\n const mountBehaviour = () => {\n if (!inputRef.current) return;\n\n // Doesnt make sense to mount an element if the element already exist\n if (ghostElement.current) return;\n\n const styles = window.getComputedStyle(inputRef.current);\n ghostElement.current = createGhostElement(options);\n\n if (options?.ghostElement?.className)\n ghostElement.current.classList.add(options?.ghostElement?.className);\n\n ghostElement.current.id = options?.ghostElement?.id || \"\";\n ghostElement.current.innerText = inputRef.current.value ?? \"\";\n\n if (options?.minWidth) inputRef.current.style.minWidth = options?.minWidth;\n if (options?.maxWidth) inputRef.current.style.maxWidth = options?.maxWidth;\n\n applyFontStyles(styles, ghostElement.current);\n\n // Here I allow you to mess up the styles of the hidden element\n if (options?.ghostElement?.styles)\n // NOTE: this will overwrite anything from the previus `applyFontStyles`\n applyStyles(options?.ghostElement?.styles, ghostElement.current);\n\n syncWidthToState(inputRef, ghostElement);\n\n inputRef.current.addEventListener(\"input\", handleInput);\n };\n\n useEffect(\n () => {\n mountBehaviour();\n return () => destroy();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const callbackRef = useCallback(\n (element: HTMLInputElement | null) => {\n inputRef.current = element;\n\n if (!element) destroy();\n else if (element && inputRef.current) {\n mountBehaviour();\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [inputRef]\n );\n\n return {\n width,\n callbackRef,\n ref: inputRef,\n };\n}\n","import type { RefObject } from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\n\nexport const applyFontStyles = (\n styles: CSSStyleDeclaration,\n target: HTMLElement\n) => {\n target.style.fontFamily = styles.fontFamily;\n target.style.fontSize = styles.fontSize;\n target.style.letterSpacing = styles.letterSpacing;\n target.style.fontWeight = styles.fontWeight;\n};\n\nexport const applyStyles = (\n styles: Partial<CSSStyleDeclaration>,\n target: HTMLElement\n) => {\n Object.keys(styles).forEach((styleAttr: string) => {\n const key = styleAttr as keyof CSSStyleDeclaration;\n\n const value = styles[key];\n\n if (typeof value === \"string\" && typeof key === \"string\") {\n target.style.setProperty(key, value);\n }\n });\n};\n\nexport const createGhostElement = (options?: AutWidthInputOptions) => {\n const tempElement = document.createElement(\"p\");\n\n if (options?.minWidth) {\n tempElement.style.minWidth = options?.minWidth;\n }\n\n Object.assign(tempElement.style, {\n position: \"absolute\",\n whiteSpace: \"pre\",\n top: \"0\",\n left: \"0\",\n visibility: \"hidden\",\n height: \"0\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n zIndex: -1000,\n margin: \"0\", // Reset margin to avoid layout interference\n });\n\n tempElement.innerText = \"\";\n tempElement.setAttribute(\"class\", \"ghost-paragraph-element\");\n\n return document.body.appendChild(tempElement);\n};\n\nexport const syncWidth = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n) => {\n if (inputRef.current) {\n inputRef.current.style.width = `${\n ghostElement.current?.getBoundingClientRect()?.width ?? 0\n }px`;\n return inputRef.current.style.width;\n }\n\n return null;\n};\n"],"mappings":"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","names":["inputRef","ghostElement"]}
1
+ {"version":3,"sources":["../src/use-auto-width-input.ts","../src/helpers.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, type RefObject } from \"react\";\nimport type { AutWidthInputOptions, UseAutoWidthInputReturn } from \"./types\";\nimport {\n applyFontStyles,\n applyStyles,\n createGhostElement,\n syncWidth,\n} from \"./helpers\";\n\nexport function useAutoWidthInput(\n inputRef?: RefObject<HTMLInputElement | null>,\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n options?: AutWidthInputOptions\n): UseAutoWidthInputReturn;\n\nexport function useAutoWidthInput(\n inputRefOrOptions?: RefObject<HTMLInputElement | null> | AutWidthInputOptions,\n opts?: AutWidthInputOptions\n): UseAutoWidthInputReturn {\n // NOTE: Removed the width state because it inserts a race condition in chrome with the onChange event and setText\n // const [width, setWidth] = useState(options?.minWidth ?? 0);\n const isRefObject =\n typeof inputRefOrOptions === \"object\" && \"current\" in inputRefOrOptions;\n\n const ghostElement = useRef<HTMLElement>(null);\n const internalInpuRef = useRef<HTMLInputElement>(null);\n\n const inputRef = isRefObject ? inputRefOrOptions : internalInpuRef;\n const options: AutWidthInputOptions | undefined = isRefObject\n ? opts\n : inputRefOrOptions;\n\n const input = inputRef.current;\n\n const handleInput = (event: Event) => {\n const target = event.target as HTMLInputElement;\n\n if (ghostElement.current) {\n ghostElement.current.innerText = target.value;\n\n syncWidth(inputRef, ghostElement);\n }\n };\n\n const destroy = () => {\n input?.removeEventListener(\"input\", handleInput);\n ghostElement.current?.remove();\n ghostElement.current = null;\n };\n\n const mountBehaviour = () => {\n if (!inputRef.current) return;\n\n // Doesnt make sense to mount an element if the element already exist\n if (ghostElement.current) return;\n\n const styles = window.getComputedStyle(inputRef.current);\n ghostElement.current = createGhostElement(options);\n\n if (options?.ghostElement?.className)\n ghostElement.current.classList.add(options?.ghostElement?.className);\n\n ghostElement.current.id = options?.ghostElement?.id || \"\";\n // Ensure we capture the current value at mount time\n ghostElement.current.innerText = inputRef.current.value ?? \"\";\n\n if (options?.minWidth) inputRef.current.style.minWidth = options?.minWidth;\n if (options?.maxWidth) inputRef.current.style.maxWidth = options?.maxWidth;\n\n applyFontStyles(styles, ghostElement.current);\n\n // Here I allow you to mess up the styles of the hidden element\n if (options?.ghostElement?.styles)\n // NOTE: this will overwrite anything from the previus `applyFontStyles`\n applyStyles(options?.ghostElement?.styles, ghostElement.current);\n\n syncWidth(inputRef, ghostElement);\n\n inputRef.current.addEventListener(\"input\", handleInput);\n };\n\n useEffect(\n () => {\n mountBehaviour();\n return () => destroy();\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n []\n );\n\n const callbackRef = useCallback(\n (element: HTMLInputElement | null) => {\n inputRef.current = element;\n\n if (!element) destroy();\n else if (element && inputRef.current) {\n mountBehaviour();\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [inputRef]\n );\n\n return {\n callbackRef,\n ref: inputRef,\n };\n}\n","import type { RefObject } from \"react\";\nimport type { AutWidthInputOptions } from \"./types\";\n\nexport const applyFontStyles = (\n styles: CSSStyleDeclaration,\n target: HTMLElement\n) => {\n target.style.fontFamily = styles.fontFamily;\n target.style.fontSize = styles.fontSize;\n target.style.letterSpacing = styles.letterSpacing;\n target.style.fontWeight = styles.fontWeight;\n};\n\nexport const applyStyles = (\n styles: Partial<CSSStyleDeclaration>,\n target: HTMLElement\n) => {\n Object.keys(styles).forEach((styleAttr: string) => {\n const key = styleAttr as keyof CSSStyleDeclaration;\n\n const value = styles[key];\n\n if (typeof value === \"string\" && typeof key === \"string\") {\n // target.style.setProperty(key, value);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (target.style as any)[key] = value;\n }\n });\n};\n\nexport const createGhostElement = (options?: AutWidthInputOptions) => {\n const tempElement = document.createElement(\"p\");\n\n if (options?.minWidth) {\n tempElement.style.minWidth = options?.minWidth;\n }\n\n Object.assign(tempElement.style, {\n position: \"absolute\",\n whiteSpace: \"pre\",\n top: \"0\",\n left: \"0\",\n visibility: \"hidden\",\n height: \"0\",\n overflow: \"hidden\",\n pointerEvents: \"none\",\n zIndex: -1000,\n margin: \"0\", // Reset margin to avoid layout interference\n });\n\n tempElement.innerText = \"\";\n tempElement.setAttribute(\"class\", \"ghost-paragraph-element\");\n\n return document.body.appendChild(tempElement);\n};\n\nexport const syncWidth = (\n inputRef: RefObject<HTMLInputElement | null>,\n ghostElement: RefObject<HTMLElement | null>\n) => {\n if (inputRef.current) {\n inputRef.current.style.width = `${\n ghostElement.current?.getBoundingClientRect()?.width ?? 0\n }px`;\n return inputRef.current.style.width;\n }\n\n return null;\n};\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "use-auto-width-input",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "description": "A React hook to automatically resize an input based on its content",
5
5
  "author": "Luis Vanin",
6
6
  "module": "./dist/index.js",
@@ -20,25 +20,36 @@
20
20
  "lint": "bun eslint",
21
21
  "build": "tsup",
22
22
  "prepare": "husky",
23
+ "test": "vitest --config ./vite.config.ts",
23
24
  "prepublishOnly": "bun run build"
24
25
  },
26
+ "dependencies": {},
27
+ "peerDependencies": {
28
+ "typescript": "^5.9.3",
29
+ "react": "^19.2.3",
30
+ "react-dom": "^19.2.3"
31
+ },
25
32
  "devDependencies": {
33
+ "@testing-library/dom": "^10.4.1",
34
+ "@testing-library/jest-dom": "^6.9.1",
35
+ "@testing-library/react": "^16.3.1",
36
+ "@testing-library/user-event": "^14.6.1",
26
37
  "@types/bun": "latest",
27
38
  "@types/react": "^19.2.7",
28
39
  "@types/react-dom": "^19.2.3",
40
+ "@vitejs/plugin-react": "^5.1.1",
29
41
  "eslint": "^9.39.2",
30
42
  "eslint-plugin-react": "^7.37.5",
31
43
  "eslint-plugin-react-hooks": "^7.0.1",
32
44
  "globals": "^16.5.0",
33
45
  "husky": "^9.1.7",
46
+ "jsdom": "^27.3.0",
34
47
  "react": "^19.2.3",
35
48
  "react-dom": "^19.2.3",
36
49
  "tsup": "^8.5.1",
37
- "typescript-eslint": "^8.49.0"
38
- },
39
- "peerDependencies": {
40
- "typescript": "^5.9.3",
41
- "react": "^19.2.3",
42
- "react-dom": "^19.2.3"
50
+ "typescript-eslint": "^8.49.0",
51
+ "unplugin-auto-import": "^20.3.0",
52
+ "vite": "^7.3.0",
53
+ "vitest": "^4.0.16"
43
54
  }
44
55
  }