drab 5.0.0 → 5.0.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.
Files changed (97) hide show
  1. package/README.md +0 -5
  2. package/animate/define.d.ts +1 -2
  3. package/animate/define.iife.js +1 -1
  4. package/animate/define.js +2 -1
  5. package/animate/index.d.ts +8 -5
  6. package/animate/index.iife.js +1 -1
  7. package/animate/index.js +138 -1
  8. package/{index-SyRipepB.d.ts → base/copy/index.d.ts} +4 -5
  9. package/base/copy/index.js +25 -0
  10. package/base/define.d.ts +1 -2
  11. package/base/define.js +2 -1
  12. package/base/index.d.ts +1 -3
  13. package/base/index.js +108 -1
  14. package/breakpoint/define.d.ts +1 -2
  15. package/breakpoint/define.js +2 -1
  16. package/breakpoint/index.d.ts +7 -5
  17. package/breakpoint/index.js +55 -1
  18. package/contextmenu/define.d.ts +1 -2
  19. package/contextmenu/define.iife.js +1 -1
  20. package/contextmenu/define.js +2 -1
  21. package/contextmenu/index.d.ts +4 -6
  22. package/contextmenu/index.iife.js +1 -1
  23. package/contextmenu/index.js +71 -1
  24. package/copy/define.d.ts +1 -2
  25. package/copy/define.js +2 -1
  26. package/copy/index.d.ts +4 -6
  27. package/copy/index.iife.js +1 -1
  28. package/copy/index.js +13 -1
  29. package/define/index.iife.js +9 -9
  30. package/define.d.ts +1 -0
  31. package/define.js +4 -0
  32. package/details/define.d.ts +1 -2
  33. package/details/define.iife.js +1 -1
  34. package/details/define.js +2 -1
  35. package/details/index.d.ts +4 -6
  36. package/details/index.iife.js +1 -1
  37. package/details/index.js +46 -1
  38. package/dialog/define.d.ts +1 -2
  39. package/dialog/define.iife.js +1 -1
  40. package/dialog/define.js +2 -1
  41. package/dialog/index.d.ts +4 -6
  42. package/dialog/index.iife.js +1 -1
  43. package/dialog/index.js +44 -1
  44. package/editor/define.d.ts +1 -2
  45. package/editor/define.js +2 -1
  46. package/editor/index.d.ts +5 -6
  47. package/editor/index.iife.js +7 -7
  48. package/editor/index.js +480 -1
  49. package/fullscreen/define.d.ts +1 -2
  50. package/fullscreen/define.iife.js +1 -1
  51. package/fullscreen/define.js +2 -1
  52. package/fullscreen/index.d.ts +4 -5
  53. package/fullscreen/index.iife.js +1 -1
  54. package/fullscreen/index.js +45 -1
  55. package/index.d.ts +14 -14
  56. package/index.iife.js +9 -9
  57. package/index.js +14 -1
  58. package/package.json +6 -5
  59. package/popover/define.d.ts +1 -2
  60. package/popover/define.iife.js +1 -1
  61. package/popover/define.js +2 -1
  62. package/popover/index.d.ts +4 -6
  63. package/popover/index.iife.js +1 -1
  64. package/popover/index.js +74 -1
  65. package/share/define.d.ts +1 -2
  66. package/share/define.js +2 -1
  67. package/share/index.d.ts +5 -7
  68. package/share/index.js +34 -1
  69. package/tablesort/define.d.ts +1 -2
  70. package/tablesort/define.iife.js +1 -1
  71. package/tablesort/define.js +2 -1
  72. package/tablesort/index.d.ts +4 -5
  73. package/tablesort/index.iife.js +1 -1
  74. package/tablesort/index.js +109 -1
  75. package/types/index.d.ts +11 -0
  76. package/types/index.js +1 -0
  77. package/youtube/define.d.ts +1 -2
  78. package/youtube/define.js +2 -1
  79. package/youtube/index.d.ts +4 -5
  80. package/youtube/index.iife.js +1 -1
  81. package/youtube/index.js +56 -1
  82. package/chunk-57VEEUFG.js +0 -1
  83. package/chunk-5JV4T7GM.js +0 -1
  84. package/chunk-6HYPZWQ4.js +0 -1
  85. package/chunk-7F7CQUEG.js +0 -1
  86. package/chunk-7KU2PRW5.js +0 -1
  87. package/chunk-7S6DTKGH.js +0 -1
  88. package/chunk-G5WFHYNX.js +0 -1
  89. package/chunk-GPET75FT.js +0 -9
  90. package/chunk-IQJQPZUL.js +0 -1
  91. package/chunk-JMJUWKN2.js +0 -1
  92. package/chunk-MXKU7AKV.js +0 -1
  93. package/chunk-T7RZI3ZL.js +0 -1
  94. package/chunk-TSTTUEAF.js +0 -1
  95. package/chunk-VEVFQB5N.js +0 -1
  96. package/define/index.d.ts +0 -2
  97. package/define/index.js +0 -1
package/README.md CHANGED
@@ -1,10 +1,5 @@
1
1
  # A Headless Custom Element Library
2
2
 
