@douglasneuroinformatics/libui 2.9.2 → 2.10.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.
@@ -1 +1 @@
1
- {"version":3,"file":"NumberFieldInput.d.ts","sourceRoot":"","sources":["../../../../src/components/Form/NumberField/NumberFieldInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAM1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAC1C,uBAAuB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CACjF,CAAC;AAEF,eAAO,MAAM,gBAAgB,6EAU1B,qBAAqB,sBA2BvB,CAAC"}
1
+ {"version":3,"file":"NumberFieldInput.d.ts","sourceRoot":"","sources":["../../../../src/components/Form/NumberField/NumberFieldInput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2B,MAAM,OAAO,CAAC;AAGhD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAM1C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAC1C,uBAAuB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,eAAe,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CACjF,CAAC;AAEF,eAAO,MAAM,gBAAgB,6EAU1B,qBAAqB,sBAqCvB,CAAC"}
@@ -1,21 +1,30 @@
1
- import React from 'react';
1
+ import React, { useRef, useState } from 'react';
2
+ import { parseNumber } from '@douglasneuroinformatics/libjs';
2
3
  import { Input } from '../../Input/Input.js';
3
4
  import { Label } from '../../Label/Label.js';
4
5
  import { FieldGroup } from '../FieldGroup/FieldGroup.js';
5
- export const NumberFieldInput = ({ description, error, label, max, min, name, readOnly, setValue, value }) => {
6
+ export const NumberFieldInput = ({ description, error, label, max = Number.MAX_SAFE_INTEGER, min = Number.MIN_SAFE_INTEGER, name, readOnly, setValue, value }) => {
7
+ const inputValueRef = useRef(value?.toString() ?? '');
8
+ const [inputKey, setInputKey] = useState(0);
6
9
  const handleChange = (event) => {
7
- const newValue = parseFloat(event.target.value);
8
- if (Number.isNaN(newValue)) {
9
- setValue(undefined);
10
+ let newValue = value;
11
+ if (/^[+-]?$/.test(event.target.value)) {
12
+ newValue = undefined;
13
+ inputValueRef.current = event.target.value;
10
14
  }
11
- else if (newValue >= (min ?? -Infinity) && newValue <= (max ?? Infinity)) {
12
- setValue(newValue);
15
+ else {
16
+ const parsedValue = parseNumber(event.target.value);
17
+ if (parsedValue >= min && parsedValue <= max) {
18
+ newValue = parsedValue;
19
+ inputValueRef.current = event.target.value;
20
+ }
13
21
  }
22
+ value === newValue ? setInputKey(inputKey + 1) : setValue(newValue);
14
23
  };
15
24
  return (React.createElement(FieldGroup, null,
16
25
  React.createElement(FieldGroup.Row, null,
17
26
  React.createElement(Label, null, label),
18
27
  React.createElement(FieldGroup.Description, { description: description })),
19
- React.createElement(Input, { disabled: readOnly, max: max, min: min, name: name, type: "text", value: value ?? '', onChange: handleChange }),
28
+ React.createElement(Input, { disabled: readOnly, max: max, min: min, name: name, type: "text", value: inputValueRef.current, onChange: handleChange }),
20
29
  React.createElement(FieldGroup.Error, { error: error })));
21
30
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@douglasneuroinformatics/libui",
3
3
  "type": "module",
4
- "version": "2.9.2",
4
+ "version": "2.10.0",
5
5
  "packageManager": "pnpm@9.3.0",
6
6
  "description": "Generic UI components for DNP projects, built using React and Tailwind CSS",
7
7
  "author": "Joshua Unrau",
@@ -64,8 +64,8 @@
64
64
  "zod": "^3.23.6"
65
65
  },
66
66
  "dependencies": {
67
- "@douglasneuroinformatics/libjs": "^0.3.1",
68
- "@douglasneuroinformatics/libui-form-types": "^0.10.0",
67
+ "@douglasneuroinformatics/libjs": "^0.5.0",
68
+ "@douglasneuroinformatics/libui-form-types": "^0.10.1",
69
69
  "@headlessui/tailwindcss": "^0.2.1",
70
70
  "@heroicons/react": "^2.1.3",
71
71
  "@radix-ui/react-accordion": "^1.1.2",
@@ -34,7 +34,7 @@ const $ExampleFormData = z.object({
34
34
  stringTextArea: z.string().optional(),
35
35
  stringPassword: z.string().optional(),
36
36
  stringInput: z.string().optional(),
37
- stringRadio: z.enum(['a', 'b', 'c'])
37
+ stringRadio: z.enum(['a', 'b', 'c']).optional()
38
38
  });
39
39
  type ExampleFormSchemaType = typeof $ExampleFormData;
40
40
  type ExampleFormData = z.TypeOf<typeof $ExampleFormData>;
@@ -79,9 +79,7 @@ const numberFields: FormFields<Pick<ExampleFormData, 'numberInput' | 'numberRadi
79
79
  numberInput: {
80
80
  description: 'This is a number field',
81
81
  kind: 'number',
82
- label: 'Input',
83
- max: 10,
84
- min: 0,
82
+ label: 'Number Input',
85
83
  variant: 'input'
86
84
  },
87
85
  numberRadio: {
@@ -109,7 +107,7 @@ const numberFields: FormFields<Pick<ExampleFormData, 'numberInput' | 'numberRadi
109
107
  description: 'This is a number field',
110
108
  kind: 'number',
111
109
  variant: 'select',
112
- label: 'Select',
110
+ label: 'Number Select',
113
111
  options: {
114
112
  1: 'Very Low',
115
113
  2: 'Low',
@@ -364,3 +362,25 @@ export const ReadOnly: StoryObj<typeof Form<ExampleFormSchemaType>> = {
364
362
  validationSchema: $ExampleFormData
365
363
  }
366
364
  };
365
+
366
+ export const WithInitialValue: StoryObj<typeof Form> = {
367
+ args: {
368
+ content: {
369
+ numberInput: {
370
+ kind: 'number',
371
+ label: 'Number Input',
372
+ variant: 'input'
373
+ }
374
+ },
375
+ initialValues: {
376
+ numberInput: 44
377
+ },
378
+ onSubmit: (data) => {
379
+ alert(JSON.stringify(data, null, 2));
380
+ },
381
+ preventResetValuesOnReset: true,
382
+ validationSchema: z.object({
383
+ numberInput: z.number()
384
+ })
385
+ }
386
+ };
@@ -1,5 +1,6 @@
1
- import React from 'react';
1
+ import React, { useRef, useState } from 'react';
2
2
 
3
+ import { parseNumber } from '@douglasneuroinformatics/libjs';
3
4
  import type { NumberFormField } from '@douglasneuroinformatics/libui-form-types';
4
5
  import type { Simplify } from 'type-fest';
5
6
 
@@ -17,21 +18,31 @@ export const NumberFieldInput = ({
17
18
  description,
18
19
  error,
19
20
  label,
20
- max,
21
- min,
21
+ max = Number.MAX_SAFE_INTEGER,
22
+ min = Number.MIN_SAFE_INTEGER,
22
23
  name,
23
24
  readOnly,
24
25
  setValue,
25
26
  value
26
27
  }: NumberFieldInputProps) => {
28
+ const inputValueRef = useRef(value?.toString() ?? '');
29
+ const [inputKey, setInputKey] = useState(0);
30
+
27
31
  const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
28
- const newValue = parseFloat(event.target.value);
29
- if (Number.isNaN(newValue)) {
30
- setValue(undefined);
31
- } else if (newValue >= (min ?? -Infinity) && newValue <= (max ?? Infinity)) {
32
- setValue(newValue);
32
+ let newValue: number | undefined = value;
33
+ if (/^[+-]?$/.test(event.target.value)) {
34
+ newValue = undefined;
35
+ inputValueRef.current = event.target.value;
36
+ } else {
37
+ const parsedValue = parseNumber(event.target.value);
38
+ if (parsedValue >= min && parsedValue <= max) {
39
+ newValue = parsedValue;
40
+ inputValueRef.current = event.target.value;
41
+ }
33
42
  }
43
+ value === newValue ? setInputKey(inputKey + 1) : setValue(newValue);
34
44
  };
45
+
35
46
  return (
36
47
  <FieldGroup>
37
48
  <FieldGroup.Row>
@@ -44,7 +55,7 @@ export const NumberFieldInput = ({
44
55
  min={min}
45
56
  name={name}
46
57
  type="text"
47
- value={value ?? ''}
58
+ value={inputValueRef.current}
48
59
  onChange={handleChange}
49
60
  />
50
61
  <FieldGroup.Error error={error} />