diff --git a/lib/core/src/lib/form/components/form-renderer.component.stories.ts b/lib/core/src/lib/form/components/form-renderer.component.stories.ts new file mode 100644 index 0000000000..a12eb7807c --- /dev/null +++ b/lib/core/src/lib/form/components/form-renderer.component.stories.ts @@ -0,0 +1,83 @@ +/*! + * @license + * Copyright © 2005-2026 Hyland Software, Inc. and its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { applicationConfig, Meta, StoryObj, moduleMetadata } from '@storybook/angular'; +import { FormRendererComponent } from './form-renderer.component'; +import { FormModel } from './widgets'; +import { provideStoryCore } from '../stories/core-story.providers'; +import { formSideNavLayoutMock, formTabsLayoutMock } from './mock/form.mock'; + +type FormRendererStoryArgs = { + readOnly: boolean; +}; + +const meta: Meta = { + component: FormRendererComponent, + title: 'Core/Form/Form Renderer', + decorators: [ + moduleMetadata({ + imports: [FormRendererComponent] + }), + applicationConfig({ + providers: [...provideStoryCore()] + }) + ], + parameters: { + docs: { + description: { + component: `Renders an ADF form definition. Supports a flat \`tabs\` layout and a hierarchical \`sidenav\` layout where categories can optionally render their children as an inline tab group.` + } + } + }, + argTypes: { + readOnly: { + control: 'boolean', + description: 'Toggles the read-only mode of the form', + defaultValue: false, + table: { + type: { summary: 'boolean' }, + defaultValue: { summary: 'false' } + } + } + }, + args: { + readOnly: false + } +}; + +export default meta; +type Story = StoryObj; + +export const TabsLayout: Story = { + render: (args) => ({ + props: { + formDefinition: new FormModel(formTabsLayoutMock), + readOnly: args.readOnly + }, + template: `` + }) +}; + +export const SidenavLayout: Story = { + render: (args) => ({ + props: { + formDefinition: new FormModel(formSideNavLayoutMock), + readOnly: args.readOnly + }, + template: `` + }) +}; diff --git a/lib/core/src/lib/form/components/mock/form.mock.ts b/lib/core/src/lib/form/components/mock/form.mock.ts index f04b032f3f..d5d9572b9c 100644 --- a/lib/core/src/lib/form/components/mock/form.mock.ts +++ b/lib/core/src/lib/form/components/mock/form.mock.ts @@ -645,3 +645,263 @@ export const fakeValidatorMock = { isSupported: () => true, validate: () => true }; + +export const formTabsLayoutMock = { + id: 'form-tabs-layout-story', + name: 'Employee Details', + layout: 'tabs', + tabs: [ + { id: 'tab-personal', title: 'Personal' }, + { id: 'tab-contact', title: 'Contact' }, + { id: 'tab-employment', title: 'Employment' } + ], + fields: [ + { + id: 'container-personal', + type: 'container', + tab: 'tab-personal', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'firstName', + name: 'First Name', + type: 'text', + required: true, + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'lastName', + name: 'Last Name', + type: 'text', + required: true, + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + }, + { + id: 'container-contact', + type: 'container', + tab: 'tab-contact', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'email', + name: 'Email', + type: 'text', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'phone', + name: 'Phone', + type: 'text', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + }, + { + id: 'container-employment', + type: 'container', + tab: 'tab-employment', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'department', + name: 'Department', + type: 'dropdown', + optionType: 'manual', + options: [ + { id: 'empty', name: 'Choose one...' }, + { id: 'hr', name: 'HR' }, + { id: 'eng', name: 'Engineering' } + ], + value: 'empty', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'startDate', + name: 'Start Date', + type: 'date', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + } + ], + outcomes: [] +}; + +export const formSideNavLayoutMock = { + id: 'form-sidenav-layout-story', + name: 'Project Form', + layout: 'sidenav', + tabs: [ + { id: 'overview', title: 'Overview' }, + { + id: 'team', + title: 'Team', + children: [ + { id: 'team-lead', title: 'Team Lead' }, + { id: 'team-members', title: 'Members' } + ] + }, + { + id: 'milestones', + title: 'Milestones', + childrenLayout: 'tabs', + children: [ + { id: 'milestone-q1', title: 'Q1' }, + { id: 'milestone-q2', title: 'Q2' } + ] + } + ], + fields: [ + { + id: 'container-overview', + type: 'container', + tab: 'overview', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'projectName', + name: 'Project Name', + type: 'text', + required: true, + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'projectStatus', + name: 'Status', + type: 'dropdown', + optionType: 'manual', + options: [ + { id: 'empty', name: 'Choose one...' }, + { id: 'active', name: 'Active' }, + { id: 'on-hold', name: 'On Hold' } + ], + value: 'empty', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + }, + { + id: 'container-team-lead', + type: 'container', + tab: 'team-lead', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'leadName', + name: 'Lead Name', + type: 'text', + required: true, + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'leadEmail', + name: 'Lead Email', + type: 'text', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + }, + { + id: 'container-team-members', + type: 'container', + tab: 'team-members', + numberOfColumns: 1, + fields: { + '1': [ + { + id: 'membersCount', + name: 'Number of Members', + type: 'integer', + colspan: 1, + params: { existingColspan: 1, maxColspan: 1 } + } + ] + } + }, + { + id: 'container-milestone-q1', + type: 'container', + tab: 'milestone-q1', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'q1Goal', + name: 'Q1 Goal', + type: 'text', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'q1Deadline', + name: 'Q1 Deadline', + type: 'date', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + }, + { + id: 'container-milestone-q2', + type: 'container', + tab: 'milestone-q2', + numberOfColumns: 2, + fields: { + '1': [ + { + id: 'q2Goal', + name: 'Q2 Goal', + type: 'text', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ], + '2': [ + { + id: 'q2Deadline', + name: 'Q2 Deadline', + type: 'date', + colspan: 1, + params: { existingColspan: 1, maxColspan: 2 } + } + ] + } + } + ], + outcomes: [] +};