Skip to content

Commit 550ac93

Browse files
committed
feat: reduce Ripple arguments and add class forwarding option
1 parent eb52cc6 commit 550ac93

File tree

8 files changed

+81
-39
lines changed

8 files changed

+81
-39
lines changed

packages/button/Button.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<svelte:component
22
this={component}
3-
use={[forwardEvents, [Ripple, [ripple, {unbounded: false}]], ...use]}
3+
use={[[Ripple, {ripple, unbounded: false, classForward: classes => rippleClasses = classes}], forwardEvents, ...use]}
44
class="
55
mdc-button
66
{className}
7+
{rippleClasses.join(' ')}
78
{variant === 'raised' ? 'mdc-button--raised' : ''}
89
{variant === 'unelevated' ? 'mdc-button--unelevated' : ''}
910
{variant === 'outlined' ? 'mdc-button--outlined' : ''}
@@ -48,6 +49,7 @@
4849
export let component = href == null ? Button : A;
4950
5051
let context = getContext('SMUI:button:context');
52+
let rippleClasses = [];
5153
5254
$: dialogExcludes = (context === 'dialog:action') ? ['action', 'default'] : [];
5355

packages/card/PrimaryAction.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{className}
77
{padded ? 'smui-card__primary-action--padded' : ''}
88
"
9-
use:Ripple={[ripple, {unbounded: false, color}]}
9+
use:Ripple={{ripple, unbounded: false, color}}
1010
{tabindex}
1111
{...exclude($$props, ['use', 'class', 'ripple', 'color', 'padded', 'tabindex'])}
1212
><slot></slot></div>

packages/fab/Fab.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{extended ? 'mdc-fab--extended' : ''}
1010
{color === 'primary' ? 'smui-fab--color-primary' : ''}
1111
"
12-
use:Ripple={[ripple, {unbounded: false}]}
12+
use:Ripple={{ripple, unbounded: false}}
1313
{...exclude($$props, ['use', 'class', 'ripple', 'color', 'mini', 'exited', 'extended'])}
1414
><slot></slot></button>
1515

packages/icon-button/IconButton.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
{context === 'top-app-bar:action' ? 'mdc-top-app-bar__action-item' : ''}
1414
{context === 'snackbar' ? 'mdc-snackbar__dismiss' : ''}
1515
"
16-
use:Ripple={[ripple && !toggle, {unbounded: true, color}]}
16+
use:Ripple={{ripple: ripple && !toggle, unbounded: true, color}}
1717
aria-hidden="true"
1818
aria-pressed={pressed}
1919
{href}
@@ -35,7 +35,7 @@
3535
{context === 'top-app-bar:action' ? 'mdc-top-app-bar__action-item' : ''}
3636
{context === 'snackbar' ? 'mdc-snackbar__dismiss' : ''}
3737
"
38-
use:Ripple={[ripple && !toggle, {unbounded: true, color}]}
38+
use:Ripple={{ripple: ripple && !toggle, unbounded: true, color}}
3939
aria-hidden="true"
4040
aria-pressed={pressed}
4141
on:MDCIconButtonToggle:change={handleChange}

packages/list/Item.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{selected ? 'mdc-list-item--selected' : ''}
1111
{disabled ? 'mdc-list-item--disabled' : ''}
1212
"
13-
use:Ripple={[ripple, {unbounded: false, color}]}
13+
use:Ripple={{ripple, unbounded: false, color}}
1414
{href}
1515
{...(activated ? {'aria-current': 'page'} : {})}
1616
{tabindex}
@@ -30,7 +30,7 @@
3030
{selected ? 'mdc-list-item--selected' : ''}
3131
{disabled ? 'mdc-list-item--disabled' : ''}
3232
"
33-
use:Ripple={[ripple, {unbounded: false, color}]}
33+
use:Ripple={{ripple, unbounded: false, color}}
3434
{...(activated ? {'aria-current': 'page'} : {})}
3535
{tabindex}
3636
on:click={action}
@@ -50,7 +50,7 @@
5050
{disabled ? 'mdc-list-item--disabled' : ''}
5151
{(role === 'menuitem' && selected) ? 'mdc-menu-item--selected' : ''}
5252
"
53-
use:Ripple={[ripple, {unbounded: false, color}]}
53+
use:Ripple={{ripple, unbounded: false, color}}
5454
{role}
5555
{...(role === 'option' ? {'aria-selected': (selected ? 'true' : 'false')} : {})}
5656
{...((role === 'radio' || role === 'checkbox') ? {'aria-checked': (checked ? 'true' : 'false')} : {})}

