@codesuma/baseline 1.0.10 → 1.0.12

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.
@@ -23,7 +23,13 @@ export const Page = () => {
23
23
  base.removeClass(styles.hiddenAbove)
24
24
  }
25
25
 
26
+ // Force reflow so browser registers the starting position
27
+ // This is critical for the first transition to be smooth
28
+ void base.el.offsetHeight
29
+
30
+ // Visual delay before entering
26
31
  await waitFor(200)
32
+
27
33
  // Clear all state classes
28
34
  base.removeClass(
29
35
  styles.exitUp,
package/index.ts CHANGED
@@ -32,5 +32,5 @@ export { default as state } from './lib/state'
32
32
  export { createEmitter, emitter, IEmitter } from './utils/emitter'
33
33
  export { createStyler, injectCSS, IStyler, CS } from './utils/styler'
34
34
  export { waitFor } from './utils/wait'
35
- export { withRipple } from './utils/ripple'
35
+ export { initRipple } from './utils/ripple'
36
36
  export { nextId, shortUUID, uuidv4 } from './utils/id'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codesuma/baseline",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "description": "A minimal, imperative UI framework for building fast web apps. No virtual DOM, no magic, no dependencies.",
5
5
  "main": "index.ts",
6
6
  "types": "index.ts",
package/utils/ripple.ts CHANGED
@@ -1,59 +1,60 @@
1
- // Ripple effect - Material Design style touch feedback
2
-
3
- import { Base, IBaseComponent } from '../components/base'
4
1
  import { injectCSS } from '../utils/styler'
5
2
 
6
3
  const RIPPLE_CSS = `
4
+ [data-ripple] {
5
+ position: relative;
6
+ overflow: hidden;
7
+ }
7
8
  [data-ripple] .ripple {
8
9
  position: absolute;
9
10
  border-radius: 50%;
10
11
  background: currentColor;
11
- opacity: 0.1;
12
+ opacity: 0.15;
12
13
  transform: scale(0);
13
14
  pointer-events: none;
14
- }
15
- [data-ripple] .ripple.animate {
16
- animation: ripple 1s ease-out;
15
+ animation: ripple 600ms ease-out forwards;
17
16
  }
18
17
  @keyframes ripple {
19
18
  to { transform: scale(4); opacity: 0; }
20
19
  }
21
20
  `
22
21
 
23
- export const withRipple = <T extends IBaseComponent<any>>(component: T): T => {
22
+ export const initRipple = () => {
24
23
  injectCSS('base-ripple', RIPPLE_CSS)
25
24
 
26
- component.el.setAttribute('data-ripple', '')
27
-
28
- const createRipple = (x: number, y: number) => {
29
- const ripple = Base('span')
30
- ripple.el.className = 'ripple'
25
+ let touchedRecently = false
31
26
 
32
- const rect = component.el.getBoundingClientRect()
27
+ const createRipple = (el: HTMLElement, x: number, y: number) => {
28
+ const rect = el.getBoundingClientRect()
33
29
  const size = Math.max(rect.width, rect.height) * 2
34
30
 
35
- ripple.style({
31
+ const ripple = document.createElement('span')
32
+ ripple.className = 'ripple'
33
+ Object.assign(ripple.style, {
36
34
  width: size + 'px',
37
35
  height: size + 'px',
38
36
  left: (x - rect.left - size / 2) + 'px',
39
37
  top: (y - rect.top - size / 2) + 'px'
40
38
  })
41
39
 
42
- component.el.appendChild(ripple.el)
43
- ripple.el.classList.add('animate')
44
-
45
- setTimeout(() => ripple.el.remove(), 600)
40
+ el.appendChild(ripple)
41
+ ripple.addEventListener('animationend', () => ripple.remove())
46
42
  }
47
43
 
48
- component.el.addEventListener('touchstart', (e: TouchEvent) => {
49
- createRipple(e.touches[0].clientX, e.touches[0].clientY)
44
+ document.addEventListener('touchstart', (e) => {
45
+ const el = (e.target as HTMLElement).closest<HTMLElement>('[data-ripple]')
46
+ if (el) {
47
+ touchedRecently = true
48
+ createRipple(el, e.touches[0].clientX, e.touches[0].clientY)
49
+ setTimeout(() => touchedRecently = false, 100)
50
+ }
50
51
  }, { passive: true })
51
52
 
52
- component.el.addEventListener('mousedown', (e: MouseEvent) => {
53
- createRipple(e.clientX, e.clientY)
53
+ document.addEventListener('mousedown', (e) => {
54
+ if (touchedRecently) return
55
+ const el = (e.target as HTMLElement).closest<HTMLElement>('[data-ripple]')
56
+ if (el) {
57
+ createRipple(el, e.clientX, e.clientY)
58
+ }
54
59
  })
55
-
56
- return component
57
- }
58
-
59
- export default withRipple
60
+ }