@lunit/oui 3.1.0 → 3.1.2

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 (53) hide show
  1. package/dist/presentations/AnalysisBar/AnalysisBar.js +3 -2
  2. package/dist/presentations/AnalysisBar/AnalysisBar.utils.js +11 -0
  3. package/dist/types/components/Alert/Alert.types.d.ts +1 -0
  4. package/dist/types/components/BaseTextField/BaseTextField.types.d.ts +9 -0
  5. package/dist/types/components/Button/Button.types.d.ts +13 -0
  6. package/dist/types/components/Card/Card.types.d.ts +4 -0
  7. package/dist/types/components/Checkbox/Checkbox.types.d.ts +12 -0
  8. package/dist/types/components/Chip/Chip.types.d.ts +2 -0
  9. package/dist/types/components/DatePicker/DatePicker.types.d.ts +2 -0
  10. package/dist/types/components/Dialog/Dialog.types.d.ts +15 -0
  11. package/dist/types/components/Divider/Divider.types.d.ts +1 -0
  12. package/dist/types/components/Dropdown/Dropdown.types.d.ts +9 -0
  13. package/dist/types/components/Dropdown/DropdownItem.types.d.ts +5 -0
  14. package/dist/types/components/Dropdown/DropdownSubtitle.types.d.ts +2 -0
  15. package/dist/types/components/Dropdown/IconDropdown.types.d.ts +7 -0
  16. package/dist/types/components/EllipsisTypography/EllipsisTypography.types.d.ts +4 -0
  17. package/dist/types/components/FileDnDZone/FileDnDZone.types.d.ts +8 -0
  18. package/dist/types/components/List/List.types.d.ts +9 -0
  19. package/dist/types/components/List/ListItem.types.d.ts +6 -0
  20. package/dist/types/components/List/ListItemCaption.types.d.ts +1 -0
  21. package/dist/types/components/LoadingIndicator/LoadingIndicator.types.d.ts +4 -0
  22. package/dist/types/components/Menu/Menu.types.d.ts +5 -0
  23. package/dist/types/components/Menu/MenuItem.types.d.ts +6 -0
  24. package/dist/types/components/Pagination/Pagination.types.d.ts +6 -0
  25. package/dist/types/components/ProductLabel/ProductLabel.types.d.ts +6 -0
  26. package/dist/types/components/Progress/CircularProgress.types.d.ts +2 -0
  27. package/dist/types/components/Progress/LinearProgress.types.d.ts +3 -0
  28. package/dist/types/components/Radio/Radio.types.d.ts +11 -0
  29. package/dist/types/components/Radio/RadioGroup.types.d.ts +6 -0
  30. package/dist/types/components/Stepper/Stepper.types.d.ts +5 -0
  31. package/dist/types/components/TabbedPanel/TabbedPanel.types.d.ts +17 -0
  32. package/dist/types/components/TextField/TextArea.types.d.ts +10 -0
  33. package/dist/types/components/TextField/TextInput.types.d.ts +14 -0
  34. package/dist/types/components/Toggle/Toggle.types.d.ts +14 -0
  35. package/dist/types/components/Tooltip/Tooltip.types.d.ts +5 -0
  36. package/dist/types/components/UploadManager/UploadManager.types.d.ts +9 -0
  37. package/dist/types/presentations/Accordion/Accordion.types.d.ts +11 -0
  38. package/dist/types/presentations/AnalysisBar/AnalysisBar.types.d.ts +18 -1
  39. package/dist/types/presentations/AnalysisBar/AnalysisBar.utils.d.ts +7 -0
  40. package/dist/types/presentations/AnalysisBar/index.d.ts +2 -2
  41. package/dist/types/presentations/FreeText/FreeText.types.d.ts +5 -0
  42. package/dist/types/presentations/Histogram/Histogram.types.d.ts +14 -0
  43. package/dist/types/presentations/HorizonDivider/HorizonDivider.types.d.ts +1 -0
  44. package/dist/types/presentations/ModelType/ModelType.types.d.ts +17 -0
  45. package/dist/types/presentations/Preview/Preview.types.d.ts +2 -0
  46. package/dist/types/presentations/Score/Score.types.d.ts +8 -0
  47. package/dist/types/presentations/Statistic/Statistic.types.d.ts +9 -0
  48. package/dist/types/presentations/Threshold/Threshold.types.d.ts +20 -0
  49. package/dist/types/presentations/ToggleControl/ToggleControl.types.d.ts +29 -0
  50. package/dist/types/presentations/ToggleControlGroup/ToggleControlGroup.types.d.ts +11 -0
  51. package/dist/types/presentations/presentations.types.d.ts +6 -0
  52. package/docs/COMPONENTS.md +28 -0
  53. package/package.json +1 -1
