@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/CHANGELOG.md +38 -0
- package/README.md +9 -0
- package/RELEASE_NOTES.md +41 -23
- package/THEMING.md +271 -0
- package/fesm2022/angular-bootstrap-ngbootstrap.mjs +605 -90
- package/fesm2022/angular-bootstrap-ngbootstrap.mjs.map +1 -1
- package/package.json +15 -5
- package/src/ai/README.md +134 -0
- package/src/styles/_controls.scss +86 -0
- package/src/styles/_drag-drop.scss +3 -0
- package/src/styles/_tokens.scss +6 -0
- package/src/styles/integrations/tailwind.css +37 -0
- package/src/styles/styles.css +12 -19
- package/src/styles/themes/_bootstrap.scss +48 -0
- package/src/styles/themes/_material.scss +44 -0
- package/src/styles/themes/_presets.scss +344 -0
- package/src/styles/themes/_tailwind.scss +32 -0
- package/src/styles/themes.scss +3 -0
- package/types/angular-bootstrap-ngbootstrap.d.ts +155 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-bootstrap/ngbootstrap",
|
|
3
|
-
"version": "2.
|
|
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
|
}
|
package/src/ai/README.md
ADDED
|
@@ -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,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
|
+
}
|
package/src/styles/styles.css
CHANGED
|
@@ -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:
|
|
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:
|
|
22
|
-
box-shadow: 0 0 0 .2rem
|
|
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:
|
|
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
|
+
}
|