@mhmo91/schmancy 0.10.34 → 0.10.35

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.
package/src/boat/boat.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  import { SchmancyElement } from '@mixins/index'
2
- import { css, html, nothing, type PropertyValues } from 'lit'
2
+ import { css, html, type PropertyValues } from 'lit'
3
3
  import { customElement, property, queryAssignedElements, state } from 'lit/decorators.js'
4
4
  import { classMap } from 'lit/directives/class-map.js'
5
5
  import { createRef, ref } from 'lit/directives/ref.js'
6
6
  import { styleMap } from 'lit/directives/style-map.js'
7
- import { when } from 'lit/directives/when.js'
8
7
  import { filter, finalize, fromEvent, map, merge, type Subscription, switchMap, takeUntil, tap } from 'rxjs'
9
- import { SPRING_SMOOTH } from '../utils/animation.js'
10
8
  import { reducedMotion$ } from '../directives/reduced-motion'
11
9
  import { show } from '../overlay/overlay.service'
12
10
  import { theme } from '../theme/theme.service.js'
11
+ import { SPRING_SMOOTH } from '../utils/animation.js'
13
12
 
14
13
  const DRAG_THRESHOLD = 5
15
14
  const POSITION_STORAGE_KEY_PREFIX = 'schmancy-boat-'
@@ -38,25 +37,22 @@ export default class SchmancyBoat extends SchmancyElement {
38
37
  }
