diff --git a/code/frameworks/angular/src/client/argsToTemplate.test.ts b/code/frameworks/angular/src/client/argsToTemplate.test.ts new file mode 100644 index 000000000000..88db1208a6ee --- /dev/null +++ b/code/frameworks/angular/src/client/argsToTemplate.test.ts @@ -0,0 +1,102 @@ +import { argsToTemplate, ArgsToTemplateOptions } from './argsToTemplate'; // adjust path + +describe('argsToTemplate', () => { + it('should correctly convert args to template string and exclude undefined values', () => { + const args: Record = { + prop1: 'value1', + prop2: undefined, + prop3: 'value3', + }; + const options: ArgsToTemplateOptions = {}; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1" [prop3]="prop3"'); + }); + + it('should include properties from include option', () => { + const args = { + prop1: 'value1', + prop2: 'value2', + prop3: 'value3', + }; + const options: ArgsToTemplateOptions = { + include: ['prop1', 'prop3'], + }; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1" [prop3]="prop3"'); + }); + + it('should include non-undefined properties from include option', () => { + const args: Record = { + prop1: 'value1', + prop2: 'value2', + prop3: undefined, + }; + const options: ArgsToTemplateOptions = { + include: ['prop1', 'prop3'], + }; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1"'); + }); + + it('should exclude properties from exclude option', () => { + const args = { + prop1: 'value1', + prop2: 'value2', + prop3: 'value3', + }; + const options: ArgsToTemplateOptions = { + exclude: ['prop2'], + }; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1" [prop3]="prop3"'); + }); + + it('should exclude properties from exclude option and undefined properties', () => { + const args: Record = { + prop1: 'value1', + prop2: 'value2', + prop3: undefined, + }; + const options: ArgsToTemplateOptions = { + exclude: ['prop2'], + }; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1"'); + }); + + it('should prioritize include over exclude when both options are given', () => { + const args = { + prop1: 'value1', + prop2: 'value2', + prop3: 'value3', + }; + const options: ArgsToTemplateOptions = { + include: ['prop1', 'prop2'], + exclude: ['prop2', 'prop3'], + }; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1" [prop2]="prop2"'); + }); + + it('should work when neither include nor exclude options are given', () => { + const args = { + prop1: 'value1', + prop2: 'value2', + }; + const options: ArgsToTemplateOptions = {}; + const result = argsToTemplate(args, options); + expect(result).toBe('[prop1]="prop1" [prop2]="prop2"'); + }); + + it('should bind events correctly when value is a function', () => { + const args = { event1: () => {}, event2: () => {} }; + const result = argsToTemplate(args, {}); + expect(result).toEqual('(event1)="event1($event)" (event2)="event2($event)"'); + }); + + it('should mix properties and events correctly', () => { + const args = { input: 'Value1', event1: () => {} }; + const result = argsToTemplate(args, {}); + expect(result).toEqual('[input]="input" (event1)="event1($event)"'); + }); +}); diff --git a/code/frameworks/angular/src/client/argsToTemplate.ts b/code/frameworks/angular/src/client/argsToTemplate.ts new file mode 100644 index 000000000000..0072aa84743d --- /dev/null +++ b/code/frameworks/angular/src/client/argsToTemplate.ts @@ -0,0 +1,74 @@ +/** + * Options for controlling the behavior of the argsToTemplate function. + * + * @template T The type of the keys in the target object. + */ +export interface ArgsToTemplateOptions { + /** + * An array of keys to specifically include in the output. + * If provided, only the keys from this array will be included in the output, + * irrespective of the `exclude` option. Undefined values will still be excluded from the output. + */ + include?: Array; + /** + * An array of keys to specifically exclude from the output. + * If provided, these keys will be omitted from the output. This option is + * ignored if the `include` option is also provided + */ + exclude?: Array; +} + +/** + * Converts an object of arguments to a string of property and event bindings and excludes undefined values. + * Why? Because Angular treats undefined values in property bindings as an actual value + * and does not apply the default value of the property as soon as the binding is set. + * This feels counter-intuitive and is a common source of bugs in stories. + * @example + * ```ts + * // component.ts + *ㅤ@Component({ selector: 'example' }) + * export class ExampleComponent { + * ㅤ@Input() input1: string = 'Default Input1'; + * ㅤ@Input() input2: string = 'Default Input2'; + * ㅤ@Output() click = new EventEmitter(); + * } + * + * // component.stories.ts + * import { argsToTemplate } from '@storybook/angular'; + * export const Input1: Story = { + * render: (args) => ({ + * props: args, + * // Problem1: + * // This will set input2 to undefined and the internal default value will not be used. + * // Problem2: + * // The default value of input2 will be used, but it is not overridable by the user via controls. + * // Solution: Now the controls will be applicable to both input1 and input2, and the default values will be used if the user does not override them. + * template: ``, + * }), + * args: { + * // In this Story, we want to set the input1 property, and the internal default property of input2 should be used. + * input1: 'Input 1', + * click: { action: 'clicked' }, + * }, + *}; + * ``` + */ +export function argsToTemplate>( + args: A, + options: ArgsToTemplateOptions = {} +) { + const includeSet = options.include ? new Set(options.include) : null; + const excludeSet = options.exclude ? new Set(options.exclude) : null; + + return Object.entries(args) + .filter(([key]) => args[key] !== undefined) + .filter(([key]) => { + if (includeSet) return includeSet.has(key); + if (excludeSet) return !excludeSet.has(key); + return true; + }) + .map(([key, value]) => + typeof value === 'function' ? `(${key})="${key}($event)"` : `[${key}]="${key}"` + ) + .join(' '); +} diff --git a/code/frameworks/angular/src/client/index.ts b/code/frameworks/angular/src/client/index.ts index bfc209efb4d4..2377678bda2e 100644 --- a/code/frameworks/angular/src/client/index.ts +++ b/code/frameworks/angular/src/client/index.ts @@ -10,6 +10,7 @@ export * from './public-types'; export type { StoryFnAngularReturnType as IStory } from './types'; export { moduleMetadata, componentWrapperDecorator, applicationConfig } from './decorators'; +export { argsToTemplate } from './argsToTemplate'; // optimization: stop HMR propagation in webpack if (typeof module !== 'undefined') module?.hot?.decline(); diff --git a/code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.stories.ts b/code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.stories.ts index d23f3896359f..11dc4d7cd32d 100644 --- a/code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.stories.ts +++ b/code/frameworks/angular/template/stories/argTypes/doc-button/doc-button.stories.ts @@ -1,24 +1,29 @@ -import { Args } from '@storybook/angular'; +import { Meta, StoryObj, argsToTemplate } from '@storybook/angular'; import { DocButtonComponent } from './doc-button.component'; -export default { +const meta: Meta> = { component: DocButtonComponent, }; -export const Basic = (args: Args) => ({ - props: args, -}); -Basic.args = { label: 'Args test', isDisabled: false }; -Basic.ArgTypes = { - theDefaultValue: { - table: { - defaultValue: { summary: 'Basic default value' }, +export default meta; + +type Story = StoryObj>; + +export const Basic: Story = { + args: { label: 'Args test', isDisabled: false }, + argTypes: { + theDefaultValue: { + table: { + defaultValue: { summary: 'Basic default value' }, + }, }, }, }; -export const WithTemplate = (args: Args) => ({ - props: args, - template: '', -}); -WithTemplate.args = { label: 'Template test', appearance: 'primary' }; +export const WithTemplate: Story = { + args: { label: 'Template test', appearance: 'primary' }, + render: (args) => ({ + props: args, + template: ``, + }), +}; diff --git a/code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.stories.ts b/code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.stories.ts index b734b93bf40d..e949d8e88252 100644 --- a/code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.stories.ts +++ b/code/frameworks/angular/template/stories/argTypes/doc-directive/doc-directive.stories.ts @@ -1,14 +1,19 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { DocDirective } from './doc-directive.directive'; -export default { +const meta: Meta = { component: DocDirective, }; -const modules = { - declarations: [DocDirective], -}; +export default meta; + +type Story = StoryObj; -export const Basic = () => ({ - moduleMetadata: modules, - template: '

