@refinitiv-ui/elements 7.8.0 → 7.9.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/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
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
+ ## [7.9.1](https://github.com/Refinitiv/refinitiv-ui/compare/@refinitiv-ui/elements@7.9.0...@refinitiv-ui/elements@7.9.1) (2023-11-13)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **time-picker:** remove pre-populate value ([#995](https://github.com/Refinitiv/refinitiv-ui/issues/995)) ([afe008c](https://github.com/Refinitiv/refinitiv-ui/commit/afe008c1059031d28f6a6c6cff79caf8f301acaa))
11
+
12
+ # [7.9.0](https://github.com/Refinitiv/refinitiv-ui/compare/@refinitiv-ui/elements@7.8.0...@refinitiv-ui/elements@7.9.0) (2023-11-06)
13
+
14
+ ### Features
15
+
16
+ - **core, elements:** custom validation for form fields ([#996](https://github.com/Refinitiv/refinitiv-ui/issues/996)) ([b8655a2](https://github.com/Refinitiv/refinitiv-ui/commit/b8655a2d2ea42aa16767ba1bd8b5ce9c67912f36))
17
+
6
18
  # [7.8.0](https://github.com/Refinitiv/refinitiv-ui/compare/@refinitiv-ui/elements@7.7.0...@refinitiv-ui/elements@7.8.0) (2023-10-31)
7
19
 
8
20
  ### Bug Fixes
@@ -138,7 +138,9 @@ export declare class ColorDialog extends Dialog {
138
138
  */
139
139
  protected update(changedProperties: PropertyValues): void;
140
140
  /**
141
- * @inheritdoc
141
+ * Make sure that confirm/cancel events are fired appropriately
142
+ * All internal opened set events can be stoppable externally
143
+ * Use this instead of setting opened directly
142
144
  * Reset value model
143
145
  * @param opened True if opened
144
146
  * @returns {void}
@@ -211,7 +211,9 @@ let ColorDialog = class ColorDialog extends Dialog {
211
211
  super.update(changedProperties);
212
212
  }
213
213
  /**
214
- * @inheritdoc
214
+ * Make sure that confirm/cancel events are fired appropriately
215
+ * All internal opened set events can be stoppable externally
216
+ * Use this instead of setting opened directly
215
217
  * Reset value model
216
218
  * @param opened True if opened
217
219
  * @returns {void}
@@ -1,3 +1,4 @@
1
+ import escapeStringRegexp from 'escape-string-regexp';
1
2
  /**
2
3
  * Default filter used by combo box
3
4
  * @param el ComboBox instance to filter
@@ -13,8 +14,8 @@ export const defaultFilter = (el) => {
13
14
  // only created once per query
14
15
  const getRegularExpressionOfQuery = () => {
15
16
  if (el.query !== query || !queryRegExp) {
16
- query = el.query || '';
17
- queryRegExp = new RegExp(query.replace(/(\W)/g, '\\$1'), 'i');
17
+ query = el.query ?? '';
18
+ queryRegExp = new RegExp(escapeStringRegexp(query), 'i');
18
19
  }
19
20
  return queryRegExp;
20
21
  };
@@ -11,6 +11,21 @@
11
11
  "type": "boolean",
12
12
  "default": "false"
13
13
  },
14
+ {
15
+ "name": "pattern",
16
+ "description": "Set regular expression for input validation",
17
+ "type": "string | null"
18
+ },
19
+ {
20
+ "name": "maxlength",
21
+ "description": "Set character max limit",
22
+ "type": "number | null"
23
+ },
24
+ {
25
+ "name": "minlength",
26
+ "description": "Set character min limit",
27
+ "type": "number | null"
28
+ },
14
29
  {
15
30
  "name": "disabled",
16
31
  "description": "Set disabled state",
@@ -68,16 +83,6 @@
68
83
  "name": "icon-has-action",
69
84
  "description": "Specify when icon need to be clickable",
70
85
  "type": "boolean"
71
- },
72
- {
73
- "name": "maxlength",
74
- "description": "Set character max limit",
75
- "type": "number"
76
- },
77
- {
78
- "name": "minlength",
79
- "description": "Set character min limit",
80
- "type": "number"
81
86
  }
82
87
  ],
83
88
  "properties": [
@@ -88,6 +93,24 @@
88
93
  "type": "boolean",
89
94
  "default": "false"
90
95
  },
96
+ {
97
+ "name": "pattern",
98
+ "attribute": "pattern",
99
+ "description": "Set regular expression for input validation",
100
+ "type": "string | null"
101
+ },
102
+ {
103
+ "name": "maxLength",
104
+ "attribute": "maxlength",
105
+ "description": "Set character max limit",
106
+ "type": "number | null"
107
+ },
108
+ {
109
+ "name": "minLength",
110
+ "attribute": "minlength",
111
+ "description": "Set character min limit",
112
+ "type": "number | null"
113
+ },
91
114
  {
92
115
  "name": "disabled",
93
116
  "attribute": "disabled",
@@ -115,22 +138,6 @@
115
138
  "type": "boolean",
116
139
  "default": "false"
117
140
  },
118
- {
119
- "name": "maxLength",
120
- "description": "Set character max limit",
121
- "type": "number | null"
122
- },
123
- {
124
- "name": "minLength",
125
- "description": "Set character min limit",
126
- "type": "number | null"
127
- },
128
- {
129
- "name": "pattern",
130
- "description": "Set regular expression for input validation",
131
- "type": "string",
132
- "default": "\"\""
133
- },
134
141
  {
135
142
  "name": "placeholder",
136
143
  "attribute": "placeholder",
@@ -7,8 +7,6 @@ A form control element for email.
7
7
  | Attribute | Type | Description |
8
8
  |-------------------|-----------|----------------------------------------|
9
9
  | `icon-has-action` | `boolean` | Specify when icon need to be clickable |
10
- | `maxlength` | `number` | Set character max limit |
11
- | `minlength` | `number` | Set character min limit |
12
10
 
13
11
  ## Properties
14
12
 
@@ -18,10 +16,10 @@ A form control element for email.
18
16
  | `error` | `error` | `boolean` | false | Set error state |
19
17
  | `icon` | `icon` | `string \| null` | null | Specify icon to display in input. Value can be icon name |
20
18
  | `iconHasAction` | `icon-has-action` | `boolean` | false | Specify when icon need to be clickable |
21
- | `maxLength` | | `number \| null` | null | Set character max limit |
22
- | `minLength` | | `number \| null` | null | Set character min limit |
19
+ | `maxLength` | `maxlength` | `number \| null` | null | Set character max limit |
20
+ | `minLength` | `minlength` | `number \| null` | null | Set character min limit |
23
21
  | `multiple` | `multiple` | `boolean` | false | Set to multiple mode, allows multiple emails in a single input |
24
- | `pattern` | | `string` | "" | Set regular expression for input validation |
22
+ | `pattern` | `pattern` | `string \| null` | null | Set regular expression for input validation |
25
23
  | `placeholder` | `placeholder` | `string` | "" | Set placeholder text |
26
24
  | `readonly` | `readonly` | `boolean` | false | Set readonly state |
27
25
  | `transparent` | `transparent` | `boolean` | false | Disables all other states and border/background styles. |
@@ -21,14 +21,6 @@ import { TextField } from '../text-field/index.js';
21
21
  * @attr {boolean} icon-has-action - Specify when icon need to be clickable
22
22
  * @prop {boolean} [iconHasAction=false] - Specify when icon need to be clickable
23
23
  *
24
- * @attr {number} maxlength - Set character max limit
25
- * @prop {number | null} [maxLength=null] - Set character max limit
26
- *
27
- * @attr {number} minlength - Set character min limit
28
- * @prop {number | null} [minLength=null] - Set character min limit
29
- *
30
- * @prop {string} [pattern=""] - Set regular expression for input validation
31
- *
32
24
  * @attr {string} placeholder - Set placeholder text
33
25
  * @prop {string} [placeholder=""] - Set placeholder text
34
26
  *
@@ -49,6 +41,18 @@ export declare class EmailField extends TextField {
49
41
  * Set to multiple mode, allows multiple emails in a single input
50
42
  */
51
43
  multiple: boolean;
44
+ /**
45
+ * Set regular expression for input validation
46
+ */
47
+ pattern: string | null;
48
+ /**
49
+ * Set character max limit
50
+ */
51
+ maxLength: number | null;
52
+ /**
53
+ * Set character min limit
54
+ */
55
+ minLength: number | null;
52
56
  /**
53
57
  * Returns `true` if the element input is valid; otherwise, returns `false`.
54
58
  * @returns element input validity
@@ -59,6 +63,11 @@ export declare class EmailField extends TextField {
59
63
  * @returns `true` if the element input is valid; otherwise, returns `false`.
60
64
  */
61
65
  reportValidity(): boolean;
66
+ /**
67
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
68
+ * @returns true if there is at least one validation constraint
69
+ */
70
+ protected shouldValidate(): boolean;
62
71
  /**
63
72
  * Decorate `<input>` element with common properties extended from text-field:
64
73
  * type="email" - always `email`
@@ -22,14 +22,6 @@ import { TextField } from '../text-field/index.js';
22
22
  * @attr {boolean} icon-has-action - Specify when icon need to be clickable
23
23
  * @prop {boolean} [iconHasAction=false] - Specify when icon need to be clickable
24
24
  *
25
- * @attr {number} maxlength - Set character max limit
26
- * @prop {number | null} [maxLength=null] - Set character max limit
27
- *
28
- * @attr {number} minlength - Set character min limit
29
- * @prop {number | null} [minLength=null] - Set character min limit
30
- *
31
- * @prop {string} [pattern=""] - Set regular expression for input validation
32
- *
33
25
  * @attr {string} placeholder - Set placeholder text
34
26
  * @prop {string} [placeholder=""] - Set placeholder text
35
27
  *
@@ -52,6 +44,20 @@ let EmailField = class EmailField extends TextField {
52
44
  * Set to multiple mode, allows multiple emails in a single input
53
45
  */
54
46
  this.multiple = false;
47
+ /**
48
+ * Set regular expression for input validation
49
+ */
50
+ this.pattern = null;
51
+ /**
52
+ * Set character max limit
53
+ */
54
+ // override to merely fix missing attribute from component's doc
55
+ this.maxLength = null;
56
+ /**
57
+ * Set character min limit
58
+ */
59
+ // override to merely fix missing attribute from component's doc
60
+ this.minLength = null;
55
61
  }
56
62
  /**
57
63
  * Returns `true` if the element input is valid; otherwise, returns `false`.
@@ -67,6 +73,16 @@ let EmailField = class EmailField extends TextField {
67
73
  reportValidity() {
68
74
  return super.reportValidity();
69
75
  }
76
+ /**
77
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
78
+ * @returns true if there is at least one validation constraint
79
+ */
80
+ shouldValidate() {
81
+ const hasMaxLength = this.maxLength !== null;
82
+ const hasMinLength = this.minLength !== null;
83
+ const hasPattern = this.pattern !== '';
84
+ return hasMaxLength || hasMinLength || hasPattern;
85
+ }
70
86
  /**
71
87
  * Decorate `<input>` element with common properties extended from text-field:
72
88
  * type="email" - always `email`
@@ -78,13 +94,23 @@ let EmailField = class EmailField extends TextField {
78
94
  ...super.decorateInputMap,
79
95
  type: 'email',
80
96
  inputmode: 'email',
81
- multiple: this.multiple
97
+ multiple: this.multiple,
98
+ pattern: this.pattern
82
99
  };
83
100
  }
84
101
  };
85
102
  __decorate([
86
103
  property({ type: Boolean, reflect: true })
87
104
  ], EmailField.prototype, "multiple", void 0);
105
+ __decorate([
106
+ property({ type: String })
107
+ ], EmailField.prototype, "pattern", void 0);
108
+ __decorate([
109
+ property({ type: Number, attribute: 'maxlength', reflect: true })
110
+ ], EmailField.prototype, "maxLength", void 0);
111
+ __decorate([
112
+ property({ type: Number, attribute: 'minlength', reflect: true })
113
+ ], EmailField.prototype, "minLength", void 0);
88
114
  EmailField = __decorate([
89
115
  customElement('ef-email-field')
90
116
  ], EmailField);
@@ -7,7 +7,6 @@ import { CollectionComposer } from '@refinitiv-ui/utils/collection.js';
7
7
  import '../pill/index.js';
8
8
  import '../text-field/index.js';
9
9
  import { VERSION } from '../version.js';
10
- const hasChanged = (newVal, oldVal) => oldVal === undefined ? false : newVal !== oldVal;
11
10
  /**
12
11
  * An input control component to display a selection of pills
13
12
  *
@@ -551,7 +550,7 @@ __decorate([
551
550
  property({ type: Number, attribute: 'maxlength', reflect: true })
552
551
  ], MultiInput.prototype, "maxLength", void 0);
553
552
  __decorate([
554
- property({ type: Number, attribute: 'minlength', reflect: true, hasChanged })
553
+ property({ type: Number, attribute: 'minlength', reflect: true })
555
554
  ], MultiInput.prototype, "minLength", void 0);
556
555
  __decorate([
557
556
  property({ type: Number, attribute: false })
@@ -288,6 +288,11 @@ export declare class NumberField extends FormFieldElement {
288
288
  * @returns {void}
289
289
  */
290
290
  stepDown(stepIncrement?: number): void;
291
+ /**
292
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
293
+ * @returns true if there is at least one validation constraint
294
+ */
295
+ private shouldValidate;
291
296
  /**
292
297
  * Validate the element input and mark it as error if its input is invalid.
293
298
  * @returns `true` if the element input is valid; otherwise, returns `false`.
@@ -300,37 +305,30 @@ export declare class NumberField extends FormFieldElement {
300
305
  checkValidity(): boolean;
301
306
  /**
302
307
  * @ignore
303
- * @inheritDoc
304
308
  */
305
309
  get selectionStart(): number | null;
306
310
  /**
307
311
  * @ignore
308
- * @inheritDoc
309
312
  */
310
313
  set selectionStart(index: number | null);
311
314
  /**
312
315
  * @ignore
313
- * @inheritDoc
314
316
  */
315
317
  get selectionEnd(): number | null;
316
318
  /**
317
319
  * @ignore
318
- * @inheritDoc
319
320
  */
320
321
  set selectionEnd(index: number | null);
321
322
  /**
322
323
  * @ignore
323
- * @inheritDoc
324
324
  */
325
325
  get selectionDirection(): SelectionDirection | null;
326
326
  /**
327
327
  * @ignore
328
- * @inheritDoc
329
328
  */
330
329
  set selectionDirection(direction: SelectionDirection | null);
331
330
  /**
332
331
  * @ignore
333
- * @inheritDoc
334
332
  */
335
333
  setSelectionRange(startSelection: number | null, endSelection: number | null, selectionDirection?: SelectionDirection): void;
336
334
  /**
@@ -166,7 +166,7 @@ let NumberField = class NumberField extends FormFieldElement {
166
166
  * @returns {void}
167
167
  */
168
168
  update(changedProperties) {
169
- if (changedProperties.has(FocusedPropertyKey) && !this.focused) {
169
+ if (changedProperties.has(FocusedPropertyKey) && !this.focused && this.shouldValidate()) {
170
170
  this.reportValidity();
171
171
  }
172
172
  super.update(changedProperties);
@@ -447,8 +447,9 @@ let NumberField = class NumberField extends FormFieldElement {
447
447
  * @returns {void}
448
448
  */
449
449
  setSilentlyValueAndNotify() {
450
- // Nobody likes to see a red border
451
- this.reportValidity();
450
+ if (this.shouldValidate()) {
451
+ this.reportValidity();
452
+ }
452
453
  const value = this.valueAsNumberString(this.inputValue);
453
454
  if (super.value !== value) {
454
455
  // here we must set the value silently to avoid re-rendering of input
@@ -639,6 +640,16 @@ let NumberField = class NumberField extends FormFieldElement {
639
640
  stepDown(stepIncrement) {
640
641
  this.applyStepDirection(Direction.Down, stepIncrement);
641
642
  }
643
+ /**
644
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
645
+ * @returns true if there is at least one validation constraint
646
+ */
647
+ shouldValidate() {
648
+ const hasMax = this.max !== null;
649
+ const hasMin = this.min !== null;
650
+ const hasStep = this.step !== ANY_STEP;
651
+ return hasMax || hasMin || hasStep;
652
+ }
642
653
  /**
643
654
  * Validate the element input and mark it as error if its input is invalid.
644
655
  * @returns `true` if the element input is valid; otherwise, returns `false`.
@@ -675,7 +686,6 @@ let NumberField = class NumberField extends FormFieldElement {
675
686
  }
676
687
  /**
677
688
  * @ignore
678
- * @inheritDoc
679
689
  */
680
690
  /* c8 ignore start */
681
691
  get selectionStart() {
@@ -684,7 +694,6 @@ let NumberField = class NumberField extends FormFieldElement {
684
694
  /* c8 ignore stop */
685
695
  /**
686
696
  * @ignore
687
- * @inheritDoc
688
697
  */
689
698
  /* c8 ignore start */
690
699
  set selectionStart(index) {
@@ -693,7 +702,6 @@ let NumberField = class NumberField extends FormFieldElement {
693
702
  /* c8 ignore stop */
694
703
  /**
695
704
  * @ignore
696
- * @inheritDoc
697
705
  */
698
706
  /* c8 ignore start */
699
707
  get selectionEnd() {
@@ -702,7 +710,6 @@ let NumberField = class NumberField extends FormFieldElement {
702
710
  /* c8 ignore stop */
703
711
  /**
704
712
  * @ignore
705
- * @inheritDoc
706
713
  */
707
714
  /* c8 ignore start */
708
715
  set selectionEnd(index) {
@@ -711,7 +718,6 @@ let NumberField = class NumberField extends FormFieldElement {
711
718
  /* c8 ignore stop */
712
719
  /**
713
720
  * @ignore
714
- * @inheritDoc
715
721
  */
716
722
  /* c8 ignore start */
717
723
  get selectionDirection() {
@@ -720,7 +726,6 @@ let NumberField = class NumberField extends FormFieldElement {
720
726
  /* c8 ignore stop */
721
727
  /**
722
728
  * @ignore
723
- * @inheritDoc
724
729
  */
725
730
  /* c8 ignore start */
726
731
  set selectionDirection(direction) {
@@ -729,7 +734,6 @@ let NumberField = class NumberField extends FormFieldElement {
729
734
  /* c8 ignore stop */
730
735
  /**
731
736
  * @ignore
732
- * @inheritDoc
733
737
  */
734
738
  /* c8 ignore start */
735
739
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
@@ -5,6 +5,16 @@
5
5
  "name": "ef-password-field",
6
6
  "description": "A form control element for password.",
7
7
  "attributes": [
8
+ {
9
+ "name": "maxlength",
10
+ "description": "Set character max limit",
11
+ "type": "number | null"
12
+ },
13
+ {
14
+ "name": "minlength",
15
+ "description": "Set character min limit",
16
+ "type": "number | null"
17
+ },
8
18
  {
9
19
  "name": "disabled",
10
20
  "description": "Set disabled state",
@@ -17,6 +27,12 @@
17
27
  "type": "boolean",
18
28
  "default": "false"
19
29
  },
30
+ {
31
+ "name": "pattern",
32
+ "description": "Set regular expression for input validation",
33
+ "type": "string",
34
+ "default": "\"\""
35
+ },
20
36
  {
21
37
  "name": "placeholder",
22
38
  "description": "Set placeholder text",
@@ -46,19 +62,21 @@
46
62
  "description": "Input's value",
47
63
  "type": "string",
48
64
  "default": "\"\""
49
- },
65
+ }
66
+ ],
67
+ "properties": [
50
68
  {
51
- "name": "maxlength",
69
+ "name": "maxLength",
70
+ "attribute": "maxlength",
52
71
  "description": "Set character max limit",
53
- "type": "number"
72
+ "type": "number | null"
54
73
  },
55
74
  {
56
- "name": "minlength",
75
+ "name": "minLength",
76
+ "attribute": "minlength",
57
77
  "description": "Set character min limit",
58
- "type": "number"
59
- }
60
- ],
61
- "properties": [
78
+ "type": "number | null"
79
+ },
62
80
  {
63
81
  "name": "disabled",
64
82
  "attribute": "disabled",
@@ -73,18 +91,9 @@
73
91
  "type": "boolean",
74
92
  "default": "false"
75
93
  },
76
- {
77
- "name": "maxLength",
78
- "description": "Set character max limit",
79
- "type": "number | null"
80
- },
81
- {
82
- "name": "minLength",
83
- "description": "Set character min limit",
84
- "type": "number | null"
85
- },
86
94
  {
87
95
  "name": "pattern",
96
+ "attribute": "pattern",
88
97
  "description": "Set regular expression for input validation",
89
98
  "type": "string",
90
99
  "default": "\"\""
@@ -2,22 +2,15 @@
2
2
 
3
3
  A form control element for password.
4
4
 
5
- ## Attributes
6
-
7
- | Attribute | Type | Description |
8
- |-------------|----------|-------------------------|
9
- | `maxlength` | `number` | Set character max limit |
10
- | `minlength` | `number` | Set character min limit |
11
-
12
5
  ## Properties
13
6
 
14
7
  | Property | Attribute | Type | Default | Description |
15
8
  |---------------|---------------|------------------|---------|--------------------------------------------------|
16
9
  | `disabled` | `disabled` | `boolean` | false | Set disabled state |
17
10
  | `error` | `error` | `boolean` | false | Set error state |
18
- | `maxLength` | | `number \| null` | null | Set character max limit |
19
- | `minLength` | | `number \| null` | null | Set character min limit |
20
- | `pattern` | | `string` | "" | Set regular expression for input validation |
11
+ | `maxLength` | `maxlength` | `number \| null` | null | Set character max limit |
12
+ | `minLength` | `minlength` | `number \| null` | null | Set character min limit |
13
+ | `pattern` | `pattern` | `string` | "" | Set regular expression for input validation |
21
14
  | `placeholder` | `placeholder` | `string` | "" | Set placeholder text |
22
15
  | `readonly` | `readonly` | `boolean` | false | Set readonly state |
23
16
  | `transparent` | `transparent` | `boolean` | false | Disables all other states and border/background styles. |
@@ -17,12 +17,7 @@ import { TextField } from '../text-field/index.js';
17
17
  * @attr {boolean} error - Set error state
18
18
  * @prop {boolean} [error=false] - Set error state
19
19
  *
20
- * @attr {number} maxlength - Set character max limit
21
- * @prop {number | null} [maxLength=null] - Set character max limit
22
- *
23
- * @attr {number} minlength - Set character min limit
24
- * @prop {number | null} [minLength=null] - Set character min limit
25
- *
20
+ * @attr {string} pattern - Set regular expression for input validation
26
21
  * @prop {string} [pattern=""] - Set regular expression for input validation
27
22
  *
28
23
  * @attr {string} placeholder - Set placeholder text
@@ -41,6 +36,14 @@ import { TextField } from '../text-field/index.js';
41
36
  * @prop {string} [value=""] - Input's value
42
37
  */
43
38
  export declare class PasswordField extends TextField {
39
+ /**
40
+ * Set character max limit
41
+ */
42
+ maxLength: number | null;
43
+ /**
44
+ * Set character min limit
45
+ */
46
+ minLength: number | null;
44
47
  /**
45
48
  * Used for translations
46
49
  */
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { html, unsafeCSS } from '@refinitiv-ui/core';
3
3
  import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js';
4
+ import { property } from '@refinitiv-ui/core/decorators/property.js';
4
5
  import { state } from '@refinitiv-ui/core/decorators/state.js';
5
6
  import '@refinitiv-ui/phrasebook/locale/en/password-field.js';
6
7
  import { translate } from '@refinitiv-ui/translate';
@@ -20,12 +21,7 @@ import { deregisterOverflowTooltip } from '../tooltip/index.js';
20
21
  * @attr {boolean} error - Set error state
21
22
  * @prop {boolean} [error=false] - Set error state
22
23
  *
23
- * @attr {number} maxlength - Set character max limit
24
- * @prop {number | null} [maxLength=null] - Set character max limit
25
- *
26
- * @attr {number} minlength - Set character min limit
27
- * @prop {number | null} [minLength=null] - Set character min limit
28
- *
24
+ * @attr {string} pattern - Set regular expression for input validation
29
25
  * @prop {string} [pattern=""] - Set regular expression for input validation
30
26
  *
31
27
  * @attr {string} placeholder - Set placeholder text
@@ -46,6 +42,16 @@ import { deregisterOverflowTooltip } from '../tooltip/index.js';
46
42
  let PasswordField = class PasswordField extends TextField {
47
43
  constructor() {
48
44
  super(...arguments);
45
+ /**
46
+ * Set character max limit
47
+ */
48
+ // override to merely fix missing attribute from component's doc
49
+ this.maxLength = null;
50
+ /**
51
+ * Set character min limit
52
+ */
53
+ // override to merely fix missing attribute from component's doc
54
+ this.minLength = null;
49
55
  /**
50
56
  * Defines whether password is visible or not
51
57
  */
@@ -150,6 +156,12 @@ let PasswordField = class PasswordField extends TextField {
150
156
  this.isPasswordVisible = !this.isPasswordVisible;
151
157
  }
152
158
  };
159
+ __decorate([
160
+ property({ type: Number, attribute: 'maxlength', reflect: true })
161
+ ], PasswordField.prototype, "maxLength", void 0);
162
+ __decorate([
163
+ property({ type: Number, attribute: 'minlength', reflect: true })
164
+ ], PasswordField.prototype, "minLength", void 0);
153
165
  __decorate([
154
166
  translate({ scope: 'ef-password-field' })
155
167
  ], PasswordField.prototype, "t", void 0);
@@ -5,6 +5,16 @@
5
5
  "name": "ef-search-field",
6
6
  "description": "Form control to get a search input from users.",
7
7
  "attributes": [
8
+ {
9
+ "name": "maxlength",
10
+ "description": "Set character max limit",
11
+ "type": "number | null"
12
+ },
13
+ {
14
+ "name": "minlength",
15
+ "description": "Set character min limit",
16
+ "type": "number | null"
17
+ },
8
18
  {
9
19
  "name": "disabled",
10
20
  "description": "Set disabled state",
@@ -23,6 +33,12 @@
23
33
  "type": "boolean",
24
34
  "default": "false"
25
35
  },
36
+ {
37
+ "name": "pattern",
38
+ "description": "Set regular expression for input validation",
39
+ "type": "string",
40
+ "default": "\"\""
41
+ },
26
42
  {
27
43
  "name": "placeholder",
28
44
  "description": "Set placeholder text",
@@ -57,19 +73,21 @@
57
73
  "name": "icon-has-action",
58
74
  "description": "Specify when icon need to be clickable",
59
75
  "type": "boolean"
60
- },
76
+ }
77
+ ],
78
+ "properties": [
61
79
  {
62
- "name": "maxlength",
80
+ "name": "maxLength",
81
+ "attribute": "maxlength",
63
82
  "description": "Set character max limit",
64
- "type": "number"
83
+ "type": "number | null"
65
84
  },
66
85
  {
67
- "name": "minlength",
86
+ "name": "minLength",
87
+ "attribute": "minlength",
68
88
  "description": "Set character min limit",
69
- "type": "number"
70
- }
71
- ],
72
- "properties": [
89
+ "type": "number | null"
90
+ },
73
91
  {
74
92
  "name": "disabled",
75
93
  "attribute": "disabled",
@@ -91,18 +109,9 @@
91
109
  "type": "boolean",
92
110
  "default": "false"
93
111
  },
94
- {
95
- "name": "maxLength",
96
- "description": "Set character max limit",
97
- "type": "number | null"
98
- },
99
- {
100
- "name": "minLength",
101
- "description": "Set character min limit",
102
- "type": "number | null"
103
- },
104
112
  {
105
113
  "name": "pattern",
114
+ "attribute": "pattern",
106
115
  "description": "Set regular expression for input validation",
107
116
  "type": "string",
108
117
  "default": "\"\""
@@ -7,8 +7,6 @@ Form control to get a search input from users.
7
7
  | Attribute | Type | Description |
8
8
  |-------------------|-----------|----------------------------------------|
9
9
  | `icon-has-action` | `boolean` | Specify when icon need to be clickable |
10
- | `maxlength` | `number` | Set character max limit |
11
- | `minlength` | `number` | Set character min limit |
12
10
 
13
11
  ## Properties
14
12
 
@@ -17,9 +15,9 @@ Form control to get a search input from users.
17
15
  | `disabled` | `disabled` | `boolean` | false | Set disabled state |
18
16
  | `error` | `error` | `boolean` | false | Set error state |
19
17
  | `iconHasAction` | `icon-has-action` | `boolean` | false | Specify when icon need to be clickable |
20
- | `maxLength` | | `number \| null` | null | Set character max limit |
21
- | `minLength` | | `number \| null` | null | Set character min limit |
22
- | `pattern` | | `string` | "" | Set regular expression for input validation |
18
+ | `maxLength` | `maxlength` | `number \| null` | null | Set character max limit |
19
+ | `minLength` | `minlength` | `number \| null` | null | Set character min limit |
20
+ | `pattern` | `pattern` | `string` | "" | Set regular expression for input validation |
23
21
  | `placeholder` | `placeholder` | `string` | "" | Set placeholder text |
24
22
  | `readonly` | `readonly` | `boolean` | false | Set readonly state |
25
23
  | `transparent` | `transparent` | `boolean` | false | Disables all other states and border/background styles. |
@@ -21,12 +21,7 @@ import { TextField } from '../text-field/index.js';
21
21
  * @attr {boolean} icon-has-action - Specify when icon need to be clickable
22
22
  * @prop {boolean} [iconHasAction=false] - Specify when icon need to be clickable
23
23
  *
24
- * @attr {number} maxlength - Set character max limit
25
- * @prop {number | null} [maxLength=null] - Set character max limit
26
- *
27
- * @attr {number} minlength - Set character min limit
28
- * @prop {number | null} [minLength=null] - Set character min limit
29
- *
24
+ * @attr {string} pattern - Set regular expression for input validation
30
25
  * @prop {string} [pattern=""] - Set regular expression for input validation
31
26
  *
32
27
  * @attr {string} placeholder - Set placeholder text
@@ -45,6 +40,14 @@ import { TextField } from '../text-field/index.js';
45
40
  * @prop {string} [value=""] - Input's value
46
41
  */
47
42
  export declare class SearchField extends TextField {
43
+ /**
44
+ * Set character max limit
45
+ */
46
+ maxLength: number | null;
47
+ /**
48
+ * Set character min limit
49
+ */
50
+ minLength: number | null;
48
51
  /**
49
52
  * Used for translations
50
53
  */
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { html, nothing } from '@refinitiv-ui/core';
3
3
  import { customElement } from '@refinitiv-ui/core/decorators/custom-element.js';
4
+ import { property } from '@refinitiv-ui/core/decorators/property.js';
4
5
  import '@refinitiv-ui/phrasebook/locale/en/search-field.js';
5
6
  import { translate } from '@refinitiv-ui/translate';
6
7
  import '../icon/index.js';
@@ -21,12 +22,7 @@ import { TextField } from '../text-field/index.js';
21
22
  * @attr {boolean} icon-has-action - Specify when icon need to be clickable
22
23
  * @prop {boolean} [iconHasAction=false] - Specify when icon need to be clickable
23
24
  *
24
- * @attr {number} maxlength - Set character max limit
25
- * @prop {number | null} [maxLength=null] - Set character max limit
26
- *
27
- * @attr {number} minlength - Set character min limit
28
- * @prop {number | null} [minLength=null] - Set character min limit
29
- *
25
+ * @attr {string} pattern - Set regular expression for input validation
30
26
  * @prop {string} [pattern=""] - Set regular expression for input validation
31
27
  *
32
28
  * @attr {string} placeholder - Set placeholder text
@@ -45,6 +41,19 @@ import { TextField } from '../text-field/index.js';
45
41
  * @prop {string} [value=""] - Input's value
46
42
  */
47
43
  let SearchField = class SearchField extends TextField {
44
+ constructor() {
45
+ super(...arguments);
46
+ /**
47
+ * Set character max limit
48
+ */
49
+ // override to merely fix missing attribute from component's doc
50
+ this.maxLength = null;
51
+ /**
52
+ * Set character min limit
53
+ */
54
+ // override to merely fix missing attribute from component's doc
55
+ this.minLength = null;
56
+ }
48
57
  /**
49
58
  * Decorate `<input>` element with common properties extended from text-field:
50
59
  * type="search" - always `search`
@@ -90,6 +99,12 @@ let SearchField = class SearchField extends TextField {
90
99
  `;
91
100
  }
92
101
  };
102
+ __decorate([
103
+ property({ type: Number, attribute: 'maxlength', reflect: true })
104
+ ], SearchField.prototype, "maxLength", void 0);
105
+ __decorate([
106
+ property({ type: Number, attribute: 'minlength', reflect: true })
107
+ ], SearchField.prototype, "minLength", void 0);
93
108
  __decorate([
94
109
  translate({ scope: 'ef-search-field' })
95
110
  ], SearchField.prototype, "t", void 0);
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "pattern",
10
10
  "description": "Set regular expression for input validation",
11
- "type": "string",
11
+ "type": "string | null",
12
12
  "default": "\"\""
13
13
  },
14
14
  {
@@ -80,7 +80,7 @@
80
80
  "name": "pattern",
81
81
  "attribute": "pattern",
82
82
  "description": "Set regular expression for input validation",
83
- "type": "string",
83
+ "type": "string | null",
84
84
  "default": "\"\""
85
85
  },
86
86
  {
@@ -12,7 +12,7 @@ Form control element for text.
12
12
  | `iconHasAction` | `icon-has-action` | `boolean` | false | Specify when icon need to be clickable |
13
13
  | `maxLength` | `maxlength` | `number \| null` | null | Set character max limit |
14
14
  | `minLength` | `minlength` | `number \| null` | null | Set character min limit |
15
- | `pattern` | `pattern` | `string` | "" | Set regular expression for input validation |
15
+ | `pattern` | `pattern` | `string \| null` | "" | Set regular expression for input validation |
16
16
  | `placeholder` | `placeholder` | `string` | "" | Set placeholder text |
17
17
  | `readonly` | `readonly` | `boolean` | false | Set readonly state |
18
18
  | `transparent` | `transparent` | `boolean` | false | Disables all other states and border/background styles. |
@@ -45,7 +45,7 @@ export declare class TextField extends FormFieldElement {
45
45
  /**
46
46
  * Set regular expression for input validation
47
47
  */
48
- pattern: string;
48
+ pattern: string | null;
49
49
  /**
50
50
  * Specify icon to display in input. Value can be icon name
51
51
  */
@@ -80,6 +80,11 @@ export declare class TextField extends FormFieldElement {
80
80
  * @returns shouldUpdate
81
81
  */
82
82
  protected updated(changedProperties: PropertyValues): void;
83
+ /**
84
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
85
+ * @returns true if there is at least one validation constraint
86
+ */
87
+ protected shouldValidate(): boolean;
83
88
  /**
84
89
  * Returns `true` if the element input is valid; otherwise, returns `false`.
85
90
  * @returns element input validity
@@ -6,7 +6,6 @@ import { isElementOverflown } from '@refinitiv-ui/utils/element.js';
6
6
  import '../icon/index.js';
7
7
  import { registerOverflowTooltip } from '../tooltip/index.js';
8
8
  import { VERSION } from '../version.js';
9
- const hasChanged = (newVal, oldVal) => oldVal === undefined ? false : newVal !== oldVal;
10
9
  /**
11
10
  * Form control element for text.
12
11
  *
@@ -114,7 +113,7 @@ let TextField = class TextField extends FormFieldElement {
114
113
  * @returns {void}
115
114
  */
116
115
  update(changedProperties) {
117
- if (changedProperties.has(FocusedPropertyKey) && !this.focused) {
116
+ if (changedProperties.has(FocusedPropertyKey) && !this.focused && this.shouldValidate()) {
118
117
  this.reportValidity();
119
118
  }
120
119
  super.update(changedProperties);
@@ -130,6 +129,16 @@ let TextField = class TextField extends FormFieldElement {
130
129
  this.syncInputValue();
131
130
  }
132
131
  }
132
+ /**
133
+ * Returns whether input of the element should be validated or not based on the existence of validation constraints
134
+ * @returns true if there is at least one validation constraint
135
+ */
136
+ shouldValidate() {
137
+ const hasMaxLength = this.maxLength !== null;
138
+ const hasMinLength = this.minLength !== null;
139
+ const hasPattern = !!this.pattern;
140
+ return hasMaxLength || hasMinLength || hasPattern;
141
+ }
133
142
  /**
134
143
  * Returns `true` if the element input is valid; otherwise, returns `false`.
135
144
  * @returns element input validity
@@ -186,7 +195,9 @@ let TextField = class TextField extends FormFieldElement {
186
195
  onPossibleValueChange(event) {
187
196
  const value = this.inputElement?.value || '';
188
197
  this.setValueAndNotify(value);
189
- this.reportValidity();
198
+ if (this.shouldValidate()) {
199
+ this.reportValidity();
200
+ }
190
201
  }
191
202
  /**
192
203
  * Fires event on `icon` click
@@ -246,7 +257,7 @@ let TextField = class TextField extends FormFieldElement {
246
257
  }
247
258
  };
248
259
  __decorate([
249
- property({ type: String, hasChanged })
260
+ property({ type: String })
250
261
  ], TextField.prototype, "pattern", void 0);
251
262
  __decorate([
252
263
  property({ type: String, reflect: true })
@@ -258,7 +269,7 @@ __decorate([
258
269
  property({ type: Number, attribute: 'maxlength', reflect: true })
259
270
  ], TextField.prototype, "maxLength", void 0);
260
271
  __decorate([
261
- property({ type: Number, attribute: 'minlength', reflect: true, hasChanged })
272
+ property({ type: Number, attribute: 'minlength', reflect: true })
262
273
  ], TextField.prototype, "minLength", void 0);
263
274
  TextField = __decorate([
264
275
  customElement('ef-text-field')
@@ -143,6 +143,10 @@ export declare class TimePicker extends ControlElement {
143
143
  * Seconds are automatically shown when `hh:mm:ss` time format is provided as a value.
144
144
  */
145
145
  private get isShowSeconds();
146
+ /**
147
+ * True if time value is complete, that is having all the required time segment
148
+ */
149
+ private get isCompleteValue();
146
150
  /**
147
151
  * Get hours taking into account AM/PM placeholder
148
152
  */
@@ -295,6 +299,7 @@ export declare class TimePicker extends ControlElement {
295
299
  /**
296
300
  * Changes a time segment value by a specified amount.
297
301
  * Also updates parent values when rolling through cycles.
302
+ * Incomplete value will update only segment without pre-populate value.
298
303
  * @param amount Amount to change by
299
304
  * @param segment Segment id
300
305
  * @returns {void}
@@ -8,7 +8,7 @@ import { state } from '@refinitiv-ui/core/decorators/state.js';
8
8
  import { guard } from '@refinitiv-ui/core/directives/guard.js';
9
9
  import '@refinitiv-ui/phrasebook/locale/en/time-picker.js';
10
10
  import { translate } from '@refinitiv-ui/translate';
11
- import { MILLISECONDS_IN_HOUR, MILLISECONDS_IN_MINUTE, MILLISECONDS_IN_SECOND, TimeFormat, addOffset, format, getFormat, isAM, isPM, isValidTime, padNumber, parse, toTimeSegment } from '@refinitiv-ui/utils/date.js';
11
+ import { MILLISECONDS_IN_HOUR, MILLISECONDS_IN_MINUTE, MILLISECONDS_IN_SECOND, MINUTES_IN_HOUR, SECONDS_IN_MINUTE, TimeFormat, addOffset, format, getFormat, isAM, isPM, isValidTime, padNumber, parse, toTimeSegment } from '@refinitiv-ui/utils/date.js';
12
12
  import '../number-field/index.js';
13
13
  import { VERSION } from '../version.js';
14
14
  var Segment;
@@ -23,6 +23,20 @@ const MAX_MINUTES = 59;
23
23
  const MAX_SECONDS = 59;
24
24
  const HOURS_IN_DAY = 24;
25
25
  const HOURS_OF_NOON = 12;
26
+ const SegmentMap = {
27
+ [Segment.HOURS]: {
28
+ milliseconds: MILLISECONDS_IN_HOUR,
29
+ cycle: HOURS_IN_DAY
30
+ },
31
+ [Segment.MINUTES]: {
32
+ milliseconds: MILLISECONDS_IN_MINUTE,
33
+ cycle: MINUTES_IN_HOUR
34
+ },
35
+ [Segment.SECONDS]: {
36
+ milliseconds: MILLISECONDS_IN_SECOND,
37
+ cycle: SECONDS_IN_MINUTE
38
+ }
39
+ };
26
40
  const Placeholder = {
27
41
  HOURS: '--',
28
42
  MINUTES: '--',
@@ -194,7 +208,7 @@ let TimePicker = TimePicker_1 = class TimePicker extends ControlElement {
194
208
  }
195
209
  }
196
210
  get value() {
197
- if (this.hours === null || this.minutes === null || (this.isShowSeconds && this.seconds === null)) {
211
+ if (!this.isCompleteValue) {
198
212
  return '';
199
213
  }
200
214
  return this.currentTimeString;
@@ -230,6 +244,12 @@ let TimePicker = TimePicker_1 = class TimePicker extends ControlElement {
230
244
  get isShowSeconds() {
231
245
  return this.showSeconds || this.valueWithSeconds;
232
246
  }
247
+ /**
248
+ * True if time value is complete, that is having all the required time segment
249
+ */
250
+ get isCompleteValue() {
251
+ return !(this.hours === null || this.minutes === null || (this.isShowSeconds && this.seconds === null));
252
+ }
233
253
  /**
234
254
  * Get hours taking into account AM/PM placeholder
235
255
  */
@@ -358,17 +378,6 @@ let TimePicker = TimePicker_1 = class TimePicker extends ControlElement {
358
378
  break;
359
379
  // no default
360
380
  }
361
- // Pre-populate empty segments
362
- if (value !== null) {
363
- if (segment === Segment.HOURS && this.minutes === null) {
364
- this.minutes = 0;
365
- }
366
- if (this.isShowSeconds &&
367
- this.seconds === null &&
368
- (segment === Segment.HOURS || segment === Segment.MINUTES)) {
369
- this.seconds = 0;
370
- }
371
- }
372
381
  // verify value again, as time segment validation
373
382
  // might fail in setter and previous value returned
374
383
  if (oldValue !== this.value) {
@@ -579,27 +588,24 @@ let TimePicker = TimePicker_1 = class TimePicker extends ControlElement {
579
588
  /**
580
589
  * Changes a time segment value by a specified amount.
581
590
  * Also updates parent values when rolling through cycles.
591
+ * Incomplete value will update only segment without pre-populate value.
582
592
  * @param amount Amount to change by
583
593
  * @param segment Segment id
584
594
  * @returns {void}
585
595
  */
586
596
  changeValueBy(amount, segment) {
587
- let offset = 0;
588
- switch (segment) {
589
- case Segment.HOURS:
590
- offset = this.hours === null ? 0 : amount * MILLISECONDS_IN_HOUR;
591
- break;
592
- case Segment.MINUTES:
593
- offset = this.minutes === null ? 0 : amount * MILLISECONDS_IN_MINUTE;
594
- break;
595
- case Segment.SECONDS:
596
- offset = this.seconds === null ? 0 : amount * MILLISECONDS_IN_SECOND;
597
- break;
598
- // no default
597
+ const segmentValue = this[segment];
598
+ const { milliseconds, cycle } = SegmentMap[segment];
599
+ if (this.isCompleteValue) {
600
+ const offset = segmentValue === null ? 0 : amount * milliseconds;
601
+ const value = addOffset(this.currentTimeString, offset);
602
+ this.setValueAndNotify(value);
603
+ this.selectedSegment = segment;
604
+ }
605
+ else {
606
+ // a segment cycle is added to support wrapping of amount with negative value
607
+ this[segment] = segmentValue === null ? 0 : (segmentValue + amount + cycle) % cycle;
599
608
  }
600
- const value = addOffset(this.currentTimeString, offset);
601
- this.setValueAndNotify(value);
602
- this.selectedSegment = segment;
603
609
  }
604
610
  /**
605
611
  * Gets the hours segment of the provided value
@@ -1,3 +1,4 @@
1
+ import escapeStringRegexp from 'escape-string-regexp';
1
2
  /**
2
3
  * Default filter used by tree
3
4
  * @param el Tree instance to filter
@@ -14,7 +15,7 @@ export const defaultFilter = (el) => {
14
15
  const getRegularExpressionOfQuery = () => {
15
16
  if (el.query !== query || !queryRegExp) {
16
17
  query = el.query || '';
17
- queryRegExp = new RegExp(query.replace(/(\W)/g, '\\$1'), 'i');
18
+ queryRegExp = new RegExp(escapeStringRegexp(query), 'i');
18
19
  }
19
20
  return queryRegExp;
20
21
  };
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = '7.8.0';
1
+ export const VERSION = '7.9.1';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@refinitiv-ui/elements",
3
- "version": "7.8.0",
3
+ "version": "7.9.1",
4
4
  "description": "Element Framework Elements",
5
5
  "author": "LSEG",
6
6
  "license": "Apache-2.0",
@@ -348,29 +348,30 @@
348
348
  "chartjs-adapter-date-fns": "^3.0.0",
349
349
  "d3-interpolate": "^3.0.1",
350
350
  "date-fns": "^2.29.3",
351
+ "escape-string-regexp": "^5.0.0",
351
352
  "lightweight-charts": "^4.1.0",
352
353
  "tslib": "^2.3.1"
353
354
  },
354
355
  "devDependencies": {
355
- "@refinitiv-ui/core": "^7.3.0",
356
- "@refinitiv-ui/demo-block": "^7.1.0",
356
+ "@refinitiv-ui/core": "^7.4.0",
357
+ "@refinitiv-ui/demo-block": "^7.1.1",
357
358
  "@refinitiv-ui/i18n": "^7.1.0",
358
359
  "@refinitiv-ui/phrasebook": "^7.1.0",
359
360
  "@refinitiv-ui/test-helpers": "^7.1.0",
360
- "@refinitiv-ui/translate": "^7.1.0",
361
+ "@refinitiv-ui/translate": "^7.1.1",
361
362
  "@refinitiv-ui/utils": "^7.2.0",
362
363
  "@types/d3-interpolate": "^3.0.1"
363
364
  },
364
365
  "peerDependencies": {
365
366
  "@refinitiv-ui/browser-sparkline": "^1.0.0 || ^2.0.0",
366
- "@refinitiv-ui/core": "^7.3.0",
367
+ "@refinitiv-ui/core": "^7.4.0",
367
368
  "@refinitiv-ui/i18n": "^7.1.0",
368
369
  "@refinitiv-ui/phrasebook": "^7.1.0",
369
- "@refinitiv-ui/translate": "^7.1.0",
370
+ "@refinitiv-ui/translate": "^7.1.1",
370
371
  "@refinitiv-ui/utils": "^7.2.0"
371
372
  },
372
373
  "publishConfig": {
373
374
  "access": "public"
374
375
  },
375
- "gitHead": "f0019ccc2f241a998c5e455b433c0e36720d5fe6"
376
+ "gitHead": "78ca6b3e5c4b3347663dc2abc713fa150c9ee638"
376
377
  }