box-ui-elements
Version:
Box UI Elements
301 lines (292 loc) • 11.1 kB
JavaScript
import * as React from 'react';
import { Card, Text, InlineNotice } from '@box/blueprint-web';
import Button from '../button/Button';
import Modal from '../modal/Modal';
import ModalActions from '../modal/ModalActions';
import HotkeyLayer from './HotkeyLayer';
import HotkeyRecord from './HotkeyRecord';
export const Hotkeys = () => {
const [message, setMessage] = React.useState('Press keys to see actions');
const [count, setCount] = React.useState(0);
const [baseMessage, setBaseMessage] = React.useState('Base layer active');
const [modalMessage, setModalMessage] = React.useState('Modal layer active');
const [isModalOpen, setIsModalOpen] = React.useState(false);
const [action, setAction] = React.useState('No action yet');
const baseHotkeys = [
// Basic single key hotkeys
new HotkeyRecord({
key: 'a',
handler: () => {
setMessage('Hotkey "a" was pressed!');
setCount(c => c + 1);
},
description: 'Show a message',
type: 'navigation',
}),
new HotkeyRecord({
key: 'b',
handler: () => {
setMessage('Hotkey "b" was pressed!');
setCount(c => c + 1);
},
description: 'Show another message',
type: 'navigation',
}),
new HotkeyRecord({
key: 'c',
handler: () => {
setCount(0);
setMessage('Count reset!');
},
description: 'Reset counter',
type: 'actions',
}),
// Navigation hotkeys
new HotkeyRecord({
key: 'n',
handler: () => {
setAction('Next item');
},
description: 'Go to next item',
type: 'navigation',
}),
new HotkeyRecord({
key: 'p',
handler: () => {
setAction('Previous item');
},
description: 'Go to previous item',
type: 'navigation',
}),
// Action hotkeys
new HotkeyRecord({
key: 's',
handler: () => {
setAction('Save changes');
},
description: 'Save',
type: 'actions',
}),
new HotkeyRecord({
key: 'd',
handler: () => {
setAction('Delete item');
},
description: 'Delete',
type: 'actions',
}),
// Key combinations
new HotkeyRecord({
key: 'ctrl+s',
handler: event => {
event.preventDefault();
setAction('Save (Ctrl+S)');
},
description: 'Save document',
type: 'actions',
}),
new HotkeyRecord({
key: 'shift+a',
handler: event => {
event.preventDefault();
setAction('Select All (Shift+A)');
},
description: 'Select all items',
type: 'actions',
}),
new HotkeyRecord({
key: ['ctrl+z', 'meta+z'],
handler: () => {
setAction('Undo (Ctrl+Z or Cmd+Z)');
},
description: 'Undo last action',
type: 'actions',
}),
new HotkeyRecord({
key: 'alt+n',
handler: event => {
event.preventDefault();
setAction('New (Alt+N)');
},
description: 'Create new item',
type: 'actions',
}),
// Hidden hotkey (no type)
new HotkeyRecord({
key: 'h',
handler: () => {
setMessage('Hidden hotkey pressed');
},
description: null, // Hidden hotkey
}),
// Open modal
new HotkeyRecord({
key: 'o',
handler: () => {
setIsModalOpen(true);
},
description: 'Open modal',
type: 'base',
}),
// Base layer action that will be overridden by modal
new HotkeyRecord({
key: 'x',
handler: () => {
setBaseMessage('Base hotkey "x" pressed');
},
description: 'Base layer action',
type: 'base',
}),
];
const modalHotkeys = [
new HotkeyRecord({
key: 'x',
handler: () => {
setModalMessage('Modal hotkey "x" pressed (overrides base)');
},
description: 'Modal layer action',
type: 'modal',
}),
new HotkeyRecord({
key: 'esc',
handler: () => {
setIsModalOpen(false);
},
description: 'Close modal',
type: 'modal',
}),
new HotkeyRecord({
key: 's',
handler: () => {
setAction('Save from modal');
},
description: 'Save in modal',
type: 'modal',
}),
];
return (
<HotkeyLayer configs={baseHotkeys} enableHelpModal helpModalShortcut="?">
<Card>
<div>
<Card>
<Text as="h2">Hotkeys</Text>
<Text>
<strong>Basic:</strong> <kbd>a</kbd> <kbd>b</kbd> <kbd>c</kbd>
</Text>
<Text>
<strong>Navigation:</strong> <kbd>n</kbd> <kbd>p</kbd>
</Text>
<Text>
<strong>Actions:</strong> <kbd>s</kbd> <kbd>d</kbd>
</Text>
<Text>
<strong>Combinations:</strong> <kbd>Ctrl</kbd>+<kbd>S</kbd> <kbd>Shift</kbd>+<kbd>A</kbd>{' '}
<kbd>Alt</kbd>+<kbd>N</kbd>
</Text>
<Text>
<strong>Hidden:</strong> <kbd>h</kbd> (not shown in help modal)
</Text>
<Text>
<strong>Modal:</strong> <kbd>o</kbd> to open, <kbd>esc</kbd> to close
</Text>
<Text>
<strong>Help:</strong> <kbd>?</kbd> to see all hotkeys
</Text>
</Card>
<Card>
<Text as="h2">Status</Text>
<Text>
<strong>Message:</strong> {message}
</Text>
<Text>
<strong>Hotkeys triggered:</strong> {count}
</Text>
<Text>
<strong>Last action:</strong> {action}
</Text>
<Text>
<strong>Base Layer:</strong> {baseMessage}
</Text>
<Text>
<strong>Modal Layer:</strong> {modalMessage}
</Text>
</Card>
</div>
<InlineNotice title="Features Demonstrated" type="info">
<ul>
<li>
<strong>Basic hotkeys:</strong> Single key presses (a, b, c)
</li>
<li>
<strong>Help modal:</strong> Press <kbd>?</kbd> to see all available hotkeys organized by
type
</li>
<li>
<strong>Multiple types:</strong> Hotkeys categorized as navigation, actions, base, modal
</li>
<li>
<strong>Hidden hotkeys:</strong> Press <kbd>h</kbd> - it works but won't show in help
modal (no type)
</li>
<li>
<strong>Key combinations:</strong> Modifier keys like Ctrl+S, Shift+A, Alt+N
</li>
<li>
<strong>Multiple bindings:</strong> Ctrl+Z (Windows/Linux) or Cmd+Z (Mac) for the same
action
</li>
<li>
<strong>Nested layers:</strong> Press <kbd>o</kbd> to open modal - it has its own hotkey
layer that overrides base layer hotkeys
</li>
</ul>
</InlineNotice>
</Card>
{isModalOpen && (
<HotkeyLayer configs={modalHotkeys} enableHelpModal helpModalShortcut="?">
<Modal
isOpen={isModalOpen}
onRequestClose={() => setIsModalOpen(false)}
title="Modal Layer (Active)"
>
<Text>This modal has its own hotkey layer that overrides the base layer.</Text>
<InlineNotice title="Try these in the modal:" type="warning">
<ul>
<li>
Press <kbd>x</kbd> - triggers modal action (not base action)
</li>
<li>
Press <kbd>s</kbd> - saves from modal context
</li>
<li>
Press <kbd>esc</kbd> - closes modal
</li>
<li>
Press <kbd>?</kbd> - see only modal hotkeys in help
</li>
</ul>
<Text>
Notice how base layer hotkeys (like <kbd>a</kbd>, <kbd>b</kbd>) don't work here -
the modal layer blocks them!
</Text>
</InlineNotice>
<ModalActions>
<Button onClick={() => setIsModalOpen(false)}>Close Modal</Button>
</ModalActions>
</Modal>
</HotkeyLayer>
)}
</HotkeyLayer>
);
};
export default {
title: 'Components/Hotkeys',
component: HotkeyLayer,
parameters: {
notes:
'The Hotkey system allows you to register keyboard shortcut handlers. ' +
'Press "?" to open the help modal. ' +
'This demo shows all hotkey features: basic hotkeys, help modal, multiple types, ' +
'hidden hotkeys, key combinations, multiple bindings, and nested layers.',
},
};