UNPKG

@sixbell-telco/sdk

Version:

A collection of reusable components designed for use in Sixbell Telco Angular projects

1,171 lines (990 loc) 35.8 kB
# Sixbell Telco SDK - Component Library Welcome to the Sixbell Telco SDK component library. This is a comprehensive Angular component library featuring 25+ pre-built, production-ready UI components built with Angular 19, Tailwind CSS v4, and DaisyUI. ## Overview The SDK provides: - **25+ Production-Ready Components**: Button, Card, Form inputs, Data Table, Dialog, Dropdown, and more - **Utility Services**: Theme management, i18n translation, logging, and resource loading - **Directive Support**: Auto-focus, click-outside, form validation directives - **Tailwind CSS v4 + DaisyUI**: Modern styling with customizable themes - **Multi-Entry Point Architecture**: Granular imports for optimized bundle sizes - **Angular 19 Signal-Based**: Modern reactive patterns with Angular signals ## Pre-requirements - **Node.js**: ^18.19.1 || ^20.11.1 || ^22.0.0 - **npm**: 9.6.7 || ^10.0.0 || ^11.0.0 - **Angular**: 19.2.x or later - **Tailwind CSS**: v4.x ## Available Components ### General Components | Component | Description | | ------------- | ------------------------------------------------- | | Accordion | Expandable/collapsible content sections | | Avatar | User profile pictures with initials fallback | | Badge | Status and label indicators | | Button | Interactive buttons with variants and sizes | | Card | Container for content with actions | | Countdown | Countdown timer with customizable formatting | | Data Table | Advanced grid with sorting, filtering, pagination | | Dialog | Modal dialogs with animations and positioning | | Dropdown | Menu dropdown for actions and links | | Dropdown Menu | Advanced nested menu system | | Dual List | Dual list selection for managing items | | File Dropzone | Drag-and-drop file upload with validation | | File Uploader | File input with validation and preview | | Icon | SVG icon component with ng-icons integration | | Link | Hyperlink component with router support | | Modal | Modal dialogs (legacy - use Dialog instead) | | Notification | Toast-style notifications | | Overlay | Generic overlay with trigger and content | | Paginator | Pagination controls for data | | Product Card | Product display card with image and actions | | Progress | Progress bar with variants | | Sonner Toast | Modern toast notifications via ngx-sonner | | Tab | Tabbed navigation interface | | Table | Basic table for displaying data | | Tooltip | Floating tooltip with positioning | | Wizard | Multi-step wizard with validation | ### Form Components | Component | Description | | ---------- | ----------------------------------------------- | | Checkbox | Checkbox input with multiple variants | | Combobox | Searchable dropdown with multi-select support | | Datepicker | Single and range date selection with time | | Form Error | Error message display for form fields | | Input | Text input with variants, icons, and validation | | Radio | Radio button group selection | | Range | Slider input for numeric ranges | | Select | Dropdown select with object support | | Switch | Toggle switch for boolean values | | Textarea | Multi-line text input with character count | | Toggle | Toggle button for boolean states | ### Utility Services | Service | Purpose | Documentation | | ------------------- | -------------------------------------------------- | ------------------------------- | | Logger Service | Theme-aware logging with IndexedDB persistence | [README](utils/logger/) | | Theme Service | Runtime theme management with multi-tenant support | [README](utils/theme/) | | Translation Service | Multi-language i18n with ngx-translate integration | [README](utils/translation/) | | Runtime Config | Last-known-good runtime config loader | [README](utils/runtime-config/) | ### Directives | Directive | Purpose | | ------------- | ---------------------------------------- | | auto-focus | Auto-focus elements when visible | | click-outside | Detect clicks outside an element | | only-numbers | Restrict input to numeric values only | | typography | Apply typography styles to text elements | ## Installation ### Step 1: Install Dependencies ```bash npm install @sixbell-telco/sdk @tailwindcss/typography daisyui @midudev/tailwind-animations ``` ### Step 2: Import SDK Styles In your global `styles.css`: ```css @import '../node_modules/@sixbell-telco/sdk/_index.css'; @import 'tailwindcss'; @source '../src'; ``` > ⚠️ **Important**: Import `_index.css` **before** the tailwind import. ### Step 3: Configure Microfrontend (if applicable) Add path mapping to `tsconfig.json`: ```json { "compilerOptions": { "paths": { "@sixbell-telco/sdk/*": ["./node_modules/@sixbell-telco/sdk/*"] } } } ``` ### Step 4: Optional - VSCode Configuration Install the Tailwind CSS extension and add to `.vscode/settings.json`: ```json { "editor.quickSuggestions": { "strings": "on" }, "files.associations": { "*.css": "tailwindcss" }, "tailwindCSS.classFunctions": ["tw", "clsx", "cva", "cn", "tw\\.[a-z-]+"] } ``` These settings improve your development experience: - `editor.quickSuggestions`: Enables autosuggestions within string literals - `files.associations`: Ensures CSS files are treated as Tailwind CSS files - `tailwindCSS.classFunctions`: Enables Tailwind intellisense in utility functions like `tw()`, `clsx()`, and `cva()`, etc that are used for conditional class name composition With these settings, VSCode will provide class autocompletion for the library's custom attributes and utility functions. ## Themes and translation configuration (an optional Logger) Configure all services using runtime providers in your `app.config.ts`. This approach loads configuration from JSON files at runtime, eliminating the need to recompile when updating themes or languages. ### Logger Service Setup Configure logging with different levels for development and production: ```typescript import { provideLogger } from '@sixbell-telco/sdk/utils/logger'; export const appConfig: ApplicationConfig = { providers: [ provideLogger({ enableLogging: true, logLevel: isDevMode() ? 'debug' : 'warn', // trace | debug | info | warn | error | fatal showTimestamp: true, persistToIndexedDB: true, // Persistent storage for debugging silentMode: !isDevMode(), }), ], }; ``` ### Translation Service Setup The Translation Service loads language configuration from a runtime JSON file: ```typescript import { provideRuntimeTranslation } from '@sixbell-telco/sdk/utils/translation'; export const appConfig: ApplicationConfig = { providers: [provideRuntimeTranslation('/assets/translation/translation.json')], }; ``` The `translation.json` file defines available languages and their translation paths: ```json { "defaultLang": "es", "translationPaths": ["/assets/i18n/"] } ``` ### Theme Service Setup The Theme Service loads theme configuration from a runtime JSON file: ```typescript import { provideRuntimeTheme } from '@sixbell-telco/sdk/utils/theme'; export const appConfig: ApplicationConfig = { providers: [provideRuntimeTheme('/assets/themes/themes.json')], }; ``` The `themes.json` file defines available themes and their variants: ```json { "meta": { "name": "themes", "updatedAt": "2026-02-02T00:00:00Z", "hash": "themes-v2", "schemaVersion": "2" }, "themes": ["/assets/themes/catalog/sixbell_telco.json", "/assets/themes/catalog/custom_theme.json"], "defaultTheme": "sixbell_telco", "defaultScheme": "system", "excludeThemes": [] } ``` ### Complete Configuration Example ```typescript // app.config.ts import { DialogModule } from '@angular/cdk/dialog'; import { ApplicationConfig, importProvidersFrom, isDevMode } from '@angular/core'; import { provideRouter } from '@angular/router'; import { provideHttpClient } from '@angular/common/http'; import { provideLogger } from '@sixbell-telco/sdk/utils/logger'; import { provideRuntimeTheme } from '@sixbell-telco/sdk/utils/theme'; import { provideRuntimeTranslation } from '@sixbell-telco/sdk/utils/translation'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { providers: [ provideRouter(routes), provideHttpClient(), // CDK Dialog providers (required for dialog component) importProvidersFrom(DialogModule), // Logger service - configure logging levels and storage provideLogger({ enableLogging: true, logLevel: isDevMode() ? 'debug' : 'warn', showTimestamp: true, persistToIndexedDB: true, silentMode: !isDevMode(), }), // Translation service - loads languages from runtime JSON provideRuntimeTranslation('/assets/translation/translation.json'), // Theme service - loads themes from runtime JSON provideRuntimeTheme('/assets/themes/themes.json'), ], }; ``` **Key Benefits of Runtime Configuration:** - **No Recompilation**: Update themes and languages without rebuilding your application - **Multi-Tenant Support**: Easily switch themes and language sets per deployment environment - **Caching Strategy**: RuntimeConfigStore keeps last-known-good config in Dexie - **Hot Updates**: Changes to `themes.json` and `translation.json` take effect immediately - **Persistent Preferences**: User language and theme preferences are stored and restored automatically ## Adding Custom Themes Themes are managed through a runtime configuration file (`themes.json`) with theme JSON files. This approach allows for: - **Zero Recompilation**: Add/modify themes without rebuilding - **Multi-Tenant Support**: Different themes per deployment - **Dynamic Assets**: Brand-specific logos and images per theme - **Runtime Fonts**: Load custom fonts for each theme - **Hot Updates**: Changes take effect immediately ### 1. Update `themes.json` Add your custom theme to `/assets/themes/themes.json`: ```json { "meta": { "name": "themes", "updatedAt": "2026-02-02T00:00:00Z", "hash": "themes-v2", "schemaVersion": "2" }, "themes": ["/assets/themes/catalog/sixbell_telco.json", "/assets/themes/catalog/custom_theme.json"], "defaultTheme": "sixbell_telco", "defaultScheme": "system", "excludeThemes": [] } ``` **Configuration Structure:** - `themes`: Theme JSON paths - `defaultTheme`: Initial theme on app startup - `defaultScheme`: Initial color scheme (`'system'`, `'light'`, or `'dark'`) ### 2. Define DaisyUI Themes in Global Styles In your global `styles.css`, import the SDK and define your theme CSS: ```css @import '../node_modules/@sixbell-telco/sdk/_index.css'; @import 'tailwindcss'; @source '../src'; ``` ### 3. Use Themes in Components The ThemeService automatically loads available themes from `themes.json`: ```typescript import { Component, ChangeDetectionStrategy, inject, computed } from '@angular/core'; import { ThemeService, ThemeAssetsService } from '@sixbell-telco/sdk/utils/theme'; import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-theme-switcher', standalone: true, imports: [CommonModule, ButtonComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: ` <div> <select (change)="themeService.setTheme($event.target.value)"> @for (theme of themeService.getAvailableThemes(); track theme) { <option [value]="theme" [selected]="themeService.selectedTheme() === theme"> {{ themeService.getLocalizedThemeName(theme) }} </option> } </select> <select (change)="themeService.setScheme($event.target.value)"> @for (scheme of themeService.getAvailableSchemes(); track scheme) { <option [value]="scheme" [selected]="themeService.selectedScheme() === scheme"> {{ themeService.getLocalizedSchemeName(scheme) }} </option> } </select> <img [src]="logoUrl()" alt="Brand Logo" /> </div> `, }) export class ThemeSwitcherComponent { themeService = inject(ThemeService); private assetsService = inject(ThemeAssetsService); logoUrl = computed( () => this.assetsService.getAssetUrl(this.themeService.selectedTheme(), 'logo', this.themeService.resolvedScheme()) || '/default-logo.svg', ); } ``` ### 4. Add Theme Names to Translations Store theme and scheme display names in translation files. Create `/assets/themes/i18n/en.json`: **English (`en.json`):** ```json { "sdk": { "theme": { "themes": { "sixbell_telco": "Sixbell Telco", "custom_theme": "Custom Theme" }, "schemes": { "system": "System", "light": "Light", "dark": "Dark" } } } } ``` **Spanish (`es.json`):** ```json { "sdk": { "theme": { "themes": { "sixbell_telco": "Sixbell Telco", "custom_theme": "Tema Personalizado" }, "schemes": { "system": "Sistema", "light": "Claro", "dark": "Oscuro" } } } } ``` **Portuguese (`pt.json`):** ```json { "sdk": { "theme": { "themes": { "sixbell_telco": "Sixbell Telco", "custom_theme": "Tema Personalizado" }, "schemes": { "system": "Sistema", "light": "Claro", "dark": "Escuro" } } } } ``` Your themes are now fully configured. The ThemeService automatically: - Loads theme definitions from `themes.json` - Injects CSS variables via signals - Resolves dynamic assets based on current theme and scheme - Persists user preferences to localStorage - Detects system dark mode preference when scheme is set to `'system'` ## Adding Custom Languages Languages are now managed through a runtime configuration file (`translation.json`), eliminating the need to reconfigure and recompile. This approach allows for: - **Zero Recompilation**: Add or modify languages without rebuilding - **Multi-Tenant Languages**: Different language sets per deployment environment - **Hot Updates**: Changes to translation configuration take effect immediately - **Flexible Structure**: Organize translation files any way you need ### 1. Create or Update `translation.json` Create `/assets/translation/translation.json` in your application: ```json { "defaultLang": "es", "translationPaths": ["/assets/i18n/"] } ``` **Configuration Structure:** - `defaultLang`: Language code used on app initialization - `translationPaths`: List of directories that contain `{lang}.json` - Custom paths are fully supported - organize as needed for your architecture ### 2. Create Translation Files Create language translation files at the paths defined in `translation.json`. The minimal translation structure includes SDK translations: **English (`/assets/sdk/i18n/en.json`):** ```json { "sdk": { "fileUpload": { "dropzone": { "selectPrompt": "Click to select files or drag and drop here", "maxSizeLabel": "Max size:", "allowedTypesLabel": "Allowed types:", "invalidFileType": "Invalid file type", "fileTooLarge": "File too large", "fileCounter": "{{current}} of {{max}} files", "maxFilesExceeded": "Maximum {{max}} file(s) allowed", "noValidFiles": "No valid files selected", "fileActions": { "play": "Play audio", "pause": "Pause audio", "download": "Download file", "remove": "Remove file" } }, "fileUploader": { "allowedTypesLabel": "Allowed types:" } }, "audioPlayer": { "trackListTitle": "Tracks", "trackInfo": { "title": "No title", "description": "No description" } }, "countdown": { "days": "Days", "hours": "Hours", "minutes": "Minutes", "seconds": "Seconds" }, "dualList": { "searchPlaceHolder": "Search" }, "combobox": { "searchPlaceholder": "Search", "placeholder": "Select", "noResultsFound": "No results found", "clearAll": "Clear All", "clearSelection": "Clear selection", "searchOptions": "Search options", "loading": "Loading..." }, "select": { "placeholder": "Select" }, "formErrors": { "validation": { "required": "*This field is required", "email": "*Please enter a valid email address", "minLength": "*Must be at least {{min}} characters", "maxLength": "*Must be no more than {{max}} characters", "min": "*Value must be at least {{min}}", "max": "*Value must be no more than {{max}}", "pattern": "*Invalid format", "unhandledError": "*Unhandled error" } }, "textarea": { "maxCharacters": "{{current}} of {{max}} characters" }, "table": { "entriesByPage": "Entries per page", "perPage": "{{count}} / page", "totalEntries": "{{total}} entries", "entriesRange": "{{range}} of {{total}} entries", "emptyListMessage": "No items to show" }, "dataTable": { "entriesByPage": "Entries per page", "perPage": "{{count}} / page", "totalEntries": "{{total}} entries", "entriesRange": "{{range}} of {{total}} entries", "emptyListMessage": "No items to show", "noData": { "title": "No data available", "message": "There are no records to display at this time." }, "noResults": { "title": "No results found", "message": "Try adjusting your search criteria" } }, "wizard": { "wizardMarker": { "completed": "Completed", "inProgress": "In progress", "pending": "Pending" }, "wizardWrapper": { "back": "Back", "previous": "Previous", "end": "End", "next": "Next", "step": "Step {{index}}" } }, "datePicker": { "quickActions": { "title": "Quick Select", "lastHour": "Last hour", "last3Hours": "Last 3 hours", "last6Hours": "Last 6 hours", "last12Hours": "Last 12 hours", "last24Hours": "Last 24 hours", "last7Days": "Last 7 days", "last30Days": "Last 30 days", "last6Months": "Last 6 months", "lastYear": "Last year", "clear": "Clear" }, "labels": { "from": "From", "to": "To" } } } } ``` **Spanish (`/assets/i18n/es.json`):** ```json { "sdk": { "fileUpload": { "dropzone": { "selectPrompt": "Haz clic para seleccionar archivos o arrastra y suelta aquí", "maxSizeLabel": "Tamaño máximo:", "allowedTypesLabel": "Tipos permitidos:", "invalidFileType": "Tipo de archivo no válido", "fileTooLarge": "Archivo demasiado grande", "fileCounter": "{{current}} de {{max}} archivos", "maxFilesExceeded": "Máximo de {{max}} archivo(s) permitido", "noValidFiles": "No se han seleccionado archivos válidos", "fileActions": { "play": "Reproducir audio", "pause": "Pausar audio", "download": "Descargar archivo", "remove": "Quitar archivo" } }, "fileUploader": { "allowTypesLabel": "Tipos permitidos:" } }, "audioPlayer": { "trackListTitle": "Pistas", "trackInfo": { "title": "Sin título", "description": "Sin descripción" } }, "countdown": { "days": "Días", "hours": "Horas", "minutes": "Minutos", "seconds": "Segundos" }, "dualList": { "searchPlaceHolder": "Buscar" }, "combobox": { "searchPlaceholder": "Buscar", "placeholder": "Seleccione", "noResultsFound": "No se encontraron resultados", "clearAll": "Limpiar Todo", "clearSelection": "Limpiar selección", "searchOptions": "Buscar opciones", "loading": "Cargando..." }, "select": { "placeholder": "Seleccione" }, "formErrors": { "validation": { "required": "*Este campo es obligatorio", "email": "*Por favor ingresa una dirección de correo válida", "minLength": "*Debe tener al menos {{min}} caracteres", "maxLength": "*No debe tener más de {{max}} caracteres", "min": "*El valor debe ser al menos {{min}}", "max": "*El valor no debe superar {{max}}", "pattern": "*Formato inválido", "unhandledError": "*Error inesperado" } }, "textarea": { "maxCharacters": "{{current}} de {{max}} caracteres" }, "table": { "entriesByPage": "Entradas por página", "perPage": "{{count}} / página", "totalEntries": "{{total}} entradas", "entriesRange": "{{range}} de {{total}} entradas", "emptyListMessage": "No hay elementos para mostrar" }, "dataTable": { "entriesByPage": "Entradas por página", "perPage": "{{count}} / página", "totalEntries": "{{total}} entradas", "entriesRange": "{{range}} de {{total}} entradas", "emptyListMessage": "No hay elementos para mostrar", "noData": { "title": "No hay datos disponibles", "message": "No hay registros para mostrar en este momento." }, "noResults": { "title": "No se encontraron resultados", "message": "Intenta ajustar tus criterios de búsqueda" } }, "wizard": { "wizardMarker": { "completed": "Completado", "inProgress": "En progreso", "pending": "Pendiente" }, "wizardWrapper": { "back": "Atrás", "previous": "Anterior", "end": "Finalizar", "next": "Siguiente", "step": "Paso {{index}}" } }, "datePicker": { "quickActions": { "title": "Selección Rápida", "lastHour": "Última hora", "last3Hours": "Últimas 3 horas", "last6Hours": "Últimas 6 horas", "last12Hours": "Últimas 12 horas", "last24Hours": "Últimas 24 horas", "last7Days": "Últimos 7 días", "last30Days": "Últimos 30 días", "last6Months": "Últimos 6 meses", "lastYear": "Último año", "clear": "Limpiar" }, "labels": { "from": "Desde", "to": "Hasta" } } } } ``` **Portuguese (`/assets/i18n/pt.json`):** ```json { "sdk": { "fileUpload": { "dropzone": { "selectPrompt": "Haz clic para seleccionar archivos o arrastra y suelta aquí", "maxSizeLabel": "Tamaño máximo:", "allowedTypesLabel": "Tipos permitidos:", "invalidFileType": "Tipo de archivo no válido", "fileTooLarge": "Archivo demasiado grande", "fileCounter": "{{current}} de {{max}} archivos", "maxFilesExceeded": "Máximo de {{max}} archivo(s) permitido", "noValidFiles": "No se han seleccionado archivos válidos", "fileActions": { "play": "Reproducir audio", "pause": "Pausar audio", "download": "Descargar archivo", "remove": "Quitar archivo" } }, "fileUploader": { "allowedTypesLabel": "Tipos permitidos:" } }, "audioPlayer": { "trackListTitle": "Trilhas", "trackInfo": { "title": "Sem título", "description": "Sem descrição" } }, "countdown": { "days": "Dias", "hours": "Horas", "minutes": "Minutos", "seconds": "Segundos" }, "dualList": { "searchPlaceHolder": "Pesquisar" }, "combobox": { "searchPlaceholder": "Pesquisar", "placeholder": "Selecione", "noResultsFound": "Nenhum resultado encontrado", "clearAll": "Limpar Tudo", "clearSelection": "Limpar seleção", "searchOptions": "Pesquisar opções", "loading": "Carregando..." }, "select": { "placeholder": "Selecione" }, "formErrors": { "validation": { "required": "*Este campo é obrigatório", "email": "*Por favor, insira um endereço de e-mail válido", "minLength": "*Deve ter pelo menos {{min}} caracteres", "maxLength": "*Deve ter no máximo {{max}} caracteres", "min": "*O valor deve ser de pelo menos {{min}}", "max": "*O valor deve ser de no máximo {{max}}", "pattern": "*Formato inválido", "unhandledError": "*Erro não tratado" } }, "textarea": { "maxCharacters": "{{current}} de {{max}} caracteres" }, "table": { "entriesByPage": "Entradas por página", "perPage": "{{count}} / página", "totalEntries": "{{total}} entradas", "entriesRange": "{{range}} de {{total}} entradas", "emptyListMessage": "Nenhum item para mostrar" }, "dataTable": { "entriesByPage": "Entradas por página", "perPage": "{{count}} / página", "totalEntries": "{{total}} entradas", "entriesRange": "{{range}} de {{total}} entradas", "emptyListMessage": "Nenhum item para mostrar", "noData": { "title": "Nenhum dado disponível", "message": "Não há registros para exibir neste momento." }, "noResults": { "title": "Nenhum resultado encontrado", "message": "Tente ajustar seus critérios de pesquisa" } }, "wizard": { "wizardMarker": { "completed": "Concluído", "inProgress": "Em andamento", "pending": "Pendente" }, "wizardWrapper": { "back": "Voltar", "previous": "Anterior", "end": "Fim", "next": "Próximo", "step": "Etapa {{index}}" } }, "datePicker": { "quickActions": { "title": "Seleção Rápida", "lastHour": "Última hora", "last3Hours": "Últimas 3 horas", "last6Hours": "Últimas 6 horas", "last12Hours": "Últimas 12 horas", "last24Hours": "Últimas 24 horas", "last7Days": "Últimos 7 dias", "last30Days": "Últimos 30 dias", "last6Months": "Últimos 6 meses", "lastYear": "Último ano", "clear": "Limpar" }, "labels": { "from": "De", "to": "Até" } } } } ``` ### 3. Access Language Functionality in Components The TranslationService automatically loads available languages from `translation.json`: ```typescript // In any component import { TranslationService } from '@sixbell-telco/sdk/utils/translation'; import { inject } from '@angular/core'; export class MyComponent { private translationService = inject(TranslationService); availableLanguages = this.translationService.getAvailableLanguageCodes(); currentLanguage = this.translationService.currentLanguage; setLanguage(languageCode: string) { this.translationService.setLanguage(languageCode); } getLanguageName(languageCode: string): string { return this.translationService.getLanguageDisplayName(languageCode); } } ``` ### 4. Use Translations in Templates Translations are automatically loaded and available through the `translate` pipe: ```html <!-- Access any translation key --> <h1>{{ 'sdk.language.languages.en' | translate }}</h1> <!-- With parameters --> <p>{{ 'welcome.message' | translate: { name: userName } }}</p> <!-- In component --> <select (change)="setLanguage($event.target.value)"> @for (lang of availableLanguages; track lang) { <option [value]="lang">{{ getLanguageName(lang) }}</option> } </select> ``` ### 5. Add Custom Application Translations Extend the translation files with your application-specific keys: **English (`/assets/i18n/en.json`):** ```json { "app": { "title": "My Application", "welcome": "Welcome to our app", "features": { "description": "Powerful features for your business" } }, "sdk": { ...// SDK translations } } ``` Your application is now configured with full multi-language support. Language preferences are automatically persisted and restored on return visits. ## Usage Examples ### Using Components Here's a basic example of using a button component: ```typescript // app.component.ts import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; @Component({ imports: [ButtonComponent], template: ` <div> <h1>Awesome button</h1> <st-button variant="primary">Click me!</st-button> </div> ` }) ``` ### Using Services in Components ```typescript // component.ts import { ThemeService } from '@sixbell-telco/sdk/utils/theme'; import { TranslationService } from '@sixbell-telco/sdk/utils/translation'; @Component({ template: ` <div [class]="themeService.finalTheme()"> <h1>{{ 'welcome.title' | translate }}</h1> <p>Current theme: {{ themeService.selectedTheme() }}</p> <p>Dark mode: {{ themeService.isDarkTheme() ? 'Yes' : 'No' }}</p> <!-- Theme selector --> <select (change)="changeTheme($event.target.value)"> @for (theme of themeService.getAvailableThemes(); track theme) { <option [value]="theme">{{ theme }}</option> } </select> <!-- Language selector --> <select (change)="changeLanguage($event.target.value)"> @for (lang of translationService.getAvailableLanguageCodes(); track lang) { <option [value]="lang">{{ translationService.getLanguageDisplayName(lang) }}</option> } </select> </div> `, }) export class MyComponent { themeService = inject(ThemeService); translationService = inject(TranslationService); changeTheme(theme: string) { this.themeService.setTheme(theme); } changeLanguage(language: string) { this.translationService.setLanguage(language); } } ``` ## Quick Start ### Using Components ```typescript import { Component } from '@angular/core'; import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; import { CardComponent } from '@sixbell-telco/sdk/components/card'; @Component({ selector: 'app-example', standalone: true, imports: [ButtonComponent, CardComponent], template: ` <st-card> <h2>Hello World</h2> <st-button variant="primary">Click me!</st-button> </st-card> `, }) export class ExampleComponent {} ``` ### Using Form Components ```typescript import { Component, signal } from '@angular/core'; import { ReactiveFormsModule, FormControl, FormGroup } from '@angular/forms'; import { InputComponent } from '@sixbell-telco/sdk/components/forms/input'; import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; @Component({ selector: 'app-form-example', standalone: true, imports: [InputComponent, ButtonComponent, ReactiveFormsModule], template: ` <form [formGroup]="form"> <st-input formControlName="email" placeholder="Enter email"></st-input> <st-button (click)="submit()">Submit</st-button> </form> `, }) export class FormExampleComponent { form = new FormGroup({ email: new FormControl(''), }); submit() { console.log(this.form.value); } } ``` ### Using Services ```typescript import { Component, inject, effect } from '@angular/core'; import { ThemeService } from '@sixbell-telco/sdk/utils/theme'; import { TranslationService } from '@sixbell-telco/sdk/utils/translation'; import { LoggerService } from '@sixbell-telco/sdk/utils/logger'; @Component({ selector: 'app-services-example', template: ` <div> <p>Current Theme: {{ themeService.selectedTheme() }}</p> <p>Dark Mode: {{ themeService.isDarkTheme() ? 'Yes' : 'No' }}</p> <button (click)="toggleTheme()">Toggle Theme</button> </div> `, }) export class ServicesExampleComponent { themeService = inject(ThemeService); translationService = inject(TranslationService); logger = inject(LoggerService); constructor() { effect(() => { this.logger.info(`Theme changed to: ${this.themeService.selectedTheme()}`); }); } toggleTheme() { const newScheme = this.themeService.isDarkTheme() ? 'light' : 'dark'; this.themeService.setScheme(newScheme); } } ``` ## Configuration ### Theme Configuration Runtime themes are loaded from `themes.json`. See [Theme Service README](utils/theme/) for detailed configuration. ### Translation Configuration Runtime translations are loaded from `translation.json`. See [Translation Service README](utils/translation/) for detailed configuration. ### Logger Configuration Configure logging levels and output. See [Logger Service README](utils/logger/) for detailed options. ## Architecture ### Multi-Entry Point Imports Always use specific imports for optimal tree-shaking: ```typescript // ✅ Correct - specific imports import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; import { ThemeService } from '@sixbell-telco/sdk/utils/theme'; // ❌ Avoid - barrel exports import { ButtonComponent } from '@sixbell-telco/sdk'; ``` ### Component Prefix All SDK components use the `st-` prefix: ```html <st-button>Button</st-button> <st-input type="text" /> <st-card>Card Content</st-card> ``` ### Signal-Based API Components use Angular 19 signals for reactive inputs: ```typescript variant = input<'primary' | 'secondary'>(); isDisabled = input(false); @Component({ template: `<button [disabled]="isDisabled()">{{ variant() }}</button>`, }) ``` ## Testing The SDK includes Jest configuration. Run tests with: ```bash npm test # Run all tests npm run test:watch # Watch mode npm run test:coverage # Coverage report ``` See `.github/instructions/testing-basics.instructions.md` for Angular 19 testing patterns. ## Documentation - **Component Stories**: View component documentation in [Storybook](../storybook/README.md) - **Live Examples**: Showcase app at `projects/showcase/` - **API Documentation**: JSDoc comments in component files - **Changelog**: See [CHANGELOG.md](./CHANGELOG.md) ## Contributing When creating new components: 1. Use `st-` prefix for selectors 2. Follow CVA pattern for styling variants 3. Use signal-based inputs 4. Add comprehensive JSDoc comments 5. Create Storybook stories 6. Add unit tests with Jest 7. Update CHANGELOG.md ## Resources - <a href="https://angular.dev" target="_blank" rel="noopener noreferrer">Angular Documentation</a> - <a href="https://tailwindcss.com" target="_blank" rel="noopener noreferrer">Tailwind CSS</a> - <a href="https://daisyui.com" target="_blank" rel="noopener noreferrer">DaisyUI</a> - <a href="https://cva.style" target="_blank" rel="noopener noreferrer">class-variance-authority</a> - <a href="https://ng-icons.herokuapp.com" target="_blank" rel="noopener noreferrer">ng-icons</a> - <a href="https://material.angular.io/cdk" target="_blank" rel="noopener noreferrer">Angular CDK</a> ## License MIT - See [LICENSE](./LICENSE) file for details ## Support For issues, questions, or feature requests, please visit the project repository or contact the Sixbell Telco team. --- **Last updated**: November 24, 2025