add input with action
This commit is contained in:
parent
b051f65c18
commit
eef1e59fdd
9
src/assets/icons/search.svg
Normal file
9
src/assets/icons/search.svg
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg height="100px" version="1.1" viewBox="0 0 100 100" width="100px"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" fill-rule="evenodd" id="search" stroke="none" stroke-width="1">
|
||||
<path
|
||||
d="M95.5,74.5 L76.5,55.5 C78.5,50.5 79.5,45.5 79.5,40 C79.5,18 61.5,0 39.5,0 C18,0 0,18 0,40 C0,62 18,80 40,80 C45.5,80 51,79 55.5,77 L74.5,96 C77.5,99 81.5,100.5 85,100.5 C89,100.5 92.5,99 95.5,96 C101.5,90 101.5,80 95.5,74.5 Z M10,40 C10,23.5 23.5,10 40,10 C56.5,10 70,23.5 70,40 C70,56.5 56.5,70 40,70 C23.5,70 10,56.5 10,40 Z M88.5,88.5 C86.5,90.5 83.5,90.5 81.5,88.5 L64.5,71.5 C67,69.5 69.5,67 71.5,64.5 L88.5,81.5 C90.5,83.5 90.5,86.5 88.5,88.5 Z"
|
||||
fill="currentColor" fill-rule="nonzero" id="Shape"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 801 B |
267
src/assets/styles/_inputs.scss
Normal file
267
src/assets/styles/_inputs.scss
Normal file
@ -0,0 +1,267 @@
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
form .iqser-input-group:not(first-of-type) {
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.iqser-input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
height: fit-content;
|
||||
|
||||
.hint {
|
||||
margin-top: 5px;
|
||||
font-size: 11px;
|
||||
line-height: 14px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
background: $quick-filter-border;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
border-left: 1px solid $quick-filter-border;
|
||||
border-top-right-radius: 7px;
|
||||
border-bottom-right-radius: 7px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.25s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&:hover {
|
||||
background: $btn-bg;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
color: $accent;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-form-field-underline {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mat-form-field-wrapper,
|
||||
.mat-form-field-infix {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.mat-form-field-label {
|
||||
opacity: 0.7 !important;
|
||||
color: $accent !important;
|
||||
transform: translateY(-1.34em) !important;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.icon-right {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.slider-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mat-button-toggle-checked {
|
||||
background: $primary;
|
||||
transition: background-color 0.25s ease;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea,
|
||||
mat-select {
|
||||
box-sizing: border-box;
|
||||
padding-left: 11px;
|
||||
padding-right: 11px;
|
||||
border: 1px solid $quick-filter-border;
|
||||
font-family: Inter, sans-serif;
|
||||
font-size: 13px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
outline: none;
|
||||
margin-top: 3px;
|
||||
min-height: 36px;
|
||||
|
||||
&.with-icon {
|
||||
padding-right: 34px;
|
||||
}
|
||||
|
||||
&:focus:not(:disabled):not(.mat-select-disabled) {
|
||||
border-color: $accent;
|
||||
}
|
||||
|
||||
&::placeholder {
|
||||
color: $accent;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
&.ng-invalid.ng-touched {
|
||||
border-color: rgba($primary, 0.3);
|
||||
|
||||
&:focus {
|
||||
border-color: $primary;
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled,
|
||||
&.mat-select-disabled {
|
||||
background-color: $filter-bg;
|
||||
color: rgba($accent, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.hex-color-input {
|
||||
width: 150px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
mat-select {
|
||||
.mat-select-trigger {
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.mat-select-value {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
@include scroll-bar;
|
||||
|
||||
&.has-scrollbar {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
label:not(.mat-slide-toggle-label) {
|
||||
opacity: 0.7;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0;
|
||||
line-height: 14px;
|
||||
margin-bottom: 2px;
|
||||
color: $accent;
|
||||
|
||||
&.mat-checkbox-layout {
|
||||
opacity: 1;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.required label:after {
|
||||
content: ' *';
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
&.datepicker-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-top: 0;
|
||||
width: 120px;
|
||||
|
||||
.mat-datepicker-input {
|
||||
margin-top: 0;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.mat-datepicker-toggle {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: $accent;
|
||||
|
||||
&.mat-datepicker-toggle-active {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.mat-icon-button {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
width: 14px;
|
||||
height: 17px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.w-75 {
|
||||
width: 75px;
|
||||
max-width: 75px;
|
||||
}
|
||||
|
||||
&.w-110 {
|
||||
width: 110px;
|
||||
max-width: 110px;
|
||||
}
|
||||
|
||||
&.w-150 {
|
||||
max-width: 150px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
&.w-160 {
|
||||
width: 160px;
|
||||
max-width: 160px;
|
||||
}
|
||||
|
||||
&.w-200 {
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
&.w-250 {
|
||||
width: 250px;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
&.w-300 {
|
||||
width: 300px;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
&.w-400 {
|
||||
width: 400px;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
&.w-450 {
|
||||
width: 450px;
|
||||
max-width: 450px;
|
||||
}
|
||||
|
||||
&.w-full {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
3
src/assets/styles/_layout.scss
Normal file
3
src/assets/styles/_layout.scss
Normal file
@ -0,0 +1,3 @@
|
||||
.mt-0 {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
29
src/assets/styles/_mixins.scss
Normal file
29
src/assets/styles/_mixins.scss
Normal file
@ -0,0 +1,29 @@
|
||||
@import 'variables';
|
||||
|
||||
@mixin no-scroll-bar {
|
||||
scrollbar-width: none; /* Firefox */
|
||||
-ms-overflow-style: none; /* IE 10+ */
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
background: transparent; /* Chrome/Safari/Webkit */
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scroll-bar {
|
||||
scrollbar-color: $quick-filter-border $filter-bg;
|
||||
scrollbar-width: thin;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 11px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
&::-webkit-scrollbar-track {
|
||||
background: $filter-bg;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: $quick-filter-border;
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,5 @@
|
||||
@import 'inputs';
|
||||
@import 'buttons';
|
||||
@import 'texts';
|
||||
@import 'tables';
|
||||
@import 'layout';
|
||||
|
||||
@ -33,4 +33,6 @@ export * from './lib/tables/table-column-name/table-column-name.component';
|
||||
export * from './lib/tables/table-header/table-header.component';
|
||||
export * from './lib/misc/status-bar/status-bar.component';
|
||||
export * from './lib/misc/status-bar/status-bar-config.model';
|
||||
export * from './lib/inputs/round-checkbox/round-checkbox.component';
|
||||
export * from './lib/inputs/editable-input/editable-input.component';
|
||||
export * from './lib/inputs/input-with-action/input-with-action.component';
|
||||
|
||||
@ -21,10 +21,11 @@ import { SyncWidthDirective } from './tables/sync-width.directive';
|
||||
import { StatusBarComponent } from './misc/status-bar/status-bar.component';
|
||||
import { EditableInputComponent } from './inputs/editable-input/editable-input.component';
|
||||
import { PopupFilterComponent } from './filtering/popup-filter/popup-filter.component';
|
||||
import { InputWithActionComponent } from './inputs/input-with-action/input-with-action.component';
|
||||
|
||||
const buttons = [IconButtonComponent, ChevronButtonComponent, CircleButtonComponent];
|
||||
|
||||
const inputs = [RoundCheckboxComponent, EditableInputComponent];
|
||||
const inputs = [RoundCheckboxComponent, EditableInputComponent, InputWithActionComponent];
|
||||
|
||||
const matModules = [MatIconModule, MatButtonModule, MatTooltipModule, MatMenuModule, MatCheckboxModule];
|
||||
|
||||
@ -49,7 +50,7 @@ const utils = [SortByPipe, HumanizePipe, SyncWidthDirective];
|
||||
})
|
||||
export class CommonUiModule {
|
||||
constructor(private readonly _iconRegistry: MatIconRegistry, private readonly _sanitizer: DomSanitizer) {
|
||||
const icons = ['arrow-down', 'check', 'close', 'edit', 'sort-asc', 'sort-desc'];
|
||||
const icons = ['arrow-down', 'check', 'close', 'edit', 'sort-asc', 'sort-desc', 'search'];
|
||||
|
||||
icons.forEach(icon => {
|
||||
_iconRegistry.addSvgIconInNamespace('iqser', icon, _sanitizer.bypassSecurityTrustResourceUrl(`/assets/icons/${icon}.svg`));
|
||||
|
||||
@ -1,23 +1,24 @@
|
||||
<div *ngIf="showPreview && !editing">
|
||||
{{ value }}
|
||||
</div>
|
||||
|
||||
<form (submit)="saveValue()" *ngIf="editing">
|
||||
<div [class]="'red-input-group ' + class">
|
||||
<input [(ngModel)]="newValue" [placeholder]="placeholder" name="name" />
|
||||
<ng-container *ngIf="!editing">
|
||||
<div *ngIf="showPreview">
|
||||
{{ value }}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="editing = true"
|
||||
*ngIf="!editing"
|
||||
[tooltip]="editTooltip"
|
||||
[type]="buttonsType"
|
||||
class="edit-button"
|
||||
icon="red:edit"
|
||||
></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="editing = true"
|
||||
[tooltip]="editTooltip"
|
||||
[type]="buttonsType"
|
||||
class="edit-button"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="editing">
|
||||
<iqser-circle-button (action)="saveValue()" [tooltip]="saveTooltip" [type]="buttonsType" icon="red:check"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="editing = false" [tooltip]="cancelTooltip" [type]="buttonsType" icon="red:close"></iqser-circle-button>
|
||||
<form (submit)="saveValue()">
|
||||
<div [class]="'iqser-input-group ' + class">
|
||||
<input [(ngModel)]="newValue" [placeholder]="placeholder" name="name" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button (action)="saveValue()" [tooltip]="saveTooltip" [type]="buttonsType" icon="iqser:check"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="editing = false" [tooltip]="cancelTooltip" [type]="buttonsType" icon="iqser:close"></iqser-circle-button>
|
||||
</ng-container>
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
<div [style.max-width]="computedWidth" [style.width]="computedWidth" class="iqser-input-group">
|
||||
<input
|
||||
[(ngModel)]="value"
|
||||
(ngModelChange)="valueChange.emit($event)"
|
||||
[autocomplete]="autocomplete"
|
||||
[placeholder]="placeholder"
|
||||
class="with-icon mt-0"
|
||||
type="text"
|
||||
/>
|
||||
|
||||
<span *ngIf="hint" class="hint">{{ hint }}</span>
|
||||
|
||||
<mat-icon *ngIf="isSearch && !hasContent" class="icon-right" svgIcon="iqser:search"></mat-icon>
|
||||
|
||||
<iqser-circle-button (action)="reset()" *ngIf="isSearch && hasContent" [size]="25" icon="iqser:close"></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="executeAction($event)"
|
||||
*ngIf="!isSearch"
|
||||
[disabled]="!hasContent"
|
||||
[icon]="icon"
|
||||
[isSubmit]="true"
|
||||
[size]="25"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
@ -0,0 +1,14 @@
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
|
||||
mat-icon.disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
iqser-circle-button {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 5px;
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-input-with-action',
|
||||
templateUrl: './input-with-action.component.html',
|
||||
styleUrls: ['./input-with-action.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class InputWithActionComponent {
|
||||
@Input() placeholder = '';
|
||||
@Input() hint?: string;
|
||||
@Input() width: number | 'full' = 250;
|
||||
@Input() icon?: string;
|
||||
@Input() autocomplete: 'on' | 'off' = 'on';
|
||||
@Input() value = '';
|
||||
@Output() readonly action = new EventEmitter<string>();
|
||||
@Output() readonly valueChange = new EventEmitter<string>();
|
||||
|
||||
get hasContent(): boolean {
|
||||
return !!this.value.length;
|
||||
}
|
||||
|
||||
get computedWidth(): string {
|
||||
return this.width === 'full' ? '100%' : `${this.width}px`;
|
||||
}
|
||||
|
||||
reset(): void {
|
||||
this.value = '';
|
||||
this.valueChange.emit(this.value);
|
||||
}
|
||||
|
||||
get isSearch(): boolean {
|
||||
return this.action.observers.length === 0;
|
||||
}
|
||||
|
||||
executeAction($event: MouseEvent): void {
|
||||
$event.stopPropagation();
|
||||
|
||||
if (this.hasContent) {
|
||||
this.action.emit(this.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user