39
38
  `]
40
39
 
40
+ /** Identity for localStorage drag-position persistence. */
41
41
  @property({ type: String }) id: string = 'default'
42
- @property({ type: String }) icon?: string
43
- @property({ type: String }) label?: string
44
- /** When true, uses a lower elevation shadow on the FAB. */
45
- @property({ type: Boolean, reflect: true }) lowered: boolean = false
46
42
  /** Corner the FAB is anchored to. */
47
43
  @property({ type: String }) corner: Corner = 'bottom-right'
48
44
  /** Open state. Bind `?open=${…}` to drive the overlay; reflected to the attribute. */
49
45
  @property({ type: Boolean, reflect: true }) open: boolean = false
50
46
 
51
47
  @state() private isDragging = false
52
- @state() private _currentCorner: Corner = 'bottom-right'
48
+ @state() private currentCorner: Corner = 'bottom-right'
53
49
 
54
- @queryAssignedElements() private _slotted!: Element[]
50
+ @queryAssignedElements() private slotted!: Element[]
55
51
 
56
- private _position: Position = { x: 16, y: 16 }
57
- private _containerRef = createRef<HTMLElement>()
58
- private _headerRef = createRef<HTMLElement>()
59
- private _currentAnimation?: Animation
52
+ private position: Position = { x: 16, y: 16 }
53
+ private containerRef = createRef<HTMLElement>()
54
+ private headerRef = createRef<HTMLElement>()
55
+ private currentAnimation?: Animation
60
56
 
61
57
  #ready = false
62
58
  #sub?: Subscription
@@ -66,76 +62,76 @@ export default class SchmancyBoat extends SchmancyElement {
66
62
  // POSITION MANAGEMENT
67
63
  // ============================================
68
64
 
69
- private _applyContainerPosition() {
70
- const container = this._containerRef.value
65
+ private applyContainerPosition() {
66
+ const container = this.containerRef.value
71
67
  if (!container) return
72
68
  container.style.removeProperty('left')
73
69
  container.style.removeProperty('right')
74
70
  container.style.removeProperty('top')
75
71
  container.style.removeProperty('bottom')
76
- const { x, y } = this._position
77
- if (this._currentCorner.includes('right')) {
72
+ const { x, y } = this.position
73
+ if (this.currentCorner.includes('right')) {
78
74
  container.style.right = `${x}px`
79
75
  } else {
80
76
  container.style.left = `${x}px`
81
77
  }
82
- if (this._currentCorner.includes('bottom')) {
78
+ if (this.currentCorner.includes('bottom')) {
83
79
  container.style.bottom = `${y + theme.bottomOffset}px`
84
80
  } else {
85
81
  container.style.top = `${y}px`
86
82
  }
87
83
  }
88
84
 
89
- private _loadPosition() {
85
+ private loadPosition() {
90
86
  try {
91
87
  const saved = localStorage.getItem(POSITION_STORAGE_KEY_PREFIX + this.id)
92
88
  if (saved) {
93
89
  const parsed = JSON.parse(saved) as { x: number; y: number; anchor: Corner }
94
- this._position = { x: parsed.x, y: parsed.y }
95
- this._currentCorner = parsed.anchor
90
+ this.position = { x: parsed.x, y: parsed.y }
91
+ this.currentCorner = parsed.anchor
96
92
  }
97
93
  } catch {
98
94
  // ignore localStorage errors
99
95
  }
100
96
  }
101
97
 
102
- private _savePosition() {
98
+ private savePosition() {
103
99
  try {
104
100
  localStorage.setItem(
105
101
  POSITION_STORAGE_KEY_PREFIX + this.id,
106
- JSON.stringify({ ...this._position, anchor: this._currentCorner }),
102
+ JSON.stringify({ ...this.position, anchor: this.currentCorner }),
107
103
  )
108
104
  } catch {
109
105
  // ignore localStorage errors
110
106
  }
111
107
  }
112
108
 
113
- private _validateBounds() {
114
- const container = this._containerRef.value
109
+ private validateBounds() {
110
+ const container = this.containerRef.value
115
111
  if (!container) return
116
112
  const rect = container.getBoundingClientRect()
117
113
  if (rect.width === 0) return
118
114
  const vw = window.innerWidth
119
115
  const vh = window.innerHeight
120
- const isRight = this._currentCorner.includes('right')
121
- const isBottom = this._currentCorner.includes('bottom')
122
- const actualLeft = isRight ? vw - this._position.x - rect.width : this._position.x
123
- const actualTop = isBottom ? vh - this._position.y - rect.height : this._position.y
116
+ const isRight = this.currentCorner.includes('right')
117
+ const isBottom = this.currentCorner.includes('bottom')
118
+ const actualLeft = isRight ? vw - this.position.x - rect.width : this.position.x
119
+ const actualTop = isBottom ? vh - this.position.y - rect.height : this.position.y
124
120
  const newLeft = Math.max(0, Math.min(actualLeft, vw - rect.width))
125
121
  const newTop = Math.max(0, Math.min(actualTop, vh - rect.height))
126
- this._position = {
122
+ this.position = {
127
123
  x: isRight ? vw - newLeft - rect.width : newLeft,
128
124
  y: isBottom ? vh - newTop - rect.height : newTop,
129
125
  }
130
- this._applyContainerPosition()
126
+ this.applyContainerPosition()
131
127
  }
132
128
 
133
129
  // ============================================
134
130
  // CORNER SNAPPING (FLIP)
135
131
  // ============================================
136
132
 
137
- private _reorientToNearestCorner(): void {
138
- const container = this._containerRef.value
133
+ private reorientToNearestCorner(): void {
134
+ const container = this.containerRef.value
139
135
  if (!container) return
140
136
 
141
137
  const rect = container.getBoundingClientRect()
@@ -143,12 +139,12 @@ export default class SchmancyBoat extends SchmancyElement {
143
139
  const fabCenterY = rect.top + rect.height / 2
144
140
  const side = fabCenterX > window.innerWidth / 2 ? 'right' : 'left'
145
141
  const vert = fabCenterY > window.innerHeight / 2 ? 'bottom' : 'top'
146
- this._currentCorner = `${vert}-${side}` as Corner
147
- this._position = { x: 16, y: 16 }
148
- this._applyContainerPosition()
142
+ this.currentCorner = `${vert}-${side}` as Corner
143
+ this.position = { x: 16, y: 16 }
144
+ this.applyContainerPosition()
149
145
 
150
146
  if (reducedMotion$.value) {
151
- this._savePosition()
147
+ this.savePosition()
152
148
  return
153
149
  }
154
150
 
@@ -157,7 +153,7 @@ export default class SchmancyBoat extends SchmancyElement {
157
153
  const dy = rect.top - newRect.top
158
154
  container.style.transform = `translate(${dx}px, ${dy}px)`
159
155
 
160
- this._currentAnimation?.cancel()
156
+ this.currentAnimation?.cancel()
161
157
  const anim = container.animate(
162
158
  [{ transform: container.style.transform }, { transform: 'translate(0,0)' }],
163
159
  {
@@ -166,22 +162,22 @@ export default class SchmancyBoat extends SchmancyElement {
166
162
  fill: 'forwards',
167
163
  },
168
164
  )
169
- this._currentAnimation = anim
165
+ this.currentAnimation = anim
170
166
  anim.finished.then(() => {
171
167
  if (container.isConnected) container.style.transform = ''
172
168
  return
173
169
  })
174
170
 
175
- this._savePosition()
171
+ this.savePosition()
176
172
  }
177
173
 
178
174
  // ============================================
179
175
  // DRAG PIPELINE
180
176
  // ============================================
181
177
 
182
- private _setupDrag() {
183
- const header = this._headerRef.value
184
- const container = this._containerRef.value
178
+ private setupDrag() {
179
+ const header = this.headerRef.value
180
+ const container = this.containerRef.value
185
181
  if (!header || !container) return
186
182
 
187
183
  let didDrag = false
@@ -228,16 +224,16 @@ export default class SchmancyBoat extends SchmancyElement {
228
224
  const vh = window.innerHeight
229
225
  const left = Math.max(0, Math.min(clientX - offsetX, vw - rect.width))
230
226
  const top = Math.max(0, Math.min(clientY - offsetY, vh - rect.height))
231
- this._position = {
232
- x: this._currentCorner.includes('right') ? vw - left - rect.width : left,
233
- y: this._currentCorner.includes('bottom') ? vh - top - rect.height : top,
227
+ this.position = {
228
+ x: this.currentCorner.includes('right') ? vw - left - rect.width : left,
229
+ y: this.currentCorner.includes('bottom') ? vh - top - rect.height : top,
234
230
  }
235
- this._applyContainerPosition()
231
+ this.applyContainerPosition()
236
232
  }),
237
233
  takeUntil(end$),
238
234
  finalize(() => {
239
235
  if (didDrag) {
240
- this._reorientToNearestCorner()
236
+ this.reorientToNearestCorner()
241
237
  this.isDragging = false
242
238
  didDrag = false
243
239
  } else {
@@ -257,12 +253,12 @@ export default class SchmancyBoat extends SchmancyElement {
257
253
  // OVERLAY DELEGATION
258
254
  // ============================================
259
255
 
260
- private _openOverlay() {
256
+ private openOverlay() {
261
257
  if (this.#sub) return
262
- const anchor = this._containerRef.value
258
+ const anchor = this.containerRef.value
263
259
  const wrapper = document.createElement('div')
264
260
  wrapper.className = 'flex flex-col'
265
- this.#captured = [...this._slotted]
261
+ this.#captured = [...this.slotted]
266
262
  this.#captured.forEach(node => wrapper.appendChild(node))
267
263
 
268
264
  this.#sub = show(wrapper, {
@@ -271,7 +267,7 @@ export default class SchmancyBoat extends SchmancyElement {
271
267
  historyStrategy: 'silent',
272
268
  })
273
269
  .pipe(
274
- finalize(() => this._restoreSlotted()),
270
+ finalize(() => this.restoreSlotted()),
275
271
  takeUntil(this.disconnecting),
276
272
  )
277
273
  .subscribe()
@@ -279,7 +275,7 @@ export default class SchmancyBoat extends SchmancyElement {
279
275
  this.dispatchScopedEvent('toggle', 'open')
280
276
  }
281
277
 
282
- private _restoreSlotted() {
278
+ private restoreSlotted() {
283
279
  this.#captured.forEach(node => this.appendChild(node))
284
280
  this.#captured = []
285
281
  this.#sub = undefined
@@ -296,33 +292,33 @@ export default class SchmancyBoat extends SchmancyElement {
296
292
 
297
293
  fromEvent(window, 'resize')
298
294
  .pipe(takeUntil(this.disconnecting))
299
- .subscribe(() => this._validateBounds())
295
+ .subscribe(() => this.validateBounds())
300
296
 
301
297
  theme.bottomOffset$.pipe(
302
- tap(() => this._applyContainerPosition()),
298
+ tap(() => this.applyContainerPosition()),
303
299
  takeUntil(this.disconnecting),
304
300
  ).subscribe()
305
301
  }
306
302
 
307
303
  firstUpdated() {
308
- this._currentCorner = this.corner
309
- this._loadPosition()
310
- if (!this._containerRef.value) return
311
- this._applyContainerPosition()
312
- this._setupDrag()
304
+ this.currentCorner = this.corner
305
+ this.loadPosition()
306
+ if (!this.containerRef.value) return
307
+ this.applyContainerPosition()
308
+ this.setupDrag()
313
309
  this.#ready = true
314
- if (this.open) this._openOverlay()
310
+ if (this.open) this.openOverlay()
315
311
  }
316
312
 
317
313
  protected willUpdate(changed: PropertyValues<this>) {
318
314
  if (!this.#ready || !changed.has('open')) return
319
- if (this.open && !this.#sub) this._openOverlay()
315
+ if (this.open && !this.#sub) this.openOverlay()
320
316
  else if (!this.open && this.#sub) this.#sub.unsubscribe()
321
317
  }
322
318
 
323
319
  disconnectedCallback() {
324
320
  super.disconnectedCallback()
325
- this._currentAnimation?.cancel()
321
+ this.currentAnimation?.cancel()
326
322
  this.#sub?.unsubscribe()
327
323
  }
328
324
 
@@ -357,50 +353,37 @@ export default class SchmancyBoat extends SchmancyElement {
357
353
 
358
354
  const fabClasses = classMap({
359
355
  'h-14': true,
356
+ 'min-w-14': true,
357
+ 'px-4': true,
360
358
  'rounded-full': true,
361
359
  flex: true,
362
360
  'items-center': true,
361
+ 'justify-center': true,
363
362
  'gap-3': true,
364
363
  'select-none': true,
365
364
  'touch-none': true,
366
365
  'cursor-grabbing': this.isDragging,
367
366
  'cursor-pointer': !this.isDragging,
368
- 'px-5': !!this.label,
369
- 'w-14': !this.label,
370
- 'justify-center': !this.label,
371
367
  })
372
368
 
373
369
  return html`