DocDirective

', -}); +export const Basic: Story = { + render: () => ({ + moduleMetadata: { + declarations: [DocDirective], + }, + template: '

DocDirective

', + }), +}; diff --git a/code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.stories.ts b/code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.stories.ts index eca5e10fb11d..7741bca9ba88 100644 --- a/code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.stories.ts +++ b/code/frameworks/angular/template/stories/argTypes/doc-injectable/doc-injectable.stories.ts @@ -1,14 +1,19 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { DocInjectableService } from './doc-injectable.service'; -export default { +const meta: Meta = { component: DocInjectableService, }; -const modules = { - provider: [DocInjectableService], -}; +export default meta; + +type Story = StoryObj; -export const Basic = () => ({ - moduleMetadata: modules, - template: '

DocInjectable

', -}); +export const Basic: Story = { + render: () => ({ + moduleMetadata: { + providers: [DocInjectableService], + }, + template: '

DocInjectable

', + }), +}; diff --git a/code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.stories.ts b/code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.stories.ts index 6ab616f16ee2..018ab04a9951 100644 --- a/code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.stories.ts +++ b/code/frameworks/angular/template/stories/argTypes/doc-pipe/doc-pipe.stories.ts @@ -1,14 +1,19 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { DocPipe } from './doc-pipe.pipe'; -export default { +const meta: Meta = { component: DocPipe, }; -const modules = { - declarations: [DocPipe], -}; +export default meta; + +type Story = StoryObj; -export const Basic = () => ({ - moduleMetadata: modules, - template: `

