@fasl-work/caos-app-shell 0.15.0 → 0.17.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
@@ -53,7 +53,8 @@ declare function WorkbenchShell({ brand, routes, navigationLabel, children, side
53
53
 
54
54
  interface FocusShellProps {
55
55
  stage: ReactNode;
56
- rail: ReactNode;
56
+ /** The parameter column on the right. Null or omitted: no column, and the stage is the whole frame (a view of a surface with no rail). */
57
+ rail?: ReactNode;
57
58
  title: string;
58
59
  description: string;
59
60
  hud: Array<{
@@ -259,8 +260,9 @@ interface CaseSelectorProps {
259
260
  * category structure is preserved either way; only the height changes.
260
261
  */
261
262
  layout?: 'chips' | 'select';
262
- /** A control that sits on the select's row, after it (the workbench's Focus button, shell 0.14.1): the select shrinks to make
263
- * room, so the selector is no taller with it. With `layout: 'chips'` it gets a row of its own, after the chips. */
263
+ /** A control of the product that sits on the select's row, after it: the select shrinks to make room, so the selector is no taller with
264
+ * it (a long case name may then be cut: keep the control narrow). The workbench's own Focus control is not an accessory since 0.17.0:
265
+ * it sits in the group tab row. With `layout: 'chips'` it gets a row of its own, after the chips. */
264
266
  accessory?: ReactNode;
265
267
  }
266
268
  /**
@@ -275,10 +277,84 @@ interface CaseSelectorProps {
275
277
  */
276
278
  declare function CaseSelector(props: CaseSelectorProps): react.JSX.Element;
277
279
 
280
+ /** The words Focus mode writes (the product writes none of them). */
281
+ declare const FOCUS_TEXT: {
282
+ readonly enter: {
283
+ readonly en: "Focus";
284
+ readonly es: "Enfocar";
285
+ };
286
+ readonly enterLabel: {
287
+ readonly en: "Open this case in focus mode";
288
+ readonly es: "Abrir este caso en modo enfoque";
289
+ };
290
+ readonly enterViewLabel: {
291
+ readonly en: "Open this view in focus mode";
292
+ readonly es: "Abrir esta vista en modo enfoque";
293
+ };
294
+ readonly exit: {
295
+ readonly en: "Back to the App";
296
+ readonly es: "Volver a la App";
297
+ };
298
+ readonly stage: {
299
+ readonly en: "Focus stage";
300
+ readonly es: "Escenario de enfoque";
301
+ };
302
+ };
303
+ /** The query parameter that holds Focus mode (`?focus=1`), beside `?case=` and `?view=`. */
304
+ declare const FOCUS_PARAM = "focus";
305
+ /** What a product may say about the Focus mode of its App (`CaseWorkbench.focus`; `true` means all defaults). */
306
+ interface CaseFocusConfig {
307
+ /** The stage's heading (default: the name of the selected case). */
308
+ title?: BiText;
309
+ /** One line under it (default: the name of the open group). */
310
+ description?: BiText;
311
+ /** Readouts laid over the stage (ADR-0070): at most four on a phone. */
312
+ hud?: Array<{
313
+ label: BiText;
314
+ value: string;
315
+ }>;
316
+ /** Called when Focus opens (`true`) and closes (`false`), for a product that records it. */
317
+ onChange?: (on: boolean) => void;
318
+ /** The query parameter (default `focus`). */
319
+ param?: string;
320
+ }
321
+ /** What a product may say about the Focus mode of a `SurfacePage` App (`SurfacePage.focus`; `true` means all defaults). */
322
+ interface SurfaceFocusConfig {
323
+ /** Called when Focus opens (`true`) and closes (`false`), for a product that records it. */
324
+ onChange?: (on: boolean) => void;
325
+ /** The query parameter (default `focus`). */
326
+ param?: string;
327
+ }
328
+ /**
329
+ * What a product may say about one view of a `SurfacePage` that has a stage (`TabDef.focus`; `true` means all defaults). Only a
330
+ * view with a stage (a simulation, a drawing, a live run) sets it: a list or a form does not, and shows no Focus control.
331
+ */
332
+ interface ViewFocusConfig {
333
+ /** The stage's heading (default: the view's label). */
334
+ title?: BiText;
335
+ /** One line under it (default: the surface's title). */
336
+ description?: BiText;
337
+ /** Readouts laid over the stage (ADR-0070): at most four on a phone. */
338
+ hud?: Array<{
339
+ label: BiText;
340
+ value: string;
341
+ }>;
342
+ /**
343
+ * The parameter column on the right of the stage in Focus (ADR-0070 requirement 2): the view's own controls, moved here by the
344
+ * product (the shell moves no DOM). Without a rail the stage is the whole frame and the view keeps its controls in its body.
345
+ */
346
+ rail?: ReactNode;
347
+ }
348
+
278
349
  interface TabDef {
279
350
  id: string;
280
351
  label: ReactNode;
281
352
  content: ReactNode;
353
+ /**
354
+ * A view with a stage (a simulation, a drawing, a live run) of a `SurfacePage` that has `focus`: it opens in Focus mode (shell
355
+ * 0.16.0, ADR-0070). `true` takes the defaults. A list or a form sets nothing. Ignored outside a `SurfacePage`.
356
+ */
357
+ focus?: boolean | ViewFocusConfig;
282
358
  }
283
359
  /** At most about six peers, then group by the question (ADR-0071 rule 5). */
284
360
  declare const MAX_PEER_TABS = 6;
@@ -291,13 +367,19 @@ interface TabsProps {
291
367
  /** Called on every selection, controlled or not. */
292
368
  onChange?: (id: string) => void;
293
369
  ariaLabel?: string;
370
+ /**
371
+ * A control at the end of the tab row, in a slot beside the tab list (never inside it) on the same row: its space is reserved
372
+ * whatever it shows, so the row does not move. The tabs scroll beside it when they do not fit. Used by `SurfacePage` for its Focus
373
+ * control (shell 0.16.0). Omit it and the markup is what it was.
374
+ */
375
+ trailing?: ReactNode;
294
376
  }
295
377
  /**
296
378
  * Accessible roving-tabindex tab strip on ONE row (ADR-0071 rule 4): arrow keys, Home and End; only the active panel
297
379
  * is rendered, inside an error boundary; a row wider than its box fades the hidden end. Controlled when `value` is
298
380
  * given (known shell defect 6). More than six peers is reported (rule 5).
299
381
  */
300
- declare function Tabs({ tabs, initial, value, onChange, ariaLabel }: TabsProps): react.JSX.Element;
382
+ declare function Tabs({ tabs, initial, value, onChange, ariaLabel, trailing }: TabsProps): react.JSX.Element;
301
383
 
302
384
  interface SubTabDef {
303
385
  id: string;
@@ -812,7 +894,7 @@ interface SurfacePageProps {
812
894
  lede?: ReactNode;
813
895
  /** Controls that act on the whole surface (a source picker, an export button), at the right of the head. */
814
896
  actions?: ReactNode;
815
- /** The surface's views: one row of at most six (ADR-0071 rule 5); the open one is held in the URL. */
897
+ /** The surface's views: one row of at most six (ADR-0071 rule 5); the open one is held in the URL. A view with a stage sets `focus`. */
816
898
  tabs?: TabDef[];
817
899
  /** Controlled selection, when the product holds it itself. */
818
900
  value?: string;
@@ -822,17 +904,28 @@ interface SurfacePageProps {
822
904
  ariaLabel?: BiText;
823
905
  /** Mark the body as the instrument, so the gate measures what is drawn in it (ADR-0071 rule 8). */
824
906
  instrument?: boolean;
907
+ /**
908
+ * Focus mode for the App (ADR-0070, shell 0.16.0): while the open view sets `TabDef.focus`, a Focus control at the end of the tab row
909
+ * opens that view in the full viewport through `FocusShell` (the view is the stage, its `rail` the parameter column), holds
910
+ * `?focus=1` beside `?view=` in the URL, and returns with Escape or the exit button to the same view and sub-view. `true` takes all
911
+ * the defaults. Omit it and the surface is exactly what it was. Needs `tabs`: a surface with one body has no view to focus.
912
+ */
913
+ focus?: boolean | SurfaceFocusConfig;
825
914
  /** The body when there are no tabs: it fills the viewport. */
826
915
  children?: ReactNode;
827
916
  }
828
917
  /**
829
918
  * The third route type, beside the workbench (`WorkbenchLayout`, a rail and an instrument for one case) and the
830
- * document (`DocPage`, a scrolling reading column): a SURFACE fills the viewport with views that are not one case's,
831
- * such as a hub, an explorer or a console. Under `ShellConfig.contain` its head and tab row keep their height and the
919
+ * document (`DocPage`, a scrolling reading column): a SURFACE fills the viewport with views that are not one case's, such
920
+ * as a hub, an explorer or a console. Under `ShellConfig.contain` its head and tab row keep their height and the
832
921
  * open panel scrolls inside; below 900 px the document scrolls. The containment fifteen to nineteen products wrote for
833
922
  * themselves (CAOS_MANAGE audit 2026-10-07, section 3), owned here so no product writes it again.
923
+ *
924
+ * Its views that have a stage (a simulation, a drawing, a live run) open in Focus mode (0.16.0, ADR-0070): the same behaviour as
925
+ * `CaseWorkbench`'s, one piece of code (`useFocusMode`). The control sits at the end of the tab row (a slot beside the tab list) with
926
+ * its space reserved, so it adds no row and moves nothing; it is hidden while the open view has no stage.
834
927
  */
835
- declare function SurfacePage({ title, lede, actions, tabs, value, onChange, deepLinkView, ariaLabel, instrument, children }: SurfacePageProps): react.JSX.Element;
928
+ declare function SurfacePage({ title, lede, actions, tabs, value, onChange, deepLinkView, ariaLabel, instrument, focus, children }: SurfacePageProps): react.JSX.Element;
836
929
 
837
930
  /** Writes one query parameter with replaceState, keeping the router's history state (React Router keeps its entry
838
931
  * key and index there; replacing it with null broke the index the back button relies on). */
@@ -1108,44 +1201,6 @@ interface VariantBarProps {
1108
1201
  * one-line note of what it shows. Selecting a regime must change every view of the case. */
1109
1202
  declare function VariantBar({ variants, activeId, onSelect, title, lane }: VariantBarProps): react.JSX.Element;
1110
1203
 
1111
- /** The words Focus mode writes (the product writes none of them). */
1112
- declare const FOCUS_TEXT: {
1113
- readonly enter: {
1114
- readonly en: "Focus";
1115
- readonly es: "Enfocar";
1116
- };
1117
- readonly enterLabel: {
1118
- readonly en: "Open this case in focus mode";
1119
- readonly es: "Abrir este caso en modo enfoque";
1120
- };
1121
- readonly exit: {
1122
- readonly en: "Back to the App";
1123
- readonly es: "Volver a la App";
1124
- };
1125
- readonly stage: {
1126
- readonly en: "Focus stage";
1127
- readonly es: "Escenario de enfoque";
1128
- };
1129
- };
1130
- /** The query parameter that holds Focus mode (`?focus=1`), beside `?case=` and `?view=`. */
1131
- declare const FOCUS_PARAM = "focus";
1132
- /** What a product may say about the Focus mode of its App (`CaseWorkbench.focus`; `true` means all defaults). */
1133
- interface CaseFocusConfig {
1134
- /** The stage's heading (default: the name of the selected case). */
1135
- title?: BiText;
1136
- /** One line under it (default: the name of the open group). */
1137
- description?: BiText;
1138
- /** Readouts laid over the stage (ADR-0070): at most four on a phone. */
1139
- hud?: Array<{
1140
- label: BiText;
1141
- value: string;
1142
- }>;
1143
- /** Called when Focus opens (`true`) and closes (`false`), for a product that records it. */
1144
- onChange?: (on: boolean) => void;
1145
- /** The query parameter (default `focus`). */
1146
- param?: string;
1147
- }
1148
-
1149
1204
  /** One group of views of the selected case, named for the question the user is asking (ADR-0071 rule 5). */
1150
1205
  interface WorkbenchGroup {
1151
1206
  id: string;
@@ -1197,7 +1252,7 @@ interface CaseWorkbenchProps {
1197
1252
  deepLinkView?: boolean | string;
1198
1253
  ariaLabel?: BiText;
1199
1254
  /**
1200
- * Focus mode for the App (ADR-0070, shell 0.14.0): a Focus button in the rail head opens the selected case's open group in
1255
+ * Focus mode for the App (ADR-0070, shell 0.14.0): a Focus control at the end of the group tab row opens the selected case's open group in
1201
1256
  * the full viewport through `FocusShell` (the stage is the view, the rail stays), holds `?focus=1` beside `?case=` and
1202
1257
  * `?view=` in the URL, and returns with Escape or the exit button to the same case, group and sub-view. `true` takes all
1203
1258
  * the defaults. Omit it and the App is exactly what it was.
@@ -1219,6 +1274,40 @@ declare const MAX_WORKBENCH_GROUPS = 6;
1219
1274
  */
1220
1275
  declare function CaseWorkbench(props: CaseWorkbenchProps): react.JSX.Element;
1221
1276
 
1277
+ /** What the hook needs of a product's Focus configuration: `CaseFocusConfig` and `SurfaceFocusConfig` both satisfy it. */
1278
+ interface FocusModeConfig {
1279
+ /** The query parameter (default `focus`). */
1280
+ param?: string;
1281
+ /** Called when Focus opens (`true`) and closes (`false`), for a product that records it. */
1282
+ onChange?: (on: boolean) => void;
1283
+ }
1284
+ interface FocusModeOptions {
1285
+ /**
1286
+ * False while what Focus would open is not available (a surface whose open view has no stage): Focus is then never shown, and a
1287
+ * `?focus=1` left in the URL is removed. Default true.
1288
+ */
1289
+ enabled?: boolean;
1290
+ /** Whether a `?focus=1` in the URL at the first render may open Focus (a surface checks the view the link names). Default true. */
1291
+ initialAllowed?: () => boolean;
1292
+ }
1293
+ interface FocusMode {
1294
+ /** True when the frame shows: configured, on, and enabled. */
1295
+ show: boolean;
1296
+ /** Opens or closes Focus: writes the URL, moves keyboard focus on the next commit and calls `onChange`. */
1297
+ setFocus: (on: boolean) => void;
1298
+ /** Attach to the control that opens Focus: keyboard focus returns to it when Focus closes. */
1299
+ enterRef: React.MutableRefObject<HTMLButtonElement | null>;
1300
+ /** What the reader had open in the tab rows of the views; provide it as `ViewMemoryContext` around both frames. */
1301
+ memory: Map<string, string>;
1302
+ }
1303
+ /**
1304
+ * Focus mode (ADR-0070), the one behaviour `CaseWorkbench` and `SurfacePage` share: the state held in the URL (`?focus=1`), Escape
1305
+ * to leave, the page behind the frame inert, keyboard focus moved to the exit control on entry and back to the entering control on
1306
+ * return, and the view memory the frame's remount reads. The component renders the frame (`FocusShell`) when `show` is true.
1307
+ * `cfg` null means the App has no Focus mode: nothing here acts.
1308
+ */
1309
+ declare function useFocusMode(cfg: FocusModeConfig | null, options?: FocusModeOptions): FocusMode;
1310
+
1222
1311
  interface KnobProps {
1223
1312
  /** Stable id, written as `data-control` so the gate can enumerate and move every control. */
1224
1313
  id: string;
@@ -1291,4 +1380,4 @@ interface ViewsRowProps {
1291
1380
  */
1292
1381
  declare function ViewsRow({ children, shares }: ViewsRowProps): react.JSX.Element;
1293
1382
 
1294
- export { BREAKPOINTS, BarChart, type BarChartProps, type BarDatum, BiText, Callout, CardDeck, type CardDeckProps, type CaseDef, type CaseFocusConfig, type CaseGroup, type CaseKind, CaseSelector, type CaseSelectorProps, type CaseSelectorText, CaseWorkbench, type CaseWorkbenchProps, ChipGroup, type ChipGroupProps, type ChipOption, type Citation, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, type DeckCard, DocPage, type DocPageProps, DocReferences, DocRefsScope, DocSection, type DocSectionProps, EXECUTIVE_SCHEMA_VERSION, Equation, type ExecutiveData, type ExecutiveProblem, ExecutiveView, type ExecutiveViewProps, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure, type FittedLabel, FlipCard, type FlipCardProps, FocusShell, type FocusShellProps, FormatOptions, Gauge, type GaugeProps, type GaugeZone, Glossary, type GlossaryEntry, InlineMath, Knob, type KnobProps, Landing, type Lane, LaneBadge, Lang, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, type PausedVizController, PlotCard, type PlotCardProps, type Provenance, Question, type QuestionProps, type RailSection, Readout, type ReadoutItem, type ReadoutProps, ReferenceList, Refs, Stage, type StageSize, Stat, type StatProps, type SubTabDef, SubTabs, type SubTabsProps, SurfacePage, type SurfacePageProps, type TabDef, type TabGroupDef, TabGroups, type TabGroupsProps, Tabs, type TabsProps, type Theme, ThemeToggle, type Tone, type UsePausedVizOptions, VariantBar, type VariantBarProps, type VariantDef, Verdict, type VerdictProps, ViewsRow, type ViewsRowProps, type VizFrame, type VizLoop, type VizLoopDeps, type VizLoopOptions, type WorkbenchGroup, WorkbenchLayout, type WorkbenchLayoutProps, type WorkbenchRoute, WorkbenchShell, type WorkbenchShellProps, type WorkbenchState, WorkbenchStateContext, applyTheme, caseKind, caseTooltip, casesInSource, createVizLoop, deckPosition, deckWindow, firstAppearance, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, perPageFor, readCaseParam, readTheme, removeQueryParam, replaceQueryParam, sourcesPresent, textWidth, usePausedViz, useStageSize, useThemeStore, useUrlView, useWorkbenchState, validateExecutive, viewParamOf, widestLabel, withCaseParam };
1383
+ export { BREAKPOINTS, BarChart, type BarChartProps, type BarDatum, BiText, Callout, CardDeck, type CardDeckProps, type CaseDef, type CaseFocusConfig, type CaseGroup, type CaseKind, CaseSelector, type CaseSelectorProps, type CaseSelectorText, CaseWorkbench, type CaseWorkbenchProps, ChipGroup, type ChipGroupProps, type ChipOption, type Citation, CitationsProvider, Cite, DECK_TEXT, DOC_AREAS, type DeckCard, DocPage, type DocPageProps, DocReferences, DocRefsScope, DocSection, type DocSectionProps, EXECUTIVE_SCHEMA_VERSION, Equation, type ExecutiveData, type ExecutiveProblem, ExecutiveView, type ExecutiveViewProps, FLIP_LIMITS, FLIP_TEXT, FOCUS_PARAM, FOCUS_TEXT, FOUR_CS, Figure, type FittedLabel, FlipCard, type FlipCardProps, type FocusMode, type FocusModeConfig, type FocusModeOptions, FocusShell, type FocusShellProps, FormatOptions, Gauge, type GaugeProps, type GaugeZone, Glossary, type GlossaryEntry, InlineMath, Knob, type KnobProps, Landing, type Lane, LaneBadge, Lang, LanguageToggle, MAX_PEER_TABS, MAX_WORKBENCH_GROUPS, PanelBoundary, type PausedVizController, PlotCard, type PlotCardProps, type Provenance, Question, type QuestionProps, type RailSection, Readout, type ReadoutItem, type ReadoutProps, ReferenceList, Refs, Stage, type StageSize, Stat, type StatProps, type SubTabDef, SubTabs, type SubTabsProps, type SurfaceFocusConfig, SurfacePage, type SurfacePageProps, type TabDef, type TabGroupDef, TabGroups, type TabGroupsProps, Tabs, type TabsProps, type Theme, ThemeToggle, type Tone, type UsePausedVizOptions, VariantBar, type VariantBarProps, type VariantDef, Verdict, type VerdictProps, type ViewFocusConfig, ViewsRow, type ViewsRowProps, type VizFrame, type VizLoop, type VizLoopDeps, type VizLoopOptions, type WorkbenchGroup, WorkbenchLayout, type WorkbenchLayoutProps, type WorkbenchRoute, WorkbenchShell, type WorkbenchShellProps, type WorkbenchState, WorkbenchStateContext, applyTheme, caseKind, caseTooltip, casesInSource, createVizLoop, deckPosition, deckWindow, firstAppearance, fitLabel, fontFamily, groupByCategory, isStale, makeStateKey, niceStep, niceTicks, perPageFor, readCaseParam, readTheme, removeQueryParam, replaceQueryParam, sourcesPresent, textWidth, useFocusMode, usePausedViz, useStageSize, useThemeStore, useUrlView, useWorkbenchState, validateExecutive, viewParamOf, widestLabel, withCaseParam };