jsl-ui 9.28.7 → 10.0.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.
Files changed (166) hide show
  1. package/docs/AutoSuggestComponent.md +17 -0
  2. package/docs/ButtonComponent.md +14 -0
  3. package/docs/CheckBoxComponent.md +12 -0
  4. package/docs/DateComponent.md +12 -0
  5. package/docs/DateRangeComponent.md +13 -0
  6. package/docs/DateTimeComponent.md +13 -0
  7. package/docs/DialogComponent.md +15 -0
  8. package/docs/ExpanderComponent.md +13 -0
  9. package/docs/FormComponent.md +15 -0
  10. package/docs/FormFieldComponent.md +15 -0
  11. package/docs/GridComponent.md +19 -0
  12. package/docs/InputComponent.md +15 -0
  13. package/docs/IntervalComponent.md +13 -0
  14. package/docs/LoadingComponent.md +12 -0
  15. package/docs/NavigationComponent.md +17 -0
  16. package/docs/Notification.md +14 -0
  17. package/docs/NotificationComponent.md +13 -0
  18. package/docs/NumberComponent.md +12 -0
  19. package/docs/OverlayComponent.md +12 -0
  20. package/docs/ProgressComponent.md +12 -0
  21. package/docs/README.md +24 -0
  22. package/docs/RibbonMenuComponent.md +14 -0
  23. package/docs/SelectComponent.md +15 -0
  24. package/docs/SplitterComponent.md +14 -0
  25. package/docs/StackPanelComponent.md +13 -0
  26. package/docs/TabsComponent.md +16 -0
  27. package/docs/TimeComponent.md +13 -0
  28. package/docs/TreeViewComponent.md +16 -0
  29. package/examples/showcase/checks-and-expanders.ts +163 -0
  30. package/examples/showcase/cultures.ts +39 -0
  31. package/examples/showcase/dates.ts +182 -0
  32. package/examples/showcase/dialogs.ts +184 -0
  33. package/examples/showcase/feedback-and-navigation.ts +174 -0
  34. package/examples/showcase/fields.ts +178 -0
  35. package/examples/showcase/fonts/Jost-Variable.ttf +0 -0
  36. package/examples/showcase/fonts/OFL-Jost.txt +93 -0
  37. package/examples/showcase/grids.ts +150 -0
  38. package/examples/showcase/index.html +60 -0
  39. package/examples/showcase/layout-and-navigation.ts +47 -0
  40. package/examples/showcase/nivona.css +98 -0
  41. package/examples/showcase/selects.ts +158 -0
  42. package/examples/showcase/showcase.css +231 -0
  43. package/examples/showcase/showcase.ts +214 -0
  44. package/examples/showcase/tabs.ts +161 -0
  45. package/examples/showcase/themes.css +83 -0
  46. package/examples/showcase/themes.ts +54 -0
  47. package/lib/components/IntervalComponent.d.ts +5 -0
  48. package/lib/components/IntervalComponent.js +29 -13
  49. package/lib/components/auto-suggest/AutoSuggestComponent.d.ts +11 -9
  50. package/lib/components/auto-suggest/AutoSuggestComponent.js +25 -38
  51. package/lib/components/button/ButtonComponent.d.ts +30 -1
  52. package/lib/components/button/ButtonComponent.js +85 -4
  53. package/lib/components/checkbox/CheckBoxComponent.d.ts +11 -1
  54. package/lib/components/checkbox/CheckBoxComponent.js +66 -56
  55. package/lib/components/checkbox/CheckBoxStyle.scss +72 -85
  56. package/lib/components/date/DateComponent.d.ts +10 -0
  57. package/lib/components/date/DateComponent.js +92 -44
  58. package/lib/components/date-range/DateRangeComponent.d.ts +14 -3
  59. package/lib/components/date-range/DateRangeComponent.js +96 -86
  60. package/lib/components/date-range/DateRangeStyle.scss +35 -11
  61. package/lib/components/date-time/DateTimeComponent.d.ts +8 -0
  62. package/lib/components/date-time/DateTimeComponent.js +64 -23
  63. package/lib/components/date-time/DateTimeStyle.scss +10 -7
  64. package/lib/components/dialog/DialogComponent.d.ts +21 -7
  65. package/lib/components/dialog/DialogComponent.js +179 -122
  66. package/lib/components/expander/ExpanderComponent.d.ts +15 -1
  67. package/lib/components/expander/ExpanderComponent.js +85 -64
  68. package/lib/components/expander/ExpanderStyle.scss +61 -47
  69. package/lib/components/form-field/FormFieldComponent.d.ts +45 -15
  70. package/lib/components/form-field/FormFieldComponent.js +249 -96
  71. package/lib/components/form-field/FormFieldStyle.scss +36 -87
  72. package/lib/components/form-field/create-control.d.ts +7 -0
  73. package/lib/components/form-field/create-control.js +48 -0
  74. package/lib/components/input/InputComponent.d.ts +18 -1
  75. package/lib/components/input/InputComponent.js +68 -93
  76. package/lib/components/loading/LoadingComponent.d.ts +9 -2
  77. package/lib/components/loading/LoadingComponent.js +13 -12
  78. package/lib/components/loading/LoadingStyle.css +19 -29
  79. package/lib/components/navigation/NavigationComponent.d.ts +34 -10
  80. package/lib/components/navigation/NavigationComponent.js +261 -33
  81. package/lib/components/navigation/NavigationStyle.scss +62 -226
  82. package/lib/components/notification/Notification.d.ts +37 -4
  83. package/lib/components/notification/Notification.js +160 -41
  84. package/lib/components/notification/Notification.scss +103 -19
  85. package/lib/components/number/NumberComponent.d.ts +16 -2
  86. package/lib/components/number/NumberComponent.js +54 -53
  87. package/lib/components/overlay/OverlayComponent.d.ts +13 -7
  88. package/lib/components/overlay/OverlayComponent.js +46 -114
  89. package/lib/components/overlay/overlay.css +18 -57
  90. package/lib/components/progress/ProgressComponent.d.ts +1 -0
  91. package/lib/components/progress/ProgressComponent.js +6 -6
  92. package/lib/components/progress/ProgressStyle.scss +5 -15
  93. package/lib/components/ribbon-menu/RibbonMenuComponent.js +2 -2
  94. package/lib/components/ribbon-menu/RibbonMenuStyle.scss +6 -76
  95. package/lib/components/select/SelectComponent.d.ts +33 -3
  96. package/lib/components/select/SelectComponent.js +312 -278
  97. package/lib/components/select/SelectDDAreaComponent.d.ts +13 -7
  98. package/lib/components/select/SelectDDAreaComponent.js +215 -256
  99. package/lib/components/select/SelectStyle.scss +204 -186
  100. package/lib/components/slider/nouislider.css +40 -54
  101. package/lib/components/stack-panel/SplitterComponent.d.ts +19 -3
  102. package/lib/components/stack-panel/SplitterComponent.js +94 -111
  103. package/lib/components/stack-panel/SplitterStyle.scss +9 -45
  104. package/lib/components/stack-panel/StackPanelComponent.js +3 -3
  105. package/lib/components/stack-panel/StackPanelStyle.scss +10 -52
  106. package/lib/components/tabs/TabsComponent.d.ts +17 -1
  107. package/lib/components/tabs/TabsComponent.js +247 -123
  108. package/lib/components/tabs/TabsStyle.scss +138 -75
  109. package/lib/components/time/TimeComponent.d.ts +5 -0
  110. package/lib/components/time/TimeComponent.js +61 -69
  111. package/lib/components/time/TimeComponent.scss +4 -4
  112. package/lib/components/tree-view/TreeViewComponent.d.ts +10 -4
  113. package/lib/components/tree-view/TreeViewComponent.js +65 -32
  114. package/lib/components/tree-view/TreeViewStyle.scss +12 -96
  115. package/lib/core/date.d.ts +2 -0
  116. package/lib/core/date.js +6 -0
  117. package/lib/core/jq.js +11 -8
  118. package/lib/grid/slick-default-theme.css +107 -31
  119. package/lib/grid/slick.creator.js +23 -5
  120. package/lib/grid/slick.formatters.js +4 -3
  121. package/lib/grid/slick.grid.css +38 -26
  122. package/lib/grid/slick.grid.d.ts +1 -0
  123. package/lib/grid/slick.grid.js +2 -3
  124. package/lib/grid.css +3413 -454
  125. package/lib/index.css +2500 -1031
  126. package/lib/index.css.map +1 -1
  127. package/lib/index.d.ts +1 -0
  128. package/lib/index.js +1 -1
  129. package/lib/index.js.map +1 -1
  130. package/lib/interaction/moveable.d.ts +1 -0
  131. package/lib/interaction/moveable.js +8 -0
  132. package/lib/interaction/resizable.d.ts +1 -0
  133. package/lib/interaction/resizable.js +9 -0
  134. package/lib/ui/auto.suggest.css +31 -14
  135. package/lib/ui/auto.suggest.d.ts +1 -0
  136. package/lib/ui/auto.suggest.js +88 -18
  137. package/lib/ui/base.css +2 -48
  138. package/lib/ui/button.css +134 -0
  139. package/lib/ui/date-input.css +11 -0
  140. package/lib/ui/date.picker/css/tiny-date-picker.css +124 -325
  141. package/lib/ui/date.picker/date-picker-options.js +4 -3
  142. package/lib/ui/date.picker/lib/date-manip.js +9 -0
  143. package/lib/ui/date.picker/mode/base-mode.d.ts +2 -1
  144. package/lib/ui/date.picker/mode/base-mode.js +112 -22
  145. package/lib/ui/date.picker/mode/dropdown-mode.d.ts +2 -4
  146. package/lib/ui/date.picker/mode/dropdown-mode.js +29 -42
  147. package/lib/ui/date.picker/mode/index.d.ts +2 -1
  148. package/lib/ui/date.picker/mode/modal-mode.d.ts +2 -1
  149. package/lib/ui/date.picker/mode/modal-mode.js +4 -2
  150. package/lib/ui/date.picker/mode/permanent-mode.d.ts +2 -1
  151. package/lib/ui/date.picker/views/day-picker.js +24 -15
  152. package/lib/ui/date.picker/views/month-picker.js +1 -1
  153. package/lib/ui/date.picker/views/year-picker.js +3 -2
  154. package/lib/ui/date.picker.d.ts +2 -1
  155. package/lib/ui/dialog.css +144 -108
  156. package/lib/ui/dialog.d.ts +19 -1
  157. package/lib/ui/dialog.js +178 -60
  158. package/lib/ui/input.css +35 -0
  159. package/lib/ui/number.input.js +50 -37
  160. package/lib/ui/theme.css +28 -0
  161. package/package.json +12 -8
  162. package/lib/components/drop-down/DropDownComponent.d.ts +0 -27
  163. package/lib/components/drop-down/DropDownComponent.js +0 -60
  164. package/lib/components/expander/OldExpanderStyle.scss +0 -37
  165. package/lib/ui/drop.down.d.ts +0 -52
  166. package/lib/ui/drop.down.js +0 -2112
