@angular-bootstrap/ngbootstrap 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular-bootstrap/ngbootstrap",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "Angular UI for data-heavy apps with DataGrid grouping, Angular-native Form Builder, drag-and-drop workflows, pagination, typeahead, tree, splitter, stepper, and chips.",
5
5
  "author": {
6
6
  "name": "Harmeet Singh"
@@ -55,11 +55,15 @@
55
55
  "@angular/core": ">=21.0.0 <23.0.0",
56
56
  "@angular/forms": ">=21.0.0 <23.0.0",
57
57
  "chart.js": ">=4.4.0 <5.0.0",
58
- "rxjs": "^7.8.0"
58
+ "rxjs": "^7.8.0",
59
+ "tailwindcss": ">=4.0.0 <5.0.0"
59
60
  },
60
61
  "peerDependenciesMeta": {
61
62
  "chart.js": {
62
63
  "optional": true
64
+ },
65
+ "tailwindcss": {
66
+ "optional": true
63
67
  }
64
68
  },
65
69
  "dependencies": {
@@ -71,12 +75,16 @@
71
75
  "@jest/reporters>glob": "^13.0.6",
72
76
  "babel-plugin-istanbul>test-exclude": "^8.0.0",
73
77
  "jest-config>glob": "^13.0.6",
74
- "jest-runtime>glob": "^13.0.6"
78
+ "jest-runtime>glob": "^13.0.6",
79
+ "fast-uri@>=3.0.0 <3.1.6": "^3.1.6",
80
+ "brace-expansion@>=4.0.0 <5.0.9": "^5.0.9",
81
+ "js-yaml@>=3.0.0 <3.15.2": "^3.15.2",
82
+ "nanoid@<3.3.18": "^3.3.18"
75
83
  }
76
84
  },
77
- "module": "fesm2022/angular-bootstrap-ngbootstrap.mjs",
78
- "typings": "types/angular-bootstrap-ngbootstrap.d.ts",
79
85
  "exports": {
86
+ "./styles/tailwind.css": "./src/styles/integrations/tailwind.css",
87
+ "./src/styles/*": "./src/styles/*",
80
88
  "./package.json": {
81
89
  "default": "./package.json"
82
90
  },
@@ -85,5 +93,7 @@
85
93
  "default": "./fesm2022/angular-bootstrap-ngbootstrap.mjs"
86
94
  }
87
95
  },
96
+ "module": "fesm2022/angular-bootstrap-ngbootstrap.mjs",
97
+ "typings": "types/angular-bootstrap-ngbootstrap.d.ts",
88
98
  "type": "module"
89
99
  }
