m3-svelte 5.2.1 → 5.2.2

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.
@@ -1,17 +1,181 @@
1
1
  <script lang="ts">
2
- import Ripple from "./_ripple.svelte";
3
- import RippleSimple from "./_ripplesimple.svelte";
4
-
5
- let ripple = $state(RippleSimple);
6
- if (
7
- // @ts-expect-error about M3_SVELTE_NO_RIPPLE
8
- typeof M3_SVELTE_NO_RIPPLE == "undefined" &&
9
- (typeof window == "undefined" || !window.matchMedia("(prefers-reduced-motion: reduce)").matches)
10
- ) {
11
- ripple = Ripple;
12
- }
2
+ let cancelRipples: (() => void)[] = $state([]);
3
+
4
+ const createRipple = (node: HTMLDivElement) => {
5
+ if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
6
+
7
+ node.classList.remove("broken");
8
+
9
+ const parent = node.parentElement!;
10
+
11
+ const ripple = (e: MouseEvent) => {
12
+ if (e.button != 0) return;
13
+ if (parent instanceof HTMLButtonElement) {
14
+ if (parent.disabled) return;
15
+ }
16
+ if (parent instanceof HTMLLabelElement) {
17
+ const control = parent.control;
18
+ if (control instanceof HTMLInputElement && control.disabled) return;
19
+ }
20
+ if (parent.classList.contains("layer-container")) {
21
+ const input = parent.previousElementSibling;
22
+ if (input instanceof HTMLInputElement && input.disabled) return;
23
+ }
24
+
25
+ const rect = parent.getBoundingClientRect();
26
+ const x = e.clientX - rect.left;
27
+ const y = e.clientY - rect.top;
28
+ const size = Math.hypot(Math.max(x, rect.width - x), Math.max(y, rect.height - y)) * 2.5;
29
+ const speed = Math.max(Math.min(Math.log(size) * 50, 600), 200);
30
+
31
+ const gradient = document.createElementNS("http://www.w3.org/2000/svg", "radialGradient");
32
+ gradient.id = `ripple-${Date.now()}`;
33
+
34
+ const stops = [
35
+ { offset: "0%", opacity: "0.12" },
36
+ { offset: "70%", opacity: "0.12" },
37
+ { offset: "100%", opacity: "0" },
38
+ ];
39
+
40
+ stops.forEach(({ offset, opacity }) => {
41
+ const stop = document.createElementNS("http://www.w3.org/2000/svg", "stop");
42
+ stop.setAttribute("offset", offset);
43
+ stop.setAttribute("stop-color", "currentColor");
44
+ stop.setAttribute("stop-opacity", opacity);
45
+ gradient.appendChild(stop);
46
+ });
47
+
48
+ const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
49
+ circle.setAttribute("cx", `${size / 2}`);
50
+ circle.setAttribute("cy", `${size / 2}`);
51
+ circle.setAttribute("r", "0");
52
+ circle.setAttribute("fill", `url(#${gradient.id})`);
53
+
54
+ const expand = document.createElementNS("http://www.w3.org/2000/svg", "animate");
55
+ expand.setAttribute("attributeName", "r");
56
+ expand.setAttribute("from", "0");
57
+ expand.setAttribute("to", `${size / 2}`);
58
+ expand.setAttribute("dur", `${speed}ms`);
59
+ expand.setAttribute("fill", "freeze");
60
+ expand.setAttribute("calcMode", "spline");
61
+ expand.setAttribute("keySplines", "0.4 0, 0.2 1");
62
+
63
+ circle.appendChild(expand);
64
+
65
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
66
+ svg.style.cssText = `
67
+ position: absolute;
68
+ left: ${x - size / 2}px;
69
+ top: ${y - size / 2}px;
70
+ width: ${size}px;
71
+ height: ${size}px;
72
+ pointer-events: none;
73
+ overflow: visible;
74
+ `;
75
+ svg.appendChild(gradient);
76
+ svg.appendChild(circle);
77
+
78
+ const ua = navigator.userAgent;
79
+ const isFirefox = ua.includes("Firefox");
80
+ const isTrulySafari = !ua.includes("Chrome") && ua.includes("Safari");
81
+ if (!isFirefox && !isTrulySafari && size > 100) {
82
+ const filter = document.createElementNS("http://www.w3.org/2000/svg", "filter");
83
+ filter.id = `noise-${Date.now()}`;
13
84
 
14
- const Component = $derived(ripple);
85
+ const turb = document.createElementNS("http://www.w3.org/2000/svg", "feTurbulence");
86
+ turb.setAttribute("type", "fractalNoise");
87
+ turb.setAttribute("baseFrequency", "0.6");
88
+ turb.setAttribute("seed", Math.random().toString());
89
+
90
+ const blur = document.createElementNS("http://www.w3.org/2000/svg", "feDisplacementMap");
91
+ blur.setAttribute("in", "SourceGraphic");
92
+ blur.setAttribute("in2", "turbulence");
93
+ blur.setAttribute("scale", `${size ** 2 * 0.0002}`);
94
+ blur.setAttribute("xChannelSelector", "R");
95
+ blur.setAttribute("yChannelSelector", "B");
96
+
97
+ filter.appendChild(turb);
98
+ filter.appendChild(blur);
99
+
100
+ circle.setAttribute("filter", `url(#${filter.id})`);
101
+ svg.appendChild(filter);
102
+ }
103
+
104
+ node.appendChild(svg);
105
+
106
+ cancelRipples.push(() => {
107
+ const fade = document.createElementNS("http://www.w3.org/2000/svg", "animate");
108
+ fade.setAttribute("attributeName", "opacity");
109
+ fade.setAttribute("from", "1");
110
+ fade.setAttribute("to", "0");
111
+ fade.setAttribute("dur", "800ms");
112
+ fade.setAttribute("fill", "freeze");
113
+ fade.setAttribute("calcMode", "spline");
114
+ fade.setAttribute("keySplines", "0.4 0, 0.2 1");
115
+ circle.appendChild(fade);
116
+ fade.beginElement();
117
+ setTimeout(() => svg.remove(), 800);
118
+ });
119
+ };
120
+
121
+ parent.addEventListener("pointerdown", ripple);
122
+
123
+ return {
124
+ destroy() {
125
+ parent.removeEventListener("pointerdown", ripple);
126
+ },
127
+ };
128
+ };
15
129
  </script>