packages/ripple/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ npm install --save-dev @smui/ripple
1919
import Ripple from '@smui/ripple';
2020
</script>
2121

22-
<p use:Ripple={[true, {color: 'surface'}]} tabindex="0">
22+
<p use:Ripple={{ripple: true, color: 'surface'}} tabindex="0">
2323
Here is an element with a ripple.
2424
</p>
2525
```
@@ -40,5 +40,7 @@ A ripple Svelte action.
4040

4141
The action accepts an array, with two entries. The first is a boolean, whether the ripple is enabled. The second is an object with the props:
4242

43+
* `ripple` - Whether to enable the ripple.
4344
* `unbounded` - Whether the ripple is unbounded.
44-
* `color` - The ripple color. ('surface', 'primary', or 'secondary')
45+
* `color` - The ripple color. ('surface', 'primary', or 'secondary')
46+
* `classForward` - A function that receives an array of classes. This is used to work around Svelte removing ripple classes in certain scenarios.

packages/ripple/Ripple.js

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,83 @@
11
import {MDCRipple} from '@material/ripple';
22
import {getContext} from 'svelte';
33

4-
export default function Ripple(node, [ripple, props = {unbounded: false, color: null}]) {
4+
export default function Ripple(node, props = {ripple: false, unbounded: false, color: null, classForward: () => {}}) {
55
let instance = null;
66
let addLayoutListener = getContext('SMUI:addLayoutListener');
77
let removeLayoutListener;
8+
let classList = [];
89

9-
function handleProps(ripple, props) {
10-
if (ripple && !instance) {
10+
function addClass(className) {
11+
const idx = classList.indexOf(className);
12+
if (idx === -1) {
13+
node.classList.add(className);
14+
classList.push(className);
15+
if (props.classForward) {
16+
props.classForward(classList);
17+
console.log('addClass', className, classList);
18+
}
19+
}
20+
}
21+
22+
function removeClass(className) {
23+
const idx = classList.indexOf(className);
24+
if (idx !== -1) {
25+
node.classList.remove(className);
26+
classList.splice(idx, 1);
27+
if (props.classForward) {
28+
props.classForward(classList);
29+
console.log('removeClass', className, classList);
30+
}
31+
}
32+
}
33+
34+
function handleProps() {
35+
if (props.ripple && !instance) {
36+
// Override the Ripple component's adapter, so that we can forward classes
37+
// to Svelte components that overwrite Ripple's classes.
38+
const _createAdapter = MDCRipple.createAdapter;
39+
MDCRipple.createAdapter = function(...args) {
40+
const adapter = _createAdapter.apply(this, args);
41+
adapter.addClass = function(className) {
42+
return addClass(className);
43+
};
44+
adapter.removeClass = function(className) {
45+
return removeClass(className);
46+
};
47+
return adapter;
48+
};
1149
instance = new MDCRipple(node);
12-
} else if (instance && !ripple) {
50+
MDCRipple.createAdapter = _createAdapter;
51+
} else if (instance && !props.ripple) {
1352
instance.destroy();
1453
instance = null;
1554
}
16-
if (ripple) {
55+
if (props.ripple) {
1756
instance.unbounded = !!props.unbounded;
1857
switch (props.color) {
1958
case 'surface':
20-
node.classList.add('mdc-ripple-surface');
21-
node.classList.remove('mdc-ripple-surface--primary');
22-
node.classList.remove('mdc-ripple-surface--accent');
59+
addClass('mdc-ripple-surface');
60+
removeClass('mdc-ripple-surface--primary');
61+
removeClass('mdc-ripple-surface--accent');
2362
return;
2463
case 'primary':
25-
node.classList.add('mdc-ripple-surface');
26-
node.classList.add('mdc-ripple-surface--primary');
27-
node.classList.remove('mdc-ripple-surface--accent');
64+
addClass('mdc-ripple-surface');
65+
addClass('mdc-ripple-surface--primary');
66+
removeClass('mdc-ripple-surface--accent');
2867
return;
2968
case 'secondary':
30-
node.classList.add('mdc-ripple-surface');
31-
node.classList.remove('mdc-ripple-surface--primary');
32-
node.classList.add('mdc-ripple-surface--accent');
69+
addClass('mdc-ripple-surface');
70+
removeClass('mdc-ripple-surface--primary');
71+
addClass('mdc-ripple-surface--accent');
3372
return;
3473
}
3574
}
36-
node.classList.remove('mdc-ripple-surface');
37-
node.classList.remove('mdc-ripple-surface--primary');
38-
node.classList.remove('mdc-ripple-surface--accent');
75+
removeClass('mdc-ripple-surface');
76+
removeClass('mdc-ripple-surface--primary');
77+
removeClass('mdc-ripple-surface--accent');
3978
}
4079

41-
if (ripple) {
42-
handleProps(ripple, props);
43-
}
80+
handleProps();
4481

4582
if (addLayoutListener) {
4683
removeLayoutListener = addLayoutListener(layout);
@@ -53,17 +90,18 @@ export default function Ripple(node, [ripple, props = {unbounded: false, color:
5390
}
5491

5592
return {
56-
update([ripple, props = {unbounded: false, color: null}]) {
57-
handleProps(ripple, props);
93+
update(newProps = {ripple: false, unbounded: false, color: null, classForward: []}) {
94+
props = newProps;
95+
handleProps();
5896
},
5997

6098
destroy() {
6199
if (instance) {
62100
instance.destroy();
63101
instance = null;
64-
node.classList.remove('mdc-ripple-surface');
65-
node.classList.remove('mdc-ripple-surface--primary');
66-
node.classList.remove('mdc-ripple-surface--accent');
102+
removeClass('mdc-ripple-surface');
103+
removeClass('mdc-ripple-surface--primary');
104+
removeClass('mdc-ripple-surface--accent');
67105
}
68106

69107
if (removeLayoutListener) {

site/src/routes/demo/ripple.svelte

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,23 @@
55
<section>
66
<h2>Ripple</h2>
77

8-
<p use:Ripple={[true, {color: 'surface'}]} tabindex="0">
8+
<p use:Ripple={{ripple: true, color: 'surface'}} tabindex="0">
99
SMUI ripples can be added to arbitrary elements, like this <code>p</code>
1010
element. Try clicking it to see the ripple.
1111
</p>
1212

1313
<p>
1414
Unbounded:
15-
<span use:Ripple={[true, {unbounded: true, color: 'surface'}]} tabindex="0" class="unbounded">
15+
<span use:Ripple={{ripple: true, unbounded: true, color: 'surface'}} tabindex="0" class="unbounded">
1616
&copy;
1717
</span>
1818
</p>
1919

20-
<p use:Ripple={[true, {color: 'primary'}]} tabindex="0">
20+
<p use:Ripple={{ripple: true, color: 'primary'}} tabindex="0">
2121
Primary color.
2222
</p>
2323

24-
<p use:Ripple={[true, {color: 'secondary'}]} tabindex="0">
24+
<p use:Ripple={{ripple: true, color: 'secondary'}} tabindex="0">
2525
Secondary color.
2626
</p>
2727
</section>

0 commit comments

Comments
 (0)