@squidit/ngx-css
v1.3.93
Published
Squid CSS Styleguide for Angular
Readme
NGX CSS - Library
About
NGX CSS Framework An angular abstraction for Squid CSS
Table of contents
Exemple
See an exemple of all components here
Usage
Install
- Install
npm install @squidit/css @squidit/ngx-css --save- Add
cssandtoast jsfiles to yourangular.json
{
// ...,
"assets": [
// This object inside assets Array
{
"glob": "**/*",
"input": "./node_modules/@squidit/css/dist/fonts",
"output": "./assets/fonts" // Output fonts
},
"src/assets" // Default assets
],
"styles": [
"src/styles.scss"
],
"scripts": [
"node_modules/@squidit/css/src/js/components/toast.js" // JS includes (legacy)
]
// ...
}- Add to your
style.scssmain file
$fontsFolderPath: '/assets/fonts'; // Overwrite default font path
@import '@squidit/css/src/scss/squid.scss'; // Import all Framework Styles- Import
SquidCSSModulein your*.module.ts
import { SquidCSSModule } from '@squidit/ngx-css'
@NgModule({
// ...
imports: [
// ...
NgxSquidModule
]
// ...
})Use form erros variables
To use the errors handled in form components, you need to follow the steps below
Install ngx-translate and follow the initial Setup
On you
.jsonfiles from each language follow the same structure (need one for each supported language of your application):
{
// ...
"forms": {
"search": "Search",
"searchSelectEmpty": "There are no options to select",
"fileSize": "File too large",
"required": "Required field",
"minimumRequired": "The minimum number of selected tags must be greater than or equal to {{ minTags }}",
"email": "Invalid email",
"url": "Invalid URL. Attention: URL must start with https://",
"date": "Invalid Date",
"phone": "Invalid phone number",
"minValueAllowed": "Min value allowed is: {{ min }}",
"maxValueAllowed": "Max value allowed is: {{ max }}",
"rangeDate:": "Date outside valid range"
}
// ...
}SqModalService
Service for programmatically opening Modal and Overlay dialogs. Fully testable, Observable-based, with proper memory management.
Basic Usage
import { Component, inject } from '@angular/core';
import { SqModalService } from '@squidit/ngx-css';
@Component({...})
export class MyComponent {
private modalService = inject(SqModalService);
openSimpleModal() {
this.modalService.openModal({
header: 'Confirm Action',
body: myBodyTemplate, // TemplateRef or Component
size: 'md'
}).subscribe(result => {
if (result) {
console.log('User confirmed!');
}
});
}
}Modal Configuration
interface SqModalConfig<T = any> {
id?: string; // Unique ID (auto-generated if not provided)
header?: string | TemplateRef; // Header content (string = title)
body?: TemplateRef | Type<any>; // Body content (template or component)
footer?: TemplateRef; // Footer content (template)
data?: T; // Data to pass to content
size?: 'sm' | 'md' | 'lg' | 'xl'; // Modal size (default: 'md')
backdrop?: 'static' | true; // Backdrop behavior (default: 'static')
showCloseButton?: boolean; // Show X button (default: true)
customClass?: string; // Additional CSS classes
cancelText?: string; // Cancel button text (default: 'Cancelar')
confirmText?: string; // Confirm button text (default: 'Confirmar')
dataTest?: string; // data-test attribute for testing
}Overlay Configuration
interface SqOverlayConfig<T = any> extends SqDialogConfig<T> {
direction?: 'left' | 'right' | 'top' | 'bottom'; // Slide direction (default: 'right')
width?: string; // Custom width for left/right overlays
height?: string; // Custom height for top/bottom overlays
borderless?: boolean;
}Opening with Templates
@ViewChild('headerTemplate') headerTemplate!: TemplateRef<any>;
@ViewChild('bodyTemplate') bodyTemplate!: TemplateRef<any>;
@ViewChild('footerTemplate') footerTemplate!: TemplateRef<any>;
openModal() {
this.modalService.openModal({
header: this.headerTemplate,
body: this.bodyTemplate,
footer: this.footerTemplate,
data: { items: this.items }
});
}<ng-template #bodyTemplate let-modal let-data="data">
<ul>
@for (item of data.items; track item.id) {
<li>{{ item.name }}</li>
}
</ul>
</ng-template>
<ng-template #footerTemplate let-modal let-data="data">
<button (click)="modal.close()">Cancel</button>
<button (click)="modal.close(data)">Save</button>
</ng-template>Opening with Components
// Content component
@Component({
selector: 'app-my-content',
template: `
<h3>{{ title }}</h3>
<button (click)="dialogRef?.close({ saved: true })">Save</button>
`
})
export class MyContentComponent {
@Input() title!: string; // Receives from data
@Input() dialogRef?: SqDialogRef; // Auto-injected
// Optional: provide header/footer templates
@ViewChild('headerTemplate') headerTemplate?: TemplateRef<any>;
@ViewChild('footerTemplate') footerTemplate?: TemplateRef<any>;
}
// Opening
this.modalService.openModal({
body: MyContentComponent,
data: { title: 'My Modal Title' }
}).subscribe(result => {
if (result?.saved) {
console.log('Data was saved!');
}
});Opening an Overlay
openSidePanel() {
this.modalService.openOverlay({
direction: 'right',
width: '500px',
body: FilterPanelComponent,
data: { filters: this.currentFilters }
}).subscribe(result => {
if (result) {
this.applyFilters(result);
}
});
}Confirmation Before Close
Use the confirmBeforeClose operator to prompt user before closing without saving:
import { confirmBeforeClose } from '@squidit/ngx-css';
this.modalService.openModal({
body: MyFormComponent,
data: { form: this.form }
}).pipe(
confirmBeforeClose(() => {
// Return Observable<boolean>, Promise<boolean>, or boolean
return confirm('You have unsaved changes. Discard?');
})
).subscribe(result => {
// Only reaches here if user confirms or saves
});Programmatic Control
const ref = this.modalService.openModal({...});
// Close with result
ref.close({ success: true });
// Close without result (cancel)
ref.close();
// Update data in content component
ref.updateData({ loading: true });
// Close all modals
this.modalService.closeAll();
// Check open count
console.log(this.modalService.openCount);SqToastService
Service for displaying toast notifications. Observable-based, fully testable, with proper memory management and data-test attributes.
Basic Usage
import { Component, inject } from '@angular/core';
import { SqToastService } from '@squidit/ngx-css';
@Component({...})
export class MyComponent {
private toastService = inject(SqToastService);
showSuccess() {
this.toastService.success('Operation completed successfully!');
}
showError() {
this.toastService.error('Something went wrong.');
}
}Toast Types
// Success (green)
this.toastService.success('Item saved!');
// Error (red)
this.toastService.error('Failed to save item.');
// Warning (yellow)
this.toastService.warning('This action cannot be undone.');
// Info (blue)
this.toastService.info('New updates available.');
// Default (gray)
this.toastService.default('Notification message.');Toast Configuration
interface SqToastConfig {
type?: 'success' | 'error' | 'warning' | 'info' | 'default';
duration?: number; // ms, 0 = persistent (default: 5000)
position?: SqToastPosition; // (default: 'top-right')
closeable?: boolean; // Show close button (default: true)
showIcon?: boolean; // Show type icon (default: false)
icon?: string; // Custom icon class (FontAwesome)
dismissOnClick?: boolean; // Click toast to dismiss (default: false)
pauseOnHover?: boolean; // Pause timer on hover (default: true)
action?: { // Action button
label: string;
callback?: () => void;
};
customClass?: string;
dataTest?: string; // data-test attribute
data?: any; // Data for template messages
}Available Positions
type SqToastPosition =
| 'top-right' // Default
| 'top-left'
| 'top-center'
| 'top-full' // Full-width banner at top
| 'bottom-right'
| 'bottom-left'
| 'bottom-center'
| 'bottom-full'; // Full-width banner at bottomWith Action Button
this.toastService.success('Item deleted', {
duration: 8000,
action: {
label: 'Undo',
callback: () => this.undoDelete()
}
});Persistent Toast (Manual Dismiss)
const ref = this.toastService.warning('Processing...', {
duration: 0 // Never auto-dismiss
});
// Later, dismiss programmatically
ref.dismiss();With Observable Lifecycle
this.toastService.info('Click me!', {
duration: 0,
dismissOnClick: true
}).afterDismissed().subscribe(reason => {
// reason: 'timeout' | 'action' | 'manual' | 'swipe'
console.log('Toast dismissed by:', reason);
});Full-Width Banner
// Top banner (like success notification)
this.toastService.success('Campaign created successfully!', {
position: 'top-full'
});
// Bottom banner
this.toastService.error('Connection lost', {
position: 'bottom-full'
});With Custom Template
@ViewChild('customToast') customToast!: TemplateRef<any>;
showCustom() {
this.toastService.success(this.customToast, {
data: { userName: 'John', count: 5 }
});
}<ng-template #customToast let-ref let-data="data">
<strong>{{ data.userName }}</strong> completed {{ data.count }} tasks!
<button (click)="ref.dismiss()">OK</button>
</ng-template>Global Operations
// Dismiss all active toasts
this.toastService.dismissAll();
// Get count of active toasts
console.log(this.toastService.getActiveCount());Unit Testing
it('should show success toast', () => {
const toastSpy = spyOn(toastService, 'success').and.callThrough();
component.save();
expect(toastSpy).toHaveBeenCalledWith('Data saved!');
});E2E Testing (Cypress)
// Find toast by data-test
cy.get('[data-test="sq-toast-container"]').should('exist');
cy.get('[data-test="sq-toast-1"]').should('contain', 'Success!');
cy.get('[data-test="sq-toast-1-close"]').click();Development
Install npm dependences
npm installRun
npm startto watch angular library (srcdirectory)In another window run
start:application
This launches an angular pattern that is contained in the application folder. Just use the components inside it, and every change in the files in the src folder will be automatically reflected in the application.
Write Documentation
We use compodoc to write docs with jsDocs
Run start:docs and the compodoc will serve the docs. For each change it is necessary to run the command again
Deploy to NPM
Just draft a new release here on Github and an actions will starts
**Important to use the same tag as package.json
Documentation
See Docs here