16
130
 
17
- <Component />
131
+ <svelte:window
132
+ onpointerup={() => {
133
+ cancelRipples.forEach((cancel) => cancel());
134
+ cancelRipples = [];
135
+ }}
136
+ ondragend={() => {
137
+ cancelRipples.forEach((cancel) => cancel());
138
+ cancelRipples = [];
139
+ }}
140
+ />
141
+
142
+ <div class="ripple-container broken" use:createRipple></div>
143
+ <div class="tint"></div>
144
+
145
+ <style>
146
+ .ripple-container {
147
+ position: absolute;
148
+ inset: 0;
149
+ border-radius: inherit;
150
+ pointer-events: none;
151
+
152
+ overflow: hidden;
153
+ }
154
+ .tint {
155
+ position: absolute;
156
+ inset: 0;
157
+ border-radius: inherit;
158
+ pointer-events: none;
159
+
160
+ background-color: currentColor;
161
+ opacity: 0;
162
+ transition: opacity var(--m3-util-easing-fast);
163
+
164
+ &:not(
165
+ :global(input:disabled + label) > .tint,
166
+ :global(input:disabled + .layer-container) > .tint,
167
+ :global(:disabled) > .tint
168
+ ) {
169
+ @media (hover: hover) {
170
+ &:is(:global(:hover) > .tint) {
171
+ opacity: 0.08;
172
+ }
173
+ }
174
+ &:is(:global(input:focus-visible + label) > .tint),
175
+ &:is(:global(:focus-visible) > .tint),
176
+ &:is(.ripple-container.broken + .tint):is(:global(:active) > .tint) {
177
+ opacity: 0.12;
178
+ }
179
+ }
180
+ }
181
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "m3-svelte",
3
- "version": "5.2.1",
3
+ "version": "5.2.2",
4
4
  "license": "Apache-2.0 OR GPL-3.0-only",
5
5
  "repository": "KTibow/m3-svelte",