@@ -0,0 +1,134 @@
1
+ # AI UI components
2
+
3
+ Provider-independent Angular controls for operational assistant workflows.
4
+ These components render supplied data and emit typed events. They do not call
5
+ an AI provider, execute generated actions, read the clipboard automatically,
6
+ or persist conversation history.
7
+
8
+ ```ts
9
+ import {
10
+ NgbPromptBoxComponent,
11
+ NgbAiChatComponent,
12
+ NgbAiPromptComponent,
13
+ NgbInlineAiPromptComponent,
14
+ NgbSmartPasteComponent,
15
+ } from '@angular-bootstrap/ngbootstrap';
16
+ ```
17
+
18
+ Add the standalone components to your application's component imports.
19
+ Bootstrap 5 CSS is required. For scoped themes, load the library global
20
+ `src/styles/themes.scss` entry and use any supported `data-ngb-theme` wrapper.
21
+ No model SDK or AI provider dependency is installed.
22
+
23
+ | Component | Use case | Application event |
24
+ | --- | --- | --- |
25
+ | `ngb-prompt-box` | Ask a question or collect a generation instruction | `promptSubmit: string`, `stop: void` |
26
+ | `ngb-ai-chat` | Conversation with a workspace assistant | `promptSubmit`, `stop`, `retry: string`, `feedback: NgbAiFeedback` |
27
+ | `ngb-ai-prompt` | Generate and review multiple drafts | `promptSubmit`, `stop`, `responseApply`, `regenerate`, `responseDismiss` |
28
+ | `ngb-inline-ai-prompt` | Propose a contextual text replacement | `promptSubmit: NgbInlineAiRequest`, `responseApply: string`, `stop`, `closed` |
29
+ | `ngb-smart-paste` | Review field values extracted from pasted notes | `mappingRequest: NgbSmartPasteRequest`, `valuesApply: readonly NgbSmartPasteSuggestion[]`, `stop` |
30
+
31
+ ## Prompt Box
32
+
33
+ ```html
34
+ <ngb-prompt-box [(value)]="instruction" [busy]="pending()"
35
+ [suggestions]="['Summarize open orders', 'Draft a delivery update']"
36
+ (promptSubmit)="send($event)" (stop)="cancel()" />
37
+ ```
38
+
39
+ `value` supports two-way binding. Set `maxLength` (default 4000),
40
+ `submitOnEnter` (default true), and `clearOnSubmit` (default true).
41
+ Empty, whitespace-only, over-limit, disabled, or busy submissions are rejected.
42
+ Shift+Enter inserts a line and composition events do not submit.
43
+ Suggestions populate the draft without sending it. The composer has
44
+ `label`, `placeholder`, `submitLabel`, and `stopLabel` string inputs.
45
+
46
+ ## Chat
47
+
48
+ ```html
49
+ <ngb-ai-chat [messages]="messages()" [busy]="pending()" [error]="error()"
50
+ (promptSubmit)="send($event)" (stop)="cancel()"
51
+ (retry)="retryMessage($event)" (feedback)="recordFeedback($event)" />
52
+ ```
53
+
54
+ Each `NgbAiMessage` has a unique `id`, a `role` (`user`, `assistant`, or
55
+ `system`), and plain-text `content`. Optional `status` is `complete`,
56
+ `streaming`, or `error`; optional `error` supplies per-message failure text.
57
+ Replace messages immutably as chunks arrive. Retry emits the failed ID;
58
+ the application decides which request to replay. Feedback emits the ID and
59
+ `helpful`, `unhelpful`, or `null` when cleared. The component manages visual
60
+ feedback selection, but the application owns its persistence.
61
+
62
+ `label`, `userLabel`, `assistantLabel`, `emptyText`, and `suggestions` configure
63
+ basic conversation copy. Busy locks the composer and exposes Stop.
64
+ User messages align to the end of the transcript; assistant responses stay at
65
+ the start, with feedback below the response. There is no forced autoscroll: users can continue reading earlier messages.
66
+
67
+ ## Draft workspace
68
+
69
+ The workspace places the instruction brief beside reviewable drafts and stacks
70
+ them on small screens. Provide `responses: readonly NgbAiResponse[]`, each with `id`, `prompt`, and
71
+ `text`. Array order determines display order. `responseApply` and `regenerate`
72
+ emit the selected response; `responseDismiss` emits its ID. These events do
73
+ not change the input history. Supply `label`, `promptLabel`, `emptyText`, and
74
+ `suggestions` as needed. The request text remains available after submission.
75
+
76
+ ## Inline edits
77
+
78
+ Provide `context` and a separately generated `response`. The `promptSubmit`
79
+ event contains `{ instruction, context }`. Only explicit Apply emits
80
+ `responseApply`; the original context is never changed by the library.
81
+ Closing with the trigger, Close, or Escape emits `closed`, restores trigger
82
+ focus, and emits `stop` if work is pending. The expanded region stays in the
83
+ page flow, and normal Tab navigation reaches its controls.
84
+
85
+ ## Reviewed paste
86
+
87
+ Provide `fields` as `{ key, label, value? }[]`; field values are strings.
88
+ `source` is an optional two-way input for the pasted text. The user pastes
89
+ into a normal textarea; the component does not request clipboard permission.
90
+ `mappingRequest` emits the text and a copied field schema. Your extraction
91
+ service returns `suggestions` as `{ field, value }[]`.
92
+
93
+ Only keys present in `fields` can be reviewed. The first valid suggestion for
94
+ a field is used; unknown fields are ignored. Users can edit proposed text and
95
+ exclude fields. `valuesApply` emits only the selected proposals. The application
96
+ must validate them and explicitly update its form. New fields or suggestions
97
+ reset the review selection and temporary edits.
98
+
99
+ ## Request lifecycle and boundaries
100
+
101
+ All panels expose `busy`, `disabled`, and (except Prompt Box) `error` inputs.
102
+ Set busy immediately when a request starts. On Stop, abort the application
103
+ request, clear busy, and ignore results from older request IDs. Cancel pending
104
+ work on destruction. Clear stale proposals when the source or context changes.
105
+ Keep provider credentials on the server and validate response data before
106
+ passing it to components or applying it to domain records.
107
+
108
+ Content is interpolated as text. HTML, Markdown rendering, attachments, voice,
109
+ model transports, persistence, AI Grid features, and WebMCP are not included.
110
+ Inputs with labels support basic copy customization; this first version does
111
+ not yet expose a full translation dictionary for every built-in action label.
112
+
113
+ Tests cover submission guards, composition/keyboard input, cancellation,
114
+ streaming updates, error/retry, feedback, explicit draft/edit application,
115
+ field allowlisting, review edits, and escaped content.
116
+
117
+ ## Accessibility and keyboard support
118
+
119
+ Native buttons support Tab/Shift+Tab navigation and Enter/Space activation.
120
+ Prompt inputs have visible labels and associated keyboard/length guidance.
121
+ Enter submits when enabled; Shift+Enter and IME composition are preserved.
122
+ During processing, the textarea stays focusable and read-only, and the same
123
+ button changes from Send to Stop without replacing the focused DOM node.
124
+ Explicitly disabled controls remain disabled.
125
+
126
+ Chat exposes a named live log and pressed feedback states. Drafts use a named,
127
+ focusable scroll region. Inline Prompt uses an expanded trigger linked to its
128
+ panel, Escape closes it, and closure restores trigger focus. New inline proposals
129
+ and Smart Paste fields have persistent live status regions. Smart Paste uses
130
+ labeled native checkboxes and inputs inside a fieldset.
131
+
132
+ These contracts have automated coverage and browser keyboard checks. They are
133
+ not a WCAG certification; perform assistive-technology testing in the consuming
134
+ application, especially for custom themes, content, and surrounding focus flows.
@@ -0,0 +1,86 @@
1
+ // Component-local Bootstrap bridges. No selectors escape Angular encapsulation.
2
+ :host {
3
+ font-family: var(--ngb-font-family, inherit);
4
+ color: var(--ngb-on-surface, inherit);
5
+ }
6
+ .btn {
7
+ --bs-btn-color: var(--ngb-on-surface, var(--bs-body-color, #212529));
8
+ --bs-btn-hover-color: var(--ngb-on-surface, var(--bs-body-color, #212529));
9
+ --bs-btn-border-radius: var(--ngb-radius-md, var(--bs-border-radius, 0.375rem));
10
+ --bs-btn-disabled-opacity: var(--ngb-disabled-opacity, 0.65);
11
+ }
12
+ .btn-primary {
13
+ --bs-btn-bg: var(--ngb-primary, #0d6efd);
14
+ --bs-btn-border-color: var(--ngb-primary, #0d6efd);
15
+ --bs-btn-color: var(--ngb-on-primary, #fff);
16
+ --bs-btn-hover-bg: var(--ngb-primary-hover, #0b5ed7);
17
+ --bs-btn-hover-border-color: var(--ngb-primary-hover, #0a58ca);
18
+ --bs-btn-hover-color: var(--ngb-on-primary, #fff);
19
+ --bs-btn-active-bg: var(--ngb-primary-hover, #0a58ca);
20
+ --bs-btn-active-border-color: var(--ngb-primary-hover, #0a53be);
21
+ --bs-btn-active-color: var(--ngb-on-primary, #fff);
22
+ --bs-btn-disabled-bg: var(--ngb-primary, #0d6efd);
23
+ --bs-btn-disabled-border-color: var(--ngb-primary, #0d6efd);
24
+ --bs-btn-disabled-color: var(--ngb-on-primary, #fff);
25
+ }
26
+ .btn-outline-secondary {
27
+ --bs-btn-color: var(--ngb-on-surface-variant, #6c757d);
28
+ --bs-btn-border-color: var(--ngb-border-color, #6c757d);
29
+ --bs-btn-hover-bg: var(--ngb-hover-bg, #6c757d);
30
+ --bs-btn-hover-color: var(--ngb-on-surface, #fff);
31
+ --bs-btn-hover-border-color: var(--ngb-border-color, #6c757d);
32
+ --bs-btn-active-bg: var(--ngb-selected-bg, #6c757d);
33
+ --bs-btn-active-color: var(--ngb-on-surface, #fff);
34
+ --bs-btn-active-border-color: var(--ngb-border-color, #6c757d);
35
+ --bs-btn-disabled-color: var(--ngb-on-surface-variant, #6c757d);
36
+ --bs-btn-disabled-border-color: var(--ngb-border-color, #6c757d);
37
+ }
38
+ .form-control, .form-select {
39
+ color: var(--ngb-on-surface, var(--bs-body-color, #212529));
40
+ background-color: var(--ngb-surface, var(--bs-body-bg, #fff));
41
+ border-color: var(--ngb-border-color, var(--bs-border-color, #dee2e6));
42
+ border-radius: var(--ngb-radius-md, var(--bs-border-radius, 0.375rem));
43
+ }
44
+ .form-control::placeholder {
45
+ color: var(--ngb-on-surface-variant, var(--bs-secondary-color, #6c757d));
46
+ }
47
+ .form-control:disabled, .form-select:disabled {
48
+ background-color: var(--ngb-surface-variant, var(--bs-secondary-bg, #e9ecef));
49
+ opacity: var(--ngb-disabled-opacity, 1);
50
+ }
51
+ .form-check-input {
52
+ background-color: var(--ngb-surface, var(--bs-body-bg, #fff));
53
+ border-color: var(--ngb-border-color, var(--bs-border-color, #dee2e6));
54
+ }
55
+ .form-check-input:checked, .form-check-input:indeterminate {
56
+ background-color: var(--ngb-primary, #0d6efd);
57
+ border-color: var(--ngb-primary, #0d6efd);
58
+ }
59
+ .form-control:focus, .form-select:focus, .form-check-input:focus {
60
+ border-color: var(--ngb-primary, #86b7fe);
61
+ box-shadow: 0 0 0 0.25rem var(--ngb-focus-ring, rgba(13, 110, 253, 0.25));
62
+ }
63
+ .btn:focus-visible, .page-link:focus-visible {
64
+ outline: 2px solid var(--ngb-focus-ring, #86b7fe);
65
+ outline-offset: 2px;
66
+ }
67
+ .dropdown-menu {
68
+ --bs-dropdown-color: var(--ngb-on-surface, var(--bs-body-color, #212529));
69
+ --bs-dropdown-bg: var(--ngb-surface, var(--bs-body-bg, #fff));
70
+ --bs-dropdown-border-color: var(--ngb-border-color, var(--bs-border-color-translucent, rgba(0,0,0,.175)));
71
+ --bs-dropdown-border-radius: var(--ngb-radius-md, var(--bs-border-radius, 0.375rem));
72
+ --bs-dropdown-link-color: var(--ngb-on-surface, var(--bs-body-color, #212529));
73
+ --bs-dropdown-link-hover-bg: var(--ngb-hover-bg, var(--bs-tertiary-bg, #f8f9fa));
74
+ --bs-dropdown-link-hover-color: var(--ngb-on-surface, var(--bs-body-color, #212529));
75
+ --bs-dropdown-link-active-bg: var(--ngb-primary, #0d6efd);
76
+ --bs-dropdown-link-active-color: var(--ngb-on-primary, #fff);
77
+ --bs-dropdown-link-disabled-color: var(--ngb-on-surface-variant, var(--bs-tertiary-color, #adb5bd));
78
+ box-shadow: var(--ngb-elevation-2, none);
79
+ }
80
+
81
+ .form-select { background-image: var(--ngb-select-icon, var(--bs-form-select-bg-img)); }
82
+
83
+ .form-check-input:disabled { opacity: var(--ngb-disabled-opacity, 0.5); }
84
+
85
+ .btn-sm { --bs-btn-border-radius: var(--ngb-radius-sm, var(--bs-border-radius-sm, 0.25rem)); }
86
+ .form-control-sm, .form-select-sm { border-radius: var(--ngb-radius-sm, var(--bs-border-radius-sm, 0.25rem)); }
@@ -0,0 +1,3 @@
1
+ // Same optional drag/drop skin used by the legacy CSS entry point.
2
+ @use "sass:meta";
3
+ @include meta.load-css("./styles.css");
@@ -0,0 +1,6 @@
1
+ // Public scoped themes. No :root aliases: local framework variables must resolve
2
+ // on the wrapper, including nested light/dark scopes.
3
+ @use './themes/bootstrap';
4
+ @use './themes/material';
5
+ @use './themes/tailwind';
6
+ @use './themes/presets';
@@ -0,0 +1,37 @@
1
+ /* Optional Tailwind CSS v4 preset. Import in your Tailwind CSS entry, not Sass.
2
+ * Requires the ngbootstrap global theme stylesheet and a data-ngb-theme scope.
3
+ * The ngb namespace preserves Tailwind defaults and avoids circular mappings
4
+ * when the Tailwind-to-ngbootstrap bridge is also used.
5
+ * Inline references resolve on each utility element, including nested themes.
6
+ */
7
+ @theme inline {
8
+ --color-ngb-primary: var(--ngb-primary);
9
+ --color-ngb-on-primary: var(--ngb-on-primary);
10
+ --color-ngb-primary-hover: var(--ngb-primary-hover);
11
+ --color-ngb-primary-container: var(--ngb-primary-container);
12
+ --color-ngb-surface: var(--ngb-surface);
13
+ --color-ngb-surface-container: var(--ngb-surface-container);
14
+ --color-ngb-surface-variant: var(--ngb-surface-variant);
15
+ --color-ngb-on-surface: var(--ngb-on-surface);
16
+ --color-ngb-on-surface-variant: var(--ngb-on-surface-variant);
17
+ --color-ngb-border: var(--ngb-border-color);
18
+ --color-ngb-focus: var(--ngb-focus-ring);
19
+ --color-ngb-hover: var(--ngb-hover-bg);
20
+ --color-ngb-selected: var(--ngb-selected-bg);
21
+ --color-ngb-success: var(--ngb-success);
22
+ --color-ngb-on-success: var(--ngb-on-success);
23
+ --color-ngb-danger: var(--ngb-danger);
24
+ --color-ngb-on-danger: var(--ngb-on-danger);
25
+ --radius-ngb-sm: var(--ngb-radius-sm);
26
+ --radius-ngb-md: var(--ngb-radius-md);
27
+ --radius-ngb-lg: var(--ngb-radius-lg);
28
+ --font-ngb: var(--ngb-font-family);
29
+ --text-ngb-sm: var(--ngb-font-size-sm);
30
+ --spacing-ngb-1: var(--ngb-space-1);
31
+ --spacing-ngb-2: var(--ngb-space-2);
32
+ --spacing-ngb-3: var(--ngb-space-3);
33
+ --spacing-ngb-4: var(--ngb-space-4);
34
+ --spacing-ngb-row: var(--ngb-density-row-height);
35
+ --shadow-ngb-1: var(--ngb-elevation-1);
36
+ --shadow-ngb-2: var(--ngb-elevation-2);
37
+ }
@@ -3,37 +3,30 @@
3
3
 
4
4
  /* Base list appearance (you likely have this already) */
5
5
  .ngb-dnd-list {
6
- border: 2px dashed var(--bs-border-color);
7
- border-radius: .5rem;
6
+ border: 2px dashed var(--ngb-border-color, var(--bs-border-color, #dee2e6));
7
+ border-radius: var(--ngb-radius-lg, .5rem);
8
8
  transition: border-color .15s ease, box-shadow .15s ease, background-color .15s ease;
9
9
  }
10
10
 
11
11
  /* Hover highlight (compatible drop) */
12
12
  .ngb-dnd-list.ngb-dnd-over[data-drop-valid="true"] {
13
- border-color: var(--bs-primary);
14
- background-color: rgba(var(--bs-primary-rgb), .04);
15
- box-shadow: 0 0 0 .2rem rgba(var(--bs-primary-rgb), .15);
13
+ border-color: var(--ngb-primary, var(--bs-primary, #0d6efd));
14
+ background-color: color-mix(in srgb, var(--ngb-primary, var(--bs-primary)) 4%, transparent);
15
+ box-shadow: 0 0 0 .2rem var(--ngb-focus-ring, rgba(var(--bs-primary-rgb), .15));
16
16
  }
17
17
 
18
18
  /* Hover highlight (NOT compatible) */
19
19
  .ngb-dnd-list.ngb-dnd-over[data-drop-valid="false"] {
20
- border-color: var(--bs-danger);
21
- background-color: rgba(var(--bs-danger-rgb), .04);
22
- box-shadow: 0 0 0 .2rem rgba(var(--bs-danger-rgb), .12);
20
+ border-color: var(--ngb-danger, var(--bs-danger, #dc3545));
21
+ background-color: color-mix(in srgb, var(--ngb-danger, var(--bs-danger)) 4%, transparent);
22
+ box-shadow: 0 0 0 .2rem color-mix(in srgb, var(--ngb-danger, var(--bs-danger)) 12%, transparent);
23
23
  }
24
24
 
25
25
  /* Make the insertion placeholder more obvious */
26
26
  .ngb-dnd-placeholder {
27
- border: 2px dashed var(--bs-primary);
28
- background: rgba(var(--bs-primary-rgb), .06);
29
- border-radius: .5rem;
30
- min-height: 40px;
27
+ border: 2px dashed var(--ngb-primary, var(--bs-primary, #0d6efd));
28
+ background: color-mix(in srgb, var(--ngb-primary, var(--bs-primary)) 6%, transparent);
29
+ border-radius: var(--ngb-radius-lg, .5rem);
30
+ min-height: var(--ngb-density-row-height, 40px);
31
31
  margin: .25rem 0;
32
32
  }
33
-
34
- table button.btn {
35
- border-color: transparent !important;
36
- text-decoration: none;
37
- color: #000;
38
- font-weight: bold;
39
- }
@@ -0,0 +1,48 @@
1
+ @use "sass:map";
2
+ // Public tokens for an explicitly scoped bootstrap theme.
3
+ @mixin tokens($overrides: ()) {
4
+ $values: (
5
+ select-icon: var(--_ngb-bootstrap-select-icon, url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")),
6
+ primary: var(--bs-primary, #0d6efd),
7
+ on-primary: #ffffff,
8
+ surface: var(--bs-body-bg, #ffffff),
9
+ surface-container: var(--bs-tertiary-bg, #f8f9fa),
10
+ surface-variant: var(--bs-secondary-bg, #e9ecef),
11
+ on-surface: var(--bs-body-color, #212529),
12
+ on-surface-variant: var(--bs-secondary-color, #6c757d),
13
+ border-color: var(--bs-border-color, #dee2e6),
14
+ primary-hover: var(--bs-link-hover-color, #0a58ca),
15
+ primary-container: var(--bs-primary-bg-subtle, #cfe2ff),
16
+ focus-ring: var(--bs-focus-ring-color, rgba(13, 110, 253, 0.25)),
17
+ radius-sm: var(--bs-border-radius-sm, 0.25rem),
18
+ radius-md: var(--bs-border-radius, 0.375rem),
19
+ radius-lg: var(--bs-border-radius-lg, 0.5rem),
20
+ font-family: var(--bs-body-font-family, system-ui, sans-serif),
21
+ font-size-sm: 0.84rem,
22
+ density-row-height: 40px,
23
+ elevation-1: var(--bs-box-shadow-sm, 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075)),
24
+ elevation-2: var(--bs-box-shadow, 0 0.5rem 1rem rgba(0, 0, 0, 0.15)),
25
+ disabled-opacity: 0.45,
26
+ hover-bg: var(--bs-tertiary-bg, #f8f9fa),
27
+ selected-bg: var(--bs-primary-bg-subtle, #cfe2ff),
28
+ success: var(--bs-success, #198754),
29
+ on-success: #ffffff,
30
+ danger: var(--bs-danger, #dc3545),
31
+ on-danger: #ffffff,
32
+ space-1: 0.25rem,
33
+ space-2: 0.5rem,
34
+ space-3: 0.75rem,
35
+ space-4: 1rem,
36
+ );
37
+ @each $name, $value in map.merge($values, $overrides) {
38
+ --ngb-#{$name}: #{$value};
39
+ }
40
+ }
41
+
42
+ [data-ngb-theme="bootstrap"] {
43
+ @include tokens();
44
+ }
45
+
46
+ // Inherit the nearest Bootstrap color mode, including a nested light reset.
47
+ [data-bs-theme="light"] { --_ngb-bootstrap-select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); }
48
+ [data-bs-theme="dark"] { --_ngb-bootstrap-select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); }
@@ -0,0 +1,44 @@
1
+ @use "sass:map";
2
+ // Public tokens for an explicitly scoped material theme.
3
+ @mixin tokens($overrides: ()) {
4
+ $values: (
5
+ select-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"),
6
+ primary: var(--mat-sys-primary, #6750a4),
7
+ on-primary: var(--mat-sys-on-primary, #ffffff),
8
+ surface: var(--mat-sys-surface, #fffbfe),
9
+ surface-container: var(--mat-sys-surface-container, #f3edf7),
10
+ surface-variant: var(--mat-sys-surface-container-high, #ece6f0),
11
+ on-surface: var(--mat-sys-on-surface, #1d1b20),
12
+ on-surface-variant: var(--mat-sys-on-surface-variant, #49454f),
13
+ border-color: var(--mat-sys-outline-variant, #cac4d0),
14
+ primary-hover: color-mix(in srgb, var(--mat-sys-primary, #6750a4) 88%, var(--mat-sys-on-surface, #1d1b20)),
15
+ primary-container: var(--mat-sys-primary-container, #eaddff),
16
+ focus-ring: var(--mat-sys-primary, #6750a4),
17
+ radius-sm: 4px,
18
+ radius-md: 12px,
19
+ radius-lg: 16px,
20
+ font-family: var(--mat-sys-body-medium-font, Roboto, Arial, sans-serif),
21
+ font-size-sm: var(--mat-sys-body-medium-size, 0.875rem),
22
+ density-row-height: 48px,
23
+ elevation-1: var(--mat-sys-level1, 0 1px 3px rgba(0, 0, 0, 0.2)),
24
+ elevation-2: var(--mat-sys-level2, 0 2px 6px rgba(0, 0, 0, 0.2)),
25
+ disabled-opacity: 0.38,
26
+ hover-bg: color-mix(in srgb, var(--mat-sys-on-surface, #1d1b20) 8%, var(--mat-sys-surface, #fffbfe)),
27
+ selected-bg: var(--mat-sys-secondary-container, #e8def8),
28
+ success: #198754,
29
+ on-success: #ffffff,
30
+ danger: var(--mat-sys-error, #b3261e),
31
+ on-danger: var(--mat-sys-on-error, #ffffff),
32
+ space-1: 0.25rem,
33
+ space-2: 0.5rem,
34
+ space-3: 0.75rem,
35
+ space-4: 1rem,
36
+ );
37
+ @each $name, $value in map.merge($values, $overrides) {
38
+ --ngb-#{$name}: #{$value};
39
+ }
40
+ }
41
+
42
+ [data-ngb-theme="material"] {
43
+ @include tokens();
44
+ }