{{ 'DocPipe' | docPipe }}

`, -}); +export const Basic: Story = { + render: () => ({ + moduleMetadata: { + declarations: [DocPipe], + }, + template: `

{{ 'DocPipe' | docPipe }}

`, + }), +}; diff --git a/code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva-component.stories.ts b/code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva-component.stories.ts index 228e2d7b9045..0396bae99acc 100644 --- a/code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva-component.stories.ts +++ b/code/frameworks/angular/template/stories/basics/angular-forms/customControlValueAccessor/custom-cva-component.stories.ts @@ -1,8 +1,8 @@ import { FormsModule } from '@angular/forms'; -import { Meta, StoryFn, moduleMetadata } from '@storybook/angular'; +import { Meta, StoryFn, StoryObj, moduleMetadata } from '@storybook/angular'; import { CustomCvaComponent } from './custom-cva.component'; -export default { +const meta: Meta = { // title: 'Basics / Angular forms / ControlValueAccessor', component: CustomCvaComponent, decorators: [ @@ -17,11 +17,16 @@ export default { ], } as Meta; -export const SimpleInput: StoryFn = () => ({ - props: { - ngModel: 'Type anything', - ngModelChange: () => {}, - }, -}); +export default meta; -SimpleInput.storyName = 'Simple input'; +type Story = StoryObj; + +export const SimpleInput: Story = { + name: 'Simple input', + render: () => ({ + props: { + ngModel: 'Type anything', + ngModelChange: () => {}, + }, + }), +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selectors.component.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selectors.component.stories.ts index d935de5215d7..73894b83b34a 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selectors.component.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-complex-selectors/attribute-selectors.component.stories.ts @@ -1,8 +1,13 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { AttributeSelectorComponent } from './attribute-selector.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Complex Selectors', component: AttributeSelectorComponent, }; -export const AttributeSelectors = {}; +export default meta; + +type Story = StoryObj; + +export const AttributeSelectors: Story = {}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.stories.ts index 647ca86d8d67..b79bd371baf3 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-enums/enums.component.stories.ts @@ -1,4 +1,4 @@ -import { Meta, StoryFn } from '@storybook/angular'; +import { Meta, StoryObj } from '@storybook/angular'; import { EnumsComponent, EnumNumeric, @@ -6,19 +6,22 @@ import { EnumStringValues, } from './enums.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Enum Types', component: EnumsComponent, -} as Meta; +}; + +export default meta; + +type Story = StoryObj; -export const Basic: StoryFn = (args) => ({ - props: args, -}); -Basic.args = { - unionType: 'union a', - aliasedUnionType: 'Type Alias 1', - enumNumeric: EnumNumeric.FIRST, - enumNumericInitial: EnumNumericInitial.UNO, - enumStrings: EnumStringValues.PRIMARY, - enumAlias: EnumNumeric.FIRST, +export const Basic: Story = { + args: { + unionType: 'Union A', + aliasedUnionType: 'Type Alias 1', + enumNumeric: EnumNumeric.FIRST, + enumNumericInitial: EnumNumericInitial.UNO, + enumStrings: EnumStringValues.PRIMARY, + enumAlias: EnumNumeric.FIRST, + }, }; diff --git a/code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.stories.ts index a206115f5de7..271e6a3fcc9d 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-inheritance/base-button.stories.ts @@ -1,12 +1,15 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { BaseButtonComponent } from './base-button.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Inheritance', component: BaseButtonComponent, }; -export const BaseButton = () => ({ - props: { +export default meta; + +export const BaseButton: StoryObj = { + args: { label: 'this is label', }, -}); +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.stories.ts index baefe65c4f58..bb5c5fb02bcb 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-inheritance/icon-button.stories.ts @@ -1,13 +1,18 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { IconButtonComponent } from './icon-button.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Inheritance', component: IconButtonComponent, }; -export const IconButton = () => ({ - props: { +export default meta; + +type Story = StoryObj; + +export const IconButton: Story = { + args: { icon: 'this is icon', label: 'this is label', }, -}); +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-about-parent.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-about-parent.stories.ts index 0512582aca6e..f8185f8eb80a 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-about-parent.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-about-parent.stories.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { componentWrapperDecorator, Meta, StoryFn } from '@storybook/angular'; +import { componentWrapperDecorator, Meta, StoryObj } from '@storybook/angular'; @Component({ selector: 'sb-button', @@ -17,7 +17,7 @@ class SbButtonComponent { color = '#5eadf5'; } -export default { +const meta: Meta = { // title: 'Basics / Component / With ng-content / Button with different contents', // Implicitly declares the component to Angular // This will be the component described by the addon docs @@ -35,24 +35,24 @@ export default { }, } as Meta; +export default meta; + +type Story = StoryObj; + // By default storybook uses the default export component if no template or component is defined in the story // So Storybook nests the component twice because it is first added by the componentWrapperDecorator. -export const AlwaysDefineTemplateOrComponent: StoryFn = () => ({}); +export const AlwaysDefineTemplateOrComponent: Story = {}; -export const EmptyButton: StoryFn = () => ({ - template: '', -}); - -export const WithDynamicContentAndArgs: StoryFn = (args) => ({ - template: `${args['content']}`, -}); -WithDynamicContentAndArgs.argTypes = { - content: { control: 'text' }, +export const EmptyButton: Story = { + render: () => ({ + template: '', + }), }; -WithDynamicContentAndArgs.args = { content: 'My button text' }; -export const InH1: StoryFn = () => ({ - template: 'My button in h1', -}); -InH1.decorators = [componentWrapperDecorator((story) => `