@@ -1,27 +1,41 @@
1
1
  import type { BoxProps, InputProps as MuiInputProps } from '@mui/material';
2
2
  import type { RootTextFieldProps, HelperMsgProps } from '../BaseTextField/BaseTextField.types';
3
3
  interface RootTextInputProps extends RootTextFieldProps, Omit<MuiInputProps, 'size' | 'error' | 'ref' | 'value' | 'defaultValue' | 'onChange'> {
4
+ /** Uses the taller input height */
4
5
  large?: boolean;
6
+ /** Icon rendered inside the field, before the text */
5
7
  leftIcon?: React.ReactNode;
8
+ /** Icon rendered inside the field, after the text; replaces the clear button */
6
9
  rightIcon?: React.ReactNode;
10
+ /** Called on every keystroke */
7
11
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
12
+ /** Props for the wrapper Box around the field and its helper message */
8
13
  OuterBoxProps?: BoxProps;
14
+ /** Props for the Box wrapping the input and its icons */
9
15
  InputContainerProps?: BoxProps;
16
+ /** Style overrides for the input element itself, replacing the default icon padding */
10
17
  inputSX?: MuiInputProps['sx'];
11
18
  }
12
19
  interface InputWithHelperMsgProps extends Omit<RootTextInputProps, 'error'>, Omit<HelperMsgProps, 'error'> {
20
+ /** Error message shown under the field; also puts the field in its error state */
13
21
  error?: string;
14
22
  }
15
23
  interface PasswordInputWithHelperMsgProps extends Omit<InputWithHelperMsgProps, 'rightIcon' | 'readOnly' | 'onClearButtonClick' | 'InputContainerProps'> {
24
+ /** Renders a password field with a built-in reveal toggle */
16
25
  type: 'password';
17
26
  }
18
27
  interface NormalTextInputProps extends InputWithHelperMsgProps {
28
+ /** Called when the clear button is pressed; the button only renders when this is set */
19
29
  onClearButtonClick?: () => void;
30
+ /** Icon rendered inside the field, after the text; replaces the clear button */
20
31
  rightIcon?: React.ReactNode;
21
32
  }
22
33
  interface FileInputProps extends NormalTextInputProps {
34
+ /** Renders a file picker field */
23
35
  type: 'file';
36
+ /** Extensions the picker accepts, as an `accept` attribute value */
24
37
  accept: string;
38
+ /** Called when the field is clicked to open the picker */
25
39
  onClick: () => void;
26
40
  }
