@yamato-daiwa/frontend-vue 0.2.0 → 0.3.0-alpha.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.

Potentially problematic release.


This version of @yamato-daiwa/frontend-vue might be problematic. Click here for more details.

Files changed (60) hide show
  1. package/.idea/codeStyles/codeStyleConfig.xml +5 -0
  2. package/.idea/inspectionProfiles/Project_Default.xml +5 -1
  3. package/README.md +5 -0
  4. package/Source/Functions/getElementByVueReference.ts +105 -8
  5. package/Source/GUI_Components/AdmonitionBlock/AdmonitionBlock.vue +67 -0
  6. package/Source/GUI_Components/AdmonitionBlock/AdmonitionBlock.vue.d.ts +48 -0
  7. package/Source/GUI_Components/AdmonitionBlock/{AdmonitionBlock.vue.ts → AdmonitionBlockLogic.vue.ts} +83 -59
  8. package/Source/GUI_Components/Badge/Badge.vue.ts +98 -63
  9. package/Source/GUI_Components/Badge/LoadingPlaceholder/Badge-LoadingPlaceholder.vue.ts +51 -32
  10. package/Source/GUI_Components/Controls/Buttons/Closing/ClosingButton.vue.pug +1 -0
  11. package/Source/GUI_Components/Controls/Buttons/Closing/ClosingButton.vue.ts +224 -0
  12. package/Source/GUI_Components/Controls/Buttons/HamburgerMenu/HamburgerMenuButton-ForInheritance.vue.ts +253 -0
  13. package/Source/GUI_Components/Controls/Buttons/HamburgerMenu/HamburgerMenuButton.vue +24 -0
  14. package/Source/GUI_Components/Controls/Buttons/HamburgerMenu/HamburgerMenuButton.vue.d.ts +45 -0
  15. package/Source/GUI_Components/Controls/Buttons/HamburgerMenu/HamburgerMenuButton.vue.pug +0 -0
  16. package/Source/GUI_Components/Controls/Buttons/Plain/Button.vue.ts +217 -105
  17. package/Source/GUI_Components/Controls/Buttons/Plain/LoadingPlaceholder/Button-LoadingPlaceholder.vue.ts +38 -30
  18. package/Source/GUI_Components/Controls/ValidatableControlShell/ValidatableControlShell.vue.pug +33 -20
  19. package/Source/GUI_Components/Controls/ValidatableControlShell/ValidatableControlShell.vue.ts +303 -121
  20. package/Source/GUI_Components/Controls/Validatables/InputtableControl.vue.ts +233 -0
  21. package/Source/GUI_Components/Controls/Validatables/TextBox/TextBox.vue.pug +38 -0
  22. package/Source/GUI_Components/Controls/Validatables/TextBox/TextBox.vue.ts +538 -96
  23. package/Source/GUI_Components/Controls/Validatables/ValidatableControl.ts +63 -54
  24. package/Source/GUI_Components/Controls/Validatables/ValidatableControlsGroup.ts +176 -0
  25. package/Source/GUI_Components/OverflowSafeSingleLineLabel.vue +9 -2
  26. package/Source/GUI_Components/ThemesShowcase.vue +10 -5
  27. package/Source/GUI_Components/YDF_ComponentsCoordinator.ts +164 -5
  28. package/Source/GUI_Components/_Decorators/AccessibleFromTemplateAsNonReactive.ts +67 -0
  29. package/Source/GUI_Components/_Decorators/NonReactiveVueData.ts +26 -0
  30. package/Source/GUI_Components/_Decorators/{OptionalButNotNullableVueProperty.ts → preventNullForOptionalVueProperty.ts} +3 -4
  31. package/Source/GUI_Components/_Errors/InvalidVueProperty/InvalidVuePropertyError.ts +43 -0
  32. package/Source/GUI_Components/_Errors/InvalidVueProperty/InvalidVuePropertyErrorLocalization.english.ts +16 -0
  33. package/Source/GUI_Components/_VuePropertiesValidators/BooleanVuePropertyValidator.ts +25 -0
  34. package/Source/GUI_Components/_VuePropertiesValidators/DecorativeModifiersVuePropertyValidator.ts +22 -0
  35. package/Source/GUI_Components/_VuePropertiesValidators/DecorativeVariationVuePropertyValidator.ts +23 -0
  36. package/Source/GUI_Components/_VuePropertiesValidators/ElementOfEnumerationVuePropertyValidator.ts +29 -0
  37. package/Source/GUI_Components/_VuePropertiesValidators/GeometricModifiersVuePropertyValidator.ts +22 -0
  38. package/Source/GUI_Components/_VuePropertiesValidators/GeometricVariationVuePropertyValidator.ts +23 -0
  39. package/Source/GUI_Components/_VuePropertiesValidators/NaturalNumberOrZeroVuePropertyValidator.ts +25 -0
  40. package/Source/GUI_Components/_VuePropertiesValidators/NonEmptyStringVuePropertyValidator.ts +25 -0
  41. package/Source/GUI_Components/_VuePropertiesValidators/ThemeVuePropertyValidator.ts +23 -0
  42. package/Source/GUI_Components/_VuePropertiesValidators/VuePropertyValidator.ts +51 -0
  43. package/Source/index.ts +24 -8
  44. package/Workbenches/Source/Decorators/Decorators.workbench.pug +20 -0
  45. package/Workbenches/Source/Decorators/Decorators.workbench.ts +5 -0
  46. package/Workbenches/Source/Decorators/DecoratorsWorkbench.vue +69 -0
  47. package/Workbenches/Source/GUI_Components/AdmonitionBlock/AdmonitionBlockComponentTestSite.vue +9 -2
  48. package/Workbenches/Source/GUI_Components/Badge/BadgeBlockComponentTestSite.vue +9 -2
  49. package/Workbenches/Source/GUI_Components/Controls/Buttons/Plain/ButtonComponentTestSite.vue +19 -8
  50. package/Workbenches/Source/GUI_Components/Controls/Validatable/TextBox/TextBoxWorkbench.vue +45 -2
  51. package/Workbenches/Source/GUI_Components/Controls/ValidatableControlShell/ValidatableControlShellTestSite.vue +9 -2
  52. package/Workbenches/Source/GUI_Components/OverflowSafeSingleLineLabel/OverflowSafeSingleLineLabelComponentTestSite.vue +9 -2
  53. package/Workbenches/Source/Workbenches.pug +6 -0
  54. package/eslint.config.js +15 -0
  55. package/package.json +40 -48
  56. package/tsconfig.json +0 -3
  57. package/yda.config.yaml +1 -1
  58. package/Source/GUI_Components/AdmonitionBlock/AdmonitionBlock.vue.pug +0 -43
  59. package/Source/GUI_Components/Controls/Validatables/InputtableControl.ts +0 -134
  60. package/Source/GUI_Components/_Utils/validateVuePropertyAndLogIfInvalid.ts +0 -34
