@asd20/ui-next 2.23.2 → 2.23.3

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
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.23.3](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.23.2...ui-next-v2.23.3) (2026-09-10)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * revise api contract to accommodate previous changes ([79ea872](https://github.com/academydistrict20/asd20-ui-next/commit/79ea8729f75b5aa382d69fd936d05b523d7f63d7))
9
+
3
10
  ## [2.23.2](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.23.1...ui-next-v2.23.2) (2026-09-10)
4
11
 
5
12
  ## [2.23.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.23.0...ui-next-v2.23.1) (2026-09-09)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asd20/ui-next",
3
- "version": "2.23.2",
3
+ "version": "2.23.3",
4
4
  "private": false,
5
5
  "description": "ASD20 UI component library for Vue 3.",
6
6
  "license": "MIT",
@@ -53,7 +53,7 @@
53
53
  v-html="computedHelpText"
54
54
  />
55
55
  <div
56
- v-for="(v, index) in validationErrors"
56
+ v-for="(v, index) in renderedValidationErrors"
57
57
  :key="index"
58
58
  class="asd20-multiselect-input__validation-error"
59
59
  v-html="v"
@@ -168,6 +168,8 @@ export default {
168
168
  },
169
169
  methods: {
170
170
  emitValue(value) {
171
+ this.isDirty = true
172
+ this.validate(value)
171
173
  this.$emit('update:modelValue', value)
172
174
  },
173
175
  resolveSelectedItem(item) {
@@ -417,24 +419,13 @@ $input-reversed-text-color: var(--color__accent-t100);
417
419
 
418
420
  &__validation-error {
419
421
  flex-basis: 100%;
420
- color: darkred;
421
422
  font-size: 0.75rem;
422
423
  margin-top: space(0.125);
423
424
  }
424
425
 
425
426
  &--has-errors {
426
- label {
427
- color: darkred;
428
- }
429
427
  & :deep(.multiselect__tags) {
430
- border: 2px solid darkred;
431
- }
432
- & :deep(.multiselect--active .multiselect__tags) {
433
- box-shadow: 0 0 0 5px darkred inset;
434
- }
435
- & :deep(.multiselect__select:before) {
436
- color: darkred;
437
- /* border-color: var(--color__danger) transparent transparent transparent;*/
428
+ border: 2px solid asd20-swatch('emergency', -1);
438
429
  }
439
430
  }
440
431
  }
@@ -14,6 +14,7 @@
14
14
  <div class="asd20-select-input__select-wrapper">
15
15
  <select
16
16
  v-bind="mergedInputAttrs"
17
+ @blur="onBlur"
17
18
  @input="input"
18
19
  >
19
20
  <option
@@ -43,7 +44,7 @@
43
44
  v-html="computedHelpText"
44
45
  />
45
46
  <div
46
- v-for="(v, index) in validationErrors"
47
+ v-for="(v, index) in renderedValidationErrors"
47
48
  :key="index"
48
49
  class="asd20-select-input__validation-error"
49
50
  v-html="v"
@@ -215,25 +216,15 @@ $input-reversed-text-color: var(--color__accent-t100);
215
216
  }
216
217
 
217
218
  &__validation-error {
218
- color: var(--color__danger-s20);
219
219
  font-size: 0.75rem;
220
220
  margin-top: space(0.125);
221
221
  }
222
222
 
223
- &--has-errors {
224
- label {
225
- color: var(--color__danger-s20);
226
- }
227
- select ~ label,
228
- select:focus ~ label {
229
- @include asd20-focus;
230
- }
231
- input {
232
- border-color: var(--color__danger);
233
- &:focus {
234
- @include asd20-focus;
235
- }
236
- }
223
+ &--has-errors .asd20-select-input__field-wrapper,
224
+ &--has-errors.asd20-select-input--bordered
225
+ .asd20-select-input__field-wrapper {
226
+ box-shadow: 0 0 0 $input-border-width
227
+ asd20-swatch('emergency', -1) inset;
237
228
  }
238
229
  }
239
230
  </style>
@@ -14,6 +14,7 @@
14
14
 
15
15
  <input
16
16
  v-bind="mergedInputAttrs"
17
+ @blur="onBlur"
17
18
  @input="input"
18
19
  />
19
20
 
@@ -25,7 +26,7 @@
25
26
  v-html="computedHelpText"
26
27
  />
27
28
  <div
28
- v-for="(v, index) in validationErrors"
29
+ v-for="(v, index) in renderedValidationErrors"
29
30
  :key="index"
30
31
  class="asd20-file-input__validation-error"
31
32
  v-html="v"
@@ -140,20 +141,13 @@ $input-focus-color: var(--color__accent-t50);
140
141
  }
141
142
 
142
143
  &__validation-error {
143
- color: var(--color__danger-s20);
144
144
  font-size: 0.75rem;
145
145
  margin-top: space(0.125);
146
146
  }
147
147
 
148
148
  &--has-errors {
149
- label {
150
- color: var(--color__danger-s20);
151
- }
152
149
  input {
153
- border-color: var(--color__danger);
154
- &:focus {
155
- box-shadow: 0 0 0 5px var(--color__danger) inset;
156
- }
150
+ border-color: asd20-swatch('emergency', -1);
157
151
  }
158
152
  }
159
153
  }
