@matrix-widget-toolkit/mui 1.0.7 → 1.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.
@@ -1,19 +1,20 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var react = require('@matrix-widget-toolkit/react');
5
4
  var material = require('@mui/material');
6
- var utils = require('@mui/utils');
7
- var reactI18next = require('react-i18next');
8
- var reactUse = require('react-use');
9
- var ErrorIcon = require('@mui/icons-material/Error');
10
5
  require('@fontsource/inter/400.css');
11
6
  require('@fontsource/inter/600.css');
7
+ var react$1 = require('@matrix-widget-toolkit/react');
12
8
  var locale = require('@mui/material/locale');
9
+ var utils = require('@mui/utils');
13
10
  var i18n = require('i18next');
14
11
  var react$2 = require('react');
15
12
  var createCache = require('@emotion/cache');
16
- var react$1 = require('@emotion/react');
13
+ var react = require('@emotion/react');
14
+ var lodash = require('lodash');
15
+ var reactI18next = require('react-i18next');
16
+ var reactUse = require('react-use');
17
+ var ErrorIcon = require('@mui/icons-material/Error');
17
18
  var CheckOutlinedIcon = require('@mui/icons-material/CheckOutlined');
18
19
  var ContentCopyOutlinedIcon = require('@mui/icons-material/ContentCopyOutlined');
19
20
  var api = require('@matrix-widget-toolkit/api');
@@ -22,72 +23,14 @@ var resourcesToBackend = require('i18next-resources-to-backend');
22
23
 
23
24
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
24
25
 
25
- var ErrorIcon__default = /*#__PURE__*/_interopDefaultCompat(ErrorIcon);
26
26
  var i18n__default = /*#__PURE__*/_interopDefaultCompat(i18n);
27
27
  var createCache__default = /*#__PURE__*/_interopDefaultCompat(createCache);
28
+ var ErrorIcon__default = /*#__PURE__*/_interopDefaultCompat(ErrorIcon);
28
29
  var CheckOutlinedIcon__default = /*#__PURE__*/_interopDefaultCompat(CheckOutlinedIcon);
29
30
  var ContentCopyOutlinedIcon__default = /*#__PURE__*/_interopDefaultCompat(ContentCopyOutlinedIcon);
30
31
  var LanguageDetector__default = /*#__PURE__*/_interopDefaultCompat(LanguageDetector);
31
32
  var resourcesToBackend__default = /*#__PURE__*/_interopDefaultCompat(resourcesToBackend);
32
33
 
33
- var __assign$a = (undefined && undefined.__assign) || function () {
34
- __assign$a = Object.assign || function(t) {
35
- for (var s, i = 1, n = arguments.length; i < n; i++) {
36
- s = arguments[i];
37
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
38
- t[p] = s[p];
39
- }
40
- return t;
41
- };
42
- return __assign$a.apply(this, arguments);
43
- };
44
- function LoadingView() {
45
- var id = utils.unstable_useId();
46
- var isLongLoad = reactUse.useTimeout(100)[0];
47
- var t = reactI18next.useTranslation('widget-toolkit').t;
48
- return isLongLoad() ? (jsxRuntime.jsxs(material.Box, __assign$a({ display: "flex", flexDirection: "column", alignItems: "center", p: 2 }, { children: [jsxRuntime.jsx(material.CircularProgress, { "aria-labelledby": id }), jsxRuntime.jsx(material.Typography, __assign$a({ py: 2, variant: "h6", id: id }, { children: t('loading.message', 'Loading…') }))] }))) : (jsxRuntime.jsx(jsxRuntime.Fragment, {}));
49
- }
50
-
51
- var __assign$9 = (undefined && undefined.__assign) || function () {
52
- __assign$9 = Object.assign || function(t) {
53
- for (var s, i = 1, n = arguments.length; i < n; i++) {
54
- s = arguments[i];
55
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
56
- t[p] = s[p];
57
- }
58
- return t;
59
- };
60
- return __assign$9.apply(this, arguments);
61
- };
62
- function MissingCapabilitiesError(_a) {
63
- var onRetry = _a.onRetry;
64
- var t = reactI18next.useTranslation('widget-toolkit').t;
65
- return (jsxRuntime.jsx(material.Box, __assign$9({ my: 2 }, { children: jsxRuntime.jsxs(material.Alert, __assign$9({ severity: "error", icon: jsxRuntime.jsx(ErrorIcon__default.default, {}) }, { children: [jsxRuntime.jsx(material.AlertTitle, { children: t('missing-capabilities.title', 'Missing capabilities') }), jsxRuntime.jsx(material.Typography, __assign$9({ variant: "body2" }, { children: t('missing-capabilities.instructions', 'The minimum capabilities required for this widget are missing. Make sure to grant all requested capabilities.') })), jsxRuntime.jsx(material.Box, __assign$9({ mt: 1 }, { children: jsxRuntime.jsx(material.Button, __assign$9({ variant: "contained", onClick: onRetry }, { children: t('missing-capabilities.request-capabilities', 'Request capabilities') })) }))] })) })));
66
- }
67
-
68
- var __assign$8 = (undefined && undefined.__assign) || function () {
69
- __assign$8 = Object.assign || function(t) {
70
- for (var s, i = 1, n = arguments.length; i < n; i++) {
71
- s = arguments[i];
72
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
73
- t[p] = s[p];
74
- }
75
- return t;
76
- };
77
- return __assign$8.apply(this, arguments);
78
- };
79
- /**
80
- * A guard that ask the user for capabilities and only shows the `children`
81
- * if all capabilities were accepted.
82
- * If capabilities are denined, a message and a button to retry is displayed
83
- * instead.
84
- * @param param0 - {@link MuiCapabilitiesGuardProps}
85
- */
86
- function MuiCapabilitiesGuard(_a) {
87
- var capabilities = _a.capabilities, children = _a.children;
88
- return (jsxRuntime.jsx(react.CapabilitiesGuard, __assign$8({ capabilities: capabilities, loadingComponent: LoadingView, missingCapabilitiesComponent: MissingCapabilitiesError }, { children: children })));
89
- }
90
-
91
34
  /*
92
35
  * Copyright 2022 Nordeck IT + Consulting GmbH
93
36
  *
@@ -149,8 +92,8 @@ function getNonce() {
149
92
  return window['NONCE'];
150
93
  }
151
94
 
152
- var __assign$7 = (undefined && undefined.__assign) || function () {
153
- __assign$7 = Object.assign || function(t) {
95
+ var __assign$b = (undefined && undefined.__assign) || function () {
96
+ __assign$b = Object.assign || function(t) {
154
97
  for (var s, i = 1, n = arguments.length; i < n; i++) {
155
98
  s = arguments[i];
156
99
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
@@ -158,7 +101,7 @@ var __assign$7 = (undefined && undefined.__assign) || function () {
158
101
  }
159
102
  return t;
160
103
  };
161
- return __assign$7.apply(this, arguments);
104
+ return __assign$b.apply(this, arguments);
162
105
  };
163
106
  function createEmotionCache() {
164
107
  return createCache__default.default({
@@ -169,7 +112,7 @@ function createEmotionCache() {
169
112
  var cache = createEmotionCache();
170
113
  function EmotionCacheProvider(_a) {
171
114
  var children = _a.children;
172
- return jsxRuntime.jsx(react$1.CacheProvider, __assign$7({ value: cache }, { children: children }));
115
+ return jsxRuntime.jsx(react.CacheProvider, __assign$b({ value: cache }, { children: children }));
173
116
  }
174
117
 
175
118
  /*
@@ -473,6 +416,19 @@ var baseTheme = {
473
416
  },
474
417
  },
475
418
  },
419
+ MuiTableCell: {
420
+ styleOverrides: {
421
+ root: function (_a) {
422
+ var theme = _a.theme;
423
+ return ({
424
+ // the default theme lightens and darkens the divider color further
425
+ // which makes it too light in the light theme and too dark in the
426
+ // dark theme.
427
+ borderBottomColor: theme.palette.divider,
428
+ });
429
+ },
430
+ },
431
+ },
476
432
  },
477
433
  };
478
434
  var lightTheme = {
@@ -657,8 +613,8 @@ var darkTheme = {
657
613
  },
658
614
  };
659
615
 
660
- var __assign$6 = (undefined && undefined.__assign) || function () {
661
- __assign$6 = Object.assign || function(t) {
616
+ var __assign$a = (undefined && undefined.__assign) || function () {
617
+ __assign$a = Object.assign || function(t) {
662
618
  for (var s, i = 1, n = arguments.length; i < n; i++) {
663
619
  s = arguments[i];
664
620
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
@@ -666,7 +622,7 @@ var __assign$6 = (undefined && undefined.__assign) || function () {
666
622
  }
667
623
  return t;
668
624
  };
669
- return __assign$6.apply(this, arguments);
625
+ return __assign$a.apply(this, arguments);
670
626
  };
671
627
  /**
672
628
  * Provide a semantic UI based theme to the child components.
@@ -674,7 +630,7 @@ var __assign$6 = (undefined && undefined.__assign) || function () {
674
630
  */