6
6
  "author": {
@@ -1,179 +0,0 @@
1
- <script lang="ts">
2
- let cancelRipples: (() => void)[] = $state([]);
3
-
4
- const createRipple = (node: HTMLDivElement) => {
5
- node.classList.remove("broken");
6
-
7
- const parent = node.parentElement!;
8
-
9
- const ripple = (e: MouseEvent) => {
10
- if (e.button != 0) return;
11
- if (parent instanceof HTMLButtonElement) {
12
- if (parent.disabled) return;
13
- }
14
- if (parent instanceof HTMLLabelElement) {
15
- const control = parent.control;
16
- if (control instanceof HTMLInputElement && control.disabled) return;
17
- }
18
- if (parent.classList.contains("layer-container")) {
19
- const input = parent.previousElementSibling;
20
- if (input instanceof HTMLInputElement && input.disabled) return;
21
- }
22
-
23
- const rect = parent.getBoundingClientRect();
24
- const x = e.clientX - rect.left;
25
- const y = e.clientY - rect.top;
26
- const size = Math.hypot(Math.max(x, rect.width - x), Math.max(y, rect.height - y)) * 2.5;
27
- const speed = Math.max(Math.min(Math.log(size) * 50, 600), 200);
28
-
29
- const gradient = document.createElementNS("http://www.w3.org/2000/svg", "radialGradient");
30
- gradient.id = `ripple-${Date.now()}`;
31
-
32
- const stops = [
33
- { offset: "0%", opacity: "0.12" },
34
- { offset: "70%", opacity: "0.12" },
35
- { offset: "100%", opacity: "0" },
36
- ];
37
-
38
- stops.forEach(({ offset, opacity }) => {
39
- const stop = document.createElementNS("http://www.w3.org/2000/svg", "stop");
40
- stop.setAttribute("offset", offset);
41
- stop.setAttribute("stop-color", "currentColor");
42
- stop.setAttribute("stop-opacity", opacity);
43
- gradient.appendChild(stop);
44
- });
45
-
46
- const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
47
- circle.setAttribute("cx", `${size / 2}`);
48
- circle.setAttribute("cy", `${size / 2}`);
49
- circle.setAttribute("r", "0");
50
- circle.setAttribute("fill", `url(#${gradient.id})`);
51
-
52
- const expand = document.createElementNS("http://www.w3.org/2000/svg", "animate");
53
- expand.setAttribute("attributeName", "r");
54
- expand.setAttribute("from", "0");
55
- expand.setAttribute("to", `${size / 2}`);
56
- expand.setAttribute("dur", `${speed}ms`);
57
- expand.setAttribute("fill", "freeze");
58
- expand.setAttribute("calcMode", "spline");
59
- expand.setAttribute("keySplines", "0.4 0, 0.2 1");
60
-
61
- circle.appendChild(expand);
62
-
63
- const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
64
- svg.style.cssText = `
65
- position: absolute;
66
- left: ${x - size / 2}px;
67
- top: ${y - size / 2}px;
68
- width: ${size}px;
69
- height: ${size}px;
70
- pointer-events: none;
71
- overflow: visible;
72
- `;
73
- svg.appendChild(gradient);
74
- svg.appendChild(circle);
75
-
76
- const ua = navigator.userAgent;
77
- const isFirefox = ua.includes("Firefox");
78
- const isTrulySafari = !ua.includes("Chrome") && ua.includes("Safari");
79
- if (!isFirefox && !isTrulySafari && size > 100) {
80
- const filter = document.createElementNS("http://www.w3.org/2000/svg", "filter");
81
- filter.id = `noise-${Date.now()}`;
82
-
83
- const turb = document.createElementNS("http://www.w3.org/2000/svg", "feTurbulence");
84
- turb.setAttribute("type", "fractalNoise");
85
- turb.setAttribute("baseFrequency", "0.6");
86
- turb.setAttribute("seed", Math.random().toString());
87
-
88
- const blur = document.createElementNS("http://www.w3.org/2000/svg", "feDisplacementMap");
89
- blur.setAttribute("in", "SourceGraphic");
90
- blur.setAttribute("in2", "turbulence");
91
- blur.setAttribute("scale", `${size ** 2 * 0.0002}`);
92
- blur.setAttribute("xChannelSelector", "R");
93
- blur.setAttribute("yChannelSelector", "B");
94
-
95
- filter.appendChild(turb);
96
- filter.appendChild(blur);
97
-
98
- circle.setAttribute("filter", `url(#${filter.id})`);
99
- svg.appendChild(filter);
100
- }
101
-
102
- node.appendChild(svg);
103
-
104
- cancelRipples.push(() => {
105
- const fade = document.createElementNS("http://www.w3.org/2000/svg", "animate");
106
- fade.setAttribute("attributeName", "opacity");
107
- fade.setAttribute("from", "1");
108
- fade.setAttribute("to", "0");
109
- fade.setAttribute("dur", "800ms");
110
- fade.setAttribute("fill", "freeze");
111
- fade.setAttribute("calcMode", "spline");
112
- fade.setAttribute("keySplines", "0.4 0, 0.2 1");
113
- circle.appendChild(fade);
114
- fade.beginElement();
115
- setTimeout(() => svg.remove(), 800);
116
- });
117
- };
118
-
119
- parent.addEventListener("pointerdown", ripple);
120
-
121
- return {
122
- destroy() {
123
- parent.removeEventListener("pointerdown", ripple);
124
- },
125
- };
126
- };
127
- </script>
128
-
129
- <svelte:window
130
- onpointerup={() => {
131
- cancelRipples.forEach((cancel) => cancel());
132
- cancelRipples = [];
133
- }}
134
- ondragend={() => {
135
- cancelRipples.forEach((cancel) => cancel());
136
- cancelRipples = [];
137
- }}
138
- />
139
-
140
- <div class="ripple-container broken" use:createRipple></div>
141
- <div class="tint"></div>
142
-
143
- <style>
144
- .ripple-container {
145
- position: absolute;
146
- inset: 0;
147
- border-radius: inherit;
148
- pointer-events: none;
149
-
150
- overflow: hidden;
151
- }
152
- .tint {
153
- position: absolute;
154
- inset: 0;
155
- border-radius: inherit;
156
- pointer-events: none;
157
-
158
- background-color: currentColor;
159
- opacity: 0;
160
- transition: opacity var(--m3-util-easing-fast);
161
-
162
- &:not(
163
- :global(input:disabled + label) > .tint,
164
- :global(input:disabled + .layer-container) > .tint,
165
- :global(:disabled) > .tint
166
- ) {
167
- @media (hover: hover) {
168
- &:is(:global(:hover) > .tint) {
169
- opacity: 0.08;
170
- }
171
- }
172
- &:is(:global(input:focus-visible + label) > .tint),
173
- &:is(:global(:focus-visible) > .tint),
174
- &:is(.ripple-container.broken + .tint):is(:global(:active) > .tint) {
175
- opacity: 0.12;
176
- }
177
- }
178
- }
179
- </style>
@@ -1,3 +0,0 @@
1
- declare const Ripple: import("svelte").Component<Record<string, never>, {}, "">;
2
- type Ripple = ReturnType<typeof Ripple>;
3
- export default Ripple;
@@ -1,33 +0,0 @@
1
- <svelte:options runes />
2
-
3
- <div class="tint"></div>
4
-
5
- <style>
6
- .tint {
7
- position: absolute;
8
- inset: 0;
9
- border-radius: inherit;
10
- pointer-events: none;
11
-
12
- background-color: currentColor;
13
- opacity: 0;
14
- transition: opacity var(--m3-util-easing-fast);
15
-
16
- &:not(
17
- :global(input:disabled + label) > .tint,
18
- :global(input:disabled + .layer-container) > .tint,
19
- :global(:disabled) > .tint
20
- ) {
21
- @media (hover: hover) {
22
- &:is(:global(:hover) > .tint) {
23
- opacity: 0.08;
24
- }
25
- }
26
- &:is(:global(input:focus-visible + label) > .tint),
27
- &:is(:global(:focus-visible) > .tint),
28
- &:is(:global(:active) > .tint) {
29
- opacity: 0.12;
30
- }
31
- }
32
- }
33
- </style>
@@ -1,6 +0,0 @@
1
- export default Ripplesimple;
2
- type Ripplesimple = {
3
- $on?(type: string, callback: (e: any) => void): () => void;
4
- $set?(props: Partial<Record<string, never>>): void;
5
- };
6
- declare const Ripplesimple: import("svelte").Component<Record<string, never>, {}, "">;