npm package: @lumston/ds-angular
Description: Lumston Design System for Angular applications
Author: tsanchez
Latest version: 1.0.2

# @lumston/ds-angular

Angular component library for the Lumston Design System.

## Requirements

- Angular 17 or later (developed and tested on Angular 21)
- `@angular/common`, `@angular/core`, `@angular/platform-browser`

---

## Installation

```bash
npm install @lumston/ds-angular
```

---

## Default font

The library uses **Nunito** as its default font family via the `--ls-font-family` token. Nunito is not bundled — you must load it yourself.

**Option 1 — Google Fonts (recommended):**

Add the following `<link>` tags inside `<head>` in your `index.html`:

```html
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap"
  rel="stylesheet" />
```

**Option 2 — Self-hosted:**

Download the font files and add a `@font-face` declaration in your global `styles.css`:

```css
@font-face {
  font-family: 'Nunito';
  src: url('/assets/fonts/Nunito-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
```

**Override the font:**

To use a different font, override the token in your global `styles.css` after the library is loaded:

```css
:root {
  --ls-font-family: 'Inter', sans-serif;
}
```

---

## Dark theme

All components support dark mode out of the box. Dark styles activate when the `dark` class is present on `<body>`.

### How it works

The library uses a CSS class strategy — no media query is required. Components listen for `body.dark` and switch their color tokens automatically:

```css
/* Light mode — default */
.ls-header {
  background-color: var(--ls-header-bg, #ffffff);
}

/* Dark mode — activated by body.dark */
body.dark .ls-header {
  background-color: var(--ls-header-bg-dark, #0e1726);
}
```

### Enabling dark mode

Toggle the `dark` class on `<body>` from your Angular service:

```ts
// theme.service.ts
export class ThemeService {
  setDark(enabled: boolean): void {
    document.body.classList.toggle('dark', enabled);
  }
}
```

### Supporting light, dark, and system preferences

```ts
// theme.service.ts
import { Injectable } from '@angular/core';

type Theme = 'light' | 'dark' | 'system';

@Injectable({ providedIn: 'root' })
export class ThemeService {
  apply(theme: Theme): void {
    if (theme === 'dark') {
      document.body.classList.add('dark');
    } else if (theme === 'light') {
      document.body.classList.remove('dark');
    } else {
      const prefersDark = window.matchMedia(
        '(prefers-color-scheme: dark)'
      ).matches;
      document.body.classList.toggle('dark', prefersDark);
    }
  }

  watchSystem(): void {
    window
      .matchMedia('(prefers-color-scheme: dark)')
      .addEventListener('change', e => {
        document.body.classList.toggle('dark', e.matches);
      });
  }
}
```

### Persisting the user preference

```ts
// On app initialization
const saved = localStorage.getItem('theme') as Theme | null;
this.themeService.apply(saved ?? 'system');
```

### Overriding dark mode tokens

All dark variants are CSS custom properties. Override them after the library import:

```css
body.dark {
  --ls-header-bg-dark: #1a1a2e;
  --ls-sidebar-bg-dark: #16213e;
  --ls-color-primary: #818cf8;
}
```

### Components with dark mode support

| Component             | Dark tokens                                                                                                                                          |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Header                | `--ls-header-bg-dark`, `--ls-header-shadow-dark`                                                                                                     |
| Sidebar               | `--ls-sidebar-bg-dark`, `--ls-sidebar-header-bg-dark`, `--ls-sidebar-icon-color-dark`, `--ls-sidebar-sublink-indicator-color-dark`                   |
| Table                 | `--ls-table-border-color`, `--ls-table-header-bg`, `--ls-table-header-color`, `--ls-table-cell-color`, `--ls-table-stripe-bg`, `--ls-table-hover-bg` |
| Stepper               | `--ls-stepper-connector-color`, `--ls-stepper-bg`, `--ls-stepper-text-color`                                                                         |
| Drag                  | `--ls-drag-ghost-bg`, `--ls-drag-drop-indicator-color`                                                                                               |
| Button (`dark` color) | `--ls-color-dark-dm`                                                                                                                                 |

