@newthink/ui 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/headless/accordion.d.ts +4 -4
  2. package/dist/headless/accordion.d.ts.map +1 -1
  3. package/dist/headless/accordion.js +2 -2
  4. package/dist/headless/accordion.js.map +1 -1
  5. package/dist/headless/dragScroll.d.ts +3 -0
  6. package/dist/headless/dragScroll.d.ts.map +1 -0
  7. package/dist/headless/dragScroll.js +62 -0
  8. package/dist/headless/dragScroll.js.map +1 -0
  9. package/dist/headless/headless.d.ts +2 -3
  10. package/dist/headless/headless.d.ts.map +1 -1
  11. package/dist/headless/headless.js.map +1 -1
  12. package/dist/headless/index.d.ts +8 -0
  13. package/dist/headless/index.d.ts.map +1 -0
  14. package/dist/headless/index.js +7 -0
  15. package/dist/headless/index.js.map +1 -0
  16. package/dist/headless/panel.d.ts +1 -1
  17. package/dist/headless/panel.d.ts.map +1 -1
  18. package/dist/headless/swipeDetect.d.ts +3 -0
  19. package/dist/headless/swipeDetect.d.ts.map +1 -0
  20. package/dist/headless/swipeDetect.js +76 -0
  21. package/dist/headless/swipeDetect.js.map +1 -0
  22. package/dist/headless/tabs.d.ts +1 -1
  23. package/dist/headless/tabs.d.ts.map +1 -1
  24. package/dist/index.d.ts +6 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +5 -4
  27. package/dist/index.js.map +1 -1
  28. package/dist/magics/index.d.ts +2 -0
  29. package/dist/magics/index.d.ts.map +1 -0
  30. package/dist/magics/index.js +2 -0
  31. package/dist/magics/index.js.map +1 -0
  32. package/dist/magics/screen.d.ts +3 -0
  33. package/dist/magics/screen.d.ts.map +1 -0
  34. package/dist/magics/screen.js +39 -0
  35. package/dist/magics/screen.js.map +1 -0
  36. package/package.json +27 -16
  37. package/src/headless/accordion.ts +10 -14
  38. package/src/headless/dragScroll.ts +86 -0
  39. package/src/headless/headless.ts +9 -9
  40. package/src/headless/index.ts +7 -0
  41. package/src/headless/swipeDetect.ts +96 -0
  42. package/src/headless/tabs.ts +1 -1
  43. package/src/index.ts +26 -6
  44. package/src/magics/index.ts +1 -0
  45. package/src/magics/screen.ts +49 -0
  46. package/src/types.d.ts +3 -0
@@ -1,6 +1,6 @@
1
- import { HeadlessComponent } from './headless';
2
- export declare const accordionGroup: HeadlessComponent;
3
- export declare const accordion: HeadlessComponent;
4
- declare const accordions: HeadlessComponent;
1
+ import { AlpinePlugin } from '../types';
2
+ export declare const accordionGroup: AlpinePlugin;
3
+ export declare const accordion: AlpinePlugin;
4
+ export declare const accordions: AlpinePlugin;
5
5
  export default accordions;
6
6
  //# sourceMappingURL=accordion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/headless/accordion.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EAIlB,MAAM,YAAY,CAAC;AAgDpB,eAAO,MAAM,cAAc,EAAE,iBAC8B,CAAC;AAqD5D,eAAO,MAAM,SAAS,mBAIrB,CAAC;AAEF,QAAA,MAAM,UAAU,EAAE,iBAGjB,CAAC;AACF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"accordion.d.ts","sourceRoot":"","sources":["../../src/headless/accordion.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAiDxC,eAAO,MAAM,cAAc,EAAE,YAC8B,CAAC;AAqD5D,eAAO,MAAM,SAAS,cAIrB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,YAGxB,CAAC;AACF,eAAe,UAAU,CAAC"}
@@ -1,4 +1,4 @@
1
- import { headless, } from './headless';
1
+ import { headless } from './headless';
2
2
  const groupMap = new WeakMap();
