@servicetitan/navigation 14.2.0 → 14.4.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/dist/components/titan-layout/__tests__/layout-sidebar-links-internal.test.d.ts +2 -0
- package/dist/components/titan-layout/__tests__/layout-sidebar-links-internal.test.d.ts.map +1 -0
- package/dist/components/titan-layout/__tests__/navigation-catalog-reset.test.d.ts +2 -0
- package/dist/components/titan-layout/__tests__/navigation-catalog-reset.test.d.ts.map +1 -0
- package/dist/components/titan-layout/interface.d.ts +66 -0
- package/dist/components/titan-layout/interface.d.ts.map +1 -1
- package/dist/components/titan-layout/interface.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts +3 -0
- package/dist/components/titan-layout/layout-sidebar-links-internal.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar-links-internal.js +58 -13
- package/dist/components/titan-layout/layout-sidebar-links-internal.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.d.ts +14 -0
- package/dist/components/titan-layout/layout-sidebar.d.ts.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.js +169 -97
- package/dist/components/titan-layout/layout-sidebar.js.map +1 -1
- package/dist/components/titan-layout/layout-sidebar.module.less +230 -144
- package/dist/components/titan-layout/layout-sidebar.module.less.d.ts +16 -5
- package/dist/components/titan-layout/navigation-catalog/index.d.ts +3 -0
- package/dist/components/titan-layout/navigation-catalog/index.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/index.js +4 -0
- package/dist/components/titan-layout/navigation-catalog/index.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.d.ts +8 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.js +88 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-footer.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.d.ts +21 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js +138 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less +89 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less.d.ts +9 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.d.ts +14 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js +343 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.js.map +1 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less +379 -0
- package/dist/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +26 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.d.ts +12 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.d.ts.map +1 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.js +48 -0
- package/dist/components/titan-layout/navigation-scroll-indicators.js.map +1 -0
- package/dist/components/titan-layout/titan-layout.d.ts +29 -1
- package/dist/components/titan-layout/titan-layout.d.ts.map +1 -1
- package/dist/components/titan-layout/titan-layout.js +46 -6
- package/dist/components/titan-layout/titan-layout.js.map +1 -1
- package/dist/components/titan-layout/titan-layout.module.less +2 -1
- package/dist/components/titan-layout/use-navigation-scroll.d.ts +20 -0
- package/dist/components/titan-layout/use-navigation-scroll.d.ts.map +1 -0
- package/dist/components/titan-layout/use-navigation-scroll.js +140 -0
- package/dist/components/titan-layout/use-navigation-scroll.js.map +1 -0
- package/dist/utils/__tests__/catalog-groups.test.d.ts +2 -0
- package/dist/utils/__tests__/catalog-groups.test.d.ts.map +1 -0
- package/dist/utils/__tests__/navigation-notifications.test.d.ts +2 -0
- package/dist/utils/__tests__/navigation-notifications.test.d.ts.map +1 -0
- package/dist/utils/__tests__/submenu-state.test.d.ts +2 -0
- package/dist/utils/__tests__/submenu-state.test.d.ts.map +1 -0
- package/dist/utils/catalog-groups.d.ts +11 -0
- package/dist/utils/catalog-groups.d.ts.map +1 -0
- package/dist/utils/catalog-groups.js +66 -0
- package/dist/utils/catalog-groups.js.map +1 -0
- package/dist/utils/navigation-notifications.d.ts +21 -0
- package/dist/utils/navigation-notifications.d.ts.map +1 -0
- package/dist/utils/navigation-notifications.js +39 -0
- package/dist/utils/navigation-notifications.js.map +1 -0
- package/dist/utils/side-nav.js +3 -1
- package/dist/utils/side-nav.js.map +1 -1
- package/dist/utils/submenu-state.d.ts +3 -0
- package/dist/utils/submenu-state.d.ts.map +1 -0
- package/dist/utils/submenu-state.js +15 -0
- package/dist/utils/submenu-state.js.map +1 -0
- package/package.json +2 -2
- package/src/components/titan-layout/__tests__/layout-sidebar-links-internal.test.tsx +225 -0
- package/src/components/titan-layout/__tests__/navigation-catalog-reset.test.tsx +190 -0
- package/src/components/titan-layout/interface.ts +73 -0
- package/src/components/titan-layout/layout-sidebar-links-internal.tsx +86 -14
- package/src/components/titan-layout/layout-sidebar.module.less +230 -144
- package/src/components/titan-layout/layout-sidebar.module.less.d.ts +16 -5
- package/src/components/titan-layout/layout-sidebar.tsx +193 -117
- package/src/components/titan-layout/navigation-catalog/index.ts +2 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-footer.tsx +88 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less +89 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.module.less.d.ts +9 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog-trigger.tsx +170 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less +379 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.module.less.d.ts +26 -0
- package/src/components/titan-layout/navigation-catalog/navigation-catalog.tsx +430 -0
- package/src/components/titan-layout/navigation-scroll-indicators.tsx +80 -0
- package/src/components/titan-layout/titan-layout.module.less +2 -1
- package/src/components/titan-layout/titan-layout.tsx +81 -5
- package/src/components/titan-layout/use-navigation-scroll.ts +145 -0
- package/src/utils/__tests__/catalog-groups.test.ts +97 -0
- package/src/utils/__tests__/navigation-notifications.test.ts +70 -0
- package/src/utils/__tests__/submenu-state.test.ts +39 -0
- package/src/utils/catalog-groups.ts +57 -0
- package/src/utils/navigation-notifications.ts +59 -0
- package/src/utils/side-nav.ts +1 -1
- package/src/utils/submenu-state.ts +16 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
@import (reference) '@servicetitan/tokens/core/tokens.less';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Scoped to `.anvil2.anvil2` so these rules outrank anvil2's own.
|
|
5
|
+
*
|
|
6
|
+
* anvil2 nests every component rule under `.anvil2`, giving it two classes of specificity,
|
|
7
|
+
* which a bare class here loses to. Doubling the scope wins outright and leaves the selectors
|
|
8
|
+
* inside it plain, rather than each one having to defend itself with `!important`.
|
|
9
|
+
*/
|
|
10
|
+
:global(.anvil2.anvil2) {
|
|
11
|
+
// Four readable columns fit the desktop dialog; narrower dialogs wrap whole groups.
|
|
12
|
+
@catalog-column: 15rem;
|
|
13
|
+
@catalog-gap: 1.5rem;
|
|
14
|
+
@catalog-padding: @spacing-2;
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
* The rail's own background, from `@bg-color` in `@servicetitan/navigation`'s
|
|
18
|
+
* `layout-sidebar.module.less`, its hover on top of it, and the trigger chip this catalog opens
|
|
19
|
+
* from.
|
|
20
|
+
*
|
|
21
|
+
* Repeated as literals because they are LESS variables private to that package, not custom
|
|
22
|
+
* properties, so there is nothing to reference at runtime. The rail paints them unconditionally and
|
|
23
|
+
* has done since it was written, so the risk of drift is low and the failure is cosmetic.
|
|
24
|
+
*
|
|
25
|
+
* They are here because the catalog is the rail's menu and should read as part of it. anvil2's dark
|
|
26
|
+
* mode is a neutral grey (#1a1a1a) and the rail is a navy, so taking the mode alone would put two
|
|
27
|
+
* different darks side by side on screen.
|
|
28
|
+
*
|
|
29
|
+
* Translucent white rather than a mixed-down navy throughout: a translucent layer tints whatever it
|
|
30
|
+
* covers, so these keep the surface's hue and only lift it, which is what makes them read as part of
|
|
31
|
+
* the same surface rather than as patches on it.
|
|
32
|
+
*/
|
|
33
|
+
@rail-surface: #0f1d26;
|
|
34
|
+
@rail-hover: rgba(255, 255, 255, 0.08);
|
|
35
|
+
@rail-field: rgba(255, 255, 255, 0.06);
|
|
36
|
+
@rail-field-border: rgba(255, 255, 255, 0.16);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Repaints the dialog in the rail's navy instead of anvil2's neutral dark, and lightens its
|
|
40
|
+
* backdrop instead of anvil2's default near-black scrim.
|
|
41
|
+
*
|
|
42
|
+
* `--a2-dialog-background-color`, `--a2-dialog-border-color` and `--a2-dialog-backdrop-color` are
|
|
43
|
+
* the hooks anvil2's Dialog reads inside its own `var()` chains, ahead of the tokens they otherwise
|
|
44
|
+
* fall back to. Setting those rather than `background-color`/`::backdrop` directly means no
|
|
45
|
+
* specificity contest — nothing else defines these properties, they are only read — and the
|
|
46
|
+
* background one reaches the header and content panels too, which paint from the same variable.
|
|
47
|
+
*
|
|
48
|
+
* The border goes with the background. Left alone it resolves to a flat `#404040`, which is the
|
|
49
|
+
* last neutral grey on the surface and outlines the whole dialog in it. The same translucent white
|
|
50
|
+
* the field's edge uses puts the outline back in the surface's own colour.
|
|
51
|
+
*
|
|
52
|
+
* `--a2-color-neutral-0` for the backdrop is the same override anvil2's own `fullScreen` variant
|
|
53
|
+
* uses in place of its default `neutral-900` — a supported swap, not a hack.
|
|
54
|
+
*/
|
|
55
|
+
.dialog {
|
|
56
|
+
--a2-dialog-background-color: @rail-surface;
|
|
57
|
+
--a2-dialog-border-color: @rail-field-border;
|
|
58
|
+
--a2-dialog-backdrop-color: var(--a2-color-neutral-0, #ffffff);
|
|
59
|
+
|
|
60
|
+
/*
|
|
61
|
+
* Pins the dialog's size to the viewport instead of its content, so opening it, searching, and
|
|
62
|
+
* clearing the search all leave it exactly where it was.
|
|
63
|
+
*
|
|
64
|
+
* anvil2 centres the dialog by giving it `inset: 0` and `margin: auto`; overriding `top` and
|
|
65
|
+
* `height` here (with the matching margins zeroed so they cannot re-introduce the auto-centring
|
|
66
|
+
* they replace) fixes the vertical position and size, while `left`/`right` stay on the anvil2
|
|
67
|
+
* default and keep centring horizontally. `--nav-offset-top` is the rail's own top-nav height
|
|
68
|
+
* custom property, already threaded through this package for the same purpose.
|
|
69
|
+
*
|
|
70
|
+
* `> *` reaches anvil2's own content wrapper, which otherwise sizes to its content rather than
|
|
71
|
+
* to this now-fixed height — there is no class hook for it, but the dialog only ever has that
|
|
72
|
+
* one child.
|
|
73
|
+
*/
|
|
74
|
+
top: calc(var(--nav-offset-top) + 10px);
|
|
75
|
+
bottom: auto;
|
|
76
|
+
height: calc(100vh - 112px);
|
|
77
|
+
margin-top: @spacing-0;
|
|
78
|
+
margin-bottom: @spacing-0;
|
|
79
|
+
|
|
80
|
+
> * {
|
|
81
|
+
height: 100%;
|
|
82
|
+
padding-bottom: @spacing-0;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Stacks the search above the columns.
|
|
88
|
+
*
|
|
89
|
+
* `Dialog.Content` is `display: flex` with the default row direction, so its children line up
|
|
90
|
+
* side by side. Without this the search field became a flex item next to the column block and sat
|
|
91
|
+
* in the left third of the dialog, reading as a fourth column.
|
|
92
|
+
*/
|
|
93
|
+
.body {
|
|
94
|
+
container-type: inline-size;
|
|
95
|
+
display: flex;
|
|
96
|
+
flex: 1;
|
|
97
|
+
min-width: 0;
|
|
98
|
+
flex-direction: column;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Lets the results area, rather than the dialog's own scroller, take the overflow.
|
|
103
|
+
*
|
|
104
|
+
* `Dialog.Content` is a flex item of that scroller, and a flex item will not shrink below its
|
|
105
|
+
* content by default. Without this the scroller is the thing that overflows, which scrolls the
|
|
106
|
+
* search field off the top along with the results.
|
|
107
|
+
*/
|
|
108
|
+
.content {
|
|
109
|
+
min-height: 0;
|
|
110
|
+
padding-inline: @catalog-padding;
|
|
111
|
+
padding-bottom: @spacing-0;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Results scroll above the full-width footer; allow its content to wrap on narrow screens.
|
|
115
|
+
.footer {
|
|
116
|
+
box-sizing: border-box;
|
|
117
|
+
min-height: 56px;
|
|
118
|
+
flex: none;
|
|
119
|
+
flex-wrap: wrap;
|
|
120
|
+
align-items: center;
|
|
121
|
+
justify-content: center;
|
|
122
|
+
gap: @spacing-1 @spacing-3;
|
|
123
|
+
padding: 12px @catalog-padding;
|
|
124
|
+
background-color: var(--a2-background-color-secondary);
|
|
125
|
+
text-align: center;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.footerActions {
|
|
129
|
+
display: flex;
|
|
130
|
+
flex: none;
|
|
131
|
+
gap: @spacing-1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/*
|
|
135
|
+
* Matched to the rail's own "Go to" field, which is what the user clicked to get here — the same
|
|
136
|
+
* control, so it should not change colour on the way.
|
|
137
|
+
*
|
|
138
|
+
* anvil2's field is an opaque neutral (#1a1a1a on a #545454 border) which, like the row hover, is
|
|
139
|
+
* the right lightness but the wrong hue against the navy. The rail's translucent white gives the
|
|
140
|
+
* same lift while keeping the surface's colour, and these are its exact values.
|
|
141
|
+
*/
|
|
142
|
+
.search {
|
|
143
|
+
--a2-text-field-input-wrapper-background-color: @rail-field;
|
|
144
|
+
--a2-text-field-input-wrapper-border-color-default: @rail-field-border;
|
|
145
|
+
|
|
146
|
+
width: 100%;
|
|
147
|
+
margin-bottom: 1.5rem;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/*
|
|
151
|
+
* Fills whatever the now fixed-height dialog leaves under the search field, instead of sizing to
|
|
152
|
+
* its own content, so browse, a narrowed search, and the empty state all hold the same height.
|
|
153
|
+
*/
|
|
154
|
+
.results {
|
|
155
|
+
flex: 1;
|
|
156
|
+
min-height: 0;
|
|
157
|
+
// Overlay scrollbars ignore scrollbar-gutter; keep the last column's stars clear of them.
|
|
158
|
+
padding-right: @spacing-2;
|
|
159
|
+
overflow-y: auto;
|
|
160
|
+
|
|
161
|
+
/*
|
|
162
|
+
* Reserve the scrollbar's width whether or not it is showing, so a query that stops the results
|
|
163
|
+
* overflowing does not shift the columns sideways as the scrollbar disappears.
|
|
164
|
+
*/
|
|
165
|
+
scrollbar-gutter: stable;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Match the input's width; let either scrollbar style occupy the dialog's right padding.
|
|
169
|
+
.searchResults {
|
|
170
|
+
padding-right: @spacing-0;
|
|
171
|
+
margin-right: -@catalog-padding;
|
|
172
|
+
scrollbar-gutter: auto;
|
|
173
|
+
|
|
174
|
+
> div {
|
|
175
|
+
width: 100cqw;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Each group owns a column, regardless of its length. In particular, Projects & Field starts
|
|
181
|
+
* beside Demand rather than flowing beneath it. The minimum shrinks to the available width
|
|
182
|
+
* on small screens. Search uses a plain single-column list instead of this grid.
|
|
183
|
+
*/
|
|
184
|
+
.columns {
|
|
185
|
+
display: grid;
|
|
186
|
+
grid-template-columns: repeat(auto-fill, minmax(min(100%, @catalog-column), 1fr));
|
|
187
|
+
gap: @catalog-gap;
|
|
188
|
+
overflow: hidden;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/*
|
|
192
|
+
* Grid items stretch to the tallest group so dividers span the row. Place each divider in the
|
|
193
|
+
* preceding gap; the grid clips the one before its first column, including after wrapping.
|
|
194
|
+
*/
|
|
195
|
+
.group {
|
|
196
|
+
position: relative;
|
|
197
|
+
min-width: 0;
|
|
198
|
+
|
|
199
|
+
&::before {
|
|
200
|
+
position: absolute;
|
|
201
|
+
top: 0;
|
|
202
|
+
bottom: 0;
|
|
203
|
+
left: -(@catalog-gap / 2);
|
|
204
|
+
width: 1px;
|
|
205
|
+
background: rgba(255, 255, 255, 0.12);
|
|
206
|
+
content: '';
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Keep eyebrow medium typography and use the catalog's specified subdued colour.
|
|
211
|
+
.groupTitle {
|
|
212
|
+
--a2-text-foreground-color-subdued: @color-neutral-70;
|
|
213
|
+
|
|
214
|
+
display: block;
|
|
215
|
+
padding: @spacing-0 0.5rem;
|
|
216
|
+
margin-bottom: 0.5rem;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.module-group {
|
|
220
|
+
margin-bottom: 0.75rem;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Match the sidebar's small, subdued headings and spacing above each page group.
|
|
224
|
+
.submenuTitle {
|
|
225
|
+
--a2-text-foreground-color-subdued: @color-neutral-70;
|
|
226
|
+
|
|
227
|
+
display: block;
|
|
228
|
+
padding: 12px @spacing-1 @spacing-half 2rem;
|
|
229
|
+
margin: @spacing-0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.row {
|
|
233
|
+
display: flex;
|
|
234
|
+
align-items: center;
|
|
235
|
+
gap: 0.25rem;
|
|
236
|
+
border-radius: var(--a2-border-radius-medium, 4px);
|
|
237
|
+
|
|
238
|
+
// Share the highlight while keeping the link and favorite button independently focusable.
|
|
239
|
+
&:hover,
|
|
240
|
+
&:has(:focus-visible) {
|
|
241
|
+
background-color: @rail-hover;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.link {
|
|
246
|
+
display: flex;
|
|
247
|
+
flex: 1;
|
|
248
|
+
min-width: 0;
|
|
249
|
+
align-items: center;
|
|
250
|
+
gap: 0.5rem;
|
|
251
|
+
padding: 0.25rem 0.5rem;
|
|
252
|
+
border-radius: var(--a2-border-radius-medium, 4px);
|
|
253
|
+
text-decoration: none;
|
|
254
|
+
|
|
255
|
+
&:hover,
|
|
256
|
+
&:focus-visible {
|
|
257
|
+
text-decoration: none;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.moduleIcon {
|
|
262
|
+
flex: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/*
|
|
266
|
+
* Level 2 of three, and the anchor of the scale: full-strength foreground at the body size, which
|
|
267
|
+
* everything else is set against. The destination is the usable part of the row, so it carries the
|
|
268
|
+
* weight and the brighter colour; the category heading above it is deliberately quieter.
|
|
269
|
+
*/
|
|
270
|
+
.moduleTitle {
|
|
271
|
+
flex: 1;
|
|
272
|
+
min-width: 0;
|
|
273
|
+
overflow: hidden;
|
|
274
|
+
text-overflow: ellipsis;
|
|
275
|
+
white-space: nowrap;
|
|
276
|
+
color: var(--a2-foreground-color-default, light-dark(#040404, #ffffff));
|
|
277
|
+
font-weight: var(--a2-font-weight-semibold, 600);
|
|
278
|
+
line-height: 1rem;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// As in the sidebar, page text sits 8px farther in than its group heading.
|
|
282
|
+
.childLink {
|
|
283
|
+
padding: @spacing-1 @spacing-1 @spacing-1 2.5rem;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Match the expanded sidebar's child-page typography.
|
|
287
|
+
.childTitle {
|
|
288
|
+
flex: 1;
|
|
289
|
+
min-width: 0;
|
|
290
|
+
overflow: hidden;
|
|
291
|
+
text-overflow: ellipsis;
|
|
292
|
+
white-space: nowrap;
|
|
293
|
+
color: var(--a2-foreground-color-default, light-dark(#040404, #ffffff));
|
|
294
|
+
font-size: @typescale-2;
|
|
295
|
+
font-weight: @font-weight-semibold;
|
|
296
|
+
line-height: 20px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/*
|
|
300
|
+
* anvil2 positions a Badge absolutely with a translate, because its usual job is to overlay the
|
|
301
|
+
* corner of an icon. Here it is a sibling in a row and has to sit in the flow, so the position
|
|
302
|
+
* and the transform are both undone — the same override the rail applies to its own submenu
|
|
303
|
+
* counters in `layout-sidebar.module.less`.
|
|
304
|
+
*
|
|
305
|
+
* No `!important` needed: anvil2 nests its rule as `.anvil2 ._badge_x`, and the enclosing
|
|
306
|
+
* `.anvil2.anvil2` scope already outranks that.
|
|
307
|
+
*
|
|
308
|
+
* `flex: none` because the title beside it takes the slack — without it a long name would
|
|
309
|
+
* squeeze the count instead of truncating itself, and a truncated count is worse than a
|
|
310
|
+
* truncated name.
|
|
311
|
+
*/
|
|
312
|
+
.badge[data-anv][data-anv] {
|
|
313
|
+
position: relative;
|
|
314
|
+
transform: none;
|
|
315
|
+
flex: none;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 2rem to match the star button's box, so both align down the column. Always visible, unlike
|
|
319
|
+
// the star, and #707070 to match the Pantheon frame.
|
|
320
|
+
.lock {
|
|
321
|
+
display: inline-flex;
|
|
322
|
+
width: 2rem;
|
|
323
|
+
height: 2rem;
|
|
324
|
+
flex: none;
|
|
325
|
+
align-items: center;
|
|
326
|
+
justify-content: center;
|
|
327
|
+
color: var(--a2-color-neutral-500, #707070);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.star {
|
|
331
|
+
flex: none;
|
|
332
|
+
opacity: 0;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Mouse clicks retain focus after leaving the row; only keyboard focus should reveal a star.
|
|
336
|
+
.row:hover .star,
|
|
337
|
+
.row:has(:focus-visible) .star {
|
|
338
|
+
opacity: 0.5;
|
|
339
|
+
|
|
340
|
+
&:hover,
|
|
341
|
+
&:focus-visible {
|
|
342
|
+
opacity: 1;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/*
|
|
347
|
+
* After the hover rules, which match at the same specificity, so a pinned star stays lit.
|
|
348
|
+
*
|
|
349
|
+
* The token's dark value, `yellow-300`, is a pale gold that clears the surface below at 13.5:1.
|
|
350
|
+
* Note that the light value on the other side of this token is `yellow-500` (#ffbe00), which only
|
|
351
|
+
* manages 1.66:1 on white — under the 3:1 WCAG 1.4.11 asks of a graphical control. That branch is
|
|
352
|
+
* unreachable while the catalog follows the rail, but it is the thing to fix first if this surface
|
|
353
|
+
* is ever made light.
|
|
354
|
+
*/
|
|
355
|
+
.starActive,
|
|
356
|
+
.row:hover .starActive,
|
|
357
|
+
.row:has(:focus-visible) .starActive {
|
|
358
|
+
color: var(--a2-status-color-warning, light-dark(#ffbe00, #ffe278));
|
|
359
|
+
opacity: 1;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/*
|
|
363
|
+
* Centred in the fixed-height results area rather than left stranded against its top edge.
|
|
364
|
+
*
|
|
365
|
+
* `border-box` so the padding is counted inside the `100%`. Under the default `content-box` the
|
|
366
|
+
* vertical padding is added to it, and the message ended up 64px taller than the area it sits in —
|
|
367
|
+
* enough to raise a scrollbar next to a single line of text.
|
|
368
|
+
*/
|
|
369
|
+
.empty {
|
|
370
|
+
display: flex;
|
|
371
|
+
box-sizing: border-box;
|
|
372
|
+
height: 100%;
|
|
373
|
+
align-items: center;
|
|
374
|
+
justify-content: center;
|
|
375
|
+
padding: 2rem 0.5rem;
|
|
376
|
+
text-align: center;
|
|
377
|
+
color: var(--a2-foreground-color-subdued, light-dark(#707070, #c4c4c4));
|
|
378
|
+
}
|
|
379
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export const __esModule: true;
|
|
2
|
+
export const badge: string;
|
|
3
|
+
export const body: string;
|
|
4
|
+
export const childLink: string;
|
|
5
|
+
export const childTitle: string;
|
|
6
|
+
export const columns: string;
|
|
7
|
+
export const content: string;
|
|
8
|
+
export const dialog: string;
|
|
9
|
+
export const empty: string;
|
|
10
|
+
export const footer: string;
|
|
11
|
+
export const footerActions: string;
|
|
12
|
+
export const group: string;
|
|
13
|
+
export const groupTitle: string;
|
|
14
|
+
export const link: string;
|
|
15
|
+
export const lock: string;
|
|
16
|
+
export const moduleGroup: string;
|
|
17
|
+
export const moduleIcon: string;
|
|
18
|
+
export const moduleTitle: string;
|
|
19
|
+
export const results: string;
|
|
20
|
+
export const row: string;
|
|
21
|
+
export const search: string;
|
|
22
|
+
export const searchResults: string;
|
|
23
|
+
export const star: string;
|
|
24
|
+
export const starActive: string;
|
|
25
|
+
export const submenuTitle: string;
|
|
26
|
+
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export declare function NavigationScrollIndicators({ expanded, above, below, hasContentAbove, hasContentBelow, aboveIndicatorRef, belowIndicatorRef, onReveal, }: {
|
|
3
|
+
expanded: boolean;
|
|
4
|
+
above: number;
|
|
5
|
+
below: number;
|
|
6
|
+
hasContentAbove: boolean;
|
|
7
|
+
hasContentBelow: boolean;
|
|
8
|
+
aboveIndicatorRef: RefObject<HTMLDivElement>;
|
|
9
|
+
belowIndicatorRef: RefObject<HTMLDivElement>;
|
|
10
|
+
onReveal(direction: 'above' | 'below'): void;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=navigation-scroll-indicators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation-scroll-indicators.d.ts","sourceRoot":"","sources":["../../../src/components/titan-layout/navigation-scroll-indicators.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAY,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5C,wBAAgB,0BAA0B,CAAC,EACvC,QAAQ,EACR,KAAK,EACL,KAAK,EACL,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,QAAQ,GACX,EAAE;IACC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,iBAAiB,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IAC7C,iBAAiB,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IAC7C,QAAQ,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;CAChD,2CAsDA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button } from '@servicetitan/anvil2';
|
|
3
|
+
import SvgArrowDown from '@servicetitan/anvil2/assets/icons/material/round/arrow_downward.svg';
|
|
4
|
+
import SvgArrowUp from '@servicetitan/anvil2/assets/icons/material/round/arrow_upward.svg';
|
|
5
|
+
import classNames from 'classnames';
|
|
6
|
+
import { Fragment } from 'react';
|
|
7
|
+
import * as Styles from './layout-sidebar.module.less';
|
|
8
|
+
export function NavigationScrollIndicators({ expanded, above, below, hasContentAbove, hasContentBelow, aboveIndicatorRef, belowIndicatorRef, onReveal }) {
|
|
9
|
+
return /*#__PURE__*/ _jsx(Fragment, {
|
|
10
|
+
children: [
|
|
11
|
+
'above',
|
|
12
|
+
'below'
|
|
13
|
+
].map((direction)=>{
|
|
14
|
+
const isAbove = direction === 'above';
|
|
15
|
+
const count = isAbove ? above : below;
|
|
16
|
+
const hasContent = isAbove ? hasContentAbove : hasContentBelow;
|
|
17
|
+
const label = `${count} ${count === 1 ? 'notification' : 'notifications'}`;
|
|
18
|
+
return /*#__PURE__*/ _jsxs(Fragment, {
|
|
19
|
+
children: [
|
|
20
|
+
hasContent && /*#__PURE__*/ _jsx("div", {
|
|
21
|
+
className: classNames(Styles.scrollShadow, isAbove ? Styles.scrollShadowAbove : Styles.scrollShadowBelow)
|
|
22
|
+
}),
|
|
23
|
+
count > 0 && /*#__PURE__*/ _jsx("div", {
|
|
24
|
+
ref: isAbove ? aboveIndicatorRef : belowIndicatorRef,
|
|
25
|
+
className: classNames(Styles.scrollIndicator, isAbove ? Styles.scrollIndicatorAbove : Styles.scrollIndicatorBelow),
|
|
26
|
+
children: /*#__PURE__*/ _jsx(Button, {
|
|
27
|
+
appearance: "secondary",
|
|
28
|
+
size: "xsmall",
|
|
29
|
+
icon: {
|
|
30
|
+
before: isAbove ? SvgArrowUp : SvgArrowDown
|
|
31
|
+
},
|
|
32
|
+
className: Styles.notificationButton,
|
|
33
|
+
"data-cy": `navigation-notifications-${direction}`,
|
|
34
|
+
"aria-label": `${label} ${direction}. Show nearest notification`,
|
|
35
|
+
onClick: (event)=>{
|
|
36
|
+
event.stopPropagation();
|
|
37
|
+
onReveal(direction);
|
|
38
|
+
},
|
|
39
|
+
children: expanded ? label : count >= 100 ? '99+' : count
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
]
|
|
43
|
+
}, direction);
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
//# sourceMappingURL=navigation-scroll-indicators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/titan-layout/navigation-scroll-indicators.tsx"],"sourcesContent":["import { Button } from '@servicetitan/anvil2';\nimport SvgArrowDown from '@servicetitan/anvil2/assets/icons/material/round/arrow_downward.svg';\nimport SvgArrowUp from '@servicetitan/anvil2/assets/icons/material/round/arrow_upward.svg';\nimport classNames from 'classnames';\nimport { Fragment, RefObject } from 'react';\nimport * as Styles from './layout-sidebar.module.less';\n\nexport function NavigationScrollIndicators({\n expanded,\n above,\n below,\n hasContentAbove,\n hasContentBelow,\n aboveIndicatorRef,\n belowIndicatorRef,\n onReveal,\n}: {\n expanded: boolean;\n above: number;\n below: number;\n hasContentAbove: boolean;\n hasContentBelow: boolean;\n aboveIndicatorRef: RefObject<HTMLDivElement>;\n belowIndicatorRef: RefObject<HTMLDivElement>;\n onReveal(direction: 'above' | 'below'): void;\n}) {\n return (\n <Fragment>\n {(['above', 'below'] as const).map(direction => {\n const isAbove = direction === 'above';\n const count = isAbove ? above : below;\n const hasContent = isAbove ? hasContentAbove : hasContentBelow;\n const label = `${count} ${count === 1 ? 'notification' : 'notifications'}`;\n return (\n <Fragment key={direction}>\n {/*\n * Its own element rather than the pill's background: the pill's height\n * insets the rail's counted area, and this gradient hides nothing, so it\n * must not. See `useNavigationScroll`.\n */}\n {hasContent && (\n <div\n className={classNames(\n Styles.scrollShadow,\n isAbove ? Styles.scrollShadowAbove : Styles.scrollShadowBelow\n )}\n />\n )}\n {count > 0 && (\n <div\n ref={isAbove ? aboveIndicatorRef : belowIndicatorRef}\n className={classNames(\n Styles.scrollIndicator,\n isAbove\n ? Styles.scrollIndicatorAbove\n : Styles.scrollIndicatorBelow\n )}\n >\n <Button\n appearance=\"secondary\"\n size=\"xsmall\"\n icon={{ before: isAbove ? SvgArrowUp : SvgArrowDown }}\n className={Styles.notificationButton}\n data-cy={`navigation-notifications-${direction}`}\n aria-label={`${label} ${direction}. Show nearest notification`}\n onClick={event => {\n event.stopPropagation();\n onReveal(direction);\n }}\n >\n {expanded ? label : count >= 100 ? '99+' : count}\n </Button>\n </div>\n )}\n </Fragment>\n );\n })}\n </Fragment>\n );\n}\n"],"names":["Button","SvgArrowDown","SvgArrowUp","classNames","Fragment","Styles","NavigationScrollIndicators","expanded","above","below","hasContentAbove","hasContentBelow","aboveIndicatorRef","belowIndicatorRef","onReveal","map","direction","isAbove","count","hasContent","label","div","className","scrollShadow","scrollShadowAbove","scrollShadowBelow","ref","scrollIndicator","scrollIndicatorAbove","scrollIndicatorBelow","appearance","size","icon","before","notificationButton","data-cy","aria-label","onClick","event","stopPropagation"],"mappings":";AAAA,SAASA,MAAM,QAAQ,uBAAuB;AAC9C,OAAOC,kBAAkB,sEAAsE;AAC/F,OAAOC,gBAAgB,oEAAoE;AAC3F,OAAOC,gBAAgB,aAAa;AACpC,SAASC,QAAQ,QAAmB,QAAQ;AAC5C,YAAYC,YAAY,+BAA+B;AAEvD,OAAO,SAASC,2BAA2B,EACvCC,QAAQ,EACRC,KAAK,EACLC,KAAK,EACLC,eAAe,EACfC,eAAe,EACfC,iBAAiB,EACjBC,iBAAiB,EACjBC,QAAQ,EAUX;IACG,qBACI,KAACV;kBACI,AAAC;YAAC;YAAS;SAAQ,CAAWW,GAAG,CAACC,CAAAA;YAC/B,MAAMC,UAAUD,cAAc;YAC9B,MAAME,QAAQD,UAAUT,QAAQC;YAChC,MAAMU,aAAaF,UAAUP,kBAAkBC;YAC/C,MAAMS,QAAQ,GAAGF,MAAM,CAAC,EAAEA,UAAU,IAAI,iBAAiB,iBAAiB;YAC1E,qBACI,MAACd;;oBAMIe,4BACG,KAACE;wBACGC,WAAWnB,WACPE,OAAOkB,YAAY,EACnBN,UAAUZ,OAAOmB,iBAAiB,GAAGnB,OAAOoB,iBAAiB;;oBAIxEP,QAAQ,mBACL,KAACG;wBACGK,KAAKT,UAAUL,oBAAoBC;wBACnCS,WAAWnB,WACPE,OAAOsB,eAAe,EACtBV,UACMZ,OAAOuB,oBAAoB,GAC3BvB,OAAOwB,oBAAoB;kCAGrC,cAAA,KAAC7B;4BACG8B,YAAW;4BACXC,MAAK;4BACLC,MAAM;gCAAEC,QAAQhB,UAAUf,aAAaD;4BAAa;4BACpDqB,WAAWjB,OAAO6B,kBAAkB;4BACpCC,WAAS,CAAC,yBAAyB,EAAEnB,WAAW;4BAChDoB,cAAY,GAAGhB,MAAM,CAAC,EAAEJ,UAAU,2BAA2B,CAAC;4BAC9DqB,SAASC,CAAAA;gCACLA,MAAMC,eAAe;gCACrBzB,SAASE;4BACb;sCAECT,WAAWa,QAAQF,SAAS,MAAM,QAAQA;;;;eApC5CF;QA0CvB;;AAGZ"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ComponentPropsWithoutRef, FC, ReactElement, ReactNode } from 'react';
|
|
2
2
|
import { NavigationItemData } from '../../utils/navigation';
|
|
3
3
|
import { NavLinkComponentProps } from '../../utils/navigation-context';
|
|
4
|
+
import { PinnedNavigationConfig } from './interface';
|
|
4
5
|
import { TitanLayoutLogoProps } from './layout-logo';
|
|
5
6
|
export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children' | 'style'> & {
|
|
6
7
|
/** layout appearance */
|
|
@@ -15,6 +16,11 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
15
16
|
navigationComponent?: FC<NavLinkComponentProps>;
|
|
16
17
|
/** data for main navigation links */
|
|
17
18
|
navigationMainItems?: NavigationItemData[];
|
|
19
|
+
/**
|
|
20
|
+
* Turns the navigation catalog on: renders a trigger in the sidebar and the dialog behind it.
|
|
21
|
+
* Omit it and the navigation is unchanged.
|
|
22
|
+
*/
|
|
23
|
+
pinnedNavigation?: PinnedNavigationConfig;
|
|
18
24
|
/** data for overflow navigation links (used only with top variant) */
|
|
19
25
|
navigationOverflowItems?: NavigationItemData[];
|
|
20
26
|
/** logo props */
|
|
@@ -27,6 +33,13 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
27
33
|
openSubmenus?: string[];
|
|
28
34
|
/** submenu accordion open state change handler */
|
|
29
35
|
onOpenSubmenuChange?: (id: string, opened: boolean) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Receives the complete next set of open modules for individual and bulk actions.
|
|
38
|
+
* Preferred over onOpenSubmenuChange when provided, so bulk updates are atomic.
|
|
39
|
+
* Required for the rail's `Expand All` / `Collapse All` control, which is hidden
|
|
40
|
+
* for hosts that supply only the per-module `onOpenSubmenuChange`.
|
|
41
|
+
*/
|
|
42
|
+
onOpenSubmenusChange?: (ids: string[]) => void;
|
|
30
43
|
/** navigation link click handler */
|
|
31
44
|
onNavigationLinkClick?: (itemId: string, submenuItemId?: string) => void;
|
|
32
45
|
/** content header content */
|
|
@@ -35,6 +48,21 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
35
48
|
top?: ReactElement;
|
|
36
49
|
/** top links for side navigation */
|
|
37
50
|
sideTop?: ReactElement[];
|
|
51
|
+
/**
|
|
52
|
+
* Destinations pinned above the sidebar's divider, ahead of `sideTop`.
|
|
53
|
+
*
|
|
54
|
+
* Rendered with the same machinery as `navigationMainItems`, so one with pages beneath it is
|
|
55
|
+
* an expandable group rather than a bare link. `sideTop` is unchanged and still takes elements
|
|
56
|
+
* the host builds itself; the two can be used together.
|
|
57
|
+
*/
|
|
58
|
+
sideTopItems?: NavigationItemData[];
|
|
59
|
+
/**
|
|
60
|
+
* Whether the sidebar shows the scroll and overflow-notification indicators.
|
|
61
|
+
*
|
|
62
|
+
* Defaults on, so a host that says nothing keeps them. Navigation versions that predate the
|
|
63
|
+
* indicators pass `false`.
|
|
64
|
+
*/
|
|
65
|
+
navigationScrollIndicators?: boolean;
|
|
38
66
|
/**
|
|
39
67
|
* profile element for layout
|
|
40
68
|
* @see ProfileDropdown
|
|
@@ -67,7 +95,7 @@ export type TitanLayoutProps = Omit<ComponentPropsWithoutRef<'div'>, 'children'
|
|
|
67
95
|
noResponsive?: boolean;
|
|
68
96
|
};
|
|
69
97
|
export declare const useViewportConfigs: (noResponsive?: boolean) => void;
|
|
70
|
-
declare function TitanLayoutComponent({ appearance, navVariant, id, children, contentOnly, navigationComponent, header, top, profile, expanded, openSubmenus, logo, onExpandedChange, onOpenSubmenuChange, navigationMainItems, navigationOverflowItems, onNavigationLinkClick, extraLinks, extraLinksTop, extraText, minContentWidth, noResponsive, sideTop, }: TitanLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
98
|
+
declare function TitanLayoutComponent({ appearance, navVariant, id, children, contentOnly, navigationComponent, header, top, profile, expanded, openSubmenus, logo, onExpandedChange, onOpenSubmenuChange, onOpenSubmenusChange, navigationMainItems, pinnedNavigation, navigationOverflowItems, onNavigationLinkClick, extraLinks, extraLinksTop, extraText, minContentWidth, noResponsive, sideTop, sideTopItems, navigationScrollIndicators, }: TitanLayoutProps): import("react/jsx-runtime").JSX.Element;
|
|
71
99
|
export declare const TitanLayout: typeof TitanLayoutComponent & {
|
|
72
100
|
Link: FC<import("./interface").TitanLayoutLinkProps>;
|
|
73
101
|
Trigger: FC<import("./interface").TitanLayoutTriggerProps>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"titan-layout.d.ts","sourceRoot":"","sources":["../../../src/components/titan-layout/titan-layout.tsx"],"names":[],"mappings":"AACA,OAAO,EAEH,wBAAwB,EACxB,EAAE,EAGF,YAAY,EACZ,SAAS,EAMZ,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAA2B,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"titan-layout.d.ts","sourceRoot":"","sources":["../../../src/components/titan-layout/titan-layout.tsx"],"names":[],"mappings":"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"}
|