@kud/jira-ink 0.9.0 → 0.10.0

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/dist/index.d.ts CHANGED
@@ -412,6 +412,12 @@ type BoardLeaves<L> = {
412
412
  }) => ReactNode;
413
413
  onOpen: (leaf: L) => void;
414
414
  };
415
+ /** The stop under the cursor, and everything hanging off it. */
416
+ type CursorAt<L> = {
417
+ stop: Stop<L>;
418
+ /** The stop and its descendants, as `subtreeOf` reads them. */
419
+ subtree: Block<L>[];
420
+ };
415
421
  type IssueBoardProps<L = never> = {
416
422
  model: BoardModel;
417
423
  leaves?: BoardLeaves<L>;
@@ -467,6 +473,18 @@ type IssueBoardProps<L = never> = {
467
473
  * app keys down while a letter is a letter — `q` must type there, not quit.
468
474
  */
469
475
  onInputFocus?: (focused: boolean) => void;
476
+ /**
477
+ * Where the cursor is, for a host that binds keys of its own — a move menu,
478
+ * or `C` / `O` over everything hanging off the row.
479
+ *
480
+ * The board owns the cursor, so a host that wanted to act on the selected
481
+ * row had no way to learn which one it was: `onOpen` answers only on ↵. The
482
+ * subtree comes with it rather than as a second call, because the host has
483
+ * no handle on `blocks` to walk it from.
484
+ *
485
+ * `null` while a tab holds nothing.
486
+ */
487
+ onCursor?: (at: CursorAt<L> | null) => void;
470
488
  };
471
489
  /**
472
490
  * Rows are windowed by hand rather than handed to `Table`, which renders every
@@ -477,7 +495,7 @@ type IssueBoardProps<L = never> = {
477
495
  * host — only the keys that open and close the layers it pushes itself: the
478
496
  * search input and the legend.
479
497
  */
480
- declare const IssueBoard: <L = never>({ model, leaves, parents, viewer, loadedAt, scope, showingAll, searchError, width, height, onOpen, onToggleAll, onRefresh, onSearch, onClearSearch, frame, onInputFocus, }: IssueBoardProps<L>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react.JSX.Element | null | undefined;
498
+ declare const IssueBoard: <L = never>({ model, leaves, parents, viewer, loadedAt, scope, showingAll, searchError, width, height, onOpen, onToggleAll, onRefresh, onSearch, onClearSearch, frame, onInputFocus, onCursor, }: IssueBoardProps<L>) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react.JSX.Element | null | undefined;
481
499
 
482
500
  type PriorityMarker = {
483
501
  /** Always one column wide, so a list filling every row keeps its grid. */
@@ -502,4 +520,4 @@ declare const priorityMarker: (name: string | null) => PriorityMarker;
502
520
  declare const MOCK_BOARD_ROWS: BoardRow[];
503
521
  declare const mockBoard: () => BoardModel;
504
522
 
505
- export { type Block, type BoardLeaves, type BoardModel, type BoardOptions, type BoardRow, type BoardScope, type BoardTab, type BoardTabs, IssueBoard, type IssueBoardProps, IssueBody, type IssueBodyProps, type IssueDetail, IssueDetailView, type IssueDetailViewProps, MOCK_BOARD_ROWS, OFF_BOARD, type Placement, type PriorityGlyph, type PriorityMarker, type StatusCategory, type Stop, type TabSource, type Transition, type TransitionTarget, blockIndexOfStop, blocksFor, boardOf, countsFor, fenceNote, headNote, isStop, issueDetailOf, mockBoard, parentsOf, pendingRow, pillVariantFor, placementOf, priorityGlyph, priorityMarker, relativeAge, rowsInTab, settleRow, stopsOf, subtreeOf, tabLabelOf, tabOf, tabsFromBoard, tabsFromCategories, tabsFromConfig, toBoardRow, transitionRow, transitionsOf, treePrefix, visibleTabs, withBehind };
523
+ export { type Block, type BoardLeaves, type BoardModel, type BoardOptions, type BoardRow, type BoardScope, type BoardTab, type BoardTabs, type CursorAt, IssueBoard, type IssueBoardProps, IssueBody, type IssueBodyProps, type IssueDetail, IssueDetailView, type IssueDetailViewProps, MOCK_BOARD_ROWS, OFF_BOARD, type Placement, type PriorityGlyph, type PriorityMarker, type StatusCategory, type Stop, type TabSource, type Transition, type TransitionTarget, blockIndexOfStop, blocksFor, boardOf, countsFor, fenceNote, headNote, isStop, issueDetailOf, mockBoard, parentsOf, pendingRow, pillVariantFor, placementOf, priorityGlyph, priorityMarker, relativeAge, rowsInTab, settleRow, stopsOf, subtreeOf, tabLabelOf, tabOf, tabsFromBoard, tabsFromCategories, tabsFromConfig, toBoardRow, transitionRow, transitionsOf, treePrefix, visibleTabs, withBehind };
package/dist/index.js CHANGED
@@ -647,7 +647,8 @@ var IssueBoard = ({
647
647
  onSearch,
648
648
  onClearSearch,
649
649
  frame,
650
- onInputFocus
650
+ onInputFocus,
651
+ onCursor
651
652
  }) => {
652
653
  const [legend, setLegend] = useState(false);
653
654
  const [search, setSearch] = useState({
@@ -704,6 +705,12 @@ var IssueBoard = ({
704
705
  isActive: listFocused
705
706
  });
706
707
  useEffect(() => setCursor(0), [tab, setCursor]);
708
+ const at = stops[cursor];
709
+ useEffect(() => {
710
+ onCursor?.(
711
+ at ? { stop: at, subtree: subtreeOf(blocks, blockIndexOfStop(blocks, cursor)) } : null
712
+ );
713
+ }, [at, blocks, cursor, onCursor]);
707
714
  const openStop = (stop) => {
708
715
  if (!stop) return;
709
716
  if (stop.kind === "issue") onOpen(stop.row.key);
@@ -810,10 +817,10 @@ var IssueBoard = ({
810
817
  /* @__PURE__ */ jsx(Box, { width: 28, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { color: colors.accent, children: glyph }) }),
811
818
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: meaning })
812
819
  ] }, glyph)) : stops.length === 0 ? /* @__PURE__ */ jsx(Box, { paddingLeft: 4, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: emptyHint() }) }) : blocks.slice(start, end).map((block, i) => {
813
- const at = start + i;
814
- const focused = at === focus;
815
- const prefix = treePrefix(blocks, at);
816
- return block.kind === "gap" ? /* @__PURE__ */ jsx(Text, { children: " " }, `gap:${at}`) : block.kind === "fence" ? (() => {
820
+ const at2 = start + i;
821
+ const focused = at2 === focus;
822
+ const prefix = treePrefix(blocks, at2);
823
+ return block.kind === "gap" ? /* @__PURE__ */ jsx(Text, { children: " " }, `gap:${at2}`) : block.kind === "fence" ? (() => {
817
824
  const { segment, behind } = fenceNote(
818
825
  block.parent,
819
826
  model.tabs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/jira-ink",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Ink components for viewing Jira issues: the board and the issue detail screen, shared by jira-cli's TUI and cockpit",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",