@adaptabletools/adaptable
Version:
Powerful AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
226 lines (225 loc) • 6.94 kB
JavaScript
import { eventMatchesKeyboardShortcut } from '@infinite-table/infinite-react';
const DEFAULT_INCREMENT_KEY = '+';
const DEFAULT_DECREMENT_KEY = '-';
const MODIFIER_TOKENS = new Set(['cmd', 'meta', 'ctrl', 'control', 'alt', 'shift']);
const MODIFIER_ALIASES = { control: 'ctrl', meta: 'cmd' };
const KEY_ALIASES = { esc: 'escape' };
function isPlusMinusCombination(trigger) {
return trigger.length > 1;
}
export function resolvePlusMinusTriggerKeysForNudge(nudge, globalOptions) {
const incrementKey = nudge.IncrementKey?.trim() || plusMinusIncrementKeyFromOptionsOnly(globalOptions);
const decrementKey = nudge.DecrementKey?.trim() || plusMinusDecrementKeyFromOptionsOnly(globalOptions);
return { incrementKey, decrementKey };
}
export function plusMinusResolvedKeysConflict(nudge, globalOptions) {
const { incrementKey, decrementKey } = resolvePlusMinusTriggerKeysForNudge(nudge, globalOptions);
const normalizedIncrement = normalizePlusMinusTrigger(incrementKey);
const normalizedDecrement = normalizePlusMinusTrigger(decrementKey);
if (!normalizedIncrement || !normalizedDecrement) {
return false;
}
return normalizedIncrement === normalizedDecrement;
}
export function plusMinusEventMatchesTrigger(event, configuredKey) {
const trigger = (configuredKey ?? '').trim();
if (!trigger) {
return false;
}
const pressedKey = event?.key;
if (!pressedKey) {
return false;
}
if (!isPlusMinusCombination(trigger)) {
return pressedKey.length === 1 && pressedKey.toLowerCase() === trigger.toLowerCase();
}
return eventMatchesKeyboardShortcut({
key: pressedKey,
metaKey: !!event.metaKey,
altKey: !!event.altKey,
ctrlKey: !!event.ctrlKey,
shiftKey: !!event.shiftKey,
}, trigger);
}
export function plusMinusIncrementKeyFromOptionsOnly(globalOptions) {
return globalOptions?.incrementKey?.trim() || DEFAULT_INCREMENT_KEY;
}
export function plusMinusDecrementKeyFromOptionsOnly(globalOptions) {
return globalOptions?.decrementKey?.trim() || DEFAULT_DECREMENT_KEY;
}
export function normalizePlusMinusTrigger(trigger) {
const value = (trigger ?? '').trim();
if (!value) {
return '';
}
if (!isPlusMinusCombination(value)) {
return value.toLowerCase();
}
const parts = value
.split('+')
.map((part) => part.trim().toLowerCase())
.filter(Boolean);
const modifiers = [];
const keys = [];
for (const part of parts) {
if (MODIFIER_TOKENS.has(part)) {
modifiers.push(MODIFIER_ALIASES[part] ?? part);
}
else {
keys.push(KEY_ALIASES[part] ?? part);
}
}
modifiers.sort();
return [...modifiers, ...keys].join('+');
}
export function plusMinusTriggerSameAsBaseline(candidate, baseline) {
return normalizePlusMinusTrigger(candidate) === normalizePlusMinusTrigger(baseline);
}
const MODIFIER_KEY_NAMES = new Set([
'Shift',
'Control',
'Alt',
'Meta',
'OS',
'AltGraph',
'CapsLock',
'NumLock',
'ScrollLock',
'Hyper',
'Super',
'Fn',
'FnLock',
'Dead',
]);
function activeModifierTokens(event) {
const tokens = [];
if (event.ctrlKey) {
tokens.push('ctrl');
}
if (event.altKey) {
tokens.push('alt');
}
if (event.metaKey) {
tokens.push('cmd');
}
if (event.shiftKey) {
tokens.push('shift');
}
return tokens;
}
export function capturePlusMinusTriggerFromEvent(event) {
const key = event?.key;
const modifiers = activeModifierTokens(event);
if (!key || MODIFIER_KEY_NAMES.has(key)) {
return { kind: 'pending', modifiers };
}
const isPrintable = key.length === 1;
const keyPart = isPrintable ? key.toLowerCase() : key;
if (!modifiers.length) {
return { kind: 'captured', trigger: keyPart };
}
const shiftOnly = modifiers.length === 1 && modifiers[0] === 'shift';
const isLetter = isPrintable && /^[a-z]$/.test(keyPart);
if (isPrintable && shiftOnly && !isLetter) {
return { kind: 'captured', trigger: keyPart };
}
if (keyPart.includes('+')) {
return { kind: 'invalid', reason: 'This key cannot be combined with modifiers.' };
}
return { kind: 'captured', trigger: [...modifiers, keyPart].join('+') };
}
const KEY_DISPLAY_LABELS = {
ctrl: 'Ctrl',
cmd: 'Cmd',
alt: 'Alt',
shift: 'Shift',
enter: 'Enter',
escape: 'Esc',
esc: 'Esc',
tab: 'Tab',
space: 'Space',
backspace: 'Backspace',
delete: 'Delete',
insert: 'Insert',
arrowup: '↑',
arrowdown: '↓',
arrowleft: '←',
arrowright: '→',
pageup: 'Page Up',
pagedown: 'Page Down',
home: 'Home',
end: 'End',
};
export function plusMinusKeyLabel(token) {
const value = (token ?? '').trim();
if (!value) {
return '';
}
const lower = value.toLowerCase();
if (KEY_DISPLAY_LABELS[lower]) {
return KEY_DISPLAY_LABELS[lower];
}
if (value.length === 1) {
return value;
}
return value.charAt(0).toUpperCase() + value.slice(1);
}
export function plusMinusTriggerDisplayParts(trigger) {
const value = (trigger ?? '').trim();
if (!value) {
return [];
}
if (!isPlusMinusCombination(value)) {
return [plusMinusKeyLabel(value)];
}
return value
.split('+')
.map((part) => part.trim())
.filter(Boolean)
.map(plusMinusKeyLabel);
}
function addConfiguredKeyToLookup(lookup, configuredKey) {
const trigger = (configuredKey ?? '').trim();
if (!trigger) {
return;
}
if (!isPlusMinusCombination(trigger)) {
lookup.effectiveKeysLower.add(trigger.toLowerCase());
return;
}
const parts = trigger
.split('+')
.map((part) => part.trim().toLowerCase())
.filter(Boolean);
for (const part of parts) {
if (MODIFIER_TOKENS.has(part)) {
continue;
}
if (part === '*') {
lookup.matchAnyKey = true;
continue;
}
lookup.effectiveKeysLower.add(KEY_ALIASES[part] ?? part);
}
}
export function buildPlusMinusTriggerKeyLookup(nudges, globalOptions) {
const lookup = {
effectiveKeysLower: new Set(),
matchAnyKey: false,
};
for (const nudge of nudges) {
const { incrementKey, decrementKey } = resolvePlusMinusTriggerKeysForNudge(nudge, globalOptions);
addConfiguredKeyToLookup(lookup, incrementKey);
addConfiguredKeyToLookup(lookup, decrementKey);
}
return lookup;
}
export function plusMinusKeyCouldTrigger(keyEventString, lookup) {
if (lookup.matchAnyKey) {
return true;
}
if (!keyEventString) {
return false;
}
return lookup.effectiveKeysLower.has(keyEventString.toLowerCase());
}