374
370
  <schmancy-surface
375
- ${ref(this._containerRef)}
371
+ ${ref(this.containerRef)}
376
372
  type="glass"
377
- .elevation=${this.lowered ? 1 : 3}
373
+ .elevation=${3}
378
374
  class=${containerClasses}
379
375
  style=${containerStyles}
380
376
  aria-expanded=${this.open}
381
377
  >
382
378
  <div
383
- ${ref(this._headerRef)}
379
+ ${ref(this.headerRef)}
384
380
  class=${fabClasses}
385
381
  role="button"
386
382
  tabindex="0"
387
- aria-label=${this.label ?? 'Open panel'}
383
+ aria-label="Open panel"
388
384
  title="Drag to move · click to open"
389
385
  >
390
- <slot name="header">
391
- ${when(
392
- !!this.icon,
393
- () => html`<schmancy-icon>${this.icon}</schmancy-icon>`,
394
- () => nothing,
395
- )}
396
- </slot>
397
- ${when(
398
- !!this.label,
399
- () => html`<schmancy-typography type="label" token="lg" class="whitespace-nowrap">
400
- ${this.label}
401
- </schmancy-typography>`,
402
- () => nothing,
403
- )}
386
+ <slot name="header"></slot>
404
387
  <slot name="summary"></slot>
405
388
  </div>
406
389
 
