diff --git a/src/index.ts b/src/index.ts index 32f55d73..18bc95b3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -128,4 +128,137 @@ export class KeyboardNavigation { toggleShortcutDialog(): void { this.navigationController.shortcutDialog.toggle(this.workspace); } + + /** + * Register CSS used by the plugin. + * This is broken up into sections by purpose, with some notes about + * where it should eventually live. + * Must be called before `Blockly.inject`. + */ + static registerKeyboardNavigationStyles() { + // Enable the delete icon for comments. + // + // This should remain in the plugin for the time being because we do + // not want to display the delete icon by default. + Blockly.Css.register(` + .blocklyDeleteIcon { + display: block; + } +`); + + // Set variables that will be used to control the appearance of the + // focus indicators. Attach them to the injectionDiv since they will + // apply to things contained therein. + // + // This should be moved to core, either to core/css.ts + // or to core/renderers/. + Blockly.Css.register(` + .injectionDiv { + --blockly-active-node-color: #fff200; + --blockly-active-tree-color: #60a5fa; + --blockly-selection-width: 3px; + } +`); + + // Styling focusing blocks, connections and fields. + // + // This should be moved to core, being integrated into the + // existing styling of renderers in core/renderers/*/constants.ts. + Blockly.Css.register(` + /* Blocks, connections and fields. */ + .blocklyKeyboardNavigation + .blocklyActiveFocus:is(.blocklyPath, .blocklyHighlightedConnectionPath), + .blocklyKeyboardNavigation + .blocklyActiveFocus.blocklyField + > .blocklyFieldRect, + .blocklyKeyboardNavigation + .blocklyActiveFocus.blocklyIconGroup + > .blocklyIconShape:first-child { + stroke: var(--blockly-active-node-color); + stroke-width: var(--blockly-selection-width); + } + .blocklyKeyboardNavigation + .blocklyPassiveFocus:is( + .blocklyPath:not(.blocklyFlyout .blocklyPath), + .blocklyHighlightedConnectionPath + ), + .blocklyKeyboardNavigation + .blocklyPassiveFocus.blocklyField + > .blocklyFieldRect, + .blocklyKeyboardNavigation + .blocklyPassiveFocus.blocklyIconGroup + > .blocklyIconShape:first-child { + stroke: var(--blockly-active-node-color); + stroke-dasharray: 5px 3px; + stroke-width: var(--blockly-selection-width); + } + .blocklyKeyboardNavigation + .blocklyPassiveFocus.blocklyHighlightedConnectionPath { + /* The connection path is being unexpectedly hidden in core */ + display: unset !important; + } +`); + + // Styling for focusing the toolbox and flyout. + // + // This should be moved to core, to core/css.ts if not to somewhere + // more specific in core/toolbox/. + Blockly.Css.register(` + .blocklyKeyboardNavigation .blocklyFlyout:has(.blocklyActiveFocus), + .blocklyKeyboardNavigation .blocklyToolbox:has(.blocklyActiveFocus), + .blocklyKeyboardNavigation + .blocklyActiveFocus:is(.blocklyFlyout, .blocklyToolbox) { + outline-offset: calc(var(--blockly-selection-width) * -1); + outline: var(--blockly-selection-width) solid + var(--blockly-active-tree-color); + } + .blocklyKeyboardNavigation + .blocklyToolboxCategoryContainer:focus-visible { + outline: none; + } +`); + + // Styling for focusing the Workspace. + // + // This should be move to core, probably to core/css.ts. + Blockly.Css.register(` + .blocklyKeyboardNavigation + .blocklyWorkspace:has(.blocklyActiveFocus) + .blocklyWorkspaceFocusRing, + .blocklyKeyboardNavigation + .blocklySvg:has(~ .blocklyBlockDragSurface .blocklyActiveFocus) + .blocklyWorkspaceFocusRing, + .blocklyKeyboardNavigation + .blocklyWorkspace.blocklyActiveFocus + .blocklyWorkspaceFocusRing { + stroke: var(--blockly-active-tree-color); + stroke-width: calc(var(--blockly-selection-width) * 2); + } + .blocklyKeyboardNavigation + .blocklyWorkspace.blocklyActiveFocus + .blocklyWorkspaceSelectionRing { + stroke: var(--blockly-active-node-color); + stroke-width: var(--blockly-selection-width); + } +`); + + // Keyboard-nav-specific styling for the context menu. + // + // This should remain in the plugin for the time being because the + // classes selected are currently only defined in the plugin. + Blockly.Css.register(` + .blocklyRTL .blocklyMenuItemContent .blocklyShortcutContainer { + flex-direction: row-reverse; + } + .blocklyMenuItemContent .blocklyShortcutContainer { + width: 100%; + display: flex; + justify-content: space-between; + gap: 16px; + } + .blocklyMenuItemContent .blocklyShortcutContainer .blocklyShortcut { + color: #ccc; + } +`); + } } diff --git a/test/index.html b/test/index.html index 6fca8c38..212d0354 100644 --- a/test/index.html +++ b/test/index.html @@ -33,10 +33,6 @@ position: relative; } - .blocklyToolboxDiv ~ .blocklyFlyout:focus { - outline: none; - } - pre, code { overflow: auto; @@ -89,98 +85,6 @@ thead { font-weight: bold; } - - html { - --blockly-active-node-color: #fff200; - --blockly-active-tree-color: #60a5fa; - --blockly-selection-width: 3px; - } - * { - box-sizing: border-box; - } - - .blocklyDeleteIcon { - display: block; - } - - /* Blocks, connections and fields. */ - .blocklyKeyboardNavigation - .blocklyActiveFocus:is(.blocklyPath, .blocklyHighlightedConnectionPath), - .blocklyKeyboardNavigation - .blocklyActiveFocus.blocklyField - > .blocklyFieldRect, - .blocklyKeyboardNavigation - .blocklyActiveFocus.blocklyIconGroup - > .blocklyIconShape:first-child { - stroke: var(--blockly-active-node-color); - stroke-width: var(--blockly-selection-width); - } - .blocklyKeyboardNavigation - .blocklyPassiveFocus:is( - .blocklyPath:not(.blocklyFlyout .blocklyPath), - .blocklyHighlightedConnectionPath - ), - .blocklyKeyboardNavigation - .blocklyPassiveFocus.blocklyField - > .blocklyFieldRect, - .blocklyKeyboardNavigation - .blocklyPassiveFocus.blocklyIconGroup - > .blocklyIconShape:first-child { - stroke: var(--blockly-active-node-color); - stroke-dasharray: 5px 3px; - stroke-width: var(--blockly-selection-width); - } - .blocklyKeyboardNavigation - .blocklyPassiveFocus.blocklyHighlightedConnectionPath { - /* The connection path is being unexpectedly hidden in core */ - display: unset !important; - } - - /* Toolbox and flyout. */ - .blocklyKeyboardNavigation .blocklyFlyout:has(.blocklyActiveFocus), - .blocklyKeyboardNavigation .blocklyToolbox:has(.blocklyActiveFocus), - .blocklyKeyboardNavigation - .blocklyActiveFocus:is(.blocklyFlyout, .blocklyToolbox) { - outline-offset: calc(var(--blockly-selection-width) * -1); - outline: var(--blockly-selection-width) solid - var(--blockly-active-tree-color); - } - /* Workspace */ - .blocklyKeyboardNavigation - .blocklyWorkspace:has(.blocklyActiveFocus) - .blocklyWorkspaceFocusRing, - .blocklyKeyboardNavigation - .blocklySvg:has(~ .blocklyBlockDragSurface .blocklyActiveFocus) - .blocklyWorkspaceFocusRing, - .blocklyKeyboardNavigation - .blocklyWorkspace.blocklyActiveFocus - .blocklyWorkspaceFocusRing { - stroke: var(--blockly-active-tree-color); - stroke-width: calc(var(--blockly-selection-width) * 2); - } - .blocklyKeyboardNavigation - .blocklyWorkspace.blocklyActiveFocus - .blocklyWorkspaceSelectionRing { - stroke: var(--blockly-active-node-color); - stroke-width: var(--blockly-selection-width); - } - .blocklyKeyboardNavigation - .blocklyToolboxCategoryContainer:focus-visible { - outline: none; - } - - .blocklyRTL .blocklyMenuItemContent .blocklyShortcutContainer { - flex-direction: row-reverse; - } - .blocklyMenuItemContent .blocklyShortcutContainer { - width: 100%; - display: flex; - justify-content: space-between; - gap: 16px; - } - .blocklyMenuItemContent .blocklyShortcutContainer .blocklyShortcut { - color: #ccc; - } diff --git a/test/index.ts b/test/index.ts index c7a40388..a49c42c0 100644 --- a/test/index.ts +++ b/test/index.ts @@ -89,6 +89,9 @@ function createWorkspace(): Blockly.WorkspaceSvg { if (!blocklyDiv) { throw new Error('Missing blocklyDiv'); } + + // Must be called before injection. + KeyboardNavigation.registerKeyboardNavigationStyles(); const workspace = Blockly.inject(blocklyDiv, injectOptions); Blockly.ContextMenuItems.registerCommentOptions(); diff --git a/test/webdriverio/index.html b/test/webdriverio/index.html index ded3c1db..0a1b923c 100644 --- a/test/webdriverio/index.html +++ b/test/webdriverio/index.html @@ -38,14 +38,6 @@ height: calc(100% - calc(var(--outline-width) * 2)); } - .blocklyToolboxDiv ~ .blocklyFlyout:focus { - outline: none; - } - - .blocklyDeleteIcon { - display: block; - } - pre, code { overflow: auto; diff --git a/test/webdriverio/index.ts b/test/webdriverio/index.ts index a43d4038..63ef40bc 100644 --- a/test/webdriverio/index.ts +++ b/test/webdriverio/index.ts @@ -78,6 +78,8 @@ function createWorkspace(): Blockly.WorkspaceSvg { if (!blocklyDiv) { throw new Error('Missing blocklyDiv'); } + // Must be called before injection. + KeyboardNavigation.registerKeyboardNavigationStyles(); const workspace = Blockly.inject(blocklyDiv, injectOptions); new KeyboardNavigation(workspace);