numora 0.0.0 → 1.0.1

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
@@ -2,12 +2,7 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/numora.svg)](https://www.npmjs.com/package/numora)
4
4
 
5
- A lightweight, framework-agnostic numeric input library for handling currency and decimal inputs in **financial/DeFi** applications. Built with TypeScript and designed for modern web applications with:
6
-
7
- - **Zero dependencies** - minimal footprint for your bundle
8
- - **Type safety** - fully typed API for better developer experience
9
- - **Framework agnostic** - use with any framework or vanilla JavaScript
10
- - **Customizable** - extensive options to fit your specific needs
5
+ A lightweight, framework-agnostic numeric input library for handling currency and decimal inputs in **financial/DeFi** applications. Built with TypeScript with **zero-dependencies**.
11
6
 
12
7
  ## Features
13
8
 
@@ -61,8 +56,8 @@ The NumericInput constructor accepts the following options:
61
56
 
62
57
  Numora is also available for popular frameworks:
63
58
 
64
- - React: `numora-react` (in progress)
65
- - Vue: `numora-vue` (in progress)
59
+ - React: `numora-react`
60
+ - Vue: `numora-vue`
66
61
  - Svelte: `numora`
67
62
 
68
63
  ## License
@@ -0,0 +1,21 @@
1
+ interface NumericInputOptions extends Partial<HTMLInputElement> {
2
+ maxDecimals?: number;
3
+ onChange?: (value: string) => void;
4
+ }
5
+ export declare class NumericInput {
6
+ private element;
7
+ private options;
8
+ constructor(container: HTMLElement, { maxDecimals, onChange, ...rest }: NumericInputOptions);
9
+ private createInputElement;
10
+ private setupEventListeners;
11
+ private handleChange;
12
+ private handleKeyDown;
13
+ private handlePaste;
14
+ getValue(): string;
15
+ setValue(value: string): void;
16
+ disable(): void;
17
+ enable(): void;
18
+ addEventListener(event: string, callback: EventListenerOrEventListenerObject): void;
19
+ removeEventListener(event: string, callback: EventListenerOrEventListenerObject): void;
20
+ }
21
+ export {};
@@ -0,0 +1 @@
1
+ export * from './NumericInput';
package/dist/index.mjs ADDED
@@ -0,0 +1,73 @@
1
+ var E = Object.defineProperty;
2
+ var b = (t, e, n) => e in t ? E(t, e, { enumerable: !0, configurable: !0, writable: !0, value: n }) : t[e] = n;
3
+ var l = (t, e, n) => b(t, typeof e != "symbol" ? e + "" : e, n);
4
+ const C = (t) => t.replace(/[^0-9.]/g, ""), D = (t) => t.replace(/(\..*?)\./g, "$1"), p = (t) => D(C(t)), L = (t) => t.replace(/,/g, "."), f = (t) => [".", ","].some(
5
+ (n) => t.key === n && t.target && t.target.value.includes(".")
6
+ ), o = (t, e) => {
7
+ const [n, s] = t.split(".");
8
+ return s ? `${n}.${s.slice(0, e)}` : t;
9
+ };
10
+ function A(t, e) {
11
+ const n = t.target;
12
+ n.value = L(n.value), n.value = p(n.value), n.value = o(n.value, e);
13
+ }
14
+ function I(t) {
15
+ f(t) && t.preventDefault();
16
+ }
17
+ function x(t, e) {
18
+ var m;
19
+ const n = t.target, { value: s, selectionStart: i, selectionEnd: g } = n, r = p(((m = t.clipboardData) == null ? void 0 : m.getData("text/plain")) || ""), h = s.slice(0, i || 0) + r + s.slice(g || 0), [v, ...c] = h.split("."), a = v + (c.length > 0 ? "." + c.join("") : "");
20
+ t.preventDefault(), n.value = o(a, e);
21
+ const u = (i || 0) + r.length - (h.length - a.length);
22
+ return n.setSelectionRange(u, u), o(a, e);
23
+ }
24
+ const d = 2;
25
+ class N {
26
+ constructor(e, { maxDecimals: n = d, onChange: s, ...i }) {
27
+ l(this, "element");
28
+ l(this, "options");
29
+ this.options = {
30
+ maxDecimals: n,
31
+ onChange: s,
32
+ ...i
33
+ }, this.createInputElement(e), this.setupEventListeners();
34
+ }
35
+ createInputElement(e) {
36
+ this.element = document.createElement("input"), this.element.setAttribute("minlength", "1"), this.element.setAttribute("pattern", "^[0-9]*[.,]?[0-9]*$"), this.element.setAttribute("spellcheck", "false"), this.element.setAttribute("type", "text"), this.element.setAttribute("inputmode", "decimal");
37
+ const { maxDecimals: n, onChange: s, ...i } = this.options;
38
+ Object.assign(this.element, i), e.appendChild(this.element);
39
+ }
40
+ setupEventListeners() {
41
+ this.element.addEventListener("input", this.handleChange.bind(this)), this.element.addEventListener("keydown", this.handleKeyDown.bind(this)), this.element.addEventListener("paste", this.handlePaste.bind(this));
42
+ }
43
+ handleChange(e) {
44
+ A(e, this.options.maxDecimals || d), this.options.onChange && this.options.onChange(e.target.value);
45
+ }
46
+ handleKeyDown(e) {
47
+ I(e);
48
+ }
49
+ handlePaste(e) {
50
+ x(e, this.options.maxDecimals), this.options.onChange && this.options.onChange(e.target.value);
51
+ }
52
+ getValue() {
53
+ return this.element.value;
54
+ }
55
+ setValue(e) {
56
+ this.element.value = e;
57
+ }
58
+ disable() {
59
+ this.element.disabled = !0;
60
+ }
61
+ enable() {
62
+ this.element.disabled = !1;
63
+ }
64
+ addEventListener(e, n) {
65
+ this.element.addEventListener(e, n);
66
+ }
67
+ removeEventListener(e, n) {
68
+ this.element.removeEventListener(e, n);
69
+ }
70
+ }
71
+ export {
72
+ N as NumericInput
73
+ };
@@ -0,0 +1,13 @@
1
+ export declare const replaceCommasWithDots: (value: string) => string;
2
+ /**
3
+ * Checks if the input already has a decimal point and prevents the user from entering another one.
4
+ */
5
+ export declare const alreadyHasDecimal: (e: KeyboardEvent) => boolean;
6
+ /**
7
+ * Trims a string representation of a number to a maximum number of decimal places.
8
+ *
9
+ * @param value - The string to trim.
10
+ * @param maxDecimals - The maximum number of decimal places to allow.
11
+ * @returns The trimmed string.
12
+ */
13
+ export declare const trimToMaxDecimals: (value: string, maxDecimals: number) => string;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Handles the input change event to ensure the value does not exceed the maximum number of decimal places,
3
+ * replaces commas with dots, and removes invalid non-numeric characters.
4
+ *
5
+ * @param e - The event triggered by the input.
6
+ * @param maxDecimals - The maximum number of decimal places allowed.
7
+ */
8
+ export declare function handleOnChangeNumericInput(e: Event, maxDecimals: number): void;
9
+ /**
10
+ * Handles the keydown event to prevent the user from entering a second decimal point.
11
+ *
12
+ * @param e - The keyboard event triggered by the input.
13
+ */
14
+ export declare function handleOnKeyDownNumericInput(e: KeyboardEvent): void;
15
+ /**
16
+ * Handles the paste event to ensure the value does not exceed the maximum number of decimal places,
17
+ * replaces commas with dots, and removes invalid non-numeric characters.
18
+ *
19
+ * @param e - The clipboard event triggered by the input.
20
+ * @param maxDecimals - The maximum number of decimal places allowed.
21
+ * @returns The sanitized value after the paste event.
22
+ */
23
+ export declare function handleOnPasteNumericInput(e: ClipboardEvent, maxDecimals: number): string;
@@ -0,0 +1 @@
1
+ export declare const sanitizeNumericInput: (value: string) => string;
package/package.json CHANGED
@@ -1,9 +1,63 @@
1
1
  {
2
2
  "name": "numora",
3
- "version": "0.0.0",
4
- "description": "Monorepo for Numora and its framework adapters",
5
- "keywords": [],
6
- "author": "Kacper Szarkiewicz <contact@sharqiewicz.com>",
3
+ "version": "1.0.1",
4
+ "description": "Framework-agnostic headless finance input library",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/Sharqiewicz/numora"
19
+ },
20
+ "keywords": [
21
+ "numeric input",
22
+ "currency input",
23
+ "input",
24
+ "form",
25
+ "form input",
26
+ "form currency input",
27
+ "form numeric input",
28
+ "input library",
29
+ "input component",
30
+ "input field",
31
+ "input form",
32
+ "input form field",
33
+ "input form field currency",
34
+ "input form field numeric",
35
+ "financial input",
36
+ "financial input component",
37
+ "financial input field",
38
+ "financial input form",
39
+ "financial input form field",
40
+ "financial input form field currency",
41
+ "financial input form field numeric"
42
+ ],
43
+ "authors": [
44
+ {
45
+ "name": "Kacper Szarkiewicz",
46
+ "email": "contact@sharqiewicz.com",
47
+ "url": "https://sharqiewicz.com"
48
+ }
49
+ ],
7
50
  "license": "MIT",
8
- "packageManager": "pnpm@9.13.2+sha512.88c9c3864450350e65a33587ab801acf946d7c814ed1134da4a924f6df5a2120fd36b46aab68f7cd1d413149112d53c7db3a4136624cfd00ff1846a0c6cef48a"
9
- }
51
+ "devDependencies": {
52
+ "@types/node": "^22.13.11",
53
+ "jsdom": "^26.0.0",
54
+ "typescript": "^5.8.2",
55
+ "vite": "^6.2.2",
56
+ "vitest": "^3.0.9"
57
+ },
58
+ "scripts": {
59
+ "build": "vite build && tsc --emitDeclarationOnly",
60
+ "test": "vitest run",
61
+ "dev": "vite build --watch"
62
+ }
63
+ }
@@ -1,6 +0,0 @@
1
- # Package Managers
2
- package-lock.json
3
- pnpm-lock.yaml
4
- yarn.lock
5
- bun.lock
6
- bun.lockb
@@ -1,37 +0,0 @@
1
- import prettier from 'eslint-config-prettier';
2
- import js from '@eslint/js';
3
- import { includeIgnoreFile } from '@eslint/compat';
4
- import svelte from 'eslint-plugin-svelte';
5
- import globals from 'globals';
6
- import { fileURLToPath } from 'node:url';
7
- import ts from 'typescript-eslint';
8
- import svelteConfig from './svelte.config.js';
9
-
10
- const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url));
11
-
12
- export default ts.config(
13
- includeIgnoreFile(gitignorePath),
14
- js.configs.recommended,
15
- ...ts.configs.recommended,
16
- ...svelte.configs.recommended,
17
- prettier,
18
- ...svelte.configs.prettier,
19
- {
20
- languageOptions: {
21
- globals: { ...globals.browser, ...globals.node }
22
- },
23
- rules: { 'no-undef': 'off' }
24
- },
25
- {
26
- files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'],
27
- ignores: ['eslint.config.js', 'svelte.config.js'],
28
- languageOptions: {
29
- parserOptions: {
30
- projectService: true,
31
- extraFileExtensions: ['.svelte'],
32
- parser: ts.parser,
33
- svelteConfig
34
- }
35
- }
36
- }
37
- );
package/docs/package.json DELETED
@@ -1,42 +0,0 @@
1
- {
2
- "name": "numora-docs",
3
- "private": true,
4
- "version": "0.0.1",
5
- "type": "module",
6
- "scripts": {
7
- "dev": "vite dev",
8
- "build": "vite build",
9
- "preview": "vite preview",
10
- "prepare": "svelte-kit sync || echo ''",
11
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
- "format": "prettier --write .",
14
- "lint": "prettier --check . && eslint ."
15
- },
16
- "devDependencies": {
17
- "@eslint/compat": "^1.2.5",
18
- "@eslint/js": "^9.18.0",
19
- "@sveltejs/adapter-auto": "^4.0.0",
20
- "@sveltejs/kit": "^2.16.0",
21
- "@sveltejs/vite-plugin-svelte": "^5.0.0",
22
- "@tailwindcss/vite": "^4.0.0",
23
- "eslint": "^9.18.0",
24
- "eslint-config-prettier": "^10.0.1",
25
- "eslint-plugin-svelte": "^3.0.0",
26
- "globals": "^16.0.0",
27
- "prettier": "^3.4.2",
28
- "prettier-plugin-svelte": "^3.3.3",
29
- "prettier-plugin-tailwindcss": "^0.6.11",
30
- "svelte": "^5.0.0",
31
- "svelte-check": "^4.0.0",
32
- "tailwindcss": "^4.0.0",
33
- "typescript": "^5.0.0",
34
- "typescript-eslint": "^8.20.0",
35
- "vite": "^6.0.0"
36
- },
37
- "pnpm": {
38
- "onlyBuiltDependencies": [
39
- "esbuild"
40
- ]
41
- }
42
- }
package/docs/src/app.css DELETED
@@ -1 +0,0 @@
1
- @import 'tailwindcss';
package/docs/src/app.d.ts DELETED
@@ -1,13 +0,0 @@
1
- // See https://svelte.dev/docs/kit/types#app.d.ts
2
- // for information about these interfaces
3
- declare global {
4
- namespace App {
5
- // interface Error {}
6
- // interface Locals {}
7
- // interface PageData {}
8
- // interface PageState {}
9
- // interface Platform {}
10
- }
11
- }
12
-
13
- export {};
package/docs/src/app.html DELETED
@@ -1,12 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <link rel="icon" href="%sveltekit.assets%/favicon.png" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1" />
7
- %sveltekit.head%
8
- </head>
9
- <body data-sveltekit-preload-data="hover">
10
- <div style="display: contents">%sveltekit.body%</div>
11
- </body>
12
- </html>
@@ -1 +0,0 @@
1
- // place files you want to import through the `$lib` alias in this folder.
@@ -1,7 +0,0 @@
1
- <script lang="ts">
2
- import '../app.css';
3
-
4
- let { children } = $props();
5
- </script>
6
-
7
- {@render children()}
@@ -1,2 +0,0 @@
1
- <h1>Welcome to SvelteKit</h1>
2
- <p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
Binary file
@@ -1,18 +0,0 @@
1
- import adapter from '@sveltejs/adapter-auto';
2
- import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
3
-
4
- /** @type {import('@sveltejs/kit').Config} */
5
- const config = {
6
- // Consult https://svelte.dev/docs/kit/integrations
7
- // for more information about preprocessors
8
- preprocess: vitePreprocess(),
9
-
10
- kit: {
11
- // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
12
- // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
13
- // See https://svelte.dev/docs/kit/adapters for more information about adapters.
14
- adapter: adapter()
15
- }
16
- };
17
-
18
- export default config;
@@ -1,19 +0,0 @@
1
- {
2
- "extends": "./.svelte-kit/tsconfig.json",
3
- "compilerOptions": {
4
- "allowJs": true,
5
- "checkJs": true,
6
- "esModuleInterop": true,
7
- "forceConsistentCasingInFileNames": true,
8
- "resolveJsonModule": true,
9
- "skipLibCheck": true,
10
- "sourceMap": true,
11
- "strict": true,
12
- "moduleResolution": "bundler"
13
- }
14
- // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
15
- // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
16
- //
17
- // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
18
- // from the referenced tsconfig.json - TypeScript does not merge them in
19
- }
@@ -1,7 +0,0 @@
1
- import tailwindcss from '@tailwindcss/vite';
2
- import { sveltekit } from '@sveltejs/kit/vite';
3
- import { defineConfig } from 'vite';
4
-
5
- export default defineConfig({
6
- plugins: [tailwindcss(), sveltekit()]
7
- });
@@ -1,65 +0,0 @@
1
- # numora
2
-
3
- [![npm version](https://img.shields.io/npm/v/numora.svg)](https://www.npmjs.com/package/numora)
4
-
5
- A lightweight, framework-agnostic numeric input library for handling currency and decimal inputs in **financial/DeFi** applications. Built with TypeScript with **zero-dependencies**.
6
-
7
- ## Features
8
-
9
- - Validates and sanitizes numeric input
10
- - Limits decimal places
11
- - Handles paste events
12
- - Converts commas to dots
13
- - Prevents multiple decimal points
14
- - Customizable with various options
15
- - Framework-agnostic core with adapters for popular frameworks
16
-
17
- ## Installation
18
-
19
- ```bash
20
- npm install numora
21
- # or
22
- yarn add numora
23
- # or
24
- pnpm add numora
25
- ```
26
-
27
- ## Usage
28
-
29
- ```typescript
30
- import { NumericInput } from 'numora';
31
-
32
- // Get the container element where you want to mount the input
33
- const container = document.querySelector('#my-input-container');
34
-
35
- // Create a new NumericInput instance
36
- const numericInput = new NumericInput(container, {
37
- maxDecimals: 2,
38
- onChange: (value) => {
39
- console.log('Value changed:', value);
40
- // Do something with the value
41
- },
42
- // ... all other input properties you want
43
- });
44
- ```
45
-
46
- ## Options
47
-
48
- The NumericInput constructor accepts the following options:
49
- | Option | Type | Default | Description |
50
- | --------------- | -------- | --------- | -------------------------------------------------------- |
51
- | maxDecimals | number | 2 | Maximum number of decimal places allowed |
52
- | onChange | function | undefined | Callback function that runs when the input value changes |
53
- | supports all input properties | - | - | - |
54
-
55
- ## Framework Adapters
56
-
57
- Numora is also available for popular frameworks:
58
-
59
- - React: `numora-react`
60
- - Vue: `numora-vue`
61
- - Svelte: `numora`
62
-
63
- ## License
64
-
65
- MIT
@@ -1,63 +0,0 @@
1
- {
2
- "name": "numora",
3
- "version": "1.0.1",
4
- "description": "Framework-agnostic headless finance input library",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "files": [
8
- "dist"
9
- ],
10
- "exports": {
11
- ".": {
12
- "import": "./dist/index.js",
13
- "types": "./dist/index.d.ts"
14
- }
15
- },
16
- "repository": {
17
- "type": "git",
18
- "url": "https://github.com/Sharqiewicz/numora"
19
- },
20
- "scripts": {
21
- "build": "vite build && tsc --emitDeclarationOnly",
22
- "test": "vitest run",
23
- "dev": "vite build --watch"
24
- },
25
- "keywords": [
26
- "numeric input",
27
- "currency input",
28
- "input",
29
- "form",
30
- "form input",
31
- "form currency input",
32
- "form numeric input",
33
- "input library",
34
- "input component",
35
- "input field",
36
- "input form",
37
- "input form field",
38
- "input form field currency",
39
- "input form field numeric",
40
- "financial input",
41
- "financial input component",
42
- "financial input field",
43
- "financial input form",
44
- "financial input form field",
45
- "financial input form field currency",
46
- "financial input form field numeric"
47
- ],
48
- "authors": [
49
- {
50
- "name": "Kacper Szarkiewicz",
51
- "email": "contact@sharqiewicz.com",
52
- "url": "https://sharqiewicz.com"
53
- }
54
- ],
55
- "license": "MIT",
56
- "devDependencies": {
57
- "@types/node": "^22.13.11",
58
- "jsdom": "^26.0.0",
59
- "typescript": "^5.8.2",
60
- "vite": "^6.2.2",
61
- "vitest": "^3.0.9"
62
- }
63
- }
@@ -1,22 +0,0 @@
1
- import { defineConfig } from 'vite';
2
- import path from 'path';
3
-
4
- export default defineConfig({
5
- resolve: {
6
- alias: {
7
- '@': path.resolve(__dirname, './src'),
8
- },
9
- },
10
- build: {
11
- lib: {
12
- entry: 'src/index.ts',
13
- name: 'numora',
14
- fileName: 'index',
15
- formats: ['es'],
16
- },
17
- outDir: 'dist',
18
- },
19
- test: {
20
- environment: 'jsdom',
21
- },
22
- });
File without changes