forked from mantinedev/mantine
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'dev' of github.com-rtivital:mantinedev/mantine
- Loading branch information
Showing
21 changed files
with
449 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...antine-demos/src/demos/core/MultiSelect/MultiSelect.demo.disableSelectedItemFiltering.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
import { MultiSelect } from '@mantine/core'; | ||
import { MantineDemo } from '@mantine/ds'; | ||
import { data } from './_data'; | ||
|
||
const code = ` | ||
import { MultiSelect } from '@mantine/core'; | ||
function Demo() { | ||
return ( | ||
<MultiSelect | ||
data={['React', 'Angular', 'Svelte', 'Vue', 'Riot', 'Next.js', 'Blitz.js']} | ||
disableSelectedItemFiltering | ||
label="Your favorite frameworks/libraries" | ||
nothingFound="Nothing found" | ||
placeholder="Pick all that you like" | ||
searchable | ||
/> | ||
); | ||
} | ||
`; | ||
|
||
function Demo() { | ||
return ( | ||
<MultiSelect | ||
data={data} | ||
disableSelectedItemFiltering | ||
label="Your favorite frameworks/libraries" | ||
maw={400} | ||
mx="auto" | ||
nothingFound="Nothing found" | ||
placeholder="Pick all that you like" | ||
searchable | ||
/> | ||
); | ||
} | ||
|
||
export const disableSelectedItemFiltering: MantineDemo = { | ||
type: 'demo', | ||
code, | ||
component: Demo, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
117 changes: 117 additions & 0 deletions
117
src/mantine-form/src/lists/change-error-indices.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { changeErrorIndices } from './change-error-indices'; | ||
|
||
const TEST_ERRORS = { | ||
name: 'name-error', | ||
|
||
// single level of nesting | ||
'fruits.0.name': 'fruit-error-1', | ||
'fruits.0.available': 'fruit-error-2', | ||
'fruits.4.available': 'fruit-error-3', | ||
'fruits.15.inner.name': 'fruit-error-4', | ||
'fruits.15.inner.0.name': 'fruit-error-5', | ||
|
||
// multiple levels of nesting | ||
'nested.0.inner.1.name': 'nested-error-1', | ||
'nested.0.inner.2.name': 'nested-error-2', | ||
'nested.2.inner.2.name': 'keep-nested-error-1', | ||
'nested.3.inner.0.name': 'keep-nested-error-2', | ||
'nested.5.inner.1.check': 'keep-nested-error-2', | ||
'nested.0.inner.2.check': 'nested-error-3', | ||
'nested.0.inner.5.check': 'nested-error-4', | ||
}; | ||
|
||
describe('@mantine/form/change-error-indices', () => { | ||
it('increments error indices', () => { | ||
expect(changeErrorIndices('fruits', 4, TEST_ERRORS, 1)).toStrictEqual({ | ||
name: 'name-error', | ||
// Errors with index lower than the given one don't change | ||
'fruits.0.name': 'fruit-error-1', | ||
'fruits.0.available': 'fruit-error-2', | ||
// Increment everything else | ||
'fruits.5.available': 'fruit-error-3', | ||
'fruits.16.inner.name': 'fruit-error-4', | ||
'fruits.16.inner.0.name': 'fruit-error-5', | ||
// Ignore non-matching paths | ||
'nested.0.inner.1.name': 'nested-error-1', | ||
'nested.0.inner.2.name': 'nested-error-2', | ||
'nested.2.inner.2.name': 'keep-nested-error-1', | ||
'nested.3.inner.0.name': 'keep-nested-error-2', | ||
'nested.5.inner.1.check': 'keep-nested-error-2', | ||
'nested.0.inner.2.check': 'nested-error-3', | ||
'nested.0.inner.5.check': 'nested-error-4', | ||
}); | ||
}); | ||
|
||
it('decrements error indices and removes errors for the removed element', () => { | ||
expect(changeErrorIndices('fruits', 4, TEST_ERRORS, -1)).toStrictEqual({ | ||
name: 'name-error', | ||
// Errors with index lower than the given one don't change | ||
'fruits.0.name': 'fruit-error-1', | ||
'fruits.0.available': 'fruit-error-2', | ||
// Remove the error with the given index | ||
// Decrement everything else | ||
'fruits.14.inner.name': 'fruit-error-4', | ||
'fruits.14.inner.0.name': 'fruit-error-5', | ||
// Ignore non-matching paths | ||
'nested.0.inner.1.name': 'nested-error-1', | ||
'nested.0.inner.2.name': 'nested-error-2', | ||
'nested.2.inner.2.name': 'keep-nested-error-1', | ||
'nested.3.inner.0.name': 'keep-nested-error-2', | ||
'nested.5.inner.1.check': 'keep-nested-error-2', | ||
'nested.0.inner.2.check': 'nested-error-3', | ||
'nested.0.inner.5.check': 'nested-error-4', | ||
}); | ||
}); | ||
|
||
it('increments deeply nested errors', () => { | ||
expect(changeErrorIndices('nested.0.inner', 2, TEST_ERRORS, 1)).toStrictEqual({ | ||
name: 'name-error', | ||
'fruits.0.name': 'fruit-error-1', | ||
'fruits.0.available': 'fruit-error-2', | ||
'fruits.4.available': 'fruit-error-3', | ||
'fruits.15.inner.name': 'fruit-error-4', | ||
'fruits.15.inner.0.name': 'fruit-error-5', | ||
'nested.0.inner.1.name': 'nested-error-1', | ||
'nested.0.inner.3.name': 'nested-error-2', | ||
'nested.2.inner.2.name': 'keep-nested-error-1', | ||
'nested.3.inner.0.name': 'keep-nested-error-2', | ||
'nested.5.inner.1.check': 'keep-nested-error-2', | ||
'nested.0.inner.3.check': 'nested-error-3', | ||
'nested.0.inner.6.check': 'nested-error-4', | ||
}); | ||
}); | ||
|
||
it('decrements deeply nested errors and removes errors for the removed element', () => { | ||
expect(changeErrorIndices('nested.0.inner', 2, TEST_ERRORS, -1)).toStrictEqual({ | ||
name: 'name-error', | ||
'fruits.0.name': 'fruit-error-1', | ||
'fruits.0.available': 'fruit-error-2', | ||
'fruits.4.available': 'fruit-error-3', | ||
'fruits.15.inner.name': 'fruit-error-4', | ||
'fruits.15.inner.0.name': 'fruit-error-5', | ||
'nested.0.inner.1.name': 'nested-error-1', | ||
'nested.2.inner.2.name': 'keep-nested-error-1', | ||
'nested.3.inner.0.name': 'keep-nested-error-2', | ||
'nested.5.inner.1.check': 'keep-nested-error-2', | ||
'nested.0.inner.4.check': 'nested-error-4', | ||
}); | ||
}); | ||
|
||
describe('returns unchanged object', () => { | ||
it('if index is undefined', () => { | ||
expect(changeErrorIndices('fruits', undefined, TEST_ERRORS, 1)).toStrictEqual(TEST_ERRORS); | ||
}); | ||
|
||
it('if path is not a string', () => { | ||
expect(changeErrorIndices(1, 1, TEST_ERRORS, 1)).toStrictEqual(TEST_ERRORS); | ||
}); | ||
|
||
it('if path does not exist', () => { | ||
expect(changeErrorIndices('does-not-exist', 1, TEST_ERRORS, 1)).toStrictEqual(TEST_ERRORS); | ||
}); | ||
|
||
it('if index is bigger than any error index', () => { | ||
expect(changeErrorIndices('fruits', 100, TEST_ERRORS, 1)).toStrictEqual(TEST_ERRORS); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import { clearListState } from './clear-list-state'; | ||
|
||
/** | ||
* Gets the part of the key after the path which can be an index | ||
*/ | ||
function getIndexFromKeyAfterPath(key: string, path: string): number { | ||
const split = key.substring(path.length + 1).split('.')[0]; | ||
return parseInt(split, 10); | ||
} | ||
|
||
/** | ||
* Changes the indices of every error that is after the given `index` with the given `change` at the given `path`. | ||
* This requires that the errors are in the format of `path.index` and that the index is a number. | ||
*/ | ||
export function changeErrorIndices<T extends Record<PropertyKey, any>>( | ||
path: PropertyKey, | ||
index: number, | ||
errors: T, | ||
change: 1 | -1 | ||
): T { | ||
if (index === undefined) { | ||
return errors; | ||
} | ||
const pathString = `${String(path)}`; | ||
let clearedErrors = errors; | ||
// Remove all errors if the corresponding item was removed | ||
if (change === -1) { | ||
clearedErrors = clearListState(`${pathString}.${index}`, clearedErrors); | ||
} | ||
|
||
const cloned = { ...clearedErrors }; | ||
const changedKeys = new Set<string>(); | ||
Object.entries(clearedErrors) | ||
.filter(([key]) => { | ||
if (!key.startsWith(`${pathString}.`)) { | ||
return false; | ||
} | ||
const currIndex = getIndexFromKeyAfterPath(key, pathString); | ||
if (Number.isNaN(currIndex)) { | ||
return false; | ||
} | ||
return currIndex >= index; | ||
}) | ||
.forEach(([key, value]) => { | ||
const currIndex = getIndexFromKeyAfterPath(key, pathString); | ||
|
||
const newKey: keyof T = key.replace( | ||
`${pathString}.${currIndex}`, | ||
`${pathString}.${currIndex + change}` | ||
); | ||
cloned[newKey] = value; | ||
changedKeys.add(newKey); | ||
if (!changedKeys.has(key)) { | ||
delete cloned[key]; | ||
} | ||
}); | ||
|
||
return cloned; | ||
} |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { clearListState } from './clear-list-state'; | ||
export { changeErrorIndices } from './change-error-indices'; | ||
export { reorderErrors } from './reorder-errors'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { reorderErrors } from './reorder-errors'; | ||
|
||
describe('@mantine/form/reorder-errors', () => { | ||
it('reorders errors at given path', () => { | ||
expect(reorderErrors('a', { from: 2, to: 0 }, { 'a.0': true })).toStrictEqual({ | ||
'a.2': true, | ||
}); | ||
expect(reorderErrors('a', { from: 2, to: 0 }, { 'a.0': true, 'a.2': 'Error' })).toStrictEqual({ | ||
'a.0': 'Error', | ||
'a.2': true, | ||
}); | ||
}); | ||
|
||
it('returns unchanged object if path does not exist', () => { | ||
const errors = { 'a.0': true }; | ||
expect(reorderErrors('c', { from: 1, to: 2 }, errors)).toStrictEqual(errors); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { ReorderPayload } from '../types'; | ||
|
||
export function reorderErrors<T>(path: unknown, { from, to }: ReorderPayload, errors: T): T { | ||
const oldKeyStart = `${path}.${from}`; | ||
const newKeyStart = `${path}.${to}`; | ||
|
||
const clone = { ...errors }; | ||
Object.keys(errors).every((key) => { | ||
let oldKey; | ||
let newKey; | ||
if (key.startsWith(oldKeyStart)) { | ||
oldKey = key; | ||
newKey = key.replace(oldKeyStart, newKeyStart); | ||
} | ||
if (key.startsWith(newKeyStart)) { | ||
oldKey = key.replace(newKeyStart, oldKeyStart); | ||
newKey = key; | ||
} | ||
if (oldKey && newKey) { | ||
const value1 = clone[oldKey]; | ||
const value2 = clone[newKey]; | ||
value2 === undefined ? delete clone[oldKey] : (clone[oldKey] = value2); | ||
value1 === undefined ? delete clone[newKey] : (clone[newKey] = value1); | ||
return false; | ||
} | ||
return true; | ||
}); | ||
|
||
return clone; | ||
} |
Oops, something went wrong.