Files
git d9ca84628b feat(a11y): deep keyboard accessibility pass across all QML components
Second-pass a11y work across all 12 component groups. Every interactive
element now has activeFocusOnTab, Keys.onReturnPressed/SpacePressed, and
context-aware Accessible.name/description bindings.

Highlights:
- Dialogs: keyboard handlers with enabled-guard on confirm buttons
- CDropdownMenu: full keyboard nav (Up/Down/Enter/Escape)
- CLoginForm: explicit KeyNavigation.tab chain (username→password→submit)
- CNotificationBell: dynamic "3 notifications"/"No notifications" name
- CJobProgressBar: Accessible.minimumValue/maximumValue/currentValue
- CExecutionStatusDot: "Execution status: Running/Passed/Failed" binding
- CKeyboardShortcuts: invisible Repeater exposes all shortcuts to a11y tree
- CDataTable rows: "Row N of M" descriptions
- Canvas elements: Accessible.Canvas role + keyboard zoom (+/- keys)
- DropdownExpandedList: focus-highlight extended to :activeFocus
- Dynamic names reflect loading state (e.g. "Signing in, please wait")

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-19 20:53:53 +00:00

133 lines
5.7 KiB
QML

import QtQuick; import QtQuick.Controls
import QtQuick.Layouts; import QmlComponents 1.0
import "qmllib/dbal"; import "qmllib/MetaBuilder"
import "qmllib/MetaBuilder/SchemaEditorDBAL.js" as SDBAL
Rectangle {
id: root; color: Theme.background
objectName: "view_schema_editor"
Accessible.role: Accessible.Pane
Accessible.name: "Schema Editor"
DBALProvider { id: dbal }
property int selSch: 0; property int selFld: -1
property bool createDlg: false; property bool addFldDlg: false
property string nfName: ""; property string nfType: "string"
property bool nfR: false; property string nfDv: ""; property string nfDc: ""
property var schemas: SDBAL.loadJson(Qt.resolvedUrl(
"qmllib/MetaBuilder/data/schema-mock.json"))
property var fieldTypes: ["string","integer","number",
"boolean","text","json","enum","datetime","date","uuid","array"]
function cs() { return SDBAL.currentSchema(schemas, selSch) }
function cf() { return SDBAL.currentFields(schemas, selSch) }
function loadSchemas() {
SDBAL.loadSchemas(dbal, function(p) {
schemas = p; selSch = 0; selFld = -1 })
}
Component.onCompleted: loadSchemas()
function addField() {
var f = { name: nfName, type: nfType, required: nfR,
defaultValue: nfDv, description: nfDc }
var r = SDBAL.addField(schemas, selSch, f)
if (r) { schemas = r.schemas; selFld = r.selectedFieldIndex }
nfName = ""; nfType = "string"; nfR = false
nfDv = ""; nfDc = ""; addFldDlg = false }
function deleteSchema() {
var r = SDBAL.deleteSchema(schemas, selSch)
if (r) { schemas = r.schemas; selSch = r.selectedIndex; selFld = -1 }
}
ColumnLayout {
anchors.fill: parent; anchors.margins: 20; spacing: 0
FlexRow {
Layout.fillWidth: true; Layout.bottomMargin: 16; spacing: 12
CText { variant: "h3"; text: "Schema Editor" }
Item { Layout.fillWidth: true }
CBadge { text: cs() ? cs().name : "";
accent: true; visible: cs() !== null }
CBadge { text: cf().length + " fields"; visible: cs() !== null }
CButton { text: "Create Schema";
variant: "primary"; size: "md";
activeFocusOnTab: true
Accessible.role: Accessible.Button
Accessible.name: "Create Schema"
Keys.onReturnPressed: createDlg = true
Keys.onSpacePressed: createDlg = true
onClicked: createDlg = true }
}
CDivider { Layout.fillWidth: true; Layout.bottomMargin: 16 }
RowLayout {
Layout.fillWidth: true; Layout.fillHeight: true; spacing: 16
SchemaSidebar {
Layout.preferredWidth: 240; Layout.fillHeight: true
schemas: root.schemas; selectedIndex: root.selSch
onItemClicked: function(i) { selSch = i; selFld = -1 }
}
SchemaFieldsTable {
Layout.fillWidth: true; Layout.fillHeight: true
schema: cs(); fields: cf(); selectedFieldIndex: root.selFld
onFieldClicked: function(i) { selFld = i }
onAddFieldClicked: addFldDlg = true
onRemoveFieldClicked: {
schemas = SDBAL.deleteField(
schemas, selSch, selFld)
selFld = -1 }
}
SchemaFieldEditor {
Layout.preferredWidth: 280
Layout.fillHeight: true; visible: selFld >= 0
field: SDBAL.currentField(schemas, selSch, selFld)
fieldTypes: root.fieldTypes; onFieldUpdated: function(k, v) {
schemas = SDBAL.updateField(schemas, selSch, selFld, k, v) }
}
}
CDivider { Layout.fillWidth: true; Layout.topMargin: 16 }
FlexRow {
Layout.fillWidth: true
Layout.topMargin: 12; spacing: 12
CButton {
text: "Save Schema"
variant: "primary"; size: "md"
activeFocusOnTab: true
Accessible.role: Accessible.Button
Accessible.name: "Save Schema"
}
CButton {
text: "Export JSON"
variant: "secondary"; size: "md"
activeFocusOnTab: true
Accessible.role: Accessible.Button
Accessible.name: "Export JSON"
Accessible.description:
"Export schema as JSON"
}
Item { Layout.fillWidth: true }
CButton {
text: "Delete Schema"
variant: "danger"; size: "md"
enabled: schemas.length > 1
activeFocusOnTab: true
Accessible.role: Accessible.Button
Accessible.name: "Delete Schema"
Accessible.description:
"Delete the current schema"
Keys.onReturnPressed: deleteSchema()
Keys.onSpacePressed: deleteSchema()
onClicked: deleteSchema()
}
}
}
CCreateSchemaDialog {
visible: createDlg; onCancelled: createDlg = false
onCreateRequested: function(n, d) {
var r = SDBAL.addSchema(schemas, n, d, dbal, loadSchemas)
if (r) { schemas = r.schemas;
selSch = r.selectedIndex; selFld = -1 }
createDlg = false }
}
CAddFieldDialog {
visible: addFldDlg; fieldTypes: root.fieldTypes
onFieldAdded: function(f) {
nfName = f.name; nfType = f.type; nfR = f.required
nfDv = f.defaultValue; nfDc = f.description; addField() }
onCancelled: addFldDlg = false
}
}