@peassoft/mnr-web-ui-kit 2.2.1 → 2.4.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,15 +1,32 @@
1
1
  import { type JSX } from 'react';
2
2
  import './styles.css';
3
3
  type Props = {
4
- /** Type of the inner input element */
4
+ /**
5
+ * Type of the inner input element
6
+ *
7
+ * @default text
8
+ */
5
9
  type?: 'text' | 'email' | 'password';
6
10
  /** Label */
7
11
  label: string;
12
+ /**
13
+ * Description text placed under the input field. Can be used to provide additional
14
+ * information about the input field, for example, about the expected format of the value.
15
+ */
16
+ description?: string;
17
+ /**
18
+ * Whether the input field is required. If true, an asterisk will be displayed next to the label.
19
+ */
20
+ required?: boolean;
8
21
  /** autocomplete attribute */
9
22
  autocompleteAttribute?: string;
10
23
  /** disabled attribule */
11
24
  disabled?: boolean;
12
- /** Width in any CSS length value */
25
+ /**
26
+ * Width in any CSS length value
27
+ *
28
+ * @default 100%
29
+ */
13
30
  width?: string;
14
31
  /** Error message */
15
32
  errorMessage?: string;
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState, useCallback, useEffect } from 'react';
2
+ import { useState, useCallback, useMemo, useEffect, useId } from 'react';
3
3
  import './styles.css';
4
4
  import processKeyDown from './process-key-down.js';