@@ -1,26 +1,44 @@
1
1
  /* ─── Assets ─────────────────────────────────────────────────────────────────────────────────────────────────────── */
2
2
  import componentVueTemplate from "./TextBox.vue.pug";
3
3
 
4
+ /* ─── Validations ─────────────────────────────────────────────────────────────────────────────────────── */
5
+ import VuePropertyValidator from "../../../_VuePropertiesValidators/VuePropertyValidator";
6
+ import BooleanVuePropertyValidator from "../../../_VuePropertiesValidators/BooleanVuePropertyValidator";
7
+ import ElementOfEnumerationVuePropertyValidator from "../../../_VuePropertiesValidators/ElementOfEnumerationVuePropertyValidator";
8
+ import NonEmptyStringVuePropertyValidator from "../../../_VuePropertiesValidators/NonEmptyStringVuePropertyValidator";
9
+ import NaturalNumberOrZeroVuePropertyValidator from "../../../_VuePropertiesValidators/NaturalNumberOrZeroVuePropertyValidator";
10
+ import ThemeVuePropertyValidator from "../../../_VuePropertiesValidators/ThemeVuePropertyValidator";
11
+ import GeometricVariationVuePropertyValidator from "../../../_VuePropertiesValidators/GeometricVariationVuePropertyValidator";
12
+ import DecorativeVariationVuePropertyValidator from "../../../_VuePropertiesValidators/DecorativeVariationVuePropertyValidator";
13
+ import preventNullForOptionalVueProperty from "../../../_Decorators/preventNullForOptionalVueProperty";
14
+
4
15
  /* ─── GUI Components ─────────────────────────────────────────────────────────────────────────────────────────────── */
5
- import InputtableControl from "../InputtableControl";
16
+ import InputtableControl from "../InputtableControl.vue";
6
17
  import ValidatableControlShell from "../../ValidatableControlShell/ValidatableControlShell.vue";
7
18
 
8
19
  /* ─── Framework ──────────────────────────────────────────────────────────────────────────────────────────────────── */
9
20
  import {
10
21
  ComponentBase as VueComponentConfiguration,
11
- Prop as VueProperty
22
+ Prop as VueProperty,
23
+ Model as VModel,
24
+ Emit as emitVueEvent
12
25
  } from "vue-facing-decorator";
13
- import {
14
- isElementOfEnumeration,
15
- isNonEmptyString,
16
- isNonNegativeInteger,
17
- type ElementOfPseudoEnumeration
18
- } from "@yamato-daiwa/es-extensions";
19
26
 
20
27
  /* ─── Utils ──────────────────────────────────────────────────────────────────────────────────────────────────────── */
28
+ import type { InputtedValueValidation } from "@yamato-daiwa/frontend";
29
+ import ValidatableControl from "../ValidatableControl";
30
+ import InvalidVuePropertyError from "../../../_Errors/InvalidVueProperty/InvalidVuePropertyError";
21
31
  import YDF_ComponentsCoordinator from "../../../YDF_ComponentsCoordinator";
22
- import OptionalButNotNullableVueProperty from "../../../_Decorators/OptionalButNotNullableVueProperty";
23
- import validateVuePropertyAndLogIfInvalid from "../../../_Utils/validateVuePropertyAndLogIfInvalid";
32
+ import getElementByVueReference from "../../../../Functions/getElementByVueReference";
33
+ import AccessibleFromTemplateAsNonReactive from "../../../_Decorators/AccessibleFromTemplateAsNonReactive";
34
+ import {
35
+ type ElementOfPseudoEnumeration,
36
+ Logger,
37
+ isNumber,
38
+ isString,
39
+ isNull,
40
+ isNotUndefined
41
+ } from "@yamato-daiwa/es-extensions";
24
42
 
25
43
 