@@ -18,30 +18,35 @@
18
18
 
19
19
  <textarea
20
20
  v-bind="mergedInputAttrs"
21
+ @blur="onBlur"
21
22
  @input="input"
22
23
  />
23
24
 
24
25
  <slot name="suffix" />
25
26
  </div>
26
27
  <div
27
- v-if="computedHelpText"
28
- class="asd20-text-area-input__help-text"
28
+ v-if="validationErrors.length || maxLength !== null"
29
+ class="asd20-text-area-input__validation-row"
29
30
  >
30
- <span
31
- v-if="helpText"
32
- v-html="helpText"
33
- />
31
+ <div class="asd20-text-area-input__validation-errors">
32
+ <div
33
+ v-for="(v, index) in renderedValidationErrors"
34
+ :key="index"
35
+ class="asd20-text-area-input__validation-error"
36
+ v-html="v"
37
+ />
38
+ </div>
34
39
  <span
35
40
  v-if="maxLength !== null"
36
41
  class="asd20-text-area-input__character-count"
37
42
  >{{ characterCountText }}</span>
38
43
  </div>
39
44
  <div
40
- v-for="(v, index) in validationErrors"
41
- :key="index"
42
- class="asd20-text-area-input__validation-error"
43
- v-html="v"
44
- />
45
+ v-if="helpText"
46
+ class="asd20-text-area-input__help-text"
47
+ >
48
+ <span v-html="helpText" />
49
+ </div>
45
50
  </div>
46
51
  </template>
47
52
 
@@ -144,6 +149,13 @@ $input-focus-color: var(--color__accent-t50);
144
149
  }
145
150
 
146
151
  &__help-text {
152
+ width: 100%;
153
+ color: var(--website-card__reverse-background-color);
154
+ font-size: 0.75rem;
155
+ margin-top: space(0.125);
156
+ }
157
+
158
+ &__validation-row {
147
159
  display: flex;
148
160
  align-items: baseline;
149
161
  justify-content: space-between;
@@ -154,27 +166,25 @@ $input-focus-color: var(--color__accent-t50);
154
166
  margin-top: space(0.125);
155
167
  }
156
168
 
169
+ &__validation-errors {
170
+ flex: 1 1 auto;
171
+ min-width: 0;
172
+ }
173
+
157
174
  &__character-count {
175
+ flex: 0 0 auto;
158
176
  margin-left: auto;
159
177
  text-align: right;
160
178
  white-space: nowrap;
161
179
  }
162
180
 
163
181
  &__validation-error {
164
- color: var(--color__danger-s20);
165
182
  font-size: 0.75rem;
166
- margin-top: space(0.125);
167
183
  }
168
184
 
169
185
  &--has-errors {
170
- label {
171
- color: var(--color__danger-s20);
172
- }
173
186
  textarea {
174
- border-color: var(--color__danger);
175
- &:focus {
176
- box-shadow: 0 0 0 5px var(--color__danger) inset;
177
- }
187
+ border-color: asd20-swatch('emergency', -1);
178
188
  }
179
189
  }
180
190
  }
@@ -14,30 +14,35 @@
14
14
 
15
15
  <input
16
16
  v-bind="mergedInputAttrs"
17
+ @blur="onBlur"
17
18
  @input="input"
18
19
  />
19
20
 
20
21
  <slot name="suffix" />
21
22
  </div>
22
23
  <div
23
- v-if="computedHelpText"
24
- class="asd20-text-input__help-text"
24
+ v-if="validationErrors.length || maxLength !== null"
25
+ class="asd20-text-input__validation-row"
25
26
  >
26
- <span
27
- v-if="helpText"
28
- v-html="helpText"
29
- />
27
+ <div class="asd20-text-input__validation-errors">
28
+ <div
29
+ v-for="(v, index) in renderedValidationErrors"
30
+ :key="index"
31
+ class="asd20-text-input__validation-error"
32
+ v-html="v"
33
+ />
34
+ </div>
30
35
  <span
31
36
  v-if="maxLength !== null"
32
37
  class="asd20-text-input__character-count"
33
38
  >{{ characterCountText }}</span>
34
39
  </div>
35
40
  <div
36
- v-for="(v, index) in validationErrors"
37
- :key="index"
38
- class="asd20-text-input__validation-error"
39
- v-html="v"
40
- />
41
+ v-if="helpText"
42
+ class="asd20-text-input__help-text"
43
+ >
44
+ <span v-html="helpText" />
45
+ </div>
41
46
  </div>
42
47
  </template>
43
48
 
@@ -137,6 +142,13 @@ $input-focus-color: var(--color__accent-t50);
137
142
  }
138
143
 
