Merge pull request #12520 from diedu89/feat/sorting-include-name

Core: Add option to include story names when sorting
This commit is contained in:
Michael Shilman 2021-04-30 14:03:40 +08:00 committed by GitHub
commit 303e4bfaa8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 123 additions and 11 deletions

View File

@ -100,11 +100,12 @@ The `storySort` can also accept a configuration object.
<!-- prettier-ignore-end -->
| Field | Type | Description | Required | Default Value | Example |
| ----------- | :----: | :------------------------------------------------------: | :------: | :---------------------: | :-----------------------: |
| **method** | String | Tells Storybook in which order the stories are displayed | No | Storybook configuration | `'alphabetical'` |
| **order** | Array | The stories to be shown, ordered by supplied name | No | Empty Array `[]` | `['Intro', 'Components']` |
| **locales** | String | The locale required to be displayed | No | System locale | `en-US` |
| Field | Type | Description | Required | Default Value | Example |
| --------------- | :-----: | :------------------------------------------------------: | :------: | :---------------------: | :-----------------------: |
| **method** | String | Tells Storybook in which order the stories are displayed | No | Storybook configuration | `'alphabetical'` |
| **order** | Array | The stories to be show, ordered by supplied name | No | Empty Array `[]` | `['Intro', 'Components']` |
| **includeName** | Boolean | Include story name in sort calculation | No | `false` | `true` |
| **locales** | String | The locale required to be displayed | No | System locale | `en-US` |
To sort your stories alphabetically, set `method` to `'alphabetical'` and optionally set the `locales` string. To sort your stories using a custom list, use the `order` array; stories that don't match an item in the `order` list will appear after the items in the list.

View File

@ -77,6 +77,7 @@ export interface StorySortObjectParameter {
method?: StorySortMethod;
order?: any[];
locales?: string;
includeNames?: boolean;
}
// The `any` here is the story store's `StoreItem` record. Ideally we should probably only
// pass a defined subset of that full data, but we pass it all so far :shrug:

View File