27
41
  interface PasswordTextInputProps extends PasswordInputWithHelperMsgProps {
@@ -1,17 +1,31 @@
1
1
  import type { BoxProps, Color, SwitchProps as MuiSwitchProps } from '@mui/material';
2
2
  export interface ToggleProps extends Omit<BoxProps<'span'>, 'onChange' | 'onChangeCapture'> {
3
+ /** Value submitted with the surrounding form */
3
4
  value?: MuiSwitchProps['value'];
5
+ /** Name of the underlying input */
4
6
  name?: MuiSwitchProps['name'];
7
+ /** Whether the switch is on, for controlled use */
5
8
  checked?: MuiSwitchProps['checked'];
9
+ /** Initial state, for uncontrolled use */
6
10
  defaultChecked?: MuiSwitchProps['defaultChecked'];
11
+ /** Blocks interaction and renders the muted disabled style */
7
12
  disabled?: MuiSwitchProps['disabled'];
13
+ /** Marks the input as required in the surrounding form */
8
14
  required?: MuiSwitchProps['required'];
15
+ /** Called when the switch is flipped */
9
16
  onChange?: MuiSwitchProps['onChange'];
17
+ /** Capture-phase change handler */
10
18
  onChangeCapture?: MuiSwitchProps['onChangeCapture'];
19
+ /** Attributes applied to the underlying input element */
11
20
  inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
21
+ /** Ref to the underlying input element */
12
22
  inputRef?: React.Ref<HTMLInputElement>;
23
+ /** Renders the partial state; the change event still reports `checked: true` */
13
24
  indeterminate?: boolean;
25
+ /** Text shown beside the switch; makes the container a `<label>` */
14
26
  label?: string;
27
+ /** Which side of the switch the label sits on. Defaults to `right` */
15
28
  labelPlacement?: 'left' | 'right';
29
+ /** Track colour while the switch is on */
16
30
  toggleColor?: React.CSSProperties['color'] | Color;
17
31
  }
@@ -3,14 +3,19 @@ import type { TooltipClasses, TooltipProps as MuiTooltipProps } from '@mui/mater
3
3
  export type Position = Pick<TooltipProps, 'placement'>;
4
4
  export type TooltipSizes = 'small' | 'large';
5
5
  export interface TooltipSize {
6
+ /** Arrow width in px */
6
7
  width: number;
8
+ /** Arrow height in px */
7
9
  height: number;
8
10
  }
9
11
  export type TooltipPlacement = TooltipClasses['tooltipPlacementBottom'] | TooltipClasses['tooltipPlacementLeft'] | TooltipClasses['tooltipPlacementRight'] | TooltipClasses['tooltipPlacementTop'];
10
12
  export type ArrowSizeBySize = Record<TooltipSizes, TooltipSize>;
11
13
  export type TooltipPlacementToSize = Record<TooltipPlacement, ArrowSizeBySize>;
12
14
  export interface TooltipProps extends MuiTooltipProps {
15
+ /** Icon rendered before the title; `small` size only */
13
16
  icon?: ReactNode;
17
+ /** Padding and typography preset. Defaults to `small` */
14
18
  size?: TooltipSizes;
19
+ /** Removes the tooltip's inner padding, for content that brings its own */
15
20
  noPadding?: boolean;
16
21
  }
@@ -1,14 +1,23 @@
1
1
  import { UppyFile } from '@uppy/core';
2
2
  export interface UploadFileProps {
3
+ /** Uppy file whose name, size and progress are rendered */
3
4
  file: UppyFile;
5
+ /** Called with the file id when its cancel button is clicked */
4
6
  onCancel?: (id: string) => void;
7
+ /** Called with the file id when a failed upload is retried */
5
8
  onRetry?: (id: string) => void;
6
9
  }
7
10
  export interface UploadManagerProps {
11
+ /** Heading of the upload panel */
8
12
  title: string;
13
+ /** Secondary line under the title, e.g. overall progress */
9
14
  subTitle?: string;
15
+ /** Files listed in the panel */
10
16
  files: UppyFile[];
17
+ /** Called when the panel's close button is clicked */
11
18
  onClose?: () => void;
19
+ /** Called with the file id when a file's cancel button is clicked */
12
20
  onCancel?: (id: string) => void;
21
+ /** Called with the file id when a failed upload is retried */
13
22
  onRetry?: (id: string) => void;
14
23
  }
@@ -4,18 +4,29 @@ import { FreeTextProps } from '../FreeText';
4
4
  import { StatisticProps } from '../Statistic';
5
5
  import { ScoreProps } from '../Score';
6
6
  export interface AccordionSpec {
7
+ /** Discriminator identifying this spec as an accordion */
7
8
  componentType: 'accordion';
9
+ /** Section heading shown in the summary row */
8
10
  title: string;
11
+ /** Text size and weight preset for the summary row */
9
12
  size?: PresentationElementSize;
13
+ /** Components rendered inside the expanded section; must contain at least one item */
10
14
  items: (StatisticProps | FreeTextProps | ScoreProps)[];
15
+ /** Whether the section starts expanded */
11
16
  isOpen?: boolean;
17
+ /** Components rendered in a tooltip behind an info icon before the title */
12
18
  tooltip?: (StatisticProps | FreeTextProps)[];
19
+ /** Value appended to the title as `title: metrics` */
13
20
  metrics?: string;
14
21
  }
15
22
  interface AccordionProps extends AccordionSpec {
23
+ /** Props forwarded to the underlying MUI Accordion */
16
24
  MuiAccordionProps?: MuiAccordionProps;
25
+ /** Props forwarded to the underlying MUI AccordionSummary */
17
26
  AccordionSummaryProps?: AccordionSummaryProps;
27
+ /** Props forwarded to the underlying MUI AccordionDetails */
18
28
  AccordionDetailsProps?: AccordionDetailsProps;
29
+ /** Called with the next expanded state when the summary row is clicked */
19
30
  onChange?: (event: React.SyntheticEvent, expanded: boolean) => void;
20
31
  }
21
32
  export type { AccordionProps };
@@ -1,13 +1,30 @@
1
+ /** A label placed at an explicit position on the bar */
2
+ export interface AnalysisBarLevel {
3
+ /** Text displayed under the bar */
4
+ label: string;
5
+ /** Horizontal position on the bar, 0-100 (%) */
6
+ position: number;
7
+ }
8
+ /** Either a numeric string ('20', '20%') that doubles as its own label, or an explicitly positioned label */
9
+ export type AnalysisBarExpressionLevel = string | AnalysisBarLevel;
1
10
  export interface AnalysisBarProps {
11
+ /** Discriminator identifying this spec as an analysis bar */
2
12
  componentType: 'analysisBar';
13
+ /** Widens segments of 1% or less to a fixed 12px so they stay visible */
3
14
  isCutoff?: boolean;
4
- expressionLevels?: string[];
15
+ /** Axis labels under the bar. Numeric strings are placed at their own value; objects at their `position` */
16
+ expressionLevels?: AnalysisBarExpressionLevel[];
17
+ /** Caption rendered at the midpoint of the bar */
5
18
  caption?: string;
19
+ /** Colour segments making up the bar; widths are normalised to 100%. A `jet` colour renders a heatmap gradient */
6
20
  segments?: {
7
21
  color: 'jet' | string;
8
22
  width: number;
9
23
  }[];
24
+ /** Value of the point indicator, which also sets its position on the bar */
10
25
  expressionValue?: string;
26
+ /** Overrides the displayed text of the axis label at the same index, leaving its position unchanged */
11
27
  expressionLabels?: string[];
28
+ /** Renders the whole bar at reduced opacity */
12
29
  isDimmed?: boolean;
13
30
  }
@@ -1,4 +1,11 @@
1
+ import type { AnalysisBarExpressionLevel, AnalysisBarLevel } from './AnalysisBar.types';
1
2
  export declare function parseStringValToNumber(val: string): number;
3
+ /**
4
+ * @description resolveExpressionLevel normalizes an expression level into a label and its position on the bar.
5
+ * @param level - A numeric string ('20', '20%') used as both label and position, or an object with an explicit label and position.
6
+ * @returns The label to display and its position on the bar.
7
+ */
8
+ export declare function resolveExpressionLevel(level: AnalysisBarExpressionLevel): AnalysisBarLevel;
2
9
  export declare function clampNumericalPercentage(value: number): number;
3
10
  export declare function clampBarLabelPosition(value: number): number;
4
11
  /**
@@ -1,4 +1,4 @@
1
1
  import AnalysisBar from './AnalysisBar';
2
- import type { AnalysisBarProps } from './AnalysisBar.types';
2
+ import type { AnalysisBarProps, AnalysisBarLevel, AnalysisBarExpressionLevel } from './AnalysisBar.types';
3
3
  export { AnalysisBar };
4
- export type { AnalysisBarProps };
4
+ export type { AnalysisBarProps, AnalysisBarLevel, AnalysisBarExpressionLevel };
@@ -1,9 +1,14 @@
1
1
  import type { PresentationElementSize } from '../presentations.types';
2
2
  interface FreeTextProps {
3
+ /** Discriminator identifying this spec as free text */
3
4
  componentType: 'freeText';
5
+ /** Text size and weight preset */
4
6
  size?: PresentationElementSize;
7
+ /** Text to render; line breaks are preserved */
5
8
  content: string;
9
+ /** Fixed height in px; the text scrolls when it overflows. Grows with the content when omitted */
6
10
  height?: number;
11
+ /** Wraps the text in a rounded grey panel with padding */
7
12
  background?: boolean;
8
13
  }
