zabi-components 8.1.0 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1011 -0
- package/README.md +1 -1
- package/THEME.md +18 -5
- package/THEMING.md +308 -74
- package/dist/atoms/ActionPanel.svelte +1 -1
- package/dist/atoms/Avatar.svelte +19 -3
- package/dist/atoms/Avatar.svelte.d.ts +12 -0
- package/dist/atoms/Badge.svelte +37 -8
- package/dist/atoms/Badge.svelte.d.ts +6 -0
- package/dist/atoms/Block.svelte +74 -0
- package/dist/atoms/Block.svelte.d.ts +29 -0
- package/dist/atoms/Button.svelte +52 -15
- package/dist/atoms/Button.svelte.d.ts +3 -2
- package/dist/atoms/Card.svelte +181 -25
- package/dist/atoms/Card.svelte.d.ts +55 -3
- package/dist/atoms/Checkbox.svelte +33 -0
- package/dist/atoms/Checkbox.svelte.d.ts +27 -0
- package/dist/atoms/Chip.svelte +351 -0
- package/dist/atoms/Chip.svelte.d.ts +57 -0
- package/dist/atoms/CodeField.svelte +385 -0
- package/dist/atoms/CodeField.svelte.d.ts +61 -0
- package/dist/atoms/ColorPicker.svelte +1 -0
- package/dist/atoms/DateField.svelte +41 -3
- package/dist/atoms/DateField.svelte.d.ts +31 -3
- package/dist/atoms/FloatingActionButton.svelte +5 -3
- package/dist/atoms/FloatingActionButton.svelte.d.ts +1 -1
- package/dist/atoms/Heading.svelte +27 -1
- package/dist/atoms/Heading.svelte.d.ts +7 -0
- package/dist/atoms/IconButton.svelte +81 -9
- package/dist/atoms/IconButton.svelte.d.ts +13 -0
- package/dist/atoms/Input.svelte +10 -5
- package/dist/atoms/Input.svelte.d.ts +3 -2
- package/dist/atoms/List.svelte +3 -2
- package/dist/atoms/ListItem.svelte +31 -7
- package/dist/atoms/ListItem.svelte.d.ts +6 -0
- package/dist/atoms/PickerField.svelte +239 -0
- package/dist/atoms/PickerField.svelte.d.ts +67 -0
- package/dist/atoms/Progress.svelte +78 -17
- package/dist/atoms/Progress.svelte.d.ts +11 -1
- package/dist/atoms/Radio.svelte +32 -0
- package/dist/atoms/Radio.svelte.d.ts +26 -0
- package/dist/atoms/Rating.svelte +132 -6
- package/dist/atoms/Rating.svelte.d.ts +24 -3
- package/dist/atoms/Select.svelte +24 -26
- package/dist/atoms/Select.svelte.d.ts +12 -0
- package/dist/atoms/SelectionControl.svelte +99 -6
- package/dist/atoms/SelectionControl.svelte.d.ts +25 -0
- package/dist/atoms/Skeleton.svelte +114 -18
- package/dist/atoms/Skeleton.svelte.d.ts +30 -3
- package/dist/atoms/SkeletonGroup.svelte +43 -0
- package/dist/atoms/SkeletonGroup.svelte.d.ts +20 -0
- package/dist/atoms/Slider.svelte +35 -0
- package/dist/atoms/Sparkline.svelte +109 -0
- package/dist/atoms/Sparkline.svelte.d.ts +27 -0
- package/dist/atoms/SpeechBubble.svelte +187 -0
- package/dist/atoms/SpeechBubble.svelte.d.ts +33 -0
- package/dist/atoms/Stat.svelte +72 -0
- package/dist/atoms/Stat.svelte.d.ts +19 -0
- package/dist/atoms/TemporalField.svelte +342 -10
- package/dist/atoms/TemporalField.svelte.d.ts +20 -4
- package/dist/atoms/Textarea.svelte +100 -5
- package/dist/atoms/Textarea.svelte.d.ts +21 -0
- package/dist/atoms/TimeColumn.svelte +150 -0
- package/dist/atoms/TimeColumn.svelte.d.ts +25 -0
- package/dist/atoms/TimeField.svelte +46 -3
- package/dist/atoms/TimeField.svelte.d.ts +34 -3
- package/dist/atoms/Toast.svelte +6 -5
- package/dist/atoms/Toggle.svelte +61 -10
- package/dist/atoms/Toggle.svelte.d.ts +15 -0
- package/dist/atoms/Tooltip.svelte +20 -1
- package/dist/atoms/Tooltip.svelte.d.ts +7 -0
- package/dist/atoms/index.d.ts +21 -0
- package/dist/atoms/index.js +17 -0
- package/dist/atoms/selection-control.styles.d.ts +15 -4
- package/dist/atoms/selection-control.styles.js +16 -5
- package/dist/components/atoms/index.d.ts +21 -0
- package/dist/components/atoms/index.d.ts.map +1 -1
- package/dist/components/atoms/selection-control.styles.d.ts +15 -4
- package/dist/components/atoms/selection-control.styles.d.ts.map +1 -1
- package/dist/components/index.d.ts +27 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/map.d.ts +11 -0
- package/dist/components/map.d.ts.map +1 -0
- package/dist/components/molecules/index.d.ts +7 -2
- package/dist/components/molecules/index.d.ts.map +1 -1
- package/dist/components/molecules/toast-store.d.ts +30 -0
- package/dist/components/molecules/toast-store.d.ts.map +1 -1
- package/dist/components/organisms/index.d.ts +6 -1
- package/dist/components/organisms/index.d.ts.map +1 -1
- package/dist/components/types/variants.d.ts +12 -3
- package/dist/components/types/variants.d.ts.map +1 -1
- package/dist/components/util/app-shell.d.ts +55 -4
- package/dist/components/util/app-shell.d.ts.map +1 -1
- package/dist/components/util/avatar.d.ts +3 -0
- package/dist/components/util/avatar.d.ts.map +1 -1
- package/dist/components/util/bottom-tab-bar.d.ts +6 -0
- package/dist/components/util/bottom-tab-bar.d.ts.map +1 -1
- package/dist/components/util/chart.d.ts +140 -0
- package/dist/components/util/chart.d.ts.map +1 -0
- package/dist/components/util/chip.d.ts +66 -0
- package/dist/components/util/chip.d.ts.map +1 -0
- package/dist/components/util/cn.d.ts.map +1 -1
- package/dist/components/util/code-field.d.ts +63 -0
- package/dist/components/util/code-field.d.ts.map +1 -0
- package/dist/components/util/collapsible.d.ts +6 -0
- package/dist/components/util/collapsible.d.ts.map +1 -1
- package/dist/components/util/display-voice.d.ts +10 -0
- package/dist/components/util/display-voice.d.ts.map +1 -0
- package/dist/components/util/field-control.d.ts +30 -0
- package/dist/components/util/field-control.d.ts.map +1 -0
- package/dist/components/util/field.d.ts +6 -0
- package/dist/components/util/field.d.ts.map +1 -1
- package/dist/components/util/focus-utils.d.ts +2 -0
- package/dist/components/util/focus-utils.d.ts.map +1 -1
- package/dist/components/util/map-view.d.ts +144 -0
- package/dist/components/util/map-view.d.ts.map +1 -0
- package/dist/components/util/photo.d.ts +19 -0
- package/dist/components/util/photo.d.ts.map +1 -1
- package/dist/components/util/progress.d.ts +19 -0
- package/dist/components/util/progress.d.ts.map +1 -0
- package/dist/components/util/scroll-edge.d.ts +33 -0
- package/dist/components/util/scroll-edge.d.ts.map +1 -0
- package/dist/components/util/sheet-drag.d.ts +25 -1
- package/dist/components/util/sheet-drag.d.ts.map +1 -1
- package/dist/components/util/skeleton.d.ts +15 -0
- package/dist/components/util/skeleton.d.ts.map +1 -0
- package/dist/components/util/sliding-indicator.d.ts +25 -0
- package/dist/components/util/sliding-indicator.d.ts.map +1 -0
- package/dist/components/util/temporal-field.d.ts +89 -0
- package/dist/components/util/temporal-field.d.ts.map +1 -0
- package/dist/components/util/toaster.d.ts +40 -0
- package/dist/components/util/toaster.d.ts.map +1 -1
- package/dist/components/util/tone-surface.d.ts +34 -0
- package/dist/components/util/tone-surface.d.ts.map +1 -0
- package/dist/components/util/top-navbar.d.ts +26 -2
- package/dist/components/util/top-navbar.d.ts.map +1 -1
- package/dist/components/util/zabi-strings.d.ts +9 -0
- package/dist/components/util/zabi-strings.d.ts.map +1 -1
- package/dist/create-theme/cli.js +6 -2
- package/dist/create-theme/index.d.ts +17 -3
- package/dist/create-theme/index.js +252 -35
- package/dist/create-theme/lib/resolve.js +97 -0
- package/dist/create-theme/theme-data.js +1618 -90
- package/dist/index.d.ts +27 -3
- package/dist/index.js +18 -0
- package/dist/map.d.ts +10 -0
- package/dist/map.js +9 -0
- package/dist/molecules/Alert.svelte +31 -12
- package/dist/molecules/Alert.svelte.d.ts +12 -1
- package/dist/molecules/AppBar.svelte +287 -28
- package/dist/molecules/AppBar.svelte.d.ts +62 -0
- package/dist/molecules/AvatarGroup.svelte +1 -1
- package/dist/molecules/BarChart.svelte +381 -0
- package/dist/molecules/BarChart.svelte.d.ts +45 -0
- package/dist/molecules/BottomSheet.svelte +88 -20
- package/dist/molecules/BottomSheet.svelte.d.ts +17 -1
- package/dist/molecules/BottomTabBar.svelte +134 -28
- package/dist/molecules/BottomTabBar.svelte.d.ts +36 -2
- package/dist/molecules/Calendar.svelte.d.ts +1 -1
- package/dist/molecules/ChipGroup.svelte +325 -0
- package/dist/molecules/ChipGroup.svelte.d.ts +41 -0
- package/dist/molecules/Collapsible.svelte +158 -54
- package/dist/molecules/Collapsible.svelte.d.ts +23 -6
- package/dist/molecules/CollapsibleGroup.svelte +16 -6
- package/dist/molecules/ConfirmDialog.svelte +5 -1
- package/dist/molecules/ConfirmDialog.svelte.d.ts +3 -0
- package/dist/molecules/Drawer.svelte +33 -12
- package/dist/molecules/Dropdown.svelte +9 -1
- package/dist/molecules/Dropdown.svelte.d.ts +2 -0
- package/dist/molecules/DropdownItem.svelte +1 -1
- package/dist/molecules/ImageUpload.svelte +230 -120
- package/dist/molecules/ImageUpload.svelte.d.ts +38 -3
- package/dist/molecules/LineChart.svelte +459 -0
- package/dist/molecules/LineChart.svelte.d.ts +53 -0
- package/dist/molecules/MapView.svelte +565 -0
- package/dist/molecules/MapView.svelte.d.ts +88 -0
- package/dist/molecules/Modal.svelte +11 -6
- package/dist/molecules/PhotoGrid.svelte +100 -10
- package/dist/molecules/PhotoGrid.svelte.d.ts +11 -0
- package/dist/molecules/PhotoViewer.svelte +121 -24
- package/dist/molecules/PhotoViewer.svelte.d.ts +18 -0
- package/dist/molecules/PieChart.svelte +421 -0
- package/dist/molecules/PieChart.svelte.d.ts +51 -0
- package/dist/molecules/RadioGroup.svelte +20 -4
- package/dist/molecules/RadioGroup.svelte.d.ts +5 -0
- package/dist/molecules/SegmentedControl.svelte +136 -3
- package/dist/molecules/SegmentedControl.svelte.d.ts +6 -0
- package/dist/molecules/SidebarFooter.svelte +1 -1
- package/dist/molecules/SidebarNavSection.svelte +1 -1
- package/dist/molecules/SortableList.svelte +1 -0
- package/dist/molecules/Stepper.svelte +21 -7
- package/dist/molecules/StickyActionBar.svelte +67 -8
- package/dist/molecules/StickyActionBar.svelte.d.ts +14 -1
- package/dist/molecules/Tabs.svelte +79 -2
- package/dist/molecules/Toaster.svelte +171 -7
- package/dist/molecules/Toaster.svelte.d.ts +60 -2
- package/dist/molecules/ToasterToast.svelte +292 -60
- package/dist/molecules/ToasterToast.svelte.d.ts +6 -0
- package/dist/molecules/UnsavedChangesBar.svelte +13 -2
- package/dist/molecules/index.d.ts +7 -2
- package/dist/molecules/index.js +4 -0
- package/dist/molecules/toast-store.d.ts +30 -0
- package/dist/molecules/toast-store.js +4 -1
- package/dist/organisms/AppNavigation.svelte +440 -0
- package/dist/organisms/AppNavigation.svelte.d.ts +72 -0
- package/dist/organisms/AppShell.svelte +539 -39
- package/dist/organisms/AppShell.svelte.d.ts +102 -6
- package/dist/organisms/AppShellHeaderPart.svelte +163 -0
- package/dist/organisms/AppShellHeaderPart.svelte.d.ts +57 -0
- package/dist/organisms/SidebarNavigation.svelte +23 -36
- package/dist/organisms/SidebarPanel.svelte +10 -14
- package/dist/organisms/SidebarPanel.svelte.d.ts +1 -0
- package/dist/organisms/SidebarShell.svelte +2 -3
- package/dist/organisms/TopNavbar.svelte +117 -28
- package/dist/organisms/TopNavbar.svelte.d.ts +22 -1
- package/dist/organisms/TopNavbarSheetContent.svelte +145 -0
- package/dist/organisms/TopNavbarSheetContent.svelte.d.ts +24 -0
- package/dist/organisms/index.d.ts +6 -1
- package/dist/organisms/index.js +4 -0
- package/dist/types/components.d.ts +17 -1
- package/dist/types/components.d.ts.map +1 -1
- package/dist/types/index.d.ts +497 -10
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/variants.ts +14 -3
- package/dist/util/app-shell.d.ts +55 -4
- package/dist/util/app-shell.js +32 -7
- package/dist/util/avatar.d.ts +3 -0
- package/dist/util/bottom-tab-bar.d.ts +6 -0
- package/dist/util/chart.d.ts +139 -0
- package/dist/util/chart.js +305 -0
- package/dist/util/chip.d.ts +65 -0
- package/dist/util/chip.js +58 -0
- package/dist/util/cn.js +28 -2
- package/dist/util/code-field.d.ts +62 -0
- package/dist/util/code-field.js +112 -0
- package/dist/util/collapsible.d.ts +6 -0
- package/dist/util/display-voice.d.ts +9 -0
- package/dist/util/display-voice.js +9 -0
- package/dist/util/field-control.d.ts +29 -0
- package/dist/util/field-control.js +32 -0
- package/dist/util/field.d.ts +6 -0
- package/dist/util/focus-utils.d.ts +2 -0
- package/dist/util/focus-utils.js +4 -0
- package/dist/util/map-view.d.ts +143 -0
- package/dist/util/map-view.js +121 -0
- package/dist/util/photo.d.ts +19 -0
- package/dist/util/photo.js +3 -0
- package/dist/util/progress.d.ts +18 -0
- package/dist/util/progress.js +17 -0
- package/dist/util/scroll-edge.d.ts +32 -0
- package/dist/util/scroll-edge.js +87 -0
- package/dist/util/sheet-drag.d.ts +25 -1
- package/dist/util/sheet-drag.js +71 -1
- package/dist/util/skeleton.d.ts +14 -0
- package/dist/util/skeleton.js +22 -0
- package/dist/util/sliding-indicator.d.ts +24 -0
- package/dist/util/sliding-indicator.js +44 -0
- package/dist/util/temporal-field.d.ts +88 -0
- package/dist/util/temporal-field.js +136 -0
- package/dist/util/toaster.d.ts +40 -0
- package/dist/util/toaster.js +55 -0
- package/dist/util/tone-surface.d.ts +33 -0
- package/dist/util/tone-surface.js +35 -0
- package/dist/util/top-navbar.d.ts +26 -2
- package/dist/util/top-navbar.js +23 -0
- package/dist/util/zabi-strings.d.ts +9 -0
- package/dist/zabi-components-colors.css +9 -3
- package/dist/zabi-components-theme-dark-only.css +474 -164
- package/dist/zabi-components-theme-dark.css +474 -164
- package/dist/zabi-components-theme-only.css +933 -99
- package/dist/zabi-components-theme.css +933 -99
- package/dist/zabi-components.css +2275 -321
- package/package.json +11 -1
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import type { Snippet } from "svelte";
|
|
4
4
|
import type { HTMLAttributes } from "svelte/elements";
|
|
5
5
|
import ArrowLeft from "@lucide/svelte/icons/arrow-left";
|
|
6
|
-
import { findScrollParent } from "../util/app-shell.js";
|
|
6
|
+
import { findScrollParent, getAppShell, isDevBuild } from "../util/app-shell.js";
|
|
7
7
|
import { cn } from "../util/cn.js";
|
|
8
|
+
import { resolveScrolledUnder, watchScrollEdge, type ScrollEdgeMode } from "../util/scroll-edge.js";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* The bar at the top of a phone screen: where you are, the way back, and
|
|
@@ -23,6 +24,16 @@
|
|
|
23
24
|
* and the actions leave it less (a wide chip in `leading`, a very narrow
|
|
24
25
|
* bar), it takes a second row of its own, as wide as the bar, and they
|
|
25
26
|
* stay together on the first.
|
|
27
|
+
*
|
|
28
|
+
* The bar is flush with the page and page-coloured at rest. Once content
|
|
29
|
+
* has scrolled under it, it turns to frosted glass with a hairline below
|
|
30
|
+
* it. Inside an `AppShell` the shell says when; on a page of its own the
|
|
31
|
+
* bar watches the window or its nearest scrolling ancestor.
|
|
32
|
+
*
|
|
33
|
+
* With `largeTitle` the title is also drawn large on a second row under
|
|
34
|
+
* the bar. That row scrolls away with the content (nothing is animated),
|
|
35
|
+
* the 56px row stays, and its own small title fades in once the large
|
|
36
|
+
* one has gone under it. The heading is the large one.
|
|
26
37
|
*/
|
|
27
38
|
type Props = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
|
|
28
39
|
/** The name of the screen, as a heading. */
|
|
@@ -59,6 +70,11 @@
|
|
|
59
70
|
* width; when that leaves the title under 72px the title moves to a
|
|
60
71
|
* row of its own, and a `leading` wider than the row is held to the
|
|
61
72
|
* row's width.
|
|
73
|
+
* The bar's row is on a fixed pixel scale (`--spacing: 4px` on the
|
|
74
|
+
* row), so the bar's own controls do not grow with the text size.
|
|
75
|
+
* Size what you place here on the same scale (Tailwind numeric
|
|
76
|
+
* classes such as `size-9`, or `calc(var(--spacing) * 9)`), not in
|
|
77
|
+
* rem, or it grows at 200% text while the bar's controls do not.
|
|
62
78
|
*/
|
|
63
79
|
leading?: Snippet;
|
|
64
80
|
/**
|
|
@@ -66,8 +82,54 @@
|
|
|
66
82
|
* a 48px target; put anything more in a menu. Their size does not
|
|
67
83
|
* grow with the text size here: inside the bar the spacing scale is
|
|
68
84
|
* in px.
|
|
85
|
+
* The bar's row is on a fixed pixel scale (`--spacing: 4px` on the
|
|
86
|
+
* row), so the bar's own controls do not grow with the text size.
|
|
87
|
+
* Size what you place here on the same scale (Tailwind numeric
|
|
88
|
+
* classes such as `size-9`, or `calc(var(--spacing) * 9)`), not in
|
|
89
|
+
* rem, or it grows at 200% text while the bar's controls do not.
|
|
69
90
|
*/
|
|
70
91
|
actions?: Snippet;
|
|
92
|
+
/**
|
|
93
|
+
* When the bar shows the glass and the hairline. `auto` follows the
|
|
94
|
+
* scroll position: flush at the top, glass once content is under it.
|
|
95
|
+
* `always` is glass all the time, `never` flush all the time.
|
|
96
|
+
*/
|
|
97
|
+
scrollEdge?: ScrollEdgeMode;
|
|
98
|
+
/**
|
|
99
|
+
* Draws the title large (30px bold, two lines at most) on a second row
|
|
100
|
+
* under the bar. It scrolls away with the content; the bar keeps its
|
|
101
|
+
* 56px row, which shows the title small once the large one is gone.
|
|
102
|
+
* The heading is the large title; the small one is hidden from
|
|
103
|
+
* assistive technology. Needs `title`. `collapseOnScroll` is ignored
|
|
104
|
+
* with it. Before the bar has been measured (the server, no scripts)
|
|
105
|
+
* the whole header simply sticks and the large title stays.
|
|
106
|
+
*/
|
|
107
|
+
largeTitle?: boolean;
|
|
108
|
+
/**
|
|
109
|
+
* The bar's fill. `default` is the page colour at rest. `transparent`
|
|
110
|
+
* has none at rest, for a canvas, an image or a colour block laid
|
|
111
|
+
* behind the bar, and takes the glass once content is under it.
|
|
112
|
+
* `brand` is the brand colour with on-brand text and controls, at rest
|
|
113
|
+
* and scrolled, with no glass and no hairline, so a brand block
|
|
114
|
+
* directly under the bar joins it. With `largeTitle` the large row is
|
|
115
|
+
* part of the brand block.
|
|
116
|
+
* `inherit` is for a bar inside a block of another colour: no fill of
|
|
117
|
+
* its own, no glass and no hairline at any scroll position, and the
|
|
118
|
+
* title, back control, actions, links, borders and focus rings take
|
|
119
|
+
* the colour the block gives the text. A sticky bar that has to cover
|
|
120
|
+
* scrolling content takes its fill from the app:
|
|
121
|
+
* `class="[--color-bar:var(--my-block-colour)]"`.
|
|
122
|
+
*/
|
|
123
|
+
tone?: "default" | "transparent" | "brand" | "inherit";
|
|
124
|
+
/**
|
|
125
|
+
* `sticky` (default) keeps the bar at the top of what scrolls.
|
|
126
|
+
* `static` leaves it where it is in the page, for a bar that sits
|
|
127
|
+
* inside a block of the content: it scrolls away with the block, is
|
|
128
|
+
* never glass, and `collapseOnScroll` and the condensing of
|
|
129
|
+
* `largeTitle` do nothing. `class="static"`, the 8.1 way to say this,
|
|
130
|
+
* is read as `position="static"`.
|
|
131
|
+
*/
|
|
132
|
+
position?: "sticky" | "static";
|
|
71
133
|
class?: string;
|
|
72
134
|
};
|
|
73
135
|
|
|
@@ -81,6 +143,10 @@
|
|
|
81
143
|
titleLines = 1,
|
|
82
144
|
leading,
|
|
83
145
|
actions,
|
|
146
|
+
scrollEdge = "auto",
|
|
147
|
+
largeTitle = false,
|
|
148
|
+
tone = "default",
|
|
149
|
+
position = "sticky",
|
|
84
150
|
class: className = "",
|
|
85
151
|
...restProps
|
|
86
152
|
}: Props = $props();
|
|
@@ -90,15 +156,96 @@
|
|
|
90
156
|
const backLabel = $derived(backLabelGiven ?? common().back);
|
|
91
157
|
|
|
92
158
|
let host: HTMLElement | undefined = $state();
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* In the flow of the page, not stuck to the top. The material's layer is
|
|
162
|
+
* placed against the bar, so the bar is always positioned: `relative`
|
|
163
|
+
* here, and a `static` class from the caller is taken out and read as this.
|
|
164
|
+
*/
|
|
165
|
+
const classStatic = $derived(/(?:^|\s)static(?:\s|$)/.test(className));
|
|
166
|
+
const inFlow = $derived(position === "static" || classStatic);
|
|
167
|
+
const ownClass = $derived(
|
|
168
|
+
classStatic ? className.replace(/(?:^|\s)static(?=\s|$)/g, " ").trim() : className,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
/** A large title needs a title to be large. */
|
|
172
|
+
const large = $derived(largeTitle && !!title);
|
|
173
|
+
/** The two scroll behaviours fight: with a large title, `collapseOnScroll` is ignored. */
|
|
174
|
+
const collapses = $derived(collapseOnScroll && !large && !inFlow);
|
|
175
|
+
|
|
176
|
+
$effect(() => {
|
|
177
|
+
if (!isDevBuild()) return;
|
|
178
|
+
if (largeTitle && collapseOnScroll) {
|
|
179
|
+
console.warn(
|
|
180
|
+
"[zabi-components] AppBar: `collapseOnScroll` is ignored with `largeTitle`; " +
|
|
181
|
+
"the large title already condenses on scroll.",
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
/** The large row, and its measured height in px: how far the header sticks above the top. Null until measured. */
|
|
187
|
+
let largeRow: HTMLElement | undefined = $state();
|
|
188
|
+
let largeHeight = $state<number | null>(null);
|
|
189
|
+
const overscroll = $derived(
|
|
190
|
+
large && !inFlow && largeHeight !== null && largeHeight > 0 ? largeHeight : 0,
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
$effect(() => {
|
|
194
|
+
const el = largeRow;
|
|
195
|
+
if (!el || typeof ResizeObserver === "undefined") {
|
|
196
|
+
largeHeight = null;
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const measure = () => {
|
|
200
|
+
const height = el.getBoundingClientRect().height;
|
|
201
|
+
// No layout (a hidden bar, a test DOM): stay as unmeasured.
|
|
202
|
+
largeHeight = height > 0 ? height : null;
|
|
203
|
+
};
|
|
204
|
+
measure();
|
|
205
|
+
const observer = new ResizeObserver(measure);
|
|
206
|
+
observer.observe(el);
|
|
207
|
+
return () => observer.disconnect();
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
/** Content is under the bar: from the shell if there is one, else from its own scroller. */
|
|
211
|
+
const shell = getAppShell();
|
|
212
|
+
let ownScrolled = $state(false);
|
|
213
|
+
$effect(() => {
|
|
214
|
+
if (shell || (scrollEdge !== "auto" && !large) || !host) return;
|
|
215
|
+
return watchScrollEdge(findScrollParent(host), (edge) => (ownScrolled = edge.top), overscroll);
|
|
216
|
+
});
|
|
217
|
+
/** Past the large row: the standard title shows and the bar is over content. Never before it has been measured. */
|
|
218
|
+
const condensed = $derived(
|
|
219
|
+
large && overscroll > 0 && (shell ? shell.scrolledTop : ownScrolled),
|
|
220
|
+
);
|
|
221
|
+
const scrolledUnder = $derived(
|
|
222
|
+
// An opaque brand bar has no glass and no hairline whatever the mode says, nor has
|
|
223
|
+
// one that takes its block's colours (glass over any colour is not readable).
|
|
224
|
+
// Nor has a bar in the flow of the page: nothing scrolls under it.
|
|
225
|
+
tone === "brand" || tone === "inherit" || inFlow
|
|
226
|
+
? false
|
|
227
|
+
: resolveScrolledUnder(
|
|
228
|
+
scrollEdge,
|
|
229
|
+
large ? condensed : shell ? shell.scrolledTop : ownScrolled,
|
|
230
|
+
),
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
// Inside a shell the sticky container is the shell's header wrapper.
|
|
234
|
+
$effect(() => {
|
|
235
|
+
if (!shell || !(overscroll > 0)) return;
|
|
236
|
+
shell.setHeaderOverscroll(overscroll);
|
|
237
|
+
return () => shell.setHeaderOverscroll(0);
|
|
238
|
+
});
|
|
239
|
+
|
|
93
240
|
/** Scrolled out of view. Only ever true with `collapseOnScroll`. */
|
|
94
241
|
let scrolledAway = $state(false);
|
|
95
|
-
const collapsed = $derived(
|
|
242
|
+
const collapsed = $derived(collapses && scrolledAway);
|
|
96
243
|
|
|
97
244
|
/** Scrolling less than this in one direction does not move the bar. */
|
|
98
245
|
const SCROLL_TOLERANCE = 8;
|
|
99
246
|
|
|
100
247
|
$effect(() => {
|
|
101
|
-
if (!
|
|
248
|
+
if (!collapses || !host) return;
|
|
102
249
|
const bar = host;
|
|
103
250
|
const parent = findScrollParent(bar);
|
|
104
251
|
const target: HTMLElement | Window = parent ?? window;
|
|
@@ -187,8 +334,13 @@
|
|
|
187
334
|
});
|
|
188
335
|
|
|
189
336
|
/** A 48px ghost target, the same as `IconButton` at `variant="ghost" size="lg"`. */
|
|
190
|
-
const backClasses =
|
|
191
|
-
"focus-ring focus-ring--muted inline-flex size-12 shrink-0 cursor-pointer items-center justify-center rounded-control bg-transparent text-headline transition-colors duration-
|
|
337
|
+
const backClasses = $derived(
|
|
338
|
+
"focus-ring focus-ring--muted inline-flex size-12 shrink-0 cursor-pointer items-center justify-center rounded-control bg-transparent text-headline transition-colors duration-(--duration-base) " +
|
|
339
|
+
// The page's hover fills are a dark veil: on the brand fill the on-brand colour is what shows.
|
|
340
|
+
(tone === "brand" || tone === "inherit"
|
|
341
|
+
? "hover:bg-[color-mix(in_srgb,var(--color-on-brand)_16%,transparent)] active:bg-[color-mix(in_srgb,var(--color-on-brand)_26%,transparent)]"
|
|
342
|
+
: "hover:bg-surface-hover active:bg-surface-active"),
|
|
343
|
+
);
|
|
192
344
|
|
|
193
345
|
const hasBack = $derived(backHref !== undefined || onback !== undefined);
|
|
194
346
|
|
|
@@ -211,6 +363,35 @@
|
|
|
211
363
|
let leadingMax = $state<number | null>(null);
|
|
212
364
|
let row: HTMLElement | undefined = $state();
|
|
213
365
|
|
|
366
|
+
/** 1.875rem, and no more than 39px however large the text is set: capped as the bar's other sizes are. */
|
|
367
|
+
const largeClasses =
|
|
368
|
+
"appbar-large-title m-0 text-[length:min(1.875rem,39px)] leading-[1.15] font-bold text-headline line-clamp-2 [overflow-wrap:anywhere]";
|
|
369
|
+
|
|
370
|
+
const headerClasses = $derived(
|
|
371
|
+
cn(
|
|
372
|
+
cn(!large && "material-bar", inFlow ? "relative" : "sticky top-0 z-sticky"),
|
|
373
|
+
// Clear of the status bar and the notch, and of the corners in landscape. With a
|
|
374
|
+
// large title the status-bar strip is the 56px row's, so it stays covered when stuck.
|
|
375
|
+
large
|
|
376
|
+
? "pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]"
|
|
377
|
+
: "pt-[env(safe-area-inset-top)] pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]",
|
|
378
|
+
!large && "transition-transform duration-(--duration-moderate) ease-out motion-reduce:transition-none",
|
|
379
|
+
// The strip under the status bar stays, so content never shows through it.
|
|
380
|
+
!large && collapsed && "-translate-y-[calc(100%-env(safe-area-inset-top,0px))]",
|
|
381
|
+
// `--color-bar` is scoped on the element that carries `material-bar`.
|
|
382
|
+
!large && tone === "transparent" && "[--color-bar:transparent]",
|
|
383
|
+
!large && tone === "brand" && "[--color-bar:var(--color-bar-brand)]",
|
|
384
|
+
// With a large title the inner bar takes whatever the header says (see below), so a caller's fill reaches it.
|
|
385
|
+
tone === "inherit" && "[--color-bar:transparent]",
|
|
386
|
+
tone === "brand" && "on-brand",
|
|
387
|
+
// The on-brand scope with the on-colour left as the block's own text colour; the
|
|
388
|
+
// focus ring's gap is the block's, not the brand fill.
|
|
389
|
+
tone === "inherit" && "on-brand [--color-on-brand:currentColor] [--color-focus-ring-offset:transparent]",
|
|
390
|
+
// The caller's classes come last: their `[--color-bar:…]` replaces the tone's.
|
|
391
|
+
ownClass,
|
|
392
|
+
),
|
|
393
|
+
);
|
|
394
|
+
|
|
214
395
|
$effect(() => {
|
|
215
396
|
const bar = row;
|
|
216
397
|
if (!bar || typeof ResizeObserver === "undefined") return;
|
|
@@ -218,10 +399,18 @@
|
|
|
218
399
|
void title;
|
|
219
400
|
void titleLines;
|
|
220
401
|
|
|
402
|
+
// `offsetWidth` is rounded: actions 62.016px wide read as 62, the row came out
|
|
403
|
+
// 0.016px too wide for what was left and wrapped. The laid-out width, up to the
|
|
404
|
+
// next pixel (layout units are 1/64px, so the tiny allowance is only float noise).
|
|
405
|
+
const widthOf = (element: HTMLElement) => Math.ceil(element.getBoundingClientRect().width - 0.001);
|
|
406
|
+
|
|
221
407
|
const measure = () => {
|
|
222
408
|
const style = getComputedStyle(bar);
|
|
409
|
+
// Down to the whole pixel, as the parts are counted up to it: `clientWidth` rounds either way.
|
|
223
410
|
const inner =
|
|
224
|
-
bar.
|
|
411
|
+
Math.floor(bar.getBoundingClientRect().width + 0.001) -
|
|
412
|
+
parseFloat(style.paddingLeft) -
|
|
413
|
+
parseFloat(style.paddingRight);
|
|
225
414
|
// Nothing is laid out (a hidden bar): leave it as it is.
|
|
226
415
|
if (!(inner > 0)) return;
|
|
227
416
|
const gap = parseFloat(style.columnGap) || 0;
|
|
@@ -235,16 +424,18 @@
|
|
|
235
424
|
for (const child of bar.children) {
|
|
236
425
|
if (!(child instanceof HTMLElement)) continue;
|
|
237
426
|
const part = child.dataset.appbarPart;
|
|
238
|
-
|
|
427
|
+
const width = widthOf(child);
|
|
428
|
+
if (part === "title" || width <= 0) continue;
|
|
239
429
|
parts += 1;
|
|
240
|
-
beside +=
|
|
430
|
+
beside += width;
|
|
241
431
|
// The back control and the actions keep their width whatever happens.
|
|
242
|
-
if (part === "back" || part === "actions") fixed +=
|
|
432
|
+
if (part === "back" || part === "actions") fixed += width;
|
|
243
433
|
}
|
|
244
434
|
delete bar.dataset.measuring;
|
|
245
435
|
|
|
246
436
|
const left = inner - beside - gap * parts;
|
|
247
|
-
|
|
437
|
+
// A bar with no title has nothing to put on a row of its own.
|
|
438
|
+
const next = title && left < TITLE_MIN ? "own" : "inline";
|
|
248
439
|
if (next !== titleRow) titleRow = next;
|
|
249
440
|
const fixedParts = bar.querySelectorAll(
|
|
250
441
|
":scope > [data-appbar-part='back'], :scope > [data-appbar-part='actions']",
|
|
@@ -274,20 +465,7 @@
|
|
|
274
465
|
});
|
|
275
466
|
</script>
|
|
276
467
|
|
|
277
|
-
|
|
278
|
-
bind:this={host}
|
|
279
|
-
data-collapsed={collapseOnScroll ? String(collapsed) : undefined}
|
|
280
|
-
class={cn(
|
|
281
|
-
"sticky top-0 z-sticky border-b border-border-weak bg-surface-elevated",
|
|
282
|
-
// Clear of the status bar and the notch, and of the corners in landscape.
|
|
283
|
-
"pt-[env(safe-area-inset-top)] pl-[env(safe-area-inset-left)] pr-[env(safe-area-inset-right)]",
|
|
284
|
-
"transition-transform duration-200 ease-out motion-reduce:transition-none",
|
|
285
|
-
// The strip under the status bar stays, so content never shows through it.
|
|
286
|
-
collapsed && "-translate-y-[calc(100%-env(safe-area-inset-top,0px))]",
|
|
287
|
-
className,
|
|
288
|
-
)}
|
|
289
|
-
{...restProps}
|
|
290
|
-
>
|
|
468
|
+
{#snippet barRow()}
|
|
291
469
|
<!-- `--spacing: 4px`: Tailwind sizes everything from `--spacing`, which
|
|
292
470
|
is 0.25rem, so a 48px button was 96px with the text at 200% and the bar
|
|
293
471
|
wrapped to 225px. In px here, the back control, the actions and whatever
|
|
@@ -300,10 +478,11 @@
|
|
|
300
478
|
<div
|
|
301
479
|
bind:this={row}
|
|
302
480
|
data-title-row={titleRow ?? undefined}
|
|
481
|
+
data-title-empty={title ? undefined : ""}
|
|
303
482
|
style:--appbar-leading-max={leadingMax !== null ? `${leadingMax}px` : undefined}
|
|
304
483
|
class={cn(
|
|
305
484
|
"appbar-row flex min-h-14 items-center gap-2 px-2 py-1 [--spacing:4px]",
|
|
306
|
-
"transition-opacity duration-
|
|
485
|
+
"transition-opacity duration-(--duration-moderate) ease-out motion-reduce:transition-none",
|
|
307
486
|
collapsed && "pointer-events-none opacity-0",
|
|
308
487
|
)}
|
|
309
488
|
>
|
|
@@ -322,14 +501,22 @@
|
|
|
322
501
|
`titleLines={2}`. 1.125rem, and no more than 1.3 times that
|
|
323
502
|
(23.4px) however large the text is set.
|
|
324
503
|
One branch per level, not a dynamic element: hydration takes a dynamic
|
|
325
|
-
element out and puts it back, which blurs a control inside it that the
|
|
326
|
-
had already tabbed to. -->
|
|
504
|
+
element out and puts it back, which blurs a control inside it that the
|
|
505
|
+
user had already tabbed to. -->
|
|
327
506
|
{@const titleClasses = cn(
|
|
328
507
|
"appbar-title m-0 text-[length:min(1.125rem,23.4px)] leading-[1.34] font-semibold text-headline",
|
|
329
508
|
titleLines === 2 ? "line-clamp-2 [overflow-wrap:anywhere]" : "truncate",
|
|
330
509
|
!hasBack && !leading && "ps-2",
|
|
331
510
|
)}
|
|
332
|
-
{#if
|
|
511
|
+
{#if large}
|
|
512
|
+
<!-- The large row holds the heading. This one only repeats the text for the
|
|
513
|
+
eye, in the title's place so the row measures as before. -->
|
|
514
|
+
<p
|
|
515
|
+
class={cn(titleClasses, "transition-opacity duration-(--duration-base)", condensed ? "opacity-100" : "opacity-0")}
|
|
516
|
+
data-appbar-part="title"
|
|
517
|
+
aria-hidden="true"
|
|
518
|
+
>{title}</p>
|
|
519
|
+
{:else if headingLevel === 1}
|
|
333
520
|
<h1 class={titleClasses} data-appbar-part="title">{title}</h1>
|
|
334
521
|
{:else if headingLevel === 2}
|
|
335
522
|
<h2 class={titleClasses} data-appbar-part="title">{title}</h2>
|
|
@@ -343,6 +530,7 @@
|
|
|
343
530
|
<h6 class={titleClasses} data-appbar-part="title">{title}</h6>
|
|
344
531
|
{/if}
|
|
345
532
|
{:else}
|
|
533
|
+
<!-- Nothing to show: no width, so no 72px to find room for. -->
|
|
346
534
|
<div class="min-w-0 flex-1" data-appbar-part="title"></div>
|
|
347
535
|
{/if}
|
|
348
536
|
{#if actions}
|
|
@@ -351,6 +539,61 @@
|
|
|
351
539
|
</div>
|
|
352
540
|
{/if}
|
|
353
541
|
</div>
|
|
542
|
+
{/snippet}
|
|
543
|
+
|
|
544
|
+
<header
|
|
545
|
+
bind:this={host}
|
|
546
|
+
data-appbar=""
|
|
547
|
+
data-tone={tone}
|
|
548
|
+
data-large-title={large ? "" : undefined}
|
|
549
|
+
data-condensed={large ? String(condensed) : undefined}
|
|
550
|
+
data-collapsed={collapses ? String(collapsed) : undefined}
|
|
551
|
+
data-scrolled-under={large ? undefined : String(scrolledUnder)}
|
|
552
|
+
style:top={large && !shell && overscroll > 0 ? `-${overscroll}px` : undefined}
|
|
553
|
+
class={headerClasses}
|
|
554
|
+
{...restProps}
|
|
555
|
+
>
|
|
556
|
+
{#if large}
|
|
557
|
+
<!-- Two rows. The header sticks at minus the large row's height and the
|
|
558
|
+
56px row sticks at 0 inside it, so the large row scrolls away behind a bar
|
|
559
|
+
that stays: no scroll-linked animation, no jump. The surface and the
|
|
560
|
+
status-bar strip belong to the 56px row; the large row is on the page
|
|
561
|
+
(on the brand fill, with `tone="brand"`). -->
|
|
562
|
+
<div
|
|
563
|
+
data-appbar-bar
|
|
564
|
+
data-scrolled-under={String(scrolledUnder)}
|
|
565
|
+
class={cn(
|
|
566
|
+
"material-bar pt-[env(safe-area-inset-top)]",
|
|
567
|
+
inFlow ? "relative" : "sticky top-0",
|
|
568
|
+
tone === "transparent" && "[--color-bar:transparent]",
|
|
569
|
+
tone === "brand" && "[--color-bar:var(--color-bar-brand)]",
|
|
570
|
+
tone === "inherit" && "[--color-bar:inherit]",
|
|
571
|
+
)}
|
|
572
|
+
>
|
|
573
|
+
{@render barRow()}
|
|
574
|
+
</div>
|
|
575
|
+
<div
|
|
576
|
+
bind:this={largeRow}
|
|
577
|
+
data-appbar-large
|
|
578
|
+
class={cn("px-[16px] pt-[4px] pb-[8px]", tone === "brand" && "bg-bar-brand")}
|
|
579
|
+
>
|
|
580
|
+
{#if headingLevel === 1}
|
|
581
|
+
<h1 class={largeClasses}>{title}</h1>
|
|
582
|
+
{:else if headingLevel === 2}
|
|
583
|
+
<h2 class={largeClasses}>{title}</h2>
|
|
584
|
+
{:else if headingLevel === 3}
|
|
585
|
+
<h3 class={largeClasses}>{title}</h3>
|
|
586
|
+
{:else if headingLevel === 4}
|
|
587
|
+
<h4 class={largeClasses}>{title}</h4>
|
|
588
|
+
{:else if headingLevel === 5}
|
|
589
|
+
<h5 class={largeClasses}>{title}</h5>
|
|
590
|
+
{:else}
|
|
591
|
+
<h6 class={largeClasses}>{title}</h6>
|
|
592
|
+
{/if}
|
|
593
|
+
</div>
|
|
594
|
+
{:else}
|
|
595
|
+
{@render barRow()}
|
|
596
|
+
{/if}
|
|
354
597
|
</header>
|
|
355
598
|
|
|
356
599
|
<style>
|
|
@@ -404,6 +647,22 @@
|
|
|
404
647
|
padding-block-end: 4px;
|
|
405
648
|
}
|
|
406
649
|
|
|
650
|
+
/*
|
|
651
|
+
* No title: the empty part asks for no width and no row, on the server
|
|
652
|
+
* and before measuring as well. One row whatever `leading` holds, which
|
|
653
|
+
* is cut to the room beside the back control and the actions. The part
|
|
654
|
+
* pulls back one gap, so the row spends none on it.
|
|
655
|
+
*/
|
|
656
|
+
.appbar-row[data-title-empty] {
|
|
657
|
+
flex-wrap: nowrap;
|
|
658
|
+
}
|
|
659
|
+
.appbar-row[data-title-empty] :global(> [data-appbar-part="title"]) {
|
|
660
|
+
flex: 0 0 0;
|
|
661
|
+
min-width: 0;
|
|
662
|
+
padding: 0;
|
|
663
|
+
margin-inline-end: -8px;
|
|
664
|
+
}
|
|
665
|
+
|
|
407
666
|
/* While it measures: every part at the width it asks for, on one line. */
|
|
408
667
|
.appbar-row[data-measuring] {
|
|
409
668
|
flex-wrap: nowrap;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Snippet } from "svelte";
|
|
2
2
|
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
+
import { type ScrollEdgeMode } from "../util/scroll-edge.js";
|
|
3
4
|
/**
|
|
4
5
|
* The bar at the top of a phone screen: where you are, the way back, and
|
|
5
6
|
* at most two things to do here.
|
|
@@ -17,6 +18,16 @@ import type { HTMLAttributes } from "svelte/elements";
|
|
|
17
18
|
* and the actions leave it less (a wide chip in `leading`, a very narrow
|
|
18
19
|
* bar), it takes a second row of its own, as wide as the bar, and they
|
|
19
20
|
* stay together on the first.
|
|
21
|
+
*
|
|
22
|
+
* The bar is flush with the page and page-coloured at rest. Once content
|
|
23
|
+
* has scrolled under it, it turns to frosted glass with a hairline below
|
|
24
|
+
* it. Inside an `AppShell` the shell says when; on a page of its own the
|
|
25
|
+
* bar watches the window or its nearest scrolling ancestor.
|
|
26
|
+
*
|
|
27
|
+
* With `largeTitle` the title is also drawn large on a second row under
|
|
28
|
+
* the bar. That row scrolls away with the content (nothing is animated),
|
|
29
|
+
* the 56px row stays, and its own small title fades in once the large
|
|
30
|
+
* one has gone under it. The heading is the large one.
|
|
20
31
|
*/
|
|
21
32
|
type Props = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
|
|
22
33
|
/** The name of the screen, as a heading. */
|
|
@@ -53,6 +64,11 @@ type Props = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
|
|
|
53
64
|
* width; when that leaves the title under 72px the title moves to a
|
|
54
65
|
* row of its own, and a `leading` wider than the row is held to the
|
|
55
66
|
* row's width.
|
|
67
|
+
* The bar's row is on a fixed pixel scale (`--spacing: 4px` on the
|
|
68
|
+
* row), so the bar's own controls do not grow with the text size.
|
|
69
|
+
* Size what you place here on the same scale (Tailwind numeric
|
|
70
|
+
* classes such as `size-9`, or `calc(var(--spacing) * 9)`), not in
|
|
71
|
+
* rem, or it grows at 200% text while the bar's controls do not.
|
|
56
72
|
*/
|
|
57
73
|
leading?: Snippet;
|
|
58
74
|
/**
|
|
@@ -60,8 +76,54 @@ type Props = Omit<HTMLAttributes<HTMLElement>, "class" | "title"> & {
|
|
|
60
76
|
* a 48px target; put anything more in a menu. Their size does not
|
|
61
77
|
* grow with the text size here: inside the bar the spacing scale is
|
|
62
78
|
* in px.
|
|
79
|
+
* The bar's row is on a fixed pixel scale (`--spacing: 4px` on the
|
|
80
|
+
* row), so the bar's own controls do not grow with the text size.
|
|
81
|
+
* Size what you place here on the same scale (Tailwind numeric
|
|
82
|
+
* classes such as `size-9`, or `calc(var(--spacing) * 9)`), not in
|
|
83
|
+
* rem, or it grows at 200% text while the bar's controls do not.
|
|
63
84
|
*/
|
|
64
85
|
actions?: Snippet;
|
|
86
|
+
/**
|
|
87
|
+
* When the bar shows the glass and the hairline. `auto` follows the
|
|
88
|
+
* scroll position: flush at the top, glass once content is under it.
|
|
89
|
+
* `always` is glass all the time, `never` flush all the time.
|
|
90
|
+
*/
|
|
91
|
+
scrollEdge?: ScrollEdgeMode;
|
|
92
|
+
/**
|
|
93
|
+
* Draws the title large (30px bold, two lines at most) on a second row
|
|
94
|
+
* under the bar. It scrolls away with the content; the bar keeps its
|
|
95
|
+
* 56px row, which shows the title small once the large one is gone.
|
|
96
|
+
* The heading is the large title; the small one is hidden from
|
|
97
|
+
* assistive technology. Needs `title`. `collapseOnScroll` is ignored
|
|
98
|
+
* with it. Before the bar has been measured (the server, no scripts)
|
|
99
|
+
* the whole header simply sticks and the large title stays.
|
|
100
|
+
*/
|
|
101
|
+
largeTitle?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* The bar's fill. `default` is the page colour at rest. `transparent`
|
|
104
|
+
* has none at rest, for a canvas, an image or a colour block laid
|
|
105
|
+
* behind the bar, and takes the glass once content is under it.
|
|
106
|
+
* `brand` is the brand colour with on-brand text and controls, at rest
|
|
107
|
+
* and scrolled, with no glass and no hairline, so a brand block
|
|
108
|
+
* directly under the bar joins it. With `largeTitle` the large row is
|
|
109
|
+
* part of the brand block.
|
|
110
|
+
* `inherit` is for a bar inside a block of another colour: no fill of
|
|
111
|
+
* its own, no glass and no hairline at any scroll position, and the
|
|
112
|
+
* title, back control, actions, links, borders and focus rings take
|
|
113
|
+
* the colour the block gives the text. A sticky bar that has to cover
|
|
114
|
+
* scrolling content takes its fill from the app:
|
|
115
|
+
* `class="[--color-bar:var(--my-block-colour)]"`.
|
|
116
|
+
*/
|
|
117
|
+
tone?: "default" | "transparent" | "brand" | "inherit";
|
|
118
|
+
/**
|
|
119
|
+
* `sticky` (default) keeps the bar at the top of what scrolls.
|
|
120
|
+
* `static` leaves it where it is in the page, for a bar that sits
|
|
121
|
+
* inside a block of the content: it scrolls away with the block, is
|
|
122
|
+
* never glass, and `collapseOnScroll` and the condensing of
|
|
123
|
+
* `largeTitle` do nothing. `class="static"`, the 8.1 way to say this,
|
|
124
|
+
* is read as `position="static"`.
|
|
125
|
+
*/
|
|
126
|
+
position?: "sticky" | "static";
|
|
65
127
|
class?: string;
|
|
66
128
|
};
|
|
67
129
|
declare const AppBar: import("svelte").Component<Props, {}, "">;
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
>
|
|
94
94
|
{#each shown as person, index (index)}
|
|
95
95
|
<li class={cn("flex", index > 0 && (OVERLAP[size] ?? OVERLAP.md))}>
|
|
96
|
-
<Avatar name={person.name} src={person.src} {size} {locale} class={ring} />
|
|
96
|
+
<Avatar name={person.name} src={person.src} children={person.picture} {size} {locale} class={ring} />
|
|
97
97
|
</li>
|
|
98
98
|
{/each}
|
|
99
99
|
{#if split.hidden > 0}
|