@fluid-topics/ft-ripple 0.1.16 → 0.2.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.
@@ -5,10 +5,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
7
  import { css, html, } from "lit";
8
- import { property, query } from "lit/decorators.js";
9
- import { Ripple } from "@material/mwc-ripple";
10
- import { RippleHandlers } from "@material/mwc-ripple/ripple-handlers";
11
- import { customElement, designSystemVariables, FtCssVariable, FtLitElement } from "@fluid-topics/ft-wc-utils";
8
+ import { property, query, state } from "lit/decorators.js";
9
+ import { classMap } from "lit/directives/class-map.js";
10
+ import { designSystemVariables, FtCssVariable, FtLitElement } from "@fluid-topics/ft-wc-utils";
12
11
  export const FtRippleCssVariables = {
13
12
  color: FtCssVariable.extend("--ft-ripple-color", designSystemVariables.colorContent),
14
13
  primaryColor: FtCssVariable.extend("--ft-ripple-primary-color", FtCssVariable.extend("--ft-ripple-color", designSystemVariables.colorPrimary)),
@@ -17,9 +16,8 @@ export const FtRippleCssVariables = {
17
16
  opacityContentOnSurfaceHover: FtCssVariable.external(designSystemVariables.opacityContentOnSurfaceHover, "Design system"),
18
17
  opacityContentOnSurfaceFocused: FtCssVariable.external(designSystemVariables.opacityContentOnSurfaceFocused, "Design system"),
19
18
  opacityContentOnSurfaceSelected: FtCssVariable.external(designSystemVariables.opacityContentOnSurfaceSelected, "Design system"),
20
- opacityContentOnSurfaceDragged: FtCssVariable.external(designSystemVariables.opacityContentOnSurfaceDragged, "Design system"),
21
19
  };
22
- let FtRipple = class FtRipple extends FtLitElement {
20
+ export class FtRipple extends FtLitElement {
23
21
  constructor() {
24
22
  super(...arguments);
25
23
  this.primary = false;
@@ -28,100 +26,283 @@ let FtRipple = class FtRipple extends FtLitElement {
28
26
  this.activated = false;
29
27
  this.selected = false;
30
28
  this.disabled = false;
31
- }
32
- //language=css
33
- getStyles() {
34
- return css `
35
- :host {
36
- display: contents;
37
-
38
- --mdc-ripple-color: ${FtRippleCssVariables.color};
39
- --mdc-ripple-press-opacity: ${FtRippleCssVariables.opacityContentOnSurfacePressed};
40
- --mdc-ripple-hover-opacity: ${FtRippleCssVariables.opacityContentOnSurfaceHover};
41
- --mdc-ripple-focus-opacity: ${FtRippleCssVariables.opacityContentOnSurfaceFocused};
42
- --mdc-ripple-selected-opacity: ${FtRippleCssVariables.opacityContentOnSurfaceSelected};
43
- --mdc-ripple-activated-opacity: ${FtRippleCssVariables.opacityContentOnSurfaceDragged};
29
+ this.hovered = false;
30
+ this.focused = false;
31
+ this.pressed = false;
32
+ this.rippling = false;
33
+ this.rippleSize = 0;
34
+ this.originX = 0;
35
+ this.originY = 0;
36
+ this.resizeObserver = new ResizeObserver(() => this.setRippleSize());
37
+ this.onTransitionStart = (e) => {
38
+ if (e.propertyName === "transform") {
39
+ this.rippling = this.pressed;
44
40
  }
45
-
46
- mwc-ripple.ft-ripple--secondary {
47
- --mdc-ripple-color: ${FtRippleCssVariables.secondaryColor};
48
- }
49
-
50
- mwc-ripple.ft-ripple--primary {
51
- --mdc-ripple-color: ${FtRippleCssVariables.primaryColor};
41
+ };
42
+ this.onTransitionEnd = (e) => {
43
+ if (e.propertyName === "transform") {
44
+ this.rippling = false;
52
45
  }
53
- `;
46
+ };
47
+ this.moveRipple = (e) => {
48
+ var _a, _b;
49
+ let { x, y } = this.getCoordinates(e);
50
+ let rect = (_b = (_a = this.ripple) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect()) !== null && _b !== void 0 ? _b : { x: 0, y: 0, width: 0, height: 0 };
51
+ this.originX = Math.round(x != null ? x - rect.x : rect.width / 2);
52
+ this.originY = Math.round(y != null ? y - rect.y : rect.height / 2);
53
+ };
54
+ this.startPress = (e) => {
55
+ this.moveRipple(e);
56
+ this.pressed = !this.isIgnored(e);
57
+ };
58
+ this.endPress = () => {
59
+ this.pressed = false;
60
+ };
61
+ this.startHover = (e) => {
62
+ this.hovered = !this.isIgnored(e);
63
+ };
64
+ this.endHover = () => {
65
+ this.hovered = false;
66
+ };
67
+ this.startFocus = (e) => {
68
+ this.focused = !this.isIgnored(e);
69
+ };
70
+ this.endFocus = () => {
71
+ this.focused = false;
72
+ };
54
73
  }
55
- getTemplate() {
74
+ render() {
75
+ let classes = {
76
+ "ft-ripple": true,
77
+ "ft-ripple--primary": this.primary,
78
+ "ft-ripple--secondary": this.secondary,
79
+ "ft-ripple--unbounded": this.unbounded,
80
+ "ft-ripple--selected": (this.selected || this.activated) && !this.disabled,
81
+ "ft-ripple--pressed": (this.pressed || this.rippling) && !this.disabled,
82
+ "ft-ripple--hovered": this.hovered && !this.disabled,
83
+ "ft-ripple--focused": this.focused && !this.disabled,
84
+ };
56
85
  return html `
57
- <mwc-ripple
58
- class="${this.primary ? "ft-ripple--primary" : this.secondary ? "ft-ripple--secondary" : ""}"
59
- ?unbounded=${this.unbounded}
60
- ?activated=${this.activated}
61
- ?selected=${this.selected}
62
- ?disabled=${this.disabled}
63
- ></mwc-ripple>
86
+ <style>
87
+ .ft-ripple .ft-ripple--effect,
88
+ .ft-ripple.ft-ripple--unbounded .ft-ripple--background {
89
+ width: ${this.rippleSize}px;
90
+ height: ${this.rippleSize}px;
91
+ }
92
+
93
+ .ft-ripple .ft-ripple--effect {
94
+ left: ${this.originX}px;
95
+ top: ${this.originY}px;
96
+ }
97
+ </style>
98
+ <div class="${classMap(classes)}">
99
+ <div class="ft-ripple--background"></div>
100
+ <div class="ft-ripple--effect"></div>
101
+ </div>
64
102
  `;
65
103
  }
104
+ contentAvailableCallback(props) {
105
+ super.contentAvailableCallback(props);
106
+ if (this.ripple) {
107
+ this.resizeObserver.observe(this.ripple);
108
+ }
109
+ if (this.rippleEffect && this.rippleEffect.ontransitionstart !== this.onTransitionStart) {
110
+ this.rippleEffect.ontransitionstart = this.onTransitionStart;
111
+ this.rippleEffect.ontransitionend = this.onTransitionEnd;
112
+ }
113
+ }
66
114
  updated(props) {
67
115
  super.updated(props);
68
116
  if (props.has("disabled") && this.disabled) {
69
117
  this.endRipple();
70
118
  }
119
+ if (props.has("unbounded")) {
120
+ this.setRippleSize();
121
+ }
71
122
  }
72
123
  endRipple() {
73
- var _a, _b, _c;
74
- (_a = this.rippleHandlers) === null || _a === void 0 ? void 0 : _a.endHover();
75
- (_b = this.rippleHandlers) === null || _b === void 0 ? void 0 : _b.endFocus();
76
- (_c = this.rippleHandlers) === null || _c === void 0 ? void 0 : _c.endPress();
124
+ this.endHover();
125
+ this.endFocus();
126
+ this.endPress();
127
+ this.rippling = false;
128
+ }
129
+ setRippleSize() {
130
+ if (this.ripple) {
131
+ const rect = this.ripple.getBoundingClientRect();
132
+ this.rippleSize = (this.unbounded ? 1 : 1.7) * Math.max(rect.width, rect.height);
133
+ }
77
134
  }
78
135
  connectedCallback() {
79
136
  var _a;
80
137
  super.connectedCallback();
81
- const parent = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.host.parentNode;
138
+ const parent = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.host.parentElement;
82
139
  if (parent) {
83
- const rh = new RippleHandlers(async () => this.mwcRipple);
84
- const startPress = (...endEvents) => {
85
- return (startEvent) => {
86
- endEvents.forEach(endEvent => window.addEventListener(endEvent, rh.endPress, { once: true }));
87
- rh.startPress(startEvent);
88
- };
140
+ this.setupFor(parent);
141
+ }
142
+ this.setRippleSize();
143
+ }
144
+ setupFor(target) {
145
+ if (this.target === target) {
146
+ return;
147
+ }
148
+ this.onDisconnect && this.onDisconnect();
149
+ this.target = target;
150
+ target.setAttribute("data-is-ft-ripple-target", "true");
151
+ const startPress = (...endEvents) => {
152
+ return (startEvent) => {
153
+ endEvents.forEach(endEvent => window.addEventListener(endEvent, this.endPress, { once: true }));
154
+ this.startPress(startEvent);
89
155
  };
90
- const mouseDownHandler = startPress("mouseup");
91
- const touchStartHandler = startPress("touchend", "touchcancel");
92
- const keyDownHandler = (e) => {
93
- if (["Enter", " "].includes(e.key)) {
94
- startPress("keyup")();
156
+ };
157
+ const mouseDownHandler = startPress("mouseup", "contextmenu");
158
+ const touchStartHandler = startPress("touchend", "touchcancel");
159
+ const keyDownHandler = (e) => {
160
+ if (["Enter", " "].includes(e.key)) {
161
+ startPress("keyup")(e);
162
+ }
163
+ };
164
+ target.addEventListener("mouseover", this.startHover);
165
+ target.addEventListener("mousemove", this.moveRipple);
166
+ target.addEventListener("mouseleave", this.endHover);
167
+ target.addEventListener("mousedown", mouseDownHandler);
168
+ target.addEventListener("touchstart", touchStartHandler);
169
+ target.addEventListener("touchmove", this.moveRipple);
170
+ target.addEventListener("keydown", keyDownHandler);
171
+ target.addEventListener("focus", this.startFocus);
172
+ target.addEventListener("blur", this.endFocus);
173
+ target.addEventListener("focusin", this.startFocus);
174
+ target.addEventListener("focusout", this.endFocus);
175
+ this.onDisconnect = () => {
176
+ target.removeAttribute("data-is-ft-ripple-target");
177
+ target.removeEventListener("mouseover", this.startHover);
178
+ target.removeEventListener("mousemove", this.moveRipple);
179
+ target.removeEventListener("mouseleave", this.endHover);
180
+ target.removeEventListener("mousedown", mouseDownHandler);
181
+ target.removeEventListener("touchstart", touchStartHandler);
182
+ target.removeEventListener("touchmove", this.moveRipple);
183
+ target.removeEventListener("keydown", keyDownHandler);
184
+ target.removeEventListener("focus", this.startFocus);
185
+ target.removeEventListener("blur", this.endFocus);
186
+ target.removeEventListener("focusin", this.startFocus);
187
+ target.removeEventListener("focusout", this.endFocus);
188
+ this.onDisconnect = undefined;
189
+ };
190
+ }
191
+ getCoordinates(e) {
192
+ const mouseEvent = e;
193
+ const touchEvent = e;
194
+ let x, y;
195
+ if (mouseEvent.x != null) {
196
+ ({ x, y } = mouseEvent);
197
+ }
198
+ else if (touchEvent.touches != null) {
199
+ x = touchEvent.touches[0].clientX;
200
+ y = touchEvent.touches[0].clientY;
201
+ }
202
+ return { x, y };
203
+ }
204
+ isIgnored(e) {
205
+ if (this.disabled) {
206
+ return true;
207
+ }
208
+ if (e != null) {
209
+ for (let t of e.composedPath()) {
210
+ if (t === this.target) {
211
+ break;
95
212
  }
96
- };
97
- parent.addEventListener("mouseenter", rh.startHover);
98
- parent.addEventListener("mouseleave", rh.endHover);
99
- parent.addEventListener("mousedown", mouseDownHandler);
100
- parent.addEventListener("touchstart", touchStartHandler);
101
- parent.addEventListener("keydown", keyDownHandler);
102
- parent.addEventListener("focus", rh.startFocus);
103
- parent.addEventListener("blur", rh.endFocus);
104
- this.onDisconnect = () => {
105
- parent.removeEventListener("mouseenter", rh.startHover);
106
- parent.removeEventListener("mouseleave", rh.endHover);
107
- parent.removeEventListener("mousedown", mouseDownHandler);
108
- parent.removeEventListener("touchstart", touchStartHandler);
109
- parent.removeEventListener("keydown", keyDownHandler);
110
- parent.removeEventListener("focus", rh.startFocus);
111
- parent.removeEventListener("blur", rh.endFocus);
112
- };
113
- this.rippleHandlers = rh;
213
+ const anotherRippleExists = "hasAttribute" in t && t.hasAttribute("data-is-ft-ripple-target");
214
+ if (anotherRippleExists) {
215
+ return true;
216
+ }
217
+ }
114
218
  }
219
+ return false;
115
220
  }
116
221
  disconnectedCallback() {
117
222
  super.disconnectedCallback();
118
223
  this.onDisconnect && this.onDisconnect();
224
+ this.resizeObserver.disconnect();
119
225
  this.endRipple();
120
226
  }
121
- };
122
- FtRipple.elementDefinitions = {
123
- "mwc-ripple": Ripple,
124
- };
227
+ }
228
+ FtRipple.elementDefinitions = {};
229
+ //language=css
230
+ FtRipple.styles = css `
231
+ :host {
232
+ display: contents;
233
+ }
234
+
235
+ .ft-ripple {
236
+ position: absolute;
237
+ inset: 0;
238
+ pointer-events: none;
239
+ }
240
+
241
+ .ft-ripple:not(.ft-ripple--unbounded) {
242
+ overflow: hidden;
243
+ }
244
+
245
+ .ft-ripple .ft-ripple--background,
246
+ .ft-ripple .ft-ripple--effect {
247
+ position: absolute;
248
+ opacity: 0;
249
+ background-color: ${FtRippleCssVariables.color};
250
+ }
251
+
252
+ .ft-ripple.ft-ripple--secondary .ft-ripple--background,
253
+ .ft-ripple.ft-ripple--secondary .ft-ripple--effect {
254
+ background-color: ${FtRippleCssVariables.secondaryColor};
255
+ }
256
+
257
+ .ft-ripple.ft-ripple--primary .ft-ripple--background,
258
+ .ft-ripple.ft-ripple--primary .ft-ripple--effect {
259
+ background-color: ${FtRippleCssVariables.primaryColor};
260
+ }
261
+
262
+ .ft-ripple .ft-ripple--background {
263
+ top: 0;
264
+ left: 0;
265
+ height: 100%;
266
+ width: 100%;
267
+ }
268
+
269
+ .ft-ripple .ft-ripple--effect,
270
+ .ft-ripple.ft-ripple--unbounded .ft-ripple--background {
271
+ border-radius: 50%;
272
+ }
273
+
274
+ .ft-ripple .ft-ripple--effect {
275
+ transform: translate(-50%, -50%) scale(0.15);
276
+ transition: transform 300ms ease, opacity 75ms linear;
277
+ }
278
+
279
+ .ft-ripple.ft-ripple--unbounded .ft-ripple--effect,
280
+ .ft-ripple.ft-ripple--unbounded .ft-ripple--background {
281
+ left: 50%;
282
+ top: 50%;
283
+ }
284
+
285
+ .ft-ripple.ft-ripple--unbounded .ft-ripple--background {
286
+ transform: translate(-50%, -50%);
287
+ }
288
+
289
+ .ft-ripple.ft-ripple--hovered .ft-ripple--background {
290
+ opacity: ${FtRippleCssVariables.opacityContentOnSurfaceHover};
291
+ }
292
+
293
+ .ft-ripple.ft-ripple--selected .ft-ripple--background {
294
+ opacity: ${FtRippleCssVariables.opacityContentOnSurfaceSelected};
295
+ }
296
+
297
+ .ft-ripple.ft-ripple--focused .ft-ripple--background {
298
+ opacity: ${FtRippleCssVariables.opacityContentOnSurfaceFocused};
299
+ }
300
+
301
+ .ft-ripple.ft-ripple--pressed .ft-ripple--effect {
302
+ opacity: ${FtRippleCssVariables.opacityContentOnSurfacePressed};
303
+ transform: translate(-50%, -50%) scale(1);
304
+ }
305
+ `;
125
306
  __decorate([
126
307
  property({ type: Boolean })
127
308
  ], FtRipple.prototype, "primary", void 0);
@@ -141,10 +322,30 @@ __decorate([
141
322
  property({ type: Boolean })
142
323
  ], FtRipple.prototype, "disabled", void 0);
143
324
  __decorate([
144
- query("mwc-ripple")
145
- ], FtRipple.prototype, "mwcRipple", void 0);
146
- FtRipple = __decorate([
147
- customElement("ft-ripple")
148
- ], FtRipple);
149
- export { FtRipple };
325
+ state()
326
+ ], FtRipple.prototype, "hovered", void 0);
327
+ __decorate([
328
+ state()
329
+ ], FtRipple.prototype, "focused", void 0);
330
+ __decorate([
331
+ state()
332
+ ], FtRipple.prototype, "pressed", void 0);
333
+ __decorate([
334
+ state()
335
+ ], FtRipple.prototype, "rippling", void 0);
336
+ __decorate([
337
+ state()
338
+ ], FtRipple.prototype, "rippleSize", void 0);
339
+ __decorate([
340
+ state()
341
+ ], FtRipple.prototype, "originX", void 0);
342
+ __decorate([
343
+ state()
344
+ ], FtRipple.prototype, "originY", void 0);
345
+ __decorate([
346
+ query(".ft-ripple")
347
+ ], FtRipple.prototype, "ripple", void 0);
348
+ __decorate([
349
+ query(".ft-ripple--effect")
350
+ ], FtRipple.prototype, "rippleEffect", void 0);
150
351
  //# sourceMappingURL=ft-ripple.js.map