diff --git a/.mcp.json b/.mcp.json index d6be026e2..cd7d1baa3 100644 --- a/.mcp.json +++ b/.mcp.json @@ -17,13 +17,6 @@ "figma-desktop": { "type": "http", "url": "http://127.0.0.1:3845/mcp" - }, - "memory": { - "command": "npx", - "args": ["-y", "@modelcontextprotocol/server-memory"], - "env": { - "MEMORY_FILE_PATH": "~/Projects/ISA-Frontend/memory.json" - } } } } diff --git a/CLAUDE.md b/CLAUDE.md index 3811c02b3..ab54ae6d0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,10 +8,6 @@ This file contains meta-instructions for how Claude should work with the ISA-Fro - **`docs-researcher`**: For ALL documentation (packages, libraries, READMEs) - **`docs-researcher-advanced`**: Auto-escalate when docs-researcher fails - **`Explore`**: For ALL code pattern searches and multi-file analysis -- **`context-manager`**: For complex projects and knowledge preservation with **persistent memory** -- **Direct tools (Read/Bash)**: ONLY for single specific files or commands - -**NEW**: The `context-manager` now autonomously stores project knowledge (decisions, patterns, solutions) in persistent memory for cross-session learning. **Violations of this rule degrade performance and context quality. NO EXCEPTIONS.** @@ -26,7 +22,7 @@ This file contains meta-instructions for how Claude should work with the ISA-Fro ## Researching and Investigating the Codebase -**🔴 MANDATORY: You MUST use subagents for research. Direct file reading/searching is FORBIDDEN except for single specific files.** +**🔴 MANDATORY: You MUST use subagents for research. Direct file reading/searching.** ### Required Agent Usage @@ -61,36 +57,3 @@ This file contains meta-instructions for how Claude should work with the ISA-Fro ``` **Remember: Using subagents is NOT optional - it's mandatory for maintaining context efficiency and search quality.** - -## Project Knowledge Management with Context-Manager - -**NEW CAPABILITY**: The `context-manager` subagent has **persistent memory** that autonomously stores and retrieves project knowledge across sessions. - -### What Gets Stored Automatically - -- **Assigned Tasks**: User-assigned tasks with context ("Remember to look up X because of Y"), TODO items, status tracking -- **Architectural Decisions**: State management patterns, API integration approaches, component architecture choices -- **Reusable Patterns**: Code conventions, testing patterns, error handling approaches -- **Integration Points**: API contracts, data flows, module boundaries -- **Domain Knowledge**: Business workflows, business rules, user roles/permissions -- **Technical Solutions**: Bug fixes with root causes, performance optimizations - -### When to Use Context-Manager - -Use the `context-manager` subagent PROACTIVELY for: -- **Task Management**: Assigning tasks for later ("Remember to investigate X because of Y") -- **Session Continuity**: Starting a new session (it will remind you of pending tasks) -- Complex, multi-step projects requiring coordination -- Long-running tasks that span multiple sessions -- Preserving architectural context -- Learning about resolved issues and their solutions - -### How It Works - -1. **Task Capture**: Listens for "Remember to...", "TODO:", "Don't forget...", stores them with full context -2. **Automatic Storage**: Proactively stores important discoveries in persistent memory -3. **Knowledge Retrieval**: Queries stored knowledge before starting new work -4. **Task Reminders**: Proactively reminds you of pending/incomplete tasks at session start -5. **Cross-Session Persistence**: Information persists across Claude Code sessions - -**Benefits**: Eliminates context loss, maintains project knowledge, provides task continuity across sessions. diff --git a/apps/isa-app/src/tailwind.scss b/apps/isa-app/src/tailwind.scss index 3f9e7f9b9..8974eaecc 100644 --- a/apps/isa-app/src/tailwind.scss +++ b/apps/isa-app/src/tailwind.scss @@ -20,6 +20,7 @@ @import "../../../libs/ui/skeleton-loader/src/skeleton-loader.scss"; @import "../../../libs/ui/tooltip/src/tooltip.scss"; @import "../../../libs/ui/label/src/label.scss"; + @import "../../../libs/ui/switch/src/switch.scss"; .input-control { @apply rounded border border-solid border-[#AEB7C1] px-4 py-[1.125rem] outline-none; diff --git a/apps/isa-app/stories/ui/switch/ui-icon-switch.stories.ts b/apps/isa-app/stories/ui/switch/ui-icon-switch.stories.ts new file mode 100644 index 000000000..8a39598c8 --- /dev/null +++ b/apps/isa-app/stories/ui/switch/ui-icon-switch.stories.ts @@ -0,0 +1,104 @@ +import { argsToTemplate, type Meta, type StoryObj } from '@storybook/angular'; +import { IconSwitchComponent, IconSwitchColor } from '@isa/ui/switch'; +import { provideIcons } from '@ng-icons/core'; +import { isaFiliale, IsaIcons, isaNavigationDashboard } from '@isa/icons'; + +type IconSwitchComponentInputs = { + icon: string; + checked: boolean; + color: IconSwitchColor; + disabled: boolean; +}; + +const meta: Meta = { + component: IconSwitchComponent, + title: 'ui/switch/IconSwitch', + decorators: [ + (story) => ({ + ...story(), + applicationConfig: { + providers: [provideIcons(IsaIcons)], + }, + }), + ], + argTypes: { + icon: { + control: { type: 'select' }, + options: Object.keys(IsaIcons), + description: 'The name of the icon to display in the switch', + }, + checked: { + control: 'boolean', + description: 'Whether the switch is checked (on) or not (off)', + }, + color: { + control: { type: 'select' }, + options: Object.values(IconSwitchColor), + description: 'Determines the switch color theme', + }, + disabled: { + control: 'boolean', + description: 'Disables the switch when true', + }, + }, + args: { + icon: 'isaFiliale', + checked: false, + color: 'primary', + disabled: false, + }, + render: (args) => ({ + props: args, + template: ``, + }), +}; +export default meta; + +type Story = StoryObj; + +export const Default: Story = { + args: {}, +}; + +export const Enabled: Story = { + args: { + checked: true, + }, + parameters: { + docs: { + description: { + story: + 'The switch in its enabled/checked state with the primary color theme.', + }, + }, + }, +}; + +export const Disabled: Story = { + args: { + checked: false, + disabled: true, + }, + parameters: { + docs: { + description: { + story: + 'The switch in a disabled state. User interactions are prevented.', + }, + }, + }, +}; + +export const EnabledAndDisabled: Story = { + args: { + checked: true, + disabled: true, + }, + parameters: { + docs: { + description: { + story: 'The switch in both enabled and disabled states simultaneously.', + }, + }, + }, +}; diff --git a/libs/checkout/feature/reward-catalog/src/lib/reward-catalog.component.html b/libs/checkout/feature/reward-catalog/src/lib/reward-catalog.component.html index 204c6106d..56b999359 100644 --- a/libs/checkout/feature/reward-catalog/src/lib/reward-catalog.component.html +++ b/libs/checkout/feature/reward-catalog/src/lib/reward-catalog.component.html @@ -1,5 +1,8 @@ - + { + const stockInput = this.#filterService + .inputs() + ?.filter((input) => input.target === 'filter') + ?.find((input) => input.key === 'stock') as FilterInput | undefined; + return stockInput + ? [ + { + filter: stockInput, + icon: 'isaFiliale', + }, + ] + : []; + }); + search(trigger: SearchTrigger): void { this.searchTrigger.set(trigger); // Ist entweder 'scan', 'input', 'filter' oder 'orderBy' this.#filterService.commit(); diff --git a/libs/shared/filter/src/index.ts b/libs/shared/filter/src/index.ts index 7db31a961..44ef3c99c 100644 --- a/libs/shared/filter/src/index.ts +++ b/libs/shared/filter/src/index.ts @@ -5,5 +5,6 @@ export * from './lib/types'; export * from './lib/actions'; export * from './lib/menus/filter-menu'; export * from './lib/menus/input-menu'; +export * from './lib/menus/switch-menu'; export * from './lib/order-by'; export * from './lib/controls-panel'; diff --git a/libs/shared/filter/src/lib/actions/filter-actions.component.spec.ts b/libs/shared/filter/src/lib/actions/filter-actions.component.spec.ts index 4e62d958c..844aeaa1f 100644 --- a/libs/shared/filter/src/lib/actions/filter-actions.component.spec.ts +++ b/libs/shared/filter/src/lib/actions/filter-actions.component.spec.ts @@ -13,8 +13,8 @@ describe('FilterActionsComponent', () => { providers: [ mockProvider(FilterService, { inputs: jest.fn().mockReturnValue([ - { group: 'filter', key: 'key1' }, - { group: 'other', key: 'key2' }, + { target: 'filter', key: 'key1', group: 'filter' }, + { target: 'input', key: 'key2', group: 'other' }, ]), commit: jest.fn(), reset: jest.fn(), @@ -31,9 +31,11 @@ describe('FilterActionsComponent', () => { expect(spectator.component).toBeTruthy(); }); - it('should filter inputs by group "filter"', () => { + it('should filter inputs by target "filter"', () => { const filteredInputs = spectator.component.filterInputs(); - expect(filteredInputs).toEqual([{ group: 'filter', key: 'key1' }]); + expect(filteredInputs).toEqual([ + { target: 'filter', key: 'key1', group: 'filter' }, + ]); }); it('should call commit and emit applied when onApply is called without inputKey', () => { diff --git a/libs/shared/filter/src/lib/actions/filter-actions.component.ts b/libs/shared/filter/src/lib/actions/filter-actions.component.ts index 41f7c3570..ce60eff8b 100644 --- a/libs/shared/filter/src/lib/actions/filter-actions.component.ts +++ b/libs/shared/filter/src/lib/actions/filter-actions.component.ts @@ -54,10 +54,10 @@ export class FilterActionsComponent { canApply = input(true); /** - * Computed signal that filters inputs to only include those with 'filter' group + * Computed signal that filters inputs to only include those with target 'filter' */ filterInputs = computed(() => - this.filterService.inputs().filter((input) => input.group === 'filter'), + this.filterService.inputs().filter((input) => input.target === 'filter'), ); /** @@ -85,7 +85,7 @@ export class FilterActionsComponent { * Resets filter values to their defaults * * If inputKey is provided, only that specific filter input is reset. - * Otherwise, all filter inputs in the 'filter' group are reset. + * Otherwise, all filter inputs with target 'filter' are reset. * After resetting, all changes are committed. */ onReset() { diff --git a/libs/shared/filter/src/lib/controls-panel/controls-panel.component.html b/libs/shared/filter/src/lib/controls-panel/controls-panel.component.html index 239245271..a3cf1402c 100644 --- a/libs/shared/filter/src/lib/controls-panel/controls-panel.component.html +++ b/libs/shared/filter/src/lib/controls-panel/controls-panel.component.html @@ -13,6 +13,14 @@ }
+ @for (switchFilter of switchFilters(); track switchFilter.filter.key) { + + } + @if (hasFilter()) { >([]); + /** * Output event that emits when any search action is triggered. * Provides the specific SearchTrigger type to indicate how the search was initiated: diff --git a/libs/shared/filter/src/lib/core/filter.service.ts b/libs/shared/filter/src/lib/core/filter.service.ts index 87256bfc1..d606e47bd 100644 --- a/libs/shared/filter/src/lib/core/filter.service.ts +++ b/libs/shared/filter/src/lib/core/filter.service.ts @@ -526,6 +526,10 @@ export class FilterService { return !input.start && !input.stop; } + if (input.type === InputType.NumberRange) { + return input.min == null && input.max == null; + } + this.#logger.warn(`Input type not supported`, () => ({ input, method: 'isEmptyFilter', @@ -540,6 +544,7 @@ export class FilterService { * For text inputs, checks if the value is falsy. * For checkbox inputs, checks if the selected array is empty. * For date range inputs, checks if both start and stop are falsy. + * For number range inputs, checks if both min and max are null or undefined. * * @param filterInput - The filter input to check * @returns True if the filter input is empty, false otherwise @@ -569,6 +574,10 @@ export class FilterService { return !currentInputState.start && !currentInputState.stop; } + if (currentInputState.type === InputType.NumberRange) { + return currentInputState.min == null && currentInputState.max == null; + } + this.logUnsupportedInputType(currentInputState, 'isEmptyFilterInput'); return true; } diff --git a/libs/shared/filter/src/lib/inputs/checkbox-input/checkbox-input.component.spec.ts b/libs/shared/filter/src/lib/inputs/checkbox-input/checkbox-input.component.spec.ts index 5b5723c5e..b91628adf 100644 --- a/libs/shared/filter/src/lib/inputs/checkbox-input/checkbox-input.component.spec.ts +++ b/libs/shared/filter/src/lib/inputs/checkbox-input/checkbox-input.component.spec.ts @@ -29,6 +29,7 @@ describe('CheckboxInputComponent', () => { group: 'group', key: 'key', type: InputType.Checkbox, + target: 'filter' as const, options: [option], selected: [], label: 'label', @@ -60,6 +61,7 @@ describe('CheckboxInputComponent', () => { group: 'group', key: 'key', type: InputType.Checkbox, + target: 'filter' as const, options: [option], selected: [], label: 'label', @@ -102,6 +104,7 @@ describe('CheckboxInputComponent', () => { group: 'group', key: 'key', type: InputType.Checkbox, + target: 'filter' as const, options: [option], selected: ['opt'], label: 'label', diff --git a/libs/shared/filter/src/lib/menus/switch-menu/index.ts b/libs/shared/filter/src/lib/menus/switch-menu/index.ts new file mode 100644 index 000000000..f70944985 --- /dev/null +++ b/libs/shared/filter/src/lib/menus/switch-menu/index.ts @@ -0,0 +1 @@ +export * from './switch-menu-button.component'; diff --git a/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.html b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.html new file mode 100644 index 000000000..8a8b69243 --- /dev/null +++ b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.html @@ -0,0 +1,8 @@ +@let inp = input(); +@if (inp) { + +} diff --git a/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.scss b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.scss new file mode 100644 index 000000000..e393ae83f --- /dev/null +++ b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.scss @@ -0,0 +1,3 @@ +.filter-switch-menu-button { + @apply flex; +} diff --git a/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.spec.ts b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.spec.ts new file mode 100644 index 000000000..5408675f9 --- /dev/null +++ b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.spec.ts @@ -0,0 +1,117 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SwitchMenuButtonComponent } from './switch-menu-button.component'; +import { FilterService } from '../../core'; +import { InputType } from '../../types'; +import { signal } from '@angular/core'; + +describe('SwitchMenuButtonComponent', () => { + let component: SwitchMenuButtonComponent; + let fixture: ComponentFixture; + let mockFilterService: jest.Mocked>; + + beforeEach(async () => { + mockFilterService = { + inputs: signal([ + { + type: InputType.Checkbox, + key: 'test-switch', + label: 'Test Switch', + group: 'test-group', + target: 'filter' as const, + options: [{ key: 'option1', label: 'Option 1' }], + selected: [], + }, + ]), + isDefaultFilterInput: jest.fn().mockReturnValue(true), + setInputCheckboxOptionSelected: jest.fn(), + } as any; + + await TestBed.configureTestingModule({ + imports: [SwitchMenuButtonComponent], + providers: [{ provide: FilterService, useValue: mockFilterService }], + }).compileComponents(); + + fixture = TestBed.createComponent(SwitchMenuButtonComponent); + component = fixture.componentInstance; + fixture.componentRef.setInput('filterInput', { + type: InputType.Checkbox, + key: 'test-switch', + label: 'Test Switch', + group: 'test-group', + target: 'filter' as const, + options: [{ key: 'option1', label: 'Option 1' }], + selected: [], + }); + fixture.componentRef.setInput('icon', 'isaActionCheck'); + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should retrieve the correct checkbox input', () => { + const input = component.input(); + expect(input).toBeDefined(); + expect(input.key).toBe('test-switch'); + }); + + it('should return false for checked when no options are selected', () => { + expect(component.checked()).toBe(false); + }); + + it('should return true for checked when options are selected', () => { + fixture.componentRef.setInput('filterInput', { + type: InputType.Checkbox, + key: 'test-switch', + label: 'Test Switch', + group: 'test-group', + target: 'filter' as const, + options: [{ key: 'option1', label: 'Option 1' }], + selected: [{ key: 'option1', label: 'Option 1' }], + }); + + mockFilterService.inputs = signal([ + { + type: InputType.Checkbox, + key: 'test-switch', + label: 'Test Switch', + group: 'test-group', + target: 'filter' as const, + options: [{ key: 'option1', label: 'Option 1' }], + selected: [{ key: 'option1', label: 'Option 1' }], + }, + ]) as any; + fixture.detectChanges(); + + expect(component.checked()).toBe(true); + }); + + it('should call setInputCheckboxOptionSelected when toggled', () => { + component.onToggle(true); + + expect( + mockFilterService.setInputCheckboxOptionSelected, + ).toHaveBeenCalledWith({ key: 'option1', label: 'Option 1' }, true, { + commit: true, + }); + }); + + it('should retrieve the first option', () => { + const option = component.option(); + expect(option).toEqual({ key: 'option1', label: 'Option 1' }); + }); + + it('should emit toggled event when onToggle is called', () => { + const spy = jest.fn(); + component.toggled.subscribe(spy); + + component.onToggle(true); + + expect(spy).toHaveBeenCalled(); + }); + + it('should check if input is in default state', () => { + expect(component.isDefaultInputState()).toBe(true); + }); +}); diff --git a/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.ts b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.ts new file mode 100644 index 000000000..8594288aa --- /dev/null +++ b/libs/shared/filter/src/lib/menus/switch-menu/switch-menu-button.component.ts @@ -0,0 +1,120 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + inject, + input, + output, + ViewEncapsulation, +} from '@angular/core'; +import { CheckboxFilterInput, FilterInput, FilterService } from '../../core'; +import { InputType } from '../../types'; +import { SwitchComponent } from '@isa/ui/switch'; + +/** + * A switch button component for filtering that displays as a toggle switch. + * Unlike the input-menu-button, this component renders directly without an overlay menu. + * It's designed for simple boolean/single-option filters where a compact toggle is preferred. + * + * Features: + * - Direct toggle interaction (no menu) + * - Auto-commits on toggle + * - Compact visual footprint + * - Uses checkbox filter model internally + * + * @example + * ```html + * + * + * ``` + */ +@Component({ + selector: 'filter-switch-menu-button', + templateUrl: './switch-menu-button.component.html', + styleUrls: ['./switch-menu-button.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [SwitchComponent], + host: { + '[class]': "['filter-switch-menu-button']", + }, +}) +export class SwitchMenuButtonComponent { + /** Filter service for managing filter state */ + #filter = inject(FilterService); + + /** + * The filter input configuration used to render the switch. + */ + filterInput = input.required(); + + /** + * The icon name to display in the switch. + */ + icon = input.required(); + + /** + * Emits an event when the switch is toggled. + */ + toggled = output(); + + /** + * Computed property that retrieves the checkbox filter input from FilterService. + * This component uses the checkbox model internally while rendering as a switch. + */ + input = computed(() => { + const filterInput = this.filterInput(); + const inputs = this.#filter.inputs(); + return inputs.find( + (input) => + input.key === filterInput.key && input.type === InputType.Checkbox, + ) as CheckboxFilterInput; + }); + + /** + * Computed property that determines if the switch is checked. + * For switch inputs, we consider it checked if there's at least one selected option. + * Typically used with single-option checkbox filters. + */ + checked = computed(() => { + const input = this.input(); + return input?.selected && input.selected.length > 0; + }); + + /** + * Computed property that gets the first option from the checkbox input. + * Switch inputs typically work with single-option checkbox configurations. + */ + option = computed(() => { + const input = this.input(); + return input?.options?.[0]; + }); + + /** + * Determines whether the current input state is the default state. + */ + isDefaultInputState = computed(() => { + const input = this.filterInput(); + return this.#filter.isDefaultFilterInput(input); + }); + + /** + * Handles the switch toggle event. + * When toggled, selects or deselects the first option in the checkbox filter. + * + * @param checked - The new checked state + */ + onToggle(checked: boolean): void { + const option = this.option(); + if (option) { + this.#filter.setInputCheckboxOptionSelected(option, checked, { + commit: true, + }); + } + this.toggled.emit(); + } +} diff --git a/libs/ui/switch/README.md b/libs/ui/switch/README.md new file mode 100644 index 000000000..841bfe23c --- /dev/null +++ b/libs/ui/switch/README.md @@ -0,0 +1,185 @@ +# UI Switch Library + +This library provides a toggle switch component with an icon for Angular applications. + +## Components + +### IconSwitchComponent + +A toggle switch component that displays an icon and supports two states (on/off). + +**Important**: Use only when the icon meaning is universally clear, otherwise prefer a labeled switch. + +#### Features + +- ✅ Customizable icon via `ng-icons` +- ✅ Two-way binding with model signal +- ✅ Hover state styling +- ✅ Disabled state handling +- ✅ Keyboard navigation support (Enter, Space) +- ✅ Fully accessible with ARIA attributes +- ✅ Smooth animations + +#### Usage + +```typescript +import { Component } from '@angular/core'; +import { IconSwitchComponent } from '@isa/ui/switch'; +import { provideIcons } from '@ng-icons/core'; +import { isaNavigationDashboard } from '@isa/icons'; + +@Component({ + selector: 'app-example', + standalone: true, + imports: [IconSwitchComponent], + providers: [provideIcons({ isaNavigationDashboard })], + template: ` + + + `, +}) +export class ExampleComponent { + isEnabled = false; +} +``` + +#### Inputs + +| Property | Type | Default | Description | +| ---------- | ---------------- | ----------- | ---------------------------------------------------- | +| `icon` | `string` | (required) | The name of the icon to display | +| `checked` | `boolean` | `false` | Two-way bindable signal for the checked state | +| `color` | `IconSwitchColor`| `'primary'` | The color theme of the switch | +| `disabled` | `boolean` | `false` | Whether the switch is disabled | +| `tabIndex` | `number` | `0` | The tab index for keyboard navigation | + +#### Two-Way Binding + +The `checked` property uses Angular's new model signal syntax for two-way binding: + +```html + + + + + + + + + +``` + +#### Accessibility + +The component follows WAI-ARIA best practices: + +- `role="switch"` - Identifies the element as a switch +- `aria-checked` - Indicates the current state +- `aria-disabled` - Indicates when the switch is disabled +- `tabindex` - Allows keyboard focus and navigation +- Keyboard support: + - `Enter` - Toggles the switch + - `Space` - Toggles the switch + +#### Styling + +The component uses the following CSS classes: + +- `.ui-icon-switch` - Main component class +- `.ui-icon-switch__primary` - Primary color theme (currently the only supported theme) +- `.ui-icon-switch__track` - The pill-shaped background track +- `.ui-icon-switch__track--checked` - Applied when checked +- `.ui-icon-switch__thumb` - The circular toggle indicator with icon +- `.ui-icon-switch__thumb--checked` - Applied when checked +- `.disabled` - Applied when disabled + +#### Color Themes + +Currently, only the `primary` theme is supported, which uses: + +- **Unchecked**: Neutral gray background (`isa-neutral-300`) +- **Checked**: Secondary blue background (`isa-secondary-600`) +- **Hover (unchecked)**: Darker neutral gray (`isa-neutral-400`) +- **Hover (checked)**: Darker secondary blue (`isa-secondary-700`) +- **Thumb**: White background with icon color matching the state + +#### Examples + +**Basic usage:** + +```html + + +``` + +**Disabled switch:** + +```html + + +``` + +**With event handling:** + +```typescript +@Component({ + template: ` + + + `, +}) +export class ExampleComponent { + isEnabled = false; + + handleToggle(checked: boolean): void { + console.log('Switch toggled:', checked); + // Perform action based on state + } +} +``` + +## Design Guidelines + +**When to use Icon Switch:** + +- ✅ The icon meaning is universally clear (e.g., home, dashboard, notification) +- ✅ Space is limited +- ✅ The action is binary (on/off, enabled/disabled) + +**When NOT to use Icon Switch:** + +- ❌ The icon meaning is ambiguous or context-specific +- ❌ Multiple related switches need differentiation +- ❌ Users need explicit labels for clarity + +For cases where labels are needed, consider using a standard labeled switch component instead. + +## Development + +### Running unit tests + +Run `nx test ui-switch` to execute the unit tests with Vitest. + +### Running Storybook + +The component has a Storybook story at `apps/isa-app/stories/ui/switch/ui-icon-switch.stories.ts`. + +Run Storybook to see the component in action: + +```bash +npm run storybook +``` diff --git a/libs/ui/switch/eslint.config.cjs b/libs/ui/switch/eslint.config.cjs new file mode 100644 index 000000000..d36ea77f0 --- /dev/null +++ b/libs/ui/switch/eslint.config.cjs @@ -0,0 +1,34 @@ +const nx = require('@nx/eslint-plugin'); +const baseConfig = require('../../../eslint.config.js'); + +module.exports = [ + ...baseConfig, + ...nx.configs['flat/angular'], + ...nx.configs['flat/angular-template'], + { + files: ['**/*.ts'], + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'lib', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'lib', + style: 'kebab-case', + }, + ], + }, + }, + { + files: ['**/*.html'], + // Override or add rules here + rules: {}, + }, +]; diff --git a/libs/ui/switch/project.json b/libs/ui/switch/project.json new file mode 100644 index 000000000..249f5e435 --- /dev/null +++ b/libs/ui/switch/project.json @@ -0,0 +1,20 @@ +{ + "name": "ui-switch", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/ui/switch/src", + "prefix": "lib", + "projectType": "library", + "tags": [], + "targets": { + "test": { + "executor": "@nx/vite:test", + "outputs": ["{options.reportsDirectory}"], + "options": { + "reportsDirectory": "../../../coverage/libs/ui/switch" + } + }, + "lint": { + "executor": "@nx/eslint:lint" + } + } +} diff --git a/libs/ui/switch/src/index.ts b/libs/ui/switch/src/index.ts new file mode 100644 index 000000000..240f3ce24 --- /dev/null +++ b/libs/ui/switch/src/index.ts @@ -0,0 +1,2 @@ +export * from './lib/switch.component'; +export * from './lib/types'; diff --git a/libs/ui/switch/src/lib/_switch.scss b/libs/ui/switch/src/lib/_switch.scss new file mode 100644 index 000000000..80a7aec7f --- /dev/null +++ b/libs/ui/switch/src/lib/_switch.scss @@ -0,0 +1,84 @@ +.ui-switch { + display: inline-flex; + align-items: center; + cursor: pointer; + user-select: none; + + &.disabled { + @apply cursor-default pointer-events-none opacity-50; + } +} + +.ui-switch__track { + position: relative; + width: 5.25rem; + height: 3rem; + border-radius: 1.5rem; + transition: background-color 0.2s ease-in-out; + @apply bg-isa-neutral-400; + + &--checked { + @apply bg-isa-secondary-400; + } +} + +.ui-switch__thumb { + position: absolute; + left: 0.375rem; + width: 1.875rem; + height: 1.875rem; + border-radius: 50%; + transition: all 0.3s ease-in-out; + @apply bg-isa-white; + top: 50%; + transform: translate(0.1875rem, -50%); + + &--checked { + transform: translate(2.2rem, -50%); + width: 2.25rem; + height: 2.25rem; + } + + .ui-switch:hover & { + transform: translate(0.1875rem, -50%) scale(0.9); + } + + .ui-switch:hover &--checked { + transform: translate(2.25rem, -50%) scale(0.9); + } +} + +.ui-switch__icon { + position: absolute; + top: 50%; + right: 0.75rem; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + pointer-events: none; + transition: color 0.2s ease-in-out; +} + +.ui-switch__primary { + .ui-switch__track { + @apply bg-isa-neutral-400; + + &--checked { + @apply bg-isa-secondary-400; + } + } + + .ui-switch__icon { + @apply text-isa-white; + } + + .ui-switch__track--checked .ui-switch__icon { + @apply text-isa-secondary-400; + } +} + +.ui-switch:disabled, +.ui-switch.disabled { + @apply cursor-default; +} diff --git a/libs/ui/switch/src/lib/switch.component.html b/libs/ui/switch/src/lib/switch.component.html new file mode 100644 index 000000000..d00ffaa6b --- /dev/null +++ b/libs/ui/switch/src/lib/switch.component.html @@ -0,0 +1,9 @@ +
+
+
+ +
+
diff --git a/libs/ui/switch/src/lib/switch.component.spec.ts b/libs/ui/switch/src/lib/switch.component.spec.ts new file mode 100644 index 000000000..c4770029b --- /dev/null +++ b/libs/ui/switch/src/lib/switch.component.spec.ts @@ -0,0 +1,202 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { SwitchComponent } from './switch.component'; +import { provideIcons } from '@ng-icons/core'; +import { isaNavigationDashboard } from '@isa/icons'; + +describe('SwitchComponent', () => { + let component: SwitchComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [SwitchComponent], + providers: [provideIcons({ isaNavigationDashboard })], + }).compileComponents(); + + fixture = TestBed.createComponent(SwitchComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('initial state', () => { + it('should have default values', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + + expect(component.checked()).toBe(false); + expect(component.color()).toBe('primary'); + expect(component.disabled()).toBe(false); + }); + + it('should render with unchecked state', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + + const track = fixture.nativeElement.querySelector('.ui-switch__track'); + expect(track).toBeTruthy(); + expect(track.classList.contains('ui-switch__track--checked')).toBe(false); + }); + }); + + describe('checked state', () => { + it('should update when checked input changes', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.componentRef.setInput('checked', true); + fixture.detectChanges(); + + expect(component.checked()).toBe(true); + }); + + it('should apply checked class to track', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.componentRef.setInput('checked', true); + fixture.detectChanges(); + + const track = fixture.nativeElement.querySelector('.ui-switch__track'); + expect(track.classList.contains('ui-switch__track--checked')).toBe(true); + }); + + it('should apply checked class to thumb', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.componentRef.setInput('checked', true); + fixture.detectChanges(); + + const thumb = fixture.nativeElement.querySelector('.ui-switch__thumb'); + expect(thumb.classList.contains('ui-switch__thumb--checked')).toBe(true); + }); + }); + + describe('toggle functionality', () => { + beforeEach(() => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + }); + + it('should toggle checked state on click', () => { + expect(component.checked()).toBe(false); + + fixture.nativeElement.click(); + fixture.detectChanges(); + + expect(component.checked()).toBe(true); + + fixture.nativeElement.click(); + fixture.detectChanges(); + + expect(component.checked()).toBe(false); + }); + + it('should toggle on Enter key', () => { + expect(component.checked()).toBe(false); + + const event = new KeyboardEvent('keydown', { key: 'Enter' }); + fixture.nativeElement.dispatchEvent(event); + fixture.detectChanges(); + + expect(component.checked()).toBe(true); + }); + + it('should toggle on Space key', () => { + expect(component.checked()).toBe(false); + + const event = new KeyboardEvent('keydown', { key: ' ' }); + fixture.nativeElement.dispatchEvent(event); + fixture.detectChanges(); + + expect(component.checked()).toBe(true); + }); + }); + + describe('disabled state', () => { + beforeEach(() => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.componentRef.setInput('disabled', true); + fixture.detectChanges(); + }); + + it('should not toggle when disabled and clicked', () => { + expect(component.checked()).toBe(false); + + fixture.nativeElement.click(); + fixture.detectChanges(); + + expect(component.checked()).toBe(false); + }); + + it('should apply disabled class', () => { + expect(fixture.nativeElement.classList.contains('disabled')).toBe(true); + }); + + it('should have aria-disabled attribute', () => { + expect(fixture.nativeElement.getAttribute('aria-disabled')).toBe('true'); + }); + }); + + describe('accessibility', () => { + beforeEach(() => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + }); + + it('should have role="switch"', () => { + expect(fixture.nativeElement.getAttribute('role')).toBe('switch'); + }); + + it('should have correct aria-checked when unchecked', () => { + expect(fixture.nativeElement.getAttribute('aria-checked')).toBe('false'); + }); + + it('should have correct aria-checked when checked', () => { + fixture.componentRef.setInput('checked', true); + fixture.detectChanges(); + + expect(fixture.nativeElement.getAttribute('aria-checked')).toBe('true'); + }); + + it('should be keyboard focusable', () => { + expect(fixture.nativeElement.getAttribute('tabindex')).toBe('0'); + }); + + it('should support custom tabindex', () => { + fixture.componentRef.setInput('tabIndex', 5); + fixture.detectChanges(); + + expect(fixture.nativeElement.getAttribute('tabindex')).toBe('5'); + }); + }); + + describe('color theme', () => { + beforeEach(() => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + }); + + it('should apply primary color class by default', () => { + expect( + fixture.nativeElement.classList.contains('ui-switch__primary'), + ).toBe(true); + }); + + it('should apply correct color class', () => { + fixture.componentRef.setInput('color', 'primary'); + fixture.detectChanges(); + + expect( + fixture.nativeElement.classList.contains('ui-switch__primary'), + ).toBe(true); + }); + }); + + describe('icon rendering', () => { + it('should render the provided icon', () => { + fixture.componentRef.setInput('icon', 'isaNavigationDashboard'); + fixture.detectChanges(); + + const icon = fixture.nativeElement.querySelector('ng-icon'); + expect(icon).toBeTruthy(); + }); + }); +}); diff --git a/libs/ui/switch/src/lib/switch.component.ts b/libs/ui/switch/src/lib/switch.component.ts new file mode 100644 index 000000000..d79809574 --- /dev/null +++ b/libs/ui/switch/src/lib/switch.component.ts @@ -0,0 +1,102 @@ +import { + ChangeDetectionStrategy, + Component, + computed, + input, + model, + ViewEncapsulation, +} from '@angular/core'; +import { NgIconComponent, provideIcons } from '@ng-icons/core'; +import { IconSwitchColor } from './types'; +import { IsaIcons } from '@isa/icons'; + +/** + * A toggle switch component that displays an icon and supports two states (on/off). + * Use only when the icon meaning is universally clear, otherwise prefer a labeled switch. + * + * The component uses reactive signals to manage its state and provides a visually + * appealing toggle animation between enabled and disabled states. + * + * Features: + * - Customizable icon + * - Two-way binding with model signal + * - Hover state styling + * - Disabled state handling + * - Keyboard navigation support + * - Accessible with ARIA attributes + * + * @property icon - The name of the icon to display in the switch + * @property checked - A two-way bindable signal indicating whether the switch is on (true) or off (false) + * @property color - The color theme of the switch (currently only 'primary' is supported) + * @property colorClass - A computed CSS class based on the current color + * @property disabled - A boolean flag indicating whether the switch is disabled + * @property disabledClass - A computed CSS class that adds a 'disabled' style when the switch is disabled + * @property tabIndex - The tab index for keyboard navigation + * + * @example + * ```html + * + * + * ``` + * + * @remarks + * - The switch uses a pill-shaped design with a circular toggle indicator + * - The icon is always visible and moves with the toggle indicator + * - Click and Enter/Space key events toggle the switch state + */ +@Component({ + selector: 'ui-switch', + templateUrl: './switch.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + standalone: true, + imports: [NgIconComponent], + host: { + '[class]': '["ui-switch", colorClass(), disabledClass()]', + '[tabindex]': 'tabIndex()', + '[attr.role]': '"switch"', + '[attr.aria-checked]': 'checked()', + '[attr.aria-disabled]': 'disabled()', + '(click)': 'toggle()', + '(keydown.enter)': 'toggle()', + '(keydown.space)': 'toggle(); $event.preventDefault()', + }, + providers: [provideIcons(IsaIcons)], +}) +export class SwitchComponent { + /** The name of the icon to display */ + icon = input.required(); + + /** Two-way bindable signal for the checked state */ + checked = model(false); + + /** The color theme of the switch */ + color = input('primary'); + + /** Computed class based on the current color */ + colorClass = computed(() => `ui-switch__${this.color()}`); + + /** Whether the switch is disabled */ + disabled = input(false); + + /** Computed CSS class for the disabled state */ + disabledClass = computed(() => (this.disabled() ? 'disabled' : '')); + + /** The tab index for keyboard navigation */ + tabIndex = input(0); + + /** Computed class for the checked state */ + checkedClass = computed(() => (this.checked() ? 'ui-switch__checked' : '')); + + /** + * Toggles the switch state unless it's disabled + */ + toggle(): void { + if (!this.disabled()) { + this.checked.set(!this.checked()); + } + } +} diff --git a/libs/ui/switch/src/lib/types.ts b/libs/ui/switch/src/lib/types.ts new file mode 100644 index 000000000..d6be68d1d --- /dev/null +++ b/libs/ui/switch/src/lib/types.ts @@ -0,0 +1,6 @@ +export const IconSwitchColor = { + Primary: 'primary', +} as const; + +export type IconSwitchColor = + (typeof IconSwitchColor)[keyof typeof IconSwitchColor]; diff --git a/libs/ui/switch/src/switch.scss b/libs/ui/switch/src/switch.scss new file mode 100644 index 000000000..a04fdf7ea --- /dev/null +++ b/libs/ui/switch/src/switch.scss @@ -0,0 +1 @@ +@import "lib/switch"; diff --git a/libs/ui/switch/src/test-setup.ts b/libs/ui/switch/src/test-setup.ts new file mode 100644 index 000000000..cebf5ae72 --- /dev/null +++ b/libs/ui/switch/src/test-setup.ts @@ -0,0 +1,13 @@ +import '@angular/compiler'; +import '@analogjs/vitest-angular/setup-zone'; + +import { + BrowserTestingModule, + platformBrowserTesting, +} from '@angular/platform-browser/testing'; +import { getTestBed } from '@angular/core/testing'; + +getTestBed().initTestEnvironment( + BrowserTestingModule, + platformBrowserTesting(), +); diff --git a/libs/ui/switch/tsconfig.json b/libs/ui/switch/tsconfig.json new file mode 100644 index 000000000..3268ed4dc --- /dev/null +++ b/libs/ui/switch/tsconfig.json @@ -0,0 +1,30 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "importHelpers": true, + "moduleResolution": "bundler", + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "typeCheckHostBindings": true, + "strictTemplates": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/libs/ui/switch/tsconfig.lib.json b/libs/ui/switch/tsconfig.lib.json new file mode 100644 index 000000000..312ee86bb --- /dev/null +++ b/libs/ui/switch/tsconfig.lib.json @@ -0,0 +1,27 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "src/**/*.spec.ts", + "src/test-setup.ts", + "jest.config.ts", + "src/**/*.test.ts", + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx" + ], + "include": ["src/**/*.ts"] +} diff --git a/libs/ui/switch/tsconfig.spec.json b/libs/ui/switch/tsconfig.spec.json new file mode 100644 index 000000000..5785a8a5f --- /dev/null +++ b/libs/ui/switch/tsconfig.spec.json @@ -0,0 +1,29 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": [ + "vitest/globals", + "vitest/importMeta", + "vite/client", + "node", + "vitest" + ] + }, + "include": [ + "vite.config.ts", + "vite.config.mts", + "vitest.config.ts", + "vitest.config.mts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ], + "files": ["src/test-setup.ts"] +} diff --git a/libs/ui/switch/vite.config.mts b/libs/ui/switch/vite.config.mts new file mode 100644 index 000000000..3f65b061b --- /dev/null +++ b/libs/ui/switch/vite.config.mts @@ -0,0 +1,27 @@ +/// +import { defineConfig } from 'vite'; +import angular from '@analogjs/vite-plugin-angular'; +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; +import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin'; + +export default defineConfig(() => ({ + root: __dirname, + cacheDir: '../../../node_modules/.vite/libs/ui/switch', + plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])], + // Uncomment this if you are using workers. + // worker: { + // plugins: [ nxViteTsPaths() ], + // }, + test: { + watch: false, + globals: true, + environment: 'jsdom', + include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + setupFiles: ['src/test-setup.ts'], + reporters: ['default'], + coverage: { + reportsDirectory: '../../../coverage/libs/ui/switch', + provider: 'v8' as const, + }, + }, +})); diff --git a/package-lock.json b/package-lock.json index 46f9f24d8..5f270b7a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -364,7 +364,6 @@ "integrity": "sha512-qEt+M6UAuBUD8lrhmHFFpaKYVeANfVrgZijkebfdDJtQybNL/2bVypJCX7D60XHC2weKHSrp8f18uhmNnvjeGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ts-morph": "^21.0.0", "vfile": "^6.0.3" @@ -429,7 +428,6 @@ "integrity": "sha512-NGHLfrNQNjwWwvyQomMM1AqRaqH3UU0TwySJh9XlSc9dC/roB5zD2NjLf98K4LfAIfHvDBwkQ+dMo3F556/Xuw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-devkit/core": "20.3.7", "rxjs": "7.8.2" @@ -474,7 +472,6 @@ "integrity": "sha512-KVA6ztqrZz/DKSCk/iV9fz9Af+54YyZs25KwClBi+7/RJIBNml8CZQLW51VxIkbjD9aZdVZdUMkkbQJp5MgY5w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.2003.7", @@ -656,7 +653,6 @@ "integrity": "sha512-uLRk3865Iz/EO9Zm/mrFfdyoZinJBihXE6HVDYRYjAqsgW14LsD8pkpWy9+LYlOwcH96Ndnev+msxaTJaNXtPg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ajv": "8.17.1", "ajv-formats": "3.0.1", @@ -685,7 +681,6 @@ "integrity": "sha512-QD7QS1oR0XcZ9ZI4D1c4JjKmSn2up/ocOU2FS1mMO7S5RtAZMsPv4J3r+6ywHA2ev2sRySOQ0D8OYBcEuYX9Jw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-devkit/core": "20.3.6", "jsonc-parser": "3.3.1", @@ -800,7 +795,6 @@ "integrity": "sha512-5Vyo/VJ1DrIsAkudFpZj1f7CpCLYuiTzTQksHTiZE18iYsLKRkEC7y9S6+TiHrdD96rhNxL28Pz9FDU4lIBjkw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-eslint/bundled-angular-compiler": "20.4.0", "eslint-scope": "^8.0.2" @@ -830,7 +824,6 @@ "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-20.3.6.tgz", "integrity": "sha512-qNaVvEOKvigoCQMg0ABnq44HhiHqKD4WN3KoUcXneklcMYCzFE5nuQxKylfWzCRiI5XqiJ9pqiL1m2D7o+Vdiw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -847,7 +840,6 @@ "integrity": "sha512-NHN5JNDqUc0Ux4IZPCe/fpFAnuRHujkxVfRHSqDFW5+jtj2JuW1XO6qlX+kDheFRlj/NvFgTpidKsE9IjpfMWQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "2.3.0", "@angular-devkit/architect": "0.2003.7", @@ -1054,7 +1046,6 @@ "integrity": "sha512-hNurF7g/e9cDHFBRCKLPSmQJs0n28jZsC3sTl/XuWE8PYtv5egh2EuqrxdruYB5GdANpIqSQNgDGQJrKrk/XnQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-devkit/architect": "0.2003.7", "@angular-devkit/core": "20.3.7", @@ -1153,7 +1144,6 @@ "resolved": "https://registry.npmjs.org/@angular/common/-/common-20.3.6.tgz", "integrity": "sha512-+gHMuFe0wz4f+vfGZ2q+fSQSYaY7KlN7QdDrFqLnA7H2sythzhXvRbXEtp4DkPjihh9gupXg2MeLh1ROy5AfSw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1170,7 +1160,6 @@ "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-20.3.6.tgz", "integrity": "sha512-OdjXBsAsnn7qiW6fSHClwn9XwjVxhtO9+RbDc6Mf+YPCnJq0s8T78H2fc8VdJFp/Rs+tMZcwwjd9VZPm8+2XWA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1182,8 +1171,8 @@ "version": "20.3.6", "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-20.3.6.tgz", "integrity": "sha512-VOFRBx9fBt2jW9I8qD23fwGeKxBI8JssJBAMqnFPl3k59VJWHQi6LlXZCLCBNdfwflTJdKeRvdgT51Q0k6tnFQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.3", "@jridgewell/sourcemap-codec": "^1.4.14", @@ -1216,7 +1205,6 @@ "resolved": "https://registry.npmjs.org/@angular/core/-/core-20.3.6.tgz", "integrity": "sha512-sDURQWnjwE4Y750u/5qwkZEYMoI4CrKghnx4aKulxCnohR3//C78wvz6p8MtCuqYfzGkdQZDYFg8tgAz17qgPw==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1242,7 +1230,6 @@ "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-20.3.6.tgz", "integrity": "sha512-tBGo/LBtCtSrClMY4DTm/3UiSjqLLMEYXS/4E0nW1mFDv7ulKnaAQB+KbfBmmTHYxlKLs+SxjKv6GoydMPSurA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1271,7 +1258,6 @@ "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-20.3.6.tgz", "integrity": "sha512-isOHiGYHSK+ySK8ry21PGO3jpJpF90E3J2BZ+LUhzpi1SzFBguEVg7j8fvbCLodiwweOnuAiKEHO0F3WpfCQ9Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "7.28.3", "@types/babel__core": "7.20.5", @@ -1296,7 +1282,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-20.3.6.tgz", "integrity": "sha512-gFp1yd+HtRN8XdpMatRLO5w6FLIzsnF31lD2Duo4BUTCoMAMdfaNT6FtcvNdKu7ANo27Ke26fxEEE2bh6FU98A==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1319,7 +1304,6 @@ "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-20.3.6.tgz", "integrity": "sha512-teO8tBygk6vD1waiLmHGXtXPF/9a9Bw2XI+s550KtJlQqRpr7IUWOFPPQik/uGkppv5Jrv6fP+8mh9QX9zoWnQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1363,7 +1347,6 @@ "resolved": "https://registry.npmjs.org/@angular/router/-/router-20.3.6.tgz", "integrity": "sha512-fSAYOR9nKpH5PoBYFNdII3nAFl2maUrYiISU33CnGwb7J7Q0s09k231c/P5tVN4URi+jdADVwiBI8cIYk8SVrg==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1382,7 +1365,6 @@ "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-20.3.6.tgz", "integrity": "sha512-utHJCoEO4EKH372BSMnNbcR96yDVkUeV7xcJb+cw9ruTOxGvCG/DUWR1h64xk3Ns6nvFmggTnIVgnBDn+92VpQ==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -1425,7 +1407,6 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.3.tgz", "integrity": "sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==", "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -4355,7 +4336,6 @@ "integrity": "sha512-nqhDw2ZcAUrKNPwhjinJny903bRhI0rQhiDz1LksjeRxqa36i3l75+4iXbOy0rlDpLJGxqtgoPavQjmmyS5UJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.2.1", "@inquirer/confirm": "^5.1.14", @@ -6563,110 +6543,6 @@ "win32" ] }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@mdx-js/react": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.1.1.tgz", @@ -7373,7 +7249,6 @@ "integrity": "sha512-YEdHA/rXlydI+ecmsidM0imAhAgyN+fSCOWRJtm72Kx10J6kS2tN1/Zah/hf9C9Msj9OOl0w22aOo7/Sy0qRqg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@module-federation/bridge-react-webpack-plugin": "0.17.1", "@module-federation/cli": "0.17.1", @@ -7710,7 +7585,6 @@ "integrity": "sha512-uQmammw3Osg8370yiRqZwKo7eA5zkyml9pAX9x4oS9QAkEBvQpDogERlF9f7gAgcP2P3v+xLg3/bCdquD0gt8A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@module-federation/runtime": "0.21.1", "@module-federation/webpack-bundler-runtime": "0.21.1" @@ -7958,7 +7832,6 @@ "integrity": "sha512-4kr6zTFFwGywJx6whBtxsc84V+COAuuBpEdEbPZN//YLXhNB0iz2IGsy9r9wDl+06h84bD+3dQ05l9euRLgXzQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@module-federation/runtime": "0.17.1", "@module-federation/webpack-bundler-runtime": "0.17.1" @@ -8530,7 +8403,6 @@ "resolved": "https://registry.npmjs.org/@ngrx/signals/-/signals-20.1.0.tgz", "integrity": "sha512-ARAHp5yA131Sw6FEtY8XtYcdGcwW5lgpZaJoDIRxc6i12VO3ZDZYp3M/FQhpIDMDXkXHR+pDqoitrqvzI69aQA==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.3.0" }, @@ -8549,7 +8421,6 @@ "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-20.1.0.tgz", "integrity": "sha512-o8j3CGAGedm+BIb+QDhNXrVaU//n9uF0wH0HZWtXHmW1mjRBaQiUA+ZPMUkDwAeN8KuOcoIEC+2QUXxXGVI7ow==", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.0.0" }, @@ -10662,7 +10533,6 @@ "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", @@ -11870,7 +11740,6 @@ "integrity": "sha512-sUd2LfiDhqYVfvknuoz0+/c+wSpn693xotnG5g1CSWKZArbtwiYzBIVnNlcHGmuoBRsnj/TkSq8dTQ7gwfBroQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@module-federation/runtime-tools": "0.18.0", "@rspack/binding": "1.5.8", @@ -12114,7 +11983,6 @@ "integrity": "sha512-YPIEyKPBOyJYlda5fA49kMThzZ4WidomEMDghshux8xidbjDaPWBZdyVPQj3IXyW0teGlUM/TH0TH2weumMZrg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@angular-devkit/core": "20.3.6", "@angular-devkit/schematics": "20.3.6", @@ -12382,7 +12250,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -12798,7 +12665,6 @@ "dev": true, "hasInstallScript": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.23" @@ -13024,7 +12890,6 @@ "integrity": "sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "@swc/counter": "^0.1.3" } @@ -13035,7 +12900,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -13368,7 +13232,6 @@ "integrity": "sha512-Mbrt4SRlXSTWryOnHAh2d4UQ/E7n9lZyGSi6KgX+4hkuL9soYbLOVXVhnk/ODp12YsGc95f4pOvqywJ6kngUwg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -13579,8 +13442,7 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.9.tgz", "integrity": "sha512-IeB32oIV4oGArLrd7znD2rkHQ6EDCM+2Sr76dJnrHwv9OHBTTM6nuDLK9bmikXzPa0ZlWMWtRGo/Uw4mrzQedA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/node-forge": { "version": "1.3.14", @@ -13619,17 +13481,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/react": { - "version": "19.2.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz", - "integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "csstype": "^3.0.2" - } - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -13804,7 +13655,6 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -13912,7 +13762,6 @@ "integrity": "sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -13972,7 +13821,6 @@ "integrity": "sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/scope-manager": "8.46.2", @@ -14474,7 +14322,6 @@ "integrity": "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", @@ -14708,7 +14555,6 @@ "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "argparse": "^2.0.1" }, @@ -14766,7 +14612,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -14886,7 +14731,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -15100,30 +14944,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -15872,7 +15692,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.19", "caniuse-lite": "^1.0.30001751", @@ -16287,8 +16106,8 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -16623,17 +16442,6 @@ "dev": true, "license": "MIT" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "optional": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -16800,14 +16608,6 @@ "node": ">=0.8" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -16835,6 +16635,7 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -18288,20 +18089,6 @@ "dev": true, "license": "MIT" }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dedent": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", @@ -18841,7 +18628,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "iconv-lite": "^0.6.2" @@ -18851,7 +18638,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -19044,7 +18831,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -19086,7 +18872,6 @@ "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.3.4" }, @@ -19175,7 +18960,6 @@ "integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -19236,7 +19020,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -19625,7 +19408,6 @@ "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", @@ -20227,7 +20009,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -20561,72 +20342,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gauge/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/gauge/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/gauge/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/gauge/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -21096,14 +20811,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -21290,7 +20997,6 @@ "integrity": "sha512-V/PZeWsqhfpE27nKeX9EO2sbR+D17A+tLf6qU+ht66jdUsN0QLKJN27Z+1+gHrVMKgndBahes0PU6rRihDgHTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -22289,7 +21995,6 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -23949,7 +23654,6 @@ "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -27156,7 +26860,6 @@ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -27217,7 +26920,6 @@ "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "abab": "^2.0.6", "cssstyle": "^3.0.0", @@ -27769,7 +27471,6 @@ "integrity": "sha512-kdTwsyRuncDfjEs0DlRILWNvxhDG/Zij4YLO4TMJgDLW+8OzpfkdPnRgrsRuY1o+oaxJGWsps5f/RVBgGmmN0w==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -27937,7 +27638,6 @@ "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", @@ -28675,20 +28375,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -29044,14 +28730,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.23.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz", - "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", @@ -29172,7 +28850,6 @@ "integrity": "sha512-hwPZNeV/6C3pWojK70AHxe6uk1rz2bzoe+WdH+GIWouUcyXrjYQjOFyLfOGD0ia9D+yWVzjsi4CKVK/dQFDQ6Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.3.0", "@rollup/plugin-json": "^6.1.0", @@ -29766,21 +29443,6 @@ "node": ">=8" } }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -29808,7 +29470,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", "@yarnpkg/lockfile": "^1.1.0", @@ -31057,7 +30718,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -31952,7 +31612,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -32305,7 +31964,6 @@ "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -32316,7 +31974,6 @@ "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -32331,17 +31988,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-refresh": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", - "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -32381,6 +32027,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14.18.0" @@ -32435,6 +32082,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, "license": "Apache-2.0" }, "node_modules/regenerate": { @@ -32829,73 +32477,6 @@ "dev": true, "license": "MIT" }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/roarr": { "version": "2.15.4", "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", @@ -32920,7 +32501,6 @@ "integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -33053,7 +32633,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -33101,7 +32680,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/sass": { @@ -33616,7 +33195,6 @@ "resolved": "https://registry.npmjs.org/scandit-web-datacapture-core/-/scandit-web-datacapture-core-6.28.6.tgz", "integrity": "sha512-D7rC+SWWG0XoZVo+LNlvpJi8+sxsylhn5zvzfDGhrDI6zTAT812HNgoGJDjNNZTZ8iaS5/dYg8LU5b+N4MLsZQ==", "license": "SEE LICENSE IN LICENSE", - "peer": true, "dependencies": { "@types/howler": "^2.2.11", "@types/js-cookie": "^2.2.6", @@ -33720,6 +33298,7 @@ "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "devOptional": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -33946,14 +33525,6 @@ "node": ">= 18" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/set-cookie-parser": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", @@ -34151,19 +33722,6 @@ "license": "MIT", "optional": true }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/sirv": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", @@ -34522,7 +34080,6 @@ "integrity": "sha512-es7uDdEwRVVUAt7XLAZZ1hicOq9r4ov5NFeFPpa2YEyAsyHYOCr0CTlHBfslWG6D5EVNWK3kVIIuW8GHB6hEig==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@storybook/global": "^5.0.0", "@testing-library/jest-dom": "^6.6.3", @@ -34862,7 +34419,6 @@ "integrity": "sha512-ZIdT8eUv8tegmqy1tTIdJv9We2DumkNZFdCF5mz/Kpq3OcTaxSuCAYZge6HKK2CmNC02G1eJig2RV7XTw5hQrA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@adobe/css-tools": "~4.3.3", "debug": "^4.3.2", @@ -35093,7 +34649,6 @@ "integrity": "sha512-6A2rnmW5xZMdw11LYjhcI5846rt9pbLSabY5XPxo+XWdxwZaFEn47Go4NzFiHu9sNNmr/kXivP1vStfvMaK1GQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -35170,7 +34725,6 @@ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -35414,7 +34968,6 @@ "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.14.0", @@ -36048,7 +35601,6 @@ "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -36155,8 +35707,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsscmp": { "version": "1.0.6", @@ -36268,9 +35819,8 @@ "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -36285,7 +35835,6 @@ "integrity": "sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/eslint-plugin": "8.46.2", "@typescript-eslint/parser": "8.46.2", @@ -36344,14 +35893,6 @@ "node": ">=0.8.0" } }, - "node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", @@ -36721,7 +36262,6 @@ "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", @@ -36820,7 +36360,6 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -37067,7 +36606,6 @@ "integrity": "sha512-4JLXU0tD6OZNVqlwzm3HGEhAHufSiyv+skb7q0d2367VDMzrU1Q/ZeepvkcHH0rZie6uqEtTQQe0OEOOluH3Mg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -37189,7 +36727,6 @@ "integrity": "sha512-QcQ72gh8a+7JO63TAx/6XZf/CWhgMzu5m0QirvPfGvptOusAxG12w2+aua1Jkjr7hzaWDnJ2n6JFeexMHI+Zjg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.13", "@types/connect-history-api-fallback": "^1.5.4", @@ -37711,7 +37248,6 @@ "integrity": "sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "ansi-html-community": "0.0.8", "html-entities": "^2.1.0", @@ -37944,52 +37480,6 @@ "node": ">=8" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wide-align/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/wide-align/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wide-align/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -38138,7 +37628,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8.3.0" }, @@ -38226,7 +37715,6 @@ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", - "peer": true, "bin": { "yaml": "bin.mjs" }, @@ -38414,7 +37902,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -38433,8 +37920,7 @@ "version": "0.15.1", "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", - "license": "MIT", - "peer": true + "license": "MIT" } } } diff --git a/tsconfig.base.json b/tsconfig.base.json index 0835ec186..e89fd0ffe 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -138,6 +138,7 @@ "@isa/ui/progress-bar": ["libs/ui/progress-bar/src/index.ts"], "@isa/ui/search-bar": ["libs/ui/search-bar/src/index.ts"], "@isa/ui/skeleton-loader": ["libs/ui/skeleton-loader/src/index.ts"], + "@isa/ui/switch": ["libs/ui/switch/src/index.ts"], "@isa/ui/toolbar": ["libs/ui/toolbar/src/index.ts"], "@isa/ui/tooltip": ["libs/ui/tooltip/src/index.ts"], "@isa/utils/ean-validation": ["libs/utils/ean-validation/src/index.ts"],