@gnist/design-system 3.6.0 → 3.7.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/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [3.7.0](https://github.com/mollerdigital/design-system-design-system/compare/@gnist/design-system@3.6.0...@gnist/design-system@3.7.0) (2025-07-11)
7
+
8
+ ### Features
9
+
10
+ * add mode prop to TextField ([015a59b](https://github.com/mollerdigital/design-system-design-system/commit/015a59b522fc04d0526a67de9d0e2ecc0fd3396f))
11
+
6
12
  ## [3.6.0](https://github.com/mollerdigital/design-system-design-system/compare/@gnist/design-system@3.5.6...@gnist/design-system@3.6.0) (2025-07-07)
7
13
 
8
14
  ### Features
@@ -23,17 +23,40 @@ const shared = require("../shared.cjs");
23
23
  const _interopDefaultCompat = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
24
24
  const classNames__default = /* @__PURE__ */ _interopDefaultCompat(classNames);
25
25
  const TextField = React.forwardRef(function TextField2(props, ref) {
26
- var _a, _b;
26
+ var _a, _b, _c, _d;
27
27
  const { wrapperProps, contentProps, commonInputProps } = shared.useInputFieldLogic(props);
28
28
  const { inputProps } = shared.getInputFieldProps(props);
29
+ const isModeCurrencyOrNumberFormatting = ((_a = props.mode) == null ? void 0 : _a.style) === "currency" || ((_b = props.mode) == null ? void 0 : _b.style) === "numberSpacing";
30
+ const onChangeHandler = (event) => {
31
+ var _a2;
32
+ if (isModeCurrencyOrNumberFormatting) {
33
+ event.target.value = event.target.value.replace(new RegExp("(?<!^)-|[^\\d\\W.,]+|[.,]|\\s+", "g"), "");
34
+ }
35
+ (_a2 = inputProps.onChange) == null ? void 0 : _a2.call(inputProps, event);
36
+ };
37
+ if (isModeCurrencyOrNumberFormatting && !!inputProps.value) {
38
+ inputProps.type = "text";
39
+ inputProps.inputMode = "numeric";
40
+ const number = inputProps.value;
41
+ const isNegativeNumber = number[0] === "-";
42
+ inputProps.value = isNegativeNumber ? inputProps.value.slice(1) : inputProps.value;
43
+ const numberPrefix = isNegativeNumber ? "-" : "";
44
+ const formattedValue = new Intl.NumberFormat("nb-NB", {
45
+ style: "currency",
46
+ currency: "NOK",
47
+ minimumFractionDigits: 0,
48
+ maximumFractionDigits: 5
49
+ }).format(parseFloat(inputProps.value)).replaceAll(/[^0-9.,\W]/g, "").trim();
50
+ inputProps.value = numberPrefix + formattedValue;
51
+ }
29
52
  return jsxRuntime.jsxs("span", { ref, className: classNames__default.default(wrapperProps.className, inputField_css.wrapperStyle), children: [props.leadingIcon && shared.isClickableIcon(props.leadingIcon) && jsxRuntime.jsx("button", { className: iconButtonOverlay_css.iconButtonOverlayRecipe({
30
53
  placement: "left",
31
54
  density: wrapperProps.density
32
55
  }), title: props.leadingIcon.title, onClick: props.leadingIcon.onClick }), jsxRuntime.jsxs("label", { htmlFor: props.id, className: inputField_css.inputFieldWrapperRecipe({
33
56
  disabled: props.disabled,
34
57
  density: props.density,
35
- validityType: (_a = props.validity) == null ? void 0 : _a.type
36
- }), children: [jsxRuntime.jsx("input", { ...commonInputProps, ...inputProps, className: classNames__default.default(inputField_css.inputFieldStyle, inputProps.className), style: dynamic.assignInlineVars({
58
+ validityType: (_c = props.validity) == null ? void 0 : _c.type
59
+ }), children: [jsxRuntime.jsx("input", { ...commonInputProps, ...inputProps, value: inputProps.value, onChange: onChangeHandler, className: classNames__default.default(inputField_css.inputFieldStyle, inputProps.className), style: dynamic.assignInlineVars({
37
60
  [inputFieldConstants_css.preInputWidth]: wrapperProps.preInputWidth,
38
61
  [inputFieldConstants_css.postInputWidth]: wrapperProps.postInputWidth
39
62
  }), onFocus: (event) => {
@@ -44,7 +67,7 @@ const TextField = React.forwardRef(function TextField2(props, ref) {
44
67
  (_b2 = inputProps.onFocus) == null ? void 0 : _b2.call(inputProps, event);
45
68
  } }), jsxRuntime.jsxs("span", { className: inputField_css.inputContentWrapper({ density: props.density }), children: [props.leadingIcon && jsxRuntime.jsx(Icon.Icon, { icon: shared.isClickableIcon(props.leadingIcon) ? props.leadingIcon.icon : props.leadingIcon, className: atoms_css_js.atoms({ paddingRight: "xxs" }) }), props.prefix && jsxRuntime.jsx("span", { ref: contentProps.prefixRef, "aria-hidden": true, className: suffixPrefix_css.prefixStyle, children: props.prefix }), jsxRuntime.jsx("label", { id: contentProps.labelId, className: labelStyles_css.labelStyle({
46
69
  density: props.density,
47
- validityType: (_b = props.validity) == null ? void 0 : _b.type,
70
+ validityType: (_d = props.validity) == null ? void 0 : _d.type,
48
71
  isElevated: !!props.value || props.type === "date" || props.type === "time",
49
72
  disabled: props.disabled
50
73
  }), style: {
@@ -1,12 +1,17 @@
1
1
  import { InputHTMLAttributes } from "react";
2
2
  import { TextInputProps } from "../shared.js";
3
- export type TextFieldProps = TextInputProps & Omit<InputHTMLAttributes<HTMLInputElement>, "placeholder" | "value" | "type"> & {
3
+ export type TextFieldModeProps = {
4
4
  /**
5
- * Input type
6
- * @default text
5
+ * Applies number spacing and numeric input mode
7
6
  */
8
- type?: "email" | "search" | "tel" | "text" | "url" | "password" | "number" | "date" | "time";
7
+ mode?: {
8
+ style: "numberSpacing";
9
+ } | {
10
+ style: "currency";
11
+ currency: "NOK";
12
+ };
9
13
  };
14
+ export type TextFieldProps = TextInputProps & TextFieldModeProps & Omit<InputHTMLAttributes<HTMLInputElement>, "placeholder" | "value">;
10
15
  /**
11
16
  A text field is an input that allows a user to write or edit text. Text fields typically appear in forms and dialogs.
12
17
 
@@ -18,11 +23,5 @@ _Accessibility note:_ The leading/trailing icon and prefix/suffix text will not
18
23
 
19
24
  Documentation: [TextField](https://gnist.moller.no/developers/components/latest/?path=/docs/components-inputs-textfields-textfield--docs)
20
25
  */
21
- export declare const TextField: import("react").ForwardRefExoticComponent<TextInputProps & Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "type" | "placeholder"> & {
22
- /**
23
- * Input type
24
- * @default text
25
- */
26
- type?: "email" | "search" | "tel" | "text" | "url" | "password" | "number" | "date" | "time";
27
- } & import("react").RefAttributes<HTMLSpanElement>>;
26
+ export declare const TextField: import("react").ForwardRefExoticComponent<TextInputProps & TextFieldModeProps & Omit<InputHTMLAttributes<HTMLInputElement>, "value" | "placeholder"> & import("react").RefAttributes<HTMLSpanElement>>;
28
27
  //# sourceMappingURL=TextField.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../../../src/components/inputs/textFields/TextField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA4B,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAetE,OAAO,EAGH,cAAc,EAEjB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,cAAc,GAAG,cAAc,GACvC,IAAI,CACA,mBAAmB,CAAC,gBAAgB,CAAC,EACrC,aAAa,GAAG,OAAO,GAAG,MAAM,CACnC,GAAG;IACA;;;OAGG;IACH,IAAI,CAAC,EACC,OAAO,GACP,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,GACL,UAAU,GACV,QAAQ,GACR,MAAM,GACN,MAAM,CAAC;CAChB,CAAC;AAEN;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS;IA3Bd;;;OAGG;WAEG,OAAO,GACP,QAAQ,GACR,KAAK,GACL,MAAM,GACN,KAAK,GACL,UAAU,GACV,QAAQ,GACR,MAAM,GACN,MAAM;mDAuJlB,CAAC"}
1
+ {"version":3,"file":"TextField.d.ts","sourceRoot":"","sources":["../../../../src/components/inputs/textFields/TextField.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA4B,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAetE,OAAO,EAGH,cAAc,EAEjB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,kBAAkB,GAAG;IAC7B;;OAEG;IACH,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,eAAe,CAAA;KAAE,GAAG;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,KAAK,CAAA;KAAE,CAAC;CAC9E,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,cAAc,GACvC,kBAAkB,GAClB,IAAI,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC;AAEzE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,wMAqLpB,CAAC"}
@@ -19,17 +19,40 @@ import { labelStyle } from "../shared-styles/labelStyles.css.js";
19
19
  import { prefixStyle, suffixStyle } from "../shared-styles/suffixPrefix.css.js";
20
20
  import { useInputFieldLogic, getInputFieldProps, isClickableIcon } from "../shared.js";
21
21
  const TextField = forwardRef(function TextField2(props, ref) {
22
- var _a, _b;
22
+ var _a, _b, _c, _d;
23
23
  const { wrapperProps, contentProps, commonInputProps } = useInputFieldLogic(props);
24
24
  const { inputProps } = getInputFieldProps(props);
25
+ const isModeCurrencyOrNumberFormatting = ((_a = props.mode) == null ? void 0 : _a.style) === "currency" || ((_b = props.mode) == null ? void 0 : _b.style) === "numberSpacing";
26
+ const onChangeHandler = (event) => {
27
+ var _a2;
28
+ if (isModeCurrencyOrNumberFormatting) {
29
+ event.target.value = event.target.value.replace(new RegExp("(?<!^)-|[^\\d\\W.,]+|[.,]|\\s+", "g"), "");
30
+ }
31
+ (_a2 = inputProps.onChange) == null ? void 0 : _a2.call(inputProps, event);
32
+ };
33
+ if (isModeCurrencyOrNumberFormatting && !!inputProps.value) {
34
+ inputProps.type = "text";
35
+ inputProps.inputMode = "numeric";
36
+ const number = inputProps.value;
37
+ const isNegativeNumber = number[0] === "-";
38
+ inputProps.value = isNegativeNumber ? inputProps.value.slice(1) : inputProps.value;
39
+ const numberPrefix = isNegativeNumber ? "-" : "";
40
+ const formattedValue = new Intl.NumberFormat("nb-NB", {
41
+ style: "currency",
42
+ currency: "NOK",
43
+ minimumFractionDigits: 0,
44
+ maximumFractionDigits: 5
45
+ }).format(parseFloat(inputProps.value)).replaceAll(/[^0-9.,\W]/g, "").trim();
46
+ inputProps.value = numberPrefix + formattedValue;
47
+ }
25
48
  return jsxs("span", { ref, className: classNames(wrapperProps.className, wrapperStyle), children: [props.leadingIcon && isClickableIcon(props.leadingIcon) && jsx("button", { className: iconButtonOverlayRecipe({
26
49
  placement: "left",
27
50
  density: wrapperProps.density
28
51
  }), title: props.leadingIcon.title, onClick: props.leadingIcon.onClick }), jsxs("label", { htmlFor: props.id, className: inputFieldWrapperRecipe({
29
52
  disabled: props.disabled,
30
53
  density: props.density,
31
- validityType: (_a = props.validity) == null ? void 0 : _a.type
32
- }), children: [jsx("input", { ...commonInputProps, ...inputProps, className: classNames(inputFieldStyle, inputProps.className), style: assignInlineVars({
54
+ validityType: (_c = props.validity) == null ? void 0 : _c.type
55
+ }), children: [jsx("input", { ...commonInputProps, ...inputProps, value: inputProps.value, onChange: onChangeHandler, className: classNames(inputFieldStyle, inputProps.className), style: assignInlineVars({
33
56
  [preInputWidth]: wrapperProps.preInputWidth,
34
57
  [postInputWidth]: wrapperProps.postInputWidth
35
58
  }), onFocus: (event) => {
@@ -40,7 +63,7 @@ const TextField = forwardRef(function TextField2(props, ref) {
40
63
  (_b2 = inputProps.onFocus) == null ? void 0 : _b2.call(inputProps, event);
41
64
  } }), jsxs("span", { className: inputContentWrapper({ density: props.density }), children: [props.leadingIcon && jsx(Icon, { icon: isClickableIcon(props.leadingIcon) ? props.leadingIcon.icon : props.leadingIcon, className: atoms({ paddingRight: "xxs" }) }), props.prefix && jsx("span", { ref: contentProps.prefixRef, "aria-hidden": true, className: prefixStyle, children: props.prefix }), jsx("label", { id: contentProps.labelId, className: labelStyle({
42
65
  density: props.density,
43
- validityType: (_b = props.validity) == null ? void 0 : _b.type,
66
+ validityType: (_d = props.validity) == null ? void 0 : _d.type,
44
67
  isElevated: !!props.value || props.type === "date" || props.type === "time",
45
68
  disabled: props.disabled
46
69
  }), style: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gnist/design-system",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -102,5 +102,5 @@
102
102
  "optional": true
103
103
  }
104
104
  },
105
- "gitHead": "13550fb6429db09a62cbcdeb9dad1cb142bc0f49"
105
+ "gitHead": "14c41444b303c99e0b9eca32b48848f84a07213c"
106
106
  }