9
14
  export type { FreeTextProps };
@@ -1,24 +1,38 @@
1
1
  import { FreeTextProps } from '../FreeText';
2
2
  export interface HistogramTab {
3
+ /** Tab label shown above the chart */
3
4
  label: string;
5
+ /** Bar heights, one entry per bucket */
4
6
  data: number[];
5
7
  }
6
8
  export interface HistogramProps {
9
+ /** Discriminator identifying this spec as a histogram */
7
10
  componentType: 'histogram';
11
+ /** Heading shown above the tabs */
8
12
  title?: string;
13
+ /** Free text blocks rendered under the chart */
9
14
  description?: FreeTextProps[];
15
+ /** Tick values along the x axis; must contain at least one item */
10
16
  xAxisLabels: number[];
17
+ /** Tick values along the y axis; must contain at least one item */
11
18
  yAxisLabels: number[];
19
+ /** Datasets selectable by tab; the first one is shown initially */
12
20
  tabs: HistogramTab[];
13
21
  }
14
22
  export interface HistogramTabsProps {
23
+ /** Tab labels in display order */
15
24
  options: string[];
25
+ /** Index of the selected tab */
16
26
  active: number;
27
+ /** Called with the index of the newly selected tab */
17
28
  onChange: (index: number) => void;
18
29
  }
