@selfcommunity/react-ui 0.11.0-alpha.94 → 0.11.0-alpha.96
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/lib/cjs/components/BottomNavigation/BottomNavigation.js +13 -1
- package/lib/cjs/components/CategoryHeader/CategoryHeader.d.ts +6 -0
- package/lib/cjs/components/CategoryHeader/CategoryHeader.js +6 -3
- package/lib/cjs/components/NavigationMenuIconButton/DefaultDrawerContent.d.ts +1 -0
- package/lib/cjs/components/NavigationMenuIconButton/DefaultDrawerContent.js +14 -2
- package/lib/cjs/components/NavigationToolbar/NavigationToolbar.js +14 -2
- package/lib/cjs/components/NavigationToolbarMobile/NavigationToolbarMobile.js +13 -1
- package/lib/cjs/components/UserAutocomplete/UserAutocomplete.d.ts +0 -1
- package/lib/cjs/components/UserAutocomplete/UserAutocomplete.js +29 -19
- package/lib/esm/components/BottomNavigation/BottomNavigation.js +14 -2
- package/lib/esm/components/CategoryHeader/CategoryHeader.d.ts +6 -0
- package/lib/esm/components/CategoryHeader/CategoryHeader.js +6 -3
- package/lib/esm/components/NavigationMenuIconButton/DefaultDrawerContent.d.ts +1 -0
- package/lib/esm/components/NavigationMenuIconButton/DefaultDrawerContent.js +15 -3
- package/lib/esm/components/NavigationToolbar/NavigationToolbar.js +15 -3
- package/lib/esm/components/NavigationToolbarMobile/NavigationToolbarMobile.js +13 -1
- package/lib/esm/components/UserAutocomplete/UserAutocomplete.d.ts +0 -1
- package/lib/esm/components/UserAutocomplete/UserAutocomplete.js +31 -21
- package/lib/umd/react-ui.js +1 -1
- package/package.json +6 -6
|
@@ -12,6 +12,7 @@ import NavigationSettingsIconButton from '../NavigationSettingsIconButton';
|
|
|
12
12
|
import NavigationMenuIconButton from '../NavigationMenuIconButton';
|
|
13
13
|
import { PREFIX } from './constants';
|
|
14
14
|
import { SCFeatureName } from '@selfcommunity/types';
|
|
15
|
+
import { scroll } from 'seamless-scroll-polyfill';
|
|
15
16
|
import ComposerIconButton from '../ComposerIconButton';
|
|
16
17
|
const classes = {
|
|
17
18
|
root: `${PREFIX}-root`,
|
|
@@ -99,13 +100,24 @@ export default function NavigationToolbarMobile(inProps) {
|
|
|
99
100
|
const handleCloseSearch = useCallback(() => {
|
|
100
101
|
setSearchOpen(false);
|
|
101
102
|
}, [setSearchOpen]);
|
|
103
|
+
const handleClickHome = useCallback(() => {
|
|
104
|
+
if (onClickHome) {
|
|
105
|
+
onClickHome();
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const pathName = window.location.pathname;
|
|
109
|
+
if (pathName && (pathName === '/' || pathName === scRoutingContext.url(SCRoutes.HOME_ROUTE_NAME, {}))) {
|
|
110
|
+
scroll(window, { top: 0, behavior: 'smooth' });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}, [onClickHome]);
|
|
102
114
|
// RENDER
|
|
103
115
|
if (scUserContext.loading) {
|
|
104
116
|
return _jsx(NavigationToolbarMobileSkeleton, {});
|
|
105
117
|
}
|
|
106
118
|
const _children = children || (_jsxs(_Fragment, { children: [_jsx(NavigationMenuIconButtonComponent, {}), _jsx(Link, Object.assign({ to: scRoutingContext.url(SCRoutes.HOME_ROUTE_NAME, {}), className: classNames(className, classes.logo, {
|
|
107
119
|
[classes.logoFlex]: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_URL].value
|
|
108
|
-
})
|
|
120
|
+
}), onClick: handleClickHome }, { children: !preserveDesktopLogo ? (_jsx("img", { src: preferences[SCPreferences.LOGO_NAVBAR_LOGO_MOBILE].value, alt: "logo" })) : (_jsx("img", { src: preferences[SCPreferences.LOGO_NAVBAR_LOGO].value, alt: "logo" })) })), preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_ENABLED].value && (_jsx(Link, Object.assign({ target: "blank", to: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_URL].value, className: classes.customItem }, { children: _jsx("img", { src: preferences[SCPreferences.CONFIGURATIONS_CUSTOM_NAVBAR_ITEM_IMAGE].value, alt: "custom_item" }) })))] }));
|
|
109
121
|
return (_jsxs(Root, Object.assign({ className: classNames(className, classes.root) }, rest, { children: [_children, startActions, (contentAvailable || scUserContext.user) && !disableSearch && (_jsxs(_Fragment, { children: [_jsx(IconButton, Object.assign({ className: classes.search, onClick: handleOpenSearch }, { children: _jsx(Icon, { children: "search" }) })), _jsx(SearchDialog, { className: classes.searchDialog, fullScreen: true, open: searchOpen, SearchAutocompleteComponentProps: Object.assign(Object.assign({}, SearchAutocompleteComponentProps), { onClear: handleCloseSearch }) })] })), endActions, (!postOnlyStaffEnabled || UserUtils.isStaff(scUserContext.user) || UserUtils.isPublisher(scUserContext.user)) &&
|
|
110
122
|
(scUserContext.user || contentAvailable) &&
|
|
111
123
|
exploreStreamEnabled && _jsx(ComposerIconButton, Object.assign({}, ComposerIconButtonProps)), scUserContext.user && (groupsEnabled || eventsEnabled) && (_jsx(IconButton, Object.assign({ className: classes.notifications, component: Link, to: scRoutingContext.url(SCRoutes.USER_NOTIFICATIONS_ROUTE_NAME, {}) }, { children: _jsx(Badge, Object.assign({ badgeContent: scUserContext.user.unseen_notification_banners_counter + scUserContext.user.unseen_interactions_counter, color: "secondary" }, { children: _jsx(Icon, { children: "notifications_active" }) })) }))), scUserContext.user ? (_jsx(NavigationSettingsIconButtonComponent, { className: classes.settings })) : (_jsx(Button, Object.assign({ className: classes.login, color: "inherit", component: Link, to: scRoutingContext.url(SCRoutes.SIGNIN_ROUTE_NAME, {}) }, { children: _jsx(FormattedMessage, { id: "ui.appBar.navigation.login", defaultMessage: "ui.appBar.navigation.login" }) })))] })));
|
|
@@ -16,7 +16,6 @@ export interface UserAutocompleteProps extends Pick<AutocompleteProps<SCUserAuto
|
|
|
16
16
|
* @default 0
|
|
17
17
|
*/
|
|
18
18
|
limitCountGroups?: number;
|
|
19
|
-
endpointQueryParams?: Record<string, string | number | boolean>;
|
|
20
19
|
}
|
|
21
20
|
declare const UserAutocomplete: (inProps: UserAutocompleteProps) => JSX.Element;
|
|
22
21
|
export default UserAutocomplete;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { __rest } from "tslib";
|
|
1
|
+
import { __awaiter, __rest } from "tslib";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import React, { Fragment, useEffect, useState } from 'react';
|
|
3
|
+
import React, { Fragment, useEffect, useMemo, useState } from 'react';
|
|
4
4
|
import { FormattedMessage } from 'react-intl';
|
|
5
5
|
import parse from 'autosuggest-highlight/parse';
|
|
6
6
|
import match from 'autosuggest-highlight/match';
|
|
7
7
|
import { Autocomplete, Chip, TextField, CircularProgress, styled, Avatar, Box, Typography, Icon } from '@mui/material';
|
|
8
8
|
import { useSCFetchUsers } from '@selfcommunity/react-core';
|
|
9
9
|
import { useThemeProps } from '@mui/system';
|
|
10
|
+
import { UserService } from '@selfcommunity/api-services';
|
|
10
11
|
const PREFIX = 'SCUserAutocomplete';
|
|
11
12
|
const classes = {
|
|
12
13
|
root: `${PREFIX}-root`,
|
|
@@ -37,15 +38,21 @@ const UserAutocomplete = (inProps) => {
|
|
|
37
38
|
const [inputValue, setInputValue] = useState('');
|
|
38
39
|
const [value, setValue] = useState(Array.isArray(defaultValue) ? defaultValue : defaultValue ? [defaultValue] : []);
|
|
39
40
|
const [textAreaValue, setTextAreaValue] = useState('');
|
|
40
|
-
//
|
|
41
|
-
const
|
|
41
|
+
// Exclude selected users by ID
|
|
42
|
+
const excludeIds = useMemo(() => value
|
|
43
|
+
.map((u) => (typeof u === 'object' ? u.id : null))
|
|
44
|
+
.filter(Boolean)
|
|
45
|
+
.join(','), [value]);
|
|
46
|
+
// Fetch users excluding selected ones
|
|
47
|
+
const { users, isLoading } = useSCFetchUsers({ search: inputValue, exclude: excludeIds });
|
|
48
|
+
const filteredUsers = users.filter((u) => !excludeIds.includes(u.id));
|
|
42
49
|
useEffect(() => {
|
|
43
50
|
onChange === null || onChange === void 0 ? void 0 : onChange(value);
|
|
44
51
|
setTextAreaValue(value.map((u) => (typeof u === 'object' ? u.username : u)).join('\n'));
|
|
45
52
|
}, [value]);
|
|
46
53
|
// Handlers
|
|
47
54
|
const handleOpen = () => {
|
|
48
|
-
|
|
55
|
+
filteredUsers.length > 0 && setOpen(true);
|
|
49
56
|
};
|
|
50
57
|
const handleClose = () => {
|
|
51
58
|
setOpen(false);
|
|
@@ -53,26 +60,29 @@ const UserAutocomplete = (inProps) => {
|
|
|
53
60
|
const handleChange = (_event, newValue) => {
|
|
54
61
|
setValue(newValue);
|
|
55
62
|
};
|
|
56
|
-
const handleTextAreaChange = (e) => {
|
|
57
|
-
const names = e.target.value
|
|
63
|
+
const handleTextAreaChange = (e) => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
|
+
const names = Array.from(new Set(e.target.value
|
|
58
65
|
.split(/\s|,|\n/)
|
|
59
66
|
.map((s) => s.trim())
|
|
60
|
-
.filter(Boolean);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
.filter(Boolean)));
|
|
68
|
+
let resolvedUsers = [];
|
|
69
|
+
try {
|
|
70
|
+
if (names.length > 0) {
|
|
71
|
+
const resp = yield UserService.matchUsernames(names.join(','));
|
|
72
|
+
const matchedMap = new Map(resp.map((u) => [u.username, u]));
|
|
73
|
+
resolvedUsers = names.map((name) => matchedMap.get(name) || name);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error(`Failed fetching users`, err);
|
|
78
|
+
resolvedUsers = names;
|
|
79
|
+
}
|
|
80
|
+
setValue(resolvedUsers);
|
|
66
81
|
setTextAreaValue(e.target.value);
|
|
67
|
-
};
|
|
68
|
-
return (_jsxs(Root, Object.assign({ className: classes.root }, { children: [_jsx(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options:
|
|
82
|
+
});
|
|
83
|
+
return (_jsxs(Root, Object.assign({ className: classes.root }, { children: [_jsx(AutocompleteRoot, Object.assign({ multiple: true, className: classes.autocompleteRoot, open: open, onOpen: handleOpen, onClose: handleClose, options: filteredUsers || [], getOptionLabel: (option) => option.username || '', value: value, inputValue: inputValue, onInputChange: (_event, newInputValue) => {
|
|
69
84
|
setInputValue(newInputValue);
|
|
70
|
-
}, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: _jsx(FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => {
|
|
71
|
-
if (typeof val === 'string') {
|
|
72
|
-
return option.username === val;
|
|
73
|
-
}
|
|
74
|
-
return option.id === val.id;
|
|
75
|
-
}, renderTags: (value, getTagProps) => value.map((option, index) => {
|
|
85
|
+
}, selectOnFocus: true, clearOnBlur: true, blurOnSelect: true, handleHomeEndKeys: true, clearIcon: null, disabled: disabled || isLoading, noOptionsText: _jsx(FormattedMessage, { id: "ui.userAutocomplete.empty", defaultMessage: "ui.userAutocomplete.empty" }), onChange: handleChange, isOptionEqualToValue: (option, val) => option.id === val.id, renderTags: (value, getTagProps) => value.map((option, index) => {
|
|
76
86
|
const username = typeof option === 'string' ? option : option.username;
|
|
77
87
|
const avatar = typeof option === 'string' ? '' : option.avatar;
|
|
78
88
|
const id = typeof option === 'string' ? `fallback-${option}` : option.id;
|