mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
feat: refactor return process models and update button styles for improved UI consistency
This commit is contained in:
@@ -36,7 +36,11 @@
|
||||
"output": "scandit"
|
||||
}
|
||||
],
|
||||
"styles": ["apps/isa-app/src/styles.scss"],
|
||||
"styles": [
|
||||
"@angular/cdk/overlay-prebuilt.css",
|
||||
"libs/ui/buttons/src/styles.scss",
|
||||
"apps/isa-app/src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@import "@angular/cdk/overlay-prebuilt.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@@ -3,6 +3,6 @@ export * from './product';
|
||||
export * from './quantity';
|
||||
export * from './receipt-item';
|
||||
export * from './receipt';
|
||||
export * from './return-process-answers';
|
||||
export * from './return-process-question-info';
|
||||
export * from './return-process-question';
|
||||
export * from './return-process';
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export interface ReturnProcessAnswers {
|
||||
answerId: string;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { ReturnProcessQuestion } from './return-process-question';
|
||||
|
||||
export interface ReturnProcessQuestionInfo {
|
||||
startsWithQuestion: string;
|
||||
formats: string[];
|
||||
questions: ReturnProcessQuestion[];
|
||||
}
|
||||
@@ -7,7 +7,7 @@ export type ReturnProcessQuestionType =
|
||||
(typeof ReturnProcessQuestionType)[keyof typeof ReturnProcessQuestionType];
|
||||
|
||||
export interface ReturnProcessQuestionBase {
|
||||
id: string;
|
||||
key: string;
|
||||
description: string;
|
||||
type: ReturnProcessQuestionType;
|
||||
}
|
||||
@@ -20,7 +20,7 @@ export interface ReturnProcessSelectQuestion extends ReturnProcessQuestionBase {
|
||||
export interface ReturnProcessQuestionSelectOptions {
|
||||
label: string;
|
||||
value: string;
|
||||
nextQuestionId?: string;
|
||||
nextQuestion?: string;
|
||||
}
|
||||
|
||||
export interface ReturnProcessProductQuestion extends ReturnProcessQuestionBase {
|
||||
|
||||
113
libs/oms/data-access/src/lib/return-process-questions.token.ts
Normal file
113
libs/oms/data-access/src/lib/return-process-questions.token.ts
Normal file
@@ -0,0 +1,113 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { ReturnProcessQuestionInfo, ReturnProcessQuestionType } from './models';
|
||||
|
||||
const questionInfo1: ReturnProcessQuestionInfo = {
|
||||
formats: ['tb', 'hc', 'ka', 'zs'],
|
||||
startsWithQuestion: 'item_condition',
|
||||
questions: [
|
||||
{
|
||||
key: 'item_condition',
|
||||
description: 'Wie ist der Artkelzustand?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{
|
||||
label: 'Neuwertig/Originalverpackt',
|
||||
value: 'ovp',
|
||||
nextQuestion: 'return_reason',
|
||||
},
|
||||
{ label: 'Beschädigt/Fehldruck', value: 'damaged' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'return_reason',
|
||||
description: 'Warum möchtest du den Artikel zurücksenden?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{ label: 'Gefällt nicht/Wiederruf', value: 'dislike' },
|
||||
{ label: 'Fehllieferung', value: 'wrong_item', nextQuestion: 'delivered_item' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'delivered_item',
|
||||
description: 'Welcher Artikel wurde geliefert?',
|
||||
type: ReturnProcessQuestionType.Product,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const questionInfo2: ReturnProcessQuestionInfo = {
|
||||
formats: ['au', 'vi', 'sw'],
|
||||
startsWithQuestion: 'item_condition',
|
||||
questions: [
|
||||
{
|
||||
key: 'item_condition',
|
||||
description: 'Wie ist der Artkelzustand?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{
|
||||
label: 'Versiegelt/Originalverpackt',
|
||||
value: 'ovp',
|
||||
},
|
||||
{ label: 'Geöffnet', value: 'damaged', nextQuestion: 'item_defective' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'item_defective',
|
||||
description: 'Ist der Artikel Defekt?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{
|
||||
label: 'Ja',
|
||||
value: 'yes',
|
||||
},
|
||||
{
|
||||
label: 'Nein',
|
||||
value: 'no',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const questionInfo3: ReturnProcessQuestionInfo = {
|
||||
formats: ['nb'],
|
||||
startsWithQuestion: 'item_condition',
|
||||
questions: [
|
||||
{
|
||||
key: 'item_condition',
|
||||
description: 'Wie ist der Artkelzustand?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{
|
||||
label: 'Neuwertig/Originalverpackt',
|
||||
value: 'ovp',
|
||||
nextQuestion: 'return_reason',
|
||||
},
|
||||
{ label: 'Beschädigt/Fehldruck', value: 'damaged' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'return_reason',
|
||||
description: 'Warum möchtest du den Artikel zurückgeben?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{ label: 'Gefällt nicht/Wiederruf', value: 'dislike' },
|
||||
{ label: 'Fehllieferung', value: 'wrong_item', nextQuestion: 'delivered_item' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'delivered_item',
|
||||
description: 'Welcher Artikel wurde geliefert?',
|
||||
type: ReturnProcessQuestionType.Product,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export const RETURN_PROCESS_QUESTION_INFOS = new InjectionToken<ReturnProcessQuestionInfo[]>(
|
||||
'oms.data-access.return-process-question-infos',
|
||||
{
|
||||
factory() {
|
||||
return [questionInfo1, questionInfo2, questionInfo3];
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -1,43 +1,56 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Product, ReturnProcessQuestion, ReturnProcessQuestionType } from './models';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
const bookAndCalendarQuestions: ReturnProcessQuestion[] = [
|
||||
{
|
||||
id: 'item_condition',
|
||||
description: 'Wie ist der Artkelzustand?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{ label: 'Neuwertig/Originalverpackt', value: 'ovp', nextQuestionId: 'return_reason' },
|
||||
{ label: 'Beschädigt/Fehldruck', value: 'damaged' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'return_reason',
|
||||
description: 'Warum möchtest du den Artikel zurücksenden?',
|
||||
type: ReturnProcessQuestionType.Select,
|
||||
options: [
|
||||
{ label: 'Gefällt nicht/Wiederruf', value: 'dislike' },
|
||||
{ label: 'Fehllieferung', value: 'wrong_item', nextQuestionId: 'delivered_item' },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'delivered_item',
|
||||
description: 'Welcher Artikel wurde geliefert?',
|
||||
type: ReturnProcessQuestionType.Product,
|
||||
},
|
||||
];
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
Product,
|
||||
ReturnProcessQuestion,
|
||||
ReturnProcessQuestionInfo,
|
||||
ReturnProcessQuestionType,
|
||||
} from './models';
|
||||
import { Observable } from 'rxjs';
|
||||
import { RETURN_PROCESS_QUESTION_INFOS } from './return-process-questions.token';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ReturnProcessService {
|
||||
returnProcessQuestions(
|
||||
#returnProcessQuestionInfos = inject(RETURN_PROCESS_QUESTION_INFOS);
|
||||
|
||||
returnProcessQuestions(product: Product): ReturnProcessQuestionInfo | undefined {
|
||||
return this.#returnProcessQuestionInfos.find((info) => {
|
||||
const format = product.format.toLowerCase();
|
||||
return info.formats.includes(format);
|
||||
});
|
||||
}
|
||||
|
||||
activeReturnProcessQuestions(
|
||||
product: Product,
|
||||
): Observable<{ startWithQuestionId: string; questions: ReturnProcessQuestion[] }> {
|
||||
if (product.format === 'HC' || product.format === 'TB') {
|
||||
return of({ startWithQuestionId: 'item_condition', questions: bookAndCalendarQuestions });
|
||||
answers: Record<string, unknown>,
|
||||
): ReturnProcessQuestion[] {
|
||||
const questions = this.returnProcessQuestions(product);
|
||||
if (!questions) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return of({ startWithQuestionId: '', questions: [] });
|
||||
let questionKey: string | undefined = questions.startsWithQuestion;
|
||||
const result: ReturnProcessQuestion[] = [];
|
||||
|
||||
while (questionKey) {
|
||||
const question = questions.questions.find((q) => q.key === questionKey);
|
||||
if (question) {
|
||||
result.push(question);
|
||||
|
||||
if (question.type === ReturnProcessQuestionType.Select) {
|
||||
const option = question.options.find((o) => o.value === answers[question.key]);
|
||||
questionKey = option?.nextQuestion;
|
||||
} else if (question.type === ReturnProcessQuestionType.Product) {
|
||||
questionKey = answers[question.key] ? question.nextQuestionId : undefined;
|
||||
} else {
|
||||
console.error('Unknown question type', question);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
eligibleForReturn(): Observable<boolean> {
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
<div class="flex items-start gap-6 flex-shrink-0 justify-between">
|
||||
<div class="flex gap-6 flex-shrink-0 justify-between items-center">
|
||||
<div>
|
||||
{{ question().description }}
|
||||
</div>
|
||||
<div class="flex flex-col gap-6">
|
||||
<div class="text-right">
|
||||
<ui-text-field>
|
||||
<ui-text-field size="small" class="min-w-[22.875rem]">
|
||||
<input
|
||||
class="isa-text-body-2-bold"
|
||||
placeholder="EAN eingeben / scannen"
|
||||
type="text"
|
||||
[formControl]="control"
|
||||
size="small"
|
||||
/>
|
||||
<button uiTextButton size="small" color="strong" (click)="check()">Prüfen</button>
|
||||
<button class="px-0" uiTextButton size="small" color="strong" (click)="check()">
|
||||
Prüfen
|
||||
</button>
|
||||
</ui-text-field>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { ChangeDetectionStrategy, Component, inject, input, signal } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, effect, inject, input, signal } from '@angular/core';
|
||||
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Product, ReturnProcessProductQuestion, ReturnProcessStore } from '@isa/oms/data-access';
|
||||
import { TextButtonComponent } from '@isa/ui/buttons';
|
||||
import { TextFieldComponent } from '@isa/ui/input-controls';
|
||||
import { rxMethod } from '@ngrx/signals/rxjs-interop';
|
||||
import { filter, pipe, switchMap } from 'rxjs';
|
||||
import { filter, pipe, switchMap, tap } from 'rxjs';
|
||||
import { CatalougeSearchService } from '@isa/catalogue/data-access';
|
||||
import { tapResponse } from '@ngrx/operators';
|
||||
import { ProductImageDirective } from '@isa/shared/product-image';
|
||||
@@ -17,30 +17,56 @@ import { ProductImageDirective } from '@isa/shared/product-image';
|
||||
imports: [ReactiveFormsModule, TextFieldComponent, TextButtonComponent, ProductImageDirective],
|
||||
})
|
||||
export class ReturnProcessProductQuestionComponent {
|
||||
// #returnProcessStore = inject(ReturnProcessStore);
|
||||
#returnProcessStore = inject(ReturnProcessStore);
|
||||
#catalogueSearchService = inject(CatalougeSearchService);
|
||||
|
||||
processId = input.required<number>();
|
||||
|
||||
question = input.required<ReturnProcessProductQuestion>();
|
||||
|
||||
control = new FormControl<string | undefined>('9783551557438', [Validators.required]);
|
||||
control = new FormControl<string>('', [Validators.required]);
|
||||
|
||||
product = signal<Product | undefined>(undefined);
|
||||
|
||||
checking = signal<boolean>(false);
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
const product = this.#returnProcessStore.entityMap()[this.processId()]?.answers[
|
||||
this.question().key
|
||||
] as Product;
|
||||
|
||||
if (product) {
|
||||
this.control.setValue(product.ean);
|
||||
this.product.set(product);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
check = rxMethod<void>(
|
||||
pipe(
|
||||
filter(() => this.control.valid),
|
||||
tap(() => {
|
||||
this.checking.set(true);
|
||||
}),
|
||||
switchMap(() =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
this.#catalogueSearchService.searchByEans(this.control.value!).pipe(
|
||||
tapResponse({
|
||||
next: (value) => {
|
||||
this.product.set(value[0].product);
|
||||
this.#returnProcessStore.setAnswer(
|
||||
this.processId(),
|
||||
this.question().key,
|
||||
value[0].product,
|
||||
);
|
||||
},
|
||||
error: (error) => {
|
||||
console.error(error);
|
||||
},
|
||||
complete: () => {
|
||||
this.checking.set(false);
|
||||
},
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@for (question of renderQuestions(); track question.id; let last = $last) {
|
||||
@for (question of questions(); track question.key; let last = $last) {
|
||||
<div class="item-content" [class.with-border-bottom]="!last">
|
||||
@switch (question.type) {
|
||||
@case ('select') {
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
import { JsonPipe } from '@angular/common';
|
||||
import { ChangeDetectionStrategy, Component, computed, inject, input } from '@angular/core';
|
||||
import { toObservable, toSignal } from '@angular/core/rxjs-interop';
|
||||
import {
|
||||
ReturnProcess,
|
||||
ReturnProcessQuestion,
|
||||
ReturnProcessQuestionType,
|
||||
ReturnProcessService,
|
||||
ReturnProcessStore,
|
||||
} from '@isa/oms/data-access';
|
||||
import { filter, switchMap } from 'rxjs';
|
||||
import { ReturnProcess, ReturnProcessService, ReturnProcessStore } from '@isa/oms/data-access';
|
||||
import { ReturnProcessSelectQuestionComponent } from './return-process-select-question/return-process-select-question.component';
|
||||
import { ReturnProcessProductQuestionComponent } from './return-process-product-question/return-process-product-question.component';
|
||||
|
||||
@@ -30,50 +22,14 @@ export class ReturnProcessQuestionsComponent {
|
||||
return this.#returnProcessStore.entityMap()[returnProcessId];
|
||||
});
|
||||
|
||||
questions = toSignal(
|
||||
toObservable(this.returnProcess).pipe(
|
||||
filter((returnProcess) => !!returnProcess),
|
||||
switchMap((returnProcess) =>
|
||||
this.#returnProcessSerivce.returnProcessQuestions(returnProcess.product),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
renderQuestions = computed(() => {
|
||||
const answers = this.returnProcess()?.answers;
|
||||
|
||||
if (!answers) {
|
||||
return [];
|
||||
questions = computed(() => {
|
||||
const returnProcess = this.returnProcess();
|
||||
if (!returnProcess) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const questions = this.questions();
|
||||
|
||||
if (!questions) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let questionId: string | undefined = questions?.startWithQuestionId;
|
||||
const result: ReturnProcessQuestion[] = [];
|
||||
|
||||
while (questionId) {
|
||||
const question = questions?.questions.find((q) => q.id === questionId);
|
||||
if (question) {
|
||||
result.push(question);
|
||||
|
||||
if (question.type === ReturnProcessQuestionType.Select) {
|
||||
const option = question.options.find((o) => o.value === answers[question.id]);
|
||||
questionId = option?.nextQuestionId;
|
||||
} else if (question.type === ReturnProcessQuestionType.Product) {
|
||||
questionId = answers[question.id] ? question.nextQuestionId : undefined;
|
||||
} else {
|
||||
console.error('Unknown question type', question);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return this.#returnProcessSerivce.activeReturnProcessQuestions(
|
||||
returnProcess.product,
|
||||
returnProcess.answers,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -24,15 +24,15 @@ export class ReturnProcessSelectQuestionComponent {
|
||||
constructor() {
|
||||
this.control.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
if (this.control.valid) {
|
||||
this.#returnProcessStore.setAnswer(this.processId(), this.question().id, value);
|
||||
this.#returnProcessStore.setAnswer(this.processId(), this.question().key, value);
|
||||
} else {
|
||||
this.#returnProcessStore.removeAnswer(this.processId(), this.question().id);
|
||||
this.#returnProcessStore.removeAnswer(this.processId(), this.question().key);
|
||||
}
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const value =
|
||||
this.#returnProcessStore.entityMap()[this.processId()]?.answers[this.question().id];
|
||||
this.#returnProcessStore.entityMap()[this.processId()]?.answers[this.question().key];
|
||||
if (value !== this.control.value) {
|
||||
this.control.setValue(value as string);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { isaLoading } from '@isa/icons';
|
||||
@Component({
|
||||
selector: 'ui-button, [uiButton]',
|
||||
templateUrl: './button.component.html',
|
||||
styleUrls: ['./button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
standalone: true,
|
||||
|
||||
@@ -12,7 +12,6 @@ import { isaLoading } from '@isa/icons';
|
||||
@Component({
|
||||
selector: 'ui-icon-button, [uiIconButton]',
|
||||
templateUrl: './icon-button.component.html',
|
||||
styleUrls: ['./icon-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
standalone: true,
|
||||
|
||||
@@ -11,7 +11,6 @@ import { NgIconComponent, provideIcons } from '@ng-icons/core';
|
||||
@Component({
|
||||
selector: 'ui-info-button, [uiInfoButton]',
|
||||
templateUrl: './info-button.component.html',
|
||||
styleUrls: ['./info-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
imports: [NgIconComponent],
|
||||
|
||||
@@ -10,7 +10,6 @@ import { TextButtonColor, TextButtonSize } from './types';
|
||||
@Component({
|
||||
selector: 'ui-text-button, [uiTextButton]',
|
||||
templateUrl: './text-button.component.html',
|
||||
styleUrls: ['./text-button.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
standalone: true,
|
||||
|
||||
4
libs/ui/buttons/src/styles.scss
Normal file
4
libs/ui/buttons/src/styles.scss
Normal file
@@ -0,0 +1,4 @@
|
||||
@use "lib/button";
|
||||
@use "lib/icon-button";
|
||||
@use "lib/info-button";
|
||||
@use "lib/text-button";
|
||||
@@ -1,3 +1 @@
|
||||
<div class="ui-text-field__wrapper">
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
<ng-content></ng-content>
|
||||
|
||||
@@ -2,43 +2,29 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
border-radius: 6.25rem;
|
||||
height: 3.5rem;
|
||||
@apply bg-isa-white;
|
||||
@apply border border-solid border-isa-neutral-600;
|
||||
padding: 0.5rem 1.25rem;
|
||||
|
||||
@apply focus-within:border-isa-neutral-900;
|
||||
@apply border border-solid border-isa-neutral-600 rounded-full;
|
||||
@apply bg-white text-isa-neutral-900;
|
||||
|
||||
&:has(input.ng-invalid) {
|
||||
@apply border-isa-accent-red;
|
||||
}
|
||||
input {
|
||||
flex: 1;
|
||||
appearance: none;
|
||||
|
||||
.ui-text-field__wrapper {
|
||||
display: flex;
|
||||
width: 22.875rem;
|
||||
height: 2.5rem;
|
||||
min-width: 10rem;
|
||||
padding: 0.5rem 1.25rem;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
@apply focus:outline-none;
|
||||
@apply text-isa-neutral-900 appearance-none;
|
||||
|
||||
font-size: 0.875rem;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1.25rem; /* 142.857% */
|
||||
|
||||
&::placeholder {
|
||||
@apply text-isa-neutral-400;
|
||||
}
|
||||
|
||||
&:hover::placeholder,
|
||||
&:focus::placeholder {
|
||||
@apply text-isa-neutral-900;
|
||||
}
|
||||
@apply isa-text-body-2-regular focus:outline-none;
|
||||
@apply placeholder:text-neutral-500 hover:placeholder:text-neutral-900 focus:placeholder:text-neutral-900;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-text-field__small {
|
||||
}
|
||||
|
||||
.ui-text-field__medium {
|
||||
height: 3rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.ui-text-field__large {
|
||||
height: 3.5rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
input,
|
||||
ViewEncapsulation,
|
||||
} from '@angular/core';
|
||||
|
||||
export const TextFieldSize = {
|
||||
Small: 'small',
|
||||
Medium: 'medium',
|
||||
Large: 'large',
|
||||
} as const;
|
||||
|
||||
export type TextFieldSize = (typeof TextFieldSize)[keyof typeof TextFieldSize];
|
||||
|
||||
@Component({
|
||||
selector: 'ui-text-field',
|
||||
@@ -9,7 +23,13 @@ import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/
|
||||
standalone: true,
|
||||
imports: [],
|
||||
host: {
|
||||
'[class]': '["ui-text-field"]',
|
||||
'[class]': '["ui-text-field", sizeClass()]',
|
||||
},
|
||||
})
|
||||
export class TextFieldComponent {}
|
||||
export class TextFieldComponent {
|
||||
size = input<TextFieldSize>('medium');
|
||||
|
||||
sizeClass = computed(() => {
|
||||
return `ui-text-field__${this.size()}`;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user