${story}

`)]; -InH1.storyName = 'In

'; +export const InH1: Story = { + render: () => ({ + template: 'My button in h1', + }), + decorators: [componentWrapperDecorator((story) => `

${story}

`)], + name: 'In

', +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-simple.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-simple.stories.ts index 13cc2eb550c5..71b0fe84df38 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-simple.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-ng-content/ng-content-simple.stories.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core'; -import { Meta, StoryFn } from '@storybook/angular/'; +import { Meta, StoryObj } from '@storybook/angular'; @Component({ selector: 'storybook-with-ng-content', @@ -9,21 +9,29 @@ import { Meta, StoryFn } from '@storybook/angular/'; }) class WithNgContentComponent {} -export default { +const meta: Meta = { // title: 'Basics / Component / With ng-content / Simple', component: WithNgContentComponent, } as Meta; -export const OnlyComponent: StoryFn = () => ({}); +export default meta; -export const Default: StoryFn = () => ({ - template: `

This is rendered in ng-content

`, -}); +type Story = StoryObj; -export const WithDynamicContentAndArgs: StoryFn = (args) => ({ - template: `

${args['content']}

`, -}); -WithDynamicContentAndArgs.argTypes = { - content: { control: 'text' }, +export const OnlyComponent: Story = {}; + +export const Default: Story = { + render: () => ({ + template: `

