Skip to content

Commit

Permalink
Merge pull request #19512 from storybookjs/future/CSF3-svelte
Browse files Browse the repository at this point in the history
Svelte: Improve CSF3 types
  • Loading branch information
ndelangen authored Oct 23, 2022
2 parents b1c48bc + 75d5e18 commit ff46c40
Show file tree
Hide file tree
Showing 27 changed files with 513 additions and 81 deletions.
2 changes: 2 additions & 0 deletions code/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ module.exports = {
'/examples/*/src/*.*',
'/examples/*/src/*/*.*',
'/examples/*/src/*/*/*.*',
// TODO: Can not get svelte-jester to work, but also not necessary for this test, as it is run by tsc/svelte-check.
'/renderers/svelte/src/public-types.test.ts',
],
collectCoverage: false,
collectCoverageFrom: [
Expand Down
1 change: 1 addition & 0 deletions code/lib/core-common/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export * from './utils/symlinks';
export * from './utils/template';
export * from './utils/validate-config';
export * from './utils/validate-configuration-files';
export * from './utils/satisfies';

export * from './types';

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@
"ts-jest": "^26.4.4",
"ts-node": "^10.4.0",
"tsup": "^6.2.2",
"typescript": "4.7.4",
"typescript": "~4.6.3",
"util": "^0.12.4",
"vite": "^3.1.7",
"wait-on": "^5.2.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { KeyboardEventHandler, ReactNode } from 'react';
import { expectTypeOf } from 'expect-type';
import { describe, test } from '@jest/globals';
import { satisfies } from '@storybook/core-common';
import { StoryAnnotations } from '@storybook/csf';
import { expectTypeOf } from 'expect-type';
import React, { KeyboardEventHandler, ReactNode } from 'react';
import { SetOptional } from 'type-fest';

import { Meta, StoryObj } from '../public-types';
import { DecoratorFn } from '../public-api';
import { satisfies } from './utils';
import { ReactFramework } from '../types';
import { DecoratorFn } from './public-api';
import { Meta, StoryObj } from './public-types';
import { ReactFramework } from './types';

type ReactStory<Args, RequiredArgs> = StoryAnnotations<ReactFramework, Args, RequiredArgs>;

Expand Down Expand Up @@ -75,6 +75,11 @@ describe('Args can be provided in multiple ways', () => {
expectTypeOf(Basic).toEqualTypeOf<Expected>();
}
});

test('Component can be used as generic parameter for StoryObj', () => {
type Expected = ReactStory<ButtonProps, ButtonProps>;
expectTypeOf<StoryObj<typeof Button>>().toEqualTypeOf<Expected>();
});
});