> All dark token overrides must be placed inside a `body.dark { }` block, after the library stylesheet import.

---

## Peer dependencies by component

Some components require additional packages that are not bundled with the library.

### PhoneInputComponent (`ls-phone-input`)

Requires [`flag-icons`](https://github.com/lipis/flag-icons) for country flag rendering.

```bash
npm install flag-icons
```

Register the stylesheet **once** in `angular.json` under `styles`, before the library stylesheet:

```json
"styles": [
  "node_modules/flag-icons/css/flag-icons.min.css",
  "node_modules/@lumston/ds-angular/styles.css",
  "src/styles.css"
]
```

> `flag-icons` must be loaded before the library stylesheet so flag sprites resolve correctly.

### EditorComponent (`ls-editor`)

Requires TipTap and its extensions for rich text editing.

```bash
npm install @tiptap/core @tiptap/starter-kit
```

No additional stylesheet registration is needed — editor styles are included in the library stylesheet.

### DatePickerComponent / TimePickerComponent / DateTimePickerComponent

Requires [`dayjs`](https://day.js.org/) for date manipulation.

```bash
npm install dayjs
```

---

## Importing styles

Add the library stylesheet in `angular.json` under `styles`:

```json
"styles": [
  "node_modules/@lumston/ds-angular/styles.css",
  "src/styles.css"
]
```

> The stylesheet includes all design tokens (CSS custom properties), base reset rules, and component styles. It must be loaded before your application styles so that overrides work correctly.

---

## Using components

All components are standalone. Import them directly in your Angular component or module:

```ts
import { ButtonComponent } from '@lumston/ds-angular/inputs/button';

@Component({
  standalone: true,
  imports: [ButtonComponent],
  template: `<ls-button variant="filled">Save</ls-button>`,
})
export class MyComponent {}
```

---

## Reactive Forms integration

Form components (`ls-text-field`, `ls-select`) implement Angular's `ControlValueAccessor` interface and integrate with both Reactive Forms and Template-driven Forms.

To use `[formControl]` or `[formControlName]`, you must import `ReactiveFormsModule` alongside the component:

```ts
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { TextFieldComponent } from '@lumston/ds-angular/inputs/text-field';

@Component({
  standalone: true,
  imports: [
    TextFieldComponent,
    ReactiveFormsModule, // required for [formControl] binding
  ],
  template: `
    <ls-text-field
      label="Email"
      type="email"
      [formControl]="emailCtrl"
      helperText="Enter your email address" />
  `,
})
export class LoginPage {
  protected readonly emailCtrl = new FormControl('');
}
```

For Template-driven Forms, import `FormsModule` and use `[(ngModel)]`:

```ts
import { FormsModule } from '@angular/forms';
import { TextFieldComponent } from '@lumston/ds-angular/inputs/text-field';

@Component({
  standalone: true,
  imports: [TextFieldComponent, FormsModule],
  template: `<ls-text-field label="Name" [(ngModel)]="name" />`,
})
export class MyForm {
  protected name = '';
}
```

Both components automatically reflect Angular validation state — `error` styles apply when the control is `invalid` and has been `touched` or `dirty`.

---

## Component catalog

### Inputs

| Component                 | Selector              | Key inputs                                                                                                                                                                                                      |
| ------------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ButtonComponent`         | `ls-button`           | `variant`, `color`, `size`, `disabled`, `loading`, `startIcon`, `endIcon`, `rounded`, `fullWidth`                                                                                                               |
| `IconButtonComponent`     | `ls-icon-button`      | `icon` (required), `ariaLabel` (required), `color`, `size`, `disabled`, `loading`                                                                                                                               |
| `TextFieldComponent`      | `ls-text-field`       | `label`, `type`, `variant`, `size`, `multiline`, `rows`, `maxRows`, `placeholder`, `helperText`, `error`, `disabled`, `readonly`, `fullWidth`, `startIcon`, `endIcon`, `startIconClickable`, `endIconClickable` |
| `SelectComponent`         | `ls-select`           | `options`, `value`, `placeholder`, `label`, `multiple`, `filter`, `autocomplete`, `remote`, `clearable`, `disabled`, `loading`, `size`, `appearance`                                                            |
| `CheckboxComponent`       | `ls-checkbox`         | `icon`, `checkedIcon`, `checked`, `color`, `size`, `disabled`, `indeterminate`, `labelPlacement`                                                                                                                |
| `RadioButtonComponent`    | `ls-radio-button`     | `value`, `color`, `size`, `disabled`, `labelPlacement`                                                                                                                                                          |
| `SwitchComponent`         | `ls-switch`           | `checked`, `color`, `size`, `disabled`, `labelPlacement`                                                                                                                                                        |
| `SliderComponent`         | `ls-slider`           | `value`, `min`, `max`, `step`, `marks`, `color`, `size`, `disabled`, `valueLabelDisplay`                                                                                                                        |
| `NumberInputComponent`    | `ls-number-input`     | `value`, `min`, `max`, `step`, `disabled`, `size`                                                                                                                                                               |
| `DatePickerComponent`     | `ls-date-picker`      | `value`, `min`, `max`, `disabled`, `placeholder`, `selectionMode`                                                                                                                                               |
| `TimePickerComponent`     | `ls-time-picker`      | `value`, `disabled`, `placeholder`                                                                                                                                                                              |
| `DateTimePickerComponent` | `ls-date-time-picker` | `value`, `disabled`, `placeholder`                                                                                                                                                                              |
| `ColorPickerComponent`    | `ls-color-picker`     | `colors`, `value`, `size`                                                                                                                                                                                       |
| `PhoneInputComponent`     | `ls-phone-input`      | `value`, `disabled`, `placeholder`                                                                                                                                                                              |
| `EditorComponent`         | `ls-editor`           | `value`, `tools`, `disabled`, `placeholder`                                                                                                                                                                     |
| `UploadComponent`         | `ls-upload`           | `accept`, `multiple`, `maxSize`, `disabled`                                                                                                                                                                     |

### Typography

| Component              | Selector           | Key inputs                                       |
| ---------------------- | ------------------ | ------------------------------------------------ |
| `TextComponent`        | `ls-text`          | `variant`, `color`, `fontWeight`                 |
| `LinkComponent`        | `ls-link`          | `href`, `variant`, `color`, `underline`, `align` |
| `TagComponent`         | `ls-tag`           | `color`, `variant`, `size`                       |
| `TextMaxLineComponent` | `ls-text-max-line` | `lines`                                          |

### Icons & Media

| Component              | Selector          | Key inputs                                                  |
| ---------------------- | ----------------- | ----------------------------------------------------------- |
| `IconComponent`        | `ls-icon`         | `name` (required), `iconClass`                              |
| `AvatarComponent`      | `ls-avatar`       | `src`, `alt`, `text`, `color`, `size`, `variant`, `tooltip` |
| `AvatarGroupComponent` | `ls-avatar-group` | `max`, `size`                                               |
| `LogoComponent`        | `ls-logo`         | —                                                           |

### Data display

| Component                  | Selector               | Key inputs                                                                           |
| -------------------------- | ---------------------- | ------------------------------------------------------------------------------------ |
| `BadgeComponent`           | `ls-badge`             | `badgeContent`, `max`, `severity`, `variant`, `badgePosition`, `overlap`, `isHidden` |
| `ChipComponent`            | `ls-chip`              | `color`, `variant`, `size`, `deletable`                                              |
| `AccordionComponent`       | `ls-accordion`         | `expanded`, `disabled`                                                               |
| `ListComponent`            | `ls-list`              | —                                                                                    |
| `TableComponent`           | `ls-table`             | `variant`, `size`, `striped`, `hoverable`                                            |
| `DragComponent`            | `ls-drag`              | `items`, `disabled`                                                                  |
| `TransferListComponent`    | `ls-transfer-list`     | `source`, `target`, `disabled`                                                       |
| `TreeViewComponent`        | `ls-tree-view`         | `nodes`, `expandAll`, `disabled`                                                     |
| `CopyToClipboardComponent` | `ls-copy-to-clipboard` | `text`, `successDuration`                                                            |

### Feedback

| Component              | Selector          | Key inputs                                                         |
| ---------------------- | ----------------- | ------------------------------------------------------------------ |
| `AlertComponent`       | `ls-alert`        | `severity`, `variant`, `closable`, `alertTitle`, `message`, `icon` |
| `LoaderComponent`      | `ls-loader`       | `size`, `variant`, `color`                                         |
| `ProgressBarComponent` | `ls-progress-bar` | `value`, `variant`, `color`, `size`                                |

### Overlay

| Component          | Selector     | Key inputs                                                                                         |
| ------------------ | ------------ | -------------------------------------------------------------------------------------------------- |
| `ModalComponent`   | `ls-modal`   | `open`, `maxWidth`, `fullScreen`, `fullWidth`, `scroll`, `disableBackdropClose`, `showCloseButton` |
| `DrawerComponent`  | `ls-drawer`  | `open`, `anchor`, `variant`                                                                        |
| `MenuComponent`    | `ls-menu`    | `open`, `anchorEl`, `anchorOrigin`, `transformOrigin`, `closeOnClick`                              |
| `TooltipComponent` | `ls-tooltip` | `content`, `position`, `disabled`                                                                  |
| `PopoverComponent` | `ls-popover` | `open`, `anchorEl`, `position`                                                                     |

### Navigation

| Component                 | Selector             | Key inputs                                                                   |
| ------------------------- | -------------------- | ---------------------------------------------------------------------------- |
| `BreadcrumbComponent`     | `ls-breadcrumb`      | `items`, `separator`                                                         |
| `PaginationComponent`     | `ls-pagination`      | `page`, `pageSize`, `total`, `color`, `size`                                 |
| `TabComponent`            | `ls-tab`             | `value`, `orientation`, `variant`, `textColor`, `indicatorColor`, `centered` |
| `StepperComponent`        | `ls-stepper`         | `steps`, `activeStep`, `orientation`, `nonLinear`                            |
| `TablePaginatorComponent` | `ls-table-paginator` | `page`, `pageSize`, `total`, `pageSizeOptions`                               |

### Layouts

| Component               | Selector          | Description                                |
| ----------------------- | ----------------- | ------------------------------------------ |
| `LsAuthLayoutComponent` | `ls-auth-layout`  | Full-screen two-panel authentication shell |
| `HeaderComponent`       | `ls-header`       | Top navigation bar with content slots      |
| `SidebarComponent`      | `ls-sidebar`      | Collapsible left navigation panel          |
| `FooterComponent`       | `ls-footer`       | Bottom bar with copyright notice           |
| `ErrorLayoutComponent`  | `ls-error-layout` | Full-page error template                   |

---

## Auth Layout

`ls-auth-layout` renders a full-screen two-panel shell: a decorative left panel (gradient, logo, illustration) and a right content area for projected form content.

```html
<ls-auth-layout
  logoSrc="/assets/images/logo.png"
  illustrationSrc="/assets/images/auth/login.svg"
  bgImage="/assets/images/auth/bg-login.png"
  overlayColor="rgba(67, 97, 238, 0.35)">
  <form>...</form>
</ls-auth-layout>
```

| Input             | Type     | Default               | Description                                                                                                           |
| ----------------- | -------- | --------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `bgImage`         | `string` | `''`                  | Background image URL for the full-screen overlay layer. When empty, only the gradient is shown.                       |
| `illustrationAlt` | `string` | `'Auth illustration'` | Alt text for the illustration image.                                                                                  |
| `illustrationSrc` | `string` | `''`                  | Illustration image displayed on the left panel.                                                                       |
| `logoAlt`         | `string` | `'Logo'`              | Alt text for the logo image.                                                                                          |
| `logoSrc`         | `string` | `''`                  | Logo image displayed on the left panel.                                                                               |
| `overlayColor`    | `string` | `''`                  | CSS color blended on top of `bgImage`. Defaults to `rgba(67, 97, 238, 0.35)`.                                         |
| `skewEdgeColor`   | `string` | `''`                  | CSS color for the decorative gradient fade on the right edge of the left panel. Defaults to `rgba(67, 97, 238, 0.1)`. |

All color inputs accept any valid CSS color value (hex, rgba, hsl). The left panel gradient colors are controlled via CSS tokens:

```css
ls-auth-layout {
  --ls-auth-gradient-start: #7c3aed;
  --ls-auth-gradient-end: #2563eb;
}
```

---

## i18n

The library peer-depends on [`@ngx-translate/core`](https://github.com/ngx-translate/core) for internationalization. Install it alongside the library:

```bash
npm install @ngx-translate/core @ngx-translate/http-loader
```

Configure the translate module in your application bootstrap:

```ts
import { provideHttpClient } from '@angular/common/http';
import { ApplicationConfig } from '@angular/core';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { HttpClient } from '@angular/common/http';

export function createTranslateLoader(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(),
    importProvidersFrom(
      TranslateModule.forRoot({
        loader: {
          provide: TranslateLoader,
          useFactory: createTranslateLoader,
          deps: [HttpClient],
        },
        defaultLanguage: 'en',
      })
    ),
  ],
};
```

---

## Overriding design tokens

The library exposes its entire palette and configuration as CSS custom properties on `:root`. You can override any token by redefining it **after** the library import in your global stylesheet.

### Override globally

```css
/* styles.css */

:root {
  /* Brand colors */
  --ls-color-primary: #ff6b35;
  --ls-color-primary-light: #fff0eb;
  --ls-color-primary-dark-light: rgba(255, 107, 53, 0.15);

  /* Typography */
  --ls-font-family: 'Inter', sans-serif;

  /* Border radius */
  --ls-border-radius-md: 0.25rem;
  --ls-border-radius-lg: 0.5rem;
  --ls-border-radius-full: 9999px;
}
```

### Override per theme (scoped)

You can scope overrides to a CSS class to support multiple themes simultaneously:

```css
.theme-corporate {
  --ls-color-primary: #1a3c6e;
  --ls-color-primary-light: #e8eef7;
  --ls-color-primary-dark-light: rgba(26, 60, 110, 0.15);
}

.theme-dark {
  --ls-color-primary: #818cf8;
  --ls-color-primary-light: #1e1b4b;
  --ls-color-primary-dark-light: rgba(129, 140, 248, 0.15);
}
```

Apply the class to a wrapper element in your template:

```html
<div class="theme-corporate">
  <ls-button variant="filled">Submit</ls-button>
</div>
```

### Available tokens

#### Colors

| Token                             | Default                | Description                                                              |
| --------------------------------- | ---------------------- | ------------------------------------------------------------------------ |
| `--ls-color-primary`              | `#4361ee`              | Primary brand color                                                      |
| `--ls-color-primary-light`        | `#eaf1ff`              | Primary tint background                                                  |
| `--ls-color-primary-dark-light`   | `rgba(67,97,238,.15)`  | Primary overlay                                                          |
| `--ls-color-secondary`            | `#805dca`              | Secondary brand color                                                    |
| `--ls-color-secondary-light`      | `#ebe4f7`              | Secondary tint background                                                |
| `--ls-color-secondary-dark-light` | `rgba(128,93,202,.15)` | Secondary overlay                                                        |
| `--ls-color-success`              | `#00ab55`              | Success state                                                            |
| `--ls-color-success-light`        | `#ddf5f0`              | Success tint background                                                  |
| `--ls-color-success-dark-light`   | `rgba(0,171,85,.15)`   | Success overlay                                                          |
| `--ls-color-danger`               | `#e7515a`              | Danger / destructive state                                               |
| `--ls-color-danger-light`         | `#fff5f5`              | Danger tint background                                                   |
| `--ls-color-danger-dark-light`    | `rgba(231,81,90,.15)`  | Danger overlay                                                           |
| `--ls-color-error`                | `#e7515a`              | Error state (alias of danger)                                            |
| `--ls-color-error-light`          | `#fff5f5`              | Error tint background                                                    |
| `--ls-color-error-dark-light`     | `rgba(231,81,90,.15)`  | Error overlay                                                            |
| `--ls-color-warning`              | `#e2a03f`              | Warning state                                                            |
| `--ls-color-warning-light`        | `#fff9ed`              | Warning tint background                                                  |
| `--ls-color-warning-dark-light`   | `rgba(226,160,63,.15)` | Warning overlay                                                          |
| `--ls-color-info`                 | `#2196f3`              | Informational state                                                      |
| `--ls-color-info-light`           | `#e7f7ff`              | Info tint background                                                     |
| `--ls-color-info-dark-light`      | `rgba(33,150,243,.15)` | Info overlay                                                             |
| `--ls-color-dark`                 | `#3b3f5c`              | Dark neutral                                                             |
| `--ls-color-dark-dm`              | `#8892a4`              | Dark neutral adapted for dark mode (higher contrast on dark backgrounds) |
| `--ls-color-dark-light`           | `#eaeaec`              | Dark tint background                                                     |
| `--ls-color-dark-dark-light`      | `rgba(59,63,92,.15)`   | Dark overlay                                                             |
| `--ls-color-black`                | `#0e1726`              | Near-black                                                               |
| `--ls-color-black-light`          | `#e3e4eb`              | Near-black tint                                                          |
| `--ls-color-black-dark-light`     | `rgba(14,23,38,.15)`   | Near-black overlay                                                       |
| `--ls-color-white`                | `#ffffff`              | White                                                                    |
| `--ls-color-white-light`          | `#e0e6ed`              | White variant                                                            |
| `--ls-color-white-dark`           | `#888ea8`              | White muted                                                              |
| `--ls-gradient-start`             | `#ef1262`              | Gradient start color                                                     |
| `--ls-gradient-end`               | `#4361ee`              | Gradient end color                                                       |

#### Typography

| Token              | Default                | Description      |
| ------------------ | ---------------------- | ---------------- |
| `--ls-font-family` | `'Nunito', sans-serif` | Base font family |

#### Transitions

| Token                                | Default | Description                        |
| ------------------------------------ | ------- | ---------------------------------- |
| `--ls-transition-duration`           | `300ms` | Default transition duration        |
| `--ls-transition-accordion-duration` | `400ms` | Accordion expand/collapse duration |

#### Border radius

| Token                     | Default    | Description               |
| ------------------------- | ---------- | ------------------------- |
| `--ls-border-radius-md`   | `0.375rem` | Medium border radius      |
| `--ls-border-radius-lg`   | `0.5rem`   | Large border radius       |
| `--ls-border-radius-full` | `9999px`   | Pill / full border radius |

#### Inputs

| Token                         | Default   | Description              |
| ----------------------------- | --------- | ------------------------ |
| `--ls-color-input-border`     | `#d0d2d6` | Input border color       |
| `--ls-color-input-label`      | `#3b3f5c` | Input label color        |
| `--ls-color-input-bg-filled`  | `#f4f4f4` | Filled input background  |
| `--ls-color-helper-text`      | `#888ea8` | Helper / hint text color |
| `--ls-color-text-placeholder` | `#adb5bd` | Placeholder text color   |

#### Header

| Token                     | Default                       | Description                       |
| ------------------------- | ----------------------------- | --------------------------------- |
| `--ls-header-height`      | `56px`                        | Minimum height of the header      |
| `--ls-header-z-index`     | `40`                          | Stack order of the header         |
| `--ls-header-padding-x`   | `1.25rem`                     | Horizontal padding                |
| `--ls-header-bg`          | `#ffffff`                     | Background color (light mode)     |
| `--ls-header-bg-dark`     | `#0e1726`                     | Background color (dark mode)      |
| `--ls-header-shadow`      | `0 1px 3px 0 rgba(0,0,0,.08)` | Box shadow (light mode)           |
| `--ls-header-shadow-dark` | `0 1px 3px 0 rgba(0,0,0,.3)`  | Box shadow (dark mode)            |
| `--ls-header-gap`         | `0.375rem`                    | Gap between header end slot items |

#### Sidebar

| Token                                       | Default                | Description                               |
| ------------------------------------------- | ---------------------- | ----------------------------------------- |
| `--ls-sidebar-width`                        | `260px`                | Sidebar width                             |
| `--ls-sidebar-bg`                           | `#ffffff`              | Background color (light mode)             |
| `--ls-sidebar-bg-dark`                      | `#0e1726`              | Background color (dark mode)              |
| `--ls-sidebar-z-index`                      | `50`                   | Stack order of the sidebar                |
| `--ls-sidebar-item-color`                   | `#506690`              | Nav item text color                       |
| `--ls-sidebar-item-active-color`            | `#4361ee`              | Active nav item text color                |
| `--ls-sidebar-item-active-bg`               | `rgba(67,97,238,.12)`  | Active nav item background                |
| `--ls-sidebar-item-hover-color`             | `#4361ee`              | Nav item text color on hover              |
| `--ls-sidebar-item-hover-bg`                | `rgba(0,0,0,.05)`      | Nav item background on hover              |
| `--ls-sidebar-icon-color`                   | `#506690`              | Icon color                                |
| `--ls-sidebar-icon-color-dark`              | `#506690`              | Icon color (dark mode)                    |
| `--ls-sidebar-header-bg`                    | `rgba(255,255,255,.3)` | Section header background                 |
| `--ls-sidebar-header-bg-dark`               | `rgba(0,0,0,.08)`      | Section header background (dark mode)     |
| `--ls-sidebar-header-color`                 | `#888ea8`              | Section header text color                 |
| `--ls-sidebar-sublink-indicator-color`      | `#bfc9d4`              | Sub-item connector line color             |
| `--ls-sidebar-sublink-indicator-color-dark` | `#3b3f5c`              | Sub-item connector line color (dark mode) |
| `--ls-sidebar-head-padding`                 | `0.75rem 1rem`         | Sidebar head area padding                 |
| `--ls-sidebar-head-height`                  | `4rem`                 | Sidebar head area height                  |
| `--ls-sidebar-close-color`                  | `#506690`              | Close button icon color                   |
| `--ls-sidebar-close-hover-bg`               | `rgba(0,0,0,.05)`      | Close button background on hover          |
| `--ls-sidebar-close-hover-color`            | `#4361ee`              | Close button icon color on hover          |

#### Modal

| Token                    | Default          | Description          |
| ------------------------ | ---------------- | -------------------- |
| `--ls-modal-z-index`     | `1000`           | Modal z-index        |
| `--ls-modal-backdrop-bg` | `rgba(0,0,0,.5)` | Modal backdrop color |

#### Drawer

| Token                     | Default          | Description                |
| ------------------------- | ---------------- | -------------------------- |
| `--ls-drawer-z-index`     | `1200`           | Drawer z-index             |
| `--ls-drawer-backdrop-bg` | `rgba(0,0,0,.5)` | Drawer backdrop color      |
| `--ls-drawer-width`       | `320px`          | Drawer width (left/right)  |
| `--ls-drawer-height`      | `280px`          | Drawer height (top/bottom) |

#### Menu

| Token               | Default | Description           |
| ------------------- | ------- | --------------------- |
| `--ls-menu-z-index` | `1001`  | Dropdown menu z-index |

#### Select

| Token                      | Default   | Description                |
| -------------------------- | --------- | -------------------------- |
| `--ls-select-bg`           | `#ffffff` | Select panel background    |
| `--ls-select-border`       | `#e0e6ed` | Select panel border color  |
| `--ls-select-option-hover` | `#f1f2f3` | Option background on hover |

#### Tab

| Token                   | Default                       | Description                  |
| ----------------------- | ----------------------------- | ---------------------------- |
| `--ls-tab-border-color` | `var(--ls-color-white-light)` | Tab underline / border color |

#### Table

| Token                     | Default                | Description             |
| ------------------------- | ---------------------- | ----------------------- |
| `--ls-table-border-color` | `rgba(224,230,237,.4)` | Table border color      |
| `--ls-table-header-bg`    | `#f6f8fa`              | Table header background |
| `--ls-table-header-color` | `#3b3f5c`              | Table header text color |
| `--ls-table-cell-color`   | `#515365`              | Table cell text color   |
| `--ls-table-stripe-bg`    | `rgba(224,230,237,.2)` | Striped row background  |
| `--ls-table-hover-bg`     | `rgba(224,230,237,.2)` | Row background on hover |

#### Date picker

| Token                         | Default   | Description                     |
| ----------------------------- | --------- | ------------------------------- |
| `--ls-color-dp-selected-bg`   | `#4361ee` | Selected date background        |
| `--ls-color-dp-range-bg`      | `#eaf1ff` | Date range highlight background |
| `--ls-color-dp-cell-hover-bg` | `#f0f4ff` | Date cell background on hover   |
| `--ls-color-dp-disabled-text` | `#888ea8` | Disabled date text color        |

#### Stepper

| Token                              | Default                         | Description                    |
| ---------------------------------- | ------------------------------- | ------------------------------ |
| `--ls-stepper-connector-color`     | `#e0e6ed`                       | Connector line color           |
| `--ls-stepper-active-color`        | `var(--ls-color-primary)`       | Active step indicator color    |
| `--ls-stepper-complete-color`      | `var(--ls-color-primary)`       | Completed step indicator color |
| `--ls-stepper-error-color`         | `var(--ls-color-danger)`        | Error step indicator color     |
| `--ls-stepper-disabled-opacity`    | `0.5`                           | Opacity for disabled steps     |
| `--ls-stepper-bg`                  | `#ffffff`                       | Step indicator background      |
| `--ls-stepper-text-color`          | `#3b3f5c`                       | Step label text color          |
| `--ls-stepper-icon-size`           | `2rem`                          | Step indicator icon size       |
| `--ls-stepper-transition-duration` | `var(--ls-transition-duration)` | Step transition duration       |

#### Color picker

| Token                    | Default | Description                |
| ------------------------ | ------- | -------------------------- |
| `--ls-cp-gap`            | `8px`   | Gap between color swatches |
| `--ls-cp-swatch-size`    | `28px`  | Swatch size (default)      |
| `--ls-cp-swatch-size-sm` | `20px`  | Swatch size (small)        |

#### Drag

| Token                             | Default                   | Description                       |
| --------------------------------- | ------------------------- | --------------------------------- |
| `--ls-drag-drop-indicator-color`  | `var(--ls-color-primary)` | Drop zone indicator color         |
| `--ls-drag-disabled-opacity`      | `0.5`                     | Opacity when drag is disabled     |
| `--ls-drag-item-dragging-opacity` | `0.4`                     | Opacity of the item being dragged |
| `--ls-drag-ghost-bg`              | `#ffffff`                 | Drag ghost element background     |

#### Map

| Token                       | Default                      | Description                 |
| --------------------------- | ---------------------------- | --------------------------- |
| `--ls-map-border-radius`    | `var(--ls-border-radius-md)` | Map container border radius |
| `--ls-map-disabled-opacity` | `0.6`                        | Map opacity when disabled   |