@@ -1,138 +1,291 @@
1
1
  import "./FormFieldStyle.scss";
2
- import { DatePicker } from "../../ui/date.picker";
3
- import { NumberInput } from "../../ui/number.input";
4
2
  import { helper } from "../../core/helper";
5
- import { AutoSuggest } from "../../ui/auto.suggest";
3
+ import { createFormFieldControl } from "./create-control";
6
4
  export class FormFieldComponent {
7
5
  constructor(options) {
8
6
  this.options = options;
7
+ this.validated = false;
8
+ this.disposed = false;
9
+ this.syncQueued = false;
10
+ this.hasPendingValue = false;
11
+ this.ownedInvalid = false;
12
+ this.onFocusEvent = (event) => {
13
+ var _a, _b, _c;
14
+ this.dom.classList.add("form-field--is-active");
15
+ (_b = (_a = this.options).onFocus) === null || _b === void 0 ? void 0 : _b.call(_a, event, this.callbackNode(event));
16
+ if (this.options.onFocus) {
17
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.refresh();
18
+ }
19
+ };
20
+ this.onBlurEvent = (event) => {
21
+ var _a, _b, _c;
22
+ this.dom.classList.remove("form-field--is-active");
23
+ (_b = (_a = this.options).onBlur) === null || _b === void 0 ? void 0 : _b.call(_a, event, this.callbackNode(event));
24
+ if (this.options.onBlur) {
25
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.refresh();
26
+ }
27
+ this.queueSync();
28
+ };
29
+ this.onInputEvent = (event) => {
30
+ var _a, _b, _c;
31
+ (_b = (_a = this.options).onInput) === null || _b === void 0 ? void 0 : _b.call(_a, event, this.callbackNode(event));
32
+ if (this.options.onInput) {
33
+ (_c = this.renderer) === null || _c === void 0 ? void 0 : _c.refresh();
34
+ }
35
+ this.queueSync();
36
+ };
37
+ this.onChangeEvent = () => { if (this.validated) {
38
+ this.validate();
39
+ } this.queueSync(); };
40
+ this.options = { ...options };
9
41
  this.id = options.id || helper.newDomGuid();
10
- this.type = this.options.type === "password" ? "password" : "text";
42
+ if (options.control) {
43
+ this.control = options.control;
44
+ }
45
+ else {
46
+ const legacy = createFormFieldControl(this.options, this.id);
47
+ this.control = legacy.control;
48
+ this.legacySetter = legacy.setValue;
49
+ }
50
+ if (options.control && options.value !== undefined) {
51
+ this.setValue(options.value);
52
+ }
53
+ if (!options.control && options.value != null) {
54
+ // Retain the legacy raw string, including a draft that cannot yet be parsed.
55
+ this.pendingValue = options.value;
56
+ this.hasPendingValue = true;
57
+ }
11
58
  }
12
59
  render() {
13
60
  var _a, _b;
61
+ this.queueSync();
14
62
  return {
15
- tag: "div",
16
- attr: { class: "form-field " + (this.options.value ? "form-field--is-filled " : "") + ((_a = this.options.class) !== null && _a !== void 0 ? _a : "") },
17
- children: [{
18
- tag: "div",
19
- attr: { class: "form-field__control" + (this.validationMessage ? " failed__valid" : "") },
20
- children: [
21
- {
22
- tag: "label",
23
- attr: { for: this.id, class: "form-field__label" },
24
- content: this.options.label +
25
- (this.options.required ? " *" : "") +
26
- (this.validationMessage ? (" " + ((_b = this.validationMessage) !== null && _b !== void 0 ? _b : "")) : "")
27
- },
28
- {
29
- tag: "input",
30
- attr: {
31
- id: this.id,
32
- type: this.type,
33
- value: this.options.value,
34
- maxLength: this.options.maxLength,
35
- class: "form-field__input",
36
- blur: this.setInActive,
37
- focus: this.setActive,
38
- input: this.onInput,
39
- disabled: this.options.disabled ? "disabled" : undefined
40
- }
41
- }
42
- ]
43
- }]
63
+ tag: "div", attr: {
64
+ class: "form-field " + (this.options.labelPosition === "floating" ? "form-field--floating " : "") +
65
+ (this.validationMessage ? "form-field--invalid " : "") + ((_a = this.options.class) !== null && _a !== void 0 ? _a : ""),
66
+ style: this.options.style
67
+ }, children: [
68
+ { tag: "label", attr: {
69
+ for: (_b = this.options.controlId) !== null && _b !== void 0 ? _b : this.id, id: this.id + "-label", class: "form-field__label"
70
+ }, children: [
71
+ { tag: "span", content: this.options.label },
72
+ { tag: "span", content: " *", attr: { class: "form-field__required", "aria-hidden": "true", hidden: this.options.required ? undefined : "hidden" } }
73
+ ] },
74
+ { tag: "fieldset", attr: {
75
+ class: "form-field__control", disabled: this.options.disabled ? "disabled" : undefined
76
+ }, children: [this.control] },
77
+ { tag: "div", content: this.options.description, attr: {
78
+ id: this.id + "-description", class: "form-field__description", hidden: this.options.description ? undefined : "hidden"
79
+ } },
80
+ { tag: "div", content: this.validationMessage, attr: {
81
+ id: this.id + "-error", class: "form-field__error", role: "status", "aria-live": "polite",
82
+ hidden: this.validationMessage ? undefined : "hidden"
83
+ } }
84
+ ]
44
85
  };
45
86
  }
87
+ onInit(renderer) { this.renderer = renderer; }
46
88
  onCreate(node) {
47
- const InputDom = node.dom.firstElementChild.children[1];
48
- if (this.options.type === "number") {
49
- NumberInput(InputDom, this.options.numberOptions);
50
- }
51
- else if (this.options.type === "date") {
52
- this.datepickerRef = DatePicker(InputDom, this.options.dateOptions);
89
+ this.dom = node.dom;
90
+ this.disposed = false;
91
+ this.dom.addEventListener("focus", this.onFocusEvent, true);
92
+ this.dom.addEventListener("blur", this.onBlurEvent, true);
93
+ this.dom.addEventListener("input", this.onInputEvent);
94
+ this.dom.addEventListener("change", this.onChangeEvent);
95
+ this.syncDom();
96
+ }
97
+ onRemove() {
98
+ var _a, _b, _c, _d;
99
+ this.disposed = true;
100
+ (_a = this.dom) === null || _a === void 0 ? void 0 : _a.removeEventListener("focus", this.onFocusEvent, true);
101
+ (_b = this.dom) === null || _b === void 0 ? void 0 : _b.removeEventListener("blur", this.onBlurEvent, true);
102
+ (_c = this.dom) === null || _c === void 0 ? void 0 : _c.removeEventListener("input", this.onInputEvent);
103
+ (_d = this.dom) === null || _d === void 0 ? void 0 : _d.removeEventListener("change", this.onChangeEvent);
104
+ this.removeDecorations();
105
+ this.input = null;
106
+ this.dom = null;
107
+ }
108
+ getControl() { return this.control; }
109
+ getValue() {
110
+ var _a, _b;
111
+ if (this.hasPendingValue) {
112
+ return this.pendingValue;
53
113
  }
54
- else if (this.options.type === "autosuggest") {
55
- AutoSuggest(InputDom, this.options.autoSuggestOptions);
114
+ const control = this.control;
115
+ if (typeof control.getValue === "function") {
116
+ return control.getValue();
56
117
  }
118
+ return ((_b = (_a = this.input) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : this.options.value);
57
119
  }
58
- onRemove(node) {
59
- if (this.datepickerRef != null) {
60
- this.datepickerRef.destroy();
120
+ setValue(value) {
121
+ const control = this.control;
122
+ if (this.legacySetter) {
123
+ this.legacySetter(value);
124
+ }
125
+ else if (typeof control.setValue === "function") {
126
+ control.setValue(value);
61
127
  }
128
+ if (!this.options.control || typeof control.setValue !== "function") {
129
+ this.pendingValue = value;
130
+ this.hasPendingValue = true;
131
+ }
132
+ this.syncDom();
133
+ this.queueSync();
62
134
  }
63
135
  validate() {
136
+ var _a, _b, _c, _d;
64
137
  const value = this.getValue();
65
- if (this.options.required && !value) {
66
- this.validationMessage = " ";
67
- return false;
68
- }
69
- if (this.options.onValidate) {
70
- const validationResult = this.options.onValidate(value);
71
- if (validationResult === false) {
72
- this.validationMessage = " ";
73
- return false;
138
+ const input = this.input;
139
+ const empty = value == null || typeof value === "string" && value.trim() === "" || Array.isArray(value) && value.length === 0;
140
+ this.validated = true;
141
+ this.validationMessage = null;
142
+ if (!this.options.disabled && !(input === null || input === void 0 ? void 0 : input.matches(":disabled"))) {
143
+ if (this.options.required && empty) {
144
+ this.validationMessage = (_a = this.options.requiredMessage) !== null && _a !== void 0 ? _a : "This field is required.";
145
+ }
146
+ else if (typeof this.control.isValid === "function" && !this.control.isValid() ||
147
+ (input === null || input === void 0 ? void 0 : input.validity) && !input.validity.valid) {
148
+ this.validationMessage = (_b = this.options.invalidMessage) !== null && _b !== void 0 ? _b : "Enter a valid value.";
74
149
  }
75
- if (validationResult !== true) {
76
- this.validationMessage = validationResult;
77
- return false;
150
+ else if (this.options.onValidate) {
151
+ const result = this.options.onValidate(value);
152
+ if (result !== true && result !== undefined) {
153
+ this.validationMessage = typeof result === "string" && result.trim() ? result : (_c = this.options.invalidMessage) !== null && _c !== void 0 ? _c : "Enter a valid value.";
154
+ }
78
155
  }
79
156
  }
80
- this.validationMessage = null;
81
- return true;
157
+ this.syncDom();
158
+ (_d = this.renderer) === null || _d === void 0 ? void 0 : _d.refresh();
159
+ return !this.validationMessage;
82
160
  }
83
- getValue() {
84
- var _a;
85
- return (_a = document.getElementById(this.id)) === null || _a === void 0 ? void 0 : _a.value;
161
+ queueSync() {
162
+ if (this.syncQueued) {
163
+ return;
164
+ }
165
+ this.syncQueued = true;
166
+ Promise.resolve().then(() => { this.syncQueued = false; if (!this.disposed) {
167
+ this.syncDom();
168
+ } });
86
169
  }
87
- setValue(value) {
88
- const el = document.getElementById(this.id);
89
- if (el == null) {
170
+ syncDom() {
171
+ var _a, _b, _c, _d;
172
+ if (!this.dom) {
173
+ return;
174
+ }
175
+ const container = this.dom.querySelector(".form-field__control");
176
+ const explicit = this.options.controlId ? document.getElementById(this.options.controlId) : null;
177
+ const target = explicit && container.contains(explicit) ? explicit :
178
+ container.querySelector('input:not([type=hidden]),textarea,select,button[role=combobox],[role=combobox],[tabindex]');
179
+ if (target !== this.input) {
180
+ this.removeDecorations();
181
+ this.input = target;
182
+ this.originalInvalid = target === null || target === void 0 ? void 0 : target.getAttribute("aria-invalid");
183
+ this.originalRequired = target === null || target === void 0 ? void 0 : target.getAttribute("required");
184
+ this.originalAriaRequired = target === null || target === void 0 ? void 0 : target.getAttribute("aria-required");
185
+ this.originalLabelledBy = target === null || target === void 0 ? void 0 : target.getAttribute("aria-labelledby");
186
+ }
187
+ if (!target) {
90
188
  return;
91
189
  }
92
- el.value = value || "";
93
- if (value) {
94
- el.parentElement.classList.add("form-field--is-filled");
190
+ target.id = (_b = (_a = this.options.controlId) !== null && _a !== void 0 ? _a : this.options.id) !== null && _b !== void 0 ? _b : (target.id || this.id);
191
+ this.dom.querySelector(".form-field__label").htmlFor = target.id;
192
+ if (!("labels" in target) && !target.hasAttribute("aria-labelledby")) {
193
+ target.setAttribute("aria-labelledby", this.id + "-label");
194
+ }
195
+ if (this.hasPendingValue && "value" in target) {
196
+ target.value = this.pendingValue == null ? "" : String(this.pendingValue);
197
+ this.hasPendingValue = false;
198
+ }
199
+ if (this.options.maxLength != null && "maxLength" in target) {
200
+ target.maxLength = this.options.maxLength;
201
+ }
202
+ if (this.options.required) {
203
+ target.setAttribute("aria-required", "true");
204
+ if ("required" in target) {
205
+ target.required = true;
206
+ }
207
+ }
208
+ const descriptions = ((_c = target.getAttribute("aria-describedby")) !== null && _c !== void 0 ? _c : "").split(/\s+/).filter(id => id && id !== this.id + "-description" && id !== this.id + "-error");
209
+ if (this.options.description) {
210
+ descriptions.push(this.id + "-description");
211
+ }
212
+ if (this.validationMessage) {
213
+ descriptions.push(this.id + "-error");
214
+ }
215
+ if (descriptions.length) {
216
+ target.setAttribute("aria-describedby", descriptions.join(" "));
95
217
  }
96
218
  else {
97
- el.parentElement.classList.remove("form-field--is-filled");
219
+ target.removeAttribute("aria-describedby");
98
220
  }
99
- }
100
- setInActive(evt, node) {
101
- const formField = node.dom.parentElement.parentElement;
102
- if (formField == null) {
103
- return;
221
+ if (this.validationMessage) {
222
+ target.setAttribute("aria-invalid", "true");
223
+ this.ownedInvalid = true;
104
224
  }
105
- setTimeout(() => {
106
- formField.classList.remove("form-field--is-active");
107
- if (node.dom.value === "") {
108
- formField.classList.remove("form-field--is-filled");
225
+ else if (this.ownedInvalid) {
226
+ if (this.originalInvalid == null) {
227
+ target.removeAttribute("aria-invalid");
109
228
  }
110
229
  else {
111
- formField.classList.add("form-field--is-filled");
230
+ target.setAttribute("aria-invalid", this.originalInvalid);
112
231
  }
113
- }, 250);
114
- if (this.options.onBlur) {
115
- this.options.onBlur(evt, node);
116
- return;
232
+ this.ownedInvalid = false;
117
233
  }
118
- return false;
234
+ const value = this.getValue();
235
+ this.dom.classList.toggle("form-field--is-filled", value != null && (!Array.isArray(value) || value.length > 0) && String(value) !== "");
236
+ this.dom.classList.toggle("form-field--invalid", !!this.validationMessage);
237
+ const error = this.dom.querySelector(".form-field__error");
238
+ error.textContent = (_d = this.validationMessage) !== null && _d !== void 0 ? _d : "";
239
+ error.hidden = !this.validationMessage;
119
240
  }
120
- setActive(evt, node) {
121
- const formField = node.dom.parentElement.parentElement;
122
- if (formField == null) {
241
+ removeDecorations() {
242
+ var _a;
243
+ if (!this.input) {
123
244
  return;
124
245
  }
125
- formField.classList.add("form-field--is-active");
126
- if (this.options.onFocus) {
127
- this.options.onFocus(evt, node);
128
- return;
246
+ const ids = ((_a = this.input.getAttribute("aria-describedby")) !== null && _a !== void 0 ? _a : "").split(/\s+/).filter(id => id && id !== this.id + "-description" && id !== this.id + "-error");
247
+ if (ids.length) {
248
+ this.input.setAttribute("aria-describedby", ids.join(" "));
129
249
  }
130
- return false;
131
- }
132
- onInput(evt, node) {
133
- if (this.options.onInput) {
134
- this.options.onInput(evt, node);
135
- return;
250
+ else {
251
+ this.input.removeAttribute("aria-describedby");
252
+ }
253
+ if (this.ownedInvalid) {
254
+ if (this.originalInvalid == null) {
255
+ this.input.removeAttribute("aria-invalid");
256
+ }
257
+ else {
258
+ this.input.setAttribute("aria-invalid", this.originalInvalid);
259
+ }
136
260
  }
261
+ this.ownedInvalid = false;
262
+ if (this.options.required) {
263
+ if (this.originalAriaRequired == null) {
264
+ this.input.removeAttribute("aria-required");
265
+ }
266
+ else {
267
+ this.input.setAttribute("aria-required", this.originalAriaRequired);
268
+ }
269
+ if ("required" in this.input) {
270
+ if (this.originalRequired == null) {
271
+ this.input.removeAttribute("required");
272
+ }
273
+ else {
274
+ this.input.setAttribute("required", this.originalRequired);
275
+ }
276
+ }
277
+ }
278
+ if (this.input.getAttribute("aria-labelledby") === this.id + "-label") {
279
+ if (this.originalLabelledBy == null) {
280
+ this.input.removeAttribute("aria-labelledby");
281
+ }
282
+ else {
283
+ this.input.setAttribute("aria-labelledby", this.originalLabelledBy);
284
+ }
285
+ }
286
+ }
287
+ callbackNode(event) {
288
+ const target = event.target;
289
+ return { tag: target.tagName.toLowerCase(), dom: target, attr: { id: target.id } };
137
290
  }
138
291
  }
@@ -1,87 +1,36 @@
1
-
2
- $primary-color: #3B99FF;
3
- $animation-duration: 0.4s;
4
-
5
- @mixin label-active() {
6
- font-size: 0.7em;
7
- transform: translateY(-14px);
8
- }
9
-
10
- .form-field {
11
- display: block;
12
- margin-bottom: 16px;
13
-
14
- .failed__valid {
15
- .form-field__input {
16
- border-color: #cc0000!important;
17
- }
18
- .form-field__label {
19
- color: #aa0000!important;
20
- }
21
- }
22
-
23
- &--is-active {
24
- .form-field__control {
25
- &::after {
26
- border-bottom: 2px solid $primary-color;
27
- transform: scaleX(150);
28
- }
29
- }
30
- .form-field__label {
31
- color: $primary-color;
32
- @include label-active();
33
- }
34
- }
35
- &--is-filled {
36
- .form-field__label {
37
- @include label-active();
38
- }
39
- }
40
- }
41
- .form-field__label {
42
- color:#606060;
43
- display: block;
44
- font-weight: normal;
45
- left: 0;
46
- margin: 0;
47
- padding: 1rem 0.5rem 0 ;
48
- position: absolute;
49
- top: 0;
50
- transition: all $animation-duration;
51
- width: 100%;
52
- }
53
- .form-field__control {
54
- background: #f6f6f6;
55
- border-radius: 0.3rem 0.3rem 0 0;
56
- overflow: hidden;
57
- position: relative;
58
- width: 100%;
59
-
60
- &::after {
61
- border-bottom: 2px solid $primary-color;
62
- bottom: 0;
63
- content: "";
64
- display: block;
65
- left: 0;
66
- margin: 0 auto;
67
- position: absolute;
68
- right: 0;
69
- transform: scaleX(0);
70
- transition: all $animation-duration;
71
- width: 1%;
72
- }
73
- }
74
- .form-field__input,
75
- .form-field__textarea {
76
- box-sizing: border-box;
77
- border:none;
78
- appearance: none;
79
- background: transparent;
80
- border-bottom: 1px solid #999;
81
- color: #333;
82
- display: block;
83
- margin-top: 1.3rem;
84
- outline: 0;
85
- padding: 0 0.3rem 0.2rem 0.3rem;
86
- width: 100%;
87
- }
1
+ @import "../../ui/theme.css";
2
+
3
+ .form-field {
4
+ position: relative;
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: .375rem;
8
+ min-width: 0;
9
+ max-width: 100%;
10
+ margin: 0 0 1rem;
11
+ color: var(--jsl-color-text);
12
+ font: inherit;
13
+ font-size: .875rem;
14
+ }
15
+ .form-field__label { display: block; color: var(--jsl-color-text-secondary); font-size: .75rem; font-weight: 500; line-height: 1.5; }
16
+ .form-field__required { color: var(--jsl-color-text-muted); }
17
+ .form-field__required[hidden] { display: none; }
18
+ .form-field__control { display: block; min-width: 0; border: 0; margin: 0; padding: 0; }
19
+ .form-field__control > .jsl-input, .form-field__control > .jsl-date-input,
20
+ .form-field__control > .select-comp, .form-field__control > .date-time-comp { width: 100%; }
21
+ .form-field__description, .form-field__error { color: var(--jsl-color-text-muted); font-size: .75rem; line-height: 1.5; }
22
+ .form-field__error { color: var(--jsl-color-danger); }
23
+ .form-field__description[hidden], .form-field__error[hidden] { display: none; }
24
+ .form-field--invalid > .form-field__label { color: var(--jsl-color-danger); }
25
+ .form-field--invalid > .form-field__control .sel-expander { border-color: var(--jsl-color-danger); }
26
+ .form-field--floating { padding-top: .5rem; }
27
+ .form-field--floating > .form-field__label {
28
+ position: absolute;
29
+ top: 0;
30
+ left: .625rem;
31
+ z-index: 1;
32
+ max-width: calc(100% - 1.25rem);
33
+ padding: 0 .25rem;
34
+ background: var(--jsl-color-surface);
35
+ }
36
+ .form-field:has(.form-field__control:disabled) > .form-field__label { color: var(--jsl-color-disabled-text); }
@@ -0,0 +1,7 @@
1
+ import { IJSLComponent } from "jsl-render";
2
+ import type { IFormFieldOptions } from "./FormFieldComponent";
3
+ /** Compatibility factory; editing behavior lives in the individual controls. */
4
+ export declare function createFormFieldControl(options: IFormFieldOptions<any>, id: string): {
5
+ control: IJSLComponent;
6
+ setValue(value: any): void;
7
+ };
@@ -0,0 +1,48 @@
1
+ import { InputComponent } from "../input/InputComponent";
2
+ import { NumberComponent } from "../number/NumberComponent";
3
+ import { DateComponent } from "../date/DateComponent";
4
+ import { AutoSuggestComponent } from "../auto-suggest/AutoSuggestComponent";
5
+ import { date } from "../../core/date";
6
+ import { numeric } from "../../core/numeric";
7
+ /** Compatibility factory; editing behavior lives in the individual controls. */
8
+ export function createFormFieldControl(options, id) {
9
+ var _a, _b, _c;
10
+ const common = { id, enabled: !options.disabled, ...(options.placeholder != null ? { placeholder: options.placeholder } : {}) };
11
+ const text = options.value == null ? "" : String(options.value);
12
+ switch (options.type) {
13
+ case "number": {
14
+ const control = new NumberComponent({
15
+ ...options.numberOptions, ...common,
16
+ enabled: !options.disabled && ((_a = options.numberOptions) === null || _a === void 0 ? void 0 : _a.enabled) !== false,
17
+ value: options.value != null ? numeric.parse(text) : (_b = options.numberOptions) === null || _b === void 0 ? void 0 : _b.value
18
+ });
19
+ return { control, setValue: value => control.setValue(value == null ? undefined : numeric.parse(String(value))) };
20
+ }
21
+ case "date": {
22
+ const parse = (value) => {
23
+ var _a, _b;
24
+ try {
25
+ return value ? ((_b = (_a = options.dateOptions) === null || _a === void 0 ? void 0 : _a.parse) !== null && _b !== void 0 ? _b : date.parse)(String(value)) : null;
26
+ }
27
+ catch (_c) {
28
+ return null;
29
+ }
30
+ };
31
+ const control = new DateComponent({ ...options.dateOptions, ...common, value: parse(text) });
32
+ return { control, setValue: value => control.setValue(parse(value)) };
33
+ }
34
+ case "autosuggest": {
35
+ const control = new AutoSuggestComponent({
36
+ source: (term, suggest) => suggest([]),
37
+ ...options.autoSuggestOptions, ...common, value: text, maxLength: options.maxLength
38
+ });
39
+ return { control, setValue: value => control.setValue(value !== null && value !== void 0 ? value : "") };
40
+ }
41
+ default: {
42
+ const control = new InputComponent({
43
+ ...common, type: (_c = options.type) !== null && _c !== void 0 ? _c : "text", value: text, maxLength: options.maxLength
44
+ });
45
+ return { control, setValue: value => control.setValue(value !== null && value !== void 0 ? value : "") };
46
+ }
47
+ }
48
+ }
@@ -1,4 +1,5 @@
1
- import { IJSLComponent, IJSLVNode } from "jsl-render";
1
+ import "../../ui/input.css";
2
+ import { IJSLComponent, IJSLVNode, JSLRender } from "jsl-render";
2
3
  import { EventHandler } from "../../interaction/eventhandler";
3
4
  import { IDataConverter } from "../../interaction/dataconverter";
4
5
  export interface IInputOptions<T = any> {
@@ -17,17 +18,33 @@ export interface IInputOptions<T = any> {
17
18
  bindOnInput?: boolean;
18
19
  maxLength?: number;
19
20
  type?: "input" | "text" | "password" | "textarea" | "color" | "time" | "email" | "month" | "number" | "search" | "tel" | "url" | "week";
21
+ unstyled?: boolean;
22
+ ariaLabel?: string;
23
+ readOnly?: boolean;
24
+ rows?: number;
25
+ autocomplete?: string;
20
26
  }
21
27
  export declare class InputComponent<T = any> implements IJSLComponent {
22
28
  private options;
23
29
  private currentDom;
30
+ private modelValue;
31
+ private initialTextValue;
32
+ protected renderer: JSLRender;
24
33
  get onChange(): EventHandler<string>;
25
34
  get onInput(): EventHandler<string>;
26
35
  constructor(options: IInputOptions<T>);
27
36
  render(): IJSLVNode;
28
37
  getValue(): string;
38
+ /** Updates the input and writable binding without raising events. */
29
39
  setValue(value: string): void;
40
+ focus(): void;
41
+ onInit(renderer: JSLRender): void;
30
42
  onCreate(node: IJSLVNode): void;
43
+ onUpdate(node: IJSLVNode): void;
44
+ onRemove(): void;
45
+ private hasBinding;
46
+ private readModel;
47
+ private writeModel;
31
48
  private raiseChangeEvent;
32
49
  private raiseInputEvent;
33
50
  }