AAE-24927 add ability to style form widget - header (#10173)

* AAE-25211 form styling PoC

* AAE-25211 poc

* AAE-25211 revert cloud form service

* AAE-24927 display text schema

* AAE-24927 radio button styles

* AAE-24927 header styles

* AAE-24927 style pipes

* AAE-24927 styles for header

* AAE-24927 remove redundand prop
This commit is contained in:
Kasia Biernat-Kluba 2024-09-05 11:59:57 +02:00 committed by GitHub
parent 5d5c1ac527
commit 166325d703
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 264 additions and 42 deletions

View File

@ -21,25 +21,7 @@
[id]="'field-' + currentRootElement?.id + '-container'"
class="adf-container-widget"
[hidden]="!currentRootElement?.isVisible">
<div [hidden]="!currentRootElement?.isGroup()" [style]="currentRootElement | adfFieldStyle" class="adf-container-widget__header">
<h4 class="adf-container-widget__header-text" id="container-header"
[class.adf-collapsible]="currentRootElement?.isCollapsible()">
<button *ngIf="currentRootElement?.isCollapsible()"
mat-icon-button
class="mdl-button--icon"
(click)="onExpanderClicked(currentRootElement)">
<mat-icon>{{ currentRootElement?.isExpanded ? 'expand_more' : 'expand_less' }}</mat-icon>
</button>
<span (click)="onExpanderClicked(currentRootElement)"
role="button"
tabindex="0"
(keyup.enter)="onExpanderClicked(currentRootElement)"
[id]="'container-header-label-' + currentRootElement?.id">
{{ currentRootElement.name | translate }}
</span>
</h4>
</div>
<adf-header-widget [element]="currentRootElement"></adf-header-widget>
<div *ngIf="currentRootElement?.form?.enableFixedSpace; else fixingTemplate">
<div class="adf-grid-list"
[ngStyle]="{ 'grid-template-columns': 'repeat(' + getNumberOfColumns(currentRootElement) + ', 1fr)' }"

View File

@ -6,20 +6,6 @@
display: none;
}
.adf-container-widget__header-text {
border-bottom: 1px solid rgba(0, 0, 0, 0.87);
padding-bottom: 10px;
cursor: default;
user-select: none;
font-size: var(--adf-header-font-size);
font-weight: var(--adf-header-font-weight);
color: var(--adf-header-color);
&.adf-collapsible {
cursor: pointer;
}
}
.adf-field-list {
padding: 0;
list-style-type: none;

View File

@ -29,6 +29,7 @@ import { FormFieldComponent } from './form-field/form-field.component';
import { FORM_FIELD_MODEL_RENDER_MIDDLEWARE, FormFieldModelRenderMiddleware } from './middlewares/middleware';
import { ContainerModel, FormFieldModel, FormModel, TabModel } from './widgets';
import { FieldStylePipe } from '../pipes/field-style.pipe';
import { HeaderWidgetComponent } from './widgets/header/header.widget';
@Component({
selector: 'adf-form-renderer',
@ -57,7 +58,8 @@ import { FieldStylePipe } from '../pipes/field-style.pipe';
JsonPipe,
UpperCasePipe,
FieldStylePipe,
NgClass
NgClass,
HeaderWidgetComponent
],
encapsulation: ViewEncapsulation.None
})
@ -103,12 +105,6 @@ export class FormRendererComponent<T> implements OnInit, OnDestroy {
return this.formDefinition.tabs.filter((tab) => tab.isVisible);
}
onExpanderClicked(content: ContainerModel) {
if (content?.isCollapsible()) {
content.isExpanded = !content.isExpanded;
}
}
getNumberOfColumns(content: ContainerModel): number {
return (content.json?.numberOfColumns || 1) > (content.columns?.length || 1)
? content.json?.numberOfColumns || 1

View File

@ -15,7 +15,13 @@
* limitations under the License.
*/
export type FormThemeVariable = '--adf-form-label-font-size' | '--adf-form-label-font-weight' | '--adf-form-label-color';
export type FormThemeVariable =
| '--adf-form-label-font-size'
| '--adf-form-label-font-weight'
| '--adf-form-label-color'
| '--adf-header-font-size'
| '--adf-header-font-weight'
| '--adf-header-color';
export type ReadonlyTextThemeVariable = '--adf-readonly-text-font-size' | '--adf-readonly-text-font-weight' | '--adf-readonly-text-color';
export type HeaderThemeVariable = '--adf-header-font-size' | '--adf-header-font-weight' | '--adf-header-color';

View File

@ -0,0 +1,89 @@
/*!
* @license
* Copyright © 2005-2024 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 { HeaderThemeVariable } from '../core/theme.model';
import { WidgetSchemaModel } from '../core/widget-schema.model';
export const headerSchema: WidgetSchemaModel<HeaderThemeVariable> = {
themeProperties: [
{
name: 'FORM.FIELD_STYLE.FONT_SIZE',
cssPropertyName: 'font-size',
fieldVariableName: '--adf-header-font-size',
formVariableName: '--adf-header-font-size',
type: 'number',
unit: 'px',
defaultValue: '16px'
},
{
name: 'FORM.FIELD_STYLE.FONT_WEIGHT',
cssPropertyName: 'font-weight',
fieldVariableName: '--adf-header-font-weight',
formVariableName: '--adf-header-font-weight',
type: 'options',
options: [
{
name: 'FORM.FIELD_STYLE.REGULAR',
value: 'normal'
},
{
name: 'FORM.FIELD_STYLE.BOLD',
value: 'bold'
}
],
defaultValue: 'normal'
},
{
name: 'FORM.FIELD_STYLE.FONT_COLOR',
cssPropertyName: 'color',
fieldVariableName: '--adf-header-color',
formVariableName: '--adf-header-color',
type: 'colorOptions',
options: [
{
name: 'FORM.FIELD_STYLE.SYSTEM_COLOR',
value: 'inherit'
},
{
name: 'FORM.FIELD_STYLE.BLACK',
value: '#000000'
},
{
name: 'FORM.FIELD_STYLE.GREY',
value: '#9CA3AF'
},
{
name: 'FORM.FIELD_STYLE.RED',
value: '#DA1500'
},
{
name: 'FORM.FIELD_STYLE.GREEN',
value: '#04A003'
},
{
name: 'FORM.FIELD_STYLE.BLUE',
value: '#0A60CE'
},
{
name: 'FORM.FIELD_STYLE.YELLOW',
value: '#FACC15'
}
],
defaultValue: 'inherit'
}
]
};

View File

@ -0,0 +1,18 @@
<div [hidden]="!element?.isGroup()" [style]="element | adfFieldStyle" class="adf-container-widget-header">
<h4 class="adf-container-widget-header__text" id="container-header"
[class.adf-collapsible]="element?.isCollapsible()">
<button *ngIf="element?.isCollapsible()"
mat-icon-button
class="mdl-button--icon"
(click)="onExpanderClicked(element)">
<mat-icon>{{ element?.isExpanded ? 'expand_more' : 'expand_less' }}</mat-icon>
</button>
<span (click)="onExpanderClicked(element)"
role="button"
tabindex="0"
(keyup.enter)="onExpanderClicked(element)"
[id]="'container-header-label-' + element?.id">
{{ element.name | translate }}
</span>
</h4>
</div>

View File

@ -0,0 +1,13 @@
.adf-container-widget-header__text {
border-bottom: 1px solid rgba(0, 0, 0, 0.87);
padding-bottom: 10px;
cursor: default;
user-select: none;
font-size: var(--adf-header-font-size);
font-weight: var(--adf-header-font-weight);
color: var(--adf-header-color);
&.adf-collapsible {
cursor: pointer;
}
}

View File

@ -0,0 +1,69 @@
/*!
* @license
* Copyright © 2005-2024 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 { ComponentFixture, TestBed } from '@angular/core/testing';
import { TranslateModule } from '@ngx-translate/core';
import { ContainerModel } from '../core/container.model';
import { FormFieldTypes } from '../core/form-field-types';
import { FormFieldModel } from '../core/form-field.model';
import { HeaderWidgetComponent } from './header.widget';
describe('HeaderWidgetComponent', () => {
let component: HeaderWidgetComponent;
let fixture: ComponentFixture<HeaderWidgetComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HeaderWidgetComponent, TranslateModule.forRoot()]
}).compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(HeaderWidgetComponent);
component = fixture.componentInstance;
fixture.componentRef.setInput(
'element',
new ContainerModel(
new FormFieldModel(
{
onFormFieldChanged: () => {}
},
{
type: FormFieldTypes.GROUP,
name: 'test-name',
id: 'test-id',
params: { allowCollapse: true }
}
)
)
);
fixture.detectChanges();
});
it('should render the header widget template', () => {
const nativeElement = fixture.nativeElement;
expect(nativeElement.querySelector('.adf-container-widget-header')).toBeTruthy();
expect(nativeElement.querySelector('#container-header-label-test-id').textContent.trim()).toEqual('test-name');
});
it('should call onExpanderClicked method when expander is clicked', () => {
spyOn(component, 'onExpanderClicked');
const expander = fixture.nativeElement.querySelector('#container-header-label-test-id');
expander.click();
expect(component.onExpanderClicked).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,42 @@
/*!
* @license
* Copyright © 2005-2024 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 { Component, Input, ViewEncapsulation } from '@angular/core';
import { ContainerModel } from '../core/container.model';
import { FieldStylePipe } from './../../../pipes/field-style.pipe';
import { MatIconModule } from '@angular/material/icon';
import { NgIf } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
@Component({
selector: 'adf-header-widget',
templateUrl: './header.widget.html',
styleUrls: ['./header.widget.scss'],
standalone: true,
encapsulation: ViewEncapsulation.None,
imports: [FieldStylePipe, MatIconModule, MatButtonModule, TranslateModule, NgIf]
})
export class HeaderWidgetComponent {
@Input() element: ContainerModel;
onExpanderClicked(content: ContainerModel) {
if (content?.isCollapsible()) {
content.isExpanded = !content.isExpanded;
}
}
}

View File

@ -0,0 +1,19 @@
/*!
* @license
* Copyright © 2005-2024 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.
*/
export * from './header.schema';
export * from './header.widget';

View File

@ -54,6 +54,7 @@ export * from './text/text-mask.component';
// widgets with schema
export * from './display-text';
export * from './header';
export const WIDGET_DIRECTIVES: any[] = [
UnknownWidgetComponent,

View File

@ -17,13 +17,14 @@
import { Pipe, PipeTransform } from '@angular/core';
import { FormFieldModel } from '../components/widgets/core/form-field.model';
import { ContainerModel } from '../components/widgets/core/container.model';
@Pipe({
name: 'adfFieldStyle',
standalone: true
})
export class FieldStylePipe implements PipeTransform {
transform(field: FormFieldModel): string {
transform(field: FormFieldModel | ContainerModel): string {
const theme = field.form?.theme?.widgets[field.type];
const style = field.style && theme?.[field.style];