diff --git a/docs/snippets/common/storybook-preview-with-ordered-pages-and-wildcard.js.mdx b/docs/snippets/common/storybook-preview-with-ordered-pages-and-wildcard.js.mdx new file mode 100644 index 000000000000..47723a4d0c0e --- /dev/null +++ b/docs/snippets/common/storybook-preview-with-ordered-pages-and-wildcard.js.mdx @@ -0,0 +1,11 @@ +```js +// .storybook/preview.js + +export const parameters = { + options: { + storySort: { + order: ['Intro', 'Pages', ['Home', 'Login', 'Admin'], 'Components', '*', 'WIP'], + }, + }, +}; +``` diff --git a/docs/writing-stories/naming-components-and-hierarchy.md b/docs/writing-stories/naming-components-and-hierarchy.md index 6468ef466e21..50b99f0c78ea 100644 --- a/docs/writing-stories/naming-components-and-hierarchy.md +++ b/docs/writing-stories/naming-components-and-hierarchy.md @@ -129,4 +129,18 @@ Which would result in this story ordering: 7. `Components` and `Components/*` stories 8. All other stories +If you want certain categories to sort to the end of the list, you can insert a `*` into your `order` array to indicate where "all other stories" should go: + + + + + + + +In this example, the `WIP` category would be displayed at the end of the list. + Note that the `order` option is independent of the `method` option; stories are sorted first by the `order` array and then by either the `method: 'alphabetical'` or the default `configure()` import order. diff --git a/lib/client-api/src/storySort.test.ts b/lib/client-api/src/storySort.test.ts index ff9a06468b28..b80ddf16ca1f 100644 --- a/lib/client-api/src/storySort.test.ts +++ b/lib/client-api/src/storySort.test.ts @@ -8,8 +8,10 @@ describe('preview.storySort', () => { b: ['', { kind: 'b' }], a_a: ['', { kind: 'a/a' }], a_b: ['', { kind: 'a/b' }], + a_c: ['', { kind: 'a/c' }], b_a_a: ['', { kind: 'b/a/a' }], b_b: ['', { kind: 'b/b' }], + c: ['', { kind: 'c' }], locale1: ['', { kind: 'Б' }], locale2: ['', { kind: 'Г' }], }; @@ -73,4 +75,26 @@ describe('preview.storySort', () => { expect(sortFn(fixture.a_a, fixture.a_b)).toBeGreaterThan(0); expect(sortFn(fixture.a_b, fixture.a_a)).toBeLessThan(0); }); + + it('sorts according to the order array with a wildcard', () => { + const sortFn = storySort({ order: ['a', '*', 'b'] }); + + expect(sortFn(fixture.a, fixture.b)).toBeLessThan(0); + expect(sortFn(fixture.c, fixture.b)).toBeLessThan(0); + expect(sortFn(fixture.b, fixture.c)).toBeGreaterThan(0); + expect(sortFn(fixture.b, fixture.a)).toBeGreaterThan(0); + }); + + it('sorts according to the nested order array with wildcard', () => { + const sortFn = storySort({ order: ['a', ['a', '*', 'b'], 'c'] }); + + expect(sortFn(fixture.a, fixture.c)).toBeLessThan(0); + expect(sortFn(fixture.c, fixture.a)).toBeGreaterThan(0); + expect(sortFn(fixture.a_a, fixture.a_b)).toBeLessThan(0); + expect(sortFn(fixture.a_b, fixture.a_a)).toBeGreaterThan(0); + expect(sortFn(fixture.a_a, fixture.a_c)).toBeLessThan(0); + expect(sortFn(fixture.a_c, fixture.a_a)).toBeGreaterThan(0); + expect(sortFn(fixture.a_c, fixture.a_b)).toBeLessThan(0); + expect(sortFn(fixture.a_b, fixture.a_c)).toBeGreaterThan(0); + }); }); diff --git a/lib/client-api/src/storySort.ts b/lib/client-api/src/storySort.ts index 73253c28ef6c..12402e58902c 100644 --- a/lib/client-api/src/storySort.ts +++ b/lib/client-api/src/storySort.ts @@ -34,15 +34,25 @@ export const storySort = (options: StorySortObjectParameter = {}): StorySortComp // Look for the names in the given `order` array. let indexA = order.indexOf(nameA); let indexB = order.indexOf(nameB); + const indexWildcard = order.indexOf('*'); // If at least one of the names is found, sort by the `order` array. if (indexA !== -1 || indexB !== -1) { - // If one of the names is not found in `order`, list it last. + // If one of the names is not found and there is a wildcard, insert it at the wildcard position. + // Otherwise, list it last. if (indexA === -1) { - indexA = order.length; + if (indexWildcard !== -1) { + indexA = indexWildcard; + } else { + indexA = order.length; + } } if (indexB === -1) { - indexB = order.length; + if (indexWildcard !== -1) { + indexB = indexWildcard; + } else { + indexB = order.length; + } } return indexA - indexB; diff --git a/lib/client-api/src/story_store.test.ts b/lib/client-api/src/story_store.test.ts index 2d2b87068fb8..6b0e43ee1d8d 100644 --- a/lib/client-api/src/story_store.test.ts +++ b/lib/client-api/src/story_store.test.ts @@ -1083,6 +1083,42 @@ describe('preview.story_store', () => { ]); }); + it('sorts stories in specified order or alphabetically with wildcards', () => { + const store = new StoryStore({ channel }); + store.addGlobalMetadata({ + decorators: [], + parameters: { + options: { + storySort: { + method: 'alphabetical', + order: ['b', ['bc', '*', 'bb'], '*', 'c'], + }, + }, + }, + }); + addStoryToStore(store, 'a/b', '1', () => 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--1', + 'b-bc--1', + 'b-ba--1', + 'b-bd--1', + 'b-bb--1', + 'a--1', + 'a-b--1', + 'c--1', + ]); + }); + it('sorts stories in specified order or by configure order', () => { const store = new StoryStore({ channel }); store.addGlobalMetadata({ @@ -1119,6 +1155,46 @@ describe('preview.story_store', () => { ]); }); + it('sorts stories in specified order or by configure order with wildcard', () => { + const store = new StoryStore({ channel }); + store.addGlobalMetadata({ + decorators: [], + parameters: { + options: { + storySort: { + method: 'configure', + order: ['b', '*', 'c'], + }, + }, + }, + }); + addStoryToStore(store, 'a/b', '1', () => 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); + addStoryToStore(store, 'e', '1', () => 0); + addStoryToStore(store, 'd', '1', () => 0); + + const extracted = store.extract(); + + expect(Object.keys(extracted)).toEqual([ + 'b--1', + 'b-bd--1', + 'b-bb--1', + 'b-ba--1', + 'b-bc--1', + 'a--1', + 'a-b--1', + 'e--1', + 'd--1', + 'c--1', + ]); + }); + it('passes kind and global parameters to sort', () => { const store = new StoryStore({ channel }); const storySort = jest.fn();