@iobroker/dm-gui-components 10.0.23 → 10.1.0
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 +10 -0
- package/build/AnimatedIcons.d.ts +37 -0
- package/build/AnimatedIcons.js +108 -0
- package/build/AnimatedIcons.js.map +1 -0
- package/build/Communication.d.ts +7 -0
- package/build/Communication.js +43 -11
- package/build/Communication.js.map +1 -1
- package/build/DeviceCard.d.ts +25 -13
- package/build/DeviceCard.js +177 -282
- package/build/DeviceCard.js.map +1 -1
- package/build/DeviceControl.js +38 -26
- package/build/DeviceControl.js.map +1 -1
- package/build/DeviceImageUpload.d.ts +5 -1
- package/build/DeviceImageUpload.js +79 -62
- package/build/DeviceImageUpload.js.map +1 -1
- package/build/DeviceList.d.ts +8 -0
- package/build/DeviceList.js +74 -59
- package/build/DeviceList.js.map +1 -1
- package/build/DeviceStatus.d.ts +20 -4
- package/build/DeviceStatus.js +146 -191
- package/build/DeviceStatus.js.map +1 -1
- package/build/StatusIndicator.js +9 -37
- package/build/StatusIndicator.js.map +1 -1
- package/build/StatusPill.d.ts +18 -0
- package/build/StatusPill.js +30 -0
- package/build/StatusPill.js.map +1 -0
- package/build/Switch.d.ts +3 -0
- package/build/Switch.js +36 -26
- package/build/Switch.js.map +1 -1
- package/build/Utils.js +92 -60
- package/build/Utils.js.map +1 -1
- package/build/i18n/de.json +3 -0
- package/build/i18n/en.json +3 -0
- package/build/i18n/es.json +3 -0
- package/build/i18n/fr.json +3 -0
- package/build/i18n/it.json +3 -0
- package/build/i18n/nl.json +3 -0
- package/build/i18n/pl.json +3 -0
- package/build/i18n/pt.json +3 -0
- package/build/i18n/ru.json +3 -0
- package/build/i18n/uk.json +3 -0
- package/build/i18n/zh-cn.json +3 -0
- package/build/styles.d.ts +17 -0
- package/build/styles.js +226 -0
- package/build/styles.js.map +1 -0
- package/package.json +10 -10
|
@@ -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={<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"]}
|
|
1
|
+
{"version":3,"file":"StatusIndicator.js","sourceRoot":"./src/","sources":["StatusIndicator.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\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 StatusPill from './StatusPill';\nimport { getIndicatorColor, getTranslation, renderIcon } from './Utils';\n\nconst styles: Record<string, React.CSSProperties> = {\n tooltipText: {\n whiteSpace: 'pre-line',\n },\n row: {\n display: 'flex',\n alignItems: 'center',\n flexWrap: 'wrap',\n gap: 4,\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 // An indicator in the color \"error\" or \"warning\" needs attention: its pill is tinted like the built-in ones\n const tone = colorName === 'error' ? 'err' : colorName === 'warning' ? 'warn' : undefined;\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, tone ? undefined : resolvedColor) : null;\n\n return (\n <StatusPill\n tone={tone}\n color={tone ? undefined : resolvedColor}\n tooltip={tooltip ? <span style={styles.tooltipText}>{tooltip}</span> : undefined}\n href={props.url}\n onClick={props.url ? undefined : props.onClick}\n disabled={props.disabled}\n >\n {iconElement}\n {label ? <span>{label}</span> : null}\n </StatusPill>\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"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { type PillTone } from './styles';
|
|
3
|
+
interface StatusPillProps {
|
|
4
|
+
/** Tints the pill with this color: the value needs attention. Without it the pill is neutral. */
|
|
5
|
+
tone?: PillTone;
|
|
6
|
+
tooltip?: React.ReactNode;
|
|
7
|
+
/** The pill becomes a button */
|
|
8
|
+
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
9
|
+
/** Opens the URL instead */
|
|
10
|
+
href?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** Text color (e.g. the color of a custom indicator), if the pill has no tone */
|
|
13
|
+
color?: string;
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/** One value of the status line: an icon and an optional short text */
|
|
17
|
+
export default function StatusPill(props: StatusPillProps): React.JSX.Element;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ButtonBase, Tooltip } from '@mui/material';
|
|
3
|
+
import { toneStyle, useDmStyles } from './styles';
|
|
4
|
+
const tooltipSlotProps = { popper: { sx: { pointerEvents: 'none' } } };
|
|
5
|
+
/** One value of the status line: an icon and an optional short text */
|
|
6
|
+
export default function StatusPill(props) {
|
|
7
|
+
useDmStyles();
|
|
8
|
+
const className = `dm-pill${props.tone ? ' dm-pill-tone' : ''}`;
|
|
9
|
+
const style = props.tone ? toneStyle(props.tone) : props.color ? { color: props.color } : undefined;
|
|
10
|
+
let pill;
|
|
11
|
+
if (props.href) {
|
|
12
|
+
pill = (React.createElement(ButtonBase, { component: "a", className: `${className} dm-pill-btn`, style: style, disabled: props.disabled, href: props.href, target: "_blank", rel: "noreferrer", onClick: (e) => e.stopPropagation() }, props.children));
|
|
13
|
+
}
|
|
14
|
+
else if (props.onClick) {
|
|
15
|
+
pill = (React.createElement(ButtonBase, { className: `${className} dm-pill-btn`, style: style, disabled: props.disabled, onClick: (e) => {
|
|
16
|
+
// The card around may react to clicks too
|
|
17
|
+
e.stopPropagation();
|
|
18
|
+
props.onClick(e);
|
|
19
|
+
} }, props.children));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
pill = (React.createElement("span", { className: className, style: style }, props.children));
|
|
23
|
+
}
|
|
24
|
+
if (!props.tooltip) {
|
|
25
|
+
return pill;
|
|
26
|
+
}
|
|
27
|
+
return (React.createElement(Tooltip, { title: props.tooltip, slotProps: tooltipSlotProps },
|
|
28
|
+
React.createElement("span", { className: "dm-pill-wrap" }, pill)));
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=StatusPill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusPill.js","sourceRoot":"./src/","sources":["StatusPill.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAiB,MAAM,UAAU,CAAC;AAgBjE,MAAM,gBAAgB,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;AAEvE,uEAAuE;AACvE,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,KAAsB;IACrD,WAAW,EAAE,CAAC;IACd,MAAM,SAAS,GAAG,UAAU,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAChE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAEpG,IAAI,IAAuB,CAAC;IAC5B,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACb,IAAI,GAAG,CACH,oBAAC,UAAU,IACP,SAAS,EAAC,GAAG,EACb,SAAS,EAAE,GAAG,SAAS,cAAc,EACrC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,OAAO,EAAE,CAAC,CAAmB,EAAE,EAAE,CAAC,CAAC,CAAC,eAAe,EAAE,IAEpD,KAAK,CAAC,QAAQ,CACN,CAChB,CAAC;IACN,CAAC;SAAM,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACvB,IAAI,GAAG,CACH,oBAAC,UAAU,IACP,SAAS,EAAE,GAAG,SAAS,cAAc,EACrC,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ,EACxB,OAAO,EAAE,CAAC,CAAsC,EAAE,EAAE;gBAChD,0CAA0C;gBAC1C,CAAC,CAAC,eAAe,EAAE,CAAC;gBACpB,KAAK,CAAC,OAAQ,CAAC,CAAC,CAAC,CAAC;YACtB,CAAC,IAEA,KAAK,CAAC,QAAQ,CACN,CAChB,CAAC;IACN,CAAC;SAAM,CAAC;QACJ,IAAI,GAAG,CACH,8BACI,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,IAEX,KAAK,CAAC,QAAQ,CACZ,CACV,CAAC;IACN,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,OAAO,CACH,oBAAC,OAAO,IACJ,KAAK,EAAE,KAAK,CAAC,OAAO,EACpB,SAAS,EAAE,gBAAgB;QAG3B,8BAAM,SAAS,EAAC,cAAc,IAAE,IAAI,CAAQ,CACtC,CACb,CAAC;AACN,CAAC","sourcesContent":["import React from 'react';\nimport { ButtonBase, Tooltip } from '@mui/material';\n\nimport { toneStyle, useDmStyles, type PillTone } from './styles';\n\ninterface StatusPillProps {\n /** Tints the pill with this color: the value needs attention. Without it the pill is neutral. */\n tone?: PillTone;\n tooltip?: React.ReactNode;\n /** The pill becomes a button */\n onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n /** Opens the URL instead */\n href?: string;\n disabled?: boolean;\n /** Text color (e.g. the color of a custom indicator), if the pill has no tone */\n color?: string;\n children: React.ReactNode;\n}\n\nconst tooltipSlotProps = { popper: { sx: { pointerEvents: 'none' } } };\n\n/** One value of the status line: an icon and an optional short text */\nexport default function StatusPill(props: StatusPillProps): React.JSX.Element {\n useDmStyles();\n const className = `dm-pill${props.tone ? ' dm-pill-tone' : ''}`;\n const style = props.tone ? toneStyle(props.tone) : props.color ? { color: props.color } : undefined;\n\n let pill: React.JSX.Element;\n if (props.href) {\n pill = (\n <ButtonBase\n component=\"a\"\n className={`${className} dm-pill-btn`}\n style={style}\n disabled={props.disabled}\n href={props.href}\n target=\"_blank\"\n rel=\"noreferrer\"\n onClick={(e: React.MouseEvent) => e.stopPropagation()}\n >\n {props.children}\n </ButtonBase>\n );\n } else if (props.onClick) {\n pill = (\n <ButtonBase\n className={`${className} dm-pill-btn`}\n style={style}\n disabled={props.disabled}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n // The card around may react to clicks too\n e.stopPropagation();\n props.onClick!(e);\n }}\n >\n {props.children}\n </ButtonBase>\n );\n } else {\n pill = (\n <span\n className={className}\n style={style}\n >\n {props.children}\n </span>\n );\n }\n\n if (!props.tooltip) {\n return pill;\n }\n\n return (\n <Tooltip\n title={props.tooltip}\n slotProps={tooltipSlotProps}\n >\n {/* A disabled button gets no mouse events, so the tooltip needs an element around it */}\n <span className=\"dm-pill-wrap\">{pill}</span>\n </Tooltip>\n );\n}\n"]}
|
package/build/Switch.d.ts
CHANGED
|
@@ -9,8 +9,11 @@ interface SwitchProps {
|
|
|
9
9
|
labelOff?: string;
|
|
10
10
|
size?: 'small';
|
|
11
11
|
disabled?: boolean;
|
|
12
|
+
/** Accessible name */
|
|
13
|
+
ariaLabel?: string;
|
|
12
14
|
}
|
|
13
15
|
export default class Switch extends Component<SwitchProps> {
|
|
16
|
+
private toggle;
|
|
14
17
|
render(): React.JSX.Element;
|
|
15
18
|
}
|
|
16
19
|
export {};
|
package/build/Switch.js
CHANGED
|
@@ -3,46 +3,56 @@ const WIDTH = 34;
|
|
|
3
3
|
const HANDLE_SIZE = 20;
|
|
4
4
|
const WIDTH_SMALL = 30;
|
|
5
5
|
const HANDLE_SIZE_SMALL = 15;
|
|
6
|
+
/** The handle overshoots a little, as if it snapped into place */
|
|
7
|
+
const SNAP = 'cubic-bezier(0.3, 1.5, 0.5, 1)';
|
|
6
8
|
export default class Switch extends Component {
|
|
9
|
+
toggle(e) {
|
|
10
|
+
if (this.props.disabled) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
e.stopPropagation();
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
this.props.onChange(!this.props.checked);
|
|
16
|
+
}
|
|
7
17
|
render() {
|
|
8
|
-
const
|
|
9
|
-
|
|
18
|
+
const small = this.props.size === 'small';
|
|
19
|
+
const width = small ? WIDTH_SMALL : WIDTH;
|
|
20
|
+
const handle = small ? HANDLE_SIZE_SMALL : HANDLE_SIZE;
|
|
21
|
+
const primary = this.props.theme.palette.primary.main;
|
|
22
|
+
const sw = (React.createElement("div", { role: "switch", className: "dm-switch", "aria-checked": this.props.checked, "aria-disabled": this.props.disabled || undefined, "aria-label": this.props.ariaLabel, tabIndex: this.props.disabled ? -1 : 0, style: {
|
|
23
|
+
width,
|
|
10
24
|
height: HANDLE_SIZE,
|
|
11
25
|
display: 'flex',
|
|
12
26
|
alignItems: 'center',
|
|
13
|
-
cursor: 'pointer',
|
|
27
|
+
cursor: this.props.disabled ? 'default' : 'pointer',
|
|
14
28
|
position: 'relative',
|
|
15
|
-
opacity: this.props.disabled ? 0.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
opacity: this.props.disabled ? 0.6 : 1,
|
|
30
|
+
borderRadius: HANDLE_SIZE / 2,
|
|
31
|
+
outlineOffset: 2,
|
|
32
|
+
...this.props.style,
|
|
33
|
+
}, onClick: e => this.toggle(e), onKeyDown: e => {
|
|
34
|
+
if (e.key === ' ' || e.key === 'Enter') {
|
|
35
|
+
this.toggle(e);
|
|
19
36
|
}
|
|
20
|
-
e.stopPropagation();
|
|
21
|
-
e.preventDefault();
|
|
22
|
-
this.props.onChange(!this.props.checked);
|
|
23
37
|
} },
|
|
24
38
|
React.createElement("div", { style: {
|
|
25
39
|
borderRadius: 15,
|
|
26
40
|
width: '100%',
|
|
27
|
-
height:
|
|
28
|
-
opacity: 0.6,
|
|
29
|
-
backgroundColor: this.props.checked
|
|
30
|
-
|
|
31
|
-
: this.props.theme.palette.text.disabled,
|
|
41
|
+
height: handle * 0.7,
|
|
42
|
+
opacity: this.props.checked ? 0.5 : 0.6,
|
|
43
|
+
backgroundColor: this.props.checked ? primary : this.props.theme.palette.text.disabled,
|
|
44
|
+
transition: 'background-color 0.25s, opacity 0.25s',
|
|
32
45
|
} }),
|
|
33
46
|
React.createElement("div", { style: {
|
|
34
47
|
position: 'absolute',
|
|
35
|
-
top:
|
|
36
|
-
left:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
width: this.props.size === 'small' ? HANDLE_SIZE_SMALL : HANDLE_SIZE,
|
|
44
|
-
height: this.props.size === 'small' ? HANDLE_SIZE_SMALL : HANDLE_SIZE,
|
|
45
|
-
backgroundColor: this.props.checked ? this.props.theme.palette.primary.main : '#EEE',
|
|
48
|
+
top: small ? (HANDLE_SIZE - HANDLE_SIZE_SMALL) / 2 : 0,
|
|
49
|
+
left: 0,
|
|
50
|
+
transform: `translateX(${this.props.checked ? width - handle : 0}px)`,
|
|
51
|
+
transition: `transform 0.3s ${SNAP}, background-color 0.25s`,
|
|
52
|
+
borderRadius: '50%',
|
|
53
|
+
width: handle,
|
|
54
|
+
height: handle,
|
|
55
|
+
backgroundColor: this.props.checked ? primary : '#EEE',
|
|
46
56
|
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px',
|
|
47
57
|
} })));
|
|
48
58
|
if (this.props.labelOn || this.props.labelOff) {
|
package/build/Switch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Switch.js","sourceRoot":"./src/","sources":["Switch.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Switch.js","sourceRoot":"./src/","sources":["Switch.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { Component } from 'react';\nimport { type IobTheme } from '@iobroker/gui-components';\n\ninterface SwitchProps {\n checked: boolean;\n style?: React.CSSProperties;\n onChange: (checked: boolean) => void;\n theme: IobTheme;\n labelOn?: string;\n labelOff?: string;\n size?: 'small';\n disabled?: boolean;\n /** Accessible name */\n ariaLabel?: string;\n}\n\nconst WIDTH = 34;\nconst HANDLE_SIZE = 20;\nconst WIDTH_SMALL = 30;\nconst HANDLE_SIZE_SMALL = 15;\n\n/** The handle overshoots a little, as if it snapped into place */\nconst SNAP = 'cubic-bezier(0.3, 1.5, 0.5, 1)';\n\nexport default class Switch extends Component<SwitchProps> {\n private toggle(e: React.SyntheticEvent): void {\n if (this.props.disabled) {\n return;\n }\n e.stopPropagation();\n e.preventDefault();\n this.props.onChange(!this.props.checked);\n }\n\n render(): React.JSX.Element {\n const small = this.props.size === 'small';\n const width = small ? WIDTH_SMALL : WIDTH;\n const handle = small ? HANDLE_SIZE_SMALL : HANDLE_SIZE;\n const primary = this.props.theme.palette.primary.main;\n\n const sw = (\n <div\n role=\"switch\"\n className=\"dm-switch\"\n aria-checked={this.props.checked}\n aria-disabled={this.props.disabled || undefined}\n aria-label={this.props.ariaLabel}\n tabIndex={this.props.disabled ? -1 : 0}\n style={{\n width,\n height: HANDLE_SIZE,\n display: 'flex',\n alignItems: 'center',\n cursor: this.props.disabled ? 'default' : 'pointer',\n position: 'relative',\n opacity: this.props.disabled ? 0.6 : 1,\n borderRadius: HANDLE_SIZE / 2,\n outlineOffset: 2,\n ...this.props.style,\n }}\n onClick={e => this.toggle(e)}\n onKeyDown={e => {\n if (e.key === ' ' || e.key === 'Enter') {\n this.toggle(e);\n }\n }}\n >\n <div\n style={{\n borderRadius: 15,\n width: '100%',\n height: handle * 0.7,\n opacity: this.props.checked ? 0.5 : 0.6,\n backgroundColor: this.props.checked ? primary : this.props.theme.palette.text.disabled,\n transition: 'background-color 0.25s, opacity 0.25s',\n }}\n />\n <div\n style={{\n position: 'absolute',\n top: small ? (HANDLE_SIZE - HANDLE_SIZE_SMALL) / 2 : 0,\n left: 0,\n transform: `translateX(${this.props.checked ? width - handle : 0}px)`,\n transition: `transform 0.3s ${SNAP}, background-color 0.25s`,\n borderRadius: '50%',\n width: handle,\n height: handle,\n backgroundColor: this.props.checked ? primary : '#EEE',\n boxShadow:\n 'rgba(0, 0, 0, 0.2) 0px 2px 1px -1px, rgba(0, 0, 0, 0.14) 0px 1px 1px 0px, rgba(0, 0, 0, 0.12) 0px 1px 3px 0px',\n }}\n />\n </div>\n );\n\n if (this.props.labelOn || this.props.labelOff) {\n return (\n <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>\n {this.props.labelOff}\n {sw}\n {this.props.labelOn}\n </div>\n );\n }\n\n return sw;\n }\n}\n"]}
|
package/build/Utils.js
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Add, Article, BatteryAlert, BatteryChargingFull, BatteryFull, Bluetooth, BluetoothDisabled,
|
|
3
|
-
import { I18n, Icon } from '@iobroker/gui-components';
|
|
2
|
+
import { Add, Article, BatteryAlert, BatteryChargingFull, BatteryFull, Bluetooth, BluetoothDisabled, Edit, FastForward, FastRewind, Fluorescent, Group, Info, Lightbulb, Link as LinkIcon, LinkOff, NotListedLocation, Pause, Person, PlayArrow, Power, QrCode, QuestionMark, Refresh, Search, Settings, Stop, Visibility, Upgrade, WbIncandescent, Wifi, WifiOff, Launch, } from '@mui/icons-material';
|
|
3
|
+
import { I18n, Icon, IconPlayPause, IconTrash } from '@iobroker/gui-components';
|
|
4
|
+
/**
|
|
5
|
+
* Class of an action symbol that shows what its button does while the mouse is over the button
|
|
6
|
+
* (see `styles.ts`): the gear turns, the pen writes, the lamp glows...
|
|
7
|
+
*/
|
|
8
|
+
const HOVER = {
|
|
9
|
+
spin: 'dm-ani dm-ani-spin',
|
|
10
|
+
gear: 'dm-ani dm-ani-gear',
|
|
11
|
+
turn: 'dm-ani dm-ani-turn',
|
|
12
|
+
pen: 'dm-ani dm-ani-pen',
|
|
13
|
+
hop: 'dm-ani dm-ani-hop',
|
|
14
|
+
search: 'dm-ani dm-ani-search',
|
|
15
|
+
nudge: 'dm-ani dm-ani-nudge',
|
|
16
|
+
launch: 'dm-ani dm-ani-launch',
|
|
17
|
+
glow: 'dm-ani dm-ani-glow',
|
|
18
|
+
tick: 'dm-ani dm-ani-tick',
|
|
19
|
+
};
|
|
20
|
+
/** An MUI icon with the given hover animation */
|
|
21
|
+
function animated(IconComponent, hover, color) {
|
|
22
|
+
return (React.createElement(IconComponent, { className: hover, style: { color } }));
|
|
23
|
+
}
|
|
4
24
|
/**
|
|
5
25
|
* Get Icon by font-awesome name. Do not use these names, use names from getIconByName
|
|
6
26
|
*
|
|
@@ -31,19 +51,20 @@ function getFaIcon(icon, color) {
|
|
|
31
51
|
.map(s => s.trim())
|
|
32
52
|
.filter(s => s !== 'fa-solid');
|
|
33
53
|
if (iconStyle.includes('fa-trash-can') || iconStyle.includes('fa-trash')) {
|
|
34
|
-
|
|
54
|
+
// The lid opens while the mouse is over the button
|
|
55
|
+
return React.createElement(IconTrash, { style: { color } });
|
|
35
56
|
}
|
|
36
57
|
if (iconStyle.includes('fa-pen')) {
|
|
37
|
-
return
|
|
58
|
+
return animated(Edit, HOVER.pen, color);
|
|
38
59
|
}
|
|
39
60
|
if (iconStyle.includes('fa-redo-alt')) {
|
|
40
|
-
return
|
|
61
|
+
return animated(Refresh, HOVER.spin, color);
|
|
41
62
|
}
|
|
42
63
|
if (iconStyle.includes('fa-plus')) {
|
|
43
|
-
return
|
|
64
|
+
return animated(Add, HOVER.turn, color);
|
|
44
65
|
}
|
|
45
66
|
if (iconStyle.includes('fa-qrcode') || iconStyle.includes('qrcode')) {
|
|
46
|
-
return
|
|
67
|
+
return animated(QrCode, HOVER.tick, color);
|
|
47
68
|
}
|
|
48
69
|
if (iconStyle.includes('fa-wifi')) {
|
|
49
70
|
return React.createElement(Wifi, { style: { color } });
|
|
@@ -58,10 +79,10 @@ function getFaIcon(icon, color) {
|
|
|
58
79
|
return React.createElement(BluetoothDisabled, { style: { color } });
|
|
59
80
|
}
|
|
60
81
|
if (iconStyle.includes('fa-eye')) {
|
|
61
|
-
return
|
|
82
|
+
return animated(Visibility, HOVER.tick, color);
|
|
62
83
|
}
|
|
63
84
|
if (iconStyle.includes('fa-search')) {
|
|
64
|
-
return
|
|
85
|
+
return animated(Search, HOVER.search, color);
|
|
65
86
|
}
|
|
66
87
|
if (iconStyle.includes('fa-unlink')) {
|
|
67
88
|
return React.createElement(LinkOff, { style: { color } });
|
|
@@ -70,10 +91,10 @@ function getFaIcon(icon, color) {
|
|
|
70
91
|
return React.createElement(LinkIcon, { style: { color } });
|
|
71
92
|
}
|
|
72
93
|
if (iconStyle.includes('fa-search-location')) {
|
|
73
|
-
return
|
|
94
|
+
return animated(NotListedLocation, HOVER.hop, color);
|
|
74
95
|
}
|
|
75
96
|
if (iconStyle.includes('fa-play')) {
|
|
76
|
-
return
|
|
97
|
+
return animated(PlayArrow, HOVER.nudge, color);
|
|
77
98
|
}
|
|
78
99
|
if (iconStyle.includes('fa-stop')) {
|
|
79
100
|
return React.createElement(Stop, { style: { color } });
|
|
@@ -120,93 +141,90 @@ function getFaIcon(icon, color) {
|
|
|
120
141
|
* @param noDefaultIcon if true, no "question mark" icon will be returned for unknown names
|
|
121
142
|
*/
|
|
122
143
|
function getIconByName(name, altName, color, noDefaultIcon) {
|
|
123
|
-
|
|
124
|
-
|
|
144
|
+
const is = (...names) => names.includes(name) || (!!altName && names.includes(altName));
|
|
145
|
+
if (is('edit', 'rename')) {
|
|
146
|
+
return animated(Edit, HOVER.pen, color);
|
|
125
147
|
}
|
|
126
|
-
if (
|
|
127
|
-
|
|
148
|
+
if (is('delete')) {
|
|
149
|
+
// The lid opens while the mouse is over the button
|
|
150
|
+
return React.createElement(IconTrash, { style: { color } });
|
|
128
151
|
}
|
|
129
|
-
if (
|
|
130
|
-
return
|
|
152
|
+
if (is('refresh')) {
|
|
153
|
+
return animated(Refresh, HOVER.spin, color);
|
|
131
154
|
}
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
name === 'add' ||
|
|
135
|
-
altName === 'newDevice' ||
|
|
136
|
-
altName === 'new' ||
|
|
137
|
-
altName === 'add') {
|
|
138
|
-
return React.createElement(Add, { style: { color } });
|
|
155
|
+
if (is('newDevice', 'new', 'add')) {
|
|
156
|
+
return animated(Add, HOVER.turn, color);
|
|
139
157
|
}
|
|
140
|
-
if (
|
|
141
|
-
return
|
|
158
|
+
if (is('discover', 'search')) {
|
|
159
|
+
return animated(Search, HOVER.search, color);
|
|
142
160
|
}
|
|
143
|
-
if (
|
|
161
|
+
if (is('unpairDevice', 'unpair')) {
|
|
144
162
|
return React.createElement(LinkOff, { style: { color } });
|
|
145
163
|
}
|
|
146
|
-
if (
|
|
164
|
+
if (is('pairDevice', 'pair')) {
|
|
147
165
|
return React.createElement(LinkIcon, { style: { color } });
|
|
148
166
|
}
|
|
149
|
-
if (
|
|
150
|
-
return
|
|
167
|
+
if (is('identify')) {
|
|
168
|
+
return animated(NotListedLocation, HOVER.hop, color);
|
|
151
169
|
}
|
|
152
|
-
if (
|
|
153
|
-
return
|
|
170
|
+
if (is('play')) {
|
|
171
|
+
return animated(PlayArrow, HOVER.nudge, color);
|
|
154
172
|
}
|
|
155
|
-
if (
|
|
173
|
+
if (is('stop')) {
|
|
156
174
|
return React.createElement(Stop, { style: { color } });
|
|
157
175
|
}
|
|
158
|
-
if (
|
|
176
|
+
if (is('pause')) {
|
|
159
177
|
return React.createElement(Pause, { style: { color } });
|
|
160
178
|
}
|
|
161
|
-
if (
|
|
162
|
-
return
|
|
179
|
+
if (is('forward', 'next')) {
|
|
180
|
+
return animated(FastForward, HOVER.nudge, color);
|
|
163
181
|
}
|
|
164
|
-
if (
|
|
182
|
+
if (is('rewind', 'previous')) {
|
|
165
183
|
return React.createElement(FastRewind, { style: { color } });
|
|
166
184
|
}
|
|
167
|
-
if (
|
|
168
|
-
return
|
|
185
|
+
if (is('lamp', 'light')) {
|
|
186
|
+
return animated(Lightbulb, HOVER.glow, color);
|
|
169
187
|
}
|
|
170
|
-
if (
|
|
171
|
-
return
|
|
188
|
+
if (is('backlight')) {
|
|
189
|
+
return animated(Fluorescent, HOVER.glow, color);
|
|
172
190
|
}
|
|
173
|
-
if (
|
|
174
|
-
return
|
|
191
|
+
if (is('dimmer')) {
|
|
192
|
+
return animated(WbIncandescent, HOVER.glow, color);
|
|
175
193
|
}
|
|
176
|
-
if (
|
|
194
|
+
if (is('socket')) {
|
|
177
195
|
return React.createElement(Power, { style: { color } });
|
|
178
196
|
}
|
|
179
|
-
if (
|
|
180
|
-
return
|
|
197
|
+
if (is('settings')) {
|
|
198
|
+
return animated(Settings, HOVER.gear, color);
|
|
181
199
|
}
|
|
182
|
-
if (
|
|
200
|
+
if (is('users', 'group')) {
|
|
183
201
|
return React.createElement(Group, { style: { color } });
|
|
184
202
|
}
|
|
185
|
-
if (
|
|
203
|
+
if (is('user')) {
|
|
186
204
|
return React.createElement(Person, { style: { color } });
|
|
187
205
|
}
|
|
188
|
-
if (
|
|
189
|
-
return
|
|
206
|
+
if (is('update')) {
|
|
207
|
+
return animated(Upgrade, HOVER.hop, color);
|
|
190
208
|
}
|
|
191
|
-
if (
|
|
192
|
-
return
|
|
209
|
+
if (is('qrcode')) {
|
|
210
|
+
return animated(QrCode, HOVER.tick, color);
|
|
193
211
|
}
|
|
194
|
-
if (
|
|
195
|
-
return
|
|
212
|
+
if (is('info')) {
|
|
213
|
+
return animated(Info, HOVER.tick, color);
|
|
196
214
|
}
|
|
197
|
-
if (
|
|
215
|
+
if (is('lines')) {
|
|
198
216
|
return React.createElement(Article, { style: { color } });
|
|
199
217
|
}
|
|
200
|
-
if (
|
|
201
|
-
return
|
|
218
|
+
if (is('web')) {
|
|
219
|
+
return animated(Launch, HOVER.launch, color);
|
|
202
220
|
}
|
|
203
|
-
if (
|
|
221
|
+
if (is('battery')) {
|
|
204
222
|
return React.createElement(BatteryFull, { style: { color } });
|
|
205
223
|
}
|
|
206
|
-
if (
|
|
224
|
+
if (is('batteryLow', 'batteryAlert')) {
|
|
207
225
|
return React.createElement(BatteryAlert, { style: { color } });
|
|
208
226
|
}
|
|
209
|
-
if (
|
|
227
|
+
if (is('batteryCharging')) {
|
|
210
228
|
return React.createElement(BatteryChargingFull, { style: { color } });
|
|
211
229
|
}
|
|
212
230
|
if (noDefaultIcon) {
|
|
@@ -227,6 +245,20 @@ export function renderControlIcon(action, colors, value, noDefaultIcon) {
|
|
|
227
245
|
color = colors.secondary;
|
|
228
246
|
}
|
|
229
247
|
}
|
|
248
|
+
// A play or pause toggle shows what a click does: play while it is stopped, pause while it runs.
|
|
249
|
+
// The symbol morphs from one into the other.
|
|
250
|
+
const isPlayPause = 'type' in action &&
|
|
251
|
+
action.type === 'icon' &&
|
|
252
|
+
!action.iconOn &&
|
|
253
|
+
(action.id === 'play' ||
|
|
254
|
+
action.id === 'pause' ||
|
|
255
|
+
action.icon === 'play' ||
|
|
256
|
+
action.icon === 'pause' ||
|
|
257
|
+
action.icon === 'fa-play' ||
|
|
258
|
+
action.icon === 'fa-pause');
|
|
259
|
+
if (isPlayPause) {
|
|
260
|
+
return (React.createElement(IconPlayPause, { running: !!value, style: { color } }));
|
|
261
|
+
}
|
|
230
262
|
if (action.icon?.startsWith('fa-') || action.icon?.startsWith('fas')) {
|
|
231
263
|
return getFaIcon(action.icon, color);
|
|
232
264
|
}
|