@rero/ng-core
Version:
RERO angular core library.
1,174 lines (1,162 loc) • 635 kB
JavaScript
import * as i0 from '@angular/core';
import { inject, Pipe, input, linkedSignal, computed, ChangeDetectionStrategy, Component, output, viewChild, effect, HostListener, Injectable, LOCALE_ID, model, Injector, runInInjectionContext, signal, DestroyRef, makeEnvironmentProviders, ElementRef, booleanAttribute, afterNextRender, Directive, ViewContainerRef, inputBinding, untracked, ChangeDetectorRef } from '@angular/core';
import { DomSanitizer, Title } from '@angular/platform-browser';
import { marked } from 'marked';
import { DateTime, Settings } from 'luxon';
import { definePreset } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura';
import { _, TranslatePipe, TranslateService, TranslateDirective } from '@ngx-translate/core';
import { Button, ButtonDirective } from 'primeng/button';
import { DynamicDialogConfig, DynamicDialogRef, DialogService } from 'primeng/dynamicdialog';
import { InputGroup } from 'primeng/inputgroup';
import { InputText } from 'primeng/inputtext';
import { AutoFocus } from 'primeng/autofocus';
import { InputGroupAddon } from 'primeng/inputgroupaddon';
import { ActivatedRoute, TitleStrategy, RouterLink, Router } from '@angular/router';
import * as i1 from '@ngx-formly/core';
import { FieldType, FormlyModule, FieldWrapper, FieldArrayType, FORMLY_CONFIG, provideFormlyCore } from '@ngx-formly/core';
import { ConfirmationService, MessageService } from 'primeng/api';
import { throwError, of, isObservable, Subscription, startWith, combineLatest, map as map$5, Subject, switchMap, shareReplay, tap, merge, forkJoin, pipe, EMPTY, catchError as catchError$1, filter, finalize as finalize$1 } from 'rxjs';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { catchError, map as map$4, debounceTime, finalize, first, switchMap as switchMap$1, distinctUntilChanged, tap as tap$1 } from 'rxjs/operators';
import { withFormlyPrimeNG } from '@ngx-formly/primeng';
import * as i1$2 from '@angular/common';
import { NgClass, NgTemplateOutlet, registerLocaleData, DatePipe, JsonPipe, SlicePipe, AsyncPipe, CommonModule, Location } from '@angular/common';
import * as i1$1 from '@angular/forms';
import { FormsModule, ReactiveFormsModule, FormControl, UntypedFormGroup } from '@angular/forms';
import { DatePicker } from 'primeng/datepicker';
import EasyMDE from 'easymde';
import { Textarea } from 'primeng/textarea';
import { toSignal, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
import { Checkbox } from 'primeng/checkbox';
import { MultiSelect } from 'primeng/multiselect';
import { Tooltip } from 'primeng/tooltip';
import { Clipboard } from '@angular/cdk/clipboard';
import { GeneratePassword } from 'generate-password-lite';
import { RadioButton } from 'primeng/radiobutton';
import { AutoComplete } from 'primeng/autocomplete';
import { Select } from 'primeng/select';
import { ToggleSwitch } from 'primeng/toggleswitch';
import { TreeSelect } from 'primeng/treeselect';
import { Fieldset } from 'primeng/fieldset';
import { TieredMenu } from 'primeng/tieredmenu';
import localeDe from '@angular/common/locales/de';
import localeEn from '@angular/common/locales/en-GB';
import localeFr from '@angular/common/locales/fr';
import localeIt from '@angular/common/locales/it';
import { de as de$6 } from 'primelocale/js/de.js';
import { en as en$6 } from 'primelocale/js/en.js';
import { fr as fr$6 } from 'primelocale/js/fr.js';
import { it as it$6 } from 'primelocale/js/it.js';
import { PrimeNG } from 'primeng/config';
import renderMathInElement from 'katex/contrib/auto-render';
import * as CryptoJS from 'crypto-js';
import { Listbox } from 'primeng/listbox';
import { signalStoreFeature, type, withState, withComputed, withMethods, patchState, withHooks, withProps, signalStore } from '@ngrx/signals';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { NgxSpinnerService } from 'ngx-spinner';
import { DataView } from 'primeng/dataview';
import { Message } from 'primeng/message';
import { InputNumber } from 'primeng/inputnumber';
import { Divider } from 'primeng/divider';
import { Menu } from 'primeng/menu';
import { Paginator } from 'primeng/paginator';
import { Ripple } from 'primeng/ripple';
import { Tabs, TabList, Tab } from 'primeng/tabs';
import { FormlyJsonschema } from '@ngx-formly/core/json-schema';
import { cloneDeep } from 'lodash-es';
import { SplitButton } from 'primeng/splitbutton';
import { DomHandler } from 'primeng/dom';
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Pipe for converting carriage returns to <br> html entities.
*/
class Nl2brPipe {
sanitizer = inject(DomSanitizer);
/**
* Returns transformed value containing <br> entities.
*
* @param value Value to transform.
* @return Transformed value.
*/
transform(value) {
if (!value) {
return this.sanitizer.bypassSecurityTrustHtml('');
}
return this.sanitizer.bypassSecurityTrustHtml(value.replace(/\r\n?|\n/g, '<br>\n'));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: Nl2brPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: Nl2brPipe, isStandalone: true, name: "nl2br" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: Nl2brPipe, decorators: [{
type: Pipe,
args: [{ name: 'nl2br' }]
}] });
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Get human readable file size.
*/
class FilesizePipe {
/**
* Transform size to a human readable size.
*
* @param size Size of file.
* @param precision Number of decimals.
* @return Human readable file size.
*/
transform(size, precision = 2) {
let i = -1;
const byteUnits = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
do {
size /= 1024;
i++;
} while (size > 1024);
return [Math.max(size, 0.1).toFixed(precision), byteUnits[i]].join(' ');
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FilesizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: FilesizePipe, isStandalone: true, name: "filesize" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: FilesizePipe, decorators: [{
type: Pipe,
args: [{ name: 'filesize' }]
}] });
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Pipe for truncating text.
*/
class TruncateTextPipe {
/**
* Truncate text.
*
* @param value Text to truncate.
* @param limit Limit after which the text is truncated.
* @param trail Trailing chars
* @param type Word or Char type
* @return Truncated string
*/
transform(value, limit = 40, trail = '…', type = 'word') {
let result = value || '';
if (type === 'char' && value) {
if (value.length < limit) {
return value;
}
else {
return value.substring(0, limit) + trail;
}
}
if (type === 'word' && value) {
const words = value.split(/\s+/);
if (words.length > Math.abs(limit)) {
if (limit < 0) {
limit *= -1;
result = trail + words.slice(words.length - limit).join(' ');
}
else {
result = words.slice(0, limit).join(' ') + trail;
}
}
}
return result;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TruncateTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: TruncateTextPipe, isStandalone: true, name: "truncateText" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: TruncateTextPipe, decorators: [{
type: Pipe,
args: [{ name: 'truncateText' }]
}] });
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
function extractIdOnRef(ref) {
if (!ref) {
throw new Error('extractIdOnRef: ref is null or empty');
}
const match = /.*\/([^/]+)$/.exec(ref);
if (!match) {
throw new Error(`extractIdOnRef: unable to extract id from ref "${ref}"`);
}
return match[1];
}
function cleanDictKeys(data) {
return Object.fromEntries(Object.entries(data).filter(([, value]) => {
if (value == null) {
return false;
}
if (typeof value === 'string' || Array.isArray(value)) {
return value.length > 0;
}
return true;
}));
}
function capitalize(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}
function removeChars(value, chars = ['"']) {
const re = new RegExp('[' + chars.join('') + ']', 'gi');
return value.replace(re, '');
}
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Uppercase the first letter of the string.
*/
class UpperCaseFirstPipe {
/**
* Uppercase the first letter of the given value.
*
* @param value Value to transform.
* @return Transformed value.
*/
transform(value) {
if (!value) {
return value;
}
return capitalize(value);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: UpperCaseFirstPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: UpperCaseFirstPipe, isStandalone: true, name: "ucfirst" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: UpperCaseFirstPipe, decorators: [{
type: Pipe,
args: [{ name: 'ucfirst' }]
}] });
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Pipe to transform markdown to html.
*/
class MarkdownPipe {
sanitizer = inject(DomSanitizer);
/**
* Transform markdown to HTML.
*
* @param value Markdown initial value.
* @returns HTML corresponding to markdown.
*/
transform(value) {
const markValue = marked.parse(value, { gfm: true, breaks: false, async: false });
return this.sanitizer.bypassSecurityTrustHtml(markValue);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: MarkdownPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: MarkdownPipe, isStandalone: true, name: "markdown" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: MarkdownPipe, decorators: [{
type: Pipe,
args: [{ name: 'markdown' }]
}] });
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Pipe for applying a callback function to filter array items.
*/
class CallbackArrayFilterPipe {
/**
* Filter array items with the given callback function.
*
* @param items List of items.
* @param callback Callback function to apply.
* @return List of filtered values.
*/
transform(items, callback) {
if (items?.length) {
if (!callback) {
return items;
}
else {
return items.filter((item) => callback(item));
}
}
return [];
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CallbackArrayFilterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.17", ngImport: i0, type: CallbackArrayFilterPipe, isStandalone: true, name: "callbackArrayFilter" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: CallbackArrayFilterPipe, decorators: [{
type: Pipe,
args: [{ name: 'callbackArrayFilter' }]
}] });
// @dynamic
class TimeValidator {
static FORMAT = 'hh:mm';
/**
* Allow to control if time interval limits are well formed : the end limit should be 'older' the start limit
* @param start: the field name where to find the start limit value
* @param end: the field name where to find the end limit value
*/
static greaterThanValidator(start, end) {
return (control) => {
const startTime = control.get(start);
const endTime = control.get(end);
if (control && startTime && endTime) {
let isLessThan = false;
const startDate = DateTime.fromFormat(startTime.value, TimeValidator.FORMAT);
const endDate = DateTime.fromFormat(endTime.value, TimeValidator.FORMAT);
if (startDate.toFormat(TimeValidator.FORMAT) !== '00:00' ||
endDate.toFormat(TimeValidator.FORMAT) !== '00:00') {
isLessThan = startDate >= endDate;
}
return isLessThan ? { lessThan: { value: isLessThan } } : null;
}
return null;
};
}
static RangePeriodValidator() {
return (control) => {
if (control.value) {
let isRangeLessThan = false;
const times = control.get('times');
if (control.get('is_open')?.value && times && times.value.length > 1) {
const firstStartDate = DateTime.fromFormat(times.at(0).get('start_time')?.value, TimeValidator.FORMAT);
const firstEndDate = DateTime.fromFormat(times.at(0).get('end_time')?.value, TimeValidator.FORMAT);
const lastStartDate = DateTime.fromFormat(times.at(1).get('start_time')?.value, TimeValidator.FORMAT);
const lastEndDate = DateTime.fromFormat(times.at(1).get('end_time')?.value, TimeValidator.FORMAT);
if (firstStartDate > lastStartDate) {
isRangeLessThan = firstStartDate <= lastStartDate || firstStartDate <= lastEndDate;
}
else {
isRangeLessThan = lastStartDate <= firstEndDate || lastStartDate <= firstEndDate;
}
}
return isRangeLessThan ? { rangeLessThan: { value: isRangeLessThan } } : null;
}
return null;
};
}
}
// @dynamic
class UniqueValidator {
static createValidator(recordService, recordType, fieldName, excludePid) {
return (control) => {
return recordService.valueAlreadyExists(recordType, fieldName, control.value, excludePid);
};
}
}
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
const primeNGConfig = {
theme: {
options: {
// Layer order (lowest → highest priority). PrimeNG injects this @layer
// declaration before styles.css, so "primeng" is established below
// "utilities" — allowing Tailwind utility classes (ui:, core:) to
// override PrimeNG component styles. Do not move "utilities" before
// "primeng" or Tailwind overrides will stop working.
cssLayer: {
name: 'primeng',
order: 'theme, base, primeng, utilities'
},
darkModeSelector: false,
},
preset: definePreset(Aura, {
primitive: {
borderRadius: {
none: '0',
xs: '2px',
sm: '4px',
md: '6px',
lg: '8px',
xl: '12px',
},
emerald: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b',
950: '#022c22',
},
green: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d',
950: '#052e16',
},
lime: {
50: '#f7fee7',
100: '#ecfccb',
200: '#d9f99d',
300: '#bef264',
400: '#a3e635',
500: '#84cc16',
600: '#65a30d',
700: '#4d7c0f',
800: '#3f6212',
900: '#365314',
950: '#1a2e05',
},
red: {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d',
950: '#450a0a',
},
orange: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12',
950: '#431407',
},
amber: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f',
950: '#451a03',
},
yellow: {
50: '#fefce8',
100: '#fef9c3',
200: '#fef08a',
300: '#fde047',
400: '#facc15',
500: '#eab308',
600: '#ca8a04',
700: '#a16207',
800: '#854d0e',
900: '#713f12',
950: '#422006',
},
teal: {
50: '#f0fdfa',
100: '#ccfbf1',
200: '#99f6e4',
300: '#5eead4',
400: '#2dd4bf',
500: '#14b8a6',
600: '#0d9488',
700: '#0f766e',
800: '#115e59',
900: '#134e4a',
950: '#042f2e',
},
cyan: {
50: '#ecfeff',
100: '#cffafe',
200: '#a5f3fc',
300: '#67e8f9',
400: '#22d3ee',
500: '#06b6d4',
600: '#0891b2',
700: '#0e7490',
800: '#155e75',
900: '#164e63',
950: '#083344',
},
sky: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49',
},
blue: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554',
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81',
950: '#1e1b4b',
},
violet: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95',
950: '#2e1065',
},
purple: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87',
950: '#3b0764',
},
fuchsia: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75',
950: '#4a044e',
},
pink: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843',
950: '#500724',
},
rose: {
50: '#fff1f2',
100: '#ffe4e6',
200: '#fecdd3',
300: '#fda4af',
400: '#fb7185',
500: '#f43f5e',
600: '#e11d48',
700: '#be123c',
800: '#9f1239',
900: '#881337',
950: '#4c0519',
},
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617',
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
950: '#030712',
},
zinc: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b',
},
neutral: {
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
950: '#0a0a0a',
},
stone: {
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917',
950: '#0c0a09',
},
},
semantic: {
transitionDuration: '0.2s',
focusRing: {
width: '1px',
style: 'solid',
color: '{primary.color}',
offset: '2px',
shadow: 'none',
},
disabledOpacity: '0.6',
iconSize: '1rem',
anchorGutter: '2px',
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
950: '#172554',
},
formField: {
paddingX: '0.75rem',
paddingY: '0.5rem',
sm: {
fontSize: '0.875rem',
paddingX: '0.625rem',
paddingY: '0.375rem',
},
lg: {
fontSize: '1.125rem',
paddingX: '0.875rem',
paddingY: '0.625rem',
},
borderRadius: '{border.radius.md}',
focusRing: {
width: '0',
style: 'none',
color: 'transparent',
offset: '0',
shadow: 'none',
},
transitionDuration: '{transition.duration}',
},
list: {
padding: '0.25rem 0.25rem',
gap: '2px',
header: {
padding: '0.5rem 1rem 0.25rem 1rem',
},
option: {
padding: '0.5rem 0.75rem',
borderRadius: '{border.radius.sm}',
},
optionGroup: {
padding: '0.5rem 0.75rem',
fontWeight: '600',
},
},
content: {
borderRadius: '{border.radius.md}',
},
mask: {
transitionDuration: '0.15s',
},
navigation: {
list: {
padding: '0.25rem 0.25rem',
gap: '2px',
},
item: {
padding: '0.5rem 0.75rem',
borderRadius: '{border.radius.sm}',
gap: '0.5rem',
},
submenuLabel: {
padding: '0.5rem 0.75rem',
fontWeight: '600',
},
submenuIcon: {
size: '0.875rem',
},
},
overlay: {
select: {
borderRadius: '{border.radius.md}',
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
},
popover: {
borderRadius: '{border.radius.md}',
padding: '0.75rem',
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
},
modal: {
borderRadius: '{border.radius.xl}',
padding: '1.25rem',
shadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
},
navigation: {
shadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
},
},
colorScheme: {
light: {
surface: {
0: '#ffffff',
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a',
950: '#020617',
},
primary: {
color: '{primary.500}',
contrastColor: '#ffffff',
hoverColor: '{primary.600}',
activeColor: '{primary.700}',
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.100}',
color: '{primary.700}',
focusColor: '{primary.800}',
},
mask: {
background: 'rgba(0,0,0,0.4)',
color: '{surface.200}',
},
formField: {
background: '{surface.0}',
disabledBackground: '{surface.200}',
filledBackground: '{surface.50}',
filledHoverBackground: '{surface.50}',
filledFocusBackground: '{surface.50}',
borderColor: '{surface.300}',
hoverBorderColor: '{surface.400}',
focusBorderColor: '{primary.color}',
invalidBorderColor: '{red.400}',
color: '{surface.700}',
disabledColor: '{surface.500}',
placeholderColor: '{surface.500}',
invalidPlaceholderColor: '{red.600}',
floatLabelColor: '{surface.500}',
floatLabelFocusColor: '{primary.600}',
floatLabelActiveColor: '{surface.500}',
floatLabelInvalidColor: '{form.field.invalid.placeholder.color}',
iconColor: '{surface.400}',
shadow: '0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)',
},
text: {
color: '{surface.800}',
hoverColor: '{surface.900}',
mutedColor: '{surface.500}',
hoverMutedColor: '{surface.600}',
},
content: {
background: '{surface.0}',
hoverBackground: '{surface.100}',
borderColor: '{surface.200}',
color: '{text.color}',
hoverColor: '{text.hover.color}',
},
overlay: {
select: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}',
},
popover: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}',
},
modal: {
background: '{surface.0}',
borderColor: '{surface.200}',
color: '{text.color}',
},
},
list: {
option: {
focusBackground: '{surface.100}',
selectedBackground: '{highlight.background}',
selectedFocusBackground: '{highlight.focus.background}',
color: '{text.color}',
focusColor: '{text.hover.color}',
selectedColor: '{highlight.color}',
selectedFocusColor: '{highlight.focus.color}',
icon: {
color: '{surface.400}',
focusColor: '{surface.500}',
},
},
optionGroup: {
background: 'transparent',
color: '{text.muted.color}',
},
},
navigation: {
item: {
focusBackground: '{surface.100}',
activeBackground: '{surface.100}',
color: '{text.color}',
focusColor: '{text.hover.color}',
activeColor: '{text.hover.color}',
icon: {
color: '{surface.400}',
focusColor: '{surface.500}',
activeColor: '{surface.500}',
},
},
submenuLabel: {
background: 'transparent',
color: '{text.muted.color}',
},
submenuIcon: {
color: '{surface.400}',
focusColor: '{surface.500}',
activeColor: '{surface.500}',
},
},
},
dark: {
surface: {
0: '#ffffff',
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b',
950: '#09090b',
},
primary: {
color: '{primary.400}',
contrastColor: '{surface.900}',
hoverColor: '{primary.300}',
activeColor: '{primary.200}',
},
highlight: {
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)',
},
mask: {
background: 'rgba(0,0,0,0.6)',
color: '{surface.200}',
},
formField: {
background: '{surface.950}',
disabledBackground: '{surface.700}',
filledBackground: '{surface.800}',
filledHoverBackground: '{surface.800}',
filledFocusBackground: '{surface.800}',
borderColor: '{surface.600}',
hoverBorderColor: '{surface.500}',
focusBorderColor: '{primary.color}',
invalidBorderColor: '{red.300}',
color: '{surface.0}',
disabledColor: '{surface.400}',
placeholderColor: '{surface.400}',
invalidPlaceholderColor: '{red.400}',
floatLabelColor: '{surface.400}',
floatLabelFocusColor: '{primary.color}',
floatLabelActiveColor: '{surface.400}',
floatLabelInvalidColor: '{form.field.invalid.placeholder.color}',
iconColor: '{surface.400}',
shadow: '0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)',
},
text: {
color: '{surface.0}',
hoverColor: '{surface.0}',
mutedColor: '{surface.400}',
hoverMutedColor: '{surface.300}',
},
content: {
background: '{surface.900}',
hoverBackground: '{surface.800}',
borderColor: '{surface.700}',
color: '{text.color}',
hoverColor: '{text.hover.color}',
},
overlay: {
select: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}',
},
popover: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}',
},
modal: {
background: '{surface.900}',
borderColor: '{surface.700}',
color: '{text.color}',
},
},
list: {
option: {
focusBackground: '{surface.800}',
selectedBackground: '{highlight.background}',
selectedFocusBackground: '{highlight.focus.background}',
color: '{text.color}',
focusColor: '{text.hover.color}',
selectedColor: '{highlight.color}',
selectedFocusColor: '{highlight.focus.color}',
icon: {
color: '{surface.500}',
focusColor: '{surface.400}',
},
},
optionGroup: {
background: 'transparent',
color: '{text.muted.color}',
},
},
navigation: {
item: {
focusBackground: '{surface.800}',
activeBackground: '{surface.800}',
color: '{text.color}',
focusColor: '{text.hover.color}',
activeColor: '{text.hover.color}',
icon: {
color: '{surface.500}',
focusColor: '{surface.400}',
activeColor: '{surface.400}',
},
},
submenuLabel: {
background: 'transparent',
color: '{text.muted.color}',
},
submenuIcon: {
color: '{surface.500}',
focusColor: '{surface.400}',
activeColor: '{surface.400}',
},
},
},
},
},
components: {
accordion: {
header: {
borderRadius: '{content.border.radius}',
borderColor: '{content.border.color}',
background: '{surface.100}',
hoverBackground: '{surface.200}',
activeBackground: '{surface.200}',
activeHoverBackground: '{surface.200}',
},
content: {
padding: '0.5rem 0.25rem',
},
},
autocomplete: {
option: {
padding: '0.2rem 0.5rem',
},
},
card: {
root: {
background: '{surface.100}',
},
body: {
padding: '0',
},
},
fieldset: {
legend: {
padding: '0 0.25rem 0.25rem 0.25rem',
},
},
listbox: {
option: {
padding: '0.2rem 0.5rem',
},
},
menubar: {
root: {
borderColor: 'transparent',
},
},
panel: {
root: {
background: '{surface.100}',
},
content: {
padding: '0',
},
},
tag: {
root: {
fontSize: '0.8rem',
fontWeight: '600',
padding: '0.15rem 0.5rem',
gap: '0.25rem',
borderRadius: '{content.border.radius}',
roundedBorderRadius: '{border.radius.xl}',
},
icon: {
size: '0.5rem',
},
colorScheme: {
light: {
primary: {
background: '{primary.100}',
color: '{primary.700}',
},
secondary: {
background: '{surface.500}',
color: '{surface.0}',
},
success: {
background: '{green.100}',
color: '{green.700}',
},
info: {
background: '{sky.100}',
color: '{sky.700}',
},
warn: {
background: '{orange.100}',
color: '{orange.700}',
},
danger: {
background: '{red.100}',
color: '{red.700}',
},
contrast: {
background: '{surface.950}',
color: '{surface.0}',
},
},
dark: {
primary: {
background: 'color-mix(in srgb, {primary.500}, transparent 84%)',
color: '{primary.300}',
},
secondary: {
background: '{surface.800}',
color: '{surface.300}',
},
success: {
background: 'color-mix(in srgb, {green.500}, transparent 84%)',
color: '{green.300}',
},
info: {
background: 'color-mix(in srgb, {sky.500}, transparent 84%)',
color: '{sky.300}',
},
warn: {
background: 'color-mix(in srgb, {orange.500}, transparent 84%)',
color: '{orange.300}',
},
danger: {
background: 'color-mix(in srgb, {red.500}, transparent 84%)',
color: '{red.300}',
},
contrast: {
background: '{surface.0}',
color: '{surface.950}',
},
},
},
},
timeline: {
event: {
minHeight: '2.5rem',
},
},
},
}),
},
};
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
const CONFIG = {
MESSAGE_LIFE: 5000, // Message lifetime in ms
DEFAULT_SELECT_SCROLL_HEIGHT: '50vh',
};
// SPDX-FileCopyrightText: Fondation RERO+
// SPDX-License-Identifier: AGPL-3.0-or-later
class ReadMoreComponent {
text = input.required(...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
limit = input(50, ...(ngDevMode ? [{ debugName: "limit" }] : /* istanbul ignore next */ []));
unit = input('word', ...(ngDevMode ? [{ debugName: "unit" }] : /* istanbul ignore next */ []));
trailing = input('…', ...(ngDevMode ? [{ debugName: "trailing" }] : /* istanbul ignore next */ []));
showMoreLabel = input(_('show more'), ...(ngDevMode ? [{ debugName: "showMoreLabel" }] : /* istanbul ignore next */ []));
showLessLabel = input(_('show less'), ...(ngDevMode ? [{ debugName: "showLessLabel" }] : /* istanbul ignore next */ []));
showMore = linkedSignal(() => this.showMoreActivated(), ...(ngDevMode ? [{ debugName: "showMore" }] : /* istanbul ignore next */ []));
textDisplay = computed(() => this.processText(this.originalText(), this.showMore()), ...(ngDevMode ? [{ debugName: "textDisplay" }] : /* istanbul ignore next */ []));
showMoreLinkLabel = computed(() => (this.showMore() ? this.showMoreLabel() : this.showLessLabel()), ...(ngDevMode ? [{ debugName: "showMoreLinkLabel" }] : /* istanbul ignore next */ []));
showMoreActivated = computed(() => this.countElement() > this.limit(), ...(ngDevMode ? [{ debugName: "showMoreActivated" }] : /* istanbul ignore next */ []));
originalText = computed(() => this.text().replace(/<.*?>/g, ''), ...(ngDevMode ? [{ debugName: "originalText" }] : /* istanbul ignore next