@@ -11,30 +11,27 @@ type Corner = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
11
11
  export default class SchmancyBoat extends SchmancyElement {
12
12
  #private;
13
13
  static styles: import("lit").CSSResult[];
14
+ /** Identity for localStorage drag-position persistence. */
14
15
  id: string;
15
- icon?: string;
16
- label?: string;
17
- /** When true, uses a lower elevation shadow on the FAB. */
18
- lowered: boolean;
19
16
  /** Corner the FAB is anchored to. */
20
17
  corner: Corner;
21
18
  /** Open state. Bind `?open=${…}` to drive the overlay; reflected to the attribute. */
22
19
  open: boolean;
23
20
  private isDragging;
24
- private _currentCorner;
25
- private _slotted;
26
- private _position;
27
- private _containerRef;
28
- private _headerRef;
29
- private _currentAnimation?;
30
- private _applyContainerPosition;
31
- private _loadPosition;
32
- private _savePosition;
33
- private _validateBounds;
34
- private _reorientToNearestCorner;
35
- private _setupDrag;
36
- private _openOverlay;
37
- private _restoreSlotted;
21
+ private currentCorner;
22
+ private slotted;
23
+ private position;
24
+ private containerRef;
25
+ private headerRef;
26
+ private currentAnimation?;
27
+ private applyContainerPosition;
28
+ private loadPosition;
29
+ private savePosition;
30
+ private validateBounds;
31
+ private reorientToNearestCorner;
32
+ private setupDrag;
33
+ private openOverlay;
34
+ private restoreSlotted;
38
35
  connectedCallback(): void;
39
36
  firstUpdated(): void;
40
37
  protected willUpdate(changed: PropertyValues<this>): void;
@@ -1,38 +0,0 @@
1
- require(`./chunk-CncqDLb2.cjs`);const e=require(`./SchmancyElement-CYIif26I.cjs`);require(`./mixins-CGXSzZc7.cjs`);const t=require(`./animation-CCOIW4wJ.cjs`),n=require(`./reduced-motion-Ds-HjMzn.cjs`),r=require(`./theme.service-p61RsJBF.cjs`),i=require(`./overlay.service-C8RsQzgM.cjs`);let a=require(`rxjs`),o=require(`lit/directives/class-map.js`),s=require(`lit/directives/style-map.js`),c=require(`lit/decorators.js`),l=require(`lit`),u=require(`lit/directives/ref.js`),d=require(`lit/directives/when.js`);var f=`schmancy-boat-`,p=class extends e.t{constructor(...e){super(...e),this.id=`default`,this.lowered=!1,this.corner=`bottom-right`,this.open=!1,this.isDragging=!1,this._currentCorner=`bottom-right`,this._position={x:16,y:16},this._containerRef=(0,u.createRef)(),this._headerRef=(0,u.createRef)(),this.#e=!1,this.#n=[]}static{this.styles=[l.css`
2
- :host {
3
- display: contents;
4
- }
5
- :host([hidden]) {
6
- display: none !important;
7
- }
8
- `]}#e;#t;#n;_applyContainerPosition(){let e=this._containerRef.value;if(!e)return;e.style.removeProperty(`left`),e.style.removeProperty(`right`),e.style.removeProperty(`top`),e.style.removeProperty(`bottom`);let{x:t,y:n}=this._position;this._currentCorner.includes(`right`)?e.style.right=`${t}px`:e.style.left=`${t}px`,this._currentCorner.includes(`bottom`)?e.style.bottom=`${n+r.n.bottomOffset}px`:e.style.top=`${n}px`}_loadPosition(){try{let e=localStorage.getItem(f+this.id);if(e){let t=JSON.parse(e);this._position={x:t.x,y:t.y},this._currentCorner=t.anchor}}catch{}}_savePosition(){try{localStorage.setItem(f+this.id,JSON.stringify({...this._position,anchor:this._currentCorner}))}catch{}}_validateBounds(){let e=this._containerRef.value;if(!e)return;let t=e.getBoundingClientRect();if(t.width===0)return;let n=window.innerWidth,r=window.innerHeight,i=this._currentCorner.includes(`right`),a=this._currentCorner.includes(`bottom`),o=i?n-this._position.x-t.width:this._position.x,s=a?r-this._position.y-t.height:this._position.y,c=Math.max(0,Math.min(o,n-t.width)),l=Math.max(0,Math.min(s,r-t.height));this._position={x:i?n-c-t.width:c,y:a?r-l-t.height:l},this._applyContainerPosition()}_reorientToNearestCorner(){let e=this._containerRef.value;if(!e)return;let r=e.getBoundingClientRect(),i=r.left+r.width/2,a=r.top+r.height/2,o=i>window.innerWidth/2?`right`:`left`,s=a>window.innerHeight/2?`bottom`:`top`;if(this._currentCorner=`${s}-${o}`,this._position={x:16,y:16},this._applyContainerPosition(),n.t.value)return void this._savePosition();let c=e.getBoundingClientRect(),l=r.left-c.left,u=r.top-c.top;e.style.transform=`translate(${l}px, ${u}px)`,this._currentAnimation?.cancel();let d=e.animate([{transform:e.style.transform},{transform:`translate(0,0)`}],{duration:t.d.duration,easing:t.d.easingFallback,fill:`forwards`});this._currentAnimation=d,d.finished.then(()=>{e.isConnected&&(e.style.transform=``)}),this._savePosition()}_setupDrag(){let e=this._headerRef.value,t=this._containerRef.value;if(!e||!t)return;let n=!1;(0,a.fromEvent)(e,`pointerdown`).pipe((0,a.filter)(e=>e.button===0),(0,a.tap)(t=>{t.preventDefault(),t.stopPropagation(),e.setPointerCapture(t.pointerId)}),(0,a.map)(e=>{let r=t.getBoundingClientRect();return n=!1,{pointerId:e.pointerId,startX:e.clientX,startY:e.clientY,offsetX:e.clientX-r.left,offsetY:e.clientY-r.top,rect:r}}),(0,a.switchMap)(({pointerId:e,startX:t,startY:r,offsetX:i,offsetY:o,rect:s})=>{let c=t=>t.pointerId===e,l=(0,a.fromEvent)(window,`pointermove`).pipe((0,a.filter)(c)),u=(0,a.merge)((0,a.fromEvent)(window,`pointerup`),(0,a.fromEvent)(window,`pointercancel`)).pipe((0,a.filter)(c));return l.pipe((0,a.tap)(({clientX:e,clientY:a})=>{let c=e-t,l=a-r;if(Math.sqrt(c*c+l*l)>5&&!n&&(n=!0,this.isDragging=!0),!n)return;let u=window.innerWidth,d=window.innerHeight,f=Math.max(0,Math.min(e-i,u-s.width)),p=Math.max(0,Math.min(a-o,d-s.height));this._position={x:this._currentCorner.includes(`right`)?u-f-s.width:f,y:this._currentCorner.includes(`bottom`)?d-p-s.height:p},this._applyContainerPosition()}),(0,a.takeUntil)(u),(0,a.finalize)(()=>{n?(this._reorientToNearestCorner(),this.isDragging=!1,n=!1):(this.isDragging=!1,n=!1,this.toggle())}))}),(0,a.takeUntil)(this.disconnecting)).subscribe()}_openOverlay(){if(this.#t)return;let e=this._containerRef.value,t=document.createElement(`div`);t.className=`flex flex-col`,this.#n=[...this._slotted],this.#n.forEach(e=>t.appendChild(e)),this.#t=i.o(t,{anchor:e??void 0,dismissable:!0,historyStrategy:`silent`}).pipe((0,a.finalize)(()=>this._restoreSlotted()),(0,a.takeUntil)(this.disconnecting)).subscribe(),this.dispatchScopedEvent(`toggle`,`open`)}_restoreSlotted(){this.#n.forEach(e=>this.appendChild(e)),this.#n=[],this.#t=void 0,this.open&&=!1,this.dispatchScopedEvent(`toggle`,`closed`)}connectedCallback(){super.connectedCallback(),(0,a.fromEvent)(window,`resize`).pipe((0,a.takeUntil)(this.disconnecting)).subscribe(()=>this._validateBounds()),r.n.bottomOffset$.pipe((0,a.tap)(()=>this._applyContainerPosition()),(0,a.takeUntil)(this.disconnecting)).subscribe()}firstUpdated(){this._currentCorner=this.corner,this._loadPosition(),this._containerRef.value&&(this._applyContainerPosition(),this._setupDrag(),this.#e=!0,this.open&&this._openOverlay())}willUpdate(e){this.#e&&e.has(`open`)&&(this.open&&!this.#t?this._openOverlay():!this.open&&this.#t&&this.#t.unsubscribe())}disconnectedCallback(){super.disconnectedCallback(),this._currentAnimation?.cancel(),this.#t?.unsubscribe()}toggle(){this.open=!this.open}render(){let e=(0,o.classMap)({"inline-flex":!0,"rounded-full":!0,"overflow-hidden":!0,"transition-opacity":!0,"duration-200":!0,"opacity-85":this.isDragging,"scale-95":this.isDragging}),t=(0,s.styleMap)({position:`fixed`,"pointer-events":`auto`}),n=(0,o.classMap)({"h-14":!0,"rounded-full":!0,flex:!0,"items-center":!0,"gap-3":!0,"select-none":!0,"touch-none":!0,"cursor-grabbing":this.isDragging,"cursor-pointer":!this.isDragging,"px-5":!!this.label,"w-14":!this.label,"justify-center":!this.label});return l.html`
9
- <schmancy-surface
10
- ${(0,u.ref)(this._containerRef)}
11
- type="glass"
12
- .elevation=${this.lowered?1:3}
13
- class=${e}
14
- style=${t}
15
- aria-expanded=${this.open}
16
- >
17
- <div
18
- ${(0,u.ref)(this._headerRef)}
19
- class=${n}
20
- role="button"
21
- tabindex="0"
22
- aria-label=${this.label??`Open panel`}
23
- title="Drag to move · click to open"
24
- >
25
- <slot name="header">
26
- ${(0,d.when)(!!this.icon,()=>l.html`<schmancy-icon>${this.icon}</schmancy-icon>`,()=>l.nothing)}
27
- </slot>
28
- ${(0,d.when)(!!this.label,()=>l.html`<schmancy-typography type="label" token="lg" class="whitespace-nowrap">
29
- ${this.label}
30
- </schmancy-typography>`,()=>l.nothing)}
31
- <slot name="summary"></slot>
32
- </div>
33
-
34
- <!-- Default-slot content parks here (hidden) while collapsed;
35
- relocated into the show() overlay on open. -->
36
- <div hidden><slot></slot></div>
37
- </schmancy-surface>
38
- `}};e.u([(0,c.property)({type:String})],p.prototype,`id`,void 0),e.u([(0,c.property)({type:String})],p.prototype,`icon`,void 0),e.u([(0,c.property)({type:String})],p.prototype,`label`,void 0),e.u([(0,c.property)({type:Boolean,reflect:!0})],p.prototype,`lowered`,void 0),e.u([(0,c.property)({type:String})],p.prototype,`corner`,void 0),e.u([(0,c.property)({type:Boolean,reflect:!0})],p.prototype,`open`,void 0),e.u([(0,c.state)()],p.prototype,`isDragging`,void 0),e.u([(0,c.state)()],p.prototype,`_currentCorner`,void 0),e.u([(0,c.queryAssignedElements)()],p.prototype,`_slotted`,void 0);var m=p=e.u([(0,c.customElement)(`schmancy-boat`)],p);Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return m}});
@@ -1 +0,0 @@
1
- {"version":3,"file":"boat-BgpWcLnV.cjs","names":["#sub","#captured","#ready"],"sources":["../src/boat/boat.ts"],"sourcesContent":["import { SchmancyElement } from '@mixins/index'\nimport { css, html, nothing, type PropertyValues } from 'lit'\nimport { customElement, property, queryAssignedElements, state } from 'lit/decorators.js'\nimport { classMap } from 'lit/directives/class-map.js'\nimport { createRef, ref } from 'lit/directives/ref.js'\nimport { styleMap } from 'lit/directives/style-map.js'\nimport { when } from 'lit/directives/when.js'\nimport { filter, finalize, fromEvent, map, merge, type Subscription, switchMap, takeUntil, tap } from 'rxjs'\nimport { SPRING_SMOOTH } from '../utils/animation.js'\nimport { reducedMotion$ } from '../directives/reduced-motion'\nimport { show } from '../overlay/overlay.service'\nimport { theme } from '../theme/theme.service.js'\n\nconst DRAG_THRESHOLD = 5\nconst POSITION_STORAGE_KEY_PREFIX = 'schmancy-boat-'\n\ntype Corner = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'\ninterface Position {\n\tx: number\n\ty: number\n}\n\n/**\n * Material-3 extended FAB that delegates its expanded panel to the `show()`\n * overlay service. Collapsed: a draggable, corner-anchored pill (icon + label,\n * circular when no label). Activated: the default-slot content blooms from the\n * FAB as an overlay (backdrop / Esc / back-button / sheet-on-narrow handled by\n * the overlay primitive).\n */\n@customElement('schmancy-boat')\nexport default class SchmancyBoat extends SchmancyElement {\n\tstatic styles = [css`\n\t\t:host {\n\t\t\tdisplay: contents;\n\t\t}\n\t\t:host([hidden]) {\n\t\t\tdisplay: none !important;\n\t\t}\n\t`]\n\n\t@property({ type: String }) id: string = 'default'\n\t@property({ type: String }) icon?: string\n\t@property({ type: String }) label?: string\n\t/** When true, uses a lower elevation shadow on the FAB. */\n\t@property({ type: Boolean, reflect: true }) lowered: boolean = false\n\t/** Corner the FAB is anchored to. */\n\t@property({ type: String }) corner: Corner = 'bottom-right'\n\t/** Open state. Bind `?open=${…}` to drive the overlay; reflected to the attribute. */\n\t@property({ type: Boolean, reflect: true }) open: boolean = false\n\n\t@state() private isDragging = false\n\t@state() private _currentCorner: Corner = 'bottom-right'\n\n\t@queryAssignedElements() private _slotted!: Element[]\n\n\tprivate _position: Position = { x: 16, y: 16 }\n\tprivate _containerRef = createRef<HTMLElement>()\n\tprivate _headerRef = createRef<HTMLElement>()\n\tprivate _currentAnimation?: Animation\n\n\t#ready = false\n\t#sub?: Subscription\n\t#captured: Element[] = []\n\n\t// ============================================\n\t// POSITION MANAGEMENT\n\t// ============================================\n\n\tprivate _applyContainerPosition() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\tcontainer.style.removeProperty('left')\n\t\tcontainer.style.removeProperty('right')\n\t\tcontainer.style.removeProperty('top')\n\t\tcontainer.style.removeProperty('bottom')\n\t\tconst { x, y } = this._position\n\t\tif (this._currentCorner.includes('right')) {\n\t\t\tcontainer.style.right = `${x}px`\n\t\t} else {\n\t\t\tcontainer.style.left = `${x}px`\n\t\t}\n\t\tif (this._currentCorner.includes('bottom')) {\n\t\t\tcontainer.style.bottom = `${y + theme.bottomOffset}px`\n\t\t} else {\n\t\t\tcontainer.style.top = `${y}px`\n\t\t}\n\t}\n\n\tprivate _loadPosition() {\n\t\ttry {\n\t\t\tconst saved = localStorage.getItem(POSITION_STORAGE_KEY_PREFIX + this.id)\n\t\t\tif (saved) {\n\t\t\t\tconst parsed = JSON.parse(saved) as { x: number; y: number; anchor: Corner }\n\t\t\t\tthis._position = { x: parsed.x, y: parsed.y }\n\t\t\t\tthis._currentCorner = parsed.anchor\n\t\t\t}\n\t\t} catch {\n\t\t\t// ignore localStorage errors\n\t\t}\n\t}\n\n\tprivate _savePosition() {\n\t\ttry {\n\t\t\tlocalStorage.setItem(\n\t\t\t\tPOSITION_STORAGE_KEY_PREFIX + this.id,\n\t\t\t\tJSON.stringify({ ...this._position, anchor: this._currentCorner }),\n\t\t\t)\n\t\t} catch {\n\t\t\t// ignore localStorage errors\n\t\t}\n\t}\n\n\tprivate _validateBounds() {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\t\tconst rect = container.getBoundingClientRect()\n\t\tif (rect.width === 0) return\n\t\tconst vw = window.innerWidth\n\t\tconst vh = window.innerHeight\n\t\tconst isRight = this._currentCorner.includes('right')\n\t\tconst isBottom = this._currentCorner.includes('bottom')\n\t\tconst actualLeft = isRight ? vw - this._position.x - rect.width : this._position.x\n\t\tconst actualTop = isBottom ? vh - this._position.y - rect.height : this._position.y\n\t\tconst newLeft = Math.max(0, Math.min(actualLeft, vw - rect.width))\n\t\tconst newTop = Math.max(0, Math.min(actualTop, vh - rect.height))\n\t\tthis._position = {\n\t\t\tx: isRight ? vw - newLeft - rect.width : newLeft,\n\t\t\ty: isBottom ? vh - newTop - rect.height : newTop,\n\t\t}\n\t\tthis._applyContainerPosition()\n\t}\n\n\t// ============================================\n\t// CORNER SNAPPING (FLIP)\n\t// ============================================\n\n\tprivate _reorientToNearestCorner(): void {\n\t\tconst container = this._containerRef.value\n\t\tif (!container) return\n\n\t\tconst rect = container.getBoundingClientRect()\n\t\tconst fabCenterX = rect.left + rect.width / 2\n\t\tconst fabCenterY = rect.top + rect.height / 2\n\t\tconst side = fabCenterX > window.innerWidth / 2 ? 'right' : 'left'\n\t\tconst vert = fabCenterY > window.innerHeight / 2 ? 'bottom' : 'top'\n\t\tthis._currentCorner = `${vert}-${side}` as Corner\n\t\tthis._position = { x: 16, y: 16 }\n\t\tthis._applyContainerPosition()\n\n\t\tif (reducedMotion$.value) {\n\t\t\tthis._savePosition()\n\t\t\treturn\n\t\t}\n\n\t\tconst newRect = container.getBoundingClientRect()\n\t\tconst dx = rect.left - newRect.left\n\t\tconst dy = rect.top - newRect.top\n\t\tcontainer.style.transform = `translate(${dx}px, ${dy}px)`\n\n\t\tthis._currentAnimation?.cancel()\n\t\tconst anim = container.animate(\n\t\t\t[{ transform: container.style.transform }, { transform: 'translate(0,0)' }],\n\t\t\t{\n\t\t\t\tduration: SPRING_SMOOTH.duration,\n\t\t\t\teasing: SPRING_SMOOTH.easingFallback,\n\t\t\t\tfill: 'forwards',\n\t\t\t},\n\t\t)\n\t\tthis._currentAnimation = anim\n\t\tanim.finished.then(() => {\n\t\t\tif (container.isConnected) container.style.transform = ''\n\t\t\treturn\n\t\t})\n\n\t\tthis._savePosition()\n\t}\n\n\t// ============================================\n\t// DRAG PIPELINE\n\t// ============================================\n\n\tprivate _setupDrag() {\n\t\tconst header = this._headerRef.value\n\t\tconst container = this._containerRef.value\n\t\tif (!header || !container) return\n\n\t\tlet didDrag = false\n\n\t\tfromEvent<PointerEvent>(header, 'pointerdown')\n\t\t\t.pipe(\n\t\t\t\tfilter(e => e.button === 0),\n\t\t\t\ttap(e => {\n\t\t\t\t\te.preventDefault()\n\t\t\t\t\te.stopPropagation()\n\t\t\t\t\theader.setPointerCapture(e.pointerId)\n\t\t\t\t}),\n\t\t\t\tmap(e => {\n\t\t\t\t\tconst rect = container.getBoundingClientRect()\n\t\t\t\t\tdidDrag = false\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpointerId: e.pointerId,\n\t\t\t\t\t\tstartX: e.clientX,\n\t\t\t\t\t\tstartY: e.clientY,\n\t\t\t\t\t\toffsetX: e.clientX - rect.left,\n\t\t\t\t\t\toffsetY: e.clientY - rect.top,\n\t\t\t\t\t\trect,\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t\tswitchMap(({ pointerId, startX, startY, offsetX, offsetY, rect }) => {\n\t\t\t\t\tconst sameId = (e: PointerEvent) => e.pointerId === pointerId\n\t\t\t\t\tconst move$ = fromEvent<PointerEvent>(window, 'pointermove').pipe(filter(sameId))\n\t\t\t\t\tconst end$ = merge(\n\t\t\t\t\t\tfromEvent<PointerEvent>(window, 'pointerup'),\n\t\t\t\t\t\tfromEvent<PointerEvent>(window, 'pointercancel'),\n\t\t\t\t\t).pipe(filter(sameId))\n\n\t\t\t\t\treturn move$.pipe(\n\t\t\t\t\t\ttap(({ clientX, clientY }) => {\n\t\t\t\t\t\t\tconst dx = clientX - startX\n\t\t\t\t\t\t\tconst dy = clientY - startY\n\t\t\t\t\t\t\tif (Math.sqrt(dx * dx + dy * dy) > DRAG_THRESHOLD && !didDrag) {\n\t\t\t\t\t\t\t\tdidDrag = true\n\t\t\t\t\t\t\t\tthis.isDragging = true\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!didDrag) return\n\n\t\t\t\t\t\t\tconst vw = window.innerWidth\n\t\t\t\t\t\t\tconst vh = window.innerHeight\n\t\t\t\t\t\t\tconst left = Math.max(0, Math.min(clientX - offsetX, vw - rect.width))\n\t\t\t\t\t\t\tconst top = Math.max(0, Math.min(clientY - offsetY, vh - rect.height))\n\t\t\t\t\t\t\tthis._position = {\n\t\t\t\t\t\t\t\tx: this._currentCorner.includes('right') ? vw - left - rect.width : left,\n\t\t\t\t\t\t\t\ty: this._currentCorner.includes('bottom') ? vh - top - rect.height : top,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis._applyContainerPosition()\n\t\t\t\t\t\t}),\n\t\t\t\t\t\ttakeUntil(end$),\n\t\t\t\t\t\tfinalize(() => {\n\t\t\t\t\t\t\tif (didDrag) {\n\t\t\t\t\t\t\t\tthis._reorientToNearestCorner()\n\t\t\t\t\t\t\t\tthis.isDragging = false\n\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.isDragging = false\n\t\t\t\t\t\t\t\tdidDrag = false\n\t\t\t\t\t\t\t\tthis.toggle()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe()\n\t}\n\n\t// ============================================\n\t// OVERLAY DELEGATION\n\t// ============================================\n\n\tprivate _openOverlay() {\n\t\tif (this.#sub) return\n\t\tconst anchor = this._containerRef.value\n\t\tconst wrapper = document.createElement('div')\n\t\twrapper.className = 'flex flex-col'\n\t\tthis.#captured = [...this._slotted]\n\t\tthis.#captured.forEach(node => wrapper.appendChild(node))\n\n\t\tthis.#sub = show(wrapper, {\n\t\t\tanchor: anchor ?? undefined,\n\t\t\tdismissable: true,\n\t\t\thistoryStrategy: 'silent',\n\t\t})\n\t\t\t.pipe(\n\t\t\t\tfinalize(() => this._restoreSlotted()),\n\t\t\t\ttakeUntil(this.disconnecting),\n\t\t\t)\n\t\t\t.subscribe()\n\n\t\tthis.dispatchScopedEvent('toggle', 'open')\n\t}\n\n\tprivate _restoreSlotted() {\n\t\tthis.#captured.forEach(node => this.appendChild(node))\n\t\tthis.#captured = []\n\t\tthis.#sub = undefined\n\t\tif (this.open) this.open = false\n\t\tthis.dispatchScopedEvent('toggle', 'closed')\n\t}\n\n\t// ============================================\n\t// LIFECYCLE\n\t// ============================================\n\n\tconnectedCallback() {\n\t\tsuper.connectedCallback()\n\n\t\tfromEvent(window, 'resize')\n\t\t\t.pipe(takeUntil(this.disconnecting))\n\t\t\t.subscribe(() => this._validateBounds())\n\n\t\ttheme.bottomOffset$.pipe(\n\t\t\ttap(() => this._applyContainerPosition()),\n\t\t\ttakeUntil(this.disconnecting),\n\t\t).subscribe()\n\t}\n\n\tfirstUpdated() {\n\t\tthis._currentCorner = this.corner\n\t\tthis._loadPosition()\n\t\tif (!this._containerRef.value) return\n\t\tthis._applyContainerPosition()\n\t\tthis._setupDrag()\n\t\tthis.#ready = true\n\t\tif (this.open) this._openOverlay()\n\t}\n\n\tprotected willUpdate(changed: PropertyValues<this>) {\n\t\tif (!this.#ready || !changed.has('open')) return\n\t\tif (this.open && !this.#sub) this._openOverlay()\n\t\telse if (!this.open && this.#sub) this.#sub.unsubscribe()\n\t}\n\n\tdisconnectedCallback() {\n\t\tsuper.disconnectedCallback()\n\t\tthis._currentAnimation?.cancel()\n\t\tthis.#sub?.unsubscribe()\n\t}\n\n\t// ============================================\n\t// PUBLIC API\n\t// ============================================\n\n\t/** Flip open ↔ closed. */\n\ttoggle() {\n\t\tthis.open = !this.open\n\t}\n\n\t// ============================================\n\t// RENDER\n\t// ============================================\n\n\tprotected render(): unknown {\n\t\tconst containerClasses = classMap({\n\t\t\t'inline-flex': true,\n\t\t\t'rounded-full': true,\n\t\t\t'overflow-hidden': true,\n\t\t\t'transition-opacity': true,\n\t\t\t'duration-200': true,\n\t\t\t'opacity-85': this.isDragging,\n\t\t\t'scale-95': this.isDragging,\n\t\t})\n\n\t\tconst containerStyles = styleMap({\n\t\t\tposition: 'fixed',\n\t\t\t'pointer-events': 'auto',\n\t\t})\n\n\t\tconst fabClasses = classMap({\n\t\t\t'h-14': true,\n\t\t\t'rounded-full': true,\n\t\t\tflex: true,\n\t\t\t'items-center': true,\n\t\t\t'gap-3': true,\n\t\t\t'select-none': true,\n\t\t\t'touch-none': true,\n\t\t\t'cursor-grabbing': this.isDragging,\n\t\t\t'cursor-pointer': !this.isDragging,\n\t\t\t'px-5': !!this.label,\n\t\t\t'w-14': !this.label,\n\t\t\t'justify-center': !this.label,\n\t\t})\n\n\t\treturn html`\n\t\t\t<schmancy-surface\n\t\t\t\t${ref(this._containerRef)}\n\t\t\t\ttype=\"glass\"\n\t\t\t\t.elevation=${this.lowered ? 1 : 3}\n\t\t\t\tclass=${containerClasses}\n\t\t\t\tstyle=${containerStyles}\n\t\t\t\taria-expanded=${this.open}\n\t\t\t>\n\t\t\t\t<div\n\t\t\t\t\t${ref(this._headerRef)}\n\t\t\t\t\tclass=${fabClasses}\n\t\t\t\t\trole=\"button\"\n\t\t\t\t\ttabindex=\"0\"\n\t\t\t\t\taria-label=${this.label ?? 'Open panel'}\n\t\t\t\t\ttitle=\"Drag to move · click to open\"\n\t\t\t\t>\n\t\t\t\t\t<slot name=\"header\">\n\t\t\t\t\t\t${when(\n\t\t\t\t\t\t\t!!this.icon,\n\t\t\t\t\t\t\t() => html`<schmancy-icon>${this.icon}</schmancy-icon>`,\n\t\t\t\t\t\t\t() => nothing,\n\t\t\t\t\t\t)}\n\t\t\t\t\t</slot>\n\t\t\t\t\t${when(\n\t\t\t\t\t\t!!this.label,\n\t\t\t\t\t\t() => html`<schmancy-typography type=\"label\" token=\"lg\" class=\"whitespace-nowrap\">\n\t\t\t\t\t\t\t${this.label}\n\t\t\t\t\t\t</schmancy-typography>`,\n\t\t\t\t\t\t() => nothing,\n\t\t\t\t\t)}\n\t\t\t\t\t<slot name=\"summary\"></slot>\n\t\t\t\t</div>\n\n\t\t\t\t<!-- Default-slot content parks here (hidden) while collapsed;\n\t\t\t\t relocated into the show() overlay on open. -->\n\t\t\t\t<div hidden><slot></slot></div>\n\t\t\t</schmancy-surface>\n\t\t`\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'schmancy-boat': SchmancyBoat\n\t}\n}\n"],"mappings":"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"}