Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/mantine.dev/src/mdx/data/mdx-hooks-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,5 @@ export const MDX_HOOKS_DATA: Record<string, Frontmatter> = {
'Track scroll position and detect which heading is currently in the viewport, can be used for table of contents'
),
useFileDialog: hDocs('useFileDialog', 'Capture one or more files from the user'),
useSelection: hDocs('useSelection', 'returns current selection'),
};
1 change: 1 addition & 0 deletions apps/mantine.dev/src/mdx/mdx-nav-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ const HOOKS_PAGES_GROUP: MdxPagesCategory[] = sortCategoriesPages([
MDX_DATA.useMutationObserver,
MDX_DATA.useScrollIntoView,
MDX_DATA.useScrollSpy,
MDX_DATA.useSelection,
MDX_DATA.useViewportSize,
MDX_DATA.useWindowEvent,
MDX_DATA.useWindowScroll,
Expand Down
11 changes: 11 additions & 0 deletions apps/mantine.dev/src/pages/hooks/use-selection.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { HooksDemos } from '@docs/demos';
import { Layout } from '@/layout';
import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.useSelection);

## Usage

`use-selection` returns current selection:

<Demo data={HooksDemos.useSelectionDemo} />
5 changes: 5 additions & 0 deletions packages/@docs/demos/src/demos/hooks/Hooks.demos.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ export const Demo_useLoggerDemo = {
render: renderDemo(demos.useLoggerDemo),
};

export const Demo_useSelectedDemo = {
name: '⭐ Demo: useSelectedDemo',
render: renderDemo(demos.useSelectionDemo),
};

export const Demo_useMediaQueryDemo = {
name: '⭐ Demo: useMediaQueryDemo',
render: renderDemo(demos.useMediaQueryDemo),
Expand Down
1 change: 1 addition & 0 deletions packages/@docs/demos/src/demos/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,5 @@ export { useIsFirstRenderUsage } from './use-is-first-render.demo.usage';
export { useRadialMoveUsage } from './use-radial-move.demo.usage';
export { useScrollSpyUsage } from './use-scroll-spy.demo.usage';
export { useScrollSpySelector } from './use-scroll-spy.demo.selector';
export { useSelectionDemo } from './use-selection.demo.usage';
export { useFileDialogUsage } from './use-file-dialog.demo';
187 changes: 187 additions & 0 deletions packages/@docs/demos/src/demos/hooks/use-selection.demo.usage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import React from 'react';
import { Button, Checkbox, Group, Table, Text } from '@mantine/core';
import { useSelection } from '@mantine/hooks';
import { MantineDemo } from '@mantinex/demo';

const code = `
import { Button, Checkbox, Group, Table, Text } from '@mantine/core';
import { useSelection } from '@mantine/hooks';

const elements = [
{ id: '1', position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
{ id: '2', position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
{ id: '3', position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium' },
{ id: '4', position: 56, mass: 137.33, symbol: 'Ba', name: 'Barium' },
{ id: '5', position: 58, mass: 140.12, symbol: 'Ce', name: 'Cerium' },
];

function Demo() {
// Initialize with the first item selected as an example
const [selected, handlers] = useSelection(elements, [elements[0]]);

const allSelected = handlers.isAllSelected();
const someSelected = handlers.isSomeSelected();

const rows = elements.map((item) => {
// Check if item (by id) is in the selected array
const isSelected = selected.some((s) => s.id === item.id);
const bg = isSelected ? 'var(--mantine-color-blue-light)' : undefined;
return (
<Table.Tr key={item.id} bg={bg}>
<Table.Td>
<Checkbox
checked={isSelected}
onChange={() => handlers.toggle(item)}
/>
</Table.Td>
<Table.Td>{item.position}</Table.Td>
<Table.Td>{item.name}</Table.Td>
<Table.Td>{item.symbol}</Table.Td>
<Table.Td>{item.mass}</Table.Td>
</Table.Tr>
);
});

const handleSelectAllToggle = () => {
if (allSelected) {
handlers.resetSelection();
} else {
handlers.setSelection(elements);
}
};

return (
<>
<Group mb="md">
<Button onClick={handleSelectAllToggle}>
{allSelected ? 'Deselect all' : 'Select all'}
</Button>
<Button onClick={() => handlers.setSelection([elements[1], elements[3]])} variant="light">
Select Nitrogen & Barium
</Button>
<Button onClick={handlers.resetSelection} variant="outline" color="red">
Reset selection
</Button>
</Group>

<Text mb="xs" size="sm">
Selected items: {selected.map(s => s.name).join(', ') || 'None'} (Total: {selected.length})
</Text>

<Table miw={700} verticalSpacing="sm">
<Table.Thead>
<Table.Tr>
<Table.Th style={{ width: '2rem' }}>
<Checkbox
checked={allSelected}
indeterminate={someSelected && !allSelected}
onChange={handleSelectAllToggle}
aria-label="Select all rows"
/>
</Table.Th>
<Table.Th>Element position</Table.Th>
<Table.Th>Element name</Table.Th>
<Table.Th>Symbol</Table.Th>
<Table.Th>Atomic mass</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
</>
);
}
`;

const elements = [
{ id: '1', position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' },
{ id: '2', position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' },
{ id: '3', position: 39, mass: 88.906, symbol: 'Y', name: 'Yttrium' },
{ id: '4', position: 56, mass: 137.33, symbol: 'Ba', name: 'Barium' },
{ id: '5', position: 58, mass: 140.12, symbol: 'Ce', name: 'Cerium' },
];

function Demo() {
// Initialize with the first item selected as an example
const [selected, handlers] = useSelection(elements, [elements[0]]);

const allSelected = handlers.isAllSelected();
const someSelected = handlers.isSomeSelected();

const rows = elements.map((item) => {
const bg = selected.some((s) => s.id === item.id)
? 'var(--mantine-color-blue-light)'
: undefined;
// Check if item (by id) is in the selected array
const isSelected = selected.some((s) => s.id === item.id);
return (
<Table.Tr key={item.id} bg={bg}>
<Table.Td>
<Checkbox
checked={isSelected}
onChange={() => handlers.toggle(item)}
aria-label={`Select row ${item.name}`}
/>
</Table.Td>
<Table.Td>{item.position}</Table.Td>
<Table.Td>{item.name}</Table.Td>
<Table.Td>{item.symbol}</Table.Td>
<Table.Td>{item.mass}</Table.Td>
</Table.Tr>
);
});

const handleSelectAllToggle = () => {
if (allSelected) {
handlers.resetSelection();
} else {
handlers.setSelection(elements);
}
};

return (
<>
<Group mb="md">
<Button onClick={handleSelectAllToggle}>
{allSelected ? 'Deselect all' : 'Select all'}
</Button>
<Button onClick={() => handlers.setSelection([elements[1], elements[3]])} variant="light">
Select Nitrogen & Barium
</Button>
<Button onClick={handlers.resetSelection} variant="outline" color="red">
Reset selection
</Button>
</Group>

<Text mb="xs" size="sm">
Selected items: {selected.map((s) => s.name).join(', ') || 'None'} (Total: {selected.length}
)
</Text>

<Table miw="auto" verticalSpacing="sm">
<Table.Thead>
<Table.Tr>
<Table.Th>
<Checkbox
checked={allSelected}
indeterminate={someSelected && !allSelected}
onChange={handleSelectAllToggle}
aria-label="Select all rows"
/>
</Table.Th>
<Table.Th>Element position</Table.Th>
<Table.Th>Element name</Table.Th>
<Table.Th>Symbol</Table.Th>
<Table.Th>Atomic mass</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
</>
);
}

export const useSelectionDemo: MantineDemo = {
type: 'code',
component: Demo,
code,
};
1 change: 1 addition & 0 deletions packages/@mantine/hooks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export { useFetch } from './use-fetch/use-fetch';
export { useRadialMove, normalizeRadialValue } from './use-radial-move/use-radial-move';
export { useScrollSpy } from './use-scroll-spy/use-scroll-spy';
export { useFileDialog } from './use-file-dialog/use-file-dialog';
export { useSelection } from './use-selection/use-selection';

export type { UseMovePosition } from './use-move/use-move';
export type { OS } from './use-os/use-os';
Expand Down
Loading
Loading