@@ -200,3 +200,115 @@ export const DragOverlayChip: FC<FieldChipProps> = (props): ReactElement => {
200200 </ span >
201201 ) ;
202202} ;
203+
204+ // ---------------------------------------------------------------------------
205+ // Synthetic (fx) measure chip — sortable within the Values zone.
206+ // ---------------------------------------------------------------------------
207+
208+ export interface SyntheticChipDisplayProps {
209+ syntheticId : string ;
210+ label : string ;
211+ testId : string ;
212+ disabled ?: boolean ;
213+ onRemove ?: ( syntheticId : string ) => void ;
214+ showDragHandle ?: boolean ;
215+ }
216+
217+ function SyntheticChipContent ( {
218+ syntheticId,
219+ label,
220+ testId,
221+ disabled,
222+ onRemove,
223+ showDragHandle,
224+ } : SyntheticChipDisplayProps ) : ReactElement {
225+ return (
226+ < >
227+ { showDragHandle && < GripDotsIcon /> }
228+ < span className = { styles . aggChipIcon } > fx</ span >
229+ < span
230+ className = { styles . chipLabelText }
231+ data-testid = { `${ testId } -synthetic-label-${ syntheticId } ` }
232+ >
233+ < span className = { styles . chipPrimaryText } > { label } </ span >
234+ </ span >
235+ { ! disabled && onRemove && (
236+ < button
237+ type = "button"
238+ className = { styles . chipRemove }
239+ onMouseDown = { ( e ) => e . stopPropagation ( ) }
240+ onClick = { ( e ) => {
241+ e . stopPropagation ( ) ;
242+ onRemove ( syntheticId ) ;
243+ } }
244+ aria-label = { `Remove ${ label } ` }
245+ data-testid = { `${ testId } -synthetic-remove-${ syntheticId } ` }
246+ >
247+ ×
248+ </ button >
249+ ) }
250+ </ >
251+ ) ;
252+ }
253+
254+ export interface SortableSyntheticChipProps extends SyntheticChipDisplayProps {
255+ id : string ;
256+ }
257+
258+ export const SortableSyntheticChip : FC < SortableSyntheticChipProps > = ( {
259+ id,
260+ syntheticId,
261+ label,
262+ testId,
263+ disabled,
264+ onRemove,
265+ } ) : ReactElement => {
266+ const {
267+ attributes,
268+ listeners,
269+ setNodeRef,
270+ transform,
271+ transition,
272+ isDragging,
273+ } = useSortable ( {
274+ id,
275+ disabled,
276+ data : { type : "synthetic" , syntheticId } ,
277+ } ) ;
278+
279+ const style : CSSProperties = {
280+ transform : CSS . Transform . toString ( transform ) ,
281+ transition,
282+ opacity : isDragging ? 0.3 : undefined ,
283+ } ;
284+
285+ return (
286+ < span
287+ ref = { setNodeRef }
288+ className = { `${ styles . chip } ${ isDragging ? styles . chipDragging : "" } ` }
289+ style = { style }
290+ { ...attributes }
291+ { ...( disabled ? { } : listeners ) }
292+ data-testid = { `${ testId } -synthetic-${ syntheticId } ` }
293+ >
294+ < SyntheticChipContent
295+ syntheticId = { syntheticId }
296+ label = { label }
297+ testId = { testId }
298+ disabled = { disabled }
299+ onRemove = { onRemove }
300+ showDragHandle = { ! disabled }
301+ />
302+ </ span >
303+ ) ;
304+ } ;
305+
306+ export const SyntheticDragOverlayChip : FC < SyntheticChipDisplayProps > = (
307+ props ,
308+ ) : ReactElement => {
309+ return (
310+ < span className = { `${ styles . chip } ${ styles . chipOverlay } ` } >
311+ < SyntheticChipContent { ...props } showDragHandle = { true } />
312+ </ span >
313+ ) ;
314+ } ;
0 commit comments