@ -14,6 +14,11 @@ describe('preview.storySort', () => {
c: ['', { kind: 'c' }],
locale1: ['', { kind: 'Б' }],
locale2: ['', { kind: 'Г' }],
c__a: ['', { kind: 'c', name: 'a' }],
c_b__a: ['', { kind: 'c/b', name: 'a' }],
c_b__b: ['', { kind: 'c/b', name: 'b' }],
c_b__c: ['', { kind: 'c/b', name: 'c' }],
c__c: ['', { kind: 'c', name: 'c' }],
};
it('uses configure order by default', () => {
@ -76,6 +81,28 @@ describe('preview.storySort', () => {
expect(sortFn(fixture.a_b, fixture.a_a)).toBeLessThan(0);
});
it('sorts alphabetically including story names', () => {
const sortFn = storySort({ method: 'alphabetical', includeNames: true });
expect(sortFn(fixture.c_b__a, fixture.c__a)).toBeGreaterThan(0);
expect(sortFn(fixture.c__a, fixture.c_b__a)).toBeLessThan(0);
expect(sortFn(fixture.c__c, fixture.c__a)).toBeGreaterThan(0);
expect(sortFn(fixture.c__a, fixture.c__c)).toBeLessThan(0);
});
it('sorts according to the order array including story names', () => {
const sortFn = storySort({
order: ['c', ['b', ['c', 'b', 'a'], 'c', 'a']],
includeNames: true,
});
expect(sortFn(fixture.c_b__a, fixture.c_b__b)).toBeGreaterThan(0);
expect(sortFn(fixture.c_b__b, fixture.c_b__c)).toBeGreaterThan(0);
expect(sortFn(fixture.c_b__a, fixture.c_b__c)).toBeGreaterThan(0);
expect(sortFn(fixture.c_b__a, fixture.c__a)).toBeLessThan(0);
expect(sortFn(fixture.c_b__a, fixture.c__c)).toBeLessThan(0);
expect(sortFn(fixture.c__a, fixture.c__c)).toBeGreaterThan(0);
});
it('sorts according to the order array with a wildcard', () => {
const sortFn = storySort({ order: ['a', '*', 'b'] });

View File

@ -6,7 +6,8 @@ export const storySort = (options: StorySortObjectParameter = {}): StorySortComp
): number => {
// If the two stories have the same story kind, then use the default
// ordering, which is the order they are defined in the story file.
if (a[1].kind === b[1].kind) {
// only when includeNames is falsy
if (a[1].kind === b[1].kind && !options.includeNames) {
return 0;
}
@ -15,8 +16,8 @@ export const storySort = (options: StorySortObjectParameter = {}): StorySortComp
let order = options.order || [];
// Examine each part of the story kind in turn.
const storyKindA = a[1].kind.split('/');
const storyKindB = b[1].kind.split('/');
const storyKindA = [...a[1].kind.split('/'), ...(options.includeNames ? a[1].name : [])];
const storyKindB = [...b[1].kind.split('/'), ...(options.includeNames ? b[1].name : [])];
let depth = 0;
while (storyKindA[depth] || storyKindB[depth]) {
// Stories with a shorter depth should go first.

View File

@ -1195,6 +1195,84 @@ describe('preview.story_store', () => {
]);
});
it('sorts stories in specified order including story names or configure', () => {
const store = new StoryStore({ channel });
store.addGlobalMetadata({
decorators: [],
parameters: {
options: {
storySort: {
method: 'configure',
order: ['b', ['bc', 'ba', 'bb'], 'a', 'c'],
includeNames: true,
},
},
},
});
addStoryToStore(store, 'a/b', '1', () => 0);
addStoryToStore(store, 'a', '2', () => 0);
addStoryToStore(store, 'a', '1', () => 0);
addStoryToStore(store, 'c', '1', () => 0);
addStoryToStore(store, 'b/bd', '1', () => 0);
addStoryToStore(store, 'b/bb', '1', () => 0);
addStoryToStore(store, 'b/ba', '1', () => 0);
addStoryToStore(store, 'b/bc', '1', () => 0);
addStoryToStore(store, 'b', '1', () => 0);
const extracted = store.extract();
expect(Object.keys(extracted)).toEqual([
'b-bc--1',
'b-ba--1',
'b-bb--1',
'b-bd--1',
'b--1',
'a-b--1',
'a--2',
'a--1',
'c--1',
]);
});
it('sorts stories in specified order including story names or alphabetically', () => {
const store = new StoryStore({ channel });
store.addGlobalMetadata({
decorators: [],
parameters: {
options: {
storySort: {
method: 'alphabetical',
order: ['b', ['bc', 'ba', 'bb'], 'a', 'c'],
includeNames: true,
},
},
},
});
addStoryToStore(store, 'a/b', '1', () => 0);
addStoryToStore(store, 'a', '2', () => 0);
addStoryToStore(store, 'a', '1', () => 0);
addStoryToStore(store, 'c', '1', () => 0);
addStoryToStore(store, 'b/bd', '1', () => 0);
addStoryToStore(store, 'b/bb', '1', () => 0);
addStoryToStore(store, 'b/ba', '1', () => 0);
addStoryToStore(store, 'b/bc', '1', () => 0);
addStoryToStore(store, 'b', '1', () => 0);
const extracted = store.extract();
expect(Object.keys(extracted)).toEqual([
'b-bc--1',
'b-ba--1',
'b-bb--1',
'b--1',
'b-bd--1',
'a--1',
'a--2',
'a-b--1',
'c--1',
]);
});
it('passes kind and global parameters to sort', () => {
const store = new StoryStore({ channel });
const storySort = jest.fn();

View File

@ -4,7 +4,9 @@ import { ZoomIFrame as IFrame } from './ZoomIFrame';
export const browserSupportsCssZoom = (): boolean => {
try {
return globalWindow.document.implementation.createHTMLDocument('').body.style.zoom !== undefined;
return (
globalWindow.document.implementation.createHTMLDocument('').body.style.zoom !== undefined
);
} catch (error) {
return false;
}

View File

@ -2,7 +2,9 @@ import { window as globalWindow } from 'global';
export function browserSupportsCssZoom(): boolean {
try {
return globalWindow.document.implementation.createHTMLDocument('').body.style.zoom !== undefined;
return (
globalWindow.document.implementation.createHTMLDocument('').body.style.zoom !== undefined
);
} catch (error) {
return false;
}

View File

@ -73,4 +73,4 @@ const Handle = styled.div<{ isDragging: boolean; axis: Axis }>(
);
export { Draggable, Handle };
export type { DraggableEvent, DraggableData };
export type { DraggableEvent, DraggableData };