139
144
  &__help-text {
145
+ width: 100%;
146
+ color: var(--website-card__reverse-background-color);
147
+ font-size: 0.75rem;
148
+ margin-top: space(0.125);
149
+ }
150
+
151
+ &__validation-row {
140
152
  display: flex;
141
153
  align-items: baseline;
142
154
  justify-content: space-between;
@@ -147,27 +159,25 @@ $input-focus-color: var(--color__accent-t50);
147
159
  margin-top: space(0.125);
148
160
  }
149
161
 
162
+ &__validation-errors {
163
+ flex: 1 1 auto;
164
+ min-width: 0;
165
+ }
166
+
150
167
  &__character-count {
168
+ flex: 0 0 auto;
151
169
  margin-left: auto;
152
170
  text-align: right;
153
171
  white-space: nowrap;
154
172
  }
155
173
 
156
174
  &__validation-error {
157
- color: var(--color__danger-s20);
158
175
  font-size: 0.75rem;
159
- margin-top: space(0.125);
160
176
  }
161
177
 
162
178
  &--has-errors {
163
- label {
164
- color: var(--color__danger-s20);
165
- }
166
179
  input {
167
- border-color: var(--color__danger);
168
- &:focus {
169
- box-shadow: 0 0 0 5px var(--color__danger) inset;
170
- }
180
+ border-color: asd20-swatch('emergency', -1);
171
181
  }
172
182
  }
173
183
  }
@@ -189,7 +189,7 @@ export default {
189
189
  & :deep(.asd20-modal__content .asd20-viewport) {
190
190
  padding: space(1);
191
191
  }
192
- :deep(.asd20-text-area-input textarea) {
192
+ & :deep(.asd20-text-area-input textarea) {
193
193
  font-family: Arial, sans-serif;
194
194
  font-size: 1rem;
195
195
  }
@@ -13,7 +13,7 @@
13
13
  id="senderName"
14
14
  v-model="emailMessage.senderName"
15
15
  label="Your Full Name"
16
- aria-required="true"
16
+ required
17
17
  @validated="validationErrors.senderName = $event"
18
18
  />
19
19
  <asd20-text-input
@@ -22,7 +22,7 @@
22
22
  type="email"
23
23
  :validator="validateEmailAddress"
24
24
  label="Your Email Address"
25
- aria-required="true"
25
+ required
26
26
  @validated="validationErrors.senderEmail = $event"
27
27
  />
28
28
  <asd20-text-input
@@ -30,16 +30,15 @@
30
30
  v-model="emailMessage.subject"
31
31
  label="Subject"
32
32
  maxlength="200"
33
- aria-required="true"
33
+ required
34
34
  @validated="validationErrors.subject = $event"
35
35
  />
36
36
  <asd20-text-area-input
37
37
  id="messageBody"
38
38
  v-model="emailMessage.messageBody"
39
39
  label="Message"
40
- help-text="All fields are required."
41
40
  maxlength="8000"
42
- aria-required="true"
41
+ required
43
42
  @validated="validationErrors.messageBody = $event"
44
43
  />
45
44
  <div
@@ -3,6 +3,7 @@ import createComponentInstanceId from '../utils/createComponentInstanceId'
3
3
 
4
4
  const INPUT_MODEL_LISTENER_KEYS = ['onInput', 'onUpdate:modelValue']
5
5
  const DEFAULT_INPUT_COMPONENT_NAME = 'asd20-input'
6
+ const REQUIRED_VALIDATION_ERROR = 'This field is required.'
6
7
 
7
8
  function resolveKebabComponentName(componentName = DEFAULT_INPUT_COMPONENT_NAME) {
8
9
  return kebabCase(componentName).replace(/-([0-9])/g, '$1')
@@ -75,7 +76,8 @@ export default {
75
76
  classes[`${this.kebabComponentName}`] = true
76
77
  classes[`${this.kebabComponentName}--hide-label`] = this.hideLabel
77
78
  classes[`${this.kebabComponentName}--is-valid`] = this.isValid
78
- classes[`${this.kebabComponentName}--has-errors`] = !this.isValid
79
+ classes[`${this.kebabComponentName}--has-errors`] =
80
+ this.isDirty && !this.isValid
79
81
  classes[`${this.kebabComponentName}--horizontal`] = this.horizontal
80
82
  classes[`${this.kebabComponentName}--transparent`] = this.transparent
81
83
  classes[`${this.kebabComponentName}--expanded`] = this.expanded
@@ -98,6 +100,13 @@ export default {
98
100
  isValid() {
99
101
  return this.validationErrors.length === 0
100
102
  },
103
+ renderedValidationErrors() {
104
+ return this.validationErrors.map(error =>
105
+ !this.isDirty && error === REQUIRED_VALIDATION_ERROR
106
+ ? 'Required'
107
+ : error
108
+ )
109
+ },
101
110
  resolvedValue() {
102
111
  return this.modelValue
103
112
  },
@@ -163,7 +172,7 @@ export default {
163
172
  this.$attrs.required.toString().toLowerCase() !== 'false'
164
173
  ) {
165
174
  if (!value) {
166
- this.validationErrors.push(`This field is required.`)
175
+ this.validationErrors.push(REQUIRED_VALIDATION_ERROR)
167
176
  }
168
177
  }
169
178