ui(components): migrates to new toolbar ui components and Numeric for Input InputRange and InputDoubleRange (#4728)

Co-authored-by: sedghi <ar.sedghi@gmail.com>
This commit is contained in:
Dan Rukasandsedghi authored and GitHub committed 2025-01-29 13:36:52 -05:00
1 parent ac5ae4a29e
commit a8d84443a9
116 files changed
+2930 -1038

No files matched your search

@@ -0,0 +1,199 @@
---
title: Input Number, Range, and Double Range
---
# Migration Guide: Moving to `Numeric` Component
This guide explains how to migrate from the existing `Input`, `InputRange`, and `InputDoubleRange` components to the new `Numeric` meta component.
## Why Migrate?
The old components relied heavily on props, making them complex and difficult to maintain and apply custom styles. The new `Numeric` component provides a structured approach with a context-based API, reducing prop clutter and improving reusability.
## `Input` > `Numeric.NumberInput`
### Basic Usage
**Old Usage:**
```tsx
<Input
id="example"
label="Enter a number"
value={value}
onChange={(e) => setValue(e.target.value)}
type="number"
/>
```
**New Usage:**
```tsx
<Numeric.Container mode="number" value={value} onChange={setValue}>
<Numeric.Label>Enter a number</Numeric.Label>
<Numeric.NumberInput />
</Numeric.Container>
```
### `Input` with Custom Classes
#### **Old Usage (with containerClassName, labelClassName, and className)**
In the old implementation, we manually applied `containerClassName`, `labelClassName`, and `className` to style the `Input` component:
```tsx
<Input
id="example"
label="Enter a number"
value={value}
onChange={(e) => setValue(e.target.value)}
type="number"
containerClassName="flex flex-col space-y-2"
labelClassName="text-gray-500 text-sm"
className="border rounded p-2"
/>
```
**New Usage (Migrating to `Numeric.NumberInput`)**
With `Numeric`, you should wrap everything inside `Numeric.Container`, and you can directly apply class names to its subcomponents:
```tsx
<Numeric.Container mode="number" value={value} onChange={setValue} className="flex flex-col space-y-2">
<Numeric.Label className="text-gray-500 text-sm">Enter a number</Numeric.Label>
<Numeric.NumberInput className="border rounded p-2" />
</Numeric.Container>
```
## `InputRange` > `Numeric.SingleRange`
### Basic Usage
**Old Usage:**
```tsx
<InputRange
value={value}
onChange={setValue}
minValue={0}
maxValue={100}
step={1}
showLabel
/>
```
**New Usage:**
```tsx
<Numeric.Container mode="singleRange" value={value} onChange={setValue} min={0} max={100} step={1}>
<Numeric.Label showValue>Range</Numeric.Label>
<Numeric.SingleRange showNumberInput />
</Numeric.Container>
```
### Custom Classes
**Old Usage**
```tsx
<InputRange
value={value}
onChange={setValue}
minValue={0}
maxValue={100}
step={1}
containerClassName="flex flex-col space-y-2"
inputClassName="w-full bg-gray-700"
labelClassName="text-gray-500 text-sm"
labelVariant="body1"
showLabel={true}
labelPosition="left"
/>
```
**New Usage**
```tsx
<Numeric.Container mode="singleRange" value={value} onChange={setValue} min={0} max={100} step={1} className="flex flex-col space-y-2">
<Numeric.Label className="text-gray-500 text-sm">Range</Numeric.Label>
<Numeric.SingleRange sliderClassName="w-full bg-gray-700" />
</Numeric.Container>
```
:::note
You now have more control over the position of the label and the slider. You can use pretty much any layout you want, whether that's flex, grid, or something else. Instead of relying on `labelPosition` to position the label, you're free to use the layout that works best for you.
:::
### AllowNumberEdit
**Old Usage:**
```tsx
<InputRange
value={value}
onChange={setValue}
minValue={0}
maxValue={100}
step={1}
allowNumberEdit={true}
showAdjustmentArrows={true}
/>
```
**New Usage:**
Using `Numeric.SingleRange` and `showNumberInput`
```tsx
<Numeric.Container mode="singleRange" value={value} onChange={setValue} min={0} max={100} step={1}>
<Numeric.Label showValue>Range</Numeric.Label>
<Numeric.SingleRange showNumberInput />
</Numeric.Container>
```
## `InputDoubleRange` > `Numeric.DoubleRange`
### Basic Usage
**Old Usage:**
```tsx
<InputDoubleRange
values={rangeValues}
onChange={setRangeValues}
minValue={0}
maxValue={100}
step={5}
showLabel
/>
```
**New Usage:**
```tsx
<Numeric.Container mode="doubleRange" values={rangeValues} onChange={setRangeValues} min={0} max={100} step={5}>
<Numeric.Label showValue>Range</Numeric.Label>
<Numeric.DoubleRange showNumberInputs />
</Numeric.Container>
```
---
## Summary of Changes
| Old Component | New Component Equivalent |
|--------------------|------------------------|
| `<Input>` | `<Numeric.NumberInput>` |
| `<InputRange>` | `<Numeric.SingleRange>` |
| `<InputDoubleRange>` | `<Numeric.DoubleRange>` |
@@ -0,0 +1,68 @@
---
title: Tests
---
## 1. ToolButton `data-active` Attribute
- **Previous**: Checked for a `bg-primary-light` class to determine if a tool was active.
- **Now**: Check for the HTML attribute `data-active="true"`.
### Example
```diff
- cy.get('@wwwcButton').should('have.class', 'bg-primary-light');
+ cy.get('@wwwcButton').should('have.attr', 'data-active', 'true');
```
## 2. Additional Data Attributes
- Each tool button now includes:
- `data-tool="<toolId>"`
- `data-active="<true|false>"`
This makes it easier to identify and assert on specific tools in the DOM.
### Example
```diff
- <span data-cy={id}>
+ <span
+ data-cy={id}
+ data-tool={id}
+ data-active={isActive}
+ >
```
## 3. MPR Button Class Change
If you were targeting the `ohif-disabled` class, you need to update your tests to target the `cursor-not-allowed` class.
- **Previous**: `ohif-disabled`
- **Now**: `cursor-not-allowed`
### Example
```diff
- cy.get('[data-cy="MPR"]').should('have.class', 'ohif-disabled');
+ cy.get('[data-cy="MPR"]').should('have.class', 'cursor-not-allowed');
```
## 4. Removal of Stack Scroll Alias
- The `[data-cy="StackScroll"]` element is no longer reliably in the DOM at study load.
- If needed, reintroduce or conditionally assert its presence when appropriate.
```diff
- cy.get('[data-cy="StackScroll"]').as('stackScrollBtn');
+ // Removed due to absence in DOM at study load
```
---
## Summary
1. **Replace** all checks for `bg-primary-light` with `data-active="true"`.
2. **Use** `data-tool` and `data-active` attributes for more robust DOM selection and assertions.
3. **Update** MPR button checks to `cursor-not-allowed`.
4. **Remove** the `[data-cy="StackScroll"]` alias (or only use it when the element is present).
@@ -0,0 +1,101 @@
---
title: Toolbar
---
# Toolbar
## New Toolbar uiType
We have two new toolbar button types: `ohif.toolButtonList` and `ohif.toolButton`, which are intended to replace the `ohif.radioGroup` and `ohif.splitButton` types.
Note that these are backward compatible, so if you are not ready to pick up the new ui types (which are more flexible and powerful), you can continue using the old types.
```js
// Old type
{
uiType: 'ohif.radioGroup',
}
// New type
{
uiType: 'ohif.toolButton',
}
```
and
```js
// Old type
{
uiType: 'ohif.splitButton',
}
// New type
{
uiType: 'ohif.toolButtonList',
}
```
The `ohif.buttonGroup` and `ohif.radioGroup` types used in the Toolbox have been replaced with `ohif.toolBoxButtonGroup` and `ohif.toolBoxButton` to reflect their usage in the Toolbox, which has distinct styling.
```js
// Old type
{
uiType: 'ohif.buttonGroup',
}
// New type
{
uiType: 'ohif.toolBoxButtonGroup',
}
```
```js
// Old type
{
uiType: 'ohif.radioGroup',
}
// New type
{
uiType: 'ohif.toolBoxButton',
}
```
## getToolbarModule
The `getToolbarModule` function previously returned `disabled`, `disabledText`, and `className` as part of its evaluation process for the button state. These properties will still be returned, but common class names are now handled internally by the new UI button components, including `ToolButton`, `ToolButtonList`, `Toolbox`, and `ToolBoxGroup`. You can override the `className` if you need to.
## ToolBox
Previously, the segmentation toolbox was not using an `evaluator` property. This is now taken into account
```js
// old
{
id: 'BrushTools',
uiType: 'ohif.buttonGroup',
props: {
groupId: 'BrushTools',
items: []
}
}
// now
{
id: 'BrushTools',
uiType: 'ohif.buttonGroup',
props: {
groupId: 'BrushTools',
evaluate: 'evaluate.cornerstone.hasSegmentation',
items: []
}
}
```