19
30
  export interface HistogramChartProps {
31
+ /** Dataset to plot */
20
32
  dataset: HistogramTab;
33
+ /** Tick values along the x axis */
21
34
  xAxisLabels: number[];
35
+ /** Tick values along the y axis */
22
36
  yAxisLabels: number[];
23
37
  }
24
38
  interface HistogramDatapoint {
@@ -1,4 +1,5 @@
1
1
  interface HorizonDividerProps {
2
+ /** Discriminator identifying this spec as a divider */
2
3
  componentType: 'divider';
3
4
  }
4
5
  export type { HorizonDividerProps };
@@ -1,33 +1,50 @@
1
1
  import { SelectChangeEvent } from '@mui/material/Select';
2
2
  import { ScoreProps } from '../Score';
3
3
  interface ModelTypeOption {
4
+ /** Option label shown in the dropdown */
4
5
  title: string;
6
+ /** Visualization this option switches the viewer to. Read by the host app, not by this component */
5
7
  target: {
6
8
  visualizationType: string;
7
9
  annotation: {
10
+ /** Annotation name; must match the LOAR annotation it refers to */
8
11
  name: string;
12
+ /** Measurement region, also used as the option's dropdown value */
9
13
  dimension: string;
10
14
  color: string;
11
15
  };
12
16
  };
13
17
  key: string;
14
18
  value: number;
19
+ /** Sensitivity of this model type; must be a number */
15
20
  sensitivity: number;
21
+ /** Specificity of this model type; must be a number */
16
22
  specificity: number;
17
23
  }
18
24
  export interface ModelTypeSpec {
25
+ /** Discriminator identifying this spec as a model type selector */
19
26
  componentType: 'modelType';
27
+ /** Heading shown above the sensitivity and specificity scores */
20
28
  title: string;
29
+ /** Subtitle rendered at the top of the dropdown list */
21
30
  optionTitle?: string;
31
+ /** Scores to show per model type, keyed by the option's `target.annotation.dimension` */
22
32
  scoreItems: Record<string, ScoreProps[]>;
33
+ /** Sensitivity of the currently applied model type */
23
34
  currentSensitivity: ScoreProps;
35
+ /** Specificity of the currently applied model type */
24
36
  currentSpecificity: ScoreProps;
37
+ /** Selectable model types; must contain at least one item */
25
38
  options: ModelTypeOption[];
39
+ /** Dimension of the model type currently applied; selects the initial dropdown value */
26
40
  userModelType: string;
41
+ /** Guidance text rendered under the update button */
27
42
  description?: string;
28
43
  }
29
44
  export interface ModelTypeProps extends ModelTypeSpec {
45
+ /** Called when a different model type is picked from the dropdown */
30
46
  onChangeDropdown: (event: SelectChangeEvent) => void;
47
+ /** Called when the update button is pressed; the button is disabled until the selection changes */
31
48
  onClickUpdateConfiguration: () => void;
32
49
  }
33
50
  export {};
@@ -9,7 +9,9 @@ import { ThresholdProps } from '../Threshold';
9
9
  import { HistogramProps } from '../Histogram';
10
10
  import { ModelTypeProps } from '../ModelType';
11
11
  interface PreviewProps {
12
+ /** Layer toggles rendered in the upper section, in display order */
12
13
  visualizationControls: (ToggleControlProps | ToggleControlGroupProps | AnalysisBarProps)[];
14
+ /** Result summary components rendered in the lower section, in display order */
13
15
  analysisSummary: (AccordionProps | AnalysisBarProps | StatisticProps | ScoreProps | FreeTextProps | ThresholdProps | HistogramProps | ModelTypeProps)[];
14
16
  }
15
17
  export type { PreviewProps };
@@ -1,12 +1,20 @@
1
1
  import { PresentationElementSize } from '../presentations.types';
2
2
  interface ScoreProps {
3
+ /** Discriminator identifying this spec as a score */
3
4
  componentType: 'score';
5
+ /** Score name shown before the value */
4
6
  title: string;
7
+ /** Text size and weight preset */
5
8
  size?: PresentationElementSize;
9
+ /** The score value and how it is coloured */
6
10
  metrics: {
11
+ /** Formatted score value shown after the title */
7
12
  value?: string;
13
+ /** Qualitative result appended after the value, capitalised on render */
8
14
  scoreType?: 'positive' | 'negative';
15
+ /** Colour applied to the score type, and to the whole line when `isFullColored` is set */
9
16
  color?: string;
17
+ /** Applies `color` to the title and value as well, not just the score type */
10
18
  isFullColored?: boolean;
11
19
  };
12
20
  }
@@ -1,15 +1,24 @@
1
1
  import { BoxProps } from '@mui/material';
2
2
  import { PresentationSymbolProps } from '../presentations.types';
3
3
  export interface StatisticSpec extends BoxProps {
4
+ /** Discriminator identifying this spec as a statistic */
4
5
  componentType: 'statistic';
6
+ /** Label describing the metric */
5
7
  title: string;
8
+ /** `horizontal` puts the value on the same line as the title, `vertical` stacks them */
6
9
  layout?: 'horizontal' | 'vertical';
10
+ /** Formatted value shown next to the title */
7
11
  metrics?: string;
12
+ /** Text size and weight preset */
8
13
  size?: 'small-dimmed' | 'small' | 'small-bold' | 'medium' | 'medium-bold' | 'large-bold';
14
+ /** Shape of the legend marker drawn before the title; horizontal layout only */
9
15
  symbol?: PresentationSymbolProps['symbol'];
16
+ /** Fill colour of the legend marker */
10
17
  color?: string;
18
+ /** DOM id applied to the container */
11
19
  id?: string;
12
20
  }
13
21
  export interface StatisticProps extends StatisticSpec {
22
+ /** Renders the marker and title at reduced opacity */
14
23
  isDimmed?: boolean;
15
24
  }
@@ -4,9 +4,13 @@ import { SelectChangeEvent } from '@mui/material/Select';
4
4
  import { ScoreProps } from '../Score';
5
5
  import { StatisticProps } from '../Statistic';
6
6
  export interface ThresholdOption {
7
+ /** Option label shown in the dropdown, also used as its value */
7
8
  title: string;
9
+ /** Grouping key for the option. Read by the host app, not by this component */
8
10
  category: string;
11
+ /** Threshold this option applies, on the 0-100 intensity scale */
9
12
  value: number;
13
+ /** Marks the option as a fixed preset, which locks the slider. Read by the host app, not by this component */
10
14
  isPreset?: boolean;
11
15
  }
12
16
  export interface ThresholdMark {
@@ -16,33 +20,49 @@ export interface ThresholdMark {
16
20
  label?: string;
17
21
  }
18
22
  export interface ThresholdSpec {
23
+ /** Discriminator identifying this spec as a threshold control */
19
24
  componentType: 'threshold';
20
25
  /** Overall score summary shown above the cell statistics; omitted when the analysis has no score */
21
26
  totalScore?: ScoreProps;
27
+ /** Total cell count shown above the per-category statistics */
22
28
  totalCells: StatisticProps;
29
+ /** Per-category cell statistics shown under the total */
23
30
  statisticItems: StatisticProps[];
31
+ /** Heading shown above the option dropdown */
24
32
  title?: string;
33
+ /** Guidance text shown under the slider, chosen by whether a preset is selected */
25
34
  description?: {
26
35
  /** Guidance shown while a preset option is selected */
27
36
  preset?: string;
28
37
  /** Guidance shown while a user-adjustable option is selected */
29
38
  user?: string;
30
39
  };
40
+ /** Selectable threshold options listed in the dropdown */
31
41
  options: ThresholdOption[];
42
+ /** Slider increment; defaults to 1 */
32
43
  controlStep?: number;
33
44
  /** Labels the selected option's threshold on the slider, e.g. `Default: 40`; off by default */
34
45
  showDefaultMark?: boolean;
35
46
  }
36
47
  export interface ThresholdProps extends ThresholdSpec {
48
+ /** Current selection and slider position, owned by the host app */
37
49
  thresholdState?: {
50
+ /** Title of the selected option */
38
51
  selectedItem: string;
52
+ /** Current slider position on the 0-100 intensity scale */
39
53
  sliderValue: number;
54
+ /** Locks the slider and shows `description.preset` instead of `description.user` */
40
55
  isPresetSelected: boolean;
41
56
  };
57
+ /** Called when a different option is picked from the dropdown */
42
58
  onChangeDropdown: (event: SelectChangeEvent) => void;
59
+ /** Called on every slider movement */
43
60
  onChangeSlider: (event: Event | SyntheticEvent, value: number | number[]) => void;
61
+ /** Called once the slider is released */
44
62
  onSliderChangeCommitted: (event: Event | SyntheticEvent, value: number | number[]) => void;
63
+ /** Called when the update button is pressed */
45
64
  onClickUpdateConfiguration: () => void;
65
+ /** Shows a spinner on the update button and blocks it */
46
66
  isLoading?: boolean;
47
67
  }
48
68
  export interface BaseSliderProps extends SliderProps {
@@ -3,47 +3,76 @@ import type { AnalysisBarProps } from '../AnalysisBar';
3
3
  import type { PresentationElementSize, PresentationSymbol } from '../presentations.types';
4
4
  import { StatisticProps } from '../Statistic';
5
5
  export interface ToggleControlSpec {
6
+ /** Discriminator identifying this spec as a toggle */
6
7
  componentType: 'toggle';
8
+ /** Label shown next to the switch */
7
9
  title: string;
10
+ /** Text size and weight preset */
8
11
  size?: PresentationElementSize;
12
+ /** Shape of the legend marker drawn before the title */
9
13
  symbol?: PresentationSymbol;
14
+ /** Fill colour of the legend marker */
10
15
  color?: string;
16
+ /** Whether the switch is on; required */
11
17
  checked: boolean;
18
+ /** Components rendered in a tooltip behind an info icon before the title */
12
19
  tooltip?: (StatisticProps | FreeTextProps)[];
20
+ /** Statistics rendered under the toggle row */
13
21
  content?: StatisticProps[];
22
+ /** Analysis bar rendered under the toggle row, below `content` */
14
23
  bar?: AnalysisBarProps;
15
24
  }
16
25
  interface PixelAnnotationSpec {
26
+ /** Annotation name; must match the LOAR `pixelAnnotations` entry */
17
27
  name: string;
28
+ /** Single measurement region to render */
18
29
  dimension?: string;
30
+ /** Multiple measurement regions to render */
19
31
  dimensions?: string[];
20
32
  }
21
33
  interface CellAnnotationSpec {
34
+ /** Annotation name; must match the LOAR `cellAnnotations` entry */
22
35
  name: string;
23
36
  }
24
37
  interface GridAnnotationSpec {
38
+ /** Annotation name; must match the LOAR `gridAnnotations` entry */
25
39
  name: string;
26
40
  }
27
41
  interface CutOffLabelProps {
42
+ /** Colour applied to the label's segment */
28
43
  color: string;
44
+ /** Index of the label within the annotation's label set */
29
45
  labelIndex: number;
30
46
  }
47
+ /** Visualization layer a toggle controls. Read by the host app, not by this component */
31
48
  interface TargetSpec {
49
+ /** Kind of visualization to render, e.g. `cell`, `grid`, `heatmap` */
32
50
  visualizationType: string;
33
51
  annotationId?: string;
52
+ /** Annotation to render, either a spec object or the annotation name */
34
53
  annotation: PixelAnnotationSpec | CellAnnotationSpec | GridAnnotationSpec | string;
54
+ /** Single annotation label to render */
35
55
  label?: string;
36
56
  labelId?: string;
57
+ /** Multiple annotation labels to render, optionally with per-label colours */
37
58
  labels?: (string | CutOffLabelProps)[];
59
+ /** Single colour applied to the layer */
38
60
  color?: string;
61
+ /** Per-label colours applied to the layer */
39
62
  colors?: string[];
40
63
  }
41
64
  export interface ToggleControlProps extends ToggleControlSpec {
65
+ /** Marks this toggle as a group header, adding spacing below it. Set by ToggleControlGroup */
42
66
  isParent?: boolean;
67
+ /** Renders the marker and title at reduced opacity, and blocks the switch */
43
68
  isDimmed?: boolean;
69
+ /** Blocks interaction with the switch */
44
70
  disabled?: boolean;
71
+ /** Visualization layer this toggle controls. Read by the host app, not by this component */
45
72
  target?: TargetSpec;
73
+ /** Marks this toggle as the master switch for every layer. Read by the host app, not by this component */
46
74
  isMaster?: boolean;
75
+ /** Called when the switch is flipped */
47
76
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
48
77
  }
49
78
  export {};
@@ -5,17 +5,28 @@ import { StatisticProps } from '../Statistic';
5
5
  import type { ToggleControlProps } from '../ToggleControl';
6
6
  export type ToggleControlGroupBehavior = 'exclusive' | 'multi';
7
7
  export interface ToggleGroupControlSpec {
8
+ /** Discriminator identifying this spec as a toggle group */
8
9
  componentType: 'toggleGroup';
10
+ /** Label shown next to the group's own switch */
9
11
  title: string;
12
+ /** Whether the children may be on together (`multi`) or only one at a time (`exclusive`). Read by the host app, not by this component */
10
13
  behavior?: ToggleControlGroupBehavior;
14
+ /** Text size and weight preset for the group header */
11
15
  size?: PresentationElementSize;
16
+ /** Components rendered in a tooltip behind an info icon before the title */
12
17
  tooltip?: (StatisticProps | FreeTextProps)[];
18
+ /** Analysis bar rendered under the group header row */
13
19
  bar?: AnalysisBarProps;
20
+ /** Whether the group switch is on; turning it off dims and disables every child. Required */
14
21
  checked: boolean;
22
+ /** Toggles rendered under the group header; must contain at least one item */
15
23
  childToggles: ToggleControlProps[];
16
24
  }
17
25
  export interface ToggleControlGroupProps extends ToggleGroupControlSpec {
26
+ /** Called when the group switch is flipped */
18
27
  onChange: (event: React.ChangeEvent<HTMLInputElement>) => void;
28
+ /** Blocks interaction with the group switch */
19
29
  disabled?: boolean;
30
+ /** Renders the group and its children at reduced opacity */
20
31
  isDimmed?: boolean;
21
32
  }
@@ -2,13 +2,19 @@ import { TypographyProps } from '@mui/material';
2
2
  export type PresentationElementSize = 'small-dimmed' | 'small' | 'small-bold' | 'medium' | 'medium-bold' | 'large-bold';
3
3
  export type PresentationSymbol = 'circle' | 'rectangle' | 'border-circle' | 'border-rectangle';
4
4
  interface PresentationSymbolProps {
5
+ /** Shape of the legend marker drawn next to a label */
5
6
  symbol?: PresentationSymbol;
7
+ /** Fill colour of the legend marker */
6
8
  color?: string;
9
+ /** Renders the marker at reduced opacity */
7
10
  isDimmed?: boolean;
8
11
  }
9
12
  interface PresentationTypographyProps extends TypographyProps {
13
+ /** Text size and weight preset */
10
14
  size?: PresentationElementSize;
15
+ /** Renders the text at reduced opacity */
11
16
  isDimmed?: boolean;
17
+ /** CSS display mode of the text element */
12
18
  display?: 'block' | 'inline-block' | 'flex' | 'inherit';
13
19
  }
14
20
  export type { PresentationSymbolProps, PresentationTypographyProps };
@@ -99,6 +99,34 @@ Exported together from `@lunit/oui`. Composite components for the oncology analy
99
99
 
100
100
  `Accordion`, `AnalysisBar`, `FreeText`, `Histogram`, `HorizonDivider`, `ModelType`, `Preview`, `Score`, `Statistic`, `Threshold`, `ToggleControl`, `ToggleControlGroup`
101
101
 
102
+ ### AnalysisBar — `expressionLevels`
103
+
104
+ Axis labels under the bar. Each item is either a numeric string, which is both the label and its position, or an object that places arbitrary text at an explicit position.
105
+
106
+ ```tsx
107
+ // numeric strings: label and position are the same value
108
+ <AnalysisBar componentType="analysisBar" expressionLevels={['0', '20', '100']} segments={segments} />
109
+
110
+ // text labels at explicit positions (0-100)
111
+ <AnalysisBar
112
+ componentType="analysisBar"
113
+ expressionLevels={[
114
+ { label: 'Low', position: 0 },
115
+ { label: 'High', position: 100 },
116
+ ]}
117
+ segments={segments}
118
+ />
119
+
120
+ // the two forms can be mixed
121
+ <AnalysisBar
122
+ componentType="analysisBar"
123
+ expressionLevels={['0', { label: 'Cutoff', position: 20 }, '100']}
124
+ segments={segments}
125
+ />
126
+ ```
127
+
128
+ `expressionLabels[i]`, when present, still overrides the displayed text of the i-th level while its position is unchanged.
129
+
102
130
  ---
103
131
 
104
132
  ## Usage examples
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunit/oui",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "validate-branch-name": {
5
5
  "pattern": "^(main|develop)|(feature|fix|release|hotfix|qe)/.+$",
6
6
  "errorMsg": "The branch name is not correct. Please check the pattern. (ex. feature/add-something)"