5
5
  export function InputField(props) {
6
6
  const {
7
7
  type = 'text',
8
8
  label,
9
+ description,
10
+ required,
9
11
  autocompleteAttribute,
10
12
  disabled = false,
11
13
  width = '100%',
@@ -18,6 +20,14 @@ export function InputField(props) {
18
20
  onBlur
19
21
  } = props;
20
22
  const [isCapslockOn, setIsCapslockOn] = useState(false);
23
+ const descriptionId = useId();
24
+ const errorMessageId = useId();
25
+ const inputDescribedByAttribute = useMemo(() => {
26
+ let returnValue = '';
27
+ if (errorMessage) returnValue = errorMessageId;
28
+ if (description) returnValue += ` ${descriptionId}`;
29
+ return returnValue || undefined;
30
+ }, [errorMessage, description, errorMessageId, descriptionId]);
21
31
  const handleChange = useCallback(e => onChange(e.target.value), [onChange]);
22
32
  const handleKeyDown = useCallback(e => processKeyDown(e, onTab, onShiftTab, onBlur), [onTab, onShiftTab, onBlur]);
23
33
  useEffect(() => {
@@ -52,9 +62,13 @@ export function InputField(props) {
52
62
  },
53
63
  children: [_jsxs("label", {
54
64
  className: 'uikit_InputField_innerCont',
55
- children: [_jsx("span", {
65
+ children: [_jsxs("span", {
56
66
  className: 'uikit_InputField_label',
57
- children: label
67
+ children: [label, required && _jsx("span", {
68
+ className: 'uikit_InputField_required',
69
+ "aria-hidden": 'true',
70
+ children: "\u00A0*"
71
+ })]
58
72
  }), _jsx("input", {
59
73
  ref: ref,
60
74
  className: 'uikit_InputField_input',
@@ -62,6 +76,8 @@ export function InputField(props) {
62
76
  autoComplete: autocompleteAttribute,
63
77
  disabled: disabled,
64
78
  value: value,
79
+ "aria-describedby": inputDescribedByAttribute,
80
+ "aria-required": required || undefined,
65
81
  onChange: handleChange,
66
82
  onKeyDown: handleKeyDown,
67
83
  onBlur: onBlur || undefined
@@ -79,9 +95,17 @@ export function InputField(props) {
79
95
  }), _jsx("span", {
80
96
  children: "CapsLock"
81
97
  })]
82
- }), !!errorMessage && _jsx("div", {
83
- className: 'uikit_InputField_errorMsg',
84
- children: errorMessage
98
+ }), _jsx("div", {
99
+ "aria-live": 'assertive',
100
+ children: !!errorMessage && _jsx("div", {
101
+ className: 'uikit_InputField_errorMsg',
102
+ id: errorMessageId,
103
+ children: errorMessage
104
+ })
105
+ }), !!description && _jsx("div", {
106
+ className: 'uikit_InputField_description',
107
+ id: descriptionId,
108
+ children: description
85
109
  })]
86
110
  });
87
111
  }
@@ -11,13 +11,23 @@
11
11
  .uikit_InputField_label {
12
12
  display: block;
13
13
  margin-bottom: 0.25em;
14
- color: #757575;
14
+ color: #737373;
15
15
  width: 100%;
16
16
  }
17
17
 
18
18
  @media (prefers-color-scheme: dark) {
19
19
  .uikit_InputField_label {
20
- color: #979797;
20
+ color: #acacac;
21
+ }
22
+ }
23
+
24
+ .uikit_InputField_required {
25
+ color: #a7241b;
26
+ }
27
+
28
+ @media (prefers-color-scheme: dark) {
29
+ .uikit_InputField_required {
30
+ color: #fb827a;
21
31
  }
22
32
  }
23
33
 
@@ -63,7 +73,7 @@
63
73
 
64
74
  @media (prefers-color-scheme: dark) {
65
75
  .uikit_InputField_capslockMsg {
66
- color: #979797;
76
+ color: #acacac;
67
77
  }
68
78
  }
69
79
 
@@ -89,3 +99,15 @@
89
99
  color: #fb827a;
90
100
  }
91
101
  }
102
+
103
+ .uikit_InputField_description {
104
+ color: #737373;
105
+ font-size: 0.85rem;
106
+ margin-top: 0.2em;
107
+ }
108
+
109
+ @media (prefers-color-scheme: dark) {
110
+ .uikit_InputField_description {
111
+ color: #acacac;
112
+ }
113
+ }
@@ -0,0 +1,3 @@
1
+ import type { JSX } from 'react';
2
+ export declare function UncheckedIcon(): JSX.Element;
3
+ export declare function CheckedIcon(): JSX.Element;
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ export function UncheckedIcon() {
3
+ return _jsx("svg", {
4
+ width: '24',
5
+ height: '24',
6
+ viewBox: '0 0 24 24',
7
+ fill: 'none',
8
+ stroke: 'currentColor',
9
+ strokeWidth: '1',
10
+ strokeLinecap: 'round',
11
+ strokeLinejoin: 'round',
12
+ className: 'uikit_PlainSelect_icon uikit_PlainSelect_uncheckedIcon',
13
+ children: _jsx("rect", {
14
+ width: '18',
15
+ height: '18',
16
+ x: '3',
17
+ y: '3',
18
+ rx: '2'
19
+ })
20
+ });
21
+ }
22
+ export function CheckedIcon() {
23
+ return _jsxs("svg", {
24
+ width: '24',
25
+ height: '24',
26
+ viewBox: '0 0 24 24',
27
+ fill: 'none',
28
+ stroke: 'currentColor',
29
+ strokeWidth: '2',
30
+ strokeLinecap: 'round',
31
+ strokeLinejoin: 'round',
32
+ className: 'uikit_PlainSelect_icon uikit_PlainSelect_checkedIcon',
33
+ children: [_jsx("path", {
34
+ d: 'M21 10.656V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12.344'
35
+ }), _jsx("path", {
36
+ d: 'm9 11 3 3L22 4'
37
+ })]
38
+ });
39
+ }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useId, useCallback, useState, useMemo, useLayoutEffect, createRef } from 'react';
3
3
  import './styles.css';
4
- import Icon from './icon.js';
4
+ import { UncheckedIcon, CheckedIcon } from './icons.js';
5
5
  /**
6
6
  * Select element implementing Listbox pattern. Presents a list of options and allows
7
7
  * a user to select one or more of them.
@@ -177,9 +177,7 @@ export function PlainSelect(props) {
177
177
  tabIndex: multiple && currFocusedIdx === idx ? 0 : -1,
178
178
  onClick: () => handleItemClick(item.id),
179
179
  onKeyDown: multiple ? handleMultiSelectKeyDown : undefined,
180
- children: [_jsx(Icon, {
181
- selected: isSelected
182
- }), _jsxs("div", {
180
+ children: [isSelected ? _jsx(CheckedIcon, {}) : _jsx(UncheckedIcon, {}), _jsxs("div", {
183
181
  className: 'uikit_PlainSelect_itemContent',
184
182
  children: [_jsx("div", {
185
183
  children: item.title
@@ -1,11 +1,11 @@
1
1
  .uikit_PlainSelect_label {
2
2
  margin: 0;
3
- color: #757575;
3
+ color: #737373;
4
4
  }
5
5
 
6
6
  @media (prefers-color-scheme: dark) {
7
7
  .uikit_PlainSelect_label {
8
- color: #979797;
8
+ color: #acacac;
9
9
  }
10
10
  }
11
11
 
@@ -37,8 +37,12 @@
37
37
  flex-shrink: 0;
38
38
  }
39
39
 
40
- .uikit_PlainSelect_icon--hidden {
41
- visibility: hidden;
40
+ .uikit_PlainSelect_uncheckedIcon {
41
+ color: #767676;
42
+ }
43
+
44
+ .uikit_PlainSelect_checkedIcon {
45
+ color: #337e33;
42
46
  }
43
47
 
44
48
  .uikit_PlainSelect_itemContent {
@@ -51,6 +55,6 @@
51
55
 
52
56
  .uikit_PlainSelect_description {
53
57
  margin-top: 0.5em;
54
- color: #757575;
58
+ color: #737373;
55
59
  font-size: 87.5%;
56
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peassoft/mnr-web-ui-kit",
3
- "version": "2.2.1",
3
+ "version": "2.4.0",
4
4
  "description": "Peassoft web UI kit for MNR web applications",
5
5
  "type": "module",
6
6
  "exports": {
@@ -46,7 +46,7 @@
46
46
  "react-dom": "^19.0.0",
47
47
  "storybook": "^10.1.4",
48
48
  "stylelint": "^17.0.0",
49
- "typescript": "^5.2.2",
49
+ "typescript": "^6.0.2",
50
50
  "vitest": "^4.0.7"
51
51
  },
52
52
  "peerDependencies": {
@@ -1,6 +0,0 @@
1
- import type { JSX } from 'react';
2
- type Props = {
3
- selected: boolean;
4
- };
5
- export default function Icon(props: Props): JSX.Element;
6
- export {};
@@ -1,17 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- export default function Icon(props) {
3
- const {
4
- selected
5
- } = props;
6
- const className = 'uikit_PlainSelect_icon' + (selected ? '' : ' uikit_PlainSelect_icon--hidden');
7
- return _jsx("svg", {
8
- className: className,
9
- width: '24',
10
- height: '24',
11
- viewBox: '0 0 24 24',
12
- children: _jsx("path", {
13
- d: 'M9 16.172l10.594-10.594 1.406 1.406-12 12-5.578-5.578 1.406-1.406z',
14
- fill: '#24b23e'
15
- })
16
- });
17
- }