This is rendered in ng-content

`, + }), +}; + +export const WithDynamicContentAndArgs: Story = { + render: (args) => ({ + template: `

${args['content']}

`, + }), + args: { content: 'Default content' }, + argTypes: { + content: { control: 'text' }, + }, }; -WithDynamicContentAndArgs.args = { content: 'Default content' }; diff --git a/code/frameworks/angular/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts index b833424367bb..9ac53d2dde03 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-ng-on-destroy/component-with-on-destroy.stories.ts @@ -27,7 +27,7 @@ class OnDestroyComponent implements OnInit, OnDestroy { } } -export default { +const meta: Meta = { // title: 'Basics / Component / with ngOnDestroy', component: OnDestroyComponent, parameters: { @@ -37,4 +37,8 @@ export default { }, } as Meta; -export const SimpleComponent: StoryObj = {}; +export default meta; + +type Story = StoryObj; + +export const SimpleComponent: Story = {}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-on-push/on-push.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-on-push/on-push.stories.ts index 6ad452797bc2..cc672938a7f2 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-on-push/on-push.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-on-push/on-push.stories.ts @@ -1,7 +1,7 @@ -import { Meta, StoryFn } from '@storybook/angular'; +import { Meta, StoryObj } from '@storybook/angular'; import { OnPushBoxComponent } from './on-push-box.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With OnPush strategy', component: OnPushBoxComponent, argTypes: { @@ -12,10 +12,12 @@ export default { word: 'The text', bgColor: '#FFF000', }, -} as Meta; +}; -export const ClassSpecifiedComponentWithOnPushAndArgs: StoryFn = (args) => ({ - props: args, -}); -ClassSpecifiedComponentWithOnPushAndArgs.storyName = - 'Class-specified component with OnPush and Args'; +export default meta; + +type Story = StoryObj; + +export const ClassSpecifiedComponentWithOnPushAndArgs: Story = { + name: 'Class-specified component with OnPush and Args', +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-pipe/custom-pipes.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-pipe/custom-pipes.stories.ts index 6c8f9254208f..9a4a8e53c577 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-pipe/custom-pipes.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-pipe/custom-pipes.stories.ts @@ -1,9 +1,9 @@ -import { Meta, StoryFn, moduleMetadata } from '@storybook/angular'; +import { Meta, StoryObj, moduleMetadata } from '@storybook/angular'; import { CustomPipePipe } from './custom.pipe'; import { WithPipeComponent } from './with-pipe.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Pipes', component: WithPipeComponent, decorators: [ @@ -11,21 +11,26 @@ export default { declarations: [CustomPipePipe], }), ], -} as Meta; +}; -export const Simple: StoryFn = () => ({ - props: { - field: 'foobar', - }, -}); +export default meta; + +type Story = StoryObj; -export const WithArgsStory: StoryFn = (args) => ({ - props: args, -}); -WithArgsStory.storyName = 'With args'; -WithArgsStory.argTypes = { - field: { control: 'text' }, +export const Simple: Story = { + render: () => ({ + props: { + field: 'foobar', + }, + }), }; -WithArgsStory.args = { - field: 'Foo Bar', + +export const WithArgsStory: Story = { + name: 'With args', + argTypes: { + field: { control: 'text' }, + }, + args: { + field: 'Foo Bar', + }, }; diff --git a/code/frameworks/angular/template/stories/basics/component-with-provider/di.component.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-provider/di.component.stories.ts index fea1bc95c15f..381c272fb96d 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-provider/di.component.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-provider/di.component.stories.ts @@ -1,26 +1,30 @@ -import { Args } from '@storybook/angular'; +import { Args, Meta, StoryObj } from '@storybook/angular'; import { DiComponent } from './di.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With Provider', component: DiComponent, }; -export const InputsAndInjectDependencies = () => ({ - props: { - title: 'Component dependencies', - }, -}); +export default meta; -InputsAndInjectDependencies.storyName = 'inputs and inject dependencies'; +type Story = StoryObj; -export const InputsAndInjectDependenciesWithArgs = (args: Args) => ({ - props: args, -}); -InputsAndInjectDependenciesWithArgs.storyName = 'inputs and inject dependencies with args'; -InputsAndInjectDependenciesWithArgs.argTypes = { - title: { control: 'text' }, +export const InputsAndInjectDependencies: Story = { + render: () => ({ + props: { + title: 'Component dependencies', + }, + }), + name: 'inputs and inject dependencies', }; -InputsAndInjectDependenciesWithArgs.args = { - title: 'Component dependencies', + +export const InputsAndInjectDependenciesWithArgs: Story = { + name: 'inputs and inject dependencies with args', + argTypes: { + title: { control: 'text' }, + }, + args: { + title: 'Component dependencies', + }, }; diff --git a/code/frameworks/angular/template/stories/basics/component-with-style/styled.component.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-style/styled.component.stories.ts index 0818ff28cc6f..c0cd88c09bc2 100644 --- a/code/frameworks/angular/template/stories/basics/component-with-style/styled.component.stories.ts +++ b/code/frameworks/angular/template/stories/basics/component-with-style/styled.component.stories.ts @@ -1,10 +1,15 @@ +import { Meta, StoryObj } from '@storybook/angular'; import { StyledComponent } from './styled.component'; -export default { +const meta: Meta = { // title: 'Basics / Component / With StyleUrls', component: StyledComponent, }; -export const ComponentWithStyles = () => ({}); +export default meta; -ComponentWithStyles.storyName = 'Component with styles'; +type Story = StoryObj; + +export const ComponentWithStyles: Story = { + name: 'Component with styles', +}; diff --git a/code/frameworks/angular/template/stories/basics/component-with-template/template.component.ts b/code/frameworks/angular/template/stories/basics/component-with-template/template.component.ts new file mode 100644 index 000000000000..2071a6db7738 --- /dev/null +++ b/code/frameworks/angular/template/stories/basics/component-with-template/template.component.ts @@ -0,0 +1,27 @@ +import { CommonModule } from '@angular/common'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; + +@Component({ + selector: 'app-template', + imports: [CommonModule], + template: `
+ Label: {{ label }} +
+ Label2: {{ label2 }} +
+ +
`, + styles: [], + standalone: true, +}) +export class Template { + @Input() label = 'default label'; + + @Input() label2 = 'default label2'; + + @Output() changed = new EventEmitter(); + + inc() { + this.changed.emit('Increase'); + } +} diff --git a/code/frameworks/angular/template/stories/basics/component-with-template/template.stories.ts b/code/frameworks/angular/template/stories/basics/component-with-template/template.stories.ts new file mode 100644 index 000000000000..55639870f262 --- /dev/null +++ b/code/frameworks/angular/template/stories/basics/component-with-template/template.stories.ts @@ -0,0 +1,24 @@ +import { Meta, StoryObj, argsToTemplate } from '@storybook/angular'; +import { Template } from './template.component'; + +const meta: Meta