3
3
  const getGroup = (el, Alpine) => {
4
4
  const root = Alpine.findClosest(el, groupMap.has.bind(groupMap));
@@ -64,7 +64,7 @@ const accordionHandlers = {
64
64
  container: handleAccordionContainer,
65
65
  };
66
66
  export const accordion = headless('accordion', handleAccordionRoot, accordionHandlers);
67
- const accordions = (Alpine) => {
67
+ export const accordions = (Alpine) => {
68
68
  accordionGroup(Alpine);
69
69
  accordion(Alpine);
70
70
  };
@@ -1 +1 @@
1
- {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../src/headless/accordion.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"accordion.js","sourceRoot":"","sources":["../../src/headless/accordion.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { AlpinePlugin } from '../types';
2
+ export declare const dragScroll: AlpinePlugin;
3
+ //# sourceMappingURL=dragScroll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dragScroll.d.ts","sourceRoot":"","sources":["../../src/headless/dragScroll.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAgBxC,eAAO,MAAM,UAAU,EAAE,YAcrB,CAAC"}
@@ -0,0 +1,62 @@
1
+ const resizeCenterer = new ResizeObserver((entries) => {
2
+ for (const entry of entries) {
3
+ const el = entry.target;
4
+ if (!(el instanceof HTMLElement))
5
+ continue;
6
+ center(el);
7
+ }
8
+ });
9
+ const center = async (el) => {
10
+ await nextTick();
11
+ el.scrollLeft = (el.scrollWidth - el.clientWidth) / 2;
12
+ el.scrollTop = (el.scrollHeight - el.clientHeight) / 2;
13
+ };
14
+ export const dragScroll = (Alpine) => Alpine.directive('dragscroll', (el, { modifiers }, { cleanup }) => {
15
+ const autoCenter = modifiers.includes('center');
16
+ registerDragScroll(el);
17
+ if (autoCenter)
18
+ Array.prototype.forEach.call(el.children, (el) => resizeCenterer.observe(el));
19
+ el.classList.add('overscroll-contain', 'cursor-grab');
20
+ cleanup(() => Array.prototype.forEach.call(el.children, (el) => resizeCenterer.unobserve(el)));
21
+ });
22
+ const preventStop = (e) => {
23
+ e.preventDefault();
24
+ e.stopPropagation();
25
+ };
26
+ const cancelEvents = ['pointerup', 'mouseup', 'touchend'];
27
+ const registerDragScroll = (el) => {
28
+ const moveHandler = (e) => {
29
+ preventStop(e);
30
+ el.scrollLeft -= e.movementX;
31
+ el.scrollTop -= e.movementY;
32
+ };
33
+ const upHandler = async (e) => {
34
+ preventStop(e);
35
+ document.removeEventListener('pointermove', moveHandler, true);
36
+ document.body.classList.remove('!cursor-grabbing', '[&>*]:pointer-events-none');
37
+ el.classList.add('cursor-grab');
38
+ await nextTick();
39
+ document.removeEventListener('click', preventStop, true);
40
+ cancelEvents.map((event) => document.removeEventListener(event, upHandler, {
41
+ capture: true,
42
+ }));
43
+ };
44
+ const downHandler = (e) => {
45
+ if (isTouch(e))
46
+ return; // skip touch inputs (allow native scrolling)
47
+ if (e.button === 2)
48
+ return; // skip right-click
49
+ preventStop(e);
50
+ el.classList.remove('cursor-grab');
51
+ document.body.classList.add('!cursor-grabbing', '[&>*]:pointer-events-none');
52
+ document.addEventListener('pointermove', moveHandler, { capture: true });
53
+ cancelEvents.map((event) => document.addEventListener(event, upHandler, {
54
+ capture: true,
55
+ }));
56
+ document.addEventListener('click', preventStop, { capture: true });
57
+ };
58
+ el.addEventListener('pointerdown', downHandler);
59
+ };
60
+ const nextTick = () => new Promise((res) => queueMicrotask(() => setTimeout(res, 0)));
61
+ const isTouch = (e) => e instanceof TouchEvent;
62
+ //# sourceMappingURL=dragScroll.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dragScroll.js","sourceRoot":"","sources":["../../src/headless/dragScroll.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,CAAC,OAAO,EAAE,EAAE;IACpD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE;QAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,CAAC,EAAE,YAAY,WAAW,CAAC;YAAE,SAAS;QAC3C,MAAM,CAAC,EAAE,CAAC,CAAC;KACZ;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,KAAK,EAAE,EAAe,EAAE,EAAE;IACvC,MAAM,QAAQ,EAAE,CAAC;IACjB,EAAE,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC,WAAW,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtD,EAAE,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC,YAAY,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAiB,CAAC,MAAM,EAAE,EAAE,CACjD,MAAM,CAAC,SAAS,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IAChE,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChD,kBAAkB,CAAC,EAAE,CAAC,CAAC;IACvB,IAAI,UAAU;QACZ,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAW,EAAE,EAAE,CACxD,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,CAC3B,CAAC;IACJ,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,oBAAoB,EAAE,aAAa,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,EAAE,CACX,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,EAAW,EAAE,EAAE,CACxD,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC,CAC7B,CACF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEL,MAAM,WAAW,GAAG,CAAC,CAAQ,EAAE,EAAE;IAC/B,CAAC,CAAC,cAAc,EAAE,CAAC;IACnB,CAAC,CAAC,eAAe,EAAE,CAAC;AACtB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,WAAW,EAAE,SAAS,EAAE,UAAU,CAAU,CAAC;AAEnE,MAAM,kBAAkB,GAAG,CAAC,EAAe,EAAE,EAAE;IAC7C,MAAM,WAAW,GAAG,CAAC,CAAe,EAAE,EAAE;QACtC,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,EAAE,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC;QAC7B,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,SAAS,CAAC;IAC9B,CAAC,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,EAAE,CAAyC,EAAE,EAAE;QACpE,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,QAAQ,CAAC,mBAAmB,CAAC,aAAa,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QAC/D,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAC5B,kBAAkB,EAClB,2BAA2B,CAC5B,CAAC;QACF,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAChC,MAAM,QAAQ,EAAE,CAAC;QACjB,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC;QACzD,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACzB,QAAQ,CAAC,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE;YAC7C,OAAO,EAAE,IAAI;SACd,CAAC,CACH,CAAC;IACJ,CAAC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,CAAyC,EAAE,EAAE;QAChE,IAAI,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,6CAA6C;QACrE,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,CAAC,mBAAmB;QAC/C,WAAW,CAAC,CAAC,CAAC,CAAC;QACf,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CACzB,kBAAkB,EAClB,2BAA2B,CAC5B,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACzE,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACzB,QAAQ,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE;YAC1C,OAAO,EAAE,IAAI;SACd,CAAC,CACH,CAAC;QACF,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IACF,EAAE,CAAC,gBAAgB,CAAC,aAAa,EAAE,WAAW,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,QAAQ,GAAG,GAAG,EAAE,CACpB,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAEjE,MAAM,OAAO,GAAG,CAAC,CAAyC,EAAmB,EAAE,CAC7E,CAAC,YAAY,UAAU,CAAC"}
@@ -1,9 +1,8 @@
1
- import type { Alpine } from 'alpinejs';
2
1
  import type { DirectiveData, ElementWithXAttributes, Utilities } from 'alpinejs/dist/types';
3
- export declare const headless: <T extends Record<string, unknown>>(name: string, rootHandler: RootHandler<T>, handlers?: HeadlessHandlers<T> | undefined) => HeadlessComponent;
2
+ import { AlpinePlugin } from '../types';
3
+ export declare const headless: <T extends Record<string, unknown>>(name: string, rootHandler: RootHandler<T>, handlers?: HeadlessHandlers<T> | undefined) => AlpinePlugin;
4
4
  type HeadlessHandlers<T extends Record<string, unknown>> = Record<string, HeadlessHandler<T>>;
5
5
  export type RootHandler<T> = (el: ElementWithXAttributes, directive: DirectiveData, utilities: Utilities) => T;
6
6
  export type HeadlessHandler<T> = (state: T, el: ElementWithXAttributes, directive: DirectiveData, utilities: Utilities) => void;
7
- export type HeadlessComponent = (Alpine: Alpine) => void;
8
7
  export {};
9
8
  //# sourceMappingURL=headless.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../src/headless/headless.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,SAAS,EACV,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,QAAQ,4CACb,MAAM,8EAGX,iBA2BF,CAAC;AAeF,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAC/D,MAAM,EACN,eAAe,CAAC,CAAC,CAAC,CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAC3B,EAAE,EAAE,sBAAsB,EAC1B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,SAAS,KACjB,CAAC,CAAC;AAEP,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAC/B,KAAK,EAAE,CAAC,EACR,EAAE,EAAE,sBAAsB,EAC1B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,SAAS,KACjB,IAAI,CAAC;AAEV,MAAM,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC"}
1
+ {"version":3,"file":"headless.d.ts","sourceRoot":"","sources":["../../src/headless/headless.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,SAAS,EACV,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,eAAO,MAAM,QAAQ,4CACb,MAAM,8EAGX,YA2BF,CAAC;AAeF,KAAK,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAC/D,MAAM,EACN,eAAe,CAAC,CAAC,CAAC,CACnB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,CAC3B,EAAE,EAAE,sBAAsB,EAC1B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,SAAS,KACjB,CAAC,CAAC;AAEP,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI,CAC/B,KAAK,EAAE,CAAC,EACR,EAAE,EAAE,sBAAsB,EAC1B,SAAS,EAAE,aAAa,EACxB,SAAS,EAAE,SAAS,KACjB,IAAI,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/headless/headless.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,WAA2B,EAC3B,QAA8B,EACX,EAAE;IACrB,MAAM,WAAW,GAAG,IAAI,OAAO,EAA6B,CAAC;IAC7D,OAAO,CAAC,MAAc,EAAE,EAAE;QACxB,MAAM,yBAAyB,GAAG,CAChC,EAA0B,EAChB,EAAE;YACZ,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,IAAI;gBACP,OAAO,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,YAAY,EAAE,EAAE,CAAC,CAAC;YACxE,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAC;QAE1D,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;YAC9C,IAAI,CAAC,SAAS,CAAC,KAAK;gBAClB,OAAO,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YAChE,MAAM,aAAa,GAAG,yBAAyB,CAAC,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,aAAa;gBAAE,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClD,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAC7C,aAAa,EACb,EAAE,EACF,SAAS,EACT,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,QAAQ,GACZ,CAAC,IAAY,EAAE,EAAE,CACjB,CAAC,CAAU,EAAE,EAA0B,EAAE,SAAwB,EAAE,EAAE;IACnE,OAAO,CAAC,KAAK,CACX,UAAU,IAAI,2BAA2B,EACzC,EAAE,EACF,SAAS,CAAC,QAAQ,CACnB,CAAC;AACJ,CAAC,CAAC;AAEJ,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAA0B,EAAE,EAAE,CAChE,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,YAAY,EAAE,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/headless/headless.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,QAAQ,GAAG,CACtB,IAAY,EACZ,WAA2B,EAC3B,QAA8B,EAChB,EAAE;IAChB,MAAM,WAAW,GAAG,IAAI,OAAO,EAA6B,CAAC;IAC7D,OAAO,CAAC,MAAc,EAAE,EAAE;QACxB,MAAM,yBAAyB,GAAG,CAChC,EAA0B,EAChB,EAAE;YACZ,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YACvE,IAAI,CAAC,IAAI;gBACP,OAAO,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,YAAY,EAAE,EAAE,CAAC,CAAC;YACxE,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC,CAAC;QAE1D,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE;YAC9C,IAAI,CAAC,SAAS,CAAC,KAAK;gBAClB,OAAO,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;YAChE,MAAM,aAAa,GAAG,yBAAyB,CAAC,EAAE,CAAC,CAAC;YACpD,IAAI,CAAC,aAAa;gBAAE,OAAO,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAClD,CAAC,QAAQ,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAC7C,aAAa,EACb,EAAE,EACF,SAAS,EACT,KAAK,CACN,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,QAAQ,GACZ,CAAC,IAAY,EAAE,EAAE,CACjB,CAAC,CAAU,EAAE,EAA0B,EAAE,SAAwB,EAAE,EAAE;IACnE,OAAO,CAAC,KAAK,CACX,UAAU,IAAI,2BAA2B,EACzC,EAAE,EACF,SAAS,CAAC,QAAQ,CACnB,CAAC;AACJ,CAAC,CAAC;AAEJ,MAAM,YAAY,GAAG,CAAC,IAAY,EAAE,EAA0B,EAAE,EAAE,CAChE,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,YAAY,EAAE,EAAE,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { accordionGroup, accordion, accordions } from './accordion';
2
+ export { dragScroll } from './dragScroll';
3
+ export { headless } from './headless';
4
+ export { panel } from './panel';
5
+ export { tabs } from './tabs';
6
+ export type { RootHandler, HeadlessHandler } from './headless';
7
+ export { swipeDetect } from './swipeDetect';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/headless/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { accordionGroup, accordion, accordions } from './accordion';
2
+ export { dragScroll } from './dragScroll';
3
+ export { headless } from './headless';
4
+ export { panel } from './panel';
5
+ export { tabs } from './tabs';
6
+ export { swipeDetect } from './swipeDetect';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/headless/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const panel: import("./headless").HeadlessComponent;
1
+ export declare const panel: import("..").AlpinePlugin;
2
2
  //# sourceMappingURL=panel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/headless/panel.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,KAAK,wCAYhB,CAAC"}
1
+ {"version":3,"file":"panel.d.ts","sourceRoot":"","sources":["../../src/headless/panel.ts"],"names":[],"mappings":"AA8BA,eAAO,MAAM,KAAK,2BAYhB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { AlpinePlugin } from '../types';
2
+ export declare const swipeDetect: AlpinePlugin;
3
+ //# sourceMappingURL=swipeDetect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipeDetect.d.ts","sourceRoot":"","sources":["../../src/headless/swipeDetect.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAsB7C,eAAO,MAAM,WAAW,EAAE,YAsBtB,CAAC"}
@@ -0,0 +1,76 @@
1
+ var SwipeDirection;
2
+ (function (SwipeDirection) {
3
+ SwipeDirection[SwipeDirection["None"] = 0] = "None";
4
+ SwipeDirection[SwipeDirection["Left"] = 1] = "Left";
5
+ SwipeDirection[SwipeDirection["Right"] = 2] = "Right";
6
+ SwipeDirection[SwipeDirection["Up"] = 4] = "Up";
7
+ SwipeDirection[SwipeDirection["Down"] = 8] = "Down";
8
+ })(SwipeDirection || (SwipeDirection = {}));
9
+ const swipableMap = new WeakMap();
10
+ const hasSwipe = swipableMap.has.bind(swipableMap);
11
+ export const swipeDetect = (Alpine) => Alpine.directive('swipe', (el, _, { cleanup }) => {
12
+ const swipeData = {
13
+ dispatch: (dir) => {
14
+ const direction = Object.entries(SwipeDirection)
15
+ .filter(([, v]) => typeof v === 'number' && v && (dir & v) === v)
16
+ .map(([k]) => k.toLowerCase());
17
+ el.dispatchEvent(new CustomEvent('swipe', {
18
+ detail: direction.join('-'),
19
+ }));
20
+ el.dispatchEvent(new CustomEvent(`swipe${direction.join('')}`, {
21
+ detail: direction.join('-'),
22
+ }));
23
+ },
24
+ };
25
+ swipableMap.set(el, swipeData);
26
+ el.addEventListener('touchstart', touchDown);
27
+ cleanup(() => el.removeEventListener('touchstart', touchDown));
28
+ });
29
+ const touchDown = (ev) => {
30
+ const swipeData = swipableMap.get(ev.currentTarget);
31
+ if (!swipeData)
32
+ return;
33
+ const touch = ev.touches[0];
34
+ const { clientX, clientY } = touch;
35
+ swipeData.start ??= { x: clientX, y: clientY };
36
+ document.addEventListener('touchend', touchUp, { once: true });
37
+ };
38
+ const touchUp = (ev) => {
39
+ const target = ev.target;
40
+ if (!target)
41
+ return;
42
+ const swipeData = swipableMap.get(findNearest(target, hasSwipe));
43
+ if (!swipeData?.start)
44
+ return;
45
+ const touch = ev.changedTouches[0];
46
+ const { clientX, clientY } = touch;
47
+ const direction = getDirection(swipeData.start, { x: clientX, y: clientY });
48
+ if (direction === SwipeDirection.None)
49
+ return;
50
+ swipeData.dispatch(direction);
51
+ };
52
+ const findNearest = (el, predicate) => {
53
+ if (predicate(el))
54
+ return el;
55
+ if (!el.parentElement)
56
+ return null;
57
+ return findNearest(el.parentElement, predicate);
58
+ };
59
+ const getDirection = (start, end) => {
60
+ const vector = [end.x - start.x, end.y - start.y];
61
+ if (vector.every((v) => Math.abs(v) < 25))
62
+ return SwipeDirection.None;
63
+ // normalize vector
64
+ const magnitude = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
65
+ const [x, y] = vector.map((v) => v / magnitude);
66
+ const direction = getDirectionSign(x) | (getDirectionSign(y) << 2);
67
+ return direction;
68
+ };
69
+ const getDirectionSign = (offset) => {
70
+ if (offset > 0.5)
71
+ return 2;
72
+ if (offset < -0.5)
73
+ return 1;
74
+ return 0;
75
+ };
76
+ //# sourceMappingURL=swipeDetect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipeDetect.js","sourceRoot":"","sources":["../../src/headless/swipeDetect.ts"],"names":[],"mappings":"AAcA,IAAK,cAMJ;AAND,WAAK,cAAc;IACjB,mDAAQ,CAAA;IACR,mDAAa,CAAA;IACb,qDAAc,CAAA;IACd,+CAAW,CAAA;IACX,mDAAa,CAAA;AACf,CAAC,EANI,cAAc,KAAd,cAAc,QAMlB;AAED,MAAM,WAAW,GAAG,IAAI,OAAO,EAAwC,CAAC;AACxE,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AACnD,MAAM,CAAC,MAAM,WAAW,GAAiB,CAAC,MAAM,EAAE,EAAE,CAClD,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IAC/C,MAAM,SAAS,GAAiB;QAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE;YAChB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC;iBAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;iBAChE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YACjC,EAAE,CAAC,aAAa,CACd,IAAI,WAAW,CAAC,OAAO,EAAE;gBACvB,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;aAC5B,CAAC,CACH,CAAC;YACF,EAAE,CAAC,aAAa,CACd,IAAI,WAAW,CAAC,QAAQ,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;gBAC5C,MAAM,EAAE,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;aAC5B,CAAC,CACH,CAAC;QACJ,CAAC;KACF,CAAC;IACF,WAAW,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;IAC/B,EAAE,CAAC,gBAAgB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,mBAAmB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC,CAAC;AACjE,CAAC,CAAC,CAAC;AAEL,MAAM,SAAS,GAAG,CAAC,EAAc,EAAE,EAAE;IACnC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,aAAuC,CAAC,CAAC;IAC9E,IAAI,CAAC,SAAS;QAAE,OAAO;IACvB,MAAM,KAAK,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IACnC,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,EAAc,EAAE,EAAE;IACjC,MAAM,MAAM,GAAG,EAAE,CAAC,MAAgC,CAAC;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAC/B,WAAW,CAAC,MAAM,EAAE,QAAQ,CAA2B,CACxD,CAAC;IACF,IAAI,CAAC,SAAS,EAAE,KAAK;QAAE,OAAO;IAC9B,MAAM,KAAK,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IACnC,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IAC5E,IAAI,SAAS,KAAK,cAAc,CAAC,IAAI;QAAE,OAAO;IAC9C,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;AAChC,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAClB,EAAK,EACL,SAA6B,EACT,EAAE;IACtB,IAAI,SAAS,CAAC,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,WAAW,CAAC,EAAE,CAAC,aAAkB,EAAE,SAAS,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAE,GAAkB,EAAE,EAAE;IAChE,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAAE,OAAO,cAAc,CAAC,IAAI,CAAC;IACtE,mBAAmB;IACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAEhD,MAAM,SAAS,GAAG,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnE,OAAO,SAAS,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,MAAc,EAAE,EAAE;IAC1C,IAAI,MAAM,GAAG,GAAG;QAAE,OAAO,CAAC,CAAC;IAC3B,IAAI,MAAM,GAAG,CAAC,GAAG;QAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,CAAC;AACX,CAAC,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const tabs: import("./headless").HeadlessComponent;
1
+ export declare const tabs: import("..").AlpinePlugin;
2
2
  //# sourceMappingURL=tabs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/headless/tabs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,wCAkDhB,CAAC"}
1
+ {"version":3,"file":"tabs.d.ts","sourceRoot":"","sources":["../../src/headless/tabs.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,IAAI,2BAkDhB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { HeadlessComponent } from './headless/headless';
2
- export declare const UI: HeadlessComponent;
1
+ import { accordion, accordionGroup, accordions, dragScroll, panel, tabs } from './headless';
2
+ import { screen } from './magics';
3
+ import type { AlpinePlugin } from './types';
4
+ export declare const NTMagics: AlpinePlugin;
5
+ export declare const UI: AlpinePlugin;
3
6
  export default UI;
7
+ export { accordion, accordionGroup, accordions, dragScroll, panel, tabs, screen, AlpinePlugin, };
4
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,eAAO,MAAM,EAAE,EAAE,iBACyB,CAAC;AAE3C,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EAEL,IAAI,EACL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,eAAO,MAAM,QAAQ,EAAE,YAAkD,CAAC;AAE1E,eAAO,MAAM,EAAE,EAAE,YAC4D,CAAC;AAE9E,eAAe,EAAE,CAAC;AAElB,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,IAAI,EACJ,MAAM,EACN,YAAY,GACb,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
- import accordions from './headless/accordion';
2
- import { panel } from './headless/panel';
3
- import { tabs } from './headless/tabs';
4
- export const UI = (Alpine) => Alpine.plugin([accordions, panel, tabs]);
1
+ import { accordion, accordionGroup, accordions, dragScroll, panel, swipeDetect, tabs, } from './headless';
2
+ import { screen } from './magics';
3
+ export const NTMagics = (Alpine) => Alpine.plugin([screen]);
4
+ export const UI = (Alpine) => Alpine.plugin([accordions, dragScroll, panel, swipeDetect, tabs, NTMagics]);
5
5
  export default UI;
6
+ export { accordion, accordionGroup, accordions, dragScroll, panel, tabs, screen, };
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,sBAAsB,CAAC;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC,MAAM,CAAC,MAAM,EAAE,GAAsB,CAAC,MAAM,EAAE,EAAE,CAC9C,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;AAE3C,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,WAAW,EACX,IAAI,GACL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,MAAM,CAAC,MAAM,QAAQ,GAAiB,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE1E,MAAM,CAAC,MAAM,EAAE,GAAiB,CAAC,MAAM,EAAE,EAAE,CACzC,MAAM,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;AAE9E,eAAe,EAAE,CAAC;AAElB,OAAO,EACL,SAAS,EACT,cAAc,EACd,UAAU,EACV,UAAU,EACV,KAAK,EACL,IAAI,EACJ,MAAM,GAEP,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { screen } from './screen';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/magics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { screen } from './screen';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/magics/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { AlpinePlugin } from '../types';
2
+ export declare const screen: AlpinePlugin;
3
+ //# sourceMappingURL=screen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.d.ts","sourceRoot":"","sources":["../../src/magics/screen.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,eAAO,MAAM,MAAM,EAAE,YAepB,CAAC"}
@@ -0,0 +1,39 @@
1
+ export const screen = (Alpine) => {
2
+ Alpine.magic('screen', () => (breakpoint) => {
3
+ const breakSize = typeof breakpoint === 'number'
4
+ ? breakpoint
5
+ : breakpoints[breakpoint] ?? Number(breakpoint);
6
+ if (!breakSize) {
7
+ console.error(`Invalid breakpoint: $screen(${JSON.stringify(breakpoint)})`);
8
+ return false;
9
+ }
10
+ const signal = getMediaSignal(breakSize, Alpine);
11
+ return signal.value;
12
+ });
13
+ };
14
+ // Configuration
15
+ const defaultBreakpoints = {
16
+ xs: 320,
17
+ sm: 640,
18
+ md: 768,
19
+ lg: 1024,
20
+ xl: 1280,
21
+ '2xl': 1536,
22
+ };
23
+ const breakpoints = defaultBreakpoints;
24
+ const mediaSignals = {};
25
+ const getMediaSignal = (breakpoint, Alpine) => {
26
+ return mediaSignals[breakpoint] ?? createMediaSignal(breakpoint, Alpine);
27
+ };
28
+ const createMediaSignal = (breakpoint, Alpine) => {
29
+ const mediaMatch = window.matchMedia(`(min-width: ${breakpoint}px)`);
30
+ const signal = Alpine.reactive({
31
+ value: mediaMatch.matches,
32
+ });
33
+ mediaSignals[breakpoint] = signal;
34
+ mediaMatch.addEventListener('change', (e) => {
35
+ signal.value = e.matches;
36
+ });
37
+ return signal;
38
+ };
39
+ //# sourceMappingURL=screen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen.js","sourceRoot":"","sources":["../../src/magics/screen.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,MAAM,MAAM,GAAiB,CAAC,MAAM,EAAE,EAAE;IAC7C,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,UAA2B,EAAE,EAAE;QAC3D,MAAM,SAAS,GACb,OAAO,UAAU,KAAK,QAAQ;YAC5B,CAAC,CAAC,UAAU;YACZ,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,SAAS,EAAE;YACd,OAAO,CAAC,KAAK,CACX,+BAA+B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAC7D,CAAC;YACF,OAAO,KAAK,CAAC;SACd;QACD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QACjD,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAEF,gBAAgB;AAChB,MAAM,kBAAkB,GAA2B;IACjD,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,KAAK,EAAE,IAAI;CACZ,CAAC;AAEF,MAAM,WAAW,GAAG,kBAAkB,CAAC;AACvC,MAAM,YAAY,GAAuC,EAAE,CAAC;AAE5D,MAAM,cAAc,GAAG,CAAC,UAAkB,EAAE,MAAc,EAAE,EAAE;IAC5D,OAAO,YAAY,CAAC,UAAU,CAAC,IAAI,iBAAiB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,UAAkB,EAAE,MAAc,EAAE,EAAE;IAC/D,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,eAAe,UAAU,KAAK,CAAC,CAAC;IACrE,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC;QAC7B,KAAK,EAAE,UAAU,CAAC,OAAO;KAC1B,CAAC,CAAC;IACH,YAAY,CAAC,UAAU,CAAC,GAAG,MAAM,CAAC;IAClC,UAAU,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;QAC1C,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,20 @@
1
1
  {
2
2
  "name": "@newthink/ui",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Simple Alpine Headless UI Components",
5
+ "author": {
6
+ "name": "Eric Kwoka",
7
+ "email": "ninjatheory@gmail.com",
8
+ "url": "https://thekwoka.net/"
9
+ },
10
+ "repository": "github:ekwoka/newthink-ui",
11
+ "keywords": [
12
+ "alpinejs",
13
+ "headless",
14
+ "components",
15
+ "plugins"
16
+ ],
17
+ "license": "ISC",
5
18
  "main": "dist/index.js",
6
19
  "module": "dist/index.js",
7
20
  "types": "dist/index.d.ts",
@@ -17,27 +30,25 @@
17
30
  "src"
18
31
  ],
19
32
  "type": "module",
20
- "keywords": [],
21
- "author": "",
22
- "license": "ISC",
33
+ "sideeffects": false,
23
34
  "devDependencies": {
24
- "@trivago/prettier-plugin-sort-imports": "4.1.1",
25
- "@types/node": "20.3.1",
26
- "@typescript-eslint/eslint-plugin": "5.59.11",
27
- "@typescript-eslint/parser": "5.59.11",
35
+ "@trivago/prettier-plugin-sort-imports": "4.2.0",
36
+ "@types/node": "20.5.0",
37
+ "@typescript-eslint/eslint-plugin": "6.3.0",
38
+ "@typescript-eslint/parser": "6.3.0",
28
39
  "@vitest/coverage-c8": "0.32.1",
29
40
  "alpinejs": "npm:@ekwoka/alpinets@0.0.1-alpha",
30
- "esbuild": "0.18.3",
31
- "eslint": "8.42.0",
41
+ "esbuild": "0.19.2",
42
+ "eslint": "8.47.0",
32
43
  "eslint-plugin-filename-export": "1.0.4",
33
44
  "husky": "8.0.3",
34
- "lint-staged": "13.2.2",
35
- "prettier": "2.8.8",
36
- "pretty-bytes": "^6.1.0",
37
- "typescript": "5.1.3",
38
- "vite": "4.3.9",
45
+ "lint-staged": "14.0.0",
46
+ "prettier": "3.0.1",
47
+ "pretty-bytes": "6.1.1",
48
+ "typescript": "5.1.6",
49
+ "vite": "4.4.9",
39
50
  "vite-tsconfig-paths": "4.2.0",
40
- "vitest": "0.32.1"
51
+ "vitest": "0.34.1"
41
52
  },
42
53
  "peerDependencies": {
43
54
  "alpinejs": "^3.10.0",
@@ -1,11 +1,7 @@
1
- import { Alpine } from 'alpinejs';
1
+ import type { Alpine } from 'alpinejs';
2
2
 
3
- import {
4
- HeadlessComponent,
5
- HeadlessHandler,
6
- RootHandler,
7
- headless,
8
- } from './headless';
3
+ import { AlpinePlugin } from '../types';
4
+ import { HeadlessHandler, RootHandler, headless } from './headless';
9
5
 
10
6
  type GroupData = {
11
7
  active: number | null;
@@ -22,7 +18,7 @@ const getGroup = (el: HTMLElement, Alpine: Alpine) => {
22
18
  const handleAccordionGroup: RootHandler<GroupData> = (
23
19
  el,
24
20
  _,
25
- { Alpine, effect }
21
+ { Alpine, effect },
26
22
  ) => {
27
23
  const groupData = Alpine.reactive({
28
24
  active: null as number | null,
@@ -53,7 +49,7 @@ const handleAccordionGroup: RootHandler<GroupData> = (
53
49
  return groupData;
54
50
  };
55
51
 
56
- export const accordionGroup: HeadlessComponent = (Alpine) =>
52
+ export const accordionGroup: AlpinePlugin = (Alpine) =>
57
53
  Alpine.directive('accordion-group', handleAccordionGroup);
58
54
 
59
55
  type AccordionData = {
@@ -62,7 +58,7 @@ type AccordionData = {
62
58
  const handleAccordionRoot: RootHandler<AccordionData> = (
63
59
  el,
64
60
  { modifiers: [initialState = 'closed'] },
65
- { Alpine }
61
+ { Alpine },
66
62
  ) =>
67
63
  getGroup(el, Alpine)?.addAccordion(initialState === 'open') ??
68
64
  Alpine.reactive({
@@ -81,7 +77,7 @@ const handleAccordionControl: HeadlessHandler<AccordionData> = (
81
77
  accordionData,
82
78
  el,
83
79
  { modifiers: [force = 'toggle'] },
84
- { Alpine }
80
+ { Alpine },
85
81
  ) => {
86
82
  Alpine.bind(el, {
87
83
  'x-on:click': () => {
@@ -95,7 +91,7 @@ const handleAccordionContainer: HeadlessHandler<AccordionData> = (
95
91
  accordionData,
96
92
  el,
97
93
  _,
98
- { Alpine }
94
+ { Alpine },
99
95
  ) => {
100
96
  Alpine.bind(el, {
101
97
  'x-show': () => accordionData.active,
@@ -110,10 +106,10 @@ const accordionHandlers = {
110
106
  export const accordion = headless(
111
107
  'accordion',
112
108
  handleAccordionRoot,
113
- accordionHandlers
109
+ accordionHandlers,
114
110
  );
115
111
 
116
- const accordions: HeadlessComponent = (Alpine) => {
112
+ export const accordions: AlpinePlugin = (Alpine) => {
117
113
  accordionGroup(Alpine);
118
114
  accordion(Alpine);
119
115
  };
@@ -0,0 +1,86 @@
1
+ import { AlpinePlugin } from '../types';
2
+
3
+ const resizeCenterer = new ResizeObserver((entries) => {
4
+ for (const entry of entries) {
5
+ const el = entry.target;
6
+ if (!(el instanceof HTMLElement)) continue;
7
+ center(el);
8
+ }
9
+ });
10
+
11
+ const center = async (el: HTMLElement) => {
12
+ await nextTick();
13
+ el.scrollLeft = (el.scrollWidth - el.clientWidth) / 2;
14
+ el.scrollTop = (el.scrollHeight - el.clientHeight) / 2;
15
+ };
16
+
17
+ export const dragScroll: AlpinePlugin = (Alpine) =>
18
+ Alpine.directive('dragscroll', (el, { modifiers }, { cleanup }) => {
19
+ const autoCenter = modifiers.includes('center');
20
+ registerDragScroll(el);
21
+ if (autoCenter)
22
+ Array.prototype.forEach.call(el.children, (el: Element) =>
23
+ resizeCenterer.observe(el),
24
+ );
25
+ el.classList.add('overscroll-contain', 'cursor-grab');
26
+ cleanup(() =>
27
+ Array.prototype.forEach.call(el.children, (el: Element) =>
28
+ resizeCenterer.unobserve(el),
29
+ ),
30
+ );
31
+ });
32
+
33
+ const preventStop = (e: Event) => {
34
+ e.preventDefault();
35
+ e.stopPropagation();
36
+ };
37
+
38
+ const cancelEvents = ['pointerup', 'mouseup', 'touchend'] as const;
39
+
40
+ const registerDragScroll = (el: HTMLElement) => {
41
+ const moveHandler = (e: PointerEvent) => {
42
+ preventStop(e);
43
+ el.scrollLeft -= e.movementX;
44
+ el.scrollTop -= e.movementY;
45
+ };
46
+ const upHandler = async (e: PointerEvent | MouseEvent | TouchEvent) => {
47
+ preventStop(e);
48
+ document.removeEventListener('pointermove', moveHandler, true);
49
+ document.body.classList.remove(
50
+ '!cursor-grabbing',
51
+ '[&>*]:pointer-events-none',
52
+ );
53
+ el.classList.add('cursor-grab');
54
+ await nextTick();
55
+ document.removeEventListener('click', preventStop, true);
56
+ cancelEvents.map((event) =>
57
+ document.removeEventListener(event, upHandler, {
58
+ capture: true,
59
+ }),
60
+ );
61
+ };
62
+ const downHandler = (e: PointerEvent | MouseEvent | TouchEvent) => {
63
+ if (isTouch(e)) return; // skip touch inputs (allow native scrolling)
64
+ if (e.button === 2) return; // skip right-click
65
+ preventStop(e);
66
+ el.classList.remove('cursor-grab');
67
+ document.body.classList.add(
68
+ '!cursor-grabbing',
69
+ '[&>*]:pointer-events-none',
70
+ );
71
+ document.addEventListener('pointermove', moveHandler, { capture: true });
72
+ cancelEvents.map((event) =>
73
+ document.addEventListener(event, upHandler, {
74
+ capture: true,
75
+ }),
76
+ );
77
+ document.addEventListener('click', preventStop, { capture: true });
78
+ };
79
+ el.addEventListener('pointerdown', downHandler);
80
+ };
81
+
82
+ const nextTick = () =>
83
+ new Promise((res) => queueMicrotask(() => setTimeout(res, 0)));
84
+
85
+ const isTouch = (e: PointerEvent | MouseEvent | TouchEvent): e is TouchEvent =>
86
+ e instanceof TouchEvent;
@@ -5,15 +5,17 @@ import type {
5
5
  Utilities,
6
6
  } from 'alpinejs/dist/types';
7
7
 
8
+ import { AlpinePlugin } from '../types';
9
+
8
10
  export const headless = <T extends Record<string, unknown>>(
9
11
  name: string,
10
12
  rootHandler: RootHandler<T>,
11
- handlers?: HeadlessHandlers<T>
12
- ): HeadlessComponent => {
13
+ handlers?: HeadlessHandlers<T>,
14
+ ): AlpinePlugin => {
13
15
  const headlessMap = new WeakMap<ElementWithXAttributes, T>();
14
16
  return (Alpine: Alpine) => {
15
17
  const getHeadlessComponentState = (
16
- el: ElementWithXAttributes
18
+ el: ElementWithXAttributes,
17
19
  ): T | void => {
18
20
  const root = Alpine.findClosest(el, headlessMap.has.bind(headlessMap));
19
21
  if (!root)
@@ -32,7 +34,7 @@ export const headless = <T extends Record<string, unknown>>(
32
34
  headlessState,
33
35
  el,
34
36
  directive,
35
- utils
37
+ utils,
36
38
  );
37
39
  });
38
40
  };
@@ -44,7 +46,7 @@ const failback =
44
46
  console.error(
45
47
  `Alpine ${name}: Invalid directive value`,
46
48
  el,
47
- directive.original
49
+ directive.original,
48
50
  );
49
51
  };
50
52
 
@@ -59,14 +61,12 @@ type HeadlessHandlers<T extends Record<string, unknown>> = Record<
59
61
  export type RootHandler<T> = (
60
62
  el: ElementWithXAttributes,
61
63
  directive: DirectiveData,
62
- utilities: Utilities
64
+ utilities: Utilities,
63
65
  ) => T;
64
66
 
65
67
  export type HeadlessHandler<T> = (
66
68
  state: T,
67
69
  el: ElementWithXAttributes,
68
70
  directive: DirectiveData,
69
- utilities: Utilities
71
+ utilities: Utilities,
70
72
  ) => void;
71
-
72
- export type HeadlessComponent = (Alpine: Alpine) => void;
@@ -0,0 +1,7 @@
1
+ export { accordionGroup, accordion, accordions } from './accordion';
2
+ export { dragScroll } from './dragScroll';
3
+ export { headless } from './headless';
4
+ export { panel } from './panel';
5
+ export { tabs } from './tabs';
6
+ export type { RootHandler, HeadlessHandler } from './headless';
7
+ export { swipeDetect } from './swipeDetect';
@@ -0,0 +1,96 @@
1
+ import type { ElementWithXAttributes } from 'alpinejs/dist/types';
2
+
3
+ import type { AlpinePlugin } from '../types';
4
+
5
+ type TouchPosition = {
6
+ x: number;
7
+ y: number;
8
+ };
9
+
10
+ type SwipableData = {
11
+ start?: TouchPosition;
12
+
13
+ dispatch: (dir: SwipeDirection) => void;
14
+ };
15
+ enum SwipeDirection {
16
+ None = 0,
17
+ Left = 1 << 0,
18
+ Right = 1 << 1,
19
+ Up = 1 << 2,
20
+ Down = 1 << 3,
21
+ }
22
+
23
+ const swipableMap = new WeakMap<ElementWithXAttributes, SwipableData>();
24
+ const hasSwipe = swipableMap.has.bind(swipableMap);
25
+ export const swipeDetect: AlpinePlugin = (Alpine) =>
26
+ Alpine.directive('swipe', (el, _, { cleanup }) => {
27
+ const swipeData: SwipableData = {
28
+ dispatch: (dir) => {
29
+ const direction = Object.entries(SwipeDirection)
30
+ .filter(([, v]) => typeof v === 'number' && v && (dir & v) === v)
31
+ .map(([k]) => k.toLowerCase());
32
+ el.dispatchEvent(
33
+ new CustomEvent('swipe', {
34
+ detail: direction.join('-'),
35
+ }),
36
+ );
37
+ el.dispatchEvent(
38
+ new CustomEvent(`swipe${direction.join('')}`, {
39
+ detail: direction.join('-'),
40
+ }),
41
+ );
42
+ },
43
+ };
44
+ swipableMap.set(el, swipeData);
45
+ el.addEventListener('touchstart', touchDown);
46
+ cleanup(() => el.removeEventListener('touchstart', touchDown));
47
+ });
48
+
49
+ const touchDown = (ev: TouchEvent) => {
50
+ const swipeData = swipableMap.get(ev.currentTarget as ElementWithXAttributes);
51
+ if (!swipeData) return;
52
+ const touch = ev.touches[0];
53
+ const { clientX, clientY } = touch;
54
+ swipeData.start ??= { x: clientX, y: clientY };
55
+ document.addEventListener('touchend', touchUp, { once: true });
56
+ };
57
+
58
+ const touchUp = (ev: TouchEvent) => {
59
+ const target = ev.target as ElementWithXAttributes;
60
+ if (!target) return;
61
+ const swipeData = swipableMap.get(
62
+ findNearest(target, hasSwipe) as ElementWithXAttributes,
63
+ );
64
+ if (!swipeData?.start) return;
65
+ const touch = ev.changedTouches[0];
66
+ const { clientX, clientY } = touch;
67
+ const direction = getDirection(swipeData.start, { x: clientX, y: clientY });
68
+ if (direction === SwipeDirection.None) return;
69
+ swipeData.dispatch(direction);
70
+ };
71
+
72
+ const findNearest = <T extends HTMLElement>(
73
+ el: T,
74
+ predicate: (el: T) => boolean,
75
+ ): HTMLElement | null => {
76
+ if (predicate(el)) return el;
77
+ if (!el.parentElement) return null;
78
+ return findNearest(el.parentElement as T, predicate);
79
+ };
80
+
81
+ const getDirection = (start: TouchPosition, end: TouchPosition) => {
82
+ const vector = [end.x - start.x, end.y - start.y];
83
+ if (vector.every((v) => Math.abs(v) < 25)) return SwipeDirection.None;
84
+ // normalize vector
85
+ const magnitude = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1]);
86
+ const [x, y] = vector.map((v) => v / magnitude);
87
+
88
+ const direction = getDirectionSign(x) | (getDirectionSign(y) << 2);
89
+ return direction;
90
+ };
91
+
92
+ const getDirectionSign = (offset: number) => {
93
+ if (offset > 0.5) return 2;
94
+ if (offset < -0.5) return 1;
95
+ return 0;
96
+ };
@@ -49,7 +49,7 @@ export const tabs = headless(
49
49
  ':aria-hidden': () => panelIndex !== tabGroup.activeTab,
50
50
  });
51
51
  },
52
- }
52
+ },
53
53
  );
54
54
 
55
55
  type FocusMagic = {
package/src/index.ts CHANGED
@@ -1,9 +1,29 @@
1
- import accordions from './headless/accordion';
2
- import { HeadlessComponent } from './headless/headless';
3
- import { panel } from './headless/panel';
4
- import { tabs } from './headless/tabs';
1
+ import {
2
+ accordion,
3
+ accordionGroup,
4
+ accordions,
5
+ dragScroll,
6
+ panel,
7
+ swipeDetect,
8
+ tabs,
9
+ } from './headless';
10
+ import { screen } from './magics';
11
+ import type { AlpinePlugin } from './types';
5
12
 
6
- export const UI: HeadlessComponent = (Alpine) =>
7
- Alpine.plugin([accordions, panel, tabs]);
13
+ export const NTMagics: AlpinePlugin = (Alpine) => Alpine.plugin([screen]);
14
+
15
+ export const UI: AlpinePlugin = (Alpine) =>
16
+ Alpine.plugin([accordions, dragScroll, panel, swipeDetect, tabs, NTMagics]);
8
17
 
9
18
  export default UI;
19
+
20
+ export {
21
+ accordion,
22
+ accordionGroup,
23
+ accordions,
24
+ dragScroll,
25
+ panel,
26
+ tabs,
27
+ screen,
28
+ AlpinePlugin,
29
+ };
@@ -0,0 +1 @@
1
+ export { screen } from './screen';
@@ -0,0 +1,49 @@
1
+ import type { Alpine } from 'alpinejs';
2
+
3
+ import { AlpinePlugin } from '../types';
4
+
5
+ export const screen: AlpinePlugin = (Alpine) => {
6
+ Alpine.magic('screen', () => (breakpoint: string | number) => {
7
+ const breakSize =
8
+ typeof breakpoint === 'number'
9
+ ? breakpoint
10
+ : breakpoints[breakpoint] ?? Number(breakpoint);
11
+ if (!breakSize) {
12
+ console.error(
13
+ `Invalid breakpoint: $screen(${JSON.stringify(breakpoint)})`,
14
+ );
15
+ return false;
16
+ }
17
+ const signal = getMediaSignal(breakSize, Alpine);
18
+ return signal.value;
19
+ });
20
+ };
21
+
22
+ // Configuration
23
+ const defaultBreakpoints: Record<string, number> = {
24
+ xs: 320,
25
+ sm: 640,
26
+ md: 768,
27
+ lg: 1024,
28
+ xl: 1280,
29
+ '2xl': 1536,
30
+ };
31
+
32
+ const breakpoints = defaultBreakpoints;
33
+ const mediaSignals: Record<number, { value: boolean }> = {};
34
+
35
+ const getMediaSignal = (breakpoint: number, Alpine: Alpine) => {
36
+ return mediaSignals[breakpoint] ?? createMediaSignal(breakpoint, Alpine);
37
+ };
38
+
39
+ const createMediaSignal = (breakpoint: number, Alpine: Alpine) => {
40
+ const mediaMatch = window.matchMedia(`(min-width: ${breakpoint}px)`);
41
+ const signal = Alpine.reactive({
42
+ value: mediaMatch.matches,
43
+ });
44
+ mediaSignals[breakpoint] = signal;
45
+ mediaMatch.addEventListener('change', (e) => {
46
+ signal.value = e.matches;
47
+ });
48
+ return signal;
49
+ };
package/src/types.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Alpine } from 'alpinejs';
2
+
3
+ export type AlpinePlugin = (Alpine: Alpine) => void;