test('✅ All void functions are optional', () => {
Expand Down
34 changes: 16 additions & 18 deletions code/renderers/react/src/public-types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import type {
AnnotatedStoryFn,
Args,
ArgsFromMeta,
ArgsStoryFn,
ComponentAnnotations,
LoaderFunction,
StoryAnnotations,
} from '@storybook/csf';
import { SetOptional, Simplify, UnionToIntersection } from 'type-fest';
import { ComponentProps, ComponentType, JSXElementConstructor } from 'react';
import { SetOptional, Simplify } from 'type-fest';

import { ReactFramework } from './types';
import { DecoratorFn } from './public-api';

type JSXElement = keyof JSX.IntrinsicElements | JSXElementConstructor<any>;

Expand All @@ -36,29 +35,28 @@ export type StoryFn<TArgs = Args> = AnnotatedStoryFn<ReactFramework, TArgs>;
* @see [Named Story exports](https://storybook.js.org/docs/formats/component-story-format/#named-story-exports)
*/

export type StoryObj<MetaOrArgs = Args> = MetaOrArgs extends {
render?: ArgsStoryFn<ReactFramework, infer RArgs>;
component?: ComponentType<infer CmpArgs>;
loaders?: (infer Loaders)[];
export type StoryObj<MetaOrCmpOrArgs = Args> = MetaOrCmpOrArgs extends {
render?: ArgsStoryFn<ReactFramework, any>;
component?: infer Component;
args?: infer DefaultArgs;
decorators?: (infer Decorators)[];
}
? Simplify<CmpArgs & RArgs & DecoratorsArgs<Decorators> & LoaderArgs<Loaders>> extends infer TArgs
? Simplify<
(Component extends ComponentType<any> ? ComponentProps<Component> : unknown) &
ArgsFromMeta<ReactFramework, MetaOrCmpOrArgs>
> extends infer TArgs
? StoryAnnotations<
ReactFramework,
TArgs,
SetOptional<TArgs, Extract<keyof TArgs, keyof (DefaultArgs & ActionArgs<TArgs>)>>
>
: never
: StoryAnnotations<ReactFramework, MetaOrArgs>;

type DecoratorsArgs<Decorators> = UnionToIntersection<
Decorators extends DecoratorFn<infer Args> ? Args : unknown
>;

type LoaderArgs<Loaders> = UnionToIntersection<
Loaders extends LoaderFunction<ReactFramework, infer Args> ? Args : unknown
>;
: MetaOrCmpOrArgs extends ComponentType<any>
? StoryAnnotations<
ReactFramework,
ComponentProps<MetaOrCmpOrArgs>,
ComponentProps<MetaOrCmpOrArgs>
>
: StoryAnnotations<ReactFramework, MetaOrCmpOrArgs>;

type ActionArgs<Args> = {
[P in keyof Args as ((...args: any[]) => void) extends Args[P] ? P : never]: Args[P];
Expand Down
7 changes: 5 additions & 2 deletions code/renderers/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"*.d.ts"
],
"scripts": {
"check": "../../../scripts/node_modules/.bin/tsc --noEmit",
"check": "svelte-check --tsconfig ./tsconfig.json",
"prep": "../../../scripts/prepare/bundle.ts"
},
"dependencies": {
Expand All @@ -63,10 +63,13 @@
"global": "^4.4.0",
"react": "16.14.0",
"react-dom": "16.14.0",
"sveltedoc-parser": "^4.2.1"
"sveltedoc-parser": "^4.2.1",
"type-fest": "2.19.0"
},
"devDependencies": {
"expect-type": "^0.14.2",
"svelte": "^3.31.2",
"svelte-check": "^2.9.2",
"typescript": "~4.6.3"
},
"peerDependencies": {
Expand Down
12 changes: 12 additions & 0 deletions code/renderers/svelte/src/__test__/Button.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte';
export let disabled: boolean;
export let label: string;
const dispatch = createEventDispatcher();
</script>

<button on:click={(e) => dispatch('clicked', e)} on:dblclick on:mousemove {disabled}>
{label}
</button>
8 changes: 8 additions & 0 deletions code/renderers/svelte/src/__test__/Decorator.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
export let decoratorArg: string;
</script>

<div>
Decorator: {decoratorArg}
<slot />
</div>
8 changes: 8 additions & 0 deletions code/renderers/svelte/src/__test__/Decorator2.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
export let decoratorArg2: string;
</script>

<div>
Decorator: {decoratorArg2}
<slot />
</div>
1 change: 1 addition & 0 deletions code/renderers/svelte/src/docs/extractArgTypes.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect } from '@jest/globals';
import svelteDoc from 'sveltedoc-parser';
import * as fs from 'fs';
import { createArgTypes } from './extractArgTypes';
Expand Down
2 changes: 1 addition & 1 deletion code/renderers/svelte/src/docs/extractArgTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export const createArgTypes = (docgen: SvelteComponentDoc) => {

/**
* Function to convert the type from sveltedoc-parser to a storybook type
* @param typeName
* @param type
* @returns string
*/
const parseTypeToControl = (type: JSDocType | undefined): any => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { describe, expect, test } from '@jest/globals';
import { extractComponentDescription } from './extractComponentDescription';

describe('extractComponentDescription', () => {
Expand Down
7 changes: 4 additions & 3 deletions code/renderers/svelte/src/docs/sourceDecorator.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { describe, expect, test } from '@jest/globals';
import type { Args } from '@storybook/api';
import { generateSvelteSource } from './sourceDecorator';

expect.addSnapshotSerializer({
print: (val: any) => val,
test: (val) => typeof val === 'string',
test: (val: unknown) => typeof val === 'string',
});

function generateForArgs(args: Args, slotProperty: string = null) {
function generateForArgs(args: Args, slotProperty: string | null = null) {
return generateSvelteSource({ name: 'Component' }, args, {}, slotProperty);
}

Expand Down Expand Up @@ -42,6 +43,6 @@ describe('generateSvelteSource', () => {
`);
});
test('component is not set', () => {
expect(generateSvelteSource(null, null, null, null)).toBeNull();
expect(generateSvelteSource(null, {}, {}, null)).toBeNull();
});
});
2 changes: 1 addition & 1 deletion code/renderers/svelte/src/docs/sourceDecorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export function generateSvelteSource(
component: any,
args: Args,
argTypes: ArgTypes,
slotProperty?: string
slotProperty?: string | null
): string | null {
const name = getComponentName(component);

Expand Down
1 change: 0 additions & 1 deletion code/renderers/svelte/src/globals.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @ts-expect-error (Converted from ts-ignore)
import global from 'global';

const { window: globalWindow } = global;
Expand Down
Loading

0 comments on commit ff46c40

Please sign in to comment.