88 */
99
1010import classNames from 'classnames' ;
11- import React , { useCallback , useEffect , useRef , useState } from 'react' ;
11+ import React , { useCallback , useEffect , useMemo , useRef , useState } from 'react' ;
1212import { Subscription , of } from 'rxjs' ;
1313
1414import { useSortable } from '@dnd-kit/sortable' ;
@@ -18,7 +18,7 @@ import {
1818 EuiFormControlLayout ,
1919 EuiFormLabel ,
2020 EuiFormRow ,
21- EuiToolTip ,
21+ EuiIcon ,
2222 type UseEuiTheme ,
2323} from '@elastic/eui' ;
2424import { css } from '@emotion/react' ;
@@ -27,12 +27,17 @@ import { useMemoCss } from '@kbn/css-utils/public/use_memo_css';
2727import { EmbeddableRenderer , type DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public' ;
2828import { i18n } from '@kbn/i18n' ;
2929import { useBatchedPublishingSubjects , type PublishingSubject } from '@kbn/presentation-publishing' ;
30-
30+ import { useIndicateRelatedPanelsSelector } from '@kbn/presentation-util' ;
31+ import {
32+ apiPublishesTooltipLabel ,
33+ type PublishesTooltipLabel ,
34+ } from '@kbn/controls-schemas/src/types' ;
3135import type { ControlsRendererParentApi } from '../types' ;
3236import { apiPublishesLabel } from '../utils' ;
3337import { controlWidthStyles } from './control_panel.styles' ;
3438import { DragHandle } from './drag_handle' ;
3539import { FloatingActions } from './floating_actions' ;
40+ import { ControlLabelTooltip } from './control_label_tooltip' ;
3641
3742export const ControlPanel = ( {
3843 parentApi,
@@ -45,7 +50,9 @@ export const ControlPanel = ({
4550} ) => {
4651 const styles = useMemoCss ( controlPanelStyles ) ;
4752
48- const [ api , setApi ] = useState < ( DefaultEmbeddableApi & Partial < HasCustomPrepend > ) | null > ( null ) ;
53+ const [ api , setApi ] = useState <
54+ ( DefaultEmbeddableApi & Partial < HasCustomPrepend > & Partial < PublishesTooltipLabel > ) | null
55+ > ( null ) ;
4956
5057 const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable ( {
5158 id,
@@ -57,9 +64,17 @@ export const ControlPanel = ({
5764 ) ;
5865
5966 const [ panelLabel , setPanelLabel ] = useState < string | undefined > ( ) ;
67+ const [ panelTooltipLabel , setPanelTooltipLabel ] = useState < string | undefined > ( ) ;
6068
6169 const prependWrapperRef = useRef < HTMLDivElement > ( null ) ;
6270
71+ const {
72+ canIndicateRelatedPanels,
73+ isIndicatingRelatedPanels,
74+ onToggleIndicateRelatedPanels,
75+ numberOfRelatedPanels,
76+ } = useIndicateRelatedPanelsSelector ( api ) ;
77+
6378 useEffect ( ( ) => {
6479 if ( ! api ) return ;
6580
@@ -72,6 +87,13 @@ export const ControlPanel = ({
7287 } )
7388 ) ;
7489 }
90+ if ( apiPublishesTooltipLabel ( api ) ) {
91+ subscriptions . add (
92+ api . tooltipLabel$ . subscribe ( ( result ) => {
93+ setPanelTooltipLabel ( result ) ;
94+ } )
95+ ) ;
96+ }
7597 return ( ) => {
7698 subscriptions . unsubscribe ( ) ;
7799 } ;
@@ -94,6 +116,45 @@ export const ControlPanel = ({
94116 ) ;
95117
96118 const isEditable = viewMode === 'edit' ;
119+ const enableIndicateRelatedPanels = Boolean ( canIndicateRelatedPanels && numberOfRelatedPanels ) ;
120+ const handleToggleIndicateRelated = useCallback (
121+ ( ) => ( enableIndicateRelatedPanels ? onToggleIndicateRelatedPanels ( ) : null ) ,
122+ [ enableIndicateRelatedPanels , onToggleIndicateRelatedPanels ]
123+ ) ;
124+
125+ const controlLabel = (
126+ < ControlLabelTooltip
127+ canIndicateRelatedPanels = { canIndicateRelatedPanels }
128+ isIndicatingRelatedPanels = { isIndicatingRelatedPanels }
129+ numberOfRelatedPanels = { numberOfRelatedPanels }
130+ panelLabel = { panelLabel }
131+ panelTooltipLabel = { panelTooltipLabel }
132+ anchorProps = { { className : 'eui-textTruncate' , css : styles . tooltipStyles } }
133+ >
134+ < EuiFormLabel
135+ className = "controlPanel--label"
136+ onClick = { handleToggleIndicateRelated }
137+ onKeyDown = { ( e ) =>
138+ e . key === 'Enter' || e . key === ' ' ? handleToggleIndicateRelated ( ) : null
139+ }
140+ role = { enableIndicateRelatedPanels ? 'button' : undefined }
141+ tabIndex = { enableIndicateRelatedPanels ? 0 : undefined }
142+ >
143+ < span css = { styles . prependWrapperStyles } ref = { prependWrapperRef } >
144+ { panelLabel } { ' ' }
145+ { canIndicateRelatedPanels && numberOfRelatedPanels === 0 && (
146+ < EuiIcon
147+ aria-label = { i18n . translate ( 'controls.controlGroup.warningNoRelatedPanels' , {
148+ defaultMessage : 'Warning: No related panels' ,
149+ } ) }
150+ type = "warning"
151+ />
152+ ) }
153+ </ span >
154+ </ EuiFormLabel >
155+ </ ControlLabelTooltip >
156+ ) ;
157+
97158 return (
98159 < EuiFlexItem
99160 component = "li"
@@ -128,6 +189,7 @@ export const ControlPanel = ({
128189 fullWidth
129190 className = { classNames ( 'controlFrame__formControlLayout' , {
130191 'controlFrame__formControlLayout--edit' : isEditable ,
192+ 'controlFrame__formControlLayout--selected' : isIndicatingRelatedPanels ,
131193 type,
132194 } ) }
133195 css = { styles . formControl }
@@ -145,24 +207,19 @@ export const ControlPanel = ({
145207 < api . CustomPrependComponent />
146208 </ >
147209 ) : (
148- < DragHandle
149- isEditable = { isEditable }
150- controlTitle = { panelLabel }
151- className = "controlFrame__dragHandle"
152- { ...attributes }
153- { ...listeners }
154- >
155- < EuiToolTip
156- content = { panelLabel }
157- anchorProps = { { className : 'eui-textTruncate' , css : styles . tooltipStyles } }
210+ < >
211+ < DragHandle
212+ isEditable = { isEditable }
213+ controlTitle = { panelLabel }
214+ className = "controlFrame__dragHandle"
215+ highContrast = { isIndicatingRelatedPanels }
216+ { ...attributes }
217+ { ...listeners }
158218 >
159- < EuiFormLabel className = "controlPanel--label" >
160- < span css = { styles . prependWrapperStyles } ref = { prependWrapperRef } >
161- { panelLabel }
162- </ span >
163- </ EuiFormLabel >
164- </ EuiToolTip >
165- </ DragHandle >
219+ { ! enableIndicateRelatedPanels && controlLabel }
220+ </ DragHandle >
221+ { enableIndicateRelatedPanels && controlLabel }
222+ </ >
166223 ) }
167224 </ >
168225 }
@@ -217,10 +274,18 @@ const controlPanelStyles = {
217274 paddingInlineStart : `${ euiTheme . size . xxs } !important` , // corrected syntax for skinny icon
218275 } ,
219276 } ,
277+ '&.controlFrame__formControlLayout--selected' : {
278+ '.euiFormControlLayout__prepend' : {
279+ backgroundColor : euiTheme . colors . vis . euiColorVis0 ,
280+ } ,
281+ } ,
220282 '.controlPanel--label' : {
221283 padding : '0 !important' ,
222284 height : '100%' ,
223285 maxWidth : '100%' ,
286+ '&[role="button"]' : {
287+ cursor : 'pointer' ,
288+ } ,
224289 } ,
225290 } ) ,
226291} ;
0 commit comments