Skip to content

Commit e6db9f2

Browse files
committed
fix: adjust position of snackbar when a page level bottom app bar is present
1 parent c9f0726 commit e6db9f2

File tree

8 files changed

+200
-11
lines changed

8 files changed

+200
-11
lines changed

packages/bottom-app-bar/_mixins.scss

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,26 @@ $acceleration-curve-timing-function: cubic-bezier(0.4, 0, 1, 1) !default;
136136
padding-bottom: $section-height;
137137
}
138138

139+
.smui-bottom-app-bar--fixed-adjust,
140+
.smui-bottom-app-bar--standard-adjust {
141+
.mdc-snackbar {
142+
transform: translateY(
143+
calc((-1 * $section-height) - var(--smui-bottom-app-bar--fab-offset, 0))
144+
);
145+
}
146+
147+
&.smui-bottom-app-bar--with-fab {
148+
.mdc-snackbar {
149+
transform: translateY(
150+
calc(
151+
(-1 * ($section-height + math.div($fab-diameter, 2))) -
152+
var(--smui-bottom-app-bar--fab-offset, 0)
153+
)
154+
);
155+
}
156+
}
157+
}
158+
139159
/*
140160
"What the fuck is this nonsense?" (I hear you asking after reading the
141161
following styles.)

packages/bottom-app-bar/src/AutoAdjust.svelte

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
[className]: true,
88
[adjustClass]: true,
99
})}
10+
style={Object.entries(internalStyles)
11+
.map(([name, value]) => `${name}: ${value};`)
12+
.concat([style])
13+
.join(' ')}
1014
{...$$restProps}
1115
>
1216
<slot />
@@ -25,6 +29,7 @@
2529
type OwnProps = {
2630
use?: ActionArray;
2731
class?: string;
32+
style?: string;
2833
bottomAppBar: BottomAppBar;
2934
component?: Component;
3035
tag?: TagName;
@@ -40,6 +45,7 @@
4045
export let use: ActionArray = [];
4146
let className = '';
4247
export { className as class };
48+
export let style = '';
4349
export let bottomAppBar: BottomAppBar;
4450
4551
let element: SvelteComponent;
@@ -49,19 +55,34 @@
4955
component === (SmuiElement as unknown as Component) ? 'main' : undefined
5056
) as TagName | undefined;
5157
58+
let internalStyles: { [k: string]: string } = {};
5259
$: propStore = bottomAppBar && bottomAppBar.getPropStore();
5360
$: adjustClass = (() => {
54-
if (
55-
!propStore ||
56-
$propStore.variant === 'standard' ||
57-
$propStore.variant === 'static'
58-
) {
61+
if (!propStore || $propStore.variant === 'static') {
5962
return '';
6063
}
6164
62-
return 'smui-bottom-app-bar--fixed-adjust';
65+
addStyle(
66+
'--smui-bottom-app-bar--fab-offset',
67+
$propStore.adjustOffset + 'px'
68+
);
69+
70+
return `smui-bottom-app-bar--${$propStore.variant}-adjust ${
71+
$propStore.withFab ? 'smui-bottom-app-bar--with-fab' : ''
72+
}`;
6373
})();
6474
75+
function addStyle(name: string, value: string) {
76+
if (internalStyles[name] != value) {
77+
if (value === '' || value == null) {
78+
delete internalStyles[name];
79+
internalStyles = internalStyles;
80+
} else {
81+
internalStyles[name] = value;
82+
}
83+
}
84+
}
85+
6586
export function getElement(): HTMLElement {
6687
return element.getElement();
6788
}

packages/bottom-app-bar/src/BottomAppBar.svelte

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
</div>
2121

2222
<script lang="ts">
23-
import { setContext } from 'svelte';
23+
import { afterUpdate, setContext } from 'svelte';
2424
import { get_current_component } from 'svelte/internal';
2525
import type { Subscriber } from 'svelte/store';
2626
import { readable, writable } from 'svelte/store';
@@ -55,20 +55,39 @@
5555
5656
let internalStyles: { [k: string]: string } = {};
5757
const colorStore = writable(color);
58+
let withFab = false;
59+
let adjustOffset = 0;
5860
$: $colorStore = color;
5961
setContext('SMUI:bottom-app-bar:color', colorStore);
6062
let propStoreSet: Subscriber<{
63+
withFab: boolean;
64+
adjustOffset: number;
6165
variant: 'fixed' | 'static' | 'standard';
6266
}>;
63-
let propStore = readable({ variant }, (set) => {
64-
propStoreSet = set;
65-
});
67+
let propStore = readable(
68+
{
69+
withFab,
70+
adjustOffset,
71+
variant,
72+
},
73+
(set) => {
74+
propStoreSet = set;
75+
}
76+
);
6677
$: if (propStoreSet) {
6778
propStoreSet({
79+
withFab,
80+
adjustOffset,
6881
variant,
6982
});
7083
}
7184
85+
afterUpdate(() => {
86+
if (variant === 'standard' || variant === 'fixed') {
87+
withFab = element.querySelector<HTMLDivElement>('.mdc-fab') != null;
88+
}
89+
});
90+
7291
function addStyle(name: string, value: string) {
7392
if (internalStyles[name] != value) {
7493
if (value === '' || value == null) {
@@ -136,6 +155,7 @@
136155
} else if (oldVariant === 'standard') {
137156
addStyle('bottom', '');
138157
addStyle('--smui-bottom-app-bar--fab-offset', '0px');
158+
adjustOffset = 0;
139159
}
140160
oldVariant = variant;
141161
}
@@ -232,6 +252,10 @@
232252
let offset = currentAppBarOffsetBottom;
233253
addStyle('--smui-bottom-app-bar--fab-offset', offset * 0.75 + 'px');
234254
addStyle('bottom', offset + 'px');
255+
adjustOffset = offset;
256+
if (withFab) {
257+
adjustOffset -= +offset * 0.75;
258+
}
235259
}
236260
}
237261
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function FixedAdjust(node: HTMLElement) {
2+
node.classList.add('smui-bottom-app-bar--standard-adjust');
3+
4+
return {
5+
destroy() {
6+
node.classList.remove('smui-bottom-app-bar--standard-adjust');
7+
},
8+
};
9+
}

packages/bottom-app-bar/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import BottomAppBar from './BottomAppBar.svelte';
33
import AutoAdjust from './AutoAdjust.svelte';
44
import FixedAdjust from './FixedAdjust.js';
55
import Section from './Section.svelte';
6+
import StandardAdjust from './StandardAdjust.js';
67

78
export default BottomAppBar;
89

9-
export { AutoAdjust, FixedAdjust, Section };
10+
export { AutoAdjust, FixedAdjust, Section, StandardAdjust };

packages/site/src/routes/demo/bottom-app-bar/+page.svelte

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@
4747
inset.
4848
</svelte:fragment>
4949
</Demo>
50+
51+
<Demo
52+
component={Snackbar}
53+
files={['bottom-app-bar/iframe/snackbar/+page.svelte']}
54+
>
55+
Snackbar positioning
56+
<svelte:fragment slot="subtitle">
57+
The snackbar is positioned above the bottom app bar. Note: to follow
58+
scrolling adjustments with the "standard" variant, this requires the
59+
AutoAdjust component.
60+
</svelte:fragment>
61+
</Demo>
5062
</section>
5163

5264
<script lang="ts">
@@ -56,4 +68,5 @@
5668
import Variants from './_Variants.svelte';
5769
import Fab from './_Fab.svelte';
5870
import InsetFab from './_InsetFab.svelte';
71+
import Snackbar from './_Snackbar.svelte';
5972
</script>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!-- Check out iframe/*.svelte too see how these work. -->
2+
<iframe
3+
class="bottom-app-bar-iframe"
4+
src="/demo/bottom-app-bar/iframe/snackbar"
5+
title="snackbar"
6+
/>
7+
<a style="display: none;" href="/demo/bottom-app-bar/iframe/snackbar"
8+
>helper needed for export</a
9+
>
10+
11+
<style>
12+
.bottom-app-bar-iframe {
13+
max-width: 480px;
14+
width: 100%;
15+
height: 320px;
16+
border: 1px solid
17+
var(--mdc-theme-text-hint-on-background, rgba(0, 0, 0, 0.1));
18+
margin: 0 18px 18px 0;
19+
}
20+
21+
@media (max-width: 480px) {
22+
.bottom-app-bar-iframe {
23+
margin-right: 0;
24+
}
25+
}
26+
</style>
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<AutoAdjust {bottomAppBar}>
2+
<h5>Standard</h5>
3+
4+
<div>
5+
<FormField>
6+
<Checkbox bind:checked={withFab} />
7+
<span slot="label">With FAB</span>
8+
</FormField>
9+
</div>
10+
11+
<Button on:click={() => snackbar.open()}>
12+
<Label>Open Snackbar</Label>
13+
</Button>
14+
15+
<Snackbar bind:this={snackbar}>
16+
<Label>This is a snackbar.</Label>
17+
<Actions>
18+
<IconButton class="material-icons" title="Dismiss">close</IconButton>
19+
</Actions>
20+
</Snackbar>
21+
22+
<LoremIpsum />
23+
<img
24+
alt="Page content placeholder"
25+
src="/page-content.jpg"
26+
style="display: block; max-width: 100%; height: auto; margin: 1em auto;"
27+
/>
28+
</AutoAdjust>
29+
30+
<BottomAppBar bind:this={bottomAppBar}>
31+
<Section>
32+
<IconButton class="material-icons">menu</IconButton>
33+
</Section>
34+
{#if withFab}
35+
<Section fabInset>
36+
<Fab aria-label="New item">
37+
<Icon class="material-icons">add</Icon>
38+
</Fab>
39+
</Section>
40+
{/if}
41+
<Section>
42+
<IconButton class="material-icons" aria-label="Search">search</IconButton>
43+
<IconButton class="material-icons" aria-label="More">more_vert</IconButton>
44+
</Section>
45+
</BottomAppBar>
46+
47+
<script lang="ts">
48+
import BottomAppBar, {
49+
Section,
50+
AutoAdjust,
51+
} from '@smui-extra/bottom-app-bar';
52+
import Snackbar, { Actions, Label } from '@smui/snackbar';
53+
import Button from '@smui/button';
54+
import IconButton from '@smui/icon-button';
55+
import Fab, { Icon } from '@smui/fab';
56+
import Checkbox from '@smui/checkbox';
57+
import FormField from '@smui/form-field';
58+
import LoremIpsum from '$lib/LoremIpsum.svelte';
59+
60+
let bottomAppBar: BottomAppBar;
61+
let snackbar: Snackbar;
62+
let withFab = false;
63+
</script>
64+
65+
<style>
66+
/* Hide everything above this component. */
67+
:global(#smui-app),
68+
:global(body),
69+
:global(html) {
70+
display: block !important;
71+
height: auto !important;
72+
width: auto !important;
73+
position: static !important;
74+
}
75+
</style>

0 commit comments

Comments
 (0)