@iobroker/dm-gui-components 10.0.22 → 10.0.23

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.
package/README.md CHANGED
@@ -197,6 +197,9 @@ const indicator = {
197
197
  -->
198
198
 
199
199
  ## Changelog
200
+ ### 10.0.23 (2026-09-21)
201
+ - (@BenAhrdt) Supported explicit line breaks in status indicator tooltips
202
+
200
203
  ### 10.0.22 (2026-09-18)
201
204
  - (@GermanBluefox) Updated packages
202
205
  - (@GermanBluefox) Renamed `Config manager` to `Konfig-Manager` (DE)
@@ -110,7 +110,7 @@ export default function StatusIndicator(props) {
110
110
  if (!tooltip) {
111
111
  return element;
112
112
  }
113
- return (React.createElement(Tooltip, { title: tooltip, slotProps: { popper: { sx: styles.tooltip } } },
113
+ return (React.createElement(Tooltip, { title: React.createElement("span", { style: { whiteSpace: 'pre-line' } }, tooltip), slotProps: { popper: { sx: styles.tooltip } } },
114
114
  React.createElement("span", { style: { display: 'inline-flex' } }, element)));
115
115
  }
116
116
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"StatusIndicator.js","sourceRoot":"./src/","sources":["StatusIndicator.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { IconButton, Tooltip } from '@mui/material';\n\nimport type { IobTheme } from '@iobroker/gui-components';\n\nimport { useStateOrObject } from './hooks';\nimport type { StatusIndicator as StatusIndicatorConfig, StatusIndicatorLevel } from './protocol/api';\nimport type { StateOrObjectHandler } from './StateOrObjectHandler';\nimport { getIndicatorColor, getTranslation, renderIcon } from './Utils';\n\nconst styles: Record<string, React.CSSProperties> = {\n tooltip: {\n pointerEvents: 'none',\n },\n content: {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n lineHeight: 1,\n },\n text: {\n fontSize: 'small',\n margin: 0,\n whiteSpace: 'nowrap',\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 8,\n },\n};\n\n/**\n * Find the first matching level for the given value.\n *\n * A level matches if its `value` equals the current value, if the numeric value lies within\n * `min`/`max` (both inclusive) or if the level defines no condition at all (catch-all).\n */\nfunction findLevel(\n levels: StatusIndicatorLevel[],\n value: string | number | boolean | undefined,\n): StatusIndicatorLevel | undefined {\n for (const level of levels) {\n if (level.value !== undefined) {\n if (level.value === value) {\n return level;\n }\n continue;\n }\n if (level.min !== undefined || level.max !== undefined) {\n if (typeof value !== 'number') {\n continue;\n }\n if (level.min !== undefined && value < level.min) {\n continue;\n }\n if (level.max !== undefined && value > level.max) {\n continue;\n }\n return level;\n }\n // no condition => catch-all\n return level;\n }\n\n return undefined;\n}\n\ninterface StatusIndicatorProps {\n indicator: StatusIndicatorConfig;\n theme: IobTheme;\n stateOrObjectHandler: StateOrObjectHandler;\n /** Called when the indicator is clicked. If not provided, the indicator is not clickable */\n onClick?: () => void;\n /** If the referenced action opens a URL instead of calling the backend */\n url?: string;\n disabled?: boolean;\n /** Color used if the indicator does not define one itself (e.g. white in the toolbar) */\n defaultColor?: string;\n}\n\n/**\n * A single custom status indicator.\n *\n * Every visual property may be bound to a state or an object, so the indicator follows its value\n * live. The optional `levels` list maps value ranges to icon, color and text.\n */\nexport default function StatusIndicator(props: StatusIndicatorProps): React.JSX.Element | null {\n const { indicator, stateOrObjectHandler } = props;\n\n const value = useStateOrObject<string | number | boolean>(indicator.value, stateOrObjectHandler);\n const icon = useStateOrObject<string>(indicator.icon, stateOrObjectHandler);\n const iconOn = useStateOrObject<string>(indicator.iconOn, stateOrObjectHandler);\n const color = useStateOrObject<string>(indicator.color, stateOrObjectHandler);\n const colorOn = useStateOrObject<string>(indicator.colorOn, stateOrObjectHandler);\n const text = useStateOrObject<ioBroker.StringOrTranslated>(indicator.text, stateOrObjectHandler);\n\n // An indicator without a value is a static icon and is always visible. With a value, it is hidden\n // while the value is \"empty\" - the numeric 0 counts as a value and stays visible.\n if (indicator.value !== undefined && indicator.hideIfEmpty !== false) {\n if (value === undefined || value === null || value === '' || value === false) {\n return null;\n }\n }\n\n const on = !!value;\n const level = indicator.levels ? findLevel(indicator.levels, value) : undefined;\n\n const iconName = level?.icon ?? (on ? (iconOn ?? icon) : icon);\n const colorName = level?.color ?? (on ? (colorOn ?? color) : color);\n const resolvedColor = getIndicatorColor(colorName, props.theme) || props.defaultColor;\n\n const levelText = level?.text ?? text;\n let label = levelText !== undefined ? getTranslation(levelText) : indicator.showValue ? String(value ?? '') : '';\n if (label && indicator.unit) {\n label += ` ${indicator.unit}`;\n }\n\n const tooltipSource = level?.tooltip ?? indicator.tooltip;\n const tooltip = tooltipSource ? getTranslation(tooltipSource) : '';\n\n // Only fall back to the \"question mark\" icon if the indicator shows nothing else at all\n const iconElement = iconName || !label ? renderIcon(iconName, resolvedColor) : null;\n\n const content = (\n <div style={styles.content}>\n {iconElement}\n {label ? <p style={{ ...styles.text, color: resolvedColor }}>{label}</p> : null}\n </div>\n );\n\n let element: React.JSX.Element;\n if (props.url) {\n element = (\n <IconButton\n size=\"small\"\n style={{ padding: 2, borderRadius: 4 }}\n href={props.url}\n target=\"_blank\"\n disabled={props.disabled}\n >\n {content}\n </IconButton>\n );\n } else if (props.onClick) {\n element = (\n <IconButton\n size=\"small\"\n style={{ padding: 2, borderRadius: 4 }}\n disabled={props.disabled}\n onClick={e => {\n // The card itself may react on clicks, so the event must not bubble\n e.stopPropagation();\n props.onClick?.();\n }}\n >\n {content}\n </IconButton>\n );\n } else {\n element = content;\n }\n\n if (!tooltip) {\n return element;\n }\n\n return (\n <Tooltip\n title={tooltip}\n slotProps={{ popper: { sx: styles.tooltip } }}\n >\n <span style={{ display: 'inline-flex' }}>{element}</span>\n </Tooltip>\n );\n}\n\ninterface StatusIndicatorsProps {\n indicators?: StatusIndicatorConfig[];\n theme: IobTheme;\n stateOrObjectHandler: StateOrObjectHandler;\n /**\n * Resolves the click handler for an indicator that references an action. Returns `undefined`\n * if the referenced action does not exist - the indicator stays a pure display element then.\n */\n resolveAction?: (actionId: string) => { onClick?: () => void; url?: string; disabled?: boolean } | undefined;\n disabled?: boolean;\n defaultColor?: string;\n style?: React.CSSProperties;\n /** Additional elements rendered in the same line (e.g. actions with `placement: 'status'`) */\n children?: React.ReactNode;\n}\n\n/**\n * The line of custom status indicators.\n *\n * The line wraps if it does not fit, so an arbitrary number of indicators can be shown without\n * cutting anything off.\n */\nexport function StatusIndicators(props: StatusIndicatorsProps): React.JSX.Element | null {\n const indicators = props.indicators?.length\n ? [...props.indicators].sort((a, b) => (a.order ?? 100) - (b.order ?? 100))\n : [];\n\n if (!indicators.length && !props.children) {\n return null;\n }\n\n return (\n <div style={{ ...styles.row, ...props.style }}>\n {indicators.map(indicator => {\n const action = indicator.actionId ? props.resolveAction?.(indicator.actionId) : undefined;\n\n return (\n <StatusIndicator\n key={indicator.id}\n indicator={indicator}\n theme={props.theme}\n stateOrObjectHandler={props.stateOrObjectHandler}\n onClick={action?.onClick}\n url={action?.url}\n disabled={props.disabled || action?.disabled}\n defaultColor={props.defaultColor}\n />\n );\n })}\n {props.children}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"StatusIndicator.js","sourceRoot":"./src/","sources":["StatusIndicator.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { IconButton, Tooltip } from '@mui/material';\n\nimport type { IobTheme } from '@iobroker/gui-components';\n\nimport { useStateOrObject } from './hooks';\nimport type { StatusIndicator as StatusIndicatorConfig, StatusIndicatorLevel } from './protocol/api';\nimport type { StateOrObjectHandler } from './StateOrObjectHandler';\nimport { getIndicatorColor, getTranslation, renderIcon } from './Utils';\n\nconst styles: Record<string, React.CSSProperties> = {\n tooltip: {\n pointerEvents: 'none',\n },\n content: {\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n lineHeight: 1,\n },\n text: {\n fontSize: 'small',\n margin: 0,\n whiteSpace: 'nowrap',\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 8,\n },\n};\n\n/**\n * Find the first matching level for the given value.\n *\n * A level matches if its `value` equals the current value, if the numeric value lies within\n * `min`/`max` (both inclusive) or if the level defines no condition at all (catch-all).\n */\nfunction findLevel(\n levels: StatusIndicatorLevel[],\n value: string | number | boolean | undefined,\n): StatusIndicatorLevel | undefined {\n for (const level of levels) {\n if (level.value !== undefined) {\n if (level.value === value) {\n return level;\n }\n continue;\n }\n if (level.min !== undefined || level.max !== undefined) {\n if (typeof value !== 'number') {\n continue;\n }\n if (level.min !== undefined && value < level.min) {\n continue;\n }\n if (level.max !== undefined && value > level.max) {\n continue;\n }\n return level;\n }\n // no condition => catch-all\n return level;\n }\n\n return undefined;\n}\n\ninterface StatusIndicatorProps {\n indicator: StatusIndicatorConfig;\n theme: IobTheme;\n stateOrObjectHandler: StateOrObjectHandler;\n /** Called when the indicator is clicked. If not provided, the indicator is not clickable */\n onClick?: () => void;\n /** If the referenced action opens a URL instead of calling the backend */\n url?: string;\n disabled?: boolean;\n /** Color used if the indicator does not define one itself (e.g. white in the toolbar) */\n defaultColor?: string;\n}\n\n/**\n * A single custom status indicator.\n *\n * Every visual property may be bound to a state or an object, so the indicator follows its value\n * live. The optional `levels` list maps value ranges to icon, color and text.\n */\nexport default function StatusIndicator(props: StatusIndicatorProps): React.JSX.Element | null {\n const { indicator, stateOrObjectHandler } = props;\n\n const value = useStateOrObject<string | number | boolean>(indicator.value, stateOrObjectHandler);\n const icon = useStateOrObject<string>(indicator.icon, stateOrObjectHandler);\n const iconOn = useStateOrObject<string>(indicator.iconOn, stateOrObjectHandler);\n const color = useStateOrObject<string>(indicator.color, stateOrObjectHandler);\n const colorOn = useStateOrObject<string>(indicator.colorOn, stateOrObjectHandler);\n const text = useStateOrObject<ioBroker.StringOrTranslated>(indicator.text, stateOrObjectHandler);\n\n // An indicator without a value is a static icon and is always visible. With a value, it is hidden\n // while the value is \"empty\" - the numeric 0 counts as a value and stays visible.\n if (indicator.value !== undefined && indicator.hideIfEmpty !== false) {\n if (value === undefined || value === null || value === '' || value === false) {\n return null;\n }\n }\n\n const on = !!value;\n const level = indicator.levels ? findLevel(indicator.levels, value) : undefined;\n\n const iconName = level?.icon ?? (on ? (iconOn ?? icon) : icon);\n const colorName = level?.color ?? (on ? (colorOn ?? color) : color);\n const resolvedColor = getIndicatorColor(colorName, props.theme) || props.defaultColor;\n\n const levelText = level?.text ?? text;\n let label = levelText !== undefined ? getTranslation(levelText) : indicator.showValue ? String(value ?? '') : '';\n if (label && indicator.unit) {\n label += ` ${indicator.unit}`;\n }\n\n const tooltipSource = level?.tooltip ?? indicator.tooltip;\n const tooltip = tooltipSource ? getTranslation(tooltipSource) : '';\n\n // Only fall back to the \"question mark\" icon if the indicator shows nothing else at all\n const iconElement = iconName || !label ? renderIcon(iconName, resolvedColor) : null;\n\n const content = (\n <div style={styles.content}>\n {iconElement}\n {label ? <p style={{ ...styles.text, color: resolvedColor }}>{label}</p> : null}\n </div>\n );\n\n let element: React.JSX.Element;\n if (props.url) {\n element = (\n <IconButton\n size=\"small\"\n style={{ padding: 2, borderRadius: 4 }}\n href={props.url}\n target=\"_blank\"\n disabled={props.disabled}\n >\n {content}\n </IconButton>\n );\n } else if (props.onClick) {\n element = (\n <IconButton\n size=\"small\"\n style={{ padding: 2, borderRadius: 4 }}\n disabled={props.disabled}\n onClick={e => {\n // The card itself may react on clicks, so the event must not bubble\n e.stopPropagation();\n props.onClick?.();\n }}\n >\n {content}\n </IconButton>\n );\n } else {\n element = content;\n }\n\n if (!tooltip) {\n return element;\n }\n\n return (\n <Tooltip\n title={<span style={{ whiteSpace: 'pre-line' }}>{tooltip}</span>}\n slotProps={{ popper: { sx: styles.tooltip } }}\n >\n <span style={{ display: 'inline-flex' }}>{element}</span>\n </Tooltip>\n );\n}\n\ninterface StatusIndicatorsProps {\n indicators?: StatusIndicatorConfig[];\n theme: IobTheme;\n stateOrObjectHandler: StateOrObjectHandler;\n /**\n * Resolves the click handler for an indicator that references an action. Returns `undefined`\n * if the referenced action does not exist - the indicator stays a pure display element then.\n */\n resolveAction?: (actionId: string) => { onClick?: () => void; url?: string; disabled?: boolean } | undefined;\n disabled?: boolean;\n defaultColor?: string;\n style?: React.CSSProperties;\n /** Additional elements rendered in the same line (e.g. actions with `placement: 'status'`) */\n children?: React.ReactNode;\n}\n\n/**\n * The line of custom status indicators.\n *\n * The line wraps if it does not fit, so an arbitrary number of indicators can be shown without\n * cutting anything off.\n */\nexport function StatusIndicators(props: StatusIndicatorsProps): React.JSX.Element | null {\n const indicators = props.indicators?.length\n ? [...props.indicators].sort((a, b) => (a.order ?? 100) - (b.order ?? 100))\n : [];\n\n if (!indicators.length && !props.children) {\n return null;\n }\n\n return (\n <div style={{ ...styles.row, ...props.style }}>\n {indicators.map(indicator => {\n const action = indicator.actionId ? props.resolveAction?.(indicator.actionId) : undefined;\n\n return (\n <StatusIndicator\n key={indicator.id}\n indicator={indicator}\n theme={props.theme}\n stateOrObjectHandler={props.stateOrObjectHandler}\n onClick={action?.onClick}\n url={action?.url}\n disabled={props.disabled || action?.disabled}\n defaultColor={props.defaultColor}\n />\n );\n })}\n {props.children}\n </div>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iobroker/dm-gui-components",
3
- "version": "10.0.22",
3
+ "version": "10.0.23",
4
4
  "description": "ReactJS components to develop admin interface for ioBroker device manager.",
5
5
  "author": {
6
6
  "name": "Jey Cee",
@@ -54,7 +54,7 @@
54
54
  "homepage": "https://github.com/ioBroker/dm-gui-components#readme",
55
55
  "dependencies": {
56
56
  "@iobroker/gui-components": "^10.3.1",
57
- "@iobroker/json-config": "^10.0.5",
57
+ "@iobroker/json-config": "^10.0.6",
58
58
  "@mui/icons-material": "^9.4.0",
59
59
  "@mui/material": "^9.4.0"
60
60
  },