@apliteni/apliteni-ui 0.98.0 → 0.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/react/dist/index.css +24 -9
- package/react/dist/index.d.ts +5 -1
- package/react/dist/index.js +13 -7
- package/src/components/shell.js +11 -3
- package/src/styles/layout.css +45 -2
- package/src/styles/table.css +68 -1
- package/src/styles/tap-zone.css +25 -1
- package/src/styles/topbar.css +23 -4
- package/src/tokens/tokens.css +2 -0
package/package.json
CHANGED
package/react/dist/index.css
CHANGED
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
--tap-clear-y: 0px;
|
|
37
37
|
}
|
|
38
38
|
@media (max-width: 560px) and (pointer: coarse) {
|
|
39
|
-
:where(.ui-seg button, .ui-tabs__tab, .ui-dropdown__trigger, .ui-toast__action, .ui-drawer__close, .ui-snippet__copy, .ui-footer__social, .ui-datepicker__opt) {
|
|
39
|
+
:where(.ui-seg button, .ui-tabs__tab, .ui-dropdown__trigger, .ui-toast__action, .ui-drawer__close, .ui-snippet__copy, .ui-footer__social, .ui-app__search, .toggle, .ui-datepicker__opt) {
|
|
40
40
|
position: relative;
|
|
41
41
|
}
|
|
42
|
-
:where(.ui-btn, .ui-seg button, .ui-tabs__tab, .ui-dropdown__trigger, .ui-toast__action, .ui-drawer__close, .ui-snippet__copy, .ui-footer__social, .ui-switch, .ui-datepicker__opt)::after {
|
|
42
|
+
:where(.ui-btn, .ui-seg button, .ui-tabs__tab, .ui-dropdown__trigger, .ui-toast__action, .ui-drawer__close, .ui-snippet__copy, .ui-footer__social, .ui-switch, .ui-datepicker__opt, .ui-app__search, .toggle)::after {
|
|
43
43
|
content: "";
|
|
44
44
|
position: absolute;
|
|
45
45
|
left: 50%;
|
|
@@ -133,6 +133,11 @@
|
|
|
133
133
|
--tap-clear-x: var(--tap-gap);
|
|
134
134
|
--tap-clear-y: var(--tap-gap);
|
|
135
135
|
}
|
|
136
|
+
.ui-app__bar,
|
|
137
|
+
.topbar__in {
|
|
138
|
+
--tap-clear-x: var(--space-3, 12px);
|
|
139
|
+
--tap-clear-y: var(--space-3, 12px);
|
|
140
|
+
}
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
/* ../src/styles/tooltip.css */
|
|
@@ -820,7 +825,7 @@
|
|
|
820
825
|
.rx-toast-stack {
|
|
821
826
|
position: fixed;
|
|
822
827
|
right: var(--space-4);
|
|
823
|
-
bottom: var(--space-4);
|
|
828
|
+
bottom: calc(var(--space-4) + var(--ui-app-bottom-clearance, 0px));
|
|
824
829
|
max-width: calc(100% - 2 * var(--space-4));
|
|
825
830
|
z-index: var(--z-toast);
|
|
826
831
|
pointer-events: none;
|
|
@@ -846,23 +851,33 @@
|
|
|
846
851
|
.ui-react-app__bottom .ui-nav__item {
|
|
847
852
|
min-height: 48px;
|
|
848
853
|
}
|
|
854
|
+
.ui-react-app:not(:has(> .ui-app__rail)) {
|
|
855
|
+
grid-template-columns: minmax(0, 1fr);
|
|
856
|
+
}
|
|
857
|
+
.ui-react-app .ui-app__bar > .ui-app__brand {
|
|
858
|
+
flex: none;
|
|
859
|
+
margin-inline-end: var(--space-2);
|
|
860
|
+
}
|
|
849
861
|
@media (max-width: 560px) {
|
|
862
|
+
:root:has(.ui-react-app__bottom) {
|
|
863
|
+
--ui-app-bottom-clearance: calc(96px + env(safe-area-inset-bottom));
|
|
864
|
+
}
|
|
865
|
+
:root:has(.ui-react-app) {
|
|
866
|
+
scroll-padding-bottom: calc(var(--space-5) + var(--ui-app-bottom-clearance, 0px));
|
|
867
|
+
}
|
|
850
868
|
.ui-react-app {
|
|
851
869
|
display: block;
|
|
852
870
|
}
|
|
853
871
|
.ui-react-app > .ui-app__rail {
|
|
854
872
|
display: none;
|
|
855
873
|
}
|
|
856
|
-
.ui-react-app .ui-app__main {
|
|
857
|
-
padding-bottom:
|
|
874
|
+
:root:has(.ui-react-app__bottom) .ui-react-app .ui-app__main {
|
|
875
|
+
padding-bottom: var(--ui-app-bottom-clearance, 0px);
|
|
858
876
|
}
|
|
859
877
|
.ui-react-app .ui-app__bar {
|
|
860
878
|
padding-inline: var(--space-4);
|
|
861
879
|
}
|
|
862
|
-
.ui-react-app .ui-
|
|
863
|
-
min-width: 0;
|
|
864
|
-
}
|
|
865
|
-
.ui-react-app .ui-app__search kbd {
|
|
880
|
+
.ui-react-app .ui-app__bar > .ui-app__brand {
|
|
866
881
|
display: none;
|
|
867
882
|
}
|
|
868
883
|
.ui-react-app__bottom {
|
package/react/dist/index.d.ts
CHANGED
|
@@ -776,6 +776,10 @@ type AppShellProps = {
|
|
|
776
776
|
lede?: string;
|
|
777
777
|
actions?: ReactNode;
|
|
778
778
|
bandControl?: ReactNode;
|
|
779
|
+
/** The band trigger's words. Below 560px the shell draws `searchShortLabel` instead;
|
|
780
|
+
* both stay the button's name, which does not change with the viewport. */
|
|
781
|
+
searchLabel?: string;
|
|
782
|
+
searchShortLabel?: string;
|
|
779
783
|
account: {
|
|
780
784
|
name: string;
|
|
781
785
|
email: string;
|
|
@@ -787,7 +791,7 @@ type AppShellProps = {
|
|
|
787
791
|
/** Spread linkProps onto the router link, including children and onClick. */
|
|
788
792
|
renderLink?: (section: AppShellSection, linkProps: ComponentPropsWithoutRef<'a'>) => ReactNode;
|
|
789
793
|
};
|
|
790
|
-
declare function AppShell({ sections, pathname, title, children, word, brand, brandHref, width, back, lede, actions, bandControl, account, onSignOut, defaultCollapsed, palette, renderLink }: AppShellProps): react.JSX.Element;
|
|
794
|
+
declare function AppShell({ sections, pathname, title, children, word, brand, brandHref, width, back, lede, actions, bandControl, account, onSignOut, searchLabel, searchShortLabel, defaultCollapsed, palette, renderLink }: AppShellProps): react.JSX.Element;
|
|
791
795
|
|
|
792
796
|
type EmptyStateVariant = 'first-run' | 'no-matches' | 'not-found' | 'not-yet-built';
|
|
793
797
|
type EmptyStateProps = {
|
package/react/dist/index.js
CHANGED
|
@@ -3407,6 +3407,8 @@ function AppShell({
|
|
|
3407
3407
|
bandControl,
|
|
3408
3408
|
account,
|
|
3409
3409
|
onSignOut,
|
|
3410
|
+
searchLabel = "Search or run a command\u2026",
|
|
3411
|
+
searchShortLabel = "Search",
|
|
3410
3412
|
defaultCollapsed = false,
|
|
3411
3413
|
palette,
|
|
3412
3414
|
renderLink
|
|
@@ -3488,15 +3490,17 @@ function AppShell({
|
|
|
3488
3490
|
}
|
|
3489
3491
|
);
|
|
3490
3492
|
const foldLabel = collapsed ? "Expand sidebar" : "Collapse sidebar";
|
|
3493
|
+
const navigable = sections.length > 1 || Boolean(back);
|
|
3491
3494
|
const visible = sections.length > 4 ? sections.slice(0, 3) : sections;
|
|
3492
3495
|
const remaining = sections.slice(visible.length);
|
|
3493
3496
|
const initials = account.name.trim().split(/\s+/).map((part) => part[0]).slice(0, 2).join("");
|
|
3497
|
+
const lockup = /* @__PURE__ */ jsxs29("a", { className: "ui-app__brand", href: brandHref, "aria-label": word, children: [
|
|
3498
|
+
brand ?? /* @__PURE__ */ jsx34("i", { "aria-hidden": "true", className: "ui-react-app__mark", dangerouslySetInnerHTML: { __html: prism(uid, 24) } }),
|
|
3499
|
+
/* @__PURE__ */ jsx34("span", { children: word })
|
|
3500
|
+
] });
|
|
3494
3501
|
return /* @__PURE__ */ jsxs29("div", { className: `ui-app ui-app--topbar ui-react-app${collapsed ? " is-collapsed" : ""}`, children: [
|
|
3495
|
-
/* @__PURE__ */ jsxs29("div", { className: "ui-app__rail", children: [
|
|
3496
|
-
/* @__PURE__ */ jsx34("div", { className: "ui-app__head", children:
|
|
3497
|
-
brand ?? /* @__PURE__ */ jsx34("i", { "aria-hidden": "true", className: "ui-react-app__mark", dangerouslySetInnerHTML: { __html: prism(uid, 24) } }),
|
|
3498
|
-
/* @__PURE__ */ jsx34("span", { children: word })
|
|
3499
|
-
] }) }),
|
|
3502
|
+
navigable && /* @__PURE__ */ jsxs29("div", { className: "ui-app__rail", children: [
|
|
3503
|
+
/* @__PURE__ */ jsx34("div", { className: "ui-app__head", children: lockup }),
|
|
3500
3504
|
sidebar(sections, "Sections"),
|
|
3501
3505
|
/* @__PURE__ */ jsx34("div", { className: "ui-app__foot", children: /* @__PURE__ */ jsx34("div", { className: "ui-app__fold-row", children: /* @__PURE__ */ jsxs29("button", { type: "button", className: "ui-nav__item ui-app__fold", "aria-expanded": !collapsed, "aria-label": foldLabel, onClick: fold, children: [
|
|
3502
3506
|
/* @__PURE__ */ jsx34("span", { className: "ui-nav__ic", children: /* @__PURE__ */ jsxs29("svg", { className: "ui-icon", viewBox: "0 0 24 24", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
@@ -3509,9 +3513,11 @@ function AppShell({
|
|
|
3509
3513
|
] }),
|
|
3510
3514
|
/* @__PURE__ */ jsxs29("div", { className: "ui-app__well", children: [
|
|
3511
3515
|
/* @__PURE__ */ jsxs29("header", { className: "ui-app__bar", children: [
|
|
3516
|
+
!navigable && lockup,
|
|
3512
3517
|
/* @__PURE__ */ jsxs29("button", { type: "button", className: "ui-app__search", "aria-haspopup": "dialog", onClick: () => setSearch(true), children: [
|
|
3513
3518
|
/* @__PURE__ */ jsx34("span", { className: "ui-app__search-ic", children: /* @__PURE__ */ jsx34(Icon, { name: "search" }) }),
|
|
3514
|
-
/* @__PURE__ */ jsx34("span", { className: "ui-app__search-txt", children:
|
|
3519
|
+
/* @__PURE__ */ jsx34("span", { className: "ui-app__search-txt", children: searchLabel }),
|
|
3520
|
+
/* @__PURE__ */ jsx34("span", { className: "ui-app__search-short", "aria-hidden": "true", children: searchShortLabel }),
|
|
3515
3521
|
/* @__PURE__ */ jsx34("kbd", { className: "ui-cmdk__key", children: paletteHotkey() })
|
|
3516
3522
|
] }),
|
|
3517
3523
|
/* @__PURE__ */ jsx34("span", { className: "ui-app__bar-gap" }),
|
|
@@ -3544,7 +3550,7 @@ function AppShell({
|
|
|
3544
3550
|
/* @__PURE__ */ jsx34("div", { className: "ui-app__body", children })
|
|
3545
3551
|
] })
|
|
3546
3552
|
] }),
|
|
3547
|
-
/* @__PURE__ */ jsx34("nav", { className: "ui-nav ui-react-app__bottom", "aria-label": "Sections on mobile", children: /* @__PURE__ */ jsxs29("ul", { className: "ui-nav__list", children: [
|
|
3553
|
+
navigable && /* @__PURE__ */ jsx34("nav", { className: "ui-nav ui-react-app__bottom", "aria-label": "Sections on mobile", children: /* @__PURE__ */ jsxs29("ul", { className: "ui-nav__list", children: [
|
|
3548
3554
|
links(visible),
|
|
3549
3555
|
remaining.length > 0 && /* @__PURE__ */ jsx34("li", { children: /* @__PURE__ */ jsxs29(
|
|
3550
3556
|
"button",
|
package/src/components/shell.js
CHANGED
|
@@ -91,12 +91,17 @@ const toWidth = (v) => (v === 'wide' ? 'wide' : 'centered');
|
|
|
91
91
|
|
|
92
92
|
// `search: 'palette-id'`, or the same id in `{ palette }` with a placeholder beside
|
|
93
93
|
// it. No palette to open, no field — the argument `signOutHref` takes.
|
|
94
|
-
//
|
|
94
|
+
// `shortLabel` is the word the band draws below 560px, where the sentence used to
|
|
95
|
+
// truncate mid-word. why: docs/components.md#the-page-shell
|
|
95
96
|
const toSearch = (v) => {
|
|
96
97
|
const given = typeof v === 'string' ? { palette: v } : (isRecord(v) && !Array.isArray(v) ? v : null);
|
|
97
98
|
const palette = given && typeof given.palette === 'string' ? given.palette.trim() : '';
|
|
98
99
|
if (!palette) return null;
|
|
99
|
-
return {
|
|
100
|
+
return {
|
|
101
|
+
palette,
|
|
102
|
+
placeholder: str(given.placeholder) || 'Search or run a command…',
|
|
103
|
+
shortLabel: str(given.shortLabel) || 'Search',
|
|
104
|
+
};
|
|
100
105
|
};
|
|
101
106
|
|
|
102
107
|
// `maxWidth` lands inside a style attribute, so a length is all this accepts — a number
|
|
@@ -236,10 +241,13 @@ function readerBlock({ name, email }, signOutHref, { band = false } = {}) {
|
|
|
236
241
|
// A field to look at, a button to press. `data-cmdk-open` and the cap's class are the
|
|
237
242
|
// palette's own, and the cap is NOT aria-hidden: it is half the button's name.
|
|
238
243
|
// why: docs/components.md#the-page-shell
|
|
239
|
-
|
|
244
|
+
// The short word repeats the sentence, so it is `aria-hidden`: the sentence and the
|
|
245
|
+
// cap are the name at every width, and layout.css clips rather than drops them.
|
|
246
|
+
const searchField = ({ palette, placeholder, shortLabel }) =>
|
|
240
247
|
`<button type="button" class="ui-app__search" data-cmdk-open="${esc(palette)}" aria-haspopup="dialog">`
|
|
241
248
|
+ `<span class="ui-app__search-ic" aria-hidden="true">${icon('search')}</span>`
|
|
242
249
|
+ `<span class="ui-app__search-txt">${esc(placeholder)}</span>`
|
|
250
|
+
+ `<span class="ui-app__search-short" aria-hidden="true">${esc(shortLabel)}</span>`
|
|
243
251
|
+ `<kbd class="ui-cmdk__key" data-palette-hotkey>${esc(paletteHotkey())}</kbd>`
|
|
244
252
|
+ `</button>`;
|
|
245
253
|
|
package/src/styles/layout.css
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
resting step. */
|
|
120
120
|
/* Re-tuned at #295, which took the light rail down a step with the page. Below 720px
|
|
121
121
|
the glyph is the whole row, so it is held at text grade rather than at 1.4.11's bar —
|
|
122
|
-
stories/apps/shell-states.test.js:
|
|
122
|
+
stories/apps/shell-states.test.js:1704 `a resting glyph is dimmer but still legible`. */
|
|
123
123
|
.ui-app__rail .ui-nav__ic svg { opacity: 0.66; }
|
|
124
124
|
|
|
125
125
|
/* A destructive row of the rail is a navigation row and rests like one; the danger
|
|
@@ -404,11 +404,26 @@
|
|
|
404
404
|
.ui-app__search-txt { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
405
405
|
/* The other half of the name, so it never gives way. */
|
|
406
406
|
.ui-app__search kbd { flex: none; }
|
|
407
|
+
/* The one word the phone band draws instead of the sentence. Above 560px the
|
|
408
|
+
sentence fits and this is a second copy of it, so it is not drawn.
|
|
409
|
+
why: docs/components.md#the-page-shell */
|
|
410
|
+
.ui-app__search-short { display: none; }
|
|
407
411
|
|
|
408
412
|
/* The mark alone — no room for two lines on a 52px row. No rule over it, since the
|
|
409
413
|
band's hairline is under the whole of it, and no column, since this is not the rail.
|
|
410
414
|
why: docs/components.md#the-page-shell */
|
|
411
415
|
.ui-app__user--bar { flex: none; padding-top: 0; border-top: 0; }
|
|
416
|
+
/* The switch is a 34px square and stays one: the trigger above is the thing on this
|
|
417
|
+
band that gives way, and a flex item with the default shrink does not wait its
|
|
418
|
+
turn. Measured at 390 with a control beside the trigger, the React band's switch
|
|
419
|
+
drew 19x34 and the strategy topbar's drew 28.47x34 — a square glyph plate squashed,
|
|
420
|
+
and a tap zone the sheet could only clamp to 29 or 39.
|
|
421
|
+
Pinning the strategy topbar's half of this rule does not make its row narrower: it
|
|
422
|
+
moves a 5.53px shortfall onto the account block's trailing gutter instead, because
|
|
423
|
+
nothing before it in that row has width to spare. topbar.css's --space-2 comment
|
|
424
|
+
names that choice and the gutter it leaves.
|
|
425
|
+
why: docs/components.md#the-page-shell */
|
|
426
|
+
.ui-app__bar .toggle, .topbar__in .toggle { flex: none; }
|
|
412
427
|
.ui-app__user--bar .ui-app__av { margin-inline-start: 0; }
|
|
413
428
|
/* Crumb, then the title block. At --space-2 the crumb sat 8px off the h1 and
|
|
414
429
|
the h1 8px off its subtitle, so all three ranks read as one. */
|
|
@@ -422,7 +437,10 @@
|
|
|
422
437
|
letter-spacing: var(--tracking-tight);
|
|
423
438
|
margin-bottom: 8px;
|
|
424
439
|
}
|
|
425
|
-
|
|
440
|
+
/* The head keeps the kit's second step below it whether or not a lede is there to
|
|
441
|
+
carry it: with no lede the title's own margin takes the step instead. */
|
|
442
|
+
.ui-app__main h1:not(.ui-card h1):not(:has(+ .ui-app__sub)) { margin-bottom: var(--space-8); }
|
|
443
|
+
.ui-app__sub { color: var(--text); font-size: calc(var(--text-base) + 0.5px); line-height: 1.6; max-width: var(--prose-body); margin-bottom: var(--space-8); }
|
|
426
444
|
.ui-app__body { display: flex; flex-direction: column; gap: var(--space-5); }
|
|
427
445
|
/* A flex child's min-width is its content by default, so one wide block — a
|
|
428
446
|
ledger, a code sample — pushes the whole page sideways instead of scrolling
|
|
@@ -515,6 +533,31 @@
|
|
|
515
533
|
.ui-app__main .ui-card__row { flex-wrap: wrap; gap: var(--space-3); }
|
|
516
534
|
}
|
|
517
535
|
|
|
536
|
+
/* -- The band's search at one column --------------------------------------- */
|
|
537
|
+
/* The band holds the trigger, the reader's mark and whatever the page puts between
|
|
538
|
+
them, so the sentence broke mid-word — "Search or run a co…". The short word takes
|
|
539
|
+
its place. Neither the sentence nor the cap is `display: none`: both are inside
|
|
540
|
+
the button's accessible name — the cap by Artur's call on #308 — so they are
|
|
541
|
+
clipped the way `.ui-sr` in loading.css clips, and the name holds at every width.
|
|
542
|
+
why: docs/components.md#the-page-shell */
|
|
543
|
+
@media (max-width: 560px) {
|
|
544
|
+
.ui-app__search-txt,
|
|
545
|
+
.ui-app__search kbd {
|
|
546
|
+
position: absolute;
|
|
547
|
+
width: 1px;
|
|
548
|
+
height: 1px;
|
|
549
|
+
margin: -1px;
|
|
550
|
+
padding: 0;
|
|
551
|
+
overflow: hidden;
|
|
552
|
+
clip-path: inset(50%);
|
|
553
|
+
white-space: nowrap;
|
|
554
|
+
border: 0;
|
|
555
|
+
}
|
|
556
|
+
/* It gives way before the band does: at a large font scale the word ellipsises
|
|
557
|
+
rather than pushing the reader's mark off the row. */
|
|
558
|
+
.ui-app__search-short { display: block; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
559
|
+
}
|
|
560
|
+
|
|
518
561
|
/* -- Auth card (sign-in / consent) — centered, glowing --------------------- */
|
|
519
562
|
.ui-auth {
|
|
520
563
|
min-height: 100vh;
|
package/src/styles/table.css
CHANGED
|
@@ -204,7 +204,35 @@
|
|
|
204
204
|
.ui-table--compact th { padding: var(--space-2) var(--space-3); }
|
|
205
205
|
.ui-table--compact th:last-child,
|
|
206
206
|
.ui-table--compact td:last-child { padding-right: var(--space-3); }
|
|
207
|
-
|
|
207
|
+
/* Columns past the box's edge, said in paint. Two shades, one per side, under two
|
|
208
|
+
cover layers that ride the content: `local` moves a cover with the scroll, so
|
|
209
|
+
reaching an end slides that cover over its shade. A cover is solid for its first
|
|
210
|
+
half, so at 24px it hides a 12px shade outright — which is why the two sizes are
|
|
211
|
+
not one. why: guidelines/dense-tables.md */
|
|
212
|
+
.ui-table-scroll {
|
|
213
|
+
overflow: auto; max-height: var(--ui-table-height, 70vh); padding: 0 var(--space-1);
|
|
214
|
+
background-color: var(--table-bg);
|
|
215
|
+
background-image:
|
|
216
|
+
linear-gradient(to right, var(--table-bg) 50%, transparent),
|
|
217
|
+
linear-gradient(to left, var(--table-bg) 50%, transparent),
|
|
218
|
+
radial-gradient(farthest-side at 0 50%, var(--table-edge), transparent),
|
|
219
|
+
radial-gradient(farthest-side at 100% 50%, var(--table-edge), transparent);
|
|
220
|
+
background-position: 0 0, 100% 0, 0 0, 100% 0;
|
|
221
|
+
background-size: var(--space-6) 100%, var(--space-6) 100%, var(--space-3) 100%, var(--space-3) 100%;
|
|
222
|
+
background-repeat: no-repeat;
|
|
223
|
+
background-attachment: local, local, scroll, scroll;
|
|
224
|
+
}
|
|
225
|
+
/* The edge darkens on a light ground and lightens on a dark one: ink has nowhere to
|
|
226
|
+
go on a near-black page, which is why --elev-drop splits its spend and a raised
|
|
227
|
+
dark surface takes a light --elev-edge. */
|
|
228
|
+
.ui-table-scroll { --table-edge: color-mix(in srgb, var(--sheen) 12%, transparent); }
|
|
229
|
+
:root[data-theme="light"] .ui-table-scroll { --table-edge: color-mix(in srgb, var(--shadow-ink) 13%, transparent); }
|
|
230
|
+
/* The surface belongs to the box that scrolls, so the shades land under the cells
|
|
231
|
+
rather than behind them; the row fills repeat that same surface and step aside.
|
|
232
|
+
The sticky header and pinned column keep their paint: they hide what scrolls
|
|
233
|
+
beneath them. */
|
|
234
|
+
.ui-table-scroll > .ui-table,
|
|
235
|
+
.ui-table-scroll > .ui-table tbody td:not(.ui-table__identity, .ui-table__selection) { background-color: transparent; }
|
|
208
236
|
/* The kit's first ringed scroller, and a scroll region inside a card like the rest, so
|
|
209
237
|
it draws the band inward too rather than spending a halo across the card around it.
|
|
210
238
|
It had no room of its own to draw in — the padding above is horizontal — which is the
|
|
@@ -216,6 +244,45 @@
|
|
|
216
244
|
.ui-table--sticky thead th { position: sticky; top: 0; z-index: var(--z-sticky); background: var(--table-bg); padding-top: var(--space-2); }
|
|
217
245
|
.ui-table--pinned .ui-table__identity, .ui-table--pinned .ui-table__selection { position: sticky; left: 0; z-index: var(--z-base); background: var(--table-bg); border-right: 1px solid var(--border); }
|
|
218
246
|
.ui-table--pinned thead .ui-table__identity, .ui-table--pinned thead .ui-table__selection { z-index: calc(var(--z-sticky) + 1); }
|
|
247
|
+
/* The divider is the pin's edge: it says the column stayed while the rest moved under it.
|
|
248
|
+
Columns that all fit never move, so the line divides nothing and reads as an arbitrary
|
|
249
|
+
rule. The resting rule keeps it, so an engine that cannot answer the query is unchanged;
|
|
250
|
+
scroll-state makes a query container, not a size one. why: guidelines/dense-tables.md */
|
|
251
|
+
.ui-table-scroll { container-type: scroll-state; }
|
|
252
|
+
/* A shared grid cell puts the edge shade over the opaque sticky header, on both
|
|
253
|
+
sides: the radial-gradient shades below answer only the table's own background
|
|
254
|
+
and fall to nothing where the sticky header paints over them, so an engine that
|
|
255
|
+
can ask whether the scrollport still has room sticks a shade of its own above
|
|
256
|
+
it instead and the base radial pair is sized to 0 here. #434 review round 2 */
|
|
257
|
+
@supports (container-type: scroll-state) {
|
|
258
|
+
.ui-table-scroll {
|
|
259
|
+
display: grid;
|
|
260
|
+
grid-template-columns: minmax(0, 1fr);
|
|
261
|
+
background-size: var(--space-6) 100%, var(--space-6) 100%, 0 100%, 0 100%;
|
|
262
|
+
}
|
|
263
|
+
.ui-table-scroll > .ui-table { grid-area: 1 / 1; }
|
|
264
|
+
.ui-table-scroll::before,
|
|
265
|
+
.ui-table-scroll::after {
|
|
266
|
+
content: '';
|
|
267
|
+
grid-area: 1 / 1;
|
|
268
|
+
position: sticky;
|
|
269
|
+
top: 0;
|
|
270
|
+
width: var(--space-3);
|
|
271
|
+
z-index: calc(var(--z-sticky) + 2);
|
|
272
|
+
pointer-events: none;
|
|
273
|
+
}
|
|
274
|
+
.ui-table-scroll::before { left: 0; right: calc(100% - var(--space-3)); justify-self: start; }
|
|
275
|
+
.ui-table-scroll::after { left: calc(100% - var(--space-3)); right: 0; justify-self: end; }
|
|
276
|
+
@container scroll-state(scrollable: left) {
|
|
277
|
+
.ui-table-scroll::before { background: linear-gradient(to right, var(--table-edge), transparent); }
|
|
278
|
+
}
|
|
279
|
+
@container scroll-state(scrollable: right) {
|
|
280
|
+
.ui-table-scroll::after { background: linear-gradient(to left, var(--table-edge), transparent); }
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
@container not scroll-state(scrollable: x) {
|
|
284
|
+
.ui-table--pinned :is(.ui-table__identity, .ui-table__selection) { border-right-color: transparent; }
|
|
285
|
+
}
|
|
219
286
|
.ui-value, .ui-delta { white-space: nowrap; font-variant-numeric: tabular-nums; }
|
|
220
287
|
.ui-value__unit { margin-left: var(--space-1); font-size: var(--text-xs); color: var(--text); }
|
|
221
288
|
.ui-delta--success { color: var(--chip-success-ink); }
|
package/src/styles/tap-zone.css
CHANGED
|
@@ -56,6 +56,8 @@
|
|
|
56
56
|
.ui-drawer__close,
|
|
57
57
|
.ui-snippet__copy,
|
|
58
58
|
.ui-footer__social,
|
|
59
|
+
.ui-app__search,
|
|
60
|
+
.toggle,
|
|
59
61
|
/* Already relative in react/src/DatePicker.css — restated because this
|
|
60
62
|
gate reads the kit's own sheets and cannot see that one, and a carrier
|
|
61
63
|
whose containing block it cannot find is a layer that measures against
|
|
@@ -75,7 +77,9 @@
|
|
|
75
77
|
.ui-snippet__copy,
|
|
76
78
|
.ui-footer__social,
|
|
77
79
|
.ui-switch,
|
|
78
|
-
.ui-datepicker__opt
|
|
80
|
+
.ui-datepicker__opt,
|
|
81
|
+
.ui-app__search,
|
|
82
|
+
.toggle
|
|
79
83
|
)::after {
|
|
80
84
|
content: "";
|
|
81
85
|
position: absolute;
|
|
@@ -215,4 +219,24 @@
|
|
|
215
219
|
--tap-clear-x: var(--tap-gap);
|
|
216
220
|
--tap-clear-y: var(--tap-gap);
|
|
217
221
|
}
|
|
222
|
+
|
|
223
|
+
/* Two 52px rows, each holding a control the kit draws under the floor: the
|
|
224
|
+
shell band's palette trigger, 37.05 tall once the phone band swaps its
|
|
225
|
+
sentence for the short word, and the theme switch at 34 square on both.
|
|
226
|
+
Neither row opens anything — the room is already in it, which is why these
|
|
227
|
+
two declare a clearance and no gap. Across, 6px a side against the band's
|
|
228
|
+
own 12px gap and the topbar's 8 below 560px, where this layer exists — not
|
|
229
|
+
the topbar's 14 above that step, where it does not. 6px a side crosses the
|
|
230
|
+
topbar's 4px midline by 1px, which does not mis-tap: neither neighbour on
|
|
231
|
+
that row carries a layer of its own. Down, the row's leftover height is 7.4px
|
|
232
|
+
above and below the trigger and 9 around the switch, where a 44px layer
|
|
233
|
+
needs 3.5 and 5. The rows keep their height, their gaps and their paint.
|
|
234
|
+
#486
|
|
235
|
+
|
|
236
|
+
--space-3 rather than --tap-gap, which is what every row above declares:
|
|
237
|
+
20 claims 10px a side and the trigger has 7.4. The clamp would still stop
|
|
238
|
+
at 44 today and be a number that is not true, which is what the browser
|
|
239
|
+
half fails a container for. */
|
|
240
|
+
.ui-app__bar,
|
|
241
|
+
.topbar__in { --tap-clear-x: var(--space-3, 12px); --tap-clear-y: var(--space-3, 12px); }
|
|
218
242
|
}
|
package/src/styles/topbar.css
CHANGED
|
@@ -246,12 +246,31 @@
|
|
|
246
246
|
/* One column, and the band is at its tightest. The row is already full at 390,
|
|
247
247
|
and at the gap above this one the account avatar stood from 365 to 397 and was
|
|
248
248
|
cut at the screen edge — the one control on this screen that opens the account
|
|
249
|
-
area. Packed to --space-2
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
area. Packed to --space-2 and a flat 14px trailing gutter the band needs 367.53
|
|
250
|
+
of the 362px it has there, a 5.53px shortfall, because layout.css now pins the
|
|
251
|
+
theme switch to a full 34px square so it keeps the tap floor it was given.
|
|
252
|
+
The wordmark, the Deck/Text switch and the version label are each already at
|
|
253
|
+
the width their own text needs, and the switch must not shrink again, so the
|
|
254
|
+
account block's trailing gutter is what gives — but a FLAT 14px gutter has no
|
|
255
|
+
fallback below the width it was sized for: at 375 it has already given every
|
|
256
|
+
one of its 14px and the row is still 6.53px short, so the avatar was cut and
|
|
257
|
+
the page gained 7px of horizontal scroll (#486 review round 2), worse again
|
|
258
|
+
at 320.
|
|
259
|
+
Both carry a share now, continuously, rather than the gutter alone holding a
|
|
260
|
+
fixed budget: the gutter still narrows first, from 14px at 390 down to 0 by
|
|
261
|
+
381.53px of available row width, and once it is spent the inter-control gap
|
|
262
|
+
takes the rest, from --space-2 down to its own floor of --space-1. 381.53px is
|
|
263
|
+
this row's own fixed width minus its gutter's full 14px — not a general
|
|
264
|
+
formula, a number that belongs to this composition's own wordmark, switch and
|
|
265
|
+
version label. The avatar is whole and the page carries no horizontal scroll
|
|
266
|
+
down to 375px. 320 still falls 41.53px short with both all the way down,
|
|
267
|
+
which stays #558; it is 5px better than main's own 46.53px there, not solved.
|
|
252
268
|
why: docs/foundations.md#breakpoints */
|
|
253
269
|
@media (max-width: 560px) {
|
|
254
|
-
.topbar__in {
|
|
270
|
+
.topbar__in {
|
|
271
|
+
gap: clamp(var(--space-1), calc(var(--space-2) - (381.53px - 100vw) / 5), var(--space-2));
|
|
272
|
+
padding-right: clamp(0px, calc(100vw - 381.53px), 14px);
|
|
273
|
+
}
|
|
255
274
|
}
|
|
256
275
|
|
|
257
276
|
/* Account — avatar + dropdown. Gated: hidden until the app confirms a session
|
package/src/tokens/tokens.css
CHANGED
|
@@ -534,6 +534,7 @@
|
|
|
534
534
|
.ui-snippet--reveal,
|
|
535
535
|
.ui-sx,
|
|
536
536
|
.ui-table,
|
|
537
|
+
.ui-table-scroll,
|
|
537
538
|
.ui-table--sticky thead th,
|
|
538
539
|
.ui-table--pinned .ui-table__identity, .ui-table--pinned .ui-table__selection,
|
|
539
540
|
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td,
|
|
@@ -557,6 +558,7 @@
|
|
|
557
558
|
* toward the page and leaves the page 1.02 away, while the card it is a variant of stays
|
|
558
559
|
* 1.07-1.14 off in both themes. Measured in stories/code-chip.test.js. */
|
|
559
560
|
.ui-table,
|
|
561
|
+
.ui-table-scroll,
|
|
560
562
|
.ui-table--sticky thead th,
|
|
561
563
|
.ui-table--pinned .ui-table__identity, .ui-table--pinned .ui-table__selection,
|
|
562
564
|
.ui-table--hover:not(.ui-table--zebra) tbody tr:hover td,
|