@entifix/react-controls 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/i18n/catalog/en.d.ts.map +1 -1
- package/dist/i18n/catalog/en.js +55 -9
- package/dist/i18n/catalog/en.js.map +1 -1
- package/dist/i18n/catalog/es.d.ts +64 -5
- package/dist/i18n/catalog/es.d.ts.map +1 -1
- package/dist/i18n/catalog/es.js +61 -9
- package/dist/i18n/catalog/es.js.map +1 -1
- package/dist/i18n/catalog/index.d.ts +102 -10
- package/dist/i18n/catalog/index.d.ts.map +1 -1
- package/dist/i18n/entity-labels.d.ts +14 -0
- package/dist/i18n/entity-labels.d.ts.map +1 -1
- package/dist/i18n/entity-labels.js +15 -0
- package/dist/i18n/entity-labels.js.map +1 -1
- package/dist/i18n/i18n-context.js +2 -2
- package/dist/i18n/i18n-context.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/primitives.d.ts +0 -1
- package/dist/primitives.d.ts.map +1 -1
- package/dist/primitives.js +0 -1
- package/dist/primitives.js.map +1 -1
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +1 -0
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/theme-context.d.ts +15 -3
- package/dist/theme/theme-context.d.ts.map +1 -1
- package/dist/theme/theme-context.js +49 -23
- package/dist/theme/theme-context.js.map +1 -1
- package/dist/theme/theme-cookie.d.ts +9 -0
- package/dist/theme/theme-cookie.d.ts.map +1 -0
- package/dist/theme/theme-cookie.js +8 -0
- package/dist/theme/theme-cookie.js.map +1 -0
- package/dist/theme/theme-script.d.ts +8 -6
- package/dist/theme/theme-script.d.ts.map +1 -1
- package/dist/theme/theme-script.js +21 -12
- package/dist/theme/theme-script.js.map +1 -1
- package/dist/ui/actions/action-surfaces.d.ts +1 -1
- package/dist/ui/actions/action-surfaces.js +1 -1
- package/dist/ui/actions/action-surfaces.js.map +1 -1
- package/dist/ui/actions/error-actions.d.ts +32 -0
- package/dist/ui/actions/error-actions.d.ts.map +1 -0
- package/dist/ui/actions/error-actions.js +40 -0
- package/dist/ui/actions/error-actions.js.map +1 -0
- package/dist/ui/actions/index.d.ts +3 -0
- package/dist/ui/actions/index.d.ts.map +1 -1
- package/dist/ui/actions/index.js +3 -0
- package/dist/ui/actions/index.js.map +1 -1
- package/dist/ui/actions/shortcut.d.ts +13 -0
- package/dist/ui/actions/shortcut.d.ts.map +1 -0
- package/dist/ui/actions/shortcut.js +18 -0
- package/dist/ui/actions/shortcut.js.map +1 -0
- package/dist/ui/actions/use-verb-invoker.d.ts +55 -0
- package/dist/ui/actions/use-verb-invoker.d.ts.map +1 -0
- package/dist/ui/actions/use-verb-invoker.js +98 -0
- package/dist/ui/actions/use-verb-invoker.js.map +1 -0
- package/dist/ui/atoms/cell-value/cell-value.d.ts.map +1 -1
- package/dist/ui/atoms/cell-value/cell-value.js +28 -14
- package/dist/ui/atoms/cell-value/cell-value.js.map +1 -1
- package/dist/ui/atoms/field-control/field-control.d.ts +1 -0
- package/dist/ui/atoms/field-control/field-control.d.ts.map +1 -1
- package/dist/ui/atoms/field-control/field-control.js +2 -0
- package/dist/ui/atoms/field-control/field-control.js.map +1 -1
- package/dist/ui/atoms/number-input/quantity-input.d.ts +8 -1
- package/dist/ui/atoms/number-input/quantity-input.d.ts.map +1 -1
- package/dist/ui/atoms/number-input/quantity-input.js +2 -1
- package/dist/ui/atoms/number-input/quantity-input.js.map +1 -1
- package/dist/ui/atoms/table/table.d.ts +12 -3
- package/dist/ui/atoms/table/table.d.ts.map +1 -1
- package/dist/ui/atoms/table/table.js +59 -10
- package/dist/ui/atoms/table/table.js.map +1 -1
- package/dist/ui/atoms/text/text.d.ts +2 -2
- package/dist/ui/atoms/text/text.d.ts.map +1 -1
- package/dist/ui/atoms/text/text.js.map +1 -1
- package/dist/ui/molecules/action-bar/action-bar.d.ts +76 -0
- package/dist/ui/molecules/action-bar/action-bar.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/action-bar.js +218 -0
- package/dist/ui/molecules/action-bar/action-bar.js.map +1 -0
- package/dist/ui/molecules/action-bar/index.d.ts +2 -0
- package/dist/ui/molecules/action-bar/index.d.ts.map +1 -0
- package/dist/ui/molecules/action-bar/index.js +3 -0
- package/dist/ui/molecules/action-bar/index.js.map +1 -0
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.d.ts.map +1 -1
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js +8 -10
- package/dist/ui/molecules/bulk-action-bar/bulk-action-bar.js.map +1 -1
- package/dist/ui/molecules/bulk-result/bulk-result.d.ts +3 -3
- package/dist/ui/molecules/bulk-result/bulk-result.js +4 -4
- package/dist/ui/molecules/bulk-result/bulk-result.js.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts +24 -9
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.d.ts.map +1 -1
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js +36 -11
- package/dist/ui/molecules/confirm-dialog/confirm-dialog.js.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts +33 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.d.ts.map +1 -1
- package/dist/ui/molecules/entity-record-card/entity-record-card.js +53 -20
- package/dist/ui/molecules/entity-record-card/entity-record-card.js.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts +8 -2
- package/dist/ui/molecules/filter-builder/filter-builder.d.ts.map +1 -1
- package/dist/ui/molecules/filter-builder/filter-builder.js +14 -5
- package/dist/ui/molecules/filter-builder/filter-builder.js.map +1 -1
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts +16 -0
- package/dist/ui/molecules/filter-chips/filter-chips.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js +73 -0
- package/dist/ui/molecules/filter-chips/filter-chips.js.map +1 -0
- package/dist/ui/molecules/filter-chips/index.d.ts +2 -0
- package/dist/ui/molecules/filter-chips/index.d.ts.map +1 -0
- package/dist/ui/molecules/filter-chips/index.js +3 -0
- package/dist/ui/molecules/filter-chips/index.js.map +1 -0
- package/dist/ui/molecules/menu/menu.d.ts +11 -1
- package/dist/ui/molecules/menu/menu.d.ts.map +1 -1
- package/dist/ui/molecules/menu/menu.js +62 -2
- package/dist/ui/molecules/menu/menu.js.map +1 -1
- package/dist/ui/molecules/pagination/pagination.d.ts +5 -0
- package/dist/ui/molecules/pagination/pagination.d.ts.map +1 -1
- package/dist/ui/molecules/pagination/pagination.js +35 -18
- package/dist/ui/molecules/pagination/pagination.js.map +1 -1
- package/dist/ui/molecules/region-state/index.d.ts +2 -0
- package/dist/ui/molecules/region-state/index.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/index.js +3 -0
- package/dist/ui/molecules/region-state/index.js.map +1 -0
- package/dist/ui/molecules/region-state/region-state.d.ts +42 -0
- package/dist/ui/molecules/region-state/region-state.d.ts.map +1 -0
- package/dist/ui/molecules/region-state/region-state.js +83 -0
- package/dist/ui/molecules/region-state/region-state.js.map +1 -0
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts +3 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.d.ts.map +1 -1
- package/dist/ui/molecules/table-toolbar/table-toolbar.js +3 -2
- package/dist/ui/molecules/table-toolbar/table-toolbar.js.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.d.ts +63 -19
- package/dist/ui/molecules/toast-region/toast-region.d.ts.map +1 -1
- package/dist/ui/molecules/toast-region/toast-region.js +129 -42
- package/dist/ui/molecules/toast-region/toast-region.js.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.d.ts.map +1 -1
- package/dist/ui/organisms/command-palette/command-palette.js +19 -12
- package/dist/ui/organisms/command-palette/command-palette.js.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.d.ts.map +1 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js +0 -1
- package/dist/ui/organisms/entity-detail-grid/entity-detail-grid.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts +1 -1
- package/dist/ui/organisms/entity-form/entity-form.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.js +322 -214
- package/dist/ui/organisms/entity-form/entity-form.js.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts +16 -0
- package/dist/ui/organisms/entity-form/entity-form.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-form/entity-form.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts +1 -1
- package/dist/ui/organisms/entity-table/entity-table.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.js +332 -197
- package/dist/ui/organisms/entity-table/entity-table.js.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts +19 -4
- package/dist/ui/organisms/entity-table/entity-table.types.d.ts.map +1 -1
- package/dist/ui/organisms/entity-table/entity-table.types.js.map +1 -1
- package/dist/ui/organisms/entity-table/header-sort.d.ts +18 -0
- package/dist/ui/organisms/entity-table/header-sort.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/header-sort.js +54 -0
- package/dist/ui/organisms/entity-table/header-sort.js.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts +25 -0
- package/dist/ui/organisms/entity-table/pivot.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/pivot.js +106 -0
- package/dist/ui/organisms/entity-table/pivot.js.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts +13 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.d.ts.map +1 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js +31 -0
- package/dist/ui/organisms/entity-table/use-result-announcement.js.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts +11 -0
- package/dist/ui/organisms/top-bar/live-indicator.d.ts.map +1 -0
- package/dist/ui/organisms/top-bar/live-indicator.js +46 -0
- package/dist/ui/organisms/top-bar/live-indicator.js.map +1 -0
- package/dist/ui/organisms/top-bar/top-bar.d.ts +11 -2
- package/dist/ui/organisms/top-bar/top-bar.d.ts.map +1 -1
- package/dist/ui/organisms/top-bar/top-bar.js +14 -5
- package/dist/ui/organisms/top-bar/top-bar.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts +1 -1
- package/dist/ui/organisms/wizard/wizard.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.js +7 -1
- package/dist/ui/organisms/wizard/wizard.js.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.d.ts +8 -0
- package/dist/ui/organisms/wizard/wizard.types.d.ts.map +1 -1
- package/dist/ui/organisms/wizard/wizard.types.js.map +1 -1
- package/dist/ui/utils/live-updates.d.ts +24 -0
- package/dist/ui/utils/live-updates.d.ts.map +1 -0
- package/dist/ui/utils/live-updates.js +20 -0
- package/dist/ui/utils/live-updates.js.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts +14 -0
- package/dist/ui/utils/use-focus-on-arrival.d.ts.map +1 -0
- package/dist/ui/utils/use-focus-on-arrival.js +42 -0
- package/dist/ui/utils/use-focus-on-arrival.js.map +1 -0
- package/dist/ui/utils/use-hotkey.d.ts +44 -25
- package/dist/ui/utils/use-hotkey.d.ts.map +1 -1
- package/dist/ui/utils/use-hotkey.js +80 -48
- package/dist/ui/utils/use-hotkey.js.map +1 -1
- package/package.json +5 -5
- package/dist/ui/molecules/split-button/index.d.ts +0 -2
- package/dist/ui/molecules/split-button/index.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/index.js +0 -3
- package/dist/ui/molecules/split-button/index.js.map +0 -1
- package/dist/ui/molecules/split-button/split-button.d.ts +0 -21
- package/dist/ui/molecules/split-button/split-button.d.ts.map +0 -1
- package/dist/ui/molecules/split-button/split-button.js +0 -35
- package/dist/ui/molecules/split-button/split-button.js.map +0 -1
|
@@ -1,31 +1,50 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly
|
|
1
|
+
/**
|
|
2
|
+
* Where a set of shortcuts applies: the page, or one workspace tab. A tab's
|
|
3
|
+
* shortcuts fire only while it is the active tab, so two tabs each holding a
|
|
4
|
+
* form can both bind Mod+S without one saving the other.
|
|
5
|
+
*/
|
|
6
|
+
export interface HotkeyScope {
|
|
7
|
+
readonly id: string;
|
|
8
|
+
readonly active: boolean;
|
|
8
9
|
}
|
|
10
|
+
/** The page: every shortcut outside a workspace tab. */
|
|
11
|
+
export declare const PAGE_SCOPE: HotkeyScope;
|
|
9
12
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
* Scopes the shortcuts bound below it — a workspace tab passes its own id and
|
|
14
|
+
* whether it is the active tab.
|
|
15
|
+
*/
|
|
16
|
+
export declare const HotkeyScopeProvider: import("react").Provider<HotkeyScope>;
|
|
17
|
+
/** For specs: a page with nothing bound. */
|
|
18
|
+
export declare const resetHotkeysForTesting: () => void;
|
|
19
|
+
export interface HotkeyOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Bind only if the chord is free, and stay silent if it is not. Without it
|
|
22
|
+
* a second binding of a chord in one scope throws at registration: two
|
|
23
|
+
* handlers for one keystroke is a bug, and whichever fired first would
|
|
24
|
+
* decide what the reader got. A built-in default — a form's Mod+S — takes
|
|
25
|
+
* this, so a host's own binding wins.
|
|
26
|
+
*/
|
|
27
|
+
readonly ifFree?: boolean;
|
|
28
|
+
/** Bound only while true; a disabled control's shortcut does nothing. */
|
|
29
|
+
readonly enabled?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Runs `handler` on any of `chords` — `"Mod+K"`, `"Mod+Shift+P"` — within
|
|
33
|
+
* the nearest {@link HotkeyScope} (ADR 0026).
|
|
19
34
|
*
|
|
20
|
-
* **
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
35
|
+
* - **Modifier chords only**: every one holds `Mod`, so no single key or
|
|
36
|
+
* Shift+key steals a character from a reader typing (WCAG 2.1.4), and no
|
|
37
|
+
* Alt+letter, which macOS Option composes into a character. The editing
|
|
38
|
+
* chords — Mod+A, C, V, X, Y, Z — stay the field's. Anything else throws
|
|
39
|
+
* when it is bound.
|
|
40
|
+
* - **They fire inside a text field**: a chord is never typing, and Mod+S
|
|
41
|
+
* is exactly what a reader presses with the caret in a field.
|
|
42
|
+
* - **A chord is held once per scope**, so a conflict is refused when it is
|
|
43
|
+
* bound rather than resolved by whoever listens first.
|
|
26
44
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
45
|
+
* It calls `preventDefault`, which stops the browser's own action for the
|
|
46
|
+
* chord where the browser lets it; no binding should be the only way to do
|
|
47
|
+
* anything, so a visible control always does the same thing.
|
|
29
48
|
*/
|
|
30
|
-
export declare function useHotkey(
|
|
49
|
+
export declare function useHotkey(chords: readonly string[], handler: (event: KeyboardEvent) => void, { ifFree, enabled }?: HotkeyOptions): void;
|
|
31
50
|
//# sourceMappingURL=use-hotkey.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-hotkey.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/use-hotkey.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-hotkey.d.ts","sourceRoot":"","sources":["../../../src/ui/utils/use-hotkey.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED,wDAAwD;AACxD,eAAO,MAAM,UAAU,EAAE,WAA0C,CAAC;AAIpE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,uCAA8B,CAAC;AAgC/D,4CAA4C;AAC5C,eAAO,MAAM,sBAAsB,QAAO,IAAqB,CAAC;AAUhE,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAC1B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,SAAS,MAAM,EAAE,EACzB,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,EACvC,EAAE,MAAc,EAAE,OAAc,EAAE,GAAE,aAAkB,GACrD,IAAI,CAqCN"}
|
|
@@ -1,68 +1,100 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// `closest`, not `isContentEditable`: the property is true for a *descendant*
|
|
8
|
-
// of an editable host but is not implemented in jsdom, so the branch that
|
|
9
|
-
// matters most for a rich editor would be the one no test could reach. The
|
|
10
|
-
// selector covers the host and everything inside it, and the `:not` arm is
|
|
11
|
-
// what keeps `contenteditable="false"` — the way a widget opts a subtree back
|
|
12
|
-
// out — from reading as editable.
|
|
13
|
-
return target.closest('[contenteditable]:not([contenteditable="false"])') !== null;
|
|
2
|
+
import { parseChord } from '@entifix/core';
|
|
3
|
+
import { createContext, useContext, useEffect, useRef } from 'react';
|
|
4
|
+
/** The page: every shortcut outside a workspace tab. */ export const PAGE_SCOPE = {
|
|
5
|
+
id: 'page',
|
|
6
|
+
active: true
|
|
14
7
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
const HotkeyScopeContext = createContext(PAGE_SCOPE);
|
|
9
|
+
/**
|
|
10
|
+
* Scopes the shortcuts bound below it — a workspace tab passes its own id and
|
|
11
|
+
* whether it is the active tab.
|
|
12
|
+
*/ export const HotkeyScopeProvider = HotkeyScopeContext.Provider;
|
|
13
|
+
/**
|
|
14
|
+
* Which chords each scope holds, for refusing a second binding of one. A
|
|
15
|
+
* chord is held at most once per scope — a second binding is refused or
|
|
16
|
+
* yields — so a set is enough.
|
|
17
|
+
*/ const bound = new Map();
|
|
18
|
+
const holds = (scope, chord)=>{
|
|
19
|
+
var _bound_get;
|
|
20
|
+
return ((_bound_get = bound.get(scope)) == null ? void 0 : _bound_get.has(chord)) === true;
|
|
24
21
|
};
|
|
25
22
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
23
|
+
* Whether `chord` is taken where `scope` would bind it: in the same scope, or
|
|
24
|
+
* — since the page's shortcuts apply inside every tab — between the page and
|
|
25
|
+
* a tab.
|
|
26
|
+
*/ function isTaken(scope, chord) {
|
|
27
|
+
if (holds(scope, chord)) return true;
|
|
28
|
+
if (scope === PAGE_SCOPE.id) return [
|
|
29
|
+
...bound.values()
|
|
30
|
+
].some((chords)=>chords.has(chord));
|
|
31
|
+
return holds(PAGE_SCOPE.id, chord);
|
|
32
|
+
}
|
|
33
|
+
function bind(scope, chord) {
|
|
34
|
+
var _bound_get;
|
|
35
|
+
const chords = (_bound_get = bound.get(scope)) != null ? _bound_get : new Set();
|
|
36
|
+
bound.set(scope, chords.add(chord));
|
|
37
|
+
return ()=>{
|
|
38
|
+
chords.delete(chord);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/** For specs: a page with nothing bound. */ export const resetHotkeysForTesting = ()=>bound.clear();
|
|
42
|
+
const matches = (event, chord)=>event.key.toLowerCase() === chord.key && // ⌘ and Ctrl are the same intent on different platforms, so either one
|
|
43
|
+
// satisfies `Mod` rather than each caller sniffing the platform.
|
|
44
|
+
(event.metaKey || event.ctrlKey) && event.shiftKey === chord.shift && event.altKey === chord.alt;
|
|
45
|
+
/**
|
|
46
|
+
* Runs `handler` on any of `chords` — `"Mod+K"`, `"Mod+Shift+P"` — within
|
|
47
|
+
* the nearest {@link HotkeyScope} (ADR 0026).
|
|
35
48
|
*
|
|
36
|
-
* **
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
49
|
+
* - **Modifier chords only**: every one holds `Mod`, so no single key or
|
|
50
|
+
* Shift+key steals a character from a reader typing (WCAG 2.1.4), and no
|
|
51
|
+
* Alt+letter, which macOS Option composes into a character. The editing
|
|
52
|
+
* chords — Mod+A, C, V, X, Y, Z — stay the field's. Anything else throws
|
|
53
|
+
* when it is bound.
|
|
54
|
+
* - **They fire inside a text field**: a chord is never typing, and Mod+S
|
|
55
|
+
* is exactly what a reader presses with the caret in a field.
|
|
56
|
+
* - **A chord is held once per scope**, so a conflict is refused when it is
|
|
57
|
+
* bound rather than resolved by whoever listens first.
|
|
42
58
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
|
|
59
|
+
* It calls `preventDefault`, which stops the browser's own action for the
|
|
60
|
+
* chord where the browser lets it; no binding should be the only way to do
|
|
61
|
+
* anything, so a visible control always does the same thing.
|
|
62
|
+
*/ export function useHotkey(chords, handler, { ifFree = false, enabled = true } = {}) {
|
|
63
|
+
const scope = useContext(HotkeyScopeContext);
|
|
46
64
|
const handlerRef = useRef(handler);
|
|
65
|
+
const activeRef = useRef(scope.active);
|
|
47
66
|
useEffect(()=>{
|
|
48
67
|
handlerRef.current = handler;
|
|
68
|
+
activeRef.current = scope.active;
|
|
49
69
|
});
|
|
50
|
-
//
|
|
51
|
-
|
|
52
|
-
// listener on each one.
|
|
53
|
-
const signature = JSON.stringify(hotkeys);
|
|
70
|
+
// Joined rather than passed by identity: callers write the list inline.
|
|
71
|
+
const signature = chords.join(' ');
|
|
54
72
|
useEffect(()=>{
|
|
55
|
-
|
|
73
|
+
if (!enabled || signature === '') return;
|
|
74
|
+
const parsed = signature.split(' ').map(parseChord);
|
|
75
|
+
const free = parsed.filter((chord)=>!isTaken(scope.id, chord.text));
|
|
76
|
+
if (free.length < parsed.length && !ifFree) {
|
|
77
|
+
const taken = parsed.find((chord)=>!free.includes(chord));
|
|
78
|
+
throw new Error(`${taken.text} is already bound here. A chord does one thing in a scope: unbind the other, or pass \`ifFree\` to the default that should yield.`);
|
|
79
|
+
}
|
|
80
|
+
if (free.length === 0) return;
|
|
81
|
+
const unbind = free.map((chord)=>bind(scope.id, chord.text));
|
|
56
82
|
const onKeyDown = (event)=>{
|
|
57
|
-
if (
|
|
58
|
-
if (!
|
|
83
|
+
if (!activeRef.current) return;
|
|
84
|
+
if (!free.some((chord)=>matches(event, chord))) return;
|
|
59
85
|
event.preventDefault();
|
|
60
86
|
handlerRef.current(event);
|
|
61
87
|
};
|
|
62
88
|
document.addEventListener('keydown', onKeyDown);
|
|
63
|
-
return ()=>
|
|
89
|
+
return ()=>{
|
|
90
|
+
document.removeEventListener('keydown', onKeyDown);
|
|
91
|
+
for (const release of unbind)release();
|
|
92
|
+
};
|
|
64
93
|
}, [
|
|
65
|
-
signature
|
|
94
|
+
signature,
|
|
95
|
+
scope.id,
|
|
96
|
+
ifFree,
|
|
97
|
+
enabled
|
|
66
98
|
]);
|
|
67
99
|
}
|
|
68
100
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/utils/use-hotkey.ts"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\n
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/utils/use-hotkey.ts"],"sourcesContent":["'use client';\n\nimport { parseChord, type ParsedChord } from '@entifix/core';\nimport { createContext, useContext, useEffect, useRef } from 'react';\n\n/**\n * Where a set of shortcuts applies: the page, or one workspace tab. A tab's\n * shortcuts fire only while it is the active tab, so two tabs each holding a\n * form can both bind Mod+S without one saving the other.\n */\nexport interface HotkeyScope {\n readonly id: string;\n readonly active: boolean;\n}\n\n/** The page: every shortcut outside a workspace tab. */\nexport const PAGE_SCOPE: HotkeyScope = { id: 'page', active: true };\n\nconst HotkeyScopeContext = createContext<HotkeyScope>(PAGE_SCOPE);\n\n/**\n * Scopes the shortcuts bound below it — a workspace tab passes its own id and\n * whether it is the active tab.\n */\nexport const HotkeyScopeProvider = HotkeyScopeContext.Provider;\n\n/**\n * Which chords each scope holds, for refusing a second binding of one. A\n * chord is held at most once per scope — a second binding is refused or\n * yields — so a set is enough.\n */\nconst bound = new Map<string, Set<string>>();\n\nconst holds = (scope: string, chord: string): boolean =>\n bound.get(scope)?.has(chord) === true;\n\n/**\n * Whether `chord` is taken where `scope` would bind it: in the same scope, or\n * — since the page's shortcuts apply inside every tab — between the page and\n * a tab.\n */\nfunction isTaken(scope: string, chord: string): boolean {\n if (holds(scope, chord)) return true;\n if (scope === PAGE_SCOPE.id)\n return [...bound.values()].some(chords => chords.has(chord));\n return holds(PAGE_SCOPE.id, chord);\n}\n\nfunction bind(scope: string, chord: string): () => void {\n const chords = bound.get(scope) ?? new Set<string>();\n bound.set(scope, chords.add(chord));\n return () => {\n chords.delete(chord);\n };\n}\n\n/** For specs: a page with nothing bound. */\nexport const resetHotkeysForTesting = (): void => bound.clear();\n\nconst matches = (event: KeyboardEvent, chord: ParsedChord): boolean =>\n event.key.toLowerCase() === chord.key &&\n // ⌘ and Ctrl are the same intent on different platforms, so either one\n // satisfies `Mod` rather than each caller sniffing the platform.\n (event.metaKey || event.ctrlKey) &&\n event.shiftKey === chord.shift &&\n event.altKey === chord.alt;\n\nexport interface HotkeyOptions {\n /**\n * Bind only if the chord is free, and stay silent if it is not. Without it\n * a second binding of a chord in one scope throws at registration: two\n * handlers for one keystroke is a bug, and whichever fired first would\n * decide what the reader got. A built-in default — a form's Mod+S — takes\n * this, so a host's own binding wins.\n */\n readonly ifFree?: boolean;\n /** Bound only while true; a disabled control's shortcut does nothing. */\n readonly enabled?: boolean;\n}\n\n/**\n * Runs `handler` on any of `chords` — `\"Mod+K\"`, `\"Mod+Shift+P\"` — within\n * the nearest {@link HotkeyScope} (ADR 0026).\n *\n * - **Modifier chords only**: every one holds `Mod`, so no single key or\n * Shift+key steals a character from a reader typing (WCAG 2.1.4), and no\n * Alt+letter, which macOS Option composes into a character. The editing\n * chords — Mod+A, C, V, X, Y, Z — stay the field's. Anything else throws\n * when it is bound.\n * - **They fire inside a text field**: a chord is never typing, and Mod+S\n * is exactly what a reader presses with the caret in a field.\n * - **A chord is held once per scope**, so a conflict is refused when it is\n * bound rather than resolved by whoever listens first.\n *\n * It calls `preventDefault`, which stops the browser's own action for the\n * chord where the browser lets it; no binding should be the only way to do\n * anything, so a visible control always does the same thing.\n */\nexport function useHotkey(\n chords: readonly string[],\n handler: (event: KeyboardEvent) => void,\n { ifFree = false, enabled = true }: HotkeyOptions = {},\n): void {\n const scope = useContext(HotkeyScopeContext);\n const handlerRef = useRef(handler);\n const activeRef = useRef(scope.active);\n useEffect(() => {\n handlerRef.current = handler;\n activeRef.current = scope.active;\n });\n\n // Joined rather than passed by identity: callers write the list inline.\n const signature = chords.join(' ');\n\n useEffect(() => {\n if (!enabled || signature === '') return;\n const parsed = signature.split(' ').map(parseChord);\n const free = parsed.filter(chord => !isTaken(scope.id, chord.text));\n if (free.length < parsed.length && !ifFree) {\n const taken = parsed.find(chord => !free.includes(chord)) as ParsedChord;\n throw new Error(\n `${taken.text} is already bound here. A chord does one thing in a scope: unbind the other, or pass \\`ifFree\\` to the default that should yield.`,\n );\n }\n if (free.length === 0) return;\n const unbind = free.map(chord => bind(scope.id, chord.text));\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (!activeRef.current) return;\n if (!free.some(chord => matches(event, chord))) return;\n event.preventDefault();\n handlerRef.current(event);\n };\n document.addEventListener('keydown', onKeyDown);\n return () => {\n document.removeEventListener('keydown', onKeyDown);\n for (const release of unbind) release();\n };\n }, [signature, scope.id, ifFree, enabled]);\n}\n"],"names":["parseChord","createContext","useContext","useEffect","useRef","PAGE_SCOPE","id","active","HotkeyScopeContext","HotkeyScopeProvider","Provider","bound","Map","holds","scope","chord","get","has","isTaken","values","some","chords","bind","Set","set","add","delete","resetHotkeysForTesting","clear","matches","event","key","toLowerCase","metaKey","ctrlKey","shiftKey","shift","altKey","alt","useHotkey","handler","ifFree","enabled","handlerRef","activeRef","current","signature","join","parsed","split","map","free","filter","text","length","taken","find","includes","Error","unbind","onKeyDown","preventDefault","document","addEventListener","removeEventListener","release"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entifix/react-controls",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Entity-agnostic React UI — table, form, filters, wizard, command palette — rendered from entity metadata, plus layout primitives.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@headlessui/react": "^2.2.10",
|
|
20
20
|
"class-variance-authority": "^0.7.1",
|
|
21
21
|
"idb": "^8.0.4",
|
|
22
|
-
"@entifix/core": "0.
|
|
22
|
+
"@entifix/core": "0.20.1"
|
|
23
23
|
},
|
|
24
24
|
"exports": {
|
|
25
25
|
"./package.json": "./package.json",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"react": "19.3.1",
|
|
56
56
|
"react-i18next": "17.1.10",
|
|
57
57
|
"storybook": "^10.6.5",
|
|
58
|
-
"@entifix/i18n": "0.
|
|
59
|
-
"@entifix/style": "0.
|
|
58
|
+
"@entifix/i18n": "0.20.1",
|
|
59
|
+
"@entifix/style": "0.20.1"
|
|
60
60
|
},
|
|
61
61
|
"nx": {
|
|
62
62
|
"tags": [
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"i18next": ">=26 <27",
|
|
112
112
|
"react": ">=19 <20",
|
|
113
113
|
"react-i18next": ">=17 <18",
|
|
114
|
-
"@entifix/i18n": "0.
|
|
114
|
+
"@entifix/i18n": "0.20.1"
|
|
115
115
|
},
|
|
116
116
|
"peerDependenciesMeta": {
|
|
117
117
|
"@entifix/i18n": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/split-button/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/split-button/index.ts"],"sourcesContent":["export * from './split-button.js';\n"],"names":[],"mappings":"AAAA,cAAc,oBAAoB"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* One main action, and a menu of the related ones beside it: `[Download │ ▾]`.
|
|
4
|
-
*
|
|
5
|
-
* The caller renders the main action — a link or a button, styled as the
|
|
6
|
-
* primary button — so it stays in the static HTML and keeps its own
|
|
7
|
-
* attributes; without `children` it stands alone, as before scripting runs.
|
|
8
|
-
* The menu is a `NavMenu`, so it opens with scripting off and the page's own
|
|
9
|
-
* menu handling closes it. Parts carry `data-slot` (`split-button`, and the
|
|
10
|
-
* menu's own).
|
|
11
|
-
*/
|
|
12
|
-
export declare function SplitButton({ primary, menuLabel, children, className, }: {
|
|
13
|
-
/** The main action, its corners squared on the side the menu joins. */
|
|
14
|
-
primary: ReactNode;
|
|
15
|
-
/** The accessible name of the ▾ trigger. */
|
|
16
|
-
menuLabel: string;
|
|
17
|
-
/** The menu's entries; none, and the main action stands alone. */
|
|
18
|
-
children?: ReactNode;
|
|
19
|
-
className?: string;
|
|
20
|
-
}): import("react").JSX.Element;
|
|
21
|
-
//# sourceMappingURL=split-button.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"split-button.d.ts","sourceRoot":"","sources":["../../../../src/ui/molecules/split-button/split-button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYvC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE;IACD,uEAAuE;IACvE,OAAO,EAAE,SAAS,CAAC;IACnB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAuBA"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { button } from '../../atoms/button/button-recipe.js';
|
|
3
|
-
import { cn } from '../../utils/cn.js';
|
|
4
|
-
import { NavMenu } from '../nav-menu/nav-menu.js';
|
|
5
|
-
/** The ▾ segment: the primary button's look, joined to the action before it. */ const TRIGGER = cn(button({
|
|
6
|
-
variant: 'primary',
|
|
7
|
-
size: 'sm'
|
|
8
|
-
}), 'h-auto cursor-pointer list-none self-stretch rounded-l-none border-l border-l-[color-mix(in_srgb,var(--color-primary-content)_25%,transparent)] px-2xs select-none [&_[data-slot=nav-menu-chevron]]:text-current [&::-webkit-details-marker]:hidden');
|
|
9
|
-
/**
|
|
10
|
-
* One main action, and a menu of the related ones beside it: `[Download │ ▾]`.
|
|
11
|
-
*
|
|
12
|
-
* The caller renders the main action — a link or a button, styled as the
|
|
13
|
-
* primary button — so it stays in the static HTML and keeps its own
|
|
14
|
-
* attributes; without `children` it stands alone, as before scripting runs.
|
|
15
|
-
* The menu is a `NavMenu`, so it opens with scripting off and the page's own
|
|
16
|
-
* menu handling closes it. Parts carry `data-slot` (`split-button`, and the
|
|
17
|
-
* menu's own).
|
|
18
|
-
*/ export function SplitButton({ primary, menuLabel, children, className }) {
|
|
19
|
-
return /*#__PURE__*/ _jsxs("div", {
|
|
20
|
-
"data-slot": "split-button",
|
|
21
|
-
className: cn('inline-flex items-stretch', children !== undefined && '[&>:first-child]:rounded-r-none', className),
|
|
22
|
-
children: [
|
|
23
|
-
primary,
|
|
24
|
-
children !== undefined && /*#__PURE__*/ _jsx(NavMenu, {
|
|
25
|
-
label: menuLabel,
|
|
26
|
-
icon: null,
|
|
27
|
-
className: "flex",
|
|
28
|
-
triggerClassName: TRIGGER,
|
|
29
|
-
children: children
|
|
30
|
-
})
|
|
31
|
-
]
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//# sourceMappingURL=split-button.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/molecules/split-button/split-button.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\n\nimport { button } from '../../atoms/button/button-recipe.js';\nimport { cn } from '../../utils/cn.js';\nimport { NavMenu } from '../nav-menu/nav-menu.js';\n\n/** The ▾ segment: the primary button's look, joined to the action before it. */\nconst TRIGGER = cn(\n button({ variant: 'primary', size: 'sm' }),\n 'h-auto cursor-pointer list-none self-stretch rounded-l-none border-l border-l-[color-mix(in_srgb,var(--color-primary-content)_25%,transparent)] px-2xs select-none [&_[data-slot=nav-menu-chevron]]:text-current [&::-webkit-details-marker]:hidden',\n);\n\n/**\n * One main action, and a menu of the related ones beside it: `[Download │ ▾]`.\n *\n * The caller renders the main action — a link or a button, styled as the\n * primary button — so it stays in the static HTML and keeps its own\n * attributes; without `children` it stands alone, as before scripting runs.\n * The menu is a `NavMenu`, so it opens with scripting off and the page's own\n * menu handling closes it. Parts carry `data-slot` (`split-button`, and the\n * menu's own).\n */\nexport function SplitButton({\n primary,\n menuLabel,\n children,\n className,\n}: {\n /** The main action, its corners squared on the side the menu joins. */\n primary: ReactNode;\n /** The accessible name of the ▾ trigger. */\n menuLabel: string;\n /** The menu's entries; none, and the main action stands alone. */\n children?: ReactNode;\n className?: string;\n}) {\n return (\n <div\n data-slot=\"split-button\"\n className={cn(\n 'inline-flex items-stretch',\n children !== undefined && '[&>:first-child]:rounded-r-none',\n className,\n )}\n >\n {primary}\n {children !== undefined && (\n <NavMenu\n label={menuLabel}\n icon={null}\n className=\"flex\"\n triggerClassName={TRIGGER}\n >\n {children}\n </NavMenu>\n )}\n </div>\n );\n}\n"],"names":["button","cn","NavMenu","TRIGGER","variant","size","SplitButton","primary","menuLabel","children","className","div","data-slot","undefined","label","icon","triggerClassName"],"mappings":";AAEA,SAASA,MAAM,QAAQ,sCAAsC;AAC7D,SAASC,EAAE,QAAQ,oBAAoB;AACvC,SAASC,OAAO,QAAQ,0BAA0B;AAElD,8EAA8E,GAC9E,MAAMC,UAAUF,GACdD,OAAO;IAAEI,SAAS;IAAWC,MAAM;AAAK,IACxC;AAGF;;;;;;;;;CASC,GACD,OAAO,SAASC,YAAY,EAC1BC,OAAO,EACPC,SAAS,EACTC,QAAQ,EACRC,SAAS,EASV;IACC,qBACE,MAACC;QACCC,aAAU;QACVF,WAAWT,GACT,6BACAQ,aAAaI,aAAa,mCAC1BH;;YAGDH;YACAE,aAAaI,2BACZ,KAACX;gBACCY,OAAON;gBACPO,MAAM;gBACNL,WAAU;gBACVM,kBAAkBb;0BAEjBM;;;;AAKX"}
|