26
44
  @VueComponentConfiguration({
@@ -30,9 +48,9 @@ import validateVuePropertyAndLogIfInvalid from "../../../_Utils/validateVuePrope
30
48
  ValidatableControlShell
31
49
  }
32
50
  })
33
- class TextBox extends InputtableControl {
51
+ class TextBox extends InputtableControl implements ValidatableControl {
34
52
 
35
- /* ━━━ Static Fields ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
53
+ /* ━━━ Common Static Fields ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
36
54
  public static CSS_NAMESPACE: string = "TextBox--YDF";
37
55
 
38
56
  public static HTML_Types: TextBox.HTML_Types = {
@@ -44,109 +62,380 @@ class TextBox extends InputtableControl {
44
62
  URI: "url"
45
63
  };
46
64
 
65
+ public static ValidityHighlightingActivationModes: TextBox.ValidityHighlightingActivationModes = {
66
+ immediate: "IMMEDIATE",
67
+ onFirstInputtedCharacter: "ON_FIRST_INPUTTED_CHARACTER",
68
+ onFocusOut: "ON_FOCUS_OUT"
69
+ };
70
+
47
71
 
48
- /* ━━━ Component Common Properties ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
72
+ /* ━━━ Component Common Parameters ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
49
73
  @VueProperty({
50
- type: String,
51
74
  default: TextBox.HTML_Types.regular,
52
- validator: validateVuePropertyAndLogIfInvalid({
53
- checker: (rawValue: string): boolean => isElementOfEnumeration(rawValue, TextBox.HTML_Types),
54
- message: "Must be the element of `TextBox.HTML_Types` enumeration."
55
- })
75
+ get validator(): VuePropertyValidator {
76
+ return ElementOfEnumerationVuePropertyValidator({
77
+ enumerationFullyQualifiedName: "Button.HTML_Types",
78
+ enumeration: TextBox.HTML_Types,
79
+ propertyName: "HTML_Type",
80
+ componentName: TextBox.CSS_NAMESPACE,
81
+ isPropertyRequired: this.required === true
82
+ });
83
+ }
56
84
  })
57
- @OptionalButNotNullableVueProperty
85
+ @preventNullForOptionalVueProperty
58
86
  protected HTML_Type!: ElementOfPseudoEnumeration<TextBox.HTML_Types>;
59
87
 
60
88
  @VueProperty({
61
- validator: validateVuePropertyAndLogIfInvalid({
62
- checker: isNonEmptyString,
63
- message: "If string specified it must be non-empty"
64
- })
89
+ required: false,
90
+ get validator(): VuePropertyValidator {
91
+ return NonEmptyStringVuePropertyValidator({
92
+ propertyName: "placeholder",
93
+ isPropertyRequired: this.required === true,
94
+ componentName: ValidatableControlShell.CSS_NAMESPACE
95
+ });
96
+ }
65
97
  })
66
- @OptionalButNotNullableVueProperty
98
+ @preventNullForOptionalVueProperty
67
99
  protected readonly placeholder?: string;
68
100
 
69
101
  /** @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#autofill */
70
102
  @VueProperty({
71
- validator: validateVuePropertyAndLogIfInvalid({
72
- checker: isNonEmptyString,
73
- message: "If string specified it must be non-empty"
74
- })
103
+ required: false,
104
+ get validator(): VuePropertyValidator {
105
+ return NonEmptyStringVuePropertyValidator({
106
+ propertyName: "autocomplete",
107
+ isPropertyRequired: this.required === true,
108
+ componentName: ValidatableControlShell.CSS_NAMESPACE
109
+ });
110
+ }
75
111
  })
76
- @OptionalButNotNullableVueProperty
112
+ @preventNullForOptionalVueProperty
77
113
  protected readonly autocomplete?: string;
78
114
 
79
115
 
80
- /* ─── Multi Line Mode ──────────────────────────────────────────────────────────────────────────────────────────── */
81
- @VueProperty({ type: Boolean, default: false })
82
- @OptionalButNotNullableVueProperty
116
+ /* ┅┅┅ Multi Line Mode ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
117
+ @VueProperty({
118
+ default: false,
119
+ get validator(): VuePropertyValidator {
120
+ return BooleanVuePropertyValidator({
121
+ propertyName: "multiline",
122
+ componentName: TextBox.CSS_NAMESPACE,
123
+ isPropertyRequired: this.required === true
124
+ });
125
+ }
126
+ })
127
+ @preventNullForOptionalVueProperty
83
128
  protected readonly multiline!: boolean;
84
129
 
85
- @VueProperty({ type: Boolean, default: true })
86
- @OptionalButNotNullableVueProperty
130
+ @VueProperty({
131
+ default: true,
132
+ get validator(): VuePropertyValidator {
133
+ return BooleanVuePropertyValidator({
134
+ propertyName: "autoResizingForMultilineMode",
135
+ componentName: TextBox.CSS_NAMESPACE,
136
+ isPropertyRequired: this.required === true
137
+ });
138
+ }
139
+ })
140
+ @preventNullForOptionalVueProperty
87
141
  protected readonly autoResizingForMultilineMode!: boolean;
88
142
 
89
143
 
90
- /* ─── Invalid Value Prevention ─────────────────────────────────────────────────────────────────────────────────── */
144
+ /* ┅┅┅ Invalid Value Prevention ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
91
145
  @VueProperty({
92
- type: Number,
93
- validator: validateVuePropertyAndLogIfInvalid({
94
- checker: isNonNegativeInteger,
95
- message: "If specified must be the positive integer or 0"
96
- })
146
+ required: false,
147
+ get validator(): VuePropertyValidator {
148
+ return NaturalNumberOrZeroVuePropertyValidator({
149
+ propertyName: "minimalCharactersCount",
150
+ isPropertyRequired: this.required === true,
151
+ componentName: ValidatableControlShell.CSS_NAMESPACE
152
+ });
153
+ }
97
154
  })
98
- @OptionalButNotNullableVueProperty
99
- protected readonly minimalCharactersCount?: number | null;
155
+ @preventNullForOptionalVueProperty
156
+ protected readonly minimalCharactersCount?: number;
100
157
 
101
158
  @VueProperty({
102
- type: Number,
103
- validator: validateVuePropertyAndLogIfInvalid({
104
- checker: isNonNegativeInteger,
105
- message: "If specified must be the positive integer or 0"
106
- })
159
+ required: false,
160
+ get validator(): VuePropertyValidator {
161
+ return NaturalNumberOrZeroVuePropertyValidator({
162
+ propertyName: "maximalCharactersCount",
163
+ isPropertyRequired: this.required === true,
164
+ componentName: ValidatableControlShell.CSS_NAMESPACE
165
+ });
166
+ }
107
167
  })
108
- @OptionalButNotNullableVueProperty
109
- protected readonly maximalCharactersCount?: number | null;
168
+ @preventNullForOptionalVueProperty
169
+ protected readonly maximalCharactersCount?: number;
110
170
 
111
171
  @VueProperty({
112
- type: Number,
113
- validator: validateVuePropertyAndLogIfInvalid({
114
- checker: isNonNegativeInteger,
115
- message: "If specified must be the positive integer or 0"
116
- })
172
+ required: false,
173
+ get validator(): VuePropertyValidator {
174
+ return NaturalNumberOrZeroVuePropertyValidator({
175
+ propertyName: "minimalNumericValue",
176
+ isPropertyRequired: this.required === true,
177
+ componentName: ValidatableControlShell.CSS_NAMESPACE
178
+ });
179
+ }
180
+ })
181
+ @preventNullForOptionalVueProperty
182
+ protected readonly minimalNumericValue?: number;
183
+
184
+ @VueProperty({
185
+ required: false,
186
+ get validator(): VuePropertyValidator {
187
+ return NaturalNumberOrZeroVuePropertyValidator({
188
+ propertyName: "maximalNumericValue",
189
+ isPropertyRequired: this.required === true,
190
+ componentName: ValidatableControlShell.CSS_NAMESPACE
191
+ });
192
+ }
193
+ })
194
+ @preventNullForOptionalVueProperty
195
+ protected readonly maximalNumericValue?: number;
196
+
197
+ @VueProperty({
198
+ default: false,
199
+ get validator(): VuePropertyValidator {
200
+ return BooleanVuePropertyValidator({
201
+ propertyName: "valueMustBeTheNonNegativeIntegerOfRegularNotation",
202
+ componentName: TextBox.CSS_NAMESPACE,
203
+ isPropertyRequired: this.required === true
204
+ });
205
+ }
206
+ })
207
+ @preventNullForOptionalVueProperty
208
+ protected readonly valueMustBeTheNonNegativeIntegerOfRegularNotation!: boolean;
209
+
210
+
211
+ @VueProperty({
212
+ default: false,
213
+ get validator(): VuePropertyValidator {
214
+ return BooleanVuePropertyValidator({
215
+ propertyName: "valueMustBeTheDigitsSequence",
216
+ componentName: TextBox.CSS_NAMESPACE,
217
+ isPropertyRequired: this.required === true
218
+ });
219
+ }
220
+ })
221
+ @preventNullForOptionalVueProperty
222
+ protected readonly valueMustBeTheDigitsSequence!: boolean;
223
+
224
+
225
+ /* ┅┅┅ Converting of Inputted Values ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
226
+ @VueProperty({
227
+ default: false,
228
+ get validator(): VuePropertyValidator {
229
+ return BooleanVuePropertyValidator({
230
+ propertyName: "mustConvertEmptyValueToZero",
231
+ componentName: TextBox.CSS_NAMESPACE,
232
+ isPropertyRequired: this.required === true
233
+ });
234
+ }
117
235
  })
118
- @OptionalButNotNullableVueProperty
119
- protected readonly minimalNumericValue?: number | null;
236
+ @preventNullForOptionalVueProperty
237
+ protected readonly mustConvertEmptyValueToZero!: boolean;
238
+
120
239
 
121
240
  @VueProperty({
122
- type: Number,
123
- validator: validateVuePropertyAndLogIfInvalid({
124
- checker: isNonNegativeInteger,
125
- message: "If specified must be the positive integer or 0"
241
+ default: false,
242
+ get validator(): VuePropertyValidator {
243
+ return BooleanVuePropertyValidator({
244
+ propertyName: "mustConvertEmptyValueToNull",
245
+ componentName: TextBox.CSS_NAMESPACE,
246
+ isPropertyRequired: this.required === true
247
+ });
248
+ }
249
+ })
250
+ @preventNullForOptionalVueProperty
251
+ protected readonly mustConvertEmptyValueToNull!: boolean;
252
+
253
+
254
+ /* ━━━ Public Methods ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
255
+ /* ┅┅┅ Implementation of `ValidatableControl` interface ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
256
+
257
+ public focus(): this {
258
+
259
+ getElementByVueReference({
260
+ vueReferenceID: TextBox.INPUT_OR_TEXT_AREA_ELEMENT_VUE_REFERENCE_ID,
261
+ parentVueComponent: this,
262
+ expectedDOM_ElementSubtype: HTMLElement,
263
+ mustExpectExactlyOneElement: true
264
+ }).focus();
265
+
266
+ return this;
267
+
268
+ }
269
+
270
+ public resetValidityHighlightingStateToInitial(): void {
271
+
272
+ }
273
+
274
+
275
+ /* ━━━ Actions Handling ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
276
+
277
+ /* [ Theory ] Action Handing in Vue: "keydown" → "input" → "keyup" */
278
+ protected rawInput: string = "";
279
+
280
+ protected invalidInputHighlightingIfAnyValidationErrorsMessages: boolean = false;
281
+ protected validInputHighlightingIfNoErrorsMessages: boolean = false;
282
+
283
+ @VueProperty({
284
+ required: true,
285
+ get validator(): VuePropertyValidator {
286
+ return ElementOfEnumerationVuePropertyValidator({
287
+ enumerationFullyQualifiedName: "TextBox.ValidityHighlightingActivationModes",
288
+ enumeration: TextBox.ValidityHighlightingActivationModes,
289
+ propertyName: "validityHighlightingActivationMode",
290
+ componentName: TextBox.CSS_NAMESPACE,
291
+ isPropertyRequired: this.required === true
292
+ });
293
+ }
294
+ })
295
+ protected validityHighlightingActivationMode!: ElementOfPseudoEnumeration<typeof TextBox.ValidityHighlightingActivationModes>;
296
+
297
+ @VModel({
298
+ type: ValidatableControl.Payload,
299
+ required: true,
300
+ validator: VuePropertyValidator.create({
301
+ checker: (rawVModel: unknown): boolean =>
302
+ ValidatableControl.VModelChecker(
303
+ rawVModel, (rawValue: unknown): boolean =>
304
+ isString(rawValue) ||
305
+ isNumber(rawValue, { mustConsiderNaN_AsNumber: false }) ||
306
+ isNull(rawValue)
307
+ ),
308
+ messageSpecificPart: "Must be either string or number or null.",
309
+ propertyName: "v-model",
310
+ componentName: TextBox.CSS_NAMESPACE
126
311
  })
127
312
  })
128
- @OptionalButNotNullableVueProperty
129
- protected readonly maximalNumericValue?: number | null;
313
+ protected readonly validatablePayload!: ValidatableControl.Payload<
314
+ TextBox.SupportedValidatablePayloadValuesTypes,
315
+ TextBox.SupportedValidatablePayloadValuesTypes,
316
+ InputtedValueValidation
317
+ >;
318
+
319
+ /* [ Theory ]
320
+ * Being fired first, "keydown" can be used for preventing of inputting of forbidden characters, but filtering out
321
+ * except allowed character is challenging because it is required to respect the "Enter", "Backspace", arrow keys
322
+ * etc. */
323
+ protected onKeyDown(event: KeyboardEvent): void {
324
+
325
+ /* 〔 理論 〕 妥当数入力処理(valueMustBeTheNonNegativeIntegerOfRegularNotation: true)〔 1 〕
326
+ * 1) 此処では利用者が先に行く不正0の入力を予防する事が出来ない。(本当?既存の値を確認すれば?)
327
+ * 例えば、利用者は「123」を入力してからカーソルを最初位置に動かして、「0」を入力しても、
328
+ * 此方ではカーソルの位置が判らないので、「onInput」で不正0の入力を遮る。
329
+ * 2) 読める文字と他に、利用者は半角空白やバックスペースや方向ボタンが押せるので、「!/^[0-9]$/u.test(event.key)」の様な正規表現では入力を予防出来ない。
330
+ * 3) 負号はボタンで入力するとは限らなく、ブラウザーに付けられたボタンにより入力も可能である。
331
+ * */
332
+ if (
333
+ (
334
+ this.valueMustBeTheNonNegativeIntegerOfRegularNotation ||
335
+ this.valueMustBeTheDigitsSequence
336
+ ) &&
337
+ (/^[+\-e.]$/u).test(event.key)
338
+ ) {
339
+ event.preventDefault();
340
+ }
341
+
342
+ }
343
+
344
+ /* [ Theory ]
345
+ * Even "input" element has "number" type, if nothing has been inputted, the "rawValue" will be the empty string. */
346
+ protected onInput(rawValue: string): void {
347
+
348
+ if (rawValue.length === 0) {
349
+
350
+ if (this.mustConvertEmptyValueToZero) {
351
+ this.$emit(TextBox.Events.input, this.validatablePayload.updateImmutably({ newValue: 0 }));
352
+ this.rawInput = "0";
353
+ return;
354
+ }
355
+
356
+
357
+ if (this.mustConvertEmptyValueToNull) {
358
+ this.$emit(TextBox.Events.input, this.validatablePayload.updateImmutably({ newValue: null }));
359
+ return;
360
+ }
361
+
362
+ }
363
+
364
+
365
+ if (
366
+ this.HTML_Type === TextBox.HTML_Types.number &&
367
+ this.mustConvertEmptyValueToZero &&
368
+ this.rawInput.startsWith("0")
369
+ ) {
370
+
371
+ const inputtedValueWithoutPrependedZeros: string = this.rawInput.replace(/^0+/u, "");
372
+
373
+ if (inputtedValueWithoutPrependedZeros.length === 0) {
374
+ this.$emit(TextBox.Events.input, this.validatablePayload.updateImmutably({ newValue: 0 }));
375
+ return;
376
+ }
377
+
378
+
379
+ this.rawInput = inputtedValueWithoutPrependedZeros;
380
+
381
+ this.$emit(
382
+ TextBox.Events.input,
383
+ this.validatablePayload.updateImmutably({
384
+ newValue: Number(inputtedValueWithoutPrependedZeros)
385
+ })
386
+ );
387
+
388
+ return;
389
+
390
+ }
391
+
392
+
393
+ if (this.HTML_Type === TextBox.HTML_Types.number) {
394
+
395
+ this.$emit(TextBox.Events.input, this.validatablePayload.updateImmutably({ newValue: Number(rawValue) }));
396
+
397
+ return;
398
+
399
+ }
400
+
401
+
402
+ this.$emit(TextBox.Events.input, this.validatablePayload.updateImmutably({ newValue: rawValue }));
403
+
404
+ }
405
+
406
+ @emitVueEvent("blur")
407
+ protected onFocusOut(): void {
408
+ this.invalidInputHighlightingIfAnyValidationErrorsMessages = true;
409
+ this.validInputHighlightingIfNoErrorsMessages = true;
410
+ }
130
411
 
131
412
 
132
413
  /* ━━━ Theming ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
133
414
  public static readonly Themes: ValidatableControlShell.Themes = { regular: "REGULAR" };
134
415
 
416
+ public static readonly selfAndChildrenComponentsThemesCorrespondence:
417
+ { validatableControlShell: { [ownThemeValue: string]: string; }; } =
418
+ { validatableControlShell: { [TextBox.Themes.regular]: ValidatableControlShell.Themes.regular } };
419
+
135
420
  @VueProperty({
136
- type: String,
137
- default: ValidatableControlShell.Themes.regular,
138
- validator: validateVuePropertyAndLogIfInvalid({
139
- checker: (rawValue: string): boolean => isElementOfEnumeration(rawValue, ValidatableControlShell.Themes),
140
- message:
141
- "Must be the one among values of `ValidatableControlShell.Themes` associative array including the ones " +
142
- "defined via `ValidatableControlShell.defineThemes()`."
143
- })
421
+ default: TextBox.Themes.regular,
422
+ validator: ThemeVuePropertyValidator(TextBox)
144
423
  })
145
- @OptionalButNotNullableVueProperty
424
+ @preventNullForOptionalVueProperty
146
425
  protected readonly theme!: string;
147
426
 
148
- public static defineThemes(themesNames: ReadonlyArray<string>): typeof ValidatableControlShell {
149
- return YDF_ComponentsCoordinator.defineThemes(themesNames, ValidatableControlShell);
427
+ protected get validatableControlShellTheme(): string {
428
+ return TextBox.selfAndChildrenComponentsThemesCorrespondence.validatableControlShell[this.theme];
429
+ }
430
+
431
+ public static defineThemes(
432
+ themesAndCorrespondenceDefinition: Readonly<{
433
+ [ownThemeKey: string]: Readonly<{ validatableControlShell: string; }>;
434
+ }>
435
+ ): typeof ValidatableControlShell {
436
+ return YDF_ComponentsCoordinator.defineThemesAndSetCorrespondenceWithOnesOfChildrenComponents(
437
+ themesAndCorrespondenceDefinition, ValidatableControlShell
438
+ );
150
439
  }
151
440
 
152
441
  public static areThemesCSS_ClassesCommon: boolean = YDF_ComponentsCoordinator.areThemesCSS_ClassesCommon;
@@ -155,9 +444,18 @@ class TextBox extends InputtableControl {
155
444
  ValidatableControlShell.areThemesCSS_ClassesCommon = true;
156
445
  }
157
446
 
158
- @VueProperty({ type: Boolean, default: ValidatableControlShell.areThemesCSS_ClassesCommon })
159
- @OptionalButNotNullableVueProperty
160
- private readonly areThemesCSS_ClassesCommon!: boolean;
447
+ @VueProperty({
448
+ default: TextBox.areThemesCSS_ClassesCommon,
449
+ get validator(): VuePropertyValidator {
450
+ return BooleanVuePropertyValidator({
451
+ propertyName: "areThemesCSS_ClassesCommon",
452
+ componentName: TextBox.CSS_NAMESPACE,
453
+ isPropertyRequired: this.required === true
454
+ });
455
+ }
456
+ })
457
+ @preventNullForOptionalVueProperty
458
+ protected readonly areThemesCSS_ClassesCommon!: boolean;
161
459
 
162
460
 
163
461
  /* ─── Geometry ─────────────────────────────────────────────────────────────────────────────────────────────────── */
@@ -166,21 +464,34 @@ class TextBox extends InputtableControl {
166
464
  small: "SMALL"
167
465
  };
168
466
 
467
+ public static readonly selfAndChildrenComponentsGeometricVariationsCorrespondence:
468
+ { validatableControlShell: { [ownGeometricVariationValue: string]: string; }; } =
469
+ {
470
+ validatableControlShell: {
471
+ [TextBox.GeometricVariations.regular]: ValidatableControlShell.GeometricVariations.regular,
472
+ [TextBox.GeometricVariations.small]: ValidatableControlShell.GeometricVariations.small
473
+ }
474
+ };
475
+
169
476
  @VueProperty({
170
- type: String,
171
- default: ValidatableControlShell.GeometricVariations.regular,
172
- validator: validateVuePropertyAndLogIfInvalid({
173
- checker: (rawValue: string): boolean => isElementOfEnumeration(rawValue, ValidatableControlShell.GeometricVariations),
174
- message:
175
- "Must be the one among values of `ValidatableControlShell.GeometricVariations` associative array including the ones " +
176
- "defined via `ValidatableControlShell.defineGeometricVariations()`."
177
- })
477
+ default: TextBox.GeometricVariations.regular,
478
+ validator: GeometricVariationVuePropertyValidator(TextBox)
178
479
  })
179
- @OptionalButNotNullableVueProperty
480
+ @preventNullForOptionalVueProperty
180
481
  protected readonly geometricVariation!: string;
181
482
 
182
- public static defineGeometricVariations(geometricVariationsNames: ReadonlyArray<string>): typeof ValidatableControlShell {
183
- return YDF_ComponentsCoordinator.defineGeometricVariations(geometricVariationsNames, ValidatableControlShell);
483
+ protected get validatableControlGeometricVariation(): string {
484
+ return TextBox.selfAndChildrenComponentsGeometricVariationsCorrespondence.validatableControlShell[this.geometricVariation];
485
+ }
486
+
487
+ public static defineGeometricVariations(
488
+ ownAndChildrenGeometricVariationsAndCorrespondenceDefinition: Readonly<{
489
+ [ownGeometricVariationKey: string]: Readonly<{ badge: string; }>;
490
+ }>
491
+ ): typeof TextBox {
492
+ return YDF_ComponentsCoordinator.defineGeometricVariationsAndSetCorrespondenceWithOnesOfChildrenComponents(
493
+ ownAndChildrenGeometricVariationsAndCorrespondenceDefinition, TextBox
494
+ );
184
495
  }
185
496
 
186
497
 
@@ -189,18 +500,25 @@ class TextBox extends InputtableControl {
189
500
  regular: "REGULAR"
190
501
  };
191
502
 
503
+ public static readonly selfAndChildrenComponentsDecorativeVariationsCorrespondence:
504
+ { validatableControlShell: { [ownDecorativeVariationValue: string]: string; }; } =
505
+ {
506
+ validatableControlShell: {
507
+ [TextBox.DecorativeVariations.regular]: ValidatableControlShell.DecorativeVariations.regular
508
+ }
509
+ };
510
+
192
511
  @VueProperty({
193
- type: String,
194
- default: ValidatableControlShell.DecorativeVariations.regular,
195
- validator: validateVuePropertyAndLogIfInvalid({
196
- checker: (rawValue: string): boolean => isElementOfEnumeration(rawValue, ValidatableControlShell.DecorativeVariations),
197
- message:
198
- "Must be the one among values of `ValidatableControlShell.DecorativeVariations` associative array including the ones " +
199
- "defined via `ValidatableControlShell.defineDecorativeVariations()`."
200
- })
512
+ default: TextBox.DecorativeVariations.regular,
513
+ validator: DecorativeVariationVuePropertyValidator(TextBox)
201
514
  })
202
515
  protected readonly decorativeVariation!: string;
203
516
 
517
+ protected get validatableControlDecorativeVariation(): string {
518
+ return TextBox.selfAndChildrenComponentsDecorativeVariationsCorrespondence.
519
+ validatableControlShell[this.decorativeVariation];
520
+ }
521
+
204
522
  public static defineDecorativeVariations(decorativeVariationsNames: ReadonlyArray<string>): typeof ValidatableControlShell {
205
523
  return YDF_ComponentsCoordinator.defineDecorativeVariations(decorativeVariationsNames, ValidatableControlShell);
206
524
  }
@@ -219,11 +537,122 @@ class TextBox extends InputtableControl {
219
537
  allDecorativeVariations: TextBox.DecorativeVariations,
220
538
  other: [
221
539
  ...this.multiline ? [ `${ TextBox.CSS_NAMESPACE }__Multiline` ] : [],
222
- ...this.disabled ? [ `${ TextBox.CSS_NAMESPACE }__DisabledState` ] : []
540
+ ...this.disabled ? [ `${ TextBox.CSS_NAMESPACE }__DisabledState` ] : [],
541
+ ...this.invalidInputHighlightingIfAnyValidationErrorsMessages && this.validatablePayload.isInvalid ?
542
+ [ "TextBox--YDF__InvalidInputState" ] : [],
543
+ ...this.validInputHighlightingIfNoErrorsMessages && !this.validatablePayload.isInvalid ?
544
+ [ "TextBox--YDF__ValidInputState" ] : []
223
545
  ]
224
546
  });
225
547
  }
226
548
 
549
+
550
+ /* ━━━ Properties Additional Validations ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
551
+ /** @descriptioin
552
+ * Validation with referencing of multiple properties is possible only via lifecycle hooks.
553
+ * This method is static because non-static methods are not accessible from the viewpoint of "vue-facing-decorator" */
554
+ protected static override validateProperties(instance: TextBox): void {
555
+
556
+ if (
557
+ isNotUndefined(instance.minimalNumericValue) &&
558
+ isNotUndefined(instance.maximalNumericValue) &&
559
+ instance.minimalNumericValue > instance.maximalNumericValue
560
+ ) {
561
+ Logger.throwErrorWithFormattedMessage({
562
+ errorInstance: new InvalidVuePropertyError({
563
+ componentName: TextBox.CSS_NAMESPACE,
564
+ propertyName: "minimalNumericValue",
565
+ messageSpecificPart: "`minimalNumericValue` is greater than `maximalNumericValue`."
566
+ }),
567
+ title: InvalidVuePropertyError.localization.defaultTitle,
568
+ occurrenceLocation: "TextBox.validateProperties(instance)"
569
+ });
570
+ }
571
+
572
+
573
+ if (
574
+ isNotUndefined(instance.minimalCharactersCount) &&
575
+ isNotUndefined(instance.maximalCharactersCount) &&
576
+ instance.minimalCharactersCount > instance.maximalCharactersCount
577
+ ) {
578
+ Logger.throwErrorWithFormattedMessage({
579
+ errorInstance: new InvalidVuePropertyError({
580
+ componentName: TextBox.CSS_NAMESPACE,
581
+ propertyName: "minimalCharactersCount",
582
+ messageSpecificPart: "`minimalCharactersCount` is greater than `maximalCharactersCount`."
583
+ }),
584
+ title: InvalidVuePropertyError.localization.defaultTitle,
585
+ occurrenceLocation: "TextBox.validateProperties(instance)"
586
+ });
587
+ }
588
+
589
+ }
590
+
591
+
592
+ /* ━━━ IDs ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
593
+ @AccessibleFromTemplateAsNonReactive
594
+ protected static readonly INPUT_OR_TEXT_AREA_ELEMENT_VUE_REFERENCE_ID: string = "INPUT_OR_TEXT_AREA_ELEMENT";
595
+
596
+
597
+ /* ┅┅┅ Instance ID ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
598
+ protected readonly INSTANCE_ID: string = TextBox.generateInstanceID();
599
+ protected static counterForInstanceID_Generating: number = 0;
600
+
601
+ public static generateInstanceID(): string {
602
+ TextBox.counterForInstanceID_Generating++;
603
+ return `TEXT_BOX--YDF-${ TextBox.counterForInstanceID_Generating }`;
604
+ }
605
+
606
+
607
+ /* ┅┅┅ HTML IDs ┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅┅ */
608
+ // TODO NonEmptyString
609
+ @VueProperty({ type: String, required: false })
610
+ protected readonly inputOrTextareaElementHTML_ID?: string;
611
+
612
+ // TODO NonEmptyString
613
+ @VueProperty({ type: String, required: false })
614
+ protected readonly labelElementHTML_ID?: string;
615
+
616
+ /* [ Performance Optimization ] Intended to be non-reactive and thus must be assigned in `create` lifecycle hook. */
617
+ protected HTML_IDs!: Readonly<{
618
+ inputOrTextarea: string;
619
+ label: string;
620
+ }>;
621
+
622
+
623
+ /* ━━━ Lifecycle Hooks ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ */
624
+ protected beforeCreate(): void {
625
+
626
+ TextBox.validateProperties(this);
627
+
628
+ this.invalidInputHighlightingIfAnyValidationErrorsMessages =
629
+ this.validityHighlightingActivationMode === TextBox.ValidityHighlightingActivationModes.immediate;
630
+
631
+ this.validInputHighlightingIfNoErrorsMessages = this.invalidInputHighlightingIfAnyValidationErrorsMessages;
632
+
633
+ }
634
+
635
+ protected created(): void {
636
+
637
+ this.HTML_IDs = {
638
+ inputOrTextarea: this.inputOrTextareaElementHTML_ID ?? `${ this.INSTANCE_ID }-INPUT_OR_TEXT_AREA`,
639
+ label: this.labelElementHTML_ID ?? `${ this.INSTANCE_ID }-LABEL`
640
+ };
641
+
642
+ if (isString(this.validatablePayload.value)) {
643
+ this.rawInput = this.validatablePayload.value;
644
+ } else if (isNumber(this.validatablePayload.value, { mustConsiderNaN_AsNumber: true })) {
645
+ this.rawInput = String(this.validatablePayload.value);
646
+ } else {
647
+ this.rawInput = "";
648
+ }
649
+
650
+ }
651
+
652
+ protected beforeUpdate(): void {
653
+ TextBox.validateProperties(this);
654
+ }
655
+
227
656
  }
228
657
 
229
658
 
@@ -238,6 +667,19 @@ namespace TextBox {
238
667
  URI: "url";
239
668
  }>;
240
669
 
670
+ export type SupportedValidatablePayloadValuesTypes = string | number | null;
671
+
672
+ export enum Events {
673
+ input = "update:modelValue",
674
+ blur = "BLUR"
675
+ }
676
+
677
+ export type ValidityHighlightingActivationModes = Readonly<{
678
+ immediate: "IMMEDIATE";
679
+ onFirstInputtedCharacter: "ON_FIRST_INPUTTED_CHARACTER";
680
+ onFocusOut: "ON_FOCUS_OUT";
681
+ }>;
682
+
241
683
  export type Themes = {
242
684
  readonly regular: "REGULAR";
243
685
  [themeName: string]: string;