feat(data overlay): add foreground background control plus orientation change in the UI and add RTDOSE support (#5007)
This commit is contained in:
1 parent
c1fced0573
commit
cd4e6408bc
105 files changed
+3117
-788
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import { Button } from '../../components/Button/Button';
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -57,7 +57,7 @@ import { cn } from '../../lib/utils';
|
||||
* @property {() => void} onColor - Callback when color change is requested
|
||||
*/
|
||||
interface DataRowProps {
|
||||
number: number;
|
||||
number: number | null;
|
||||
disableEditing: boolean;
|
||||
description: string;
|
||||
details?: { primary: string[]; secondary: string[] };
|
||||
@@ -208,15 +208,18 @@ export const DataRow: React.FC<DataRowProps> = ({
|
||||
<div className="bg-primary/20 pointer-events-none absolute inset-0 opacity-0 transition-opacity group-hover:opacity-100"></div>
|
||||
|
||||
{/* Number Box */}
|
||||
<div
|
||||
className={`flex h-7 max-h-7 w-7 flex-shrink-0 items-center justify-center rounded-l border-r border-black text-base ${
|
||||
isSelected ? 'bg-highlight text-black' : 'bg-muted text-muted-foreground'
|
||||
} overflow-hidden`}
|
||||
>
|
||||
{number}
|
||||
</div>
|
||||
{number !== null && (
|
||||
<div
|
||||
className={`flex h-7 max-h-7 w-7 flex-shrink-0 items-center justify-center rounded-l border-r border-black text-base ${
|
||||
isSelected ? 'bg-highlight text-black' : 'bg-muted text-muted-foreground'
|
||||
} overflow-hidden`}
|
||||
>
|
||||
{number}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Color Circle (Optional) */}
|
||||
{/* add some space if there is not segment index */}
|
||||
{number === null && <div className="ml-1 h-7"></div>}
|
||||
{colorHex && (
|
||||
<div className="flex h-7 w-5 items-center justify-center">
|
||||
<span
|
||||
|
||||
@@ -12,6 +12,7 @@ interface DoubleSliderProps {
|
||||
defaultValue?: [number, number];
|
||||
onValueChange?: (value: [number, number]) => void;
|
||||
showNumberInputs?: boolean;
|
||||
lockMode?: boolean;
|
||||
}
|
||||
|
||||
const DoubleSlider = React.forwardRef<HTMLDivElement, DoubleSliderProps>(
|
||||
@@ -24,10 +25,19 @@ const DoubleSlider = React.forwardRef<HTMLDivElement, DoubleSliderProps>(
|
||||
step = 1,
|
||||
defaultValue = [min, max],
|
||||
showNumberInputs = false,
|
||||
lockMode = false,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [value, setValue] = React.useState<[number, number]>(defaultValue);
|
||||
const trackRef = React.useRef<HTMLDivElement>(null);
|
||||
const dragStateRef = React.useRef<{
|
||||
startX: number;
|
||||
startValue: [number, number];
|
||||
rangeWidth: number;
|
||||
trackLeft: number;
|
||||
trackWidth: number;
|
||||
} | null>(null);
|
||||
|
||||
const prevDefaultValueRef = React.useRef<[number, number] | null>(null);
|
||||
|
||||
@@ -50,8 +60,172 @@ const DoubleSlider = React.forwardRef<HTMLDivElement, DoubleSliderProps>(
|
||||
return Math.round(num * inverse) / inverse;
|
||||
};
|
||||
|
||||
const handleRangePointerDown = (event: React.PointerEvent) => {
|
||||
if (!lockMode) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
const rect = trackRef.current!.getBoundingClientRect();
|
||||
dragStateRef.current = {
|
||||
startX: event.clientX,
|
||||
startValue: [...value] as [number, number],
|
||||
rangeWidth: value[1] - value[0],
|
||||
trackLeft: rect.left,
|
||||
trackWidth: rect.width,
|
||||
};
|
||||
window.addEventListener('pointermove', handleRangePointerMove);
|
||||
window.addEventListener('pointerup', handleRangePointerUp, { once: true });
|
||||
};
|
||||
|
||||
const handleRangePointerMove = (event: PointerEvent) => {
|
||||
const state = dragStateRef.current;
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
const { startX, startValue, rangeWidth, trackWidth } = state;
|
||||
const dxPx = event.clientX - startX;
|
||||
const pct = dxPx / trackWidth;
|
||||
const delta = pct * (max - min);
|
||||
|
||||
let newLeft = startValue[0] + delta;
|
||||
let newRight = newLeft + rangeWidth;
|
||||
|
||||
// clamp to bounds
|
||||
if (newLeft < min) {
|
||||
newLeft = min;
|
||||
newRight = min + rangeWidth;
|
||||
} else if (newRight > max) {
|
||||
newRight = max;
|
||||
newLeft = max - rangeWidth;
|
||||
}
|
||||
|
||||
const clampedLeft = roundToStep(newLeft);
|
||||
const clampedRight = roundToStep(newRight);
|
||||
setValue([clampedLeft, clampedRight]);
|
||||
onValueChange?.([clampedLeft, clampedRight]);
|
||||
};
|
||||
|
||||
const handleRangePointerUp = () => {
|
||||
dragStateRef.current = null;
|
||||
window.removeEventListener('pointermove', handleRangePointerMove);
|
||||
};
|
||||
|
||||
const handleSliderChange = React.useCallback(
|
||||
(newValue: number[]) => {
|
||||
// Default behavior (no lock mode)
|
||||
if (!lockMode) {
|
||||
const clampedValue: [number, number] = [
|
||||
roundToStep(Math.max(min, Math.min(newValue[0], max))),
|
||||
roundToStep(Math.min(max, Math.max(newValue[1], min))),
|
||||
];
|
||||
setValue(clampedValue);
|
||||
onValueChange?.(clampedValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Lock mode behavior
|
||||
// First, determine if this is a symmetric expansion/contraction or a range shift
|
||||
// by checking which thumb(s) moved
|
||||
const isLeftThumbMoved = newValue[0] !== value[0];
|
||||
const isRightThumbMoved = newValue[1] !== value[1];
|
||||
|
||||
// Case 1: Left thumb moved, right thumb needs to move symmetrically (opposite)
|
||||
if (isLeftThumbMoved && !isRightThumbMoved) {
|
||||
const delta = newValue[0] - value[0];
|
||||
const centerPoint = (value[0] + value[1]) / 2;
|
||||
|
||||
// Symmetric movement: move right thumb in opposite direction
|
||||
const newRight = value[1] - delta;
|
||||
|
||||
// Ensure values stay within bounds
|
||||
const clampedLeft = roundToStep(Math.max(min, Math.min(newValue[0], max)));
|
||||
const clampedRight = roundToStep(Math.min(max, Math.max(newRight, min)));
|
||||
|
||||
// Special case: If right would go out of bounds, adjust left too to maintain center
|
||||
if (newRight !== clampedRight) {
|
||||
// Calculate new delta given the clamped right value
|
||||
const adjustedDelta = value[1] - clampedRight;
|
||||
// Apply same delta to left but in opposite direction
|
||||
const adjustedLeft = value[0] + adjustedDelta;
|
||||
const finalClampedLeft = roundToStep(Math.max(min, Math.min(adjustedLeft, max)));
|
||||
|
||||
const finalValues: [number, number] = [finalClampedLeft, clampedRight];
|
||||
setValue(finalValues);
|
||||
onValueChange?.(finalValues);
|
||||
return;
|
||||
}
|
||||
|
||||
const finalValues: [number, number] = [clampedLeft, clampedRight];
|
||||
setValue(finalValues);
|
||||
onValueChange?.(finalValues);
|
||||
return;
|
||||
}
|
||||
|
||||
// Case 2: Right thumb moved, left thumb needs to move symmetrically (opposite)
|
||||
if (!isLeftThumbMoved && isRightThumbMoved) {
|
||||
const delta = newValue[1] - value[1];
|
||||
const centerPoint = (value[0] + value[1]) / 2;
|
||||
|
||||
// Symmetric movement: move left thumb in opposite direction
|
||||
const newLeft = value[0] - delta;
|
||||
|
||||
// Ensure values stay within bounds
|
||||
const clampedRight = roundToStep(Math.min(max, Math.max(newValue[1], min)));
|
||||
const clampedLeft = roundToStep(Math.max(min, Math.min(newLeft, max)));
|
||||
|
||||
// Special case: If left would go out of bounds, adjust right too to maintain center
|
||||
if (newLeft !== clampedLeft) {
|
||||
// Calculate new delta given the clamped left value
|
||||
const adjustedDelta = value[0] - clampedLeft;
|
||||
// Apply same delta to right but in opposite direction
|
||||
const adjustedRight = value[1] + adjustedDelta;
|
||||
const finalClampedRight = roundToStep(Math.min(max, Math.max(adjustedRight, min)));
|
||||
|
||||
const finalValues: [number, number] = [clampedLeft, finalClampedRight];
|
||||
setValue(finalValues);
|
||||
onValueChange?.(finalValues);
|
||||
return;
|
||||
}
|
||||
|
||||
const finalValues: [number, number] = [clampedLeft, clampedRight];
|
||||
setValue(finalValues);
|
||||
onValueChange?.(finalValues);
|
||||
return;
|
||||
}
|
||||
|
||||
// Case 3: Both thumbs moved (range shift) - maintain the same distance between thumbs
|
||||
if (isLeftThumbMoved && isRightThumbMoved) {
|
||||
const rangeWidth = value[1] - value[0];
|
||||
|
||||
// Calculate how much the left thumb moved
|
||||
const leftDelta = newValue[0] - value[0];
|
||||
|
||||
// New values maintaining the same range width
|
||||
let newLeft = newValue[0];
|
||||
let newRight = newLeft + rangeWidth;
|
||||
|
||||
// Handle bounds checking
|
||||
if (newRight > max) {
|
||||
newRight = max;
|
||||
newLeft = newRight - rangeWidth;
|
||||
}
|
||||
|
||||
if (newLeft < min) {
|
||||
newLeft = min;
|
||||
newRight = newLeft + rangeWidth;
|
||||
}
|
||||
|
||||
const clampedValues: [number, number] = [
|
||||
roundToStep(Math.max(min, Math.min(newLeft, max))),
|
||||
roundToStep(Math.min(max, Math.max(newRight, min))),
|
||||
];
|
||||
|
||||
setValue(clampedValues);
|
||||
onValueChange?.(clampedValues);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback to default behavior
|
||||
const clampedValue: [number, number] = [
|
||||
roundToStep(Math.max(min, Math.min(newValue[0], max))),
|
||||
roundToStep(Math.min(max, Math.max(newValue[1], min))),
|
||||
@@ -59,25 +233,86 @@ const DoubleSlider = React.forwardRef<HTMLDivElement, DoubleSliderProps>(
|
||||
setValue(clampedValue);
|
||||
onValueChange?.(clampedValue);
|
||||
},
|
||||
[min, max, onValueChange, step]
|
||||
[min, max, onValueChange, step, value, lockMode]
|
||||
);
|
||||
|
||||
const handleInputChange = React.useCallback(
|
||||
(index: 0 | 1, inputValue: string) => {
|
||||
const newValue = parseFloat(inputValue);
|
||||
if (!isNaN(newValue)) {
|
||||
const clampedValue: [number, number] = [...value];
|
||||
clampedValue[index] = roundToStep(Math.min(Math.max(newValue, min), max));
|
||||
if (index === 0 && clampedValue[0] > clampedValue[1]) {
|
||||
clampedValue[1] = clampedValue[0];
|
||||
} else if (index === 1 && clampedValue[1] < clampedValue[0]) {
|
||||
clampedValue[0] = clampedValue[1];
|
||||
// Default behavior (no lock mode)
|
||||
if (!lockMode) {
|
||||
const clampedValue: [number, number] = [...value];
|
||||
clampedValue[index] = roundToStep(Math.min(Math.max(newValue, min), max));
|
||||
if (index === 0 && clampedValue[0] > clampedValue[1]) {
|
||||
clampedValue[1] = clampedValue[0];
|
||||
} else if (index === 1 && clampedValue[1] < clampedValue[0]) {
|
||||
clampedValue[0] = clampedValue[1];
|
||||
}
|
||||
setValue(clampedValue);
|
||||
onValueChange?.(clampedValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Lock mode behavior
|
||||
const centerPoint = (value[0] + value[1]) / 2;
|
||||
const rangeWidth = value[1] - value[0];
|
||||
const clampedValue: [number, number] = [...value];
|
||||
|
||||
// Calculate new value with constraints
|
||||
const boundedNewValue = roundToStep(Math.min(Math.max(newValue, min), max));
|
||||
|
||||
if (index === 0) {
|
||||
// Left thumb changed
|
||||
const delta = boundedNewValue - value[0];
|
||||
|
||||
// Symmetric change: move right thumb in opposite direction
|
||||
const newRight = value[1] - delta;
|
||||
const boundedNewRight = roundToStep(Math.min(Math.max(newRight, min), max));
|
||||
|
||||
// If right would go out of bounds, adjust left too
|
||||
if (newRight !== boundedNewRight) {
|
||||
// Adjust to maintain the same width but respect bounds
|
||||
if (boundedNewRight === max) {
|
||||
clampedValue[0] = roundToStep(Math.max(max - rangeWidth, min));
|
||||
clampedValue[1] = max;
|
||||
} else if (boundedNewRight === min) {
|
||||
clampedValue[0] = min;
|
||||
clampedValue[1] = roundToStep(Math.min(min + rangeWidth, max));
|
||||
}
|
||||
} else {
|
||||
clampedValue[0] = boundedNewValue;
|
||||
clampedValue[1] = boundedNewRight;
|
||||
}
|
||||
} else {
|
||||
// Right thumb changed
|
||||
const delta = boundedNewValue - value[1];
|
||||
|
||||
// Symmetric change: move left thumb in opposite direction
|
||||
const newLeft = value[0] - delta;
|
||||
const boundedNewLeft = roundToStep(Math.min(Math.max(newLeft, min), max));
|
||||
|
||||
// If left would go out of bounds, adjust right too
|
||||
if (newLeft !== boundedNewLeft) {
|
||||
// Adjust to maintain the same width but respect bounds
|
||||
if (boundedNewLeft === min) {
|
||||
clampedValue[0] = min;
|
||||
clampedValue[1] = roundToStep(Math.min(min + rangeWidth, max));
|
||||
} else if (boundedNewLeft === max) {
|
||||
clampedValue[0] = roundToStep(Math.max(max - rangeWidth, min));
|
||||
clampedValue[1] = max;
|
||||
}
|
||||
} else {
|
||||
clampedValue[0] = boundedNewLeft;
|
||||
clampedValue[1] = boundedNewValue;
|
||||
}
|
||||
}
|
||||
|
||||
setValue(clampedValue);
|
||||
onValueChange?.(clampedValue);
|
||||
}
|
||||
},
|
||||
[value, min, max, onValueChange, step]
|
||||
[value, min, max, onValueChange, step, lockMode]
|
||||
);
|
||||
|
||||
const formatValue = (val: number) => {
|
||||
@@ -109,8 +344,14 @@ const DoubleSlider = React.forwardRef<HTMLDivElement, DoubleSliderProps>(
|
||||
value={value}
|
||||
onValueChange={handleSliderChange}
|
||||
>
|
||||
<SliderPrimitive.Track className="bg-primary/30 relative h-1 w-full grow overflow-hidden rounded-full">
|
||||
<SliderPrimitive.Range className="bg-primary absolute h-full" />
|
||||
<SliderPrimitive.Track
|
||||
ref={trackRef}
|
||||
className="bg-primary/30 relative h-1 w-full grow overflow-hidden rounded-full"
|
||||
>
|
||||
<SliderPrimitive.Range
|
||||
className={cn('bg-primary absolute h-full', lockMode && 'cursor-grab')}
|
||||
onPointerDown={handleRangePointerDown}
|
||||
/>
|
||||
</SliderPrimitive.Track>
|
||||
<SliderPrimitive.Thumb className="border-background bg-primary focus-visible:ring-ring block h-4 w-4 rounded-full border-2 shadow transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50" />
|
||||
<SliderPrimitive.Thumb className="border-background bg-primary focus-visible:ring-ring block h-4 w-4 rounded-full border-2 shadow transition-colors focus-visible:outline-none focus-visible:ring-1 disabled:pointer-events-none disabled:opacity-50" />
|
||||
|
||||
@@ -75,6 +75,10 @@ import IconTransferring from './Sources/IconTransferring';
|
||||
import Alert from './Sources/Alert';
|
||||
import AlertOutline from './Sources/AlertOutline';
|
||||
import Clipboard from './Sources/Clipboard';
|
||||
import OrientationSwitch from './Sources/OrientationSwitch';
|
||||
import LayerBackground from './Sources/LayerBackground';
|
||||
import LayerForeground from './Sources/LayerForeground';
|
||||
import LayerSegmentation from './Sources/LayerSegmentation';
|
||||
import {
|
||||
Tool3DRotate,
|
||||
ToolAngle,
|
||||
@@ -378,6 +382,10 @@ export const Icons = {
|
||||
/>
|
||||
),
|
||||
// Icons
|
||||
LayerBackground,
|
||||
LayerForeground,
|
||||
LayerSegmentation,
|
||||
OrientationSwitch,
|
||||
Clipboard,
|
||||
ActionNewDialog,
|
||||
GroupLayers,
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const LayerBackground = (props: IconProps) => (
|
||||
<svg
|
||||
width="29"
|
||||
height="28"
|
||||
viewBox="0 0 29 28"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M20.0801 8.92383C22.013 8.92383 23.5799 10.4909 23.5801 12.4238V19.0801C23.5801 21.0131 22.0131 22.5801 20.0801 22.5801H13.4238C11.4908 22.5801 9.92383 21.0131 9.92383 19.0801V16.6562H14.6562C16.3131 16.6562 17.6562 15.3131 17.6562 13.6562V8.92383H20.0801Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<rect
|
||||
x="5.5"
|
||||
y="4.5"
|
||||
width="11.6565"
|
||||
height="11.6565"
|
||||
rx="2.5"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default LayerBackground;
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const LayerForeground = (props: IconProps) => (
|
||||
<svg
|
||||
width="28"
|
||||
height="28"
|
||||
viewBox="0 0 28 28"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<rect
|
||||
x="10.3999"
|
||||
y="9.3999"
|
||||
width="12.6001"
|
||||
height="12.6001"
|
||||
rx="3"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
<rect
|
||||
x="5.5"
|
||||
y="4.5"
|
||||
width="11.6001"
|
||||
height="11.6001"
|
||||
rx="2.5"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default LayerForeground;
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const LayerSegmentation = (props: IconProps) => (
|
||||
<svg
|
||||
width="28"
|
||||
height="28"
|
||||
viewBox="0 0 28 28"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M7 9.16547L9.16546 7.00002M7 12.4512L12.4999 6.95129M7 15.7369L15.7369 6.99999M7.18447 18.8381L18.8381 7.1845M8.77085 20.5375L20.4043 8.90397M11.794 20.8L20.8 11.794M15.0797 20.8L20.8 15.0797M18.4323 20.7333L20.7332 18.4324M10 20.8H17.8C19.4569 20.8 20.8 19.4569 20.8 17.8V10C20.8 8.34315 19.4569 7.00001 17.8 7.00001H10C8.34315 7.00001 7 8.34316 7 10V17.8C7 19.4569 8.34315 20.8 10 20.8Z"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default LayerSegmentation;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const OrientationSwitch = (props: IconProps) => (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M8.07778 16.4182L9.96563 18.8288L7.30469 20.4557"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.25"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M20.0917 14C20.3502 14.1669 20.5669 14.3909 20.7252 14.6547C20.8835 14.9186 20.9792 15.2152 21.0048 15.5218C21.0048 17.3123 17.4909 18.7938 13.0151 18.946"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.25"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.96782 18.828C6.23931 18.4354 3.5 17.1038 3.5 15.5218C3.52464 15.2179 3.61841 14.9236 3.77416 14.6614C3.9299 14.3992 4.1435 14.1761 4.39865 14.0091"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.25"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M9.02539 14.1079C8.52393 14.1079 8.2002 13.8159 8.2002 13.3525C8.2002 13.2256 8.23193 13.0479 8.30811 12.8511L10.9678 5.62109C11.1899 5.01172 11.5581 4.73242 12.1548 4.73242C12.7578 4.73242 13.126 4.99902 13.3545 5.61475L16.0205 12.8511C16.0967 13.0605 16.1284 13.2065 16.1284 13.3525C16.1284 13.7969 15.7856 14.1079 15.3096 14.1079C14.8652 14.1079 14.6177 13.9048 14.4717 13.416L13.8687 11.6641H10.4473L9.84424 13.4033C9.69189 13.8984 9.45068 14.1079 9.02539 14.1079ZM10.8345 10.3691H13.4688L12.1675 6.45898H12.123L10.8345 10.3691Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default OrientationSwitch;
|
||||
@@ -29,6 +29,7 @@ interface NumericMetaContextValue {
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
lockMode?: boolean;
|
||||
}
|
||||
|
||||
const NumericMetaContext = createContext<NumericMetaContextValue | null>(null);
|
||||
@@ -47,6 +48,7 @@ interface NumericMetaContainerProps {
|
||||
max?: number;
|
||||
step?: number;
|
||||
className?: string;
|
||||
lockMode?: boolean; // Add lock mode prop for doubleRange
|
||||
}
|
||||
|
||||
function NumericMetaContainer({
|
||||
@@ -60,6 +62,7 @@ function NumericMetaContainer({
|
||||
max = 100,
|
||||
step = 1,
|
||||
className,
|
||||
lockMode = false,
|
||||
children,
|
||||
}: PropsWithChildren<NumericMetaContainerProps>) {
|
||||
// Calculate default values based on min and max
|
||||
@@ -115,6 +118,7 @@ function NumericMetaContainer({
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
lockMode,
|
||||
}}
|
||||
>
|
||||
<div className={cn('flex flex-col', className)}>{children}</div>
|
||||
@@ -236,7 +240,7 @@ function DoubleRange({ showNumberInputs, className }: DoubleRangeProps) {
|
||||
throw new Error('DoubleRange must be used inside <Numeric.Container>.');
|
||||
}
|
||||
|
||||
const { mode, doubleValue, setDoubleValue, min, max, step } = ctx;
|
||||
const { mode, doubleValue, setDoubleValue, min, max, step, lockMode } = ctx;
|
||||
|
||||
const handleSliderChange = useCallback(
|
||||
(values: [number, number]) => {
|
||||
@@ -258,6 +262,7 @@ function DoubleRange({ showNumberInputs, className }: DoubleRangeProps) {
|
||||
defaultValue={doubleValue}
|
||||
onValueChange={handleSliderChange}
|
||||
showNumberInputs={showNumberInputs}
|
||||
lockMode={lockMode}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea
|
||||
onSegmentEdit,
|
||||
onSegmentDelete,
|
||||
data,
|
||||
showSegmentIndex = true,
|
||||
} = useSegmentationTableContext('SegmentationSegments');
|
||||
|
||||
// Try to get segmentation data from expanded context first, then fall back to table context
|
||||
@@ -76,7 +77,7 @@ export const SegmentationSegments = ({ children = null }: { children?: React.Rea
|
||||
const DataRowComponent = (
|
||||
<DataRow
|
||||
key={segmentIndex}
|
||||
number={segmentIndex}
|
||||
number={showSegmentIndex ? segmentIndex : null}
|
||||
title={label}
|
||||
// details={displayText}
|
||||
description={displayText}
|
||||
|
||||
+1
@@ -62,6 +62,7 @@ export interface SegmentationTableContextType {
|
||||
activeSegmentation?: Segmentation;
|
||||
disableEditing: boolean;
|
||||
showAddSegment?: boolean;
|
||||
showSegmentIndex?: boolean;
|
||||
renderInactiveSegmentations?: boolean;
|
||||
|
||||
// Function handlers
|
||||
|
||||
@@ -17,7 +17,7 @@ const SelectTrigger = React.forwardRef<
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'border-input text-foreground ring-offset-background placeholder:text-muted-foreground focus:ring-ring [&>span]:line-clamp-1 hover:bg-primary/10 flex h-7 w-full items-center justify-between whitespace-nowrap rounded border bg-transparent px-2 py-2 text-base shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50',
|
||||
'border-input text-foreground ring-offset-background placeholder:text-muted-foreground focus:ring-ring hover:bg-primary/10 flex h-7 w-full min-w-0 items-center justify-between rounded border bg-transparent px-2 py-2 text-base shadow-sm focus:outline-none focus:ring-1 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:truncate',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -64,4 +64,4 @@ ViewportActionCorners.propTypes = {
|
||||
cornerComponents: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export { ViewportActionCorners };
|
||||
export { ViewportActionCorners };
|
||||
@@ -124,6 +124,7 @@ interface ViewportGridApi {
|
||||
getActiveViewportOptionByKey: (key: string) => any;
|
||||
setViewportGridSizeChanged: (props: any) => void;
|
||||
publishViewportsReady: () => void;
|
||||
getDisplaySetsUIDsForViewport: (viewportId: string) => string[];
|
||||
}
|
||||
|
||||
// Update the context type
|
||||
@@ -539,6 +540,7 @@ export function ViewportGridProvider({ children, service }: ViewportGridProvider
|
||||
setViewportGridSizeChanged: props => service.setViewportGridSizeChanged(props),
|
||||
publishViewportsReady: () => service.publishViewportsReady(),
|
||||
getLayoutOptionsFromState: state => service.getLayoutOptionsFromState(state),
|
||||
getDisplaySetsUIDsForViewport: viewportId => service.getDisplaySetsUIDsForViewport(viewportId),
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { ViewportActionCornersLocations } from '../components/Viewport/ViewportActionCorners';
|
||||
|
||||
export interface ViewportActionCornersComponentInfo {
|
||||
id: string;
|
||||
component: ReactNode;
|
||||
}
|
||||
|
||||
export interface ViewportActionCornersProps {
|
||||
cornerComponents: Record<ViewportActionCornersLocations, ViewportActionCornersComponentInfo[]>;
|
||||
visibleItemsPerCorner?: number;
|
||||
isActiveViewport: boolean;
|
||||
}
|
||||
Reference in new issue
Block a user