@dereekb/dbx-web 13.19.0 → 13.20.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.
@@ -147,24 +147,32 @@ $calendar-content-border-consideration: 2px;
147
147
  }
148
148
 
149
149
  // Calendar color tokens (theme-aware via --mat-sys-* / --dbx-* CSS variables)
150
+ //
151
+ // Tone-based colors resolve from a public `--dbx-calendar-<name>-color` (hue)
152
+ // + `--dbx-calendar-<name>-tone` (opacity level) pair so consumers can re-tint or
153
+ // soften a state independently without redefining the full color-mix() expression.
150
154
  #{calendar.$cal-event-icon-color-var}: var(--dbx-primary-color);
151
155
  #{calendar.$cal-event-color-primary-var}: var(--mat-sys-on-primary-container);
152
156
  #{calendar.$cal-event-color-secondary-var}: var(--mat-sys-primary-container);
153
- #{calendar.$cal-border-color-var}: var(--mat-sys-outline);
157
+ // Defaults to the shared divider at full strength so calendar cell borders match
158
+ // dbx-table-view / dbx-two-column. --dbx-divider-color is already semi-transparent, so
159
+ // applying an extra tone here would double-fade it; lower --dbx-calendar-border-tone
160
+ // (or this whole calendar's --dbx-divider-color) to soften the dense grid if desired.
161
+ #{calendar.$cal-border-color-var}: color-mix(in srgb, var(--dbx-calendar-border-color, var(--dbx-divider-color)) var(--dbx-calendar-border-tone, 100%), transparent);
154
162
  #{calendar.$cal-bg-primary-var}: var(--mat-sys-background);
155
- #{calendar.$cal-bg-secondary-var}: color-mix(in srgb, var(--mat-sys-on-surface) 4%, transparent);
156
- #{calendar.$cal-bg-hover-var}: color-mix(in srgb, var(--mat-sys-on-surface) 4%, transparent);
157
- #{calendar.$cal-bg-active-var}: color-mix(in srgb, var(--dbx-accent-color) 30%, transparent);
158
- #{calendar.$cal-bg-selected-var}: color-mix(in srgb, var(--dbx-primary-color) 60%, transparent);
163
+ #{calendar.$cal-bg-secondary-var}: color-mix(in srgb, var(--dbx-calendar-secondary-color, var(--mat-sys-on-surface)) var(--dbx-calendar-secondary-tone, 4%), transparent);
164
+ #{calendar.$cal-bg-hover-var}: color-mix(in srgb, var(--dbx-calendar-hover-color, var(--mat-sys-on-surface)) var(--dbx-calendar-hover-tone, 4%), transparent);
165
+ #{calendar.$cal-bg-active-var}: color-mix(in srgb, var(--dbx-calendar-active-day-color, var(--dbx-primary-color)) var(--dbx-calendar-active-day-tone, 30%), transparent);
166
+ #{calendar.$cal-bg-selected-var}: color-mix(in srgb, var(--dbx-calendar-selected-day-color, var(--dbx-primary-color)) var(--dbx-calendar-selected-day-tone, 60%), transparent);
159
167
  #{calendar.$cal-bg-disabled-var}: var(--mat-sys-surface);
160
168
  #{calendar.$cal-bg-not-applicable-var}: var(--mat-sys-surface);
161
- #{calendar.$cal-bg-highlight-var}: color-mix(in srgb, var(--dbx-accent-color) 30%, transparent);
162
- #{calendar.$cal-today-bg-var}: color-mix(in srgb, var(--mat-sys-on-surface) 4%, transparent);
169
+ #{calendar.$cal-bg-highlight-var}: color-mix(in srgb, var(--dbx-calendar-highlight-color, var(--dbx-accent-color)) var(--dbx-calendar-highlight-tone, 30%), transparent);
170
+ #{calendar.$cal-today-bg-var}: color-mix(in srgb, var(--dbx-calendar-today-color, var(--mat-sys-on-surface)) var(--dbx-calendar-today-tone, 4%), transparent);
163
171
  #{calendar.$cal-weekend-color-var}: var(--mat-sys-on-surface);
164
172
  #{calendar.$cal-badge-color-var}: var(--dbx-accent-color);
165
173
  #{calendar.$cal-selected-var}: var(--mat-sys-on-primary);
166
174
  #{calendar.$cal-disabled-var}: var(--dbx-warn-color);
167
- #{calendar.$cal-not-applicable-var}: color-mix(in srgb, var(--mat-sys-on-surface) 30%, transparent);
175
+ #{calendar.$cal-not-applicable-var}: color-mix(in srgb, var(--dbx-calendar-not-applicable-color, var(--mat-sys-on-surface)) var(--dbx-calendar-not-applicable-tone, 30%), transparent);
168
176
  #{calendar.$cal-current-time-marker-color-var}: var(--dbx-accent-color);
169
177
  #{calendar.$cal-white-var}: var(--mat-sys-surface);
170
178
  #{calendar.$cal-gray-var}: var(--mat-sys-on-surface-variant);
@@ -6,6 +6,11 @@
6
6
  // MARK: Mixin
