@asd20/ui-next 2.33.3 → 2.34.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
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.34.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.34.0...ui-next-v2.34.1) (2026-10-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* edit order of records on student records request form ([6880af6](https://github.com/academydistrict20/asd20-ui-next/commit/6880af607ab042d62f59b4b10da770f99e573cba))
|
|
9
|
+
|
|
10
|
+
# [2.34.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.33.3...ui-next-v2.34.0) (2026-10-28)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* support checkbox groups for school transfer records ([9596d21](https://github.com/academydistrict20/asd20-ui-next/commit/9596d21fea018afec4c03de64471549cb77e9487))
|
|
16
|
+
|
|
3
17
|
## [2.33.3](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.33.2...ui-next-v2.33.3) (2026-10-27)
|
|
4
18
|
|
|
5
19
|
|
package/package.json
CHANGED
|
@@ -149,6 +149,33 @@
|
|
|
149
149
|
</label>
|
|
150
150
|
</fieldset>
|
|
151
151
|
|
|
152
|
+
<fieldset
|
|
153
|
+
v-else-if="field.type === 'checkbox-group'"
|
|
154
|
+
:id="inputId"
|
|
155
|
+
class="asd20-public-form-field__choices"
|
|
156
|
+
tabindex="-1"
|
|
157
|
+
:aria-describedby="describedBy"
|
|
158
|
+
:aria-invalid="hasErrors ? 'true' : undefined"
|
|
159
|
+
>
|
|
160
|
+
<legend>{{ displayLabel }}</legend>
|
|
161
|
+
<label
|
|
162
|
+
v-for="option in field.options"
|
|
163
|
+
:key="option.value"
|
|
164
|
+
:class="{ 'asd20-public-form-field__option--separated': option.separatorAfter }"
|
|
165
|
+
:for="`${inputId}-${option.value}`"
|
|
166
|
+
>
|
|
167
|
+
<input
|
|
168
|
+
:id="`${inputId}-${option.value}`"
|
|
169
|
+
:name="inputId"
|
|
170
|
+
type="checkbox"
|
|
171
|
+
:value="option.value"
|
|
172
|
+
:checked="Array.isArray(modelValue) && modelValue.includes(option.value)"
|
|
173
|
+
@change="toggleChoice(option.value, $event.target.checked)"
|
|
174
|
+
/>
|
|
175
|
+
<span>{{ option.label }}</span>
|
|
176
|
+
</label>
|
|
177
|
+
</fieldset>
|
|
178
|
+
|
|
152
179
|
<asd20-checkbox
|
|
153
180
|
v-else-if="field.type === 'checkbox'"
|
|
154
181
|
:id="inputId"
|
|
@@ -276,6 +303,12 @@ export default {
|
|
|
276
303
|
},
|
|
277
304
|
},
|
|
278
305
|
methods: {
|
|
306
|
+
toggleChoice(value, checked) {
|
|
307
|
+
const selected = Array.isArray(this.modelValue) ? this.modelValue : []
|
|
308
|
+
this.$emit('update:modelValue', checked
|
|
309
|
+
? [...selected.filter(choice => choice !== value), value]
|
|
310
|
+
: selected.filter(choice => choice !== value))
|
|
311
|
+
},
|
|
279
312
|
addFiles(event) {
|
|
280
313
|
const addedFiles = Array.from(event.target.files || [])
|
|
281
314
|
if (addedFiles.length) {
|
|
@@ -407,7 +440,14 @@ export default {
|
|
|
407
440
|
align-items: flex-start;
|
|
408
441
|
}
|
|
409
442
|
|
|
410
|
-
&__choices
|
|
443
|
+
&__choices label.asd20-public-form-field__option--separated {
|
|
444
|
+
border-bottom: 1px solid #d9d9d9;
|
|
445
|
+
margin-bottom: space(0.25);
|
|
446
|
+
padding-bottom: space(0.25);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
&__choices input[type='radio'],
|
|
450
|
+
&__choices input[type='checkbox'] {
|
|
411
451
|
flex: 0 0 auto;
|
|
412
452
|
margin: 0;
|
|
413
453
|
}
|
|
@@ -410,7 +410,7 @@ export default {
|
|
|
410
410
|
for (const field of this.formDefinition.fields) {
|
|
411
411
|
if (!isPublicFormFieldVisible(field, this.values)) {
|
|
412
412
|
this.values[field.name] =
|
|
413
|
-
field.type === 'checkbox' ? false : field.type
|
|
413
|
+
field.type === 'checkbox' ? false : ['file', 'checkbox-group'].includes(field.type) ? [] : ''
|
|
414
414
|
}
|
|
415
415
|
}
|
|
416
416
|
if (this.validationAttempted) this.validate(false)
|
|
@@ -7,6 +7,7 @@ export const SUPPORTED_PUBLIC_FORM_FIELD_TYPES = Object.freeze([
|
|
|
7
7
|
'select',
|
|
8
8
|
'radio',
|
|
9
9
|
'checkbox',
|
|
10
|
+
'checkbox-group',
|
|
10
11
|
'file',
|
|
11
12
|
])
|
|
12
13
|
|
|
@@ -48,7 +49,7 @@ function optionalBoolean(value, label) {
|
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
function normalizeOptions(field) {
|
|
51
|
-
if (!['select', 'radio'].includes(field.type)) return undefined
|
|
52
|
+
if (!['select', 'radio', 'checkbox-group'].includes(field.type)) return undefined
|
|
52
53
|
if (
|
|
53
54
|
!Array.isArray(field.options) ||
|
|
54
55
|
!field.options.length ||
|
|
@@ -71,7 +72,13 @@ function normalizeOptions(field) {
|
|
|
71
72
|
'Option description',
|
|
72
73
|
1000
|
|
73
74
|
)
|
|
74
|
-
|
|
75
|
+
const separatorAfter = optionalBoolean(option?.separatorAfter, 'Option separator')
|
|
76
|
+
return {
|
|
77
|
+
label,
|
|
78
|
+
value,
|
|
79
|
+
...(description ? { description } : {}),
|
|
80
|
+
...(separatorAfter ? { separatorAfter: true } : {}),
|
|
81
|
+
}
|
|
75
82
|
})
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -184,17 +191,19 @@ function normalizeConditions(conditions) {
|
|
|
184
191
|
return conditions.map(normalizeCondition)
|
|
185
192
|
}
|
|
186
193
|
|
|
194
|
+
function matchesCondition(condition, values) {
|
|
195
|
+
const value = values[condition.fieldName]
|
|
196
|
+
return Array.isArray(value)
|
|
197
|
+
? value.some(choice => condition.values.includes(choice))
|
|
198
|
+
: condition.values.includes(String(value || '').trim())
|
|
199
|
+
}
|
|
200
|
+
|
|
187
201
|
export function isPublicFormFieldVisible(field, values) {
|
|
188
|
-
return (
|
|
189
|
-
!field.visibleWhen ||
|
|
190
|
-
field.visibleWhen.values.includes(String(values[field.visibleWhen.fieldName] || '').trim())
|
|
191
|
-
)
|
|
202
|
+
return !field.visibleWhen || matchesCondition(field.visibleWhen, values)
|
|
192
203
|
}
|
|
193
204
|
|
|
194
205
|
export function isPublicFormFieldRequired(field, values) {
|
|
195
|
-
const required = field.required || field.requiredWhen?.some(condition =>
|
|
196
|
-
condition.values.includes(String(values[condition.fieldName] || '').trim())
|
|
197
|
-
)
|
|
206
|
+
const required = field.required || field.requiredWhen?.some(condition => matchesCondition(condition, values))
|
|
198
207
|
const uploaded = field.requiredUnlessUploaded &&
|
|
199
208
|
Array.isArray(values[field.requiredUnlessUploaded]) &&
|
|
200
209
|
values[field.requiredUnlessUploaded].length > 0
|
|
@@ -268,8 +277,8 @@ export function normalizePublicFormDefinition(definition) {
|
|
|
268
277
|
)
|
|
269
278
|
if (
|
|
270
279
|
!dependency ||
|
|
271
|
-
dependency
|
|
272
|
-
!['radio', 'select'].includes(dependency.type) ||
|
|
280
|
+
fields.indexOf(dependency) >= fields.indexOf(field) ||
|
|
281
|
+
!['radio', 'select', 'checkbox-group'].includes(dependency.type) ||
|
|
273
282
|
condition.values.some(
|
|
274
283
|
value => !dependency.options.some(option => option.value === value)
|
|
275
284
|
)
|
|
@@ -369,7 +378,7 @@ export function createPublicFormValues(definition) {
|
|
|
369
378
|
return Object.fromEntries(
|
|
370
379
|
definition.fields.map(field => [
|
|
371
380
|
field.name,
|
|
372
|
-
field.type
|
|
381
|
+
['file', 'checkbox-group'].includes(field.type) ? [] : field.type === 'checkbox' ? false : '',
|
|
373
382
|
])
|
|
374
383
|
)
|
|
375
384
|
}
|
|
@@ -403,9 +412,9 @@ export function validatePublicFormValues(definition, sourceValues = {}) {
|
|
|
403
412
|
const values = {}
|
|
404
413
|
|
|
405
414
|
for (const field of definition.fields) {
|
|
406
|
-
if (!isPublicFormFieldVisible(field,
|
|
415
|
+
if (!isPublicFormFieldVisible(field, values)) {
|
|
407
416
|
values[field.name] =
|
|
408
|
-
field.type
|
|
417
|
+
['file', 'checkbox-group'].includes(field.type) ? [] : field.type === 'checkbox' ? false : ''
|
|
409
418
|
continue
|
|
410
419
|
}
|
|
411
420
|
const required = isPublicFormFieldRequired(field, sourceValues)
|
|
@@ -433,6 +442,21 @@ export function validatePublicFormValues(definition, sourceValues = {}) {
|
|
|
433
442
|
'Upload up to 5 PDF documents, 5 MB each and 10 MB total.'
|
|
434
443
|
)
|
|
435
444
|
}
|
|
445
|
+
} else if (field.type === 'checkbox-group') {
|
|
446
|
+
const selected = rawValue == null ? [] : rawValue
|
|
447
|
+
const allowed = new Set((field.options || []).map(option => option.value))
|
|
448
|
+
if (
|
|
449
|
+
!Array.isArray(selected) ||
|
|
450
|
+
selected.length > allowed.size ||
|
|
451
|
+
selected.some(choice => typeof choice !== 'string' || !allowed.has(choice)) ||
|
|
452
|
+
new Set(selected).size !== selected.length
|
|
453
|
+
) {
|
|
454
|
+
values[field.name] = []
|
|
455
|
+
fieldErrors.push(`Select valid choices for ${field.label.toLowerCase()}.`)
|
|
456
|
+
} else {
|
|
457
|
+
values[field.name] = [...selected]
|
|
458
|
+
if (required && !selected.length) fieldErrors.push(`${field.label} is required.`)
|
|
459
|
+
}
|
|
436
460
|
} else if (field.type === 'checkbox') {
|
|
437
461
|
const value = rawValue === true
|
|
438
462
|
values[field.name] = value
|