3
- - [Docs](https://drab.robino.dev)
4
- - [GitHub](https://github.com/rossrobino/drab)
5
- - [npm](https://www.npmjs.com/package/drab)
6
- - [MIT License](https://github.com/rossrobino/drab/blob/main/LICENSE.md)
7
-
8
3
  ## Features
9
4
 
10
5
  **drab** focuses on providing JavaScript functionality where it's most useful. Many of the elements are helpful wrappers around browser APIs. Here are some of the features of the library.
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export {};
@@ -1 +1 @@
1
- "use strict";(()=>{var m=class extends HTMLElement{#e=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(s){this.setAttribute("event",s)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(s=HTMLElement){let n=this.querySelector(this.getAttribute("content")??"[data-content]");if(n instanceof s)return n;throw new Error("Content not found")}swapContent(s=!0,n=800){let e=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(e){let t=Array.from(this.getContent().childNodes);e instanceof HTMLTemplateElement?this.getContent().replaceChildren(e.content.cloneNode(!0)):this.getContent().replaceChildren(...e.childNodes),s&&setTimeout(()=>this.getContent().replaceChildren(...t),n)}}safeListener(s,n,e=document.body,t={}){t.signal=this.#e.signal,e.addEventListener(s,n,t)}triggerListener(s,n=this.event){for(let e of this.getTrigger())e.addEventListener(n,s)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#e.abort()}};var f=class extends m{constructor(){super()}get animationOptions(){let s={};for(let n of this.getAttributeNames())if(n.startsWith("animation-option-")){let e=this.getAttribute(n),[,,t]=n.split("-");e&&(t==="duration"||t==="delay"?s[t]=Number(e):t==="easing"&&(s[t]=e))}return s}async animateElement(s={element:this.getContent(),options:{}}){let{element:n=this.getContent(),options:e={}}=s,t=this.keyframes;if(t.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){e=Object.assign(this.animationOptions,e),e.duration||(e.duration=200),e.easing||(e.easing="ease-in-out");let r=t.at(0),i=t.at(-1);if(r&&i){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete i[l]}e.direction?.includes("reverse")&&([r,i]=[i,r]),Object.assign(n.style,r),await n.animate(t,e).finished,Object.assign(n.style,i)}}get keyframes(){let s=[];for(let n of this.getAttributeNames()){let e=this.getAttribute(n),[,,t,...r]=n.split("-");if(n.startsWith("animation-keyframe-")){let i=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(t&&i){t==="from"?t="0":t==="to"?t="1":t=String(parseInt(t)*.01);let o=Number(t),a=s.find(l=>l.offset===o);a?a[i]=e:s.push({[i]:e,offset:o})}}}return s.sort((n,e)=>Number(n.offset)-Number(e.offset)),s}};customElements.define("drab-animate",f);})();
1
+ "use strict";(()=>{var l=class extends HTMLElement{#e=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(i){this.setAttribute("event",i)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(i=HTMLElement){let n=this.querySelector(this.getAttribute("content")??"[data-content]");if(n instanceof i)return n;throw new Error("Content not found")}swapContent(i=!0,n=800){let e=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(e){let t=Array.from(this.getContent().childNodes);e instanceof HTMLTemplateElement?this.getContent().replaceChildren(e.content.cloneNode(!0)):this.getContent().replaceChildren(...e.childNodes),i&&setTimeout(()=>this.getContent().replaceChildren(...t),n)}}safeListener(i,n,e=document.body,t={}){t.signal=this.#e.signal,e.addEventListener(i,n,t)}triggerListener(i,n=this.event){for(let e of this.getTrigger())e.addEventListener(n,i)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#e.abort()}};var f=class extends l{constructor(){super()}get animationOptions(){let i={};for(let n of this.getAttributeNames())if(n.startsWith("animation-option-")){let e=this.getAttribute(n),[,,t]=n.split("-");e&&(t==="duration"||t==="delay"?i[t]=Number(e):t==="easing"&&(i[t]=e))}return i}async animateElement(i={element:this.getContent(),options:{}}){let{element:n=this.getContent(),options:e={}}=i,t=this.keyframes;if(t.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){e=Object.assign(this.animationOptions,e),e.duration||(e.duration=200),e.easing||(e.easing="ease-in-out");let o=t.at(0),s=t.at(-1);if(o&&s){let a=["composite","easing","offset"];for(let m of a)delete o[m],delete s[m]}e.direction?.includes("reverse")&&([o,s]=[s,o]),Object.assign(n.style,o),await n.animate(t,e).finished,Object.assign(n.style,s)}}get keyframes(){let i=[];for(let n of this.getAttributeNames()){let e=this.getAttribute(n),[,,t,...o]=n.split("-");if(n.startsWith("animation-keyframe-")){let s=o.map((r,a)=>a<1?r:r.at(0)?.toUpperCase()+r.slice(1)).join("");if(t&&s){t==="from"?t="0":t==="to"?t="1":t=String(parseInt(t)*.01);let r=Number(t),a=i.find(m=>m.offset===r);a?a[s]=e:i.push({[s]:e,offset:r})}}}return i.sort((n,e)=>Number(n.offset)-Number(e.offset)),i}};customElements.define("drab-animate",f);})();
package/animate/define.js CHANGED
@@ -1 +1,2 @@
1
- import{a as e}from"../chunk-7KU2PRW5.js";import"../chunk-MXKU7AKV.js";customElements.define("drab-animate",e);
1
+ import { Animate } from "./index.js";
2
+ customElements.define("drab-animate", Animate);
@@ -1,5 +1,9 @@
1
- import { Base } from '../base/index.js';
2
-
1
+ import { Base } from "../base/index.js";
2
+ type AnimationKeyframe = `animation-keyframe-${"from" | "to" | number}-${string}`;
3
+ type AnimationOption = `animation-option-${"easing" | "duration" | "delay"}`;
4
+ export type AnimateAttributes = Partial<{
5
+ [K in AnimationKeyframe | AnimationOption]: string;
6
+ }>;
3
7
  /**
4
8
  * The `Animate` base class provides a declarative way to use the
5
9
  * [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)
@@ -26,7 +30,7 @@ import { Base } from '../base/index.js';
26
30
  *
27
31
  * `property` can be `duration`, `delay`, or `easing`.
28
32
  */
29
- declare class Animate extends Base {
33
+ export declare class Animate extends Base {
30
34
  constructor();
31
35
  /**
32
36
  * @returns An object containing the values of each `animation-option` attribute
@@ -50,5 +54,4 @@ declare class Animate extends Base {
50
54
  }): Promise<void>;
51
55
  get keyframes(): Keyframe[];
52
56
  }
53
-
54
- export { Animate };
57
+ export {};
@@ -1 +1 @@
1
- "use strict";(()=>{var f=class extends HTMLElement{#e=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(s){this.setAttribute("event",s)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(s=HTMLElement){let n=this.querySelector(this.getAttribute("content")??"[data-content]");if(n instanceof s)return n;throw new Error("Content not found")}swapContent(s=!0,n=800){let e=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(e){let t=Array.from(this.getContent().childNodes);e instanceof HTMLTemplateElement?this.getContent().replaceChildren(e.content.cloneNode(!0)):this.getContent().replaceChildren(...e.childNodes),s&&setTimeout(()=>this.getContent().replaceChildren(...t),n)}}safeListener(s,n,e=document.body,t={}){t.signal=this.#e.signal,e.addEventListener(s,n,t)}triggerListener(s,n=this.event){for(let e of this.getTrigger())e.addEventListener(n,s)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#e.abort()}};var m=class extends f{constructor(){super()}get animationOptions(){let s={};for(let n of this.getAttributeNames())if(n.startsWith("animation-option-")){let e=this.getAttribute(n),[,,t]=n.split("-");e&&(t==="duration"||t==="delay"?s[t]=Number(e):t==="easing"&&(s[t]=e))}return s}async animateElement(s={element:this.getContent(),options:{}}){let{element:n=this.getContent(),options:e={}}=s,t=this.keyframes;if(t.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){e=Object.assign(this.animationOptions,e),e.duration||(e.duration=200),e.easing||(e.easing="ease-in-out");let r=t.at(0),i=t.at(-1);if(r&&i){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete i[l]}e.direction?.includes("reverse")&&([r,i]=[i,r]),Object.assign(n.style,r),await n.animate(t,e).finished,Object.assign(n.style,i)}}get keyframes(){let s=[];for(let n of this.getAttributeNames()){let e=this.getAttribute(n),[,,t,...r]=n.split("-");if(n.startsWith("animation-keyframe-")){let i=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(t&&i){t==="from"?t="0":t==="to"?t="1":t=String(parseInt(t)*.01);let o=Number(t),a=s.find(l=>l.offset===o);a?a[i]=e:s.push({[i]:e,offset:o})}}}return s.sort((n,e)=>Number(n.offset)-Number(e.offset)),s}};})();
1
+ "use strict";(()=>{var m=class extends HTMLElement{#e=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(i){this.setAttribute("event",i)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(i=HTMLElement){let n=this.querySelector(this.getAttribute("content")??"[data-content]");if(n instanceof i)return n;throw new Error("Content not found")}swapContent(i=!0,n=800){let e=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(e){let t=Array.from(this.getContent().childNodes);e instanceof HTMLTemplateElement?this.getContent().replaceChildren(e.content.cloneNode(!0)):this.getContent().replaceChildren(...e.childNodes),i&&setTimeout(()=>this.getContent().replaceChildren(...t),n)}}safeListener(i,n,e=document.body,t={}){t.signal=this.#e.signal,e.addEventListener(i,n,t)}triggerListener(i,n=this.event){for(let e of this.getTrigger())e.addEventListener(n,i)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#e.abort()}};var f=class extends m{constructor(){super()}get animationOptions(){let i={};for(let n of this.getAttributeNames())if(n.startsWith("animation-option-")){let e=this.getAttribute(n),[,,t]=n.split("-");e&&(t==="duration"||t==="delay"?i[t]=Number(e):t==="easing"&&(i[t]=e))}return i}async animateElement(i={element:this.getContent(),options:{}}){let{element:n=this.getContent(),options:e={}}=i,t=this.keyframes;if(t.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){e=Object.assign(this.animationOptions,e),e.duration||(e.duration=200),e.easing||(e.easing="ease-in-out");let o=t.at(0),s=t.at(-1);if(o&&s){let a=["composite","easing","offset"];for(let l of a)delete o[l],delete s[l]}e.direction?.includes("reverse")&&([o,s]=[s,o]),Object.assign(n.style,o),await n.animate(t,e).finished,Object.assign(n.style,s)}}get keyframes(){let i=[];for(let n of this.getAttributeNames()){let e=this.getAttribute(n),[,,t,...o]=n.split("-");if(n.startsWith("animation-keyframe-")){let s=o.map((r,a)=>a<1?r:r.at(0)?.toUpperCase()+r.slice(1)).join("");if(t&&s){t==="from"?t="0":t==="to"?t="1":t=String(parseInt(t)*.01);let r=Number(t),a=i.find(l=>l.offset===r);a?a[s]=e:i.push({[s]:e,offset:r})}}}return i.sort((n,e)=>Number(n.offset)-Number(e.offset)),i}};})();
package/animate/index.js CHANGED
@@ -1 +1,138 @@
1
- import{a}from"../chunk-7KU2PRW5.js";import"../chunk-MXKU7AKV.js";export{a as Animate};
1
+ import { Base } from "../base/index.js";
2
+ /**
3
+ * The `Animate` base class provides a declarative way to use the
4
+ * [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API)
5
+ * through HTML attributes. The `animateElement` method uses these attributes and
6
+ * persists the final animation state. Other elements in **drab** extend this class
7
+ * to provide animations. You can also extend this class to create your own custom
8
+ * animated element.
9
+ *
10
+ * Keyframes can be set via HTML attributes on the element in the form of:
11
+ *
12
+ * ```html
13
+ * <drab-animate animation-keyframe-offset-property="value">
14
+ * ```
15
+ *
16
+ * `offset` can be `to`, `from`, or a `number`.
17
+ *
18
+ * `property` can be any animatable CSS property separated by dashes.
19
+ *
20
+ * Animations `options` can be set:
21
+ *
22
+ * ```html
23
+ * <drab-animate animation-option-property="value">
24
+ * ```
25
+ *
26
+ * `property` can be `duration`, `delay`, or `easing`.
27
+ */
28
+ export class Animate extends Base {
29
+ constructor() {
30
+ super();
31
+ }
32
+ /**
33
+ * @returns An object containing the values of each `animation-option` attribute
34
+ */
35
+ get animationOptions() {
36
+ const options = {};
37
+ for (const attributeName of this.getAttributeNames()) {
38
+ if (attributeName.startsWith("animation-option-")) {
39
+ const value = this.getAttribute(attributeName);
40
+ let [, , option] = attributeName.split("-");
41
+ if (value) {
42
+ if (option === "duration" || option === "delay") {
43
+ options[option] = Number(value);
44
+ }
45
+ else if (option === "easing") {
46
+ options[option] = value;
47
+ }
48
+ }
49
+ }
50
+ }
51
+ return options;
52
+ }
53
+ /**
54
+ * @description
55
+ * Animates a particular element using the web animations API.
56
+ *
57
+ * - Disables animation if the user prefers reduced motion.
58
+ * - Sets default options
59
+ * - Uses the keyframes provided from `this.keyframes`
60
+ * - Waits for the animation to complete
61
+ * - Sets the start and end styles based on the first and last keyframe
62
+ *
63
+ * @param animateOptions - animates `this.content()` by default
64
+ */
65
+ async animateElement(animateOptions = { element: this.getContent(), options: {} }) {
66
+ let { element = this.getContent(), options = {} } = animateOptions;
67
+ const keyframes = this.keyframes;
68
+ if (keyframes.length &&
69
+ !window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
70
+ // options passed in via JS override the html attributes
71
+ options = Object.assign(this.animationOptions, options);
72
+ // defaults
73
+ if (!options.duration)
74
+ options.duration = 200;
75
+ if (!options.easing)
76
+ options.easing = "ease-in-out";
77
+ let startStyles = keyframes.at(0);
78
+ let endStyles = keyframes.at(-1);
79
+ if (startStyles && endStyles) {
80
+ // Don't modify the start/end style based on these,
81
+ // everything else is a CSS property.
82
+ // This is instead of doing `fill` since it is discouraged:
83
+ // https://www.w3.org/TR/web-animations-1/#fill-behavior
84
+ const notStyles = ["composite", "easing", "offset"];
85
+ for (const key of notStyles) {
86
+ delete startStyles[key];
87
+ delete endStyles[key];
88
+ }
89
+ }
90
+ if (options.direction?.includes("reverse")) {
91
+ // swap the start and ending values
92
+ [startStyles, endStyles] = [endStyles, startStyles];
93
+ }
94
+ Object.assign(element.style, startStyles);
95
+ const animation = element.animate(keyframes, options);
96
+ await animation.finished;
97
+ Object.assign(element.style, endStyles);
98
+ }
99
+ }
100
+ get keyframes() {
101
+ const keyframes = [];
102
+ for (const attributeName of this.getAttributeNames()) {
103
+ /** the css property value, ex: "translate(100%,0)" */
104
+ const value = this.getAttribute(attributeName);
105
+ let [, , offset, ...propertyArray] = attributeName.split("-");
106
+ if (attributeName.startsWith("animation-keyframe-")) {
107
+ const property = propertyArray
108
+ .map((v, i) => {
109
+ if (i < 1)
110
+ return v;
111
+ return v.at(0)?.toUpperCase() + v.slice(1);
112
+ })
113
+ .join("");
114
+ if (offset && property) {
115
+ if (offset === "from")
116
+ offset = "0";
117
+ else if (offset === "to")
118
+ offset = "1";
119
+ else
120
+ offset = String(parseInt(offset) * 0.01);
121
+ const numberOffset = Number(offset);
122
+ const sameOffsetKeyframe = keyframes.find((v) => v.offset === numberOffset);
123
+ if (sameOffsetKeyframe) {
124
+ sameOffsetKeyframe[property] = value;
125
+ }
126
+ else {
127
+ keyframes.push({
128
+ [property]: value,
129
+ offset: numberOffset,
130
+ });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ keyframes.sort((a, b) => Number(a.offset) - Number(b.offset));
136
+ return keyframes;
137
+ }
138
+ }
@@ -1,8 +1,9 @@
1
- import { Base } from './base/index.js';
2
-
3
- declare class BaseCopy extends Base {
1
+ import { Base } from "../index.js";
2
+ export declare class BaseCopy extends Base {
4
3
  constructor();
5
4
  /**
5
+ * The value to copy or share.
6
+ *
6
7
  * @default "" the empty string
7
8
  */
8
9
  get value(): string;
@@ -13,5 +14,3 @@ declare class BaseCopy extends Base {
13
14
  */
14
15
  copy(text?: string): Promise<void>;
15
16
  }
16
-
17
- export { BaseCopy as B };
@@ -0,0 +1,25 @@
1
+ import { Base } from "../index.js";
2
+ export class BaseCopy extends Base {
3
+ constructor() {
4
+ super();
5
+ }
6
+ /**
7
+ * The value to copy or share.
8
+ *
9
+ * @default "" the empty string
10
+ */
11
+ get value() {
12
+ return this.getAttribute("value") ?? "";
13
+ }
14
+ set value(value) {
15
+ this.setAttribute("value", value);
16
+ }
17
+ /**
18
+ * Copies the `text`.
19
+ * @param text The `text` to share
20
+ */
21
+ async copy(text = this.value) {
22
+ await navigator.clipboard.writeText(text);
23
+ this.swapContent();
24
+ }
25
+ }
package/base/define.d.ts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export {};
package/base/define.js CHANGED
@@ -1 +1,2 @@
1
- import{b as e}from"../chunk-MXKU7AKV.js";customElements.define("drab-base",e);
1
+ import { Base } from "./index.js";
2
+ customElements.define("drab-base", Base);
package/base/index.d.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  *
11
11
  * Each element can have multiple `trigger`s, but will only have one `content`.
12
12
  */
13
- declare class Base extends HTMLElement {
13
+ export declare class Base extends HTMLElement {
14
14
  #private;
15
15
  constructor();
16
16
  /**
@@ -65,5 +65,3 @@ declare class Base extends HTMLElement {
65
65
  connectedCallback(): void;
66
66
  disconnectedCallback(): void;
67
67
  }
68
-
69
- export { Base };
package/base/index.js CHANGED
@@ -1 +1,108 @@
1
- import{b as a}from"../chunk-MXKU7AKV.js";export{a as Base};
1
+ /**
2
+ * Each element in the library extends the `Base` class. It provides methods
3
+ * for selecting elements via HTML attributes along with other helpers.
4
+ *
5
+ * By default, `trigger`s and `content` will be selected via the `data-trigger` and
6
+ * `data-content` attributes. Alternatively, you can set the `trigger` or
7
+ * `content` attribute to a CSS selector to change the default selector from
8
+ * `[data-trigger]` or `[data-content]` to a selector of your choosing.
9
+ * This can be useful if you have multiple elements within one another.
10
+ *
11
+ * Each element can have multiple `trigger`s, but will only have one `content`.
12
+ */
13
+ export class Base extends HTMLElement {
14
+ /**
15
+ * To clean up event listeners added to `document` when the element is removed.
16
+ */
17
+ #listenerController = new AbortController();
18
+ constructor() {
19
+ super();
20
+ }
21
+ /**
22
+ * Event for the `trigger` to execute.
23
+ *
24
+ * For example, set to `"mouseover"` to execute the event when the user hovers the mouse over the `trigger`, instead of when they click it.
25
+ *
26
+ * @default "click"
27
+ */
28
+ get event() {
29
+ return (this.getAttribute("event") ?? "click");
30
+ }
31
+ set event(value) {
32
+ this.setAttribute("event", value);
33
+ }
34
+ /**
35
+ * @returns All of the elements that match the `trigger` selector.
36
+ * @default this.querySelectorAll("[data-trigger]")
37
+ */
38
+ getTrigger() {
39
+ const triggers = this.querySelectorAll(this.getAttribute("trigger") ?? "[data-trigger]");
40
+ return triggers;
41
+ }
42
+ /**
43
+ * @param instance The instance of the desired element, ex: `HTMLDialogElement`.
44
+ * Defaults to `HTMLElement`.
45
+ * @returns The element that matches the `content` selector.
46
+ * @default this.querySelector("[data-content]")
47
+ */
48
+ getContent(instance = HTMLElement) {
49
+ const content = this.querySelector(this.getAttribute("content") ?? "[data-content]");
50
+ if (content instanceof instance)
51
+ return content;
52
+ throw new Error("Content not found");
53
+ }
54
+ /**
55
+ * Finds the `HTMLElement | HTMLTemplateElement` via the `swap` selector and
56
+ * swaps `this.content()` with the content of the element found.
57
+ *
58
+ * @param revert Swap back to old content
59
+ * @param delay Wait time before swapping back
60
+ */
61
+ swapContent(revert = true, delay = 800) {
62
+ const swap = this.querySelector(this.getAttribute("swap") ?? "[data-swap]");
63
+ if (swap) {
64
+ const original = Array.from(this.getContent().childNodes);
65
+ if (swap instanceof HTMLTemplateElement) {
66
+ this.getContent().replaceChildren(swap.content.cloneNode(true));
67
+ }
68
+ else {
69
+ this.getContent().replaceChildren(...swap.childNodes);
70
+ }
71
+ if (revert) {
72
+ setTimeout(() => this.getContent().replaceChildren(...original), delay);
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * Wrapper around `document.body.addEventListener` that ensures when the
78
+ * element is removed from the DOM, these event listeners are cleaned up.
79
+ * @param type
80
+ * @param listener
81
+ * @param options
82
+ */
83
+ safeListener(type, listener, element = document.body, options = {}) {
84
+ options.signal = this.#listenerController.signal;
85
+ //@ts-ignore - inferred listener type not working...?
86
+ element.addEventListener(type, listener, options);
87
+ }
88
+ /**
89
+ * @param listener Listener to attach to all of the `trigger` elements.
90
+ */
91
+ triggerListener(listener, type = this.event) {
92
+ for (const trigger of this.getTrigger()) {
93
+ trigger.addEventListener(type, listener);
94
+ }
95
+ }
96
+ /**
97
+ * Placeholder function is passed into `queueMicrotask` in `connectedCallback`. It is overridden in each component that needs to run `connectedCallback`.
98
+ *
99
+ * The reason for this is to make these elements work better with frameworks like Svelte. For SSR this isn't necessary, but when client side rendering, the HTML within the custom element isn't available before `connectedCallback` is called. By waiting until the next microtask, the HTML content is available---then for example, listeners can be attached to elements inside.
100
+ */
101
+ mount() { }
102
+ connectedCallback() {
103
+ queueMicrotask(() => this.mount());
104
+ }
105
+ disconnectedCallback() {
106
+ this.#listenerController.abort();
107
+ }
108
+ }
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export {};
@@ -1 +1,2 @@
1
- import{a as e}from"../chunk-6HYPZWQ4.js";import"../chunk-MXKU7AKV.js";customElements.define("drab-breakpoint",e);
1
+ import { Breakpoint } from "./index.js";
2
+ customElements.define("drab-breakpoint", Breakpoint);
@@ -1,5 +1,8 @@
1
- import { Base } from '../base/index.js';
2
-
1
+ import { Base } from "../base/index.js";
2
+ import type { Attributes } from "../types/index.js";
3
+ export type BreakpointAttributes = Attributes<Breakpoint> & Partial<{
4
+ [attr: `breakpoint-${string}`]: string;
5
+ }>;
3
6
  type Breakpoints = {
4
7
  name: string;
5
8
  width: number;
@@ -13,12 +16,11 @@ type Breakpoints = {
13
16
  * <drab-breakpoint breakpoint-name="400">
14
17
  * ```
15
18
  */
16
- declare class Breakpoint extends Base {
19
+ export declare class Breakpoint extends Base {
17
20
  breakpoints: Breakpoints;
18
21
  constructor();
19
22
  /** finds the current breakpoint */
20
23
  get breakpoint(): string;
21
24
  mount(): void;
22
25
  }
23
-
24
- export { Breakpoint, type Breakpoints };
26
+ export {};
@@ -1 +1,55 @@
1
- import{a}from"../chunk-6HYPZWQ4.js";import"../chunk-MXKU7AKV.js";export{a as Breakpoint};
1
+ import { Base } from "../base/index.js";
2
+ /**
3
+ * Displays the current breakpoint and `window.innerWidth`, based on the `breakpoints` provided. Defaults to [TailwindCSS breakpoint sizes](https://tailwindcss.com/docs/responsive-design).
4
+ *
5
+ * Provide alternate breakpoints by specifying `breakpoint` attributes:
6
+ *
7
+ * ```html
8
+ * <drab-breakpoint breakpoint-name="400">
9
+ * ```
10
+ */
11
+ export class Breakpoint extends Base {
12
+ breakpoints = [
13
+ { name: "sm", width: 640 },
14
+ { name: "md", width: 768 },
15
+ { name: "lg", width: 1024 },
16
+ { name: "xl", width: 1280 },
17
+ { name: "2xl", width: 1536 },
18
+ ];
19
+ constructor() {
20
+ super();
21
+ const custom = [];
22
+ for (const attributeName of this.getAttributeNames()) {
23
+ if (attributeName.startsWith("breakpoint-")) {
24
+ const [, ...name] = attributeName.split("-");
25
+ if (name) {
26
+ custom.push({
27
+ name: name.join("-"),
28
+ width: Number(this.getAttribute(attributeName)),
29
+ });
30
+ }
31
+ }
32
+ }
33
+ if (custom.length)
34
+ this.breakpoints = custom;
35
+ // highest to lowest
36
+ this.breakpoints.sort((a, b) => b.width - a.width);
37
+ }
38
+ /** finds the current breakpoint */
39
+ get breakpoint() {
40
+ for (let i = 0; i < this.breakpoints.length; i++) {
41
+ const breakpoint = this.breakpoints[i];
42
+ if (breakpoint) {
43
+ if (window.innerWidth > breakpoint.width) {
44
+ return breakpoint.name;
45
+ }
46
+ }
47
+ }
48
+ return "none";
49
+ }
50
+ mount() {
51
+ const render = () => (this.getContent().innerHTML = `${this.breakpoint}:${window.innerWidth}`);
52
+ render();
53
+ this.safeListener("resize", render, window);
54
+ }
55
+ }
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export {};
@@ -1 +1 @@
1
- "use strict";(()=>{var c=class extends HTMLElement{#t=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(t){this.setAttribute("event",t)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(t=HTMLElement){let e=this.querySelector(this.getAttribute("content")??"[data-content]");if(e instanceof t)return e;throw new Error("Content not found")}swapContent(t=!0,e=800){let n=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(n){let s=Array.from(this.getContent().childNodes);n instanceof HTMLTemplateElement?this.getContent().replaceChildren(n.content.cloneNode(!0)):this.getContent().replaceChildren(...n.childNodes),t&&setTimeout(()=>this.getContent().replaceChildren(...s),e)}}safeListener(t,e,n=document.body,s={}){s.signal=this.#t.signal,n.addEventListener(t,e,s)}triggerListener(t,e=this.event){for(let n of this.getTrigger())n.addEventListener(e,t)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#t.abort()}};var f=class extends c{constructor(){super()}get animationOptions(){let t={};for(let e of this.getAttributeNames())if(e.startsWith("animation-option-")){let n=this.getAttribute(e),[,,s]=e.split("-");n&&(s==="duration"||s==="delay"?t[s]=Number(n):s==="easing"&&(t[s]=n))}return t}async animateElement(t={element:this.getContent(),options:{}}){let{element:e=this.getContent(),options:n={}}=t,s=this.keyframes;if(s.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){n=Object.assign(this.animationOptions,n),n.duration||(n.duration=200),n.easing||(n.easing="ease-in-out");let r=s.at(0),i=s.at(-1);if(r&&i){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete i[l]}n.direction?.includes("reverse")&&([r,i]=[i,r]),Object.assign(e.style,r),await e.animate(s,n).finished,Object.assign(e.style,i)}}get keyframes(){let t=[];for(let e of this.getAttributeNames()){let n=this.getAttribute(e),[,,s,...r]=e.split("-");if(e.startsWith("animation-keyframe-")){let i=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(s&&i){s==="from"?s="0":s==="to"?s="1":s=String(parseInt(s)*.01);let o=Number(s),a=t.find(l=>l.offset===o);a?a[i]=n:t.push({[i]:n,offset:o})}}}return t.sort((e,n)=>Number(e.offset)-Number(n.offset)),t}};var m=class extends f{#t;constructor(){super()}set#e(t){this.getContent().style.left=`${t.x}px`,this.getContent().style.top=`${t.y}px`}async show(t){let e=window.scrollY,n=window.scrollX,s=t instanceof MouseEvent?t.clientX:t.touches[0]?.clientX??0,r=t instanceof MouseEvent?t.clientY:t.touches[0]?.clientY??0,i=s+n,o=r+e;this.getContent().style.position="absolute",this.getContent().style.display="block";let a=this.getContent().offsetWidth+24,l=this.getContent().offsetHeight+6,u=window.innerWidth,d=window.innerHeight;i+a>n+u&&(i=n+u-a),o+l>e+d&&(o=e+d-l),this.#e={x:i,y:o},await this.animateElement()}async hide(){this.getContent().style.display!=="none"&&(await this.animateElement({options:{direction:"reverse"}}),this.getContent().style.display="none")}mount(){this.triggerListener(e=>{e.preventDefault(),this.show(e)},"contextmenu"),this.safeListener("click",()=>this.hide()),this.triggerListener(e=>{this.#t=setTimeout(()=>{this.show(e)},800)},"touchstart");let t=()=>clearTimeout(this.#t);this.triggerListener(t,"touchend"),this.triggerListener(t,"touchcancel"),this.safeListener("keydown",e=>{e.key==="Escape"&&this.hide()})}};customElements.define("drab-contextmenu",m);})();
1
+ "use strict";(()=>{var c=class extends HTMLElement{#t=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(t){this.setAttribute("event",t)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(t=HTMLElement){let e=this.querySelector(this.getAttribute("content")??"[data-content]");if(e instanceof t)return e;throw new Error("Content not found")}swapContent(t=!0,e=800){let n=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(n){let i=Array.from(this.getContent().childNodes);n instanceof HTMLTemplateElement?this.getContent().replaceChildren(n.content.cloneNode(!0)):this.getContent().replaceChildren(...n.childNodes),t&&setTimeout(()=>this.getContent().replaceChildren(...i),e)}}safeListener(t,e,n=document.body,i={}){i.signal=this.#t.signal,n.addEventListener(t,e,i)}triggerListener(t,e=this.event){for(let n of this.getTrigger())n.addEventListener(e,t)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#t.abort()}};var m=class extends c{constructor(){super()}get animationOptions(){let t={};for(let e of this.getAttributeNames())if(e.startsWith("animation-option-")){let n=this.getAttribute(e),[,,i]=e.split("-");n&&(i==="duration"||i==="delay"?t[i]=Number(n):i==="easing"&&(t[i]=n))}return t}async animateElement(t={element:this.getContent(),options:{}}){let{element:e=this.getContent(),options:n={}}=t,i=this.keyframes;if(i.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){n=Object.assign(this.animationOptions,n),n.duration||(n.duration=200),n.easing||(n.easing="ease-in-out");let r=i.at(0),s=i.at(-1);if(r&&s){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete s[l]}n.direction?.includes("reverse")&&([r,s]=[s,r]),Object.assign(e.style,r),await e.animate(i,n).finished,Object.assign(e.style,s)}}get keyframes(){let t=[];for(let e of this.getAttributeNames()){let n=this.getAttribute(e),[,,i,...r]=e.split("-");if(e.startsWith("animation-keyframe-")){let s=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(i&&s){i==="from"?i="0":i==="to"?i="1":i=String(parseInt(i)*.01);let o=Number(i),a=t.find(l=>l.offset===o);a?a[s]=n:t.push({[s]:n,offset:o})}}}return t.sort((e,n)=>Number(e.offset)-Number(n.offset)),t}};var f=class extends m{#t;constructor(){super()}set#e(t){this.getContent().style.left=`${t.x}px`,this.getContent().style.top=`${t.y}px`}async show(t){let e=window.scrollY,n=window.scrollX,i=t instanceof MouseEvent?t.clientX:t.touches[0]?.clientX??0,r=t instanceof MouseEvent?t.clientY:t.touches[0]?.clientY??0,s=i+n,o=r+e;this.getContent().style.position="absolute",this.getContent().style.display="block";let a=this.getContent().offsetWidth+24,l=this.getContent().offsetHeight+6,u=window.innerWidth,d=window.innerHeight;s+a>n+u&&(s=n+u-a),o+l>e+d&&(o=e+d-l),this.#e={x:s,y:o},await this.animateElement()}async hide(){this.getContent().style.display!=="none"&&(await this.animateElement({options:{direction:"reverse"}}),this.getContent().style.display="none")}mount(){this.triggerListener(e=>{e.preventDefault(),this.show(e)},"contextmenu"),this.safeListener("click",()=>this.hide()),this.triggerListener(e=>{this.#t=setTimeout(()=>{this.show(e)},800)},"touchstart");let t=()=>clearTimeout(this.#t);this.triggerListener(t,"touchend"),this.triggerListener(t,"touchcancel"),this.safeListener("keydown",e=>{e.key==="Escape"&&this.hide()})}};customElements.define("drab-contextmenu",f);})();
@@ -1 +1,2 @@
1
- import{a as e}from"../chunk-57VEEUFG.js";import"../chunk-7KU2PRW5.js";import"../chunk-MXKU7AKV.js";customElements.define("drab-contextmenu",e);
1
+ import { ContextMenu } from "./index.js";
2
+ customElements.define("drab-contextmenu", ContextMenu);
@@ -1,15 +1,13 @@
1
- import { Animate } from '../animate/index.js';
2
- import '../base/index.js';
3
-
1
+ import { Animate, type AnimateAttributes } from "../animate/index.js";
2
+ import type { Attributes } from "../types/index.js";
3
+ export type ContextMenuAttributes = Attributes<ContextMenu> & AnimateAttributes;
4
4
  /**
5
5
  * Displays content when the `trigger` element is right clicked, or long pressed on mobile.
6
6
  */
7
- declare class ContextMenu extends Animate {
7
+ export declare class ContextMenu extends Animate {
8
8
  #private;
9
9
  constructor();
10
10
  show(e: MouseEvent | TouchEvent): Promise<void>;
11
11
  hide(): Promise<void>;
12
12
  mount(): void;
13
13
  }
14
-
15
- export { ContextMenu };
@@ -1 +1 @@
1
- "use strict";(()=>{var c=class extends HTMLElement{#t=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(t){this.setAttribute("event",t)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(t=HTMLElement){let e=this.querySelector(this.getAttribute("content")??"[data-content]");if(e instanceof t)return e;throw new Error("Content not found")}swapContent(t=!0,e=800){let n=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(n){let s=Array.from(this.getContent().childNodes);n instanceof HTMLTemplateElement?this.getContent().replaceChildren(n.content.cloneNode(!0)):this.getContent().replaceChildren(...n.childNodes),t&&setTimeout(()=>this.getContent().replaceChildren(...s),e)}}safeListener(t,e,n=document.body,s={}){s.signal=this.#t.signal,n.addEventListener(t,e,s)}triggerListener(t,e=this.event){for(let n of this.getTrigger())n.addEventListener(e,t)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#t.abort()}};var f=class extends c{constructor(){super()}get animationOptions(){let t={};for(let e of this.getAttributeNames())if(e.startsWith("animation-option-")){let n=this.getAttribute(e),[,,s]=e.split("-");n&&(s==="duration"||s==="delay"?t[s]=Number(n):s==="easing"&&(t[s]=n))}return t}async animateElement(t={element:this.getContent(),options:{}}){let{element:e=this.getContent(),options:n={}}=t,s=this.keyframes;if(s.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){n=Object.assign(this.animationOptions,n),n.duration||(n.duration=200),n.easing||(n.easing="ease-in-out");let r=s.at(0),i=s.at(-1);if(r&&i){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete i[l]}n.direction?.includes("reverse")&&([r,i]=[i,r]),Object.assign(e.style,r),await e.animate(s,n).finished,Object.assign(e.style,i)}}get keyframes(){let t=[];for(let e of this.getAttributeNames()){let n=this.getAttribute(e),[,,s,...r]=e.split("-");if(e.startsWith("animation-keyframe-")){let i=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(s&&i){s==="from"?s="0":s==="to"?s="1":s=String(parseInt(s)*.01);let o=Number(s),a=t.find(l=>l.offset===o);a?a[i]=n:t.push({[i]:n,offset:o})}}}return t.sort((e,n)=>Number(e.offset)-Number(n.offset)),t}};var d=class extends f{#t;constructor(){super()}set#e(t){this.getContent().style.left=`${t.x}px`,this.getContent().style.top=`${t.y}px`}async show(t){let e=window.scrollY,n=window.scrollX,s=t instanceof MouseEvent?t.clientX:t.touches[0]?.clientX??0,r=t instanceof MouseEvent?t.clientY:t.touches[0]?.clientY??0,i=s+n,o=r+e;this.getContent().style.position="absolute",this.getContent().style.display="block";let a=this.getContent().offsetWidth+24,l=this.getContent().offsetHeight+6,m=window.innerWidth,u=window.innerHeight;i+a>n+m&&(i=n+m-a),o+l>e+u&&(o=e+u-l),this.#e={x:i,y:o},await this.animateElement()}async hide(){this.getContent().style.display!=="none"&&(await this.animateElement({options:{direction:"reverse"}}),this.getContent().style.display="none")}mount(){this.triggerListener(e=>{e.preventDefault(),this.show(e)},"contextmenu"),this.safeListener("click",()=>this.hide()),this.triggerListener(e=>{this.#t=setTimeout(()=>{this.show(e)},800)},"touchstart");let t=()=>clearTimeout(this.#t);this.triggerListener(t,"touchend"),this.triggerListener(t,"touchcancel"),this.safeListener("keydown",e=>{e.key==="Escape"&&this.hide()})}};})();
1
+ "use strict";(()=>{var c=class extends HTMLElement{#t=new AbortController;constructor(){super()}get event(){return this.getAttribute("event")??"click"}set event(t){this.setAttribute("event",t)}getTrigger(){return this.querySelectorAll(this.getAttribute("trigger")??"[data-trigger]")}getContent(t=HTMLElement){let e=this.querySelector(this.getAttribute("content")??"[data-content]");if(e instanceof t)return e;throw new Error("Content not found")}swapContent(t=!0,e=800){let n=this.querySelector(this.getAttribute("swap")??"[data-swap]");if(n){let i=Array.from(this.getContent().childNodes);n instanceof HTMLTemplateElement?this.getContent().replaceChildren(n.content.cloneNode(!0)):this.getContent().replaceChildren(...n.childNodes),t&&setTimeout(()=>this.getContent().replaceChildren(...i),e)}}safeListener(t,e,n=document.body,i={}){i.signal=this.#t.signal,n.addEventListener(t,e,i)}triggerListener(t,e=this.event){for(let n of this.getTrigger())n.addEventListener(e,t)}mount(){}connectedCallback(){queueMicrotask(()=>this.mount())}disconnectedCallback(){this.#t.abort()}};var m=class extends c{constructor(){super()}get animationOptions(){let t={};for(let e of this.getAttributeNames())if(e.startsWith("animation-option-")){let n=this.getAttribute(e),[,,i]=e.split("-");n&&(i==="duration"||i==="delay"?t[i]=Number(n):i==="easing"&&(t[i]=n))}return t}async animateElement(t={element:this.getContent(),options:{}}){let{element:e=this.getContent(),options:n={}}=t,i=this.keyframes;if(i.length&&!window.matchMedia("(prefers-reduced-motion: reduce)").matches){n=Object.assign(this.animationOptions,n),n.duration||(n.duration=200),n.easing||(n.easing="ease-in-out");let r=i.at(0),s=i.at(-1);if(r&&s){let a=["composite","easing","offset"];for(let l of a)delete r[l],delete s[l]}n.direction?.includes("reverse")&&([r,s]=[s,r]),Object.assign(e.style,r),await e.animate(i,n).finished,Object.assign(e.style,s)}}get keyframes(){let t=[];for(let e of this.getAttributeNames()){let n=this.getAttribute(e),[,,i,...r]=e.split("-");if(e.startsWith("animation-keyframe-")){let s=r.map((o,a)=>a<1?o:o.at(0)?.toUpperCase()+o.slice(1)).join("");if(i&&s){i==="from"?i="0":i==="to"?i="1":i=String(parseInt(i)*.01);let o=Number(i),a=t.find(l=>l.offset===o);a?a[s]=n:t.push({[s]:n,offset:o})}}}return t.sort((e,n)=>Number(e.offset)-Number(n.offset)),t}};var d=class extends m{#t;constructor(){super()}set#e(t){this.getContent().style.left=`${t.x}px`,this.getContent().style.top=`${t.y}px`}async show(t){let e=window.scrollY,n=window.scrollX,i=t instanceof MouseEvent?t.clientX:t.touches[0]?.clientX??0,r=t instanceof MouseEvent?t.clientY:t.touches[0]?.clientY??0,s=i+n,o=r+e;this.getContent().style.position="absolute",this.getContent().style.display="block";let a=this.getContent().offsetWidth+24,l=this.getContent().offsetHeight+6,h=window.innerWidth,u=window.innerHeight;s+a>n+h&&(s=n+h-a),o+l>e+u&&(o=e+u-l),this.#e={x:s,y:o},await this.animateElement()}async hide(){this.getContent().style.display!=="none"&&(await this.animateElement({options:{direction:"reverse"}}),this.getContent().style.display="none")}mount(){this.triggerListener(e=>{e.preventDefault(),this.show(e)},"contextmenu"),this.safeListener("click",()=>this.hide()),this.triggerListener(e=>{this.#t=setTimeout(()=>{this.show(e)},800)},"touchstart");let t=()=>clearTimeout(this.#t);this.triggerListener(t,"touchend"),this.triggerListener(t,"touchcancel"),this.safeListener("keydown",e=>{e.key==="Escape"&&this.hide()})}};})();
@@ -1 +1,71 @@
1
- import{a}from"../chunk-57VEEUFG.js";import"../chunk-7KU2PRW5.js";import"../chunk-MXKU7AKV.js";export{a as ContextMenu};
1
+ import { Animate } from "../animate/index.js";
2
+ /**
3
+ * Displays content when the `trigger` element is right clicked, or long pressed on mobile.
4
+ */
5
+ export class ContextMenu extends Animate {
6
+ /** Tracks the long press duration on mobile. */
7
+ #touchTimer;
8
+ constructor() {
9
+ super();
10
+ }
11
+ /** Sets the context menu's `style.left` and `style.top` position. */
12
+ set #coordinates(value) {
13
+ this.getContent().style.left = `${value.x}px`;
14
+ this.getContent().style.top = `${value.y}px`;
15
+ }
16
+ async show(e) {
17
+ // find coordinates of the click
18
+ const scrollY = window.scrollY;
19
+ const scrollX = window.scrollX;
20
+ const clientX = e instanceof MouseEvent ? e.clientX : e.touches[0]?.clientX ?? 0;
21
+ const clientY = e instanceof MouseEvent ? e.clientY : e.touches[0]?.clientY ?? 0;
22
+ let x = clientX + scrollX;
23
+ let y = clientY + scrollY;
24
+ this.getContent().style.position = "absolute";
25
+ this.getContent().style.display = "block";
26
+ const offsetWidth = this.getContent().offsetWidth + 24;
27
+ const offsetHeight = this.getContent().offsetHeight + 6;
28
+ const innerWidth = window.innerWidth;
29
+ const innerHeight = window.innerHeight;
30
+ // ensure menu is within view
31
+ if (x + offsetWidth > scrollX + innerWidth) {
32
+ x = scrollX + innerWidth - offsetWidth;
33
+ }
34
+ if (y + offsetHeight > scrollY + innerHeight) {
35
+ y = scrollY + innerHeight - offsetHeight;
36
+ }
37
+ this.#coordinates = { x, y };
38
+ await this.animateElement();
39
+ }
40
+ async hide() {
41
+ if (this.getContent().style.display !== "none") {
42
+ await this.animateElement({
43
+ options: { direction: "reverse" },
44
+ });
45
+ this.getContent().style.display = "none";
46
+ }
47
+ }
48
+ mount() {
49
+ // mouse
50
+ this.triggerListener((e) => {
51
+ e.preventDefault();
52
+ this.show(e);
53
+ }, "contextmenu");
54
+ this.safeListener("click", () => this.hide());
55
+ // touch
56
+ this.triggerListener((e) => {
57
+ this.#touchTimer = setTimeout(() => {
58
+ this.show(e);
59
+ }, 800);
60
+ }, "touchstart");
61
+ const resetTimer = () => clearTimeout(this.#touchTimer);
62
+ this.triggerListener(resetTimer, "touchend");
63
+ this.triggerListener(resetTimer, "touchcancel");
64
+ // keyboard
65
+ this.safeListener("keydown", (e) => {
66
+ if (e.key === "Escape") {
67
+ this.hide();
68
+ }
69
+ });
70
+ }
71
+ }
package/copy/define.d.ts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export {};