7
7
  @mixin core() {
8
8
  .dbx-table-view {
9
+ // Route Material's table row outline through the shared divider token so the row
10
+ // separators match dbx-two-column / dbx-calendar dividers. (Material always sets
11
+ // --mat-table-row-item-outline-color, so a fallback alone never takes effect.)
12
+ --mat-table-row-item-outline-color: var(--dbx-divider-color);
13
+
9
14
  .dbx-table-view-table-wrapper {
10
15
  max-height: var(--dbx-table-view-max-height, 600px);
11
16
  overflow: auto;
@@ -45,7 +50,7 @@
45
50
 
46
51
  // MARK: Full summary row
47
52
  .dbx-table-view-full-summary-row-container > .mat-mdc-row {
48
- border-top-color: var(--mat-table-row-item-outline-color, var(--mat-sys-outline-variant));
53
+ border-top-color: var(--mat-table-row-item-outline-color, var(--dbx-divider-color));
49
54
  border-top-width: var(--mat-table-row-item-outline-width, 1px);
50
55
  border-top-style: solid;
51
56
  }
@@ -1,5 +1,3 @@
1
- @use '../../style/theming';
2
-
3
1
  // Sections
4
2
  @mixin core() {
5
3
  .cdk-overlay-pane .mat-menu-panel {
@@ -9,8 +7,7 @@
9
7
  .cdk-overlay-pane.ng-overlay-container {
10
8
  color: var(--mat-sys-on-surface);
11
9
  background-color: var(--mat-sys-surface);
12
- @include theming.elevation(8);
13
- border: 1px solid color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent);
10
+ border-radius: var(--dbx-overlay-border-radius, var(--mat-sys-corner-medium));
14
11
  }
15
12
  }
16
13
 
@@ -18,6 +18,12 @@ $two-columns-right-padding-size: var(--dbx-padding-2);
18
18
  flex-direction: row;
19
19
  overflow-x: hidden;
20
20
 
21
+ // Top boundary separating the two-column block from the page header above it.
22
+ // Uses the shared divider token; apps can disable or restyle the boundary by
23
+ // overriding --dbx-two-column-border-top (e.g. to `none`).
24
+ box-sizing: border-box;
25
+ border-top: var(--dbx-two-column-border-top, 1px solid var(--dbx-divider-color));
26
+
21
27
  .dbx-content-container {
22
28
  margin: 0;
23
29
  }
@@ -84,7 +90,7 @@ $two-columns-right-padding-size: var(--dbx-padding-2);
84
90
 
85
91
  .dbx-two-column-head {
86
92
  padding: 0 var(--dbx-padding-2); // only padded on the left
87
- border-bottom: 1px solid var(--mat-sys-outline-variant);
93
+ border-bottom: 1px solid var(--dbx-divider-color);
88
94
  height: $two-column-navbar-height;
89
95
 
90
96
  display: flex;
@@ -33,12 +33,18 @@ $dbx-border-opacity-default: 20%;
33
33
  }
34
34
 
35
35
  /// @dbx-utility content-elevate
36
- /// @intent padded content surface lifted with elevation 2combines inner padding with a Material elevation shadow
36
+ /// @intent padded content surface lifted above its surroundingsthe mirror of `.dbx-content-pit`. Per Material 3, elevation is communicated primarily with color (the brightest `surface-bright` tone, always lighter than the pit's `surface-dim` in both light and dark) plus a soft lift shadow for protection against the background, so it reads as raised and stays clearly distinct from the recessed pit. Tonal by default — a low-opacity wash of the active dbxColor over `surface-bright`; rounded by default, opt out with `.dbx-corners-none`. Override `--dbx-content-elevate-tone` (percentage) to tune the wash, `--dbx-content-elevate-bg` to replace the background outright, or `--dbx-content-elevate-shadow` to retune/remove (`none`) the shadow.
37
37
  /// @role layout
38
- /// @see-also dbx-content-border, dbx-content-pit
38
+ /// @see-also dbx-content-border, dbx-content-pit, dbx-corners-none
39
39
  .dbx-content-elevate {
40
40
  padding: $content-border-inner-padding;
41
- @include theming.elevation(2);
41
+ }
42
+
43
+ // Elevate rounds by default. Kept OUT of the `.dbx-content-elevate` rule and
44
+ // wrapped in `:where()` so specificity stays at 0 — any single-class utility
45
+ // (`.dbx-corners-none`, `.dbx-corners-large`, or an app class) overrides it.
46
+ :where(.dbx-content-elevate) {
47
+ border-radius: theming.$dbx-content-pit-rounded-border-radius;
42
48
  }
43
49
 
44
50
  /// @dbx-utility content-box
@@ -57,7 +63,7 @@ $dbx-border-opacity-default: 20%;
57
63
  }
58
64
 
59
65
  /// @dbx-utility content-pit
60
- /// @intent recessed surface pit — `--mat-sys-surface-container` background with a `padding-4` inset, used to visually nest content (e.g. logs, JSON, quoted blocks); rounded by default, opt out with `.dbx-corners-none`
66
+ /// @intent recessed surface pit ("negative elevation") a semi-transparent tonal wash of the active dbxColor over `--mat-sys-surface-dim` (the dimmest/greyest M3 surface, the opposite end of the dim/bright pair from `.dbx-content-elevate`) so the lighter surface behind shows through, with a `padding-4` inset, used to visually nest content (e.g. logs, JSON, quoted blocks); rounded by default, opt out with `.dbx-corners-none`
61
67
  /// @role layout
62
68
  /// @see-also dbx-content-pit-scrollable, dbx-content-border, dbx-content-elevate, dbx-corners-none
63
69
  .dbx-content-pit {
@@ -86,14 +92,39 @@ $dbx-border-opacity-default: 20%;
86
92
  }
87
93
 
88
94
  /// @dbx-utility content-pit-scrollable
89
- /// @intent scrollable modifier for `.dbx-content-pit` — caps height at `theming.$dbx-content-pit-scrollable-max-height` and forces `overflow-y: scroll` for long inner content
95
+ /// @intent scrollable modifier for `.dbx-content-pit` — turns the pit into a fixed frame that clips an inner `.dbx-content-pit-scrollable-content` wrapper; the wrapper (not the frame) scrolls, so the padded/cornered surface never shifts. Drive the height via the `[scrollable]` input (which writes `--dbx-content-pit-scrollable-max-height`) or fall back to `theming.$dbx-content-pit-scrollable-max-height`.
90
96
  /// @role layout
91
97
  /// @parent content-pit
92
- /// @see-also dbx-content-pit
98
+ /// @see-also dbx-content-pit, dbx-content-pit-scrollable-content
93
99
  .dbx-content-pit-scrollable {
100
+ // Fixed frame that clips its scrolling child. Keeping the pit's padding here
101
+ // and the overflow on the inner wrapper (rather than both on this box) avoids
102
+ // the Chrome scroll-anchor / overscroll shift that moves the whole pit when
103
+ // the scroll reaches its top or bottom.
104
+ overflow: hidden;
105
+ max-width: 100%;
106
+ }
107
+
108
+ /// @dbx-utility content-pit-scrollable-content
109
+ /// @intent inner scroll region for a scrollable `.dbx-content-pit` — wrap the pit body in this element when using `[scrollable]`; it owns the height cap + `overflow-y` so the pit frame stays put. The cap reads `--dbx-content-pit-scrollable-max-height` (published per-pit by `dbxContentPit`; `none` when the pit isn't scrollable).
110
+ /// @role layout
111
+ /// @parent content-pit-scrollable
112
+ /// @see-also dbx-content-pit, dbx-content-pit-scrollable
113
+ .dbx-content-pit .dbx-content-pit-scrollable-content {
94
114
  max-height: theming.$dbx-content-pit-scrollable-max-height;
95
115
  max-width: 100%;
96
- overflow-y: scroll;
116
+ overflow-y: auto;
117
+ overscroll-behavior: contain;
118
+ overflow-anchor: none;
119
+
120
+ // Negate the pit's vertical padding so the scroll region spans the full pit
121
+ // height, then re-add it as padding here — the inset now scrolls with the
122
+ // content so it can scroll flush to the pit's top and bottom edges, instead
123
+ // of being clipped by a static padding band.
124
+ margin-top: calc(-1 * #{$pit-padding});
125
+ margin-bottom: calc(-1 * #{$pit-padding});
126
+ padding-top: $pit-padding;
127
+ padding-bottom: $pit-padding;
97
128
  }
98
129
 
99
130
  /// @dbx-utility content-pit-floating-button
@@ -110,7 +141,9 @@ $dbx-border-opacity-default: 20%;
110
141
  margin-bottom: $dbx-content-pit-floating-button-margin;
111
142
  }
112
143
 
113
- .dbx-content-pit-scrollable > .dbx-content-pit-floating-button {
144
+ // In a scrollable pit the floating button lives inside the inner scroll region
145
+ // so `position: sticky` anchors to it; pin it flush to the top of that region.
146
+ .dbx-content-pit-scrollable-content > .dbx-content-pit-floating-button {
114
147
  top: 0;
115
148
  }
116
149
 
@@ -225,19 +258,47 @@ $dbx-border-opacity-default: 20%;
225
258
  padding-bottom: var(--dbx-scroll-content-bottom-padding, #{$scroll-content-bottom-padding});
226
259
  }
227
260
 
261
+ // Recessed surface ("negative elevation"): the pit reads as a tonal step below the surfaces it
262
+ // nests in. It sits on `surface-dim` — the dimmest/greyest M3 surface tone — so it reads as a
263
+ // grey recess in light mode and the darkest surface in dark mode, the opposite end of the
264
+ // dim/bright pair from `.dbx-content-elevate`. (`surface-dim`/`surface-bright` are the one M3
265
+ // pairing whose light/dark luminance ordering is stable, so the pit is reliably dimmer than the
266
+ // elevate in both themes — the container ladder flips and can't guarantee that.) Tonal by
267
+ // default — a low-opacity wash of the active dbxColor (`--dbx-bg-color-current`, primary by
268
+ // default, driven by an ancestor/host `[dbxColor]`) laid over `surface-dim`, so the pit both
269
+ // steps down a tone AND picks up the color context, instead of being a flat grey. That dim wash is
270
+ // then rendered semi-transparent (`--dbx-content-pit-opacity`, default 50%) so the lighter surface
271
+ // behind it shows through — the pit reads as a soft, airy recess rather than a heavy grey block,
272
+ // while keeping its grey/dim character so it stays clearly dimmer than the elevate's
273
+ // `surface-bright`. Override `--dbx-content-pit-tone` (percentage) to tune the wash strength,
274
+ // `--dbx-content-pit-opacity` to make the recess lighter (lower %, more transparent) or heavier
275
+ // (higher %), or set `--dbx-content-pit-bg` to replace the background outright (e.g. on a painted
276
+ // surface where the tonal wash would clash).
228
277
  .dbx-content-pit {
229
- background: var(--mat-sys-surface-container);
278
+ background: var(--dbx-content-pit-bg, color-mix(in srgb, color-mix(in srgb, #{theming.$dbx-bg-color} var(--dbx-content-pit-tone, 8%), var(--mat-sys-surface-dim)) var(--dbx-content-pit-opacity, 50%), transparent));
230
279
  }
231
280
 
232
- // pits on a [dbxColor]-painted surface wash from the current contrast color instead of the
233
- // surface-container token, which would clash with the painted background (e.g. a dark inverse
234
- // card). Override --dbx-content-pit-color-tone (percentage) to tune the wash.
235
- .dbx-color .dbx-content-pit {
236
- background: color-mix(in srgb, #{theming.$dbx-color} var(--dbx-content-pit-color-tone, 11%), transparent);
281
+ // Elevated surface ("positive elevation"): the tonal mirror of the pit. It sits on
282
+ // `surface-bright` the brightest M3 surface tone so it reads lighter than its surroundings
283
+ // (and always lighter than the pit's `surface-dim`, in BOTH themes, since dim/bright are the one
284
+ // M3 pairing with a stable luminance ordering). It also carries a soft M3 shadow: per M3 the lift
285
+ // is communicated primarily with color, and the subtle shadow is the sanctioned "protection
286
+ // against a background" that sells the raise. Tonal by default — a low-opacity wash of the active
287
+ // dbxColor (`--dbx-bg-color-current`, primary by default, driven by an ancestor/host `[dbxColor]`)
288
+ // over `surface-bright`. Override `--dbx-content-elevate-tone` (percentage) to tune the wash,
289
+ // `--dbx-content-elevate-bg` to replace the background outright, or `--dbx-content-elevate-shadow`
290
+ // to retune/remove (`none`) the lift shadow.
291
+ .dbx-content-elevate {
292
+ background: var(--dbx-content-elevate-bg, color-mix(in srgb, #{theming.$dbx-bg-color} var(--dbx-content-elevate-tone, 8%), var(--mat-sys-surface-bright)));
293
+ box-shadow: var(--dbx-content-elevate-shadow, var(--mat-sys-level1));
237
294
  }
238
295
 
239
296
  .dbx-content-border {
240
- border: 3px dashed color-mix(in srgb, var(--dbx-border-color, var(--mat-sys-outline-variant)) var(--dbx-border-opacity, $dbx-border-opacity-default), transparent);
297
+ // Faint dashed frame keeps its own low opacity locally while sharing the global
298
+ // border base color. The computed --dbx-border-color-current re-blends with this
299
+ // overridden opacity at the point of use.
300
+ --dbx-border-opacity: #{$dbx-border-opacity-default};
301
+ border: 3px dashed var(--dbx-border-color-current);
241
302
  }
242
303
  }
243
304
 
@@ -9,16 +9,121 @@ $list-item-padded-min-height: 42px;
9
9
  overflow: hidden;
10
10
  height: 100%;
11
11
 
12
- // dbx-list (selection/standard) rows default to an M3 medium corner via the overridable
13
- // `--dbx-list-item-border-radius` token; `.dbx-list-square-items` zeroes it and the style-demo
14
- // `list-corner-*` levers re-point it. Both shape tokens resolve to the same value, so no
15
- // `border-radius` redeclaration is needed; the more specific `.dbx-list-card-items-list` item rule
16
- // deliberately wins for card lists.
17
- --mat-list-active-indicator-shape: var(--dbx-list-item-border-radius, var(--mat-sys-corner-medium, 12px));
18
- --mat-list-list-item-container-shape: var(--dbx-list-item-border-radius, var(--mat-sys-corner-medium, 12px));
12
+ // `--dbx-list-item-border-radius` (medium default) is the "how round" knob for the corners that
13
+ // actually round the first row's top, the last row's bottom, and any hovered/selected/activated
14
+ // row. Interior corners stay square so the rows read as one connected group (see the per-position
15
+ // and per-state rules below). `.dbx-list-square-items` zeroes the token and the style-demo
16
+ // `list-corner-*` levers re-point it, so both keep working. The more specific
17
+ // `.dbx-list-card-items-list` item rules deliberately win for card lists.
18
+ //
19
+ // IMPORTANT: do NOT declare `--dbx-list-item-border-radius` here — the style-demo levers set it on
20
+ // an ancestor, and a local declaration would shadow that inherited value (killing the levers).
21
+ // Instead resolve it once (with the medium fallback) into a private var the rules below consume;
22
+ // referencing it here still reads the inherited lever value, so the levers keep control.
23
+ --dbx-list-item-radius-resolved: var(--dbx-list-item-border-radius, var(--mat-sys-corner-medium, 12px));
24
+
25
+ // Hairline gap between rows. Default 1px.
26
+ --dbx-list-item-spacing: 1px;
27
+
28
+ // Selected (selection list) / activated (nav list) row tone. Defaults to the M3 primary container
29
+ // tone instead of the grey `--mat-sys-secondary-container` Material ships, with an on-tone for the
30
+ // row's text + icons.
31
+ --dbx-list-item-selected-color: var(--mat-sys-primary-container);
32
+ --dbx-list-item-selected-on-color: var(--mat-sys-on-primary-container);
33
+
34
+ // Rows are square by default; their corners round per-position / per-state below.
35
+ --mat-list-active-indicator-shape: 0;
36
+ --mat-list-list-item-container-shape: 0;
37
+
38
+ // Selected (selection-list `--selected`) + activated (nav-list `--activated`) rows pick up the
39
+ // primary tone rather than the grey default.
40
+ --mat-list-list-item-selected-container-color: var(--dbx-list-item-selected-color);
41
+ --mat-list-active-indicator-color: var(--dbx-list-item-selected-color);
42
+
43
+ // Soften the hover state-layer so hovering doesn't grey-out as heavily (M3 default is 0.08).
44
+ --mat-list-list-item-hover-state-layer-opacity: var(--dbx-list-item-hover-state-layer-opacity, 0.04);
19
45
 
20
46
  .mat-mdc-list-item {
47
+ // Focus ring follows the row's own (per-position / per-state) shape token.
21
48
  --mat-focus-indicator-border-radius: var(--mat-list-list-item-container-shape);
49
+ // Hairline gap between rows; the trailing row's gap is stripped by the :last-of-type / :only-of-type rules.
50
+ margin-bottom: var(--dbx-list-item-spacing);
51
+ }
52
+
53
+ // Angular Material's `.mat-mdc-nav-list .mat-mdc-list-item` rule pins `border-radius` to
54
+ // `--mat-list-active-indicator-shape` (which we set to 0 for square-by-default rows), so it would
55
+ // otherwise ignore the per-position / per-state `--mat-list-list-item-container-shape` we set below
56
+ // and leave nav/value-list rows square. Redeclare `border-radius` from the container-shape token at
57
+ // higher specificity so those rows round too. (Selection-list `<mat-list-option>` rows have no
58
+ // nav-list ancestor and already honor the container-shape token directly.)
59
+ .dbx-list-view .mat-mdc-list-item {
60
+ border-radius: var(--mat-list-list-item-container-shape);
61
+ }
62
+
63
+ // Connected-group corner shaping. The list rows are square by default (token = 0 above); here we
64
+ // round only the outer corners of the group and any row in an interactive/selected state.
65
+ //
66
+ // Selection list (`<mat-selection-list>` > `<mat-list-option>` siblings). NOTE: the element's CSS
67
+ // class is `.mat-mdc-selection-list` (there is no `.mat-selection-list` class), so match the host
68
+ // by its element/tag name instead.
69
+ mat-selection-list > .dbx-list-view-item:first-of-type {
70
+ --mat-list-list-item-container-shape: var(--dbx-list-item-radius-resolved) var(--dbx-list-item-radius-resolved) 0 0;
71
+ }
72
+
73
+ mat-selection-list > .dbx-list-view-item:last-of-type {
74
+ --mat-list-list-item-container-shape: 0 0 var(--dbx-list-item-radius-resolved) var(--dbx-list-item-radius-resolved);
75
+ margin-bottom: 0;
76
+ }
77
+
78
+ mat-selection-list > .dbx-list-view-item:only-of-type {
79
+ --mat-list-list-item-container-shape: var(--dbx-list-item-radius-resolved);
80
+ }
81
+
82
+ // Value/nav list (`dbx-list-view-content-group` > `dbx-anchor` rows). First/last is resolved per
83
+ // group, so a grouped list reads as one connected block per group; a single-group list rounds the
84
+ // whole list. Header/footer are `div`s, so `:first/last-of-type` of `dbx-anchor` is correct.
85
+ .dbx-list-view-group-content > dbx-anchor:first-of-type .dbx-list-view-item {
86
+ --mat-list-list-item-container-shape: var(--dbx-list-item-radius-resolved) var(--dbx-list-item-radius-resolved) 0 0;
87
+ }
88
+
89
+ .dbx-list-view-group-content > dbx-anchor:last-of-type .dbx-list-view-item {
90
+ --mat-list-list-item-container-shape: 0 0 var(--dbx-list-item-radius-resolved) var(--dbx-list-item-radius-resolved);
91
+ }
92
+
93
+ .dbx-list-view-group-content > dbx-anchor:last-of-type .dbx-list-view-item.mat-mdc-list-item {
94
+ margin-bottom: 0;
95
+ }
96
+
97
+ .dbx-list-view-group-content > dbx-anchor:only-of-type .dbx-list-view-item {
98
+ --mat-list-list-item-container-shape: var(--dbx-list-item-radius-resolved);
99
+ }
100
+
101
+ // Any hovered / focused / selected / activated row rounds all four corners (wins over the
102
+ // per-position rules above via source order at equal specificity, and the :hover/--selected
103
+ // selectors out-specify the bare position rules).
104
+ .dbx-list-view .mat-mdc-list-item:hover,
105
+ .dbx-list-view .mat-mdc-list-item:focus,
106
+ .dbx-list-view .mat-mdc-list-item.mdc-list-item--selected,
107
+ .dbx-list-view .mat-mdc-list-item.mdc-list-item--activated,
108
+ .dbx-list-view .mat-mdc-list-item[aria-selected='true'] {
109
+ --mat-list-list-item-container-shape: var(--dbx-list-item-radius-resolved);
110
+ }
111
+
112
+ // Paint the selected / activated row with the primary tone, and set an on-tone `color` so the
113
+ // injected row content stays legible (Material only recolors its own `.mdc-list-item__primary-text`
114
+ // / `__start`).
115
+ //
116
+ // A multi-select `mat-list-option` conveys selection via `aria-selected` + its checkbox — it does
117
+ // NOT get the `.mdc-list-item--selected` class (Material only adds that in single-select mode), and
118
+ // it never paints `--mat-list-list-item-selected-container-color`. So match `[aria-selected='true']`
119
+ // too and drive the tint through `--mat-list-list-item-container-color` (the row's own background
120
+ // token), which paints every selected row regardless of the missing class. Nav rows use
121
+ // `.mdc-list-item--activated`.
122
+ .dbx-list-view .mat-mdc-list-item.mdc-list-item--selected,
123
+ .dbx-list-view .mat-mdc-list-item.mdc-list-item--activated,
124
+ .dbx-list-view .mat-mdc-list-item[aria-selected='true'] {
125
+ --mat-list-list-item-container-color: var(--dbx-list-item-selected-color);
126
+ color: var(--dbx-list-item-selected-on-color);
22
127
  }
23
128
  }
24
129
 
@@ -219,6 +324,18 @@ $list-item-padded-min-height: 42px;
219
324
  margin-bottom: var(--dbx-list-card-items-list-gap);
220
325
  }
221
326
 
327
+ // Keep every card a fully-rounded standalone surface — defeat the connected-list per-position /
328
+ // per-state corner shaping defined on `.dbx-list` (those rules out-specify the card item rule
329
+ // above). Re-scoping under `.dbx-list` adds the card-ancestor class so these always win.
330
+ .dbx-list .dbx-list-view-group-content > dbx-anchor .dbx-list-view-item.mat-mdc-list-item,
331
+ .dbx-list mat-selection-list > .dbx-list-view-item.mat-mdc-list-item,
332
+ .dbx-list .dbx-list-view .mat-mdc-list-item:hover,
333
+ .dbx-list .dbx-list-view .mat-mdc-list-item:focus,
334
+ .dbx-list .dbx-list-view .mat-mdc-list-item.mdc-list-item--selected,
335
+ .dbx-list .dbx-list-view .mat-mdc-list-item.mdc-list-item--activated {
336
+ --mat-list-list-item-container-shape: var(--dbx-list-item-card-border-radius, var(--mat-sys-corner-large, calc(var(--mat-chip-container-shape-radius) * 2)));
337
+ }
338
+
222
339
  // Strip the trailing card's bottom gap. The nav-list path wraps each
223
340
  // item in a `<dbx-anchor>`; the selection-list path renders
224
341
  // `<mat-list-option>` siblings directly under `<mat-selection-list>`.
@@ -352,7 +469,7 @@ $list-item-padded-min-height: 42px;
352
469
 
353
470
  .dbx-list-view-group-header {
354
471
  color: var(--mdc-list-list-item-label-text-color);
355
- background: var(--mat-sidenav-content-background-color);
472
+ background: var(--dbx-list-view-group-header-background, var(--mat-sidenav-content-background-color));
356
473
 
357
474
  .item-details {
358
475
  color: var(--mdc-list-list-item-supporting-text-color);
@@ -21,6 +21,8 @@ $active-background-transparent-color: 0.93;
21
21
 
22
22
  > mat-sidenav {
23
23
  width: var(--dbx-sidenav-width, #{$width});
24
+ border-top-right-radius: var(--dbx-sidenav-top-corner-radius, var(--mat-sys-corner-extra-large, 24px));
25
+ border-bottom-right-radius: var(--dbx-sidenav-bottom-corner-radius, var(--mat-sys-corner-extra-large, 24px));
24
26
 
25
27
  .mat-drawer-inner-container {
26
28
  display: flex;
@@ -133,6 +135,10 @@ $active-background-transparent-color: 0.93;
133
135
  // --dbx-sidenav-mobile-width Mobile overlay drawer width (default: 80vw)
134
136
  // --dbx-sidenav-icon-width Icon rail drawer width (default: 65px)
135
137
  //
138
+ // Shape:
139
+ // --dbx-sidenav-top-corner-radius Top trailing-edge corner radius (default: --mat-sys-corner-extra-large / 24px)
140
+ // --dbx-sidenav-bottom-corner-radius Bottom trailing-edge corner radius (default: --mat-sys-corner-extra-large / 24px)
141
+ //
136
142
  // Drawer colors:
137
143
  // --dbx-sidenav-background Drawer background color
138
144
  // --dbx-sidenav-text-color Drawer text color
@@ -161,6 +161,19 @@
161
161
  #{theming.$dbx-outline-variant-color-var}: var(--mat-sys-outline-variant);
162
162
  #{theming.$dbx-error-color-var}: var(--mat-sys-error);
163
163
 
164
+ // Shared border system — base divider color + opacity knob, blended into a single
165
+ // semi-transparent border color. Components apply var(--dbx-border-color-current);
166
+ // override --dbx-border-color or --dbx-border-opacity (globally here, or locally on a
167
+ // scope) and the computed value recomputes automatically at the point of use.
168
+ #{theming.$dbx-border-color-var}: var(--mat-sys-outline-variant);
169
+ #{theming.$dbx-border-opacity-var}: 60%;
170
+ #{theming.$dbx-border-color-current-var}: color-mix(in srgb, var(--dbx-border-color) var(--dbx-border-opacity), transparent);
171
+
172
+ // Shared divider color — defaults to the computed semi-transparent border so dbx-table-view,
173
+ // dbx-two-column, dbx-calendar (and any other) dividers stay consistent. Override here for an
174
+ // app-wide divider retint, or override a component's own divider token for a one-off.
175
+ #{theming.$dbx-divider-color-var}: var(--dbx-border-color-current);
176
+
164
177
  // Curated color set (avatar initials, etc.) — selects light/dark values from the theme's theme-type.
165
178
  @include curated.curated-color-variables($theme-config);
166
179
  }
@@ -115,6 +115,16 @@
115
115
  @return ('--dbx-anchor-list-item-border-radius': $value);
116
116
  }
117
117
 
118
+ /// Builds the dbx-sidenav-only trailing-edge shape override map for a single corner-radius value.
119
+ ///
120
+ /// Backs the `sidenav-corner-*` levers: re-points the nested `mat-sidenav` drawer's top/bottom trailing-edge
121
+ /// radius tokens (`--dbx-sidenav-top-corner-radius` / `--dbx-sidenav-bottom-corner-radius`, extra-large by
122
+ /// default) together so the rounded drawer edge flips live. Independent of every other shape lever — the
123
+ /// sidenav reads its own tokens. Private to this module (`-` prefix).
124
+ @function -dbx-style-demo-sidenav-shape-map($value) {
125
+ @return ('--dbx-sidenav-top-corner-radius': $value, '--dbx-sidenav-bottom-corner-radius': $value);
126
+ }
127
+
118
128
  /// Map of demo template key -> CSS custom-property overrides emitted for that template's debug class.
119
129
  $dbx-style-demo-templates: (
120
130
  // M3 corner-radius scale levers. Each re-points the component shape tokens that `dbx-components-shapes()`
@@ -157,6 +167,12 @@ $dbx-style-demo-templates: (
157
167
  'anchor-list-corner-medium': -dbx-style-demo-anchor-list-shape-map(var(--mat-sys-corner-medium)),
158
168
  'anchor-list-corner-large': -dbx-style-demo-anchor-list-shape-map(var(--mat-sys-corner-large)),
159
169
  'anchor-list-corner-extra-large': -dbx-style-demo-anchor-list-shape-map(var(--mat-sys-corner-extra-large)),
170
+ // dbx-sidenav-only trailing-edge corner levers (own 'Sidenav Shape' toggle group), independent of every other
171
+ // shape lever (the sidenav drawer reads its own --dbx-sidenav-top/bottom-corner-radius tokens). Only the three
172
+ // requested stops are exposed: none (square), medium, and extra (extra-large, the drawer's default).
173
+ 'sidenav-corner-none': -dbx-style-demo-sidenav-shape-map(0),
174
+ 'sidenav-corner-medium': -dbx-style-demo-sidenav-shape-map(var(--mat-sys-corner-medium)),
175
+ 'sidenav-corner-extra': -dbx-style-demo-sidenav-shape-map(var(--mat-sys-corner-extra-large)),
160
176
  // Tints surfaces toward the primary color by mixing the theme's own system tokens — stays theme-correct.
161
177
  'surface-tint': (
162
178
  '--mat-sys-surface': color-mix(in srgb, var(--mat-sys-primary) 8%, var(--mat-sys-surface)),
@@ -157,6 +157,37 @@ $dbx-outline-variant-color-var: --dbx-outline-variant-color;
157
157
  /// @see --mat-sys-error
158
158
  $dbx-error-color-var: --dbx-error-color;
159
159
 
160
+ // Shared border system — a base color + an opacity knob blended into a single
161
+ // semi-transparent border color. Components apply --dbx-border-color-current and
162
+ // can tune either input token locally without touching the others.
163
+ /// Base border color for the shared semi-transparent border system. Defaults to `--mat-sys-outline-variant` (the M3 divider color). Blended with `--dbx-border-opacity` to produce `--dbx-border-color-current`.
164
+ /// @intent border base color, divider base color, outline base color
165
+ /// @role color
166
+ /// @see --mat-sys-outline-variant
167
+ /// @see --dbx-border-opacity
168
+ /// @see --dbx-border-color-current
169
+ $dbx-border-color-var: --dbx-border-color;
170
+ /// Opacity applied to `--dbx-border-color` when computing the effective border color. A percentage (e.g. `70%`). Lower it for a fainter border, raise it toward `100%` for a solid divider.
171
+ /// @intent border opacity, divider transparency, border alpha, semi-transparent border opacity
172
+ /// @role misc
173
+ /// @see --dbx-border-color
174
+ /// @see --dbx-border-color-current
175
+ $dbx-border-opacity-var: --dbx-border-opacity;
176
+ /// Effective, semi-transparent border color — a `color-mix` of `--dbx-border-color` at `--dbx-border-opacity`. Apply this directly to `border` / `border-top` / `border-bottom`. Overriding either input token (globally or on a local scope) recomputes this automatically.
177
+ /// @intent border color, divider color, semi-transparent border color, computed border color
178
+ /// @role color
179
+ /// @anti-use Don't hardcode `border: 1px solid rgba(0,0,0,0.1)`; use this token so the color and opacity stay themeable.
180
+ /// @see --dbx-border-color
181
+ /// @see --dbx-border-opacity
182
+ $dbx-border-color-current-var: --dbx-border-color-current;
183
+
184
+ /// Shared divider color for component dividers/separators (dbx-table-view summary rule, dbx-two-column boundary, dbx-calendar cell borders, etc.). Defaults to `--dbx-border-color-current` so every divider inherits the themeable semi-transparent border by default; override this single token (globally or on a local scope) to retint all dividers at once, or override a component's own divider token to retint just that one.
185
+ /// @intent divider color, separator color, shared divider, component divider color
186
+ /// @role color
187
+ /// @anti-use Don't hardcode a per-component divider color; default it to this token so dividers stay consistent and themeable.
188
+ /// @see --dbx-border-color-current
189
+ $dbx-divider-color-var: --dbx-divider-color;
190
+
160
191
  /// Per-app additional offset subtracted from the app-height base. Set to a non-zero value to shrink `--dbx-app-height` by a fixed amount (e.g. for a sticky footer). Defaults to `0px`.
161
192
  /// @intent app height offset, app height adjustment, shrink app height
162
193
  /// @role size
@@ -323,6 +354,11 @@ $dbx-outline-color: var($dbx-outline-color-var);
323
354
  $dbx-outline-variant-color: var($dbx-outline-variant-color-var);
324
355
  $dbx-error-color: var($dbx-error-color-var);
325
356
 
357
+ $dbx-border-color: var($dbx-border-color-var);
358
+ $dbx-border-opacity: var($dbx-border-opacity-var);
359
+ $dbx-border-color-current: var($dbx-border-color-current-var);
360
+ $dbx-divider-color: var($dbx-divider-color-var);
361
+
326
362
  /// Border radius for the `[dbxContentPit]`, applied by default to every pit. Defaults to `var(--mat-sys-corner-medium)`.
327
363
  /// @intent pit radius, rounded pit corner, content pit radius
328
364
  /// @role radius
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/dbx-web",
3
- "version": "13.19.0",
3
+ "version": "13.20.0",
4
4
  "sideEffects": [
5
5
  "*.scss",
6
6
  "*.css"
@@ -13,12 +13,12 @@
13
13
  "@angular/material": "^21.2.9",
14
14
  "@angular/platform-browser": "21.2.11",
15
15
  "@cantoo/pdf-lib": "^2.6.5",
16
- "@dereekb/browser": "13.19.0",
17
- "@dereekb/date": "13.19.0",
18
- "@dereekb/dbx-core": "13.19.0",
19
- "@dereekb/rxjs": "13.19.0",
20
- "@dereekb/util": "13.19.0",
21
- "@dereekb/vitest": "13.19.0",
16
+ "@dereekb/browser": "13.20.0",
17
+ "@dereekb/date": "13.20.0",
18
+ "@dereekb/dbx-core": "13.20.0",
19
+ "@dereekb/rxjs": "13.20.0",
20
+ "@dereekb/util": "13.20.0",
21
+ "@dereekb/vitest": "13.20.0",
22
22
  "@ngbracket/ngx-layout": "^21.0.0",
23
23
  "@ngrx/component-store": "^21.1.0",
24
24
  "@ngrx/effects": "^21.1.0",
@@ -818,7 +818,9 @@ declare class DbxStyleDemoTypeRolesSectionComponent {
818
818
  * `'Shape'` toggle group, so only one is active at a time; `pill-controls` (`'Controls'`), `button-corner-*`
819
819
  * (`'Button Shape'`), `list-corner-*` (`'List Shape'`) and `anchor-list-corner-*` (`'Anchor List Shape'`) each live in
820
820
  * their own group so they compose on top of a corner lever instead of radio-excluding it — their debug classes are
821
- * emitted after `corner-shape-*` / `pill-controls` so they win the shape tokens they share.
821
+ * emitted after `corner-shape-*` / `pill-controls` so they win the shape tokens they share. The `sidenav-corner-*`
822
+ * levers (`'Sidenav Shape'`) re-round the nested `mat-sidenav` drawer's own trailing-edge tokens and are independent
823
+ * of every other shape lever.
822
824
  */
823
825
  declare const DBX_WEB_STYLE_DEMO_TEMPLATES: DbxStyleDemoStyleTemplate[];
824
826
  /**
@@ -827,7 +829,8 @@ declare const DBX_WEB_STYLE_DEMO_TEMPLATES: DbxStyleDemoStyleTemplate[];
827
829
  * The `corner-shape-*` levers share the `'Shape'` group (mutually exclusive); the component-scoped `button-corner-*`
828
830
  * (`'Button Shape'`), `list-corner-*` (`'List Shape'`) and `anchor-list-corner-*` (`'Anchor List Shape'`) levers are
829
831
  * mutually exclusive within their own groups but compose with `'Shape'` and `'Controls'`, letting a global corner
830
- * preset be overridden for just buttons, just `dbx-list` rows, or just `dbx-anchor-list` (nav) rows. `pill-controls`
832
+ * preset be overridden for just buttons, just `dbx-list` rows, or just `dbx-anchor-list` (nav) rows. The
833
+ * `sidenav-corner-*` levers (`'Sidenav Shape'`) re-round the `dbx-sidenav` drawer edge independently. `pill-controls`
831
834
  * (`'Controls'`), `surface-tint` and `vivid-primary` are independent toggles in their own groups.
832
835
  */
833
836
  declare const DBX_WEB_STYLE_DEMO_TEMPLATE_TOGGLES: DbxStyleDemoTemplateToggle[];
@@ -2448,9 +2448,14 @@ type DbxContentPitScrollableHeightSetting = 'small' | 'medium' | 'large';
2448
2448
  * Wraps content in a recessed "pit" container with optional scrollable overflow and rounded corners.
2449
2449
  * Useful for displaying bounded content areas such as lists or previews with a constrained height.
2450
2450
  *
2451
- * Pits round their corners by default. Pass `[rounded]="false"` to square the pit — this applies the
2451
+ * Pits round their corners by default. Pass `[square]="true"` to square the pit — this applies the
2452
2452
  * common `.dbx-corners-none` opt-out utility rather than a pit-specific class.
2453
2453
  *
2454
+ * When `[scrollable]` is set the pit frame (padding, background, corners) stays fixed and an inner
2455
+ * `.dbx-content-pit-scrollable-content` wrapper does the scrolling — wrap the body in that element so
2456
+ * the frame doesn't shift at the scroll extremes. The resolved max height is published as the
2457
+ * `--dbx-content-pit-scrollable-max-height` custom property, which the inner wrapper reads.
2458
+ *
2454
2459
  * @dbxWebComponent
2455
2460
  * @dbxWebSlug content-pit
2456
2461
  * @dbxWebCategory layout
@@ -2467,10 +2472,11 @@ type DbxContentPitScrollableHeightSetting = 'small' | 'medium' | 'large';
2467
2472
  */
2468
2473
  declare class DbxContentPitDirective {
2469
2474
  readonly scrollable: _angular_core.InputSignal<Maybe<DbxContentPitScrollableInput>>;
2470
- readonly rounded: _angular_core.InputSignal<boolean>;
2475
+ readonly square: _angular_core.InputSignal<boolean>;
2471
2476
  readonly scrollableHeightSignal: _angular_core.Signal<string | null>;
2477
+ readonly scrollableMaxHeightSignal: _angular_core.Signal<string>;
2472
2478
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DbxContentPitDirective, never>;
2473
- static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DbxContentPitDirective, "dbx-content-pit, [dbxContentPit]", never, { "scrollable": { "alias": "scrollable"; "required": false; "isSignal": true; }; "rounded": { "alias": "rounded"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2479
+ static ɵdir: _angular_core.ɵɵDirectiveDeclaration<DbxContentPitDirective, "dbx-content-pit, [dbxContentPit]", never, { "scrollable": { "alias": "scrollable"; "required": false; "isSignal": true; }; "square": { "alias": "square"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
2474
2480
  }
2475
2481
 
2476
2482
  /**