From 7cdf263da11d49cc57c3cafe4744a69b3df00d0f Mon Sep 17 00:00:00 2001 From: Pete Matsyburka Date: Fri, 17 Apr 2026 14:49:14 +0300 Subject: [PATCH] add screen reader mode --- .../submit_form_metadata_controller.rb | 37 ++ app/javascript/elements/scroll_buttons.js | 4 +- .../submission_form/accessibility_areas.vue | 434 ++++++++++++++++++ app/javascript/submission_form/area.vue | 15 +- .../submission_form/attachment_step.vue | 10 +- app/javascript/submission_form/completed.vue | 12 +- app/javascript/submission_form/date_step.vue | 5 +- app/javascript/submission_form/form.vue | 66 ++- app/javascript/submission_form/i18n.js | 43 +- app/javascript/submission_form/image_step.vue | 5 +- .../submission_form/initials_step.vue | 35 +- .../submission_form/signature_step.vue | 11 +- app/models/document_metadata.rb | 27 ++ app/views/shared/_html_modal.html.erb | 2 +- app/views/submissions/_value.html.erb | 4 +- app/views/submit_form/email_2fa.html.erb | 2 +- app/views/submit_form/show.html.erb | 14 +- config/routes.rb | 1 + ...20260416100000_create_document_metadata.rb | 15 + db/schema.rb | 11 +- lib/document_metadatas.rb | 34 ++ lib/pdfium.rb | 98 ++++ spec/system/signing_form_spec.rb | 8 +- 23 files changed, 834 insertions(+), 59 deletions(-) create mode 100644 app/controllers/submit_form_metadata_controller.rb create mode 100644 app/javascript/submission_form/accessibility_areas.vue create mode 100644 app/models/document_metadata.rb create mode 100644 db/migrate/20260416100000_create_document_metadata.rb create mode 100644 lib/document_metadatas.rb diff --git a/app/controllers/submit_form_metadata_controller.rb b/app/controllers/submit_form_metadata_controller.rb new file mode 100644 index 00000000..49bf8666 --- /dev/null +++ b/app/controllers/submit_form_metadata_controller.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class SubmitFormMetadataController < ApplicationController + skip_before_action :authenticate_user! + skip_authorization_check + + def index + submitter = Submitter.find_by!(slug: params[:submit_form_slug]) + + return head :not_found if submitter.declined_at? || + submitter.completed_at? || + submitter.submission.archived_at? || + submitter.submission.expired? || + submitter.submission.template&.archived_at? || + submitter.account.archived_at? || + !Submitters::AuthorizedForForm.call(submitter, current_user, request) + + submission = submitter.submission + values = submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } + schema = Submissions.filtered_conditions_schema(submission, values:, include_submitter_uuid: submitter.uuid) + + documents = schema.filter_map do |item| + submission.schema_documents.find { |a| a.uuid == item['attachment_uuid'] } + end + + ActiveRecord::Associations::Preloader.new(records: documents, associations: %i[blob record]).call + + text_runs = documents.to_h do |document| + [ + document.uuid, + DocumentMetadatas.find_or_create_for_document(document, account_id: document.record.account_id).text_runs + ] + end + + render json: { text_runs: } + end +end diff --git a/app/javascript/elements/scroll_buttons.js b/app/javascript/elements/scroll_buttons.js index 09e4796e..08ca40ab 100644 --- a/app/javascript/elements/scroll_buttons.js +++ b/app/javascript/elements/scroll_buttons.js @@ -47,13 +47,13 @@ export default class extends HTMLElement { this.classList.remove('hidden', '-translate-y-10', 'opacity-0') this.classList.add('translate-y-0', 'opacity-100') - this.querySelectorAll('[tabindex]').forEach((el) => { el.tabIndex = 0 }) + this.inert = false } hideButtons () { this.classList.remove('translate-y-0', 'opacity-100') this.classList.add('-translate-y-10', 'opacity-0') - this.querySelectorAll('[tabindex]').forEach((el) => { el.tabIndex = -1 }) + this.inert = true setTimeout(() => { if (this.classList.contains('-translate-y-10')) { diff --git a/app/javascript/submission_form/accessibility_areas.vue b/app/javascript/submission_form/accessibility_areas.vue new file mode 100644 index 00000000..6e720e93 --- /dev/null +++ b/app/javascript/submission_form/accessibility_areas.vue @@ -0,0 +1,434 @@ + + + diff --git a/app/javascript/submission_form/area.vue b/app/javascript/submission_form/area.vue index a3e83b62..e3138254 100644 --- a/app/javascript/submission_form/area.vue +++ b/app/javascript/submission_form/area.vue @@ -4,11 +4,11 @@ dir="auto" :style="[computedStyle, fontStyle]" :class="{ 'cursor-default': !submittable, 'border border-red-100 bg-red-100 cursor-pointer': submittable, 'border border-red-100': !isActive && submittable, 'bg-opacity-80': !isActive && !isValueSet && submittable, 'outline-red-500 outline-dashed outline-2 z-10 field-area-active': isActive && submittable, 'bg-opacity-40': (isActive || isValueSet) && submittable }" - :role="submittable && field.type !== 'checkbox' && field.type !== 'radio' && field.type !== 'multiple' ? 'button' : undefined" - :tabindex="submittable ? 0 : undefined" - :aria-label="submittable ? fieldAreaLabel : undefined" - @keydown.enter.prevent="submittable ? $el.click() : undefined" - @keydown.space.prevent="submittable ? $el.click() : undefined" + :role="submittable && !isNativeInputField ? 'button' : undefined" + :tabindex="submittable && !isNativeInputField ? 0 : undefined" + :aria-label="submittable && !isNativeInputField ? fieldAreaLabel : undefined" + @keydown.enter.prevent="submittable && !isNativeInputField ? $el.click() : undefined" + @keydown.space.prevent="submittable && !isNativeInputField ? $el.click() : undefined" > @@ -155,6 +156,7 @@ v-if="submittable" type="radio" :value="false" + :name="`radio-area-${field.uuid}`" :aria-label="optionValue(option)" class="aspect-square checked:checkbox checked:checkbox-xs" :class="{ 'base-radio': !modelValue || modelValue !== optionValue(option), '!w-auto !h-full': area.w > area.h, '!w-full !h-auto': area.w <= area.h }" @@ -408,6 +410,9 @@ export default { kba: this.t('kba') } }, + isNativeInputField () { + return ['checkbox', 'radio', 'multiple'].includes(this.field.type) + }, fieldAreaLabel () { const name = this.field.name || this.fieldNames[this.field.type] || this.field.type if (this.area.option_uuid && this.option) { diff --git a/app/javascript/submission_form/attachment_step.vue b/app/javascript/submission_form/attachment_step.vue index 0379c242..691f5491 100644 --- a/app/javascript/submission_form/attachment_step.vue +++ b/app/javascript/submission_form/attachment_step.vue @@ -1,6 +1,10 @@