@iobroker/gui-components 10.3.0 → 10.3.1

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
@@ -36,7 +36,7 @@ npm create vite@latest src -- --template react-ts
36
36
  "dependencies": {
37
37
  "@emotion/react": "^11.14.0",
38
38
  "@emotion/styled": "^11.14.1",
39
- "@iobroker/gui-components": "^10.3.0",
39
+ "@iobroker/gui-components": "^10.3.1",
40
40
  "@mui/icons-material": "^9.0.1",
41
41
  "@mui/material": "^9.0.1",
42
42
  "react": "^19.2.5",
@@ -877,6 +877,10 @@ You can find the migration instructions:
877
877
  -->
878
878
 
879
879
  ## Changelog
880
+ ### 10.3.1 (2026-09-15)
881
+
882
+ - (@GermanBluefox) Changed: the details of the selected object in the narrow view of the object browser were reworked - theme colors, the full ID with a copy button, a dash for empty values and buttons with tooltips
883
+
880
884
  ### 10.3.0 (2026-09-14)
881
885
 
882
886
  - (@GermanBluefox) Added: the icon selector offers a library of 448 icons for rooms, buildings, furniture, lighting, climate, windows and shading, security, energy, water, household appliances, multimedia, garden, weather, people and more. Every icon has a name in all 11 languages, and the search looks through all categories. The icons are taken from Material Design Icons (Apache License 2.0), painted with `currentColor` and loaded only when the dialog is opened. The classic room and device icons stay available as their own categories
@@ -842,7 +842,7 @@ export function renderLeaf(that, item, isExpanded, counter) {
842
842
  };
843
843
  let colValue = showValueCell ? (React.createElement("div", { style: {
844
844
  ...styles.cellValue,
845
- width: that.width !== 'xs' ? colWidth('val') : 'calc(100% - 100px)',
845
+ width: that.width !== 'xs' ? colWidth('val') : '100%',
846
846
  // An empty inline-block has no height, so a state without a value would offer nothing
847
847
  // to tap on in the narrow details view.
848
848
  minHeight: narrowStyleWithDetails ? 20 : undefined,
@@ -904,80 +904,91 @@ export function renderLeaf(that, item, isExpanded, counter) {
904
904
  width: that.width !== 'xs' ? colWidth('buttons') : undefined,
905
905
  } }, renderColumnButtons(that, id, item))) : null;
906
906
  let colDetails = null;
907
- if (that.width === 'xs' && that.state.focused === id) {
908
- colMiddle = colMiddle.filter(a => a);
909
- let renderedMiddle;
910
- if (!colMiddle.length) {
911
- renderedMiddle = null;
912
- }
913
- else {
914
- renderedMiddle = colMiddle.map(it => {
915
- if (!it) {
916
- return null;
917
- }
918
- return (React.createElement("div", { key: it.type, style: styles.cellDetailsLine },
919
- React.createElement("span", { style: styles.cellDetailsName },
920
- that.texts[it.type],
921
- ":"),
922
- it.el,
923
- React.createElement("div", { style: { flexGrow: 1 } }),
924
- it.onClick ? (React.createElement(IconEdit, { style: styles.cellCopyButtonInDetails, onClick: () => {
925
- if (it?.onClick) {
926
- it.onClick();
927
- }
928
- } })) : null));
929
- });
930
- }
931
- if (!colCustom.length) {
907
+ if (narrowStyleWithDetails) {
908
+ /** Texts of the middle columns: the cells are always rendered, so an empty one must be detected here */
909
+ const middleTexts = {
910
+ filter_type: obj?.type,
911
+ filter_role: common?.role,
912
+ filter_room: item.data.rooms,
913
+ filter_func: item.data.funcs,
914
+ };
915
+ const editTitles = {
916
+ filter_role: 'ra_Edit role',
917
+ filter_room: 'ra_Edit room',
918
+ filter_func: 'ra_Edit function',
919
+ };
920
+ /** One line of the details: the label, the value (or a dash) and the buttons for it */
921
+ const detailsLine = (key, label, value, actions = []) => (React.createElement("div", { key: key, style: styles.cellDetailsLine },
922
+ React.createElement("span", { style: styles.cellDetailsName }, label),
923
+ React.createElement(Box, { sx: styles.cellDetailsValue }, value || React.createElement("span", { style: styles.cellDetailsEmpty }, "\u2013")),
924
+ actions.map(action => (React.createElement(Tooltip, { key: action.title, title: action.title, slotProps: { popper: { sx: styles.tooltip } } },
925
+ React.createElement(IconButton, { size: "small", sx: styles.cellDetailsButton, onClick: action.onClick }, action.icon))))));
926
+ const copyTitle = that.props.t('ra_Copy to clipboard');
927
+ const copyIcon = React.createElement(IconCopy, { style: styles.cellDetailsIcon });
928
+ const editIcon = React.createElement(IconEdit, { style: styles.cellDetailsIcon });
929
+ if (!colCustom?.length) {
932
930
  colCustom = null;
933
931
  }
932
+ // a folder without an object has nothing but its ID, so the header does not need a separator then
933
+ const hasLines = !!colName || !!colMiddle?.some(it => it) || !!colCustom || that.objects[id]?.type === 'state';
934
934
  colDetails = (React.createElement(Paper
935
935
  // `renderItem` pushes this panel into the array of rows, so it needs its own key
936
936
  , {
937
937
  // `renderItem` pushes this panel into the array of rows, so it needs its own key
938
- key: `details_${id}`, style: {
939
- width: '100%',
940
- // the padding must be inside of the width, else the row is wider than the table
941
- boxSizing: 'border-box',
942
- display: 'flex',
943
- flexDirection: 'column',
944
- padding: 10,
945
- backgroundColor: that.props.theme.palette.mode === 'dark' ? '#333' : '#ccc',
946
- } },
947
- React.createElement("div", { style: styles.cellDetailsLine },
948
- React.createElement("div", { style: { flexGrow: 1 } }),
949
- React.createElement(IconCopy, { style: styles.cellCopyButtonInDetails, onClick: e => that.onCopy(e, id) })),
950
- colName && (React.createElement("div", { style: styles.cellDetailsLine },
951
- React.createElement("span", { style: styles.cellDetailsName },
952
- that.texts.name,
953
- ":"),
954
- colName,
955
- React.createElement("div", { style: { flexGrow: 1 } }),
956
- item.data?.title ? (React.createElement(IconCopy, { className: "copyButton", style: styles.cellCopyButtonInDetails, onClick: e => that.onCopy(e, item.data?.title) })) : null)),
957
- renderedMiddle,
958
- colCustom && React.createElement("div", { style: styles.cellDetailsLine }, colCustom),
959
- that.objects[id]?.type === 'state' && (React.createElement("div", { style: styles.cellDetailsLine },
960
- React.createElement("span", { style: styles.cellDetailsName },
961
- that.texts.value,
962
- ":"),
963
- colValue,
964
- React.createElement("div", { style: { flexGrow: 1 } }),
965
- React.createElement(IconCopy, { className: "copyButton", style: styles.cellCopyButtonInDetails, onClick: e => {
966
- const { valText } = formatValue({
967
- state: that.states[id],
968
- obj: that.objects[id],
969
- texts: that.texts,
970
- dateFormat: that.props.dateFormat ||
971
- that.systemConfig?.common.dateFormat ||
972
- DEFAULT_DATE_FORMAT,
973
- isFloatComma: that.props.isFloatComma === undefined
974
- ? (that.systemConfig?.common.isFloatComma ?? true)
975
- : that.props.isFloatComma,
976
- });
977
- that.onCopy(e, valText.c !== undefined ? valText.c : valText.v.toString());
978
- }, key: "cc" }),
979
- valueEditable ? (React.createElement(IconEdit, { style: styles.cellCopyButtonInDetails, onClick: editValue, key: "ce" })) : null)),
980
- colButtons && React.createElement("div", { style: { ...styles.cellDetailsLine, justifyContent: 'right' } }, colButtons)));
938
+ key: `details_${id}`, elevation: 0, sx: styles.cellDetails },
939
+ React.createElement("div", { style: {
940
+ ...styles.cellDetailsHeader,
941
+ ...(hasLines ? styles.cellDetailsHeaderWithLines : undefined),
942
+ } },
943
+ React.createElement(Box, { sx: styles.cellDetailsId }, id),
944
+ React.createElement(Tooltip, { title: copyTitle, slotProps: { popper: { sx: styles.tooltip } } },
945
+ React.createElement(IconButton, { size: "small", sx: styles.cellDetailsButton, onClick: e => that.onCopy(e, id) }, copyIcon))),
946
+ colName
947
+ ? detailsLine('name', that.texts.name, colName, item.data?.title
948
+ ? [{ title: copyTitle, icon: copyIcon, onClick: e => that.onCopy(e, item.data?.title) }]
949
+ : [])
950
+ : null,
951
+ colMiddle?.map(it => it
952
+ ? detailsLine(it.type, that.texts[it.type], it.type in middleTexts && !middleTexts[it.type] ? null : it.el, it.onClick
953
+ ? [
954
+ {
955
+ title: that.props.t(editTitles[it.type] || 'ra_Edit'),
956
+ icon: editIcon,
957
+ onClick: () => it.onClick?.(),
958
+ },
959
+ ]
960
+ : [])
961
+ : null),
962
+ colCustom ? React.createElement("div", { style: styles.cellDetailsLine }, colCustom) : null,
963
+ that.objects[id]?.type === 'state'
964
+ ? // an editable state without value has its own edit button here, so show a dash instead of the empty cell
965
+ detailsLine('value', that.texts.value, columnValue ? colValue : null, [
966
+ {
967
+ title: that.texts.copyState,
968
+ icon: copyIcon,
969
+ onClick: e => {
970
+ const { valText } = formatValue({
971
+ state: that.states[id],
972
+ obj: that.objects[id],
973
+ texts: that.texts,
974
+ dateFormat: that.props.dateFormat ||
975
+ that.systemConfig?.common.dateFormat ||
976
+ DEFAULT_DATE_FORMAT,
977
+ isFloatComma: that.props.isFloatComma === undefined
978
+ ? (that.systemConfig?.common.isFloatComma ?? true)
979
+ : that.props.isFloatComma,
980
+ });
981
+ that.onCopy(e, valText.c !== undefined ? valText.c : valText.v.toString());
982
+ },
983
+ },
984
+ // Tapping the value itself only works when there is something to tap on -
985
+ // a state that was never written renders nothing
986
+ ...(valueEditable
987
+ ? [{ title: that.props.t('ra_Edit value'), icon: editIcon, onClick: editValue }]
988
+ : []),
989
+ ])
990
+ : null,
991
+ colButtons ? React.createElement(Box, { sx: styles.cellDetailsButtons }, colButtons) : null));
981
992
  colName = null;
982
993
  colMiddle = null;
983
994
  colCustom = null;