summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/components
diff options
context:
space:
mode:
Diffstat (limited to 'gui/src/renderer/components')
-rw-r--r--gui/src/renderer/components/ChevronButton.tsx6
-rw-r--r--gui/src/renderer/components/CustomDnsSettings.tsx18
-rw-r--r--gui/src/renderer/components/ExpiredAccountAddTime.tsx2
-rw-r--r--gui/src/renderer/components/NavigationBar.tsx27
-rw-r--r--gui/src/renderer/components/SplitTunnelingSettings.tsx20
-rw-r--r--gui/src/renderer/components/VpnSettings.tsx155
-rw-r--r--gui/src/renderer/components/WireguardSettings.tsx4
-rw-r--r--gui/src/renderer/components/cell/Section.tsx64
-rw-r--r--gui/src/renderer/components/cell/Selector.tsx56
9 files changed, 205 insertions, 147 deletions
diff --git a/gui/src/renderer/components/ChevronButton.tsx b/gui/src/renderer/components/ChevronButton.tsx
index 0485c22caf..6e16fdf6db 100644
--- a/gui/src/renderer/components/ChevronButton.tsx
+++ b/gui/src/renderer/components/ChevronButton.tsx
@@ -2,7 +2,7 @@ import * as React from 'react';
import styled from 'styled-components';
import { colors } from '../../config.json';
-import * as Cell from './cell';
+import { Icon } from './cell/Label';
interface IProps extends React.HTMLAttributes<HTMLButtonElement> {
up: boolean;
@@ -13,7 +13,7 @@ const Button = styled.button({
background: 'none',
});
-const Icon = styled(Cell.Icon)({
+const StyledIcon = styled(Icon)({
flex: 0,
alignSelf: 'stretch',
justifyContent: 'center',
@@ -24,7 +24,7 @@ export default function ChevronButton(props: IProps) {
return (
<Button {...otherProps}>
- <Icon
+ <StyledIcon
tintColor={colors.white80}
tintHoverColor={colors.white}
source={up ? 'icon-chevron-up' : 'icon-chevron-down'}
diff --git a/gui/src/renderer/components/CustomDnsSettings.tsx b/gui/src/renderer/components/CustomDnsSettings.tsx
index bda3fbb864..fbf7d3dce0 100644
--- a/gui/src/renderer/components/CustomDnsSettings.tsx
+++ b/gui/src/renderer/components/CustomDnsSettings.tsx
@@ -4,6 +4,7 @@ import { sprintf } from 'sprintf-js';
import { colors, strings } from '../../config.json';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
+import { formatHtml } from '../lib/html-formatter';
import { IpAddress } from '../lib/ip';
import { useBoolean, useMounted } from '../lib/utilityHooks';
import { useSelector } from '../redux/store';
@@ -286,14 +287,15 @@ export default function CustomDnsSettings() {
<Cell.CellFooterText>
{featureAvailable
? messages.pgettext('vpn-settings-view', 'Enable to add at least one DNS server.')
- : // This line makes sure that the next one isn't prefixed by the color.
- // TRANSLATORS: This is displayed when either or both of the block ads/trackers settings are
- // TRANSLATORS: turned on which makes the custom DNS setting disabled.
- // TRANSLATORS: Available placeholders:
- // TRANSLATORS: %(preferencesPageName)s - The page title showed on top in the preferences page.
- messages.pgettext(
- 'vpn-settings-view',
- 'Disable all content blockers to activate this setting.',
+ : formatHtml(
+ // TRANSLATORS: This is displayed when either or both of the block ads/trackers settings are
+ // TRANSLATORS: turned on which makes the custom DNS setting disabled.
+ // TRANSLATORS: Available placeholders:
+ // TRANSLATORS: %(preferencesPageName)s - The page title showed on top in the preferences page.
+ messages.pgettext(
+ 'vpn-settings-view',
+ 'Disable all <b>DNS content blockers</b> above to activate this setting.',
+ ),
)}
</Cell.CellFooterText>
</StyledCustomDnsFooter>
diff --git a/gui/src/renderer/components/ExpiredAccountAddTime.tsx b/gui/src/renderer/components/ExpiredAccountAddTime.tsx
index 14a2de74c4..54d27f75d8 100644
--- a/gui/src/renderer/components/ExpiredAccountAddTime.tsx
+++ b/gui/src/renderer/components/ExpiredAccountAddTime.tsx
@@ -280,7 +280,7 @@ function useFinishedCallback() {
accountSetupFinished();
}
- history.reset(RoutePath.main, undefined, transitions.push);
+ history.reset(RoutePath.main, transitions.push);
}, [isNewAccount, accountSetupFinished, history]);
return callback;
diff --git a/gui/src/renderer/components/NavigationBar.tsx b/gui/src/renderer/components/NavigationBar.tsx
index 4c27665b65..317a9bd26e 100644
--- a/gui/src/renderer/components/NavigationBar.tsx
+++ b/gui/src/renderer/components/NavigationBar.tsx
@@ -3,11 +3,8 @@ import React, { useCallback, useContext, useEffect, useLayoutEffect, useRef } fr
import { colors } from '../../config.json';
import { messages } from '../../shared/gettext';
import { useAppContext } from '../context';
-import useActions from '../lib/actionsHook';
import { useHistory } from '../lib/history';
import { useCombinedRefs } from '../lib/utilityHooks';
-import { useSelector } from '../redux/store';
-import userInterface from '../redux/userinterface/actions';
import CustomScrollbars, { CustomScrollbarsRef, IScrollEvent } from './CustomScrollbars';
import { BackActionContext } from './KeyboardNavigation';
import {
@@ -92,41 +89,35 @@ export const NavigationScrollbars = React.forwardRef(function NavigationScrollba
forwardedRef?: React.Ref<CustomScrollbarsRef>,
) {
const history = useHistory();
+ const { setNavigationHistory } = useAppContext();
const { onScroll } = useContext(NavigationScrollContext);
- const { setScrollPositions } = useAppContext();
const ref = useRef<CustomScrollbarsRef>();
const combinedRefs = useCombinedRefs(forwardedRef, ref);
- const { addScrollPosition, removeScrollPosition } = useActions(userInterface);
- const scrollPositions = useSelector((state) => state.userInterface.scrollPosition);
-
useEffect(() => {
- const path = history.location.pathname;
const beforeunload = () => {
if (ref.current) {
- const scrollPosition = ref.current.getScrollPosition();
- setScrollPositions({ ...scrollPositions, [path]: scrollPosition });
+ history.location.state.scrollPosition = ref.current.getScrollPosition();
+ setNavigationHistory(history.asObject);
}
};
window.addEventListener('beforeunload', beforeunload);
return () => window.removeEventListener('beforeunload', beforeunload);
- }, [scrollPositions]);
+ }, []);
useLayoutEffect(() => {
- const path = history.location.pathname;
-
- const scrollPosition = scrollPositions[history.location.pathname];
- if (history.action === 'POP' && scrollPosition) {
- ref.current?.scrollTo(...scrollPosition);
- removeScrollPosition(path);
+ const location = history.location;
+ if (history.action === 'POP') {
+ ref.current?.scrollTo(...location.state.scrollPosition);
}
return () => {
if (history.action === 'PUSH' && ref.current) {
- addScrollPosition(path, ref.current.getScrollPosition());
+ location.state.scrollPosition = ref.current.getScrollPosition();
+ setNavigationHistory(history.asObject);
}
};
}, []);
diff --git a/gui/src/renderer/components/SplitTunnelingSettings.tsx b/gui/src/renderer/components/SplitTunnelingSettings.tsx
index 4cad24f445..f68be19589 100644
--- a/gui/src/renderer/components/SplitTunnelingSettings.tsx
+++ b/gui/src/renderer/components/SplitTunnelingSettings.tsx
@@ -410,6 +410,16 @@ export function WindowsSplitTunnelingSettings(props: IPlatformSplitTunnelingSett
splitTunnelingEnabled &&
(!filteredNonSplitApplications || filteredNonSplitApplications.length > 0);
+ const excludedTitle = (
+ <Cell.SectionTitle>
+ {messages.pgettext('split-tunneling-view', 'Excluded apps')}
+ </Cell.SectionTitle>
+ );
+
+ const allTitle = (
+ <Cell.SectionTitle>{messages.pgettext('split-tunneling-view', 'All apps')}</Cell.SectionTitle>
+ );
+
return (
<>
<SettingsHeader>
@@ -428,10 +438,7 @@ export function WindowsSplitTunnelingSettings(props: IPlatformSplitTunnelingSett
{splitTunnelingEnabled && <SearchBar searchTerm={searchTerm} onSearch={setSearchTerm} />}
<Accordion expanded={showSplitSection}>
- <Cell.Section>
- <Cell.SectionTitle>
- {messages.pgettext('split-tunneling-view', 'Excluded apps')}
- </Cell.SectionTitle>
+ <Cell.Section sectionTitle={excludedTitle}>
<ApplicationList
applications={filteredSplitApplications}
rowRenderer={excludedRowRenderer}
@@ -440,10 +447,7 @@ export function WindowsSplitTunnelingSettings(props: IPlatformSplitTunnelingSett
</Accordion>
<Accordion expanded={showNonSplitSection}>
- <Cell.Section>
- <Cell.SectionTitle>
- {messages.pgettext('split-tunneling-view', 'All apps')}
- </Cell.SectionTitle>
+ <Cell.Section sectionTitle={allTitle}>
<ApplicationList
applications={filteredNonSplitApplications}
rowRenderer={includedRowRenderer}
diff --git a/gui/src/renderer/components/VpnSettings.tsx b/gui/src/renderer/components/VpnSettings.tsx
index ad5d3439b1..1213703f61 100644
--- a/gui/src/renderer/components/VpnSettings.tsx
+++ b/gui/src/renderer/components/VpnSettings.tsx
@@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react';
import { sprintf } from 'sprintf-js';
import styled from 'styled-components';
-import { strings } from '../../config.json';
+import { colors, strings } from '../../config.json';
import { IDnsOptions, TunnelProtocol } from '../../shared/daemon-rpc-types';
import { messages } from '../../shared/gettext';
import log from '../../shared/logging';
@@ -47,6 +47,14 @@ const StyledSelectorContainer = styled.div({
flex: 0,
});
+const StyledTitleLabel = styled(Cell.SectionTitle)({
+ flex: 1,
+});
+
+const StyledSectionItem = styled(Cell.Container)({
+ backgroundColor: colors.blue40,
+});
+
export default function VpnSettings() {
const { pop } = useHistory();
@@ -82,11 +90,7 @@ export default function VpnSettings() {
</Cell.Group>
<Cell.Group>
- <BlockAds />
- <BlockTrackers />
- <BlockMalware />
- <BlockGambling />
- <BlockAdultContent />
+ <DnsBlockers />
</Cell.Group>
<Cell.Group>
@@ -230,38 +234,63 @@ function useDns(setting: keyof IDnsOptions['defaultOptions']) {
return [dns, updateBlockSetting] as const;
}
+function DnsBlockers() {
+ const dns = useSelector((state) => state.settings.dns);
+
+ const title = (
+ <>
+ <StyledTitleLabel as="label" disabled={dns.state === 'custom'}>
+ {messages.pgettext('vpn-settings-view', 'DNS content blockers')}
+ </StyledTitleLabel>
+ <InfoButton>
+ <ModalMessage>
+ {messages.pgettext(
+ 'vpn-settings-view',
+ 'When this feature is enabled it stops the device from contacting certain domains or websites known for distributing ads, malware, trackers and more.',
+ )}
+ </ModalMessage>
+ <ModalMessage>
+ {messages.pgettext(
+ 'vpn-settings-view',
+ 'This might cause issues on certain websites, services, and programs.',
+ )}
+ </ModalMessage>
+ </InfoButton>
+ </>
+ );
+
+ return (
+ <Cell.ExpandableSection sectionTitle={title} expandableId="dns-blockers">
+ <BlockAds />
+ <BlockTrackers />
+ <BlockMalware />
+ <BlockGambling />
+ <BlockAdultContent />
+ </Cell.ExpandableSection>
+ );
+}
+
function BlockAds() {
const [dns, setBlockAds] = useDns('blockAds');
return (
<AriaInputGroup>
- <Cell.Container disabled={dns.state === 'custom'}>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
<AriaLabel>
- <Cell.InputLabel>{messages.pgettext('vpn-settings-view', 'Block ads')}</Cell.InputLabel>
+ <Cell.InputLabel>
+ {
+ // TRANSLATORS: Label for settings that enables ad blocking.
+ messages.pgettext('vpn-settings-view', 'Ads')
+ }
+ </Cell.InputLabel>
</AriaLabel>
- <AriaDetails>
- <InfoButton>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'When enabled, this feature stops the device from contacting certain known ad domains.',
- )}
- </ModalMessage>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'Warning: This might cause issues on certain websites, services, and programs.',
- )}
- </ModalMessage>
- </InfoButton>
- </AriaDetails>
<AriaInput>
<Cell.Switch
isOn={dns.state === 'default' && dns.defaultOptions.blockAds}
onChange={setBlockAds}
/>
</AriaInput>
- </Cell.Container>
+ </StyledSectionItem>
</AriaInputGroup>
);
}
@@ -271,35 +300,22 @@ function BlockTrackers() {
return (
<AriaInputGroup>
- <Cell.Container disabled={dns.state === 'custom'}>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
<AriaLabel>
<Cell.InputLabel>
- {messages.pgettext('vpn-settings-view', 'Block trackers')}
+ {
+ // TRANSLATORS: Label for settings that enables tracker blocking.
+ messages.pgettext('vpn-settings-view', 'Trackers')
+ }
</Cell.InputLabel>
</AriaLabel>
- <AriaDetails>
- <InfoButton>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'When enabled, this feature stops the device from contacting certain domains known to track users.',
- )}
- </ModalMessage>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'Warning: This might cause issues on certain websites, services, and programs.',
- )}
- </ModalMessage>
- </InfoButton>
- </AriaDetails>
<AriaInput>
<Cell.Switch
isOn={dns.state === 'default' && dns.defaultOptions.blockTrackers}
onChange={setBlockTrackers}
/>
</AriaInput>
- </Cell.Container>
+ </StyledSectionItem>
</AriaInputGroup>
);
}
@@ -309,10 +325,13 @@ function BlockMalware() {
return (
<AriaInputGroup>
- <Cell.Container disabled={dns.state === 'custom'}>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
<AriaLabel>
<Cell.InputLabel>
- {messages.pgettext('vpn-settings-view', 'Block malware')}
+ {
+ // TRANSLATORS: Label for settings that enables malware blocking.
+ messages.pgettext('vpn-settings-view', 'Malware')
+ }
</Cell.InputLabel>
</AriaLabel>
<AriaDetails>
@@ -320,13 +339,7 @@ function BlockMalware() {
<ModalMessage>
{messages.pgettext(
'vpn-settings-view',
- 'When enabled, this feature stops the device from contacting certain domains known to host malware.',
- )}
- </ModalMessage>
- <ModalMessage>
- {messages.pgettext(
- 'vpn-settings-view',
- 'Warning: This is not an anti-virus and should not be treated as such, this is just an extra layer of protection.',
+ 'Warning: The malware blocker is not an anti-virus and should not be treated as such, this is just an extra layer of protection.',
)}
</ModalMessage>
</InfoButton>
@@ -337,7 +350,7 @@ function BlockMalware() {
onChange={setBlockMalware}
/>
</AriaInput>
- </Cell.Container>
+ </StyledSectionItem>
</AriaInputGroup>
);
}
@@ -347,27 +360,22 @@ function BlockGambling() {
return (
<AriaInputGroup>
- <Cell.Container disabled={dns.state === 'custom'}>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
<AriaLabel>
<Cell.InputLabel>
- {messages.pgettext('vpn-settings-view', 'Block gambling')}
+ {
+ // TRANSLATORS: Label for settings that enables block of gamling related websites.
+ messages.pgettext('vpn-settings-view', 'Gambling')
+ }
</Cell.InputLabel>
</AriaLabel>
- <AriaDetails>
- <InfoButton
- message={messages.pgettext(
- 'vpn-settings-view',
- 'When enabled, this feature stops the device from contacting certain websites and services known to host gambling content.',
- )}
- />
- </AriaDetails>
<AriaInput>
<Cell.Switch
isOn={dns.state === 'default' && dns.defaultOptions.blockGambling}
onChange={setBlockGambling}
/>
</AriaInput>
- </Cell.Container>
+ </StyledSectionItem>
</AriaInputGroup>
);
}
@@ -377,27 +385,22 @@ function BlockAdultContent() {
return (
<AriaInputGroup>
- <Cell.Container disabled={dns.state === 'custom'}>
+ <StyledSectionItem disabled={dns.state === 'custom'}>
<AriaLabel>
<Cell.InputLabel>
- {messages.pgettext('vpn-settings-view', 'Block adult content')}
+ {
+ // TRANSLATORS: Label for settings that enables block of adult content.
+ messages.pgettext('vpn-settings-view', 'Adult content')
+ }
</Cell.InputLabel>
</AriaLabel>
- <AriaDetails>
- <InfoButton
- message={messages.pgettext(
- 'vpn-settings-view',
- 'When enabled, this feature stops the device from contacting certain websites and services known to host adult content.',
- )}
- />
- </AriaDetails>
<AriaInput>
<Cell.Switch
isOn={dns.state === 'default' && dns.defaultOptions.blockAdultContent}
onChange={setBlockAdultContent}
/>
</AriaInput>
- </Cell.Container>
+ </StyledSectionItem>
{dns.state === 'custom' && <CustomDnsEnabledFooter />}
</AriaInputGroup>
);
diff --git a/gui/src/renderer/components/WireguardSettings.tsx b/gui/src/renderer/components/WireguardSettings.tsx
index dea8c6dbc2..18c39a7396 100644
--- a/gui/src/renderer/components/WireguardSettings.tsx
+++ b/gui/src/renderer/components/WireguardSettings.tsx
@@ -276,6 +276,8 @@ function Udp2tcpPortSetting() {
[],
);
+ const expandableProps = useMemo(() => ({ expandable: true, id: 'udp2tcp-port' }), []);
+
const selectPort = useCallback(
async (port: LiftedConstraint<number>) => {
await setObfuscationSettings({
@@ -307,7 +309,7 @@ function Udp2tcpPortSetting() {
value={port}
onSelect={selectPort}
disabled={obfuscationSettings.selectedObfuscation === ObfuscationType.off}
- expandable
+ expandable={expandableProps}
thinTitle
automaticValue={'any' as const}
/>
diff --git a/gui/src/renderer/components/cell/Section.tsx b/gui/src/renderer/components/cell/Section.tsx
index 38df17ebdb..8ba5975476 100644
--- a/gui/src/renderer/components/cell/Section.tsx
+++ b/gui/src/renderer/components/cell/Section.tsx
@@ -1,8 +1,14 @@
-import React from 'react';
+import React, { useEffect } from 'react';
import styled from 'styled-components';
import { colors } from '../../../config.json';
+import { useAppContext } from '../../context';
+import { useHistory } from '../../lib/history';
+import { useBoolean } from '../../lib/utilityHooks';
+import Accordion from '../Accordion';
+import ChevronButton from '../ChevronButton';
import { buttonText, openSans, sourceSansPro } from '../common-styles';
+import { Container } from './Container';
import { Row } from './Row';
const StyledSection = styled.div({
@@ -25,11 +31,61 @@ export const SectionTitle = styled(Row)(buttonText, (props: SectionTitleProps) =
export const CellSectionContext = React.createContext<boolean>(false);
-export function Section(props: React.HTMLAttributes<HTMLDivElement>) {
- const { children, ...otherProps } = props;
+interface SectionProps extends React.HTMLAttributes<HTMLDivElement> {
+ sectionTitle?: React.ReactElement;
+}
+
+export function Section(props: SectionProps) {
+ const { children, sectionTitle, ...otherProps } = props;
return (
<StyledSection {...otherProps}>
- <CellSectionContext.Provider value={true}>{children}</CellSectionContext.Provider>
+ <CellSectionContext.Provider value={true}>
+ {sectionTitle && <StyledTitleContainer>{sectionTitle}</StyledTitleContainer>}
+ {children}
+ </CellSectionContext.Provider>
</StyledSection>
);
}
+
+const StyledChevronButton = styled(ChevronButton)({
+ padding: 0,
+ marginRight: '16px',
+});
+
+const StyledTitleContainer = styled(Container)({
+ display: 'flex',
+ padding: 0,
+});
+
+interface ExpandableSectionProps extends SectionProps {
+ expandableId: string;
+ expandedInitially?: boolean;
+}
+
+export function ExpandableSection(props: ExpandableSectionProps) {
+ const { expandableId, expandedInitially, sectionTitle, ...otherProps } = props;
+
+ const history = useHistory();
+ const { setNavigationHistory } = useAppContext();
+ const expandedValue =
+ history.location.state.expandedSections[props.expandableId] ?? !!expandedInitially;
+ const [expanded, , , toggleExpanded] = useBoolean(expandedValue);
+
+ useEffect(() => {
+ history.location.state.expandedSections[props.expandableId] = expanded;
+ setNavigationHistory(history.asObject);
+ }, [expanded]);
+
+ const title = (
+ <>
+ {sectionTitle}
+ <StyledChevronButton up={expanded} onClick={toggleExpanded} />
+ </>
+ );
+
+ return (
+ <Section className={props.className} sectionTitle={title} {...otherProps}>
+ <Accordion expanded={expanded}>{props.children}</Accordion>
+ </Section>
+ );
+}
diff --git a/gui/src/renderer/components/cell/Selector.tsx b/gui/src/renderer/components/cell/Selector.tsx
index cb0d6344b6..ed49444da1 100644
--- a/gui/src/renderer/components/cell/Selector.tsx
+++ b/gui/src/renderer/components/cell/Selector.tsx
@@ -3,28 +3,15 @@ import styled from 'styled-components';
import { colors } from '../../../config.json';
import { messages } from '../../../shared/gettext';
-import { useBoolean } from '../../lib/utilityHooks';
-import Accordion from '../Accordion';
import { AriaDetails, AriaInput, AriaLabel } from '../AriaGroup';
-import ChevronButton from '../ChevronButton';
import { normalText } from '../common-styles';
import InfoButton from '../InfoButton';
import * as Cell from '.';
-const StyledTitle = styled(Cell.Container)({
- display: 'flex',
- padding: 0,
-});
-
const StyledTitleLabel = styled(Cell.SectionTitle)({
flex: 1,
});
-const StyledChevronButton = styled(ChevronButton)({
- padding: 0,
- marginRight: '16px',
-});
-
export interface SelectorItem<T> {
label: string;
value: T;
@@ -39,7 +26,7 @@ interface CommonSelectorProps<T, U> {
selectedCellRef?: React.Ref<HTMLElement>;
className?: string;
details?: React.ReactElement;
- expandable?: boolean;
+ expandable?: { expandable: boolean; id: string };
disabled?: boolean;
thinTitle?: boolean;
automaticLabel?: string;
@@ -52,8 +39,6 @@ interface SelectorProps<T, U> extends CommonSelectorProps<T, U> {
}
export default function Selector<T, U>(props: SelectorProps<T, U>) {
- const [expanded, , , toggleExpanded] = useBoolean(!props.expandable);
-
const items = props.items.map((item) => {
const selected = props.value === item.value;
const ref = selected ? (props.selectedCellRef as React.Ref<HTMLButtonElement>) : undefined;
@@ -88,8 +73,8 @@ export default function Selector<T, U>(props: SelectorProps<T, U>) {
);
}
- const title = props.title && (
- <StyledTitle>
+ const title = props.title ? (
+ <>
<AriaLabel>
<StyledTitleLabel as="label" disabled={props.disabled} thin={props.thinTitle}>
{props.title}
@@ -100,8 +85,9 @@ export default function Selector<T, U>(props: SelectorProps<T, U>) {
<InfoButton>{props.details}</InfoButton>
</AriaDetails>
)}
- {props.expandable && <StyledChevronButton up={expanded} onClick={toggleExpanded} />}
- </StyledTitle>
+ </>
+ ) : (
+ <></>
);
// Add potential additional items to the list. Used for custom entry.
@@ -112,14 +98,28 @@ export default function Selector<T, U>(props: SelectorProps<T, U>) {
</Cell.Group>
);
- return (
- <AriaInput>
- <Cell.Section role="listbox" className={props.className}>
- {title}
- {props.expandable ? <Accordion expanded={expanded}>{children}</Accordion> : children}
- </Cell.Section>
- </AriaInput>
- );
+ if (props.expandable?.expandable) {
+ return (
+ <AriaInput>
+ <Cell.ExpandableSection
+ role="listbox"
+ expandedInitially={false}
+ className={props.className}
+ sectionTitle={title}
+ expandableId={props.expandable.id}>
+ {children}
+ </Cell.ExpandableSection>
+ </AriaInput>
+ );
+ } else {
+ return (
+ <AriaInput>
+ <Cell.Section role="listbox" className={props.className} sectionTitle={title}>
+ {children}
+ </Cell.Section>
+ </AriaInput>
+ );
+ }
}
const StyledCellIcon = styled(Cell.Icon)((props: { visible: boolean }) => ({