ink-cartridge 3.6.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.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +249 -0
  3. package/dist/binary-storage/BinaryStorage.d.ts +308 -0
  4. package/dist/binary-storage/BinaryStorage.js +548 -0
  5. package/dist/binary-storage/StreamingReader.d.ts +53 -0
  6. package/dist/binary-storage/StreamingReader.js +530 -0
  7. package/dist/binary-storage/index.d.ts +91 -0
  8. package/dist/binary-storage/index.js +91 -0
  9. package/dist/binary-storage/types.d.ts +400 -0
  10. package/dist/binary-storage/types.js +15 -0
  11. package/dist/cli/index.d.ts +2 -0
  12. package/dist/cli/index.js +214 -0
  13. package/dist/cli/initTheme.d.ts +14 -0
  14. package/dist/cli/initTheme.js +124 -0
  15. package/dist/cli/makeLanguageType.d.ts +46 -0
  16. package/dist/cli/makeLanguageType.js +264 -0
  17. package/dist/cli/makeThemeType.d.ts +43 -0
  18. package/dist/cli/makeThemeType.js +222 -0
  19. package/dist/components/badge/Badge.d.ts +7 -0
  20. package/dist/components/badge/Badge.js +9 -0
  21. package/dist/components/dialog/ConfirmDialog.d.ts +23 -0
  22. package/dist/components/dialog/ConfirmDialog.js +57 -0
  23. package/dist/components/dialog/types.d.ts +20 -0
  24. package/dist/components/dialog/types.js +1 -0
  25. package/dist/components/divider/Divider.d.ts +8 -0
  26. package/dist/components/divider/Divider.js +10 -0
  27. package/dist/components/fold/Fold.d.ts +3 -0
  28. package/dist/components/fold/Fold.js +44 -0
  29. package/dist/components/fold/types.d.ts +28 -0
  30. package/dist/components/fold/types.js +1 -0
  31. package/dist/components/form/Field.d.ts +30 -0
  32. package/dist/components/form/Field.js +59 -0
  33. package/dist/components/form/Form.d.ts +32 -0
  34. package/dist/components/form/Form.js +163 -0
  35. package/dist/components/form/context.d.ts +14 -0
  36. package/dist/components/form/context.js +20 -0
  37. package/dist/components/form/types.d.ts +115 -0
  38. package/dist/components/form/types.js +1 -0
  39. package/dist/components/key-hint/KeyHint.d.ts +10 -0
  40. package/dist/components/key-hint/KeyHint.js +12 -0
  41. package/dist/components/multi-select/MultiSelectInput.d.ts +125 -0
  42. package/dist/components/multi-select/MultiSelectInput.js +287 -0
  43. package/dist/components/multi-select/types.d.ts +100 -0
  44. package/dist/components/multi-select/types.js +1 -0
  45. package/dist/components/number-input/NumberInput.d.ts +11 -0
  46. package/dist/components/number-input/NumberInput.js +44 -0
  47. package/dist/components/progress-bar/ProgressBar.d.ts +11 -0
  48. package/dist/components/progress-bar/ProgressBar.js +9 -0
  49. package/dist/components/search-input/SearchInput.d.ts +10 -0
  50. package/dist/components/search-input/SearchInput.js +15 -0
  51. package/dist/components/select/SelectInput.d.ts +100 -0
  52. package/dist/components/select/SelectInput.js +147 -0
  53. package/dist/components/select/types.d.ts +63 -0
  54. package/dist/components/select/types.js +1 -0
  55. package/dist/components/spinner/Spinner.d.ts +12 -0
  56. package/dist/components/spinner/Spinner.js +24 -0
  57. package/dist/components/tabs/Tabs.d.ts +3 -0
  58. package/dist/components/tabs/Tabs.js +57 -0
  59. package/dist/components/tabs/types.d.ts +32 -0
  60. package/dist/components/tabs/types.js +1 -0
  61. package/dist/components/text/TextInput.d.ts +39 -0
  62. package/dist/components/text/TextInput.js +233 -0
  63. package/dist/components/text/types.d.ts +62 -0
  64. package/dist/components/text/types.js +1 -0
  65. package/dist/dev/dev-screen.d.ts +36 -0
  66. package/dist/dev/dev-screen.js +142 -0
  67. package/dist/dev/entrance.d.ts +51 -0
  68. package/dist/dev/entrance.js +67 -0
  69. package/dist/dev/globalKey-display.d.ts +2 -0
  70. package/dist/dev/globalKey-display.js +8 -0
  71. package/dist/dev/types.d.ts +9 -0
  72. package/dist/dev/types.js +1 -0
  73. package/dist/index.d.ts +46 -0
  74. package/dist/index.js +50 -0
  75. package/dist/keyboard/check-global-key.d.ts +18 -0
  76. package/dist/keyboard/check-global-key.js +52 -0
  77. package/dist/keyboard/context.d.ts +398 -0
  78. package/dist/keyboard/context.js +9 -0
  79. package/dist/keyboard/global-key-processor/index.d.ts +16 -0
  80. package/dist/keyboard/global-key-processor/index.js +75 -0
  81. package/dist/keyboard/global-sequence-processor/index.d.ts +14 -0
  82. package/dist/keyboard/global-sequence-processor/index.js +165 -0
  83. package/dist/keyboard/hook.d.ts +51 -0
  84. package/dist/keyboard/hook.js +105 -0
  85. package/dist/keyboard/index.d.ts +5 -0
  86. package/dist/keyboard/index.js +3 -0
  87. package/dist/keyboard/keyNormalizer.d.ts +37 -0
  88. package/dist/keyboard/keyNormalizer.js +119 -0
  89. package/dist/keyboard/layer-handler.d.ts +57 -0
  90. package/dist/keyboard/layer-handler.js +274 -0
  91. package/dist/keyboard/modal-processor/index.d.ts +16 -0
  92. package/dist/keyboard/modal-processor/index.js +97 -0
  93. package/dist/keyboard/overlay-processor/index.d.ts +16 -0
  94. package/dist/keyboard/overlay-processor/index.js +30 -0
  95. package/dist/keyboard/pipeline/chain.d.ts +10 -0
  96. package/dist/keyboard/pipeline/chain.js +45 -0
  97. package/dist/keyboard/pipeline/context.d.ts +34 -0
  98. package/dist/keyboard/pipeline/context.js +42 -0
  99. package/dist/keyboard/pipeline/index.d.ts +3 -0
  100. package/dist/keyboard/pipeline/index.js +2 -0
  101. package/dist/keyboard/provider.d.ts +32 -0
  102. package/dist/keyboard/provider.js +985 -0
  103. package/dist/keyboard/screen-stack-processor/index.d.ts +14 -0
  104. package/dist/keyboard/screen-stack-processor/index.js +32 -0
  105. package/dist/keyboard/types.d.ts +632 -0
  106. package/dist/keyboard/types.js +1 -0
  107. package/dist/language/context.d.ts +7 -0
  108. package/dist/language/context.js +7 -0
  109. package/dist/language/hook.d.ts +19 -0
  110. package/dist/language/hook.js +26 -0
  111. package/dist/language/index.d.ts +3 -0
  112. package/dist/language/index.js +2 -0
  113. package/dist/language/provider.d.ts +30 -0
  114. package/dist/language/provider.js +155 -0
  115. package/dist/language/types.d.ts +124 -0
  116. package/dist/language/types.js +1 -0
  117. package/dist/screen/ModalContext.d.ts +11 -0
  118. package/dist/screen/ModalContext.js +12 -0
  119. package/dist/screen/OverlayContext.d.ts +9 -0
  120. package/dist/screen/OverlayContext.js +10 -0
  121. package/dist/screen/context.d.ts +61 -0
  122. package/dist/screen/context.js +8 -0
  123. package/dist/screen/current-screen.d.ts +16 -0
  124. package/dist/screen/current-screen.js +38 -0
  125. package/dist/screen/hook.d.ts +13 -0
  126. package/dist/screen/hook.js +20 -0
  127. package/dist/screen/index.d.ts +7 -0
  128. package/dist/screen/index.js +5 -0
  129. package/dist/screen/provider.d.ts +112 -0
  130. package/dist/screen/provider.js +577 -0
  131. package/dist/screen/registry.d.ts +27 -0
  132. package/dist/screen/registry.js +71 -0
  133. package/dist/screen/types.d.ts +227 -0
  134. package/dist/screen/types.js +1 -0
  135. package/dist/storage/index.d.ts +45 -0
  136. package/dist/storage/index.js +46 -0
  137. package/dist/storage/storage.d.ts +139 -0
  138. package/dist/storage/storage.js +236 -0
  139. package/dist/storage/types.d.ts +145 -0
  140. package/dist/storage/types.js +1 -0
  141. package/dist/theme/context.d.ts +7 -0
  142. package/dist/theme/context.js +7 -0
  143. package/dist/theme/hook.d.ts +11 -0
  144. package/dist/theme/hook.js +18 -0
  145. package/dist/theme/index.d.ts +4 -0
  146. package/dist/theme/index.js +2 -0
  147. package/dist/theme/provider.d.ts +18 -0
  148. package/dist/theme/provider.js +308 -0
  149. package/dist/theme/types.d.ts +53 -0
  150. package/dist/theme/types.js +1 -0
  151. package/package.json +71 -0
@@ -0,0 +1,97 @@
1
+ import { handleLayer } from '../layer-handler.js';
2
+ /**
3
+ * Check whether a list of bindings contains one whose `keys` match
4
+ * the event but whose `when` returns `false`.
5
+ */
6
+ function hasWhenFalseBinding(bindings, eventNames) {
7
+ return bindings.some((b) => b.when?.() === false &&
8
+ b.keys.some((k) => eventNames.includes(k)));
9
+ }
10
+ /**
11
+ * Check whether any non-active focus target has a binding matching
12
+ * the event.
13
+ */
14
+ function matchesOtherFocusTarget(layer, eventNames) {
15
+ for (const [fid, ft] of layer.focusTargets) {
16
+ if (fid === layer.currentFocusId)
17
+ continue;
18
+ if (ft.bindings.some((b) => b.keys.some((k) => eventNames.includes(k)))) {
19
+ return true;
20
+ }
21
+ }
22
+ return false;
23
+ }
24
+ /**
25
+ * Determine whether a key event is a "miss" and invoke the callback.
26
+ *
27
+ * @returns true if the callback was invoked with miss=true.
28
+ */
29
+ function invokeMissIfNeeded(layer, handled, key, input, eventNames) {
30
+ if (!layer.onMiss)
31
+ return false;
32
+ const opts = layer.onMissOptions ?? {};
33
+ // fix: The stop API and blockedKey API cases are no longer handled.
34
+ // Instead, it is left to handlerLayer to handle natural
35
+ // So the expectation is that, So the Stop API returns miss: false, but the BlockedKeys API returns miss: true
36
+ // TODO: You need to modify the corresponding test and do it later.
37
+ // @2026-06-23 3.6.1
38
+ if (handled) {
39
+ layer.onMiss({ miss: false });
40
+ return false;
41
+ }
42
+ // handled === false — key was not consumed by handleLayer.
43
+ if (opts.monitorWhen && hasWhenFalseBinding(layer.bindings, eventNames)) {
44
+ layer.onMiss({ miss: true, key, input, eventNames });
45
+ return true;
46
+ }
47
+ if (opts.monitorWhen &&
48
+ layer.currentFocusId) {
49
+ const ft = layer.focusTargets.get(layer.currentFocusId);
50
+ if (ft && hasWhenFalseBinding(ft.bindings, eventNames)) {
51
+ layer.onMiss({ miss: true, key, input, eventNames });
52
+ return true;
53
+ }
54
+ }
55
+ if (opts.monitorFocusMismatch &&
56
+ matchesOtherFocusTarget(layer, eventNames)) {
57
+ layer.onMiss({ miss: true, key, input, eventNames });
58
+ return true;
59
+ }
60
+ // Definitely a miss — no mechanism handled this key.
61
+ layer.onMiss({ miss: true, key, input, eventNames });
62
+ return true;
63
+ }
64
+ /**
65
+ * Create a processor for the modal stage (stage 0 — highest priority).
66
+ *
67
+ * When a modal is active (activeModalId is set), the modal's keyboard layer
68
+ * receives the event. The processor always returns `true`, consuming every
69
+ * event — even keys not bound in the modal — so that no event reaches
70
+ * lower-priority stages (global keys, overlays, or screens).
71
+ *
72
+ * Before blocking, if the layer has an {@link ScreenKeyboardLayer.onMiss}
73
+ * callback registered (via {@link useModalMissListener}), the processor
74
+ * determines whether the key was handled or missed and invokes the callback.
75
+ *
76
+ * @returns A PipelineProcessor for the modal stage.
77
+ */
78
+ export function createModalProcessor() {
79
+ return {
80
+ process(ctx) {
81
+ if (!ctx.activeModalId)
82
+ return false;
83
+ const layer = ctx.layersRef.current.get(ctx.activeModalId);
84
+ let handled = false;
85
+ if (layer) {
86
+ handled = handleLayer(layer, ctx.eventNames, ctx.input, ctx.key, true, // isTop — modal is always the top layer
87
+ ctx.notifyFocusChange, 1, // activeCount — modal is singleton
88
+ true, // isOverlay — modal is treated as a floating layer for onlyThis semantics
89
+ ctx.wildcardFirst);
90
+ }
91
+ if (layer) {
92
+ invokeMissIfNeeded(layer, handled, ctx.key, ctx.input, ctx.eventNames);
93
+ }
94
+ return true;
95
+ },
96
+ };
97
+ }
@@ -0,0 +1,16 @@
1
+ import type { PipelineProcessor } from '../types.js';
2
+ /**
3
+ * Create a processor for the overlay broadcast stage.
4
+ *
5
+ * Iterates all active overlays (sorted by zIndex ascending) and offers
6
+ * the event to each one via {@link handleLayer}. Unlike other processors,
7
+ * this stage does NOT stop on the first consumer — every active overlay
8
+ * receives the event. The `anyOverlayConsumed` flag on the context is
9
+ * set if at least one overlay handled the event, which later determines
10
+ * whether the screen stack (stage ⑥) runs.
11
+ *
12
+ * @returns A PipelineProcessor for the overlay broadcast stage.
13
+ *
14
+ * @2026-06-14 v3.4.0
15
+ */
16
+ export declare function createOverlayProcessor(): PipelineProcessor;
@@ -0,0 +1,30 @@
1
+ import { handleLayer } from '../layer-handler.js';
2
+ /**
3
+ * Create a processor for the overlay broadcast stage.
4
+ *
5
+ * Iterates all active overlays (sorted by zIndex ascending) and offers
6
+ * the event to each one via {@link handleLayer}. Unlike other processors,
7
+ * this stage does NOT stop on the first consumer — every active overlay
8
+ * receives the event. The `anyOverlayConsumed` flag on the context is
9
+ * set if at least one overlay handled the event, which later determines
10
+ * whether the screen stack (stage ⑥) runs.
11
+ *
12
+ * @returns A PipelineProcessor for the overlay broadcast stage.
13
+ *
14
+ * @2026-06-14 v3.4.0
15
+ */
16
+ export function createOverlayProcessor() {
17
+ return {
18
+ process(ctx) {
19
+ for (const overlay of ctx.activeOverlays) {
20
+ const layer = ctx.layersRef.current.get(overlay.id);
21
+ if (layer && handleLayer(layer, ctx.eventNames, ctx.input, ctx.key, true, ctx.notifyFocusChange, ctx.activeCount, true, ctx.wildcardFirst)) {
22
+ ctx.anyOverlayConsumed = true;
23
+ // Do not break — continue to next overlay (broadcast semantics).
24
+ }
25
+ }
26
+ // Always return false so the chain continues to subsequent stages.
27
+ return false;
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,10 @@
1
+ import type { PipelineContext } from '../types.js';
2
+ /**
3
+ * Run a keyboard event through the full processor chain.
4
+ *
5
+ * Each processor's {@link PipelineProcessor.process} is called in order.
6
+ * The first processor to return `true` (event consumed) stops the chain.
7
+ *
8
+ * @param ctx - Snapshot context built by {@link buildPipelineContext}.
9
+ */
10
+ export declare function runPipeline(ctx: PipelineContext): void;
@@ -0,0 +1,45 @@
1
+ import { createModalProcessor } from '../modal-processor/index.js';
2
+ import { createGlobalSequenceProcessor } from '../global-sequence-processor/index.js';
3
+ import { createGlobalKeyProcessor } from '../global-key-processor/index.js';
4
+ import { createOverlayProcessor } from '../overlay-processor/index.js';
5
+ import { createScreenStackProcessor } from '../screen-stack-processor/index.js';
6
+ /**
7
+ * Build the canonical 7-stage processor chain.
8
+ *
9
+ * Priority order (highest first):
10
+ * ⓪ Modal — active modal, always blocks
11
+ * ① GlobalSequence (affectOverlay: true) — pending + start
12
+ * ② GlobalKey (affectOverlay: true) — fire before overlays
13
+ * ③ Overlay broadcast — all active overlays, zIndex asc
14
+ * ④ GlobalSequence (affectOverlay: false) — pending + start
15
+ * ⑤ GlobalKey (affectOverlay: false) — fire before screen stack
16
+ * ⑥ Screen stack — top → bottom, only if no overlay consumed
17
+ *
18
+ * @2026-06-22 v3.6.1
19
+ */
20
+ function buildProcessors() {
21
+ return [
22
+ createModalProcessor(),
23
+ createGlobalSequenceProcessor({ affectOverlay: true }),
24
+ createGlobalKeyProcessor({ affectOverlay: true }),
25
+ createOverlayProcessor(),
26
+ createGlobalSequenceProcessor({ affectOverlay: false }),
27
+ createGlobalKeyProcessor({ affectOverlay: false }),
28
+ createScreenStackProcessor(),
29
+ ];
30
+ }
31
+ /**
32
+ * Run a keyboard event through the full processor chain.
33
+ *
34
+ * Each processor's {@link PipelineProcessor.process} is called in order.
35
+ * The first processor to return `true` (event consumed) stops the chain.
36
+ *
37
+ * @param ctx - Snapshot context built by {@link buildPipelineContext}.
38
+ */
39
+ export function runPipeline(ctx) {
40
+ const processors = buildProcessors();
41
+ for (const processor of processors) {
42
+ if (processor.process(ctx))
43
+ return;
44
+ }
45
+ }
@@ -0,0 +1,34 @@
1
+ import type { Key } from 'ink';
2
+ import type React from 'react';
3
+ import type { OverlayEntry } from '../../screen/types.js';
4
+ import type { LayerOwner } from '../context.js';
5
+ import type { PipelineContext, ScreenKeyboardLayer, ResolvedGlobalKeyEntry, ResolvedGlobalSequenceEntry } from '../types.js';
6
+ /**
7
+ * Collection of all provider refs needed by {@link buildPipelineContext}
8
+ * to snapshot the current keyboard state for a single event.
9
+ */
10
+ export interface PipelineRefs {
11
+ pathRef: React.MutableRefObject<React.ComponentType<any>[]>;
12
+ globalKeysRef: React.MutableRefObject<ResolvedGlobalKeyEntry[]>;
13
+ globalSequencesRef: React.MutableRefObject<ResolvedGlobalSequenceEntry[]>;
14
+ activeOverlayIdsRef: React.MutableRefObject<Set<string>>;
15
+ displayedOverlaysRef: React.MutableRefObject<OverlayEntry[]>;
16
+ activeModalIdRef: React.MutableRefObject<string | null>;
17
+ layersRef: React.MutableRefObject<Map<LayerOwner, ScreenKeyboardLayer>>;
18
+ globalPendingSeqRef: React.MutableRefObject<import('../types.js').GlobalPendingSequence | null>;
19
+ wildcardPriorityCountRef: React.MutableRefObject<number>;
20
+ notifyFocusChange: () => void;
21
+ }
22
+ /**
23
+ * Build a {@link PipelineContext} snapshot from the provider's refs.
24
+ *
25
+ * Called once per key event at the top of the `useInput` callback.
26
+ * All `ref.current` values are read synchronously to produce a
27
+ * consistent snapshot for the current event.
28
+ *
29
+ * @param input - Raw character string from Ink's useInput.
30
+ * @param key - Full Key descriptor from Ink.
31
+ * @param refs - All mutable refs owned by the keyboard provider.
32
+ * @returns A frozen-in-time context for the pipeline chain.
33
+ */
34
+ export declare function buildPipelineContext(input: string, key: Key, refs: PipelineRefs): PipelineContext;
@@ -0,0 +1,42 @@
1
+ import { normalizeKeyNames } from '../keyNormalizer.js';
2
+ /**
3
+ * Build a {@link PipelineContext} snapshot from the provider's refs.
4
+ *
5
+ * Called once per key event at the top of the `useInput` callback.
6
+ * All `ref.current` values are read synchronously to produce a
7
+ * consistent snapshot for the current event.
8
+ *
9
+ * @param input - Raw character string from Ink's useInput.
10
+ * @param key - Full Key descriptor from Ink.
11
+ * @param refs - All mutable refs owned by the keyboard provider.
12
+ * @returns A frozen-in-time context for the pipeline chain.
13
+ */
14
+ export function buildPipelineContext(input, key, refs) {
15
+ const eventNames = normalizeKeyNames(input, key);
16
+ const path = refs.pathRef.current;
17
+ const topComponent = path.length > 0 ? path[path.length - 1] : null;
18
+ const globalKeys = refs.globalKeysRef.current;
19
+ const globalSequences = refs.globalSequencesRef.current;
20
+ const activeIds = refs.activeOverlayIdsRef.current;
21
+ const overlays = refs.displayedOverlaysRef.current;
22
+ const activeOverlays = overlays.filter(n => activeIds.has(n.id));
23
+ const activeCount = activeIds.size;
24
+ const wildcardFirst = refs.wildcardPriorityCountRef.current > 0;
25
+ return {
26
+ input,
27
+ key,
28
+ eventNames,
29
+ topComponent,
30
+ globalKeys,
31
+ globalSequences,
32
+ activeOverlays,
33
+ activeCount,
34
+ wildcardFirst,
35
+ screenPath: path,
36
+ activeModalId: refs.activeModalIdRef.current,
37
+ layersRef: refs.layersRef,
38
+ pendingSeqRef: refs.globalPendingSeqRef,
39
+ notifyFocusChange: refs.notifyFocusChange,
40
+ anyOverlayConsumed: false,
41
+ };
42
+ }
@@ -0,0 +1,3 @@
1
+ export { buildPipelineContext } from './context.js';
2
+ export type { PipelineRefs } from './context.js';
3
+ export { runPipeline } from './chain.js';
@@ -0,0 +1,2 @@
1
+ export { buildPipelineContext } from './context.js';
2
+ export { runPipeline } from './chain.js';
@@ -0,0 +1,32 @@
1
+ import React, { ReactNode } from 'react';
2
+ /**
3
+ * Clear all registered shortcut operations.
4
+ *
5
+ * NOTE: Since the refactoring to per-instance useRef state, this function
6
+ * is a no-op at module level. Shortcut operations are now scoped to each
7
+ * {@link KeyboardProvider} instance and are automatically cleaned up when
8
+ * the provider unmounts.
9
+ *
10
+ * Kept for backward compatibility with tests and external consumers that
11
+ * call this function in cleanup routines.
12
+ */
13
+ export declare function clearShortcutOperations(): void;
14
+ export interface KeyboardProviderProps {
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * Keyboard context provider for layered key handling.
19
+ *
20
+ * Manages per-screen-layer key bindings, transparent keys (`blockedKey`),
21
+ * key-stop propagation barriers (`stop`), and global keys (`globalKeys`).
22
+ * Handles the full event priority chain:
23
+ * 1. Global keys with `affectOverlay: true`
24
+ * 2. Broadcast to all active overlays (sorted by zIndex ascending)
25
+ * 3. Global keys with `affectOverlay: false` (default)
26
+ * 4. Screen stack (top → bottom), only if no overlay consumed the event
27
+ * 5. Drop unhandled keys
28
+ *
29
+ * Must be nested inside a {@link ScenarioManagementProvider} so that the
30
+ * current screen path and overlay state are available.
31
+ */
32
+ export declare function KeyboardProvider({ children }: KeyboardProviderProps): React.JSX.Element;