Drag and drop
Select with drag & drop
tsx
import React from 'react';
import Button from 'intergalactic/button';
import Counter from 'intergalactic/counter';
import SettingsM from 'intergalactic/icon/Settings/m';
import Select from 'intergalactic/select';
import { Text } from 'intergalactic/typography';
import Link from 'intergalactic/link';
import { Flex } from 'intergalactic/flex-box';
import DnD from 'intergalactic/drag-and-drop';
const defeaultColumns = [
{ id: 'uniquePageviews', label: 'Unique Pageviews' },
{ id: 'uniqueVisitors', label: 'Unique Visitors' },
{ id: 'entranceSources', label: 'Entrance Sources' },
{ id: 'desktop', label: 'Desktop' },
{ id: 'mobile', label: 'Mobile' },
];
const defaultSelectedColumns = ['uniquePageviews', 'entranceSources'];
const Demo = () => {
const [columns, setColumns] = React.useState(defeaultColumns);
const handleDnD = React.useCallback(
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
setColumns((columns) => {
const newColumns = [...columns];
const shift = fromIndex < toIndex ? 1 : -1;
for (let i = fromIndex; i !== toIndex; i += shift) {
newColumns[i] = columns[i + shift];
}
newColumns[toIndex] = columns[fromIndex];
return newColumns;
});
},
[],
);
const [selectedColumns, setSelectedColumns] = React.useState<string[]>(defaultSelectedColumns);
const resetToDefault = React.useCallback(() => {
setSelectedColumns(defaultSelectedColumns);
}, []);
const toggleAll = React.useCallback(() => {
const allSelected = selectedColumns.length === columns.length;
const allColumns = columns.map((column) => column.id);
if (allSelected) {
setSelectedColumns([]);
} else {
setSelectedColumns(allColumns);
}
}, [selectedColumns, columns]);
return (
<Select multiselect value={selectedColumns} onChange={setSelectedColumns}>
<Select.Trigger mt={2} mr='auto' id='dropdown-menu-basic' tag={Button}>
<Button.Addon>
<SettingsM />
</Button.Addon>
<Button.Text>Manage columns</Button.Text>
<Button.Addon>
<Counter>
{selectedColumns.length}/{columns.length}
</Counter>
</Button.Addon>
</Select.Trigger>
<Select.Menu hMax={800}>
{({ highlightedIndex }) => {
return (
<DnD onDnD={handleDnD} customFocus={highlightedIndex}>
<Flex direction='column' alignItems='flex-start' p={2} gap={2}>
<Text bold>Show table columns</Text>
<Link tag='button' size={200} onClick={resetToDefault}>
Reset to default
</Link>
<Link tag='button' size={200} onClick={toggleAll}>
{selectedColumns.length === columns.length ? 'Deselect' : 'Select'} all
</Link>
</Flex>
{columns.map((column) => (
<DnD.Draggable
tag={Select.Option}
id={column.id}
selected={selectedColumns.includes(column.id)}
value={column.id}
key={column.id}
>
<Select.Option.Checkbox />
{column.label}
</DnD.Draggable>
))}
</DnD>
);
}}
</Select.Menu>
</Select>
);
};
export default Demo;
Cards with drag & drop
tsx
import React from 'react';
import DnD from 'intergalactic/drag-and-drop';
import Card from 'intergalactic/card';
import { Flex } from 'intergalactic/flex-box';
import { Chart } from 'intergalactic/d3-chart';
import MathPlusL from 'intergalactic/icon/MathPlus/l';
import { Text } from 'intergalactic/typography';
const stableRandom = (seed: number) => {
let randomIndex = seed;
return () => {
if (randomIndex > 20) randomIndex = 1;
return Math.abs(Math.sin(Math.PI * randomIndex * Math.cos(100 - randomIndex++)));
};
};
const Widget: React.FC<{ title: string }> = ({ title }) => {
const data = React.useMemo(() => {
const random = stableRandom(title.length);
const dateFormatter = new Intl.DateTimeFormat('en', { month: 'numeric', day: 'numeric' });
return Array(3)
.fill(0)
.map((_, i) => ({
date: dateFormatter.format(new Date(Date.now() - 1000 * 60 * 60 * 24 * 3 * i)),
value: Math.round(random() * 10),
}));
}, [title]);
return (
<Card w={240} h={300}>
<Card.Header>
<Card.Title>{title}</Card.Title>
</Card.Header>
<Card.Body>
<Chart.Bar
duration={0}
mt={5}
groupKey={'date'}
data={data}
plotWidth={200}
plotHeight={200}
/>
</Card.Body>
</Card>
);
};
const widgetsSetup = [
{
title: 'Market traffic',
id: 'market-traffic',
},
{
title: 'Backlinks',
id: 'backlinks',
},
];
const defaultWidgets = [null, 'market-traffic', 'backlinks', null];
const Demo = () => {
const [widgets, setWidgets] = React.useState(defaultWidgets);
const handleDnD = React.useCallback(
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
setWidgets((widgets) => {
const newWidgets = [...widgets];
const shift = fromIndex < toIndex ? 1 : -1;
for (let i = fromIndex; i !== toIndex; i += shift) {
newWidgets[i] = widgets[i + shift];
}
newWidgets[toIndex] = widgets[fromIndex];
return newWidgets;
});
},
[],
);
return (
<DnD tag={Flex} flexWrap gap={4} onDnD={handleDnD}>
{widgets.map((id, index) => {
if (!id) {
return (
<DnD.DropZone key={index}>
<Flex
alignItems='center'
gap={1}
justifyContent='center'
h={300}
direction='column'
p={5}
style={{
border: '1px dashed var(--intergalactic-border-primary, #c4c7cf)',
borderRadius: '6px',
}}
>
<Text color='text-secondary'>
<MathPlusL />
</Text>
<Text color='text-secondary' bold size={200}>
Place widget here
</Text>
<Text color='text-secondary' textAlign='center' size={200}>
Change the order of the widgets!
</Text>
</Flex>
</DnD.DropZone>
);
}
const widget = widgetsSetup.find((widget) => widget.id === id)!;
return (
<DnD.Draggable placement='top' key={id} aria-label={`${widget.title} widget`} h='100%'>
<Widget title={widget.title} />
</DnD.Draggable>
);
})}
</DnD>
);
};
export default Demo;
TabPanel with drag & drop
tsx
import React from 'react';
import DnD from 'intergalactic/drag-and-drop';
import Badge from 'intergalactic/badge';
import LinkedInM from 'intergalactic/icon/LinkedIn/m';
import TabPanel from 'intergalactic/tab-panel';
import Counter from 'intergalactic/counter';
import Flag from 'intergalactic/flags';
const renderTab = (tab: string) => {
if (tab === 'overview') {
return <TabPanel.Item.Text>Overview</TabPanel.Item.Text>;
} else if (tab === 'activity') {
return (
<>
<TabPanel.Item.Text>Activity</TabPanel.Item.Text> <Counter>23</Counter>
</>
);
} else if (tab === 'users') {
return <TabPanel.Item.Text>Users</TabPanel.Item.Text>;
} else if (tab === 'query-log') {
return <TabPanel.Item.Text>Query Log</TabPanel.Item.Text>;
} else if (tab === 'geolocation') {
return (
<>
<TabPanel.Item.Addon>
<Flag iso2='US' />
</TabPanel.Item.Addon>
<TabPanel.Item.Text>Geolocation</TabPanel.Item.Text>
</>
);
} else if (tab === 'disabled-tab') {
return <TabPanel.Item.Text>Disabled Tab</TabPanel.Item.Text>;
} else {
return <TabPanel.Item.Text>{tab}</TabPanel.Item.Text>;
}
};
const disabledTabs = ['disabled-tab'];
const Demo = () => {
const [tabs, setTabs] = React.useState([
'overview',
'activity',
'users',
'query-log',
'geolocation',
'disabled-tab',
]);
const [currentTab, setCurrentTab] = React.useState('overview');
const handleDnD = React.useCallback(
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
setTabs((tabs) => {
const newTabs = [...tabs];
const shift = fromIndex < toIndex ? 1 : -1;
for (let i = fromIndex; i !== toIndex; i += shift) {
newTabs[i] = tabs[i + shift];
}
newTabs[toIndex] = tabs[fromIndex];
return newTabs;
});
},
[],
);
return (
<DnD
tag={TabPanel}
value={currentTab}
onChange={(tab) => setCurrentTab(tab as string)}
onDnD={handleDnD}
>
{tabs.map((tab) => (
<DnD.Draggable
placement='bottom'
tag={TabPanel.Item}
value={tab}
key={tab}
pb={0}
disabled={disabledTabs.includes(tab)}
>
{renderTab(tab)}
</DnD.Draggable>
))}
</DnD>
);
};
export default Demo;
Secondary DataTable with drag & drop
tsx
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Flag from 'intergalactic/flags';
import { Flex } from '@semcore/flex-box';
import DnD from 'intergalactic/drag-and-drop';
const data = [
{
countryCode: 'US',
countryTitle: 'United States',
cpc: 1,
vol: 1.14,
kd: 37.7,
},
{
countryCode: 'RS',
countryTitle: 'Serbia',
cpc: 1,
vol: 1.58,
kd: 37.7,
},
{
countryCode: 'ES',
countryTitle: 'Spain',
cpc: 3,
vol: 2.3,
kd: 37.7,
},
{
countryCode: 'CY',
countryTitle: 'Cyprus',
cpc: 53,
vol: 4.8,
kd: 37.7,
},
];
const Demo = () => {
const [sortedData, setSortedData] = React.useState(data);
const handleDnD = React.useCallback(
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
setSortedData((data) => {
const newData = [...data];
const shift = fromIndex < toIndex ? 1 : -1;
for (let i = fromIndex; i !== toIndex; i += shift) {
newData[i] = data[i + shift];
}
newData[toIndex] = data[fromIndex];
return newData;
});
},
[],
);
return (
<DataTable use='secondary' data={sortedData} w={400} aria-label={'Table title'}>
<DataTable.Head>
<DataTable.Column name='countryTitle' children='Keyword' wMin={140} justifyContent='left' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' justifyContent='left' />
<DataTable.Column name='kd' children='KD' justifyContent='right' />
</DataTable.Head>
<DnD onDnD={handleDnD}>
<DataTable.Body>
<DataTable.Cell data={data} name='countryTitle'>
{(_, row) => ({
children: (
<Flex gap={1} alignItems='center'>
<Flag iso2={row.countryCode as any} />
<span>{row.countryTitle}</span>
</Flex>
),
})}
</DataTable.Cell>
<DataTable.Row>
{(props) => {
return {
children: (
<DnD.Draggable tag={Flex} placement='left'>
{props.children}
</DnD.Draggable>
),
};
}}
</DataTable.Row>
</DataTable.Body>
</DnD>
</DataTable>
);
};
export default Demo;
Primary DataTable with drag & drop
tsx
import React from 'react';
import DataTable from 'intergalactic/data-table';
import { Flex } from 'intergalactic/flex-box';
import DnD from 'intergalactic/drag-and-drop';
import Checkbox from 'intergalactic/checkbox';
import { Text } from 'intergalactic/typography';
import Link from 'intergalactic/link';
import LinkExternalM from 'intergalactic/icon/LinkExternal/m';
import { DescriptionTooltip } from 'intergalactic/tooltip';
import { ButtonLink } from 'intergalactic/button';
const data = [
{
domain: 'https://www.example.com',
title: 'Example',
cpc: 1,
vol: 1.14,
kd: 37.7,
},
{
domain: 'https://semrush.com',
title: 'Semrush',
cpc: 1,
vol: 1.58,
kd: 37.7,
},
{
domain: 'https://wikipedia.org',
title: 'Wikipedia',
cpc: 3,
vol: 2.3,
kd: 37.7,
},
];
const Demo = () => {
const [sortedData, setSortedData] = React.useState(data);
const handleDnD = React.useCallback(
({ fromIndex, toIndex }: { fromIndex: number; toIndex: number }) => {
setSortedData((data) => {
const newData = [...data];
const shift = fromIndex < toIndex ? 1 : -1;
for (let i = fromIndex; i !== toIndex; i += shift) {
newData[i] = data[i + shift];
}
newData[toIndex] = data[fromIndex];
return newData;
});
},
[],
);
return (
<DataTable data={sortedData} w={600} aria-label={'Table title'}>
<DataTable.Head>
<DataTable.Column name='checkbox' wMax={30}>
<Checkbox />
</DataTable.Column>
<DataTable.Column name='title' children='Website' wMin={250} />
<DataTable.Column name='hint' children='Hints' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
<DataTable.Column name='kd' children='KD' />
</DataTable.Head>
<DnD onDnD={handleDnD}>
<DataTable.Body>
<DataTable.Cell data={data} name='checkbox'>
{() => ({ children: <Checkbox /> })}
</DataTable.Cell>
<DataTable.Cell data={data} name='title'>
{(_, row) => ({
children: (
<Flex direction='column' gap={1}>
<Text>{row.title}</Text>
<Link href={row.domain} addonRight={LinkExternalM}>
{row.domain}
</Link>
</Flex>
),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='hint' alignItems='start'>
{() => ({
children: (
<DescriptionTooltip>
<DescriptionTooltip.Trigger tag={ButtonLink} use='secondary'>
About
</DescriptionTooltip.Trigger>
<DescriptionTooltip.Popper aria-label='About data'>
Some description of the data.
</DescriptionTooltip.Popper>
</DescriptionTooltip>
),
})}
</DataTable.Cell>
<DataTable.Row>
{(props) => {
return {
children: (
<DnD.Draggable tag={Flex} placement='left'>
{props.children}
</DnD.Draggable>
),
};
}}
</DataTable.Row>
</DataTable.Body>
</DnD>
</DataTable>
);
};
export default Demo;