diff --git a/app/assets/tailwind/sure-design-system/base.css b/app/assets/tailwind/sure-design-system/base.css index 991cfc4ef..10a6bbd33 100644 --- a/app/assets/tailwind/sure-design-system/base.css +++ b/app/assets/tailwind/sure-design-system/base.css @@ -1,6 +1,10 @@ @layer base { button { - @apply cursor-pointer focus-visible:outline-gray-900; + @apply cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900; + + @variant theme-dark { + @apply focus-visible:outline-white; + } } hr { diff --git a/app/components/DS/button.rb b/app/components/DS/button.rb index a253c04c7..667b85e3d 100644 --- a/app/components/DS/button.rb +++ b/app/components/DS/button.rb @@ -33,6 +33,27 @@ class DS::Button < DS::Buttonish data = data.merge(turbo_frame: frame) end + # `content_tag(:button, ...)` defaults to `type="submit"` per the HTML + # spec — meaning a DS::Button rendered inside a form will steal Enter-key + # submission from the first text input. Default to `type="button"` so + # callers must opt into submit behavior explicitly. `button_to` (href + # branch) wraps the button in its own form, so submit there is correct. + if href.blank? + merged_opts[:type] ||= "button" + end + + # Icon-only buttons have no visible text node, so screen readers fall + # back to announcing "button" with no name. Derive a humanized fallback + # from the icon key so AT users hear *something* meaningful; explicit + # `aria: { label: }` on the caller still wins. + if icon_only? && icon.present? + aria = (merged_opts[:aria] || {}).symbolize_keys + if aria[:label].blank? && merged_opts[:"aria-label"].blank? + aria[:label] = icon.to_s.tr("-_", " ").capitalize + merged_opts[:aria] = aria + end + end + merged_opts.merge( class: class_names(container_classes, extra_classes), data: data diff --git a/app/components/DS/buttonish.rb b/app/components/DS/buttonish.rb index bd8894be6..f1e864511 100644 --- a/app/components/DS/buttonish.rb +++ b/app/components/DS/buttonish.rb @@ -10,7 +10,7 @@ class DS::Buttonish < DesignSystemComponent }, destructive: { container_classes: "text-inverse bg-red-500 theme-dark:bg-red-400 hover:bg-red-600 theme-dark:hover:bg-red-500 disabled:bg-red-200 theme-dark:disabled:bg-red-600", - icon_classes: "fg-white" + icon_classes: "text-inverse" }, outline: { container_classes: "text-primary border border-secondary bg-transparent hover:bg-surface-hover", @@ -43,13 +43,13 @@ class DS::Buttonish < DesignSystemComponent }, md: { container_classes: "px-3 py-2", - icon_container_classes: "inline-flex items-center justify-center w-9 h-9", + icon_container_classes: "inline-flex items-center justify-center w-11 h-11", radius_classes: "rounded-lg", text_classes: "text-sm" }, lg: { container_classes: "px-4 py-3", - icon_container_classes: "inline-flex items-center justify-center w-10 h-10", + icon_container_classes: "inline-flex items-center justify-center w-12 h-12", radius_classes: "rounded-xl", text_classes: "text-base" }