675
631
  function MuiThemeProvider(_a) {
676
632
  var children = _a.children;
677
- return (jsxRuntime.jsx(EmotionCacheProvider, { children: jsxRuntime.jsx(react.ThemeSelectionProvider, { children: jsxRuntime.jsx(ElementMuiThemeProvider, { children: children }) }) }));
633
+ return (jsxRuntime.jsx(EmotionCacheProvider, { children: jsxRuntime.jsx(react$1.ThemeSelectionProvider, { children: jsxRuntime.jsx(ElementMuiThemeProvider, { children: children }) }) }));
678
634
  }
679
635
  function chooseTheme(theme) {
680
636
  var isDark = theme === 'dark';
@@ -693,7 +649,7 @@ function chooseTheme(theme) {
693
649
  function ElementMuiThemeProvider(_a) {
694
650
  var _b;
695
651
  var children = _a.children;
696
- var theme = react.useThemeSelection().theme;
652
+ var theme = react$1.useThemeSelection().theme;
697
653
  var _c = react$2.useState((_b = i18n__default.default.languages) === null || _b === void 0 ? void 0 : _b[0]), locale$1 = _c[0], setLocale = _c[1];
698
654
  react$2.useEffect(function () {
699
655
  var callback = function () { var _a; return setLocale((_a = i18n__default.default.languages) === null || _a === void 0 ? void 0 : _a[0]); };
@@ -705,7 +661,192 @@ function ElementMuiThemeProvider(_a) {
705
661
  var localeOptions = locale$1 && new Intl.Locale(locale$1).language === 'de' ? locale.deDE : locale.enUS;
706
662
  return material.createTheme(utils.deepmerge(baseTheme, themeOptions), localeOptions);
707
663
  }, [locale$1, theme]);
708
- return (jsxRuntime.jsxs(material.ThemeProvider, __assign$6({ theme: muiTheme }, { children: [jsxRuntime.jsx(material.CssBaseline, {}), children] })));
664
+ return (jsxRuntime.jsxs(material.ThemeProvider, __assign$a({ theme: muiTheme }, { children: [jsxRuntime.jsx(material.CssBaseline, {}), children] })));
665
+ }
666
+
667
+ /*
668
+ * Copyright 2022 Nordeck IT + Consulting GmbH
669
+ *
670
+ * Licensed under the Apache License, Version 2.0 (the "License");
671
+ * you may not use this file except in compliance with the License.
672
+ * You may obtain a copy of the License at
673
+ *
674
+ * http://www.apache.org/licenses/LICENSE-2.0
675
+ *
676
+ * Unless required by applicable law or agreed to in writing, software
677
+ * distributed under the License is distributed on an "AS IS" BASIS,
678
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
679
+ * See the License for the specific language governing permissions and
680
+ * limitations under the License.
681
+ */
682
+ function createAvatarUrl(url, _a) {
683
+ var _b = _a === void 0 ? {} : _a, _c = _b.size, size = _c === void 0 ? 60 : _c;
684
+ var mxcUrl = new URL(url);
685
+ if (mxcUrl.protocol.toLowerCase() !== 'mxc:') {
686
+ return url;
687
+ }
688
+ // TODO: Instead of retrieving the home server from an env variable, it would
689
+ // be good to get this passed by the widget host, e.g. as an URL parameter.
690
+ // In general our tight CSP makes it difficult to load images from this
691
+ // source.
692
+ // We could already access the home server URL by using the domain part of the
693
+ // current users id and resolving the home server URL from the well-known
694
+ // endpoint. However, this would also require a broad connect-src in the CSP.
695
+ var homeServer = getEnvironment('REACT_APP_HOME_SERVER_URL', 'https://matrix-client.matrix.org');
696
+ var imageUrl = new URL("/_matrix/media/r0/thumbnail/".concat(mxcUrl.hostname).concat(mxcUrl.pathname, "?width=").concat(size, "&height=").concat(size, "&method=crop"), homeServer);
697
+ return imageUrl.toString();
698
+ }
699
+
700
+ /*
701
+ * Copyright 2022 Nordeck IT + Consulting GmbH
702
+ *
703
+ * Licensed under the Apache License, Version 2.0 (the "License");
704
+ * you may not use this file except in compliance with the License.
705
+ * You may obtain a copy of the License at
706
+ *
707
+ * http://www.apache.org/licenses/LICENSE-2.0
708
+ *
709
+ * Unless required by applicable law or agreed to in writing, software
710
+ * distributed under the License is distributed on an "AS IS" BASIS,
711
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
712
+ * See the License for the specific language governing permissions and
713
+ * limitations under the License.
714
+ */
715
+ function getColor(id) {
716
+ // Same colors and algorithm as Element is using, to get the same results:
717
+ // https://github.com/matrix-org/matrix-react-sdk/blob/667ec166d736dfb0ac49f67398a8b7a13db7d5ef/src/Avatar.ts#L91
718
+ var defaultColors = ['#0DBD8B', '#368bd6', '#ac3ba8'];
719
+ var total = 0;
720
+ for (var i = 0; i < id.length; ++i) {
721
+ total += id.charCodeAt(i);
722
+ }
723
+ var colorIndex = total % defaultColors.length;
724
+ return defaultColors[colorIndex];
725
+ }
726
+
727
+ /*
728
+ * Copyright 2022 Nordeck IT + Consulting GmbH
729
+ *
730
+ * Licensed under the Apache License, Version 2.0 (the "License");
731
+ * you may not use this file except in compliance with the License.
732
+ * You may obtain a copy of the License at
733
+ *
734
+ * http://www.apache.org/licenses/LICENSE-2.0
735
+ *
736
+ * Unless required by applicable law or agreed to in writing, software
737
+ * distributed under the License is distributed on an "AS IS" BASIS,
738
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
739
+ * See the License for the specific language governing permissions and
740
+ * limitations under the License.
741
+ */
742
+ // Based on the way Element selects the initial letter
743
+ // https://github.com/matrix-org/matrix-react-sdk/blob/667ec166d736dfb0ac49f67398a8b7a13db7d5ef/src/Avatar.ts#L121
744
+ function getInitialLetter(name) {
745
+ if (name.length < 1) {
746
+ return undefined;
747
+ }
748
+ var initial = name[0];
749
+ if ((initial === '@' || initial === '#' || initial === '+') && name[1]) {
750
+ name = name.substring(1);
751
+ }
752
+ // rely on the grapheme cluster splitter in lodash so that we don't break apart compound emojis
753
+ return lodash.split(name, '', 1)[0].toUpperCase();
754
+ }
755
+
756
+ var __assign$9 = (undefined && undefined.__assign) || function () {
757
+ __assign$9 = Object.assign || function(t) {
758
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
759
+ s = arguments[i];
760
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
761
+ t[p] = s[p];
762
+ }
763
+ return t;
764
+ };
765
+ return __assign$9.apply(this, arguments);
766
+ };
767
+ var StyledAvatar = material.styled(material.Avatar, {
768
+ shouldForwardProp: function (p) { return p !== 'color'; },
769
+ })(function (_a) {
770
+ var theme = _a.theme, color = _a.color;
771
+ return ({
772
+ // increase the specificity of the css selector to override styles of
773
+ // chip or button components that provide their own css for avatars.
774
+ '&, &&.MuiChip-avatar': {
775
+ fontSize: 18,
776
+ background: color,
777
+ color: theme.palette.common.white,
778
+ },
779
+ width: 24,
780
+ height: 24,
781
+ });
782
+ });
783
+ /**
784
+ * A component to display user and room avatars in the style of Element.
785
+ * @param param0 - {@link ElementAvatarProps}
786
+ */
787
+ function ElementAvatar(_a) {
788
+ var avatarUrl = _a.avatarUrl, userId = _a.userId, displayName = _a.displayName, sx = _a.sx;
789
+ var src = avatarUrl ? createAvatarUrl(avatarUrl) : undefined;
790
+ var name = displayName !== null && displayName !== void 0 ? displayName : userId;
791
+ return (jsxRuntime.jsx(StyledAvatar, __assign$9({ alt: "", "aria-hidden": true, src: src, color: getColor(userId), sx: sx }, { children: getInitialLetter(name) })));
792
+ }
793
+
794
+ var __assign$8 = (undefined && undefined.__assign) || function () {
795
+ __assign$8 = Object.assign || function(t) {
796
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
797
+ s = arguments[i];
798
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
799
+ t[p] = s[p];
800
+ }
801
+ return t;
802
+ };
803
+ return __assign$8.apply(this, arguments);
804
+ };
805
+ function LoadingView() {
806
+ var id = utils.unstable_useId();
807
+ var isLongLoad = reactUse.useTimeout(100)[0];
808
+ var t = reactI18next.useTranslation('widget-toolkit').t;
809
+ return isLongLoad() ? (jsxRuntime.jsxs(material.Box, __assign$8({ display: "flex", flexDirection: "column", alignItems: "center", p: 2 }, { children: [jsxRuntime.jsx(material.CircularProgress, { "aria-labelledby": id }), jsxRuntime.jsx(material.Typography, __assign$8({ py: 2, variant: "h6", id: id }, { children: t('loading.message', 'Loading…') }))] }))) : (jsxRuntime.jsx(jsxRuntime.Fragment, {}));
810
+ }
811
+
812
+ var __assign$7 = (undefined && undefined.__assign) || function () {
813
+ __assign$7 = Object.assign || function(t) {
814
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
815
+ s = arguments[i];
816
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
817
+ t[p] = s[p];
818
+ }
819
+ return t;
820
+ };
821
+ return __assign$7.apply(this, arguments);
822
+ };
823
+ function MissingCapabilitiesError(_a) {
824
+ var onRetry = _a.onRetry;
825
+ var t = reactI18next.useTranslation('widget-toolkit').t;
826
+ return (jsxRuntime.jsx(material.Box, __assign$7({ my: 2 }, { children: jsxRuntime.jsxs(material.Alert, __assign$7({ severity: "error", icon: jsxRuntime.jsx(ErrorIcon__default.default, {}) }, { children: [jsxRuntime.jsx(material.AlertTitle, { children: t('missing-capabilities.title', 'Missing capabilities') }), jsxRuntime.jsx(material.Typography, __assign$7({ variant: "body2" }, { children: t('missing-capabilities.instructions', 'The minimum capabilities required for this widget are missing. Make sure to grant all requested capabilities.') })), jsxRuntime.jsx(material.Box, __assign$7({ mt: 1 }, { children: jsxRuntime.jsx(material.Button, __assign$7({ variant: "contained", onClick: onRetry }, { children: t('missing-capabilities.request-capabilities', 'Request capabilities') })) }))] })) })));
827
+ }
828
+
829
+ var __assign$6 = (undefined && undefined.__assign) || function () {
830
+ __assign$6 = Object.assign || function(t) {
831
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
832
+ s = arguments[i];
833
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
834
+ t[p] = s[p];
835
+ }
836
+ return t;
837
+ };
838
+ return __assign$6.apply(this, arguments);
839
+ };
840
+ /**
841
+ * A guard that ask the user for capabilities and only shows the `children`
842
+ * if all capabilities were accepted.
843
+ * If capabilities are denied, a message and a button to retry is displayed
844
+ * instead.
845
+ * @param param0 - {@link MuiCapabilitiesGuardProps}
846
+ */
847
+ function MuiCapabilitiesGuard(_a) {
848
+ var capabilities = _a.capabilities, children = _a.children;
849
+ return (jsxRuntime.jsx(react$1.CapabilitiesGuard, __assign$6({ capabilities: capabilities, loadingComponent: LoadingView, missingCapabilitiesComponent: MissingCapabilitiesError }, { children: children })));
709
850
  }
710
851
 
711
852
  var __assign$5 = (undefined && undefined.__assign) || function () {
@@ -803,7 +944,7 @@ function MissingParametersError(_a) {
803
944
  var _this = this;
804
945
  var widgetRegistration = _a.widgetRegistration;
805
946
  var t = reactI18next.useTranslation('widget-toolkit').t;
806
- var widgetApi = react.useWidgetApi();
947
+ var widgetApi = react$1.useWidgetApi();
807
948
  var _b = react$2.useState(false), isErrorDialogOpen = _b[0], setErrorDialogOpen = _b[1];
808
949
  var _c = react$2.useState(false), isCompleted = _c[0], setCompleted = _c[1];
809
950
  var handleRepairWidget = react$2.useCallback(function () { return __awaiter(_this, void 0, void 0, function () {
@@ -884,7 +1025,7 @@ var __assign = (undefined && undefined.__assign) || function () {
884
1025
  */
885
1026
  function MuiWidgetApiProvider(_a) {
886
1027
  var widgetRegistration = _a.widgetRegistration, widgetApiPromise = _a.widgetApiPromise, children = _a.children;
887
- return (jsxRuntime.jsx(react.WidgetApiProvider, __assign({ widgetApiPromise: widgetApiPromise, widgetRegistration: widgetRegistration, loadingViewComponent: LoadingView, mobileClientErrorComponent: MobileClientError, childErrorComponent: ChildError, outsideClientErrorComponent: OutsideClientError, missingCapabilitiesComponent: MissingCapabilitiesError, missingParametersErrorComponent: MissingParametersError }, { children: children })));
1028
+ return (jsxRuntime.jsx(react$1.WidgetApiProvider, __assign({ widgetApiPromise: widgetApiPromise, widgetRegistration: widgetRegistration, loadingViewComponent: LoadingView, mobileClientErrorComponent: MobileClientError, childErrorComponent: ChildError, outsideClientErrorComponent: OutsideClientError, missingCapabilitiesComponent: MissingCapabilitiesError, missingParametersErrorComponent: MissingParametersError }, { children: children })));
888
1029
  }
889
1030
 
890
1031
  /*
@@ -949,6 +1090,7 @@ var WidgetApiLanguageDetector = /** @class */ (function (_super) {
949
1090
  return WidgetApiLanguageDetector;
950
1091
  }(LanguageDetector__default.default));
951
1092
 
1093
+ exports.ElementAvatar = ElementAvatar;
952
1094
  exports.MuiCapabilitiesGuard = MuiCapabilitiesGuard;
953
1095
  exports.MuiThemeProvider = MuiThemeProvider;
954
1096
  exports.MuiWidgetApiProvider = MuiWidgetApiProvider;
@@ -1,81 +1,24 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { CapabilitiesGuard, ThemeSelectionProvider, useThemeSelection, useWidgetApi, WidgetApiProvider } from '@matrix-widget-toolkit/react';
3
- import { Box, CircularProgress, Typography, Alert, AlertTitle, Button, createTheme, ThemeProvider, CssBaseline, Paper, IconButton, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material';
4
- import { unstable_useId, deepmerge } from '@mui/utils';
5
- import { useTranslation } from 'react-i18next';
6
- import { useTimeout, useCopyToClipboard } from 'react-use';
7
- import ErrorIcon from '@mui/icons-material/Error';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { createTheme, ThemeProvider, CssBaseline, styled, Avatar, Box, CircularProgress, Typography, Alert, AlertTitle, Button, Paper, IconButton, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } from '@mui/material';
8
3
  import '@fontsource/inter/400.css';
9
4
  import '@fontsource/inter/600.css';
5
+ import { ThemeSelectionProvider, useThemeSelection, CapabilitiesGuard, useWidgetApi, WidgetApiProvider } from '@matrix-widget-toolkit/react';
10
6
  import { deDE, enUS } from '@mui/material/locale';
7
+ import { deepmerge, unstable_useId } from '@mui/utils';
11
8
  import i18n from 'i18next';
12
9
  import { useState, useEffect, useMemo, useCallback } from 'react';
13
10
  import createCache from '@emotion/cache';
14
11
  import { CacheProvider } from '@emotion/react';
12
+ import { split } from 'lodash';
13
+ import { useTranslation } from 'react-i18next';
14
+ import { useTimeout, useCopyToClipboard } from 'react-use';
15
+ import ErrorIcon from '@mui/icons-material/Error';
15
16
  import CheckOutlinedIcon from '@mui/icons-material/CheckOutlined';
16
17
  import ContentCopyOutlinedIcon from '@mui/icons-material/ContentCopyOutlined';
17
18
  import { repairWidgetRegistration, generateWidgetRegistrationUrl, extractWidgetParameters } from '@matrix-widget-toolkit/api';
18
19
  import LanguageDetector from 'i18next-browser-languagedetector';
19
20
  import resourcesToBackend from 'i18next-resources-to-backend';
20
21
 
21
- var __assign$a = (undefined && undefined.__assign) || function () {
22
- __assign$a = Object.assign || function(t) {
23
- for (var s, i = 1, n = arguments.length; i < n; i++) {
24
- s = arguments[i];
25
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
26
- t[p] = s[p];
27
- }
28
- return t;
29
- };
30
- return __assign$a.apply(this, arguments);
31
- };
32
- function LoadingView() {
33
- var id = unstable_useId();
34
- var isLongLoad = useTimeout(100)[0];
35
- var t = useTranslation('widget-toolkit').t;
36
- return isLongLoad() ? (jsxs(Box, __assign$a({ display: "flex", flexDirection: "column", alignItems: "center", p: 2 }, { children: [jsx(CircularProgress, { "aria-labelledby": id }), jsx(Typography, __assign$a({ py: 2, variant: "h6", id: id }, { children: t('loading.message', 'Loading…') }))] }))) : (jsx(Fragment, {}));
37
- }
38
-
39
- var __assign$9 = (undefined && undefined.__assign) || function () {
40
- __assign$9 = Object.assign || function(t) {
41
- for (var s, i = 1, n = arguments.length; i < n; i++) {
42
- s = arguments[i];
43
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
44
- t[p] = s[p];
45
- }
46
- return t;
47
- };
48
- return __assign$9.apply(this, arguments);
49
- };
50
- function MissingCapabilitiesError(_a) {
51
- var onRetry = _a.onRetry;
52
- var t = useTranslation('widget-toolkit').t;
53
- return (jsx(Box, __assign$9({ my: 2 }, { children: jsxs(Alert, __assign$9({ severity: "error", icon: jsx(ErrorIcon, {}) }, { children: [jsx(AlertTitle, { children: t('missing-capabilities.title', 'Missing capabilities') }), jsx(Typography, __assign$9({ variant: "body2" }, { children: t('missing-capabilities.instructions', 'The minimum capabilities required for this widget are missing. Make sure to grant all requested capabilities.') })), jsx(Box, __assign$9({ mt: 1 }, { children: jsx(Button, __assign$9({ variant: "contained", onClick: onRetry }, { children: t('missing-capabilities.request-capabilities', 'Request capabilities') })) }))] })) })));
54
- }
55
-
56
- var __assign$8 = (undefined && undefined.__assign) || function () {
57
- __assign$8 = Object.assign || function(t) {
58
- for (var s, i = 1, n = arguments.length; i < n; i++) {
59
- s = arguments[i];
60
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
61
- t[p] = s[p];
62
- }
63
- return t;
64
- };
65
- return __assign$8.apply(this, arguments);
66
- };
67
- /**
68
- * A guard that ask the user for capabilities and only shows the `children`
69
- * if all capabilities were accepted.
70
- * If capabilities are denined, a message and a button to retry is displayed
71
- * instead.
72
- * @param param0 - {@link MuiCapabilitiesGuardProps}
73
- */
74
- function MuiCapabilitiesGuard(_a) {
75
- var capabilities = _a.capabilities, children = _a.children;
76
- return (jsx(CapabilitiesGuard, __assign$8({ capabilities: capabilities, loadingComponent: LoadingView, missingCapabilitiesComponent: MissingCapabilitiesError }, { children: children })));
77
- }
78
-
79
22
  /*
80
23
  * Copyright 2022 Nordeck IT + Consulting GmbH
81
24
  *
@@ -137,8 +80,8 @@ function getNonce() {
137
80
  return window['NONCE'];
138
81
  }
139
82
 
140
- var __assign$7 = (undefined && undefined.__assign) || function () {
141
- __assign$7 = Object.assign || function(t) {
83
+ var __assign$b = (undefined && undefined.__assign) || function () {
84
+ __assign$b = Object.assign || function(t) {
142
85
  for (var s, i = 1, n = arguments.length; i < n; i++) {
143
86
  s = arguments[i];
144
87
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
@@ -146,7 +89,7 @@ var __assign$7 = (undefined && undefined.__assign) || function () {
146
89
  }
147
90
  return t;
148
91
  };
149
- return __assign$7.apply(this, arguments);
92
+ return __assign$b.apply(this, arguments);
150
93
  };
151
94
  function createEmotionCache() {
152
95
  return createCache({
@@ -157,7 +100,7 @@ function createEmotionCache() {
157
100
  var cache = createEmotionCache();
158
101
  function EmotionCacheProvider(_a) {
159
102
  var children = _a.children;
160
- return jsx(CacheProvider, __assign$7({ value: cache }, { children: children }));
103
+ return jsx(CacheProvider, __assign$b({ value: cache }, { children: children }));
161
104
  }
162
105
 
163
106
  /*
@@ -461,6 +404,19 @@ var baseTheme = {
461
404
  },
462
405
  },
463
406
  },
407
+ MuiTableCell: {
408
+ styleOverrides: {
409
+ root: function (_a) {
410
+ var theme = _a.theme;
411
+ return ({
412
+ // the default theme lightens and darkens the divider color further
413
+ // which makes it too light in the light theme and too dark in the
414
+ // dark theme.
415
+ borderBottomColor: theme.palette.divider,
416
+ });
417
+ },
418
+ },
419
+ },
464
420
  },
465
421
  };
466
422
  var lightTheme = {
@@ -645,8 +601,8 @@ var darkTheme = {
645
601
  },
646
602
  };
647
603
 
648
- var __assign$6 = (undefined && undefined.__assign) || function () {
649
- __assign$6 = Object.assign || function(t) {
604
+ var __assign$a = (undefined && undefined.__assign) || function () {
605
+ __assign$a = Object.assign || function(t) {
650
606
  for (var s, i = 1, n = arguments.length; i < n; i++) {
651
607
  s = arguments[i];
652
608
  for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
@@ -654,7 +610,7 @@ var __assign$6 = (undefined && undefined.__assign) || function () {
654
610
  }
655
611
  return t;
656
612
  };
657
- return __assign$6.apply(this, arguments);
613
+ return __assign$a.apply(this, arguments);
658
614
  };
659
615
  /**
660
616
  * Provide a semantic UI based theme to the child components.
@@ -693,7 +649,192 @@ function ElementMuiThemeProvider(_a) {
693
649
  var localeOptions = locale && new Intl.Locale(locale).language === 'de' ? deDE : enUS;
694
650
  return createTheme(deepmerge(baseTheme, themeOptions), localeOptions);
695
651
  }, [locale, theme]);
696
- return (jsxs(ThemeProvider, __assign$6({ theme: muiTheme }, { children: [jsx(CssBaseline, {}), children] })));
652
+ return (jsxs(ThemeProvider, __assign$a({ theme: muiTheme }, { children: [jsx(CssBaseline, {}), children] })));
653
+ }
654
+
655
+ /*
656
+ * Copyright 2022 Nordeck IT + Consulting GmbH
657
+ *
658
+ * Licensed under the Apache License, Version 2.0 (the "License");
659
+ * you may not use this file except in compliance with the License.
660
+ * You may obtain a copy of the License at
661
+ *
662
+ * http://www.apache.org/licenses/LICENSE-2.0
663
+ *
664
+ * Unless required by applicable law or agreed to in writing, software
665
+ * distributed under the License is distributed on an "AS IS" BASIS,
666
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
667
+ * See the License for the specific language governing permissions and
668
+ * limitations under the License.
669
+ */
670
+ function createAvatarUrl(url, _a) {
671
+ var _b = _a === void 0 ? {} : _a, _c = _b.size, size = _c === void 0 ? 60 : _c;
672
+ var mxcUrl = new URL(url);
673
+ if (mxcUrl.protocol.toLowerCase() !== 'mxc:') {
674
+ return url;
675
+ }
676
+ // TODO: Instead of retrieving the home server from an env variable, it would
677
+ // be good to get this passed by the widget host, e.g. as an URL parameter.
678
+ // In general our tight CSP makes it difficult to load images from this
679
+ // source.
680
+ // We could already access the home server URL by using the domain part of the
681
+ // current users id and resolving the home server URL from the well-known
682
+ // endpoint. However, this would also require a broad connect-src in the CSP.
683
+ var homeServer = getEnvironment('REACT_APP_HOME_SERVER_URL', 'https://matrix-client.matrix.org');
684
+ var imageUrl = new URL("/_matrix/media/r0/thumbnail/".concat(mxcUrl.hostname).concat(mxcUrl.pathname, "?width=").concat(size, "&height=").concat(size, "&method=crop"), homeServer);
685
+ return imageUrl.toString();
686
+ }
687
+
688
+ /*
689
+ * Copyright 2022 Nordeck IT + Consulting GmbH
690
+ *
691
+ * Licensed under the Apache License, Version 2.0 (the "License");
692
+ * you may not use this file except in compliance with the License.
693
+ * You may obtain a copy of the License at
694
+ *
695
+ * http://www.apache.org/licenses/LICENSE-2.0
696
+ *
697
+ * Unless required by applicable law or agreed to in writing, software
698
+ * distributed under the License is distributed on an "AS IS" BASIS,
699
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
700
+ * See the License for the specific language governing permissions and
701
+ * limitations under the License.
702
+ */
703
+ function getColor(id) {
704
+ // Same colors and algorithm as Element is using, to get the same results:
705
+ // https://github.com/matrix-org/matrix-react-sdk/blob/667ec166d736dfb0ac49f67398a8b7a13db7d5ef/src/Avatar.ts#L91
706
+ var defaultColors = ['#0DBD8B', '#368bd6', '#ac3ba8'];
707
+ var total = 0;
708
+ for (var i = 0; i < id.length; ++i) {
709
+ total += id.charCodeAt(i);
710
+ }
711
+ var colorIndex = total % defaultColors.length;
712
+ return defaultColors[colorIndex];
713
+ }
714
+
715
+ /*
716
+ * Copyright 2022 Nordeck IT + Consulting GmbH
717
+ *
718
+ * Licensed under the Apache License, Version 2.0 (the "License");
719
+ * you may not use this file except in compliance with the License.
720
+ * You may obtain a copy of the License at
721
+ *
722
+ * http://www.apache.org/licenses/LICENSE-2.0
723
+ *
724
+ * Unless required by applicable law or agreed to in writing, software
725
+ * distributed under the License is distributed on an "AS IS" BASIS,
726
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
727
+ * See the License for the specific language governing permissions and
728
+ * limitations under the License.
729
+ */
730
+ // Based on the way Element selects the initial letter
731
+ // https://github.com/matrix-org/matrix-react-sdk/blob/667ec166d736dfb0ac49f67398a8b7a13db7d5ef/src/Avatar.ts#L121
732
+ function getInitialLetter(name) {
733
+ if (name.length < 1) {
734
+ return undefined;
735
+ }
736
+ var initial = name[0];
737
+ if ((initial === '@' || initial === '#' || initial === '+') && name[1]) {
738
+ name = name.substring(1);
739
+ }
740
+ // rely on the grapheme cluster splitter in lodash so that we don't break apart compound emojis
741
+ return split(name, '', 1)[0].toUpperCase();
742
+ }
743
+
744
+ var __assign$9 = (undefined && undefined.__assign) || function () {
745
+ __assign$9 = Object.assign || function(t) {
746
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
747
+ s = arguments[i];
748
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
749
+ t[p] = s[p];
750
+ }
751
+ return t;
752
+ };
753
+ return __assign$9.apply(this, arguments);
754
+ };
755
+ var StyledAvatar = styled(Avatar, {
756
+ shouldForwardProp: function (p) { return p !== 'color'; },
757
+ })(function (_a) {
758
+ var theme = _a.theme, color = _a.color;
759
+ return ({
760
+ // increase the specificity of the css selector to override styles of
761
+ // chip or button components that provide their own css for avatars.
762
+ '&, &&.MuiChip-avatar': {
763
+ fontSize: 18,
764
+ background: color,
765
+ color: theme.palette.common.white,
766
+ },
767
+ width: 24,
768
+ height: 24,
769
+ });
770
+ });
771
+ /**
772
+ * A component to display user and room avatars in the style of Element.
773
+ * @param param0 - {@link ElementAvatarProps}
774
+ */
775
+ function ElementAvatar(_a) {
776
+ var avatarUrl = _a.avatarUrl, userId = _a.userId, displayName = _a.displayName, sx = _a.sx;
777
+ var src = avatarUrl ? createAvatarUrl(avatarUrl) : undefined;
778
+ var name = displayName !== null && displayName !== void 0 ? displayName : userId;
779
+ return (jsx(StyledAvatar, __assign$9({ alt: "", "aria-hidden": true, src: src, color: getColor(userId), sx: sx }, { children: getInitialLetter(name) })));
780
+ }
781
+
782
+ var __assign$8 = (undefined && undefined.__assign) || function () {
783
+ __assign$8 = Object.assign || function(t) {
784
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
785
+ s = arguments[i];
786
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
787
+ t[p] = s[p];
788
+ }
789
+ return t;
790
+ };
791
+ return __assign$8.apply(this, arguments);
792
+ };
793
+ function LoadingView() {
794
+ var id = unstable_useId();
795
+ var isLongLoad = useTimeout(100)[0];
796
+ var t = useTranslation('widget-toolkit').t;
797
+ return isLongLoad() ? (jsxs(Box, __assign$8({ display: "flex", flexDirection: "column", alignItems: "center", p: 2 }, { children: [jsx(CircularProgress, { "aria-labelledby": id }), jsx(Typography, __assign$8({ py: 2, variant: "h6", id: id }, { children: t('loading.message', 'Loading…') }))] }))) : (jsx(Fragment, {}));
798
+ }
799
+
800
+ var __assign$7 = (undefined && undefined.__assign) || function () {
801
+ __assign$7 = Object.assign || function(t) {
802
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
803
+ s = arguments[i];
804
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
805
+ t[p] = s[p];
806
+ }
807
+ return t;
808
+ };
809
+ return __assign$7.apply(this, arguments);
810
+ };
811
+ function MissingCapabilitiesError(_a) {
812
+ var onRetry = _a.onRetry;
813
+ var t = useTranslation('widget-toolkit').t;
814
+ return (jsx(Box, __assign$7({ my: 2 }, { children: jsxs(Alert, __assign$7({ severity: "error", icon: jsx(ErrorIcon, {}) }, { children: [jsx(AlertTitle, { children: t('missing-capabilities.title', 'Missing capabilities') }), jsx(Typography, __assign$7({ variant: "body2" }, { children: t('missing-capabilities.instructions', 'The minimum capabilities required for this widget are missing. Make sure to grant all requested capabilities.') })), jsx(Box, __assign$7({ mt: 1 }, { children: jsx(Button, __assign$7({ variant: "contained", onClick: onRetry }, { children: t('missing-capabilities.request-capabilities', 'Request capabilities') })) }))] })) })));
815
+ }
816
+
817
+ var __assign$6 = (undefined && undefined.__assign) || function () {
818
+ __assign$6 = Object.assign || function(t) {
819
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
820
+ s = arguments[i];
821
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
822
+ t[p] = s[p];
823
+ }
824
+ return t;
825
+ };
826
+ return __assign$6.apply(this, arguments);
827
+ };
828
+ /**
829
+ * A guard that ask the user for capabilities and only shows the `children`
830
+ * if all capabilities were accepted.
831
+ * If capabilities are denied, a message and a button to retry is displayed
832
+ * instead.
833
+ * @param param0 - {@link MuiCapabilitiesGuardProps}
834
+ */
835
+ function MuiCapabilitiesGuard(_a) {
836
+ var capabilities = _a.capabilities, children = _a.children;
837
+ return (jsx(CapabilitiesGuard, __assign$6({ capabilities: capabilities, loadingComponent: LoadingView, missingCapabilitiesComponent: MissingCapabilitiesError }, { children: children })));
697
838
  }
698
839
 
699
840
  var __assign$5 = (undefined && undefined.__assign) || function () {
@@ -937,4 +1078,4 @@ var WidgetApiLanguageDetector = /** @class */ (function (_super) {
937
1078
  return WidgetApiLanguageDetector;
938
1079
  }(LanguageDetector));
939
1080
 
940
- export { MuiCapabilitiesGuard, MuiThemeProvider, MuiWidgetApiProvider, WidgetApiLanguageDetector, WidgetToolkitI18nBackend, getEnvironment, getNonce };
1081
+ export { ElementAvatar, MuiCapabilitiesGuard, MuiThemeProvider, MuiWidgetApiProvider, WidgetApiLanguageDetector, WidgetToolkitI18nBackend, getEnvironment, getNonce };
package/build/index.d.ts CHANGED
@@ -3,15 +3,49 @@
3
3
  * the default Element theme.
4
4
  */
5
5
 
6
+ /// <reference types="react" />
7
+
6
8
  import { BackendModule } from 'i18next';
7
9
  import { Capability } from 'matrix-widget-api';
8
10
  import LanguageDetector from 'i18next-browser-languagedetector';
9
11
  import { PropsWithChildren } from 'react';
10
12
  import { ReactElement } from 'react';
13
+ import { SxProps } from '@mui/material';
14
+ import { Theme } from '@mui/material';
11
15
  import { WidgetApi } from '@matrix-widget-toolkit/api';
12
16
  import { WidgetEventCapability } from 'matrix-widget-api';
13
17
  import { WidgetRegistration } from '@matrix-widget-toolkit/api';
14
18
 
19
+ /**
20
+ * A component to display user and room avatars in the style of Element.
21
+ * @param param0 - {@link ElementAvatarProps}
22
+ */
23
+ export declare function ElementAvatar({ avatarUrl, userId, displayName, sx, }: ElementAvatarProps): JSX.Element;
24
+
25
+ /**
26
+ * Props for the {@link ElementAvatar} component.
27
+ */
28
+ export declare type ElementAvatarProps = {
29
+ /**
30
+ * The id of the user.
31
+ * Even though the field is called userId, it can also be used to display
32
+ * avatars for rooms.
33
+ */
34
+ userId: string;
35
+ /**
36
+ * The display name of the user.
37
+ * If not provided, the userId is used instead.
38
+ */
39
+ displayName?: string;
40
+ /**
41
+ * The url of the avatar.
42
+ * If not provided, the initial letter based on the display name or userId is used instead.
43
+ */
44
+ avatarUrl?: string;
45
+ /** Additional styling for the avatar */
46
+ sx?: SxProps<Theme>;
47
+ };
48
+
15
49
  /**
16
50
  * Reads environment variables starting with `REACT_APP_` from a global variable
17
51
  * at runtime and falls back to `process.env` build time variables.
@@ -42,7 +76,7 @@ export declare function getNonce(): string | undefined;
42
76
  /**
43
77
  * A guard that ask the user for capabilities and only shows the `children`
44
78
  * if all capabilities were accepted.
45
- * If capabilities are denined, a message and a button to retry is displayed
79
+ * If capabilities are denied, a message and a button to retry is displayed
46
80
  * instead.
47
81
  * @param param0 - {@link MuiCapabilitiesGuardProps}
48
82
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@matrix-widget-toolkit/mui",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "A customized material-ui theme that matches the style of the Element Matrix client",
5
5
  "author": "Nordeck IT + Consulting GmbH",
6
6
  "license": "Apache-2.0",
@@ -14,10 +14,11 @@
14
14
  "@testing-library/user-event": "^14.4.3",
15
15
  "@types/jest": "^27.5.2",
16
16
  "@types/jest-axe": "^3.5.5",
17
- "@types/node": "^16.18.11",
17
+ "@types/lodash": "^4.14.191",
18
+ "@types/node": "^16.18.14",
18
19
  "@types/react": "^17.0.45",
19
20
  "copyfiles": "^2.4.1",
20
- "i18next-parser": "^7.2.0",
21
+ "i18next-parser": "^7.6.0",
21
22
  "jest-axe": "^7.0.0",
22
23
  "react": "^17.0.2",
23
24
  "react-scripts": "5.0.1",
@@ -49,6 +50,7 @@
49
50
  "i18next": "^22.0.4",
50
51
  "i18next-browser-languagedetector": "^7.0.1",
51
52
  "i18next-resources-to-backend": "^1.0.0",
53
+ "lodash": "^4.17.21",
52
54
  "matrix-widget-api": "^1.1.1",
53
55
  "react": "^17.0.2",
54
56
  "react-i18next": "^12.0.0",