@benqoder/beam 0.1.3 → 0.2.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.
package/dist/client.js CHANGED
@@ -105,16 +105,6 @@ const api = {
105
105
  // @ts-ignore - capnweb stub methods are dynamically typed
106
106
  return session.call(action, data);
107
107
  },
108
- async modal(modalId, params = {}) {
109
- const session = await ensureConnected();
110
- // @ts-ignore - capnweb stub methods are dynamically typed
111
- return session.modal(modalId, params);
112
- },
113
- async drawer(drawerId, params = {}) {
114
- const session = await ensureConnected();
115
- // @ts-ignore - capnweb stub methods are dynamically typed
116
- return session.drawer(drawerId, params);
117
- },
118
108
  // Direct access to RPC session for advanced usage (promise pipelining, etc.)
119
109
  async getSession() {
120
110
  return ensureConnected();
@@ -456,6 +446,72 @@ function swap(target, html, mode, trigger) {
456
446
  // Process hungry elements - auto-update elements that match IDs in response
457
447
  processHungryElements(html);
458
448
  }
449
+ /**
450
+ * Handle HTML response - supports both single string and array of HTML strings.
451
+ * Target resolution order (server wins, frontend is fallback):
452
+ * 1. Server target from comma-separated list (by index)
453
+ * - Use "!selector" to exclude that selector (blocks frontend fallback too)
454
+ * 2. Frontend target (beam-target) as fallback for remaining items
455
+ * 3. ID from HTML fragment's root element
456
+ * 4. Skip if none found
457
+ */
458
+ function handleHtmlResponse(response, frontendTarget, frontendSwap, trigger) {
459
+ if (!response.html)
460
+ return;
461
+ const htmlArray = Array.isArray(response.html) ? response.html : [response.html];
462
+ // Server targets take priority, collect exclusions
463
+ const serverTargets = response.target ? response.target.split(',').map(s => s.trim()) : [];
464
+ const excluded = new Set(serverTargets.filter(t => t.startsWith('!')).map(t => t.slice(1)));
465
+ const swapMode = response.swap || frontendSwap;
466
+ htmlArray.forEach((htmlItem, index) => {
467
+ const serverTarget = serverTargets[index];
468
+ // Skip if this is an exclusion marker
469
+ if (serverTarget?.startsWith('!')) {
470
+ return;
471
+ }
472
+ // Priority 1: Server target (by index)
473
+ let explicitTarget = serverTarget;
474
+ // Priority 2: Frontend target as fallback (only if no server target and not excluded)
475
+ if (!explicitTarget && frontendTarget && !excluded.has(frontendTarget)) {
476
+ explicitTarget = frontendTarget;
477
+ }
478
+ if (explicitTarget) {
479
+ // Explicit target provided - use normal swap
480
+ const target = $(explicitTarget);
481
+ if (target) {
482
+ swap(target, htmlItem, swapMode, trigger);
483
+ }
484
+ else {
485
+ console.warn(`[beam] Target "${explicitTarget}" not found on page, skipping`);
486
+ }
487
+ }
488
+ else {
489
+ // Priority 3: id, beam-id, or beam-item-id on root element
490
+ const temp = document.createElement('div');
491
+ temp.innerHTML = htmlItem.trim();
492
+ const rootEl = temp.firstElementChild;
493
+ // Check id first, then beam-id, then beam-item-id
494
+ const id = rootEl?.id;
495
+ const beamId = rootEl?.getAttribute('beam-id');
496
+ const beamItemId = rootEl?.getAttribute('beam-item-id');
497
+ const selector = id ? `#${id}`
498
+ : beamId ? `[beam-id="${beamId}"]`
499
+ : beamItemId ? `[beam-item-id="${beamItemId}"]`
500
+ : null;
501
+ if (selector && !excluded.has(selector)) {
502
+ const target = $(selector);
503
+ if (target) {
504
+ // Replace entire element using outerHTML (preserves styles/classes)
505
+ target.outerHTML = htmlItem.trim();
506
+ }
507
+ else {
508
+ console.warn(`[beam] Target "${selector}" (from HTML) not found on page, skipping`);
509
+ }
510
+ }
511
+ // If no id/beam-id/beam-item-id found or excluded, skip silently
512
+ }
513
+ });
514
+ }
459
515
  function parseOobSwaps(html) {
460
516
  const temp = document.createElement('div');
461
517
  temp.innerHTML = html;
@@ -484,16 +540,20 @@ async function rpc(action, data, el) {
484
540
  location.href = response.redirect;
485
541
  return;
486
542
  }
487
- // Server target/swap override frontend values
488
- const targetSelector = response.target || frontendTarget;
489
- const swapMode = response.swap || frontendSwap;
490
- // Handle HTML (if present)
491
- if (response.html && targetSelector) {
492
- const target = $(targetSelector);
493
- if (target) {
494
- swap(target, response.html, swapMode, el);
495
- }
543
+ // Handle modal (if present)
544
+ if (response.modal) {
545
+ const modalData = typeof response.modal === 'string'
546
+ ? { html: response.modal } : response.modal;
547
+ openModal(modalData.html, modalData.size || 'medium', modalData.spacing);
548
+ }
549
+ // Handle drawer (if present)
550
+ if (response.drawer) {
551
+ const drawerData = typeof response.drawer === 'string'
552
+ ? { html: response.drawer } : response.drawer;
553
+ openDrawer(drawerData.html, drawerData.position || 'right', drawerData.size || 'medium', drawerData.spacing);
496
554
  }
555
+ // Handle HTML (if present) - supports single string or array
556
+ handleHtmlResponse(response, frontendTarget, frontendSwap, el);
497
557
  // Execute script (if present)
498
558
  if (response.script) {
499
559
  executeScript(response.script);
@@ -583,8 +643,9 @@ document.addEventListener('click', async (e) => {
583
643
  closeDrawer();
584
644
  }
585
645
  });
586
- // ============ MODALS ============
587
- document.addEventListener('click', (e) => {
646
+ // ============ MODALS & DRAWERS ============
647
+ // beam-modal trigger - calls action and opens result in modal
648
+ document.addEventListener('click', async (e) => {
588
649
  const target = e.target;
589
650
  if (!target?.closest)
590
651
  return;
@@ -594,30 +655,48 @@ document.addEventListener('click', (e) => {
594
655
  // Check confirmation
595
656
  if (!checkConfirm(trigger))
596
657
  return;
597
- const modalId = trigger.getAttribute('beam-modal');
658
+ const action = trigger.getAttribute('beam-modal');
659
+ if (!action)
660
+ return;
598
661
  const size = trigger.getAttribute('beam-size') || 'medium';
599
662
  const params = getParams(trigger);
600
- if (modalId) {
601
- openModal(modalId, params, { size });
663
+ const placeholder = trigger.getAttribute('beam-placeholder');
664
+ // Show placeholder modal while loading
665
+ if (placeholder) {
666
+ openModal(placeholder, size);
602
667
  }
603
- }
604
- // Close on backdrop click
605
- if (target.matches?.('#modal-backdrop')) {
606
- closeModal();
607
- }
608
- // Close button (handles both modal and drawer)
609
- const closeBtn = target.closest('[beam-close]');
610
- if (closeBtn && !closeBtn.hasAttribute('beam-action')) {
611
- if (activeDrawer) {
612
- closeDrawer();
668
+ setLoading(trigger, true, action, params);
669
+ try {
670
+ const response = await api.call(action, params);
671
+ // Handle the response - if it returns modal, use that, otherwise use html
672
+ if (response.modal) {
673
+ const modalData = typeof response.modal === 'string'
674
+ ? { html: response.modal } : response.modal;
675
+ openModal(modalData.html, modalData.size || size, modalData.spacing);
676
+ }
677
+ else if (response.html) {
678
+ // For modals, use first item if array, otherwise use as-is
679
+ const htmlStr = Array.isArray(response.html) ? response.html[0] : response.html;
680
+ if (htmlStr)
681
+ openModal(htmlStr, size);
682
+ }
683
+ // Execute script if present
684
+ if (response.script) {
685
+ executeScript(response.script);
686
+ }
613
687
  }
614
- else {
688
+ catch (err) {
615
689
  closeModal();
690
+ showToast('Failed to open modal.', 'error');
691
+ console.error('Modal error:', err);
692
+ }
693
+ finally {
694
+ setLoading(trigger, false, action, params);
616
695
  }
617
696
  }
618
697
  });
619
- // Drawer triggers
620
- document.addEventListener('click', (e) => {
698
+ // beam-drawer trigger - calls action and opens result in drawer
699
+ document.addEventListener('click', async (e) => {
621
700
  const target = e.target;
622
701
  if (!target?.closest)
623
702
  return;
@@ -627,18 +706,69 @@ document.addEventListener('click', (e) => {
627
706
  // Check confirmation
628
707
  if (!checkConfirm(trigger))
629
708
  return;
630
- const drawerId = trigger.getAttribute('beam-drawer');
709
+ const action = trigger.getAttribute('beam-drawer');
710
+ if (!action)
711
+ return;
631
712
  const position = trigger.getAttribute('beam-position') || 'right';
632
713
  const size = trigger.getAttribute('beam-size') || 'medium';
633
714
  const params = getParams(trigger);
634
- if (drawerId) {
635
- openDrawer(drawerId, params, { position, size });
715
+ const placeholder = trigger.getAttribute('beam-placeholder');
716
+ // Show placeholder drawer while loading
717
+ if (placeholder) {
718
+ openDrawer(placeholder, position, size);
719
+ }
720
+ setLoading(trigger, true, action, params);
721
+ try {
722
+ const response = await api.call(action, params);
723
+ // Handle the response - if it returns drawer, use that, otherwise use html
724
+ if (response.drawer) {
725
+ const drawerData = typeof response.drawer === 'string'
726
+ ? { html: response.drawer } : response.drawer;
727
+ openDrawer(drawerData.html, drawerData.position || position, drawerData.size || size, drawerData.spacing);
728
+ }
729
+ else if (response.html) {
730
+ // For drawers, use first item if array, otherwise use as-is
731
+ const htmlStr = Array.isArray(response.html) ? response.html[0] : response.html;
732
+ if (htmlStr)
733
+ openDrawer(htmlStr, position, size);
734
+ }
735
+ // Execute script if present
736
+ if (response.script) {
737
+ executeScript(response.script);
738
+ }
739
+ }
740
+ catch (err) {
741
+ closeDrawer();
742
+ showToast('Failed to open drawer.', 'error');
743
+ console.error('Drawer error:', err);
744
+ }
745
+ finally {
746
+ setLoading(trigger, false, action, params);
636
747
  }
637
748
  }
749
+ });
750
+ // Close handlers
751
+ document.addEventListener('click', (e) => {
752
+ const target = e.target;
753
+ if (!target?.closest)
754
+ return;
638
755
  // Close on backdrop click
756
+ if (target.matches?.('#modal-backdrop')) {
757
+ closeModal();
758
+ }
639
759
  if (target.matches?.('#drawer-backdrop')) {
640
760
  closeDrawer();
641
761
  }
762
+ // Close button (handles both modal and drawer)
763
+ const closeBtn = target.closest('[beam-close]');
764
+ if (closeBtn && !closeBtn.hasAttribute('beam-action')) {
765
+ if (activeDrawer) {
766
+ closeDrawer();
767
+ }
768
+ else {
769
+ closeModal();
770
+ }
771
+ }
642
772
  });
643
773
  document.addEventListener('keydown', (e) => {
644
774
  if (e.key === 'Escape') {
@@ -650,33 +780,30 @@ document.addEventListener('keydown', (e) => {
650
780
  }
651
781
  }
652
782
  });
653
- async function openModal(id, params = {}, options = { size: 'medium' }) {
654
- try {
655
- const html = await api.modal(id, params);
656
- let backdrop = $('#modal-backdrop');
657
- if (!backdrop) {
658
- backdrop = document.createElement('div');
659
- backdrop.id = 'modal-backdrop';
660
- document.body.appendChild(backdrop);
661
- }
662
- const { size } = options;
663
- backdrop.innerHTML = `
664
- <div id="modal-content" role="dialog" aria-modal="true" data-size="${size}">
665
- ${html}
666
- </div>
667
- `;
668
- backdrop.offsetHeight;
669
- backdrop.classList.add('open');
670
- document.body.classList.add('modal-open');
671
- activeModal = $('#modal-content');
672
- const autoFocus = activeModal?.querySelector('[autofocus]');
673
- const firstInput = activeModal?.querySelector('input, button, textarea, select');
674
- (autoFocus || firstInput)?.focus();
675
- }
676
- catch (err) {
677
- showToast('Failed to open modal.', 'error');
678
- console.error('Modal error:', err);
783
+ function openModal(html, size = 'medium', spacing) {
784
+ // Close any existing drawer first (modal takes priority)
785
+ if (activeDrawer) {
786
+ closeDrawer();
679
787
  }
788
+ let backdrop = $('#modal-backdrop');
789
+ if (!backdrop) {
790
+ backdrop = document.createElement('div');
791
+ backdrop.id = 'modal-backdrop';
792
+ document.body.appendChild(backdrop);
793
+ }
794
+ const style = spacing !== undefined ? `padding: ${spacing}px;` : '';
795
+ backdrop.innerHTML = `
796
+ <div id="modal-content" role="dialog" aria-modal="true" data-size="${size}" style="${style}">
797
+ ${html}
798
+ </div>
799
+ `;
800
+ backdrop.offsetHeight;
801
+ backdrop.classList.add('open');
802
+ document.body.classList.add('modal-open');
803
+ activeModal = $('#modal-content');
804
+ const autoFocus = activeModal?.querySelector('[autofocus]');
805
+ const firstInput = activeModal?.querySelector('input, button, textarea, select');
806
+ (autoFocus || firstInput)?.focus();
680
807
  }
681
808
  function closeModal() {
682
809
  const backdrop = $('#modal-backdrop');
@@ -689,34 +816,31 @@ function closeModal() {
689
816
  document.body.classList.remove('modal-open');
690
817
  activeModal = null;
691
818
  }
692
- async function openDrawer(id, params = {}, options) {
693
- try {
694
- const html = await api.drawer(id, params);
695
- let backdrop = $('#drawer-backdrop');
696
- if (!backdrop) {
697
- backdrop = document.createElement('div');
698
- backdrop.id = 'drawer-backdrop';
699
- document.body.appendChild(backdrop);
700
- }
701
- // Set position and size as data attributes for CSS styling
702
- const { position, size } = options;
703
- backdrop.innerHTML = `
704
- <div id="drawer-content" role="dialog" aria-modal="true" data-position="${position}" data-size="${size}">
705
- ${html}
706
- </div>
707
- `;
708
- backdrop.offsetHeight; // Force reflow
709
- backdrop.classList.add('open');
710
- document.body.classList.add('drawer-open');
711
- activeDrawer = $('#drawer-content');
712
- const autoFocus = activeDrawer?.querySelector('[autofocus]');
713
- const firstInput = activeDrawer?.querySelector('input, button, textarea, select');
714
- (autoFocus || firstInput)?.focus();
715
- }
716
- catch (err) {
717
- showToast('Failed to open drawer.', 'error');
718
- console.error('Drawer error:', err);
819
+ // ============ DRAWERS ============
820
+ function openDrawer(html, position = 'right', size = 'medium', spacing) {
821
+ // Close any existing modal first (drawer takes priority)
822
+ if (activeModal) {
823
+ closeModal();
719
824
  }
825
+ let backdrop = $('#drawer-backdrop');
826
+ if (!backdrop) {
827
+ backdrop = document.createElement('div');
828
+ backdrop.id = 'drawer-backdrop';
829
+ document.body.appendChild(backdrop);
830
+ }
831
+ const style = spacing !== undefined ? `padding: ${spacing}px;` : '';
832
+ backdrop.innerHTML = `
833
+ <div id="drawer-content" role="dialog" aria-modal="true" data-position="${position}" data-size="${size}" style="${style}">
834
+ ${html}
835
+ </div>
836
+ `;
837
+ backdrop.offsetHeight; // Force reflow
838
+ backdrop.classList.add('open');
839
+ document.body.classList.add('drawer-open');
840
+ activeDrawer = $('#drawer-content');
841
+ const autoFocus = activeDrawer?.querySelector('[autofocus]');
842
+ const firstInput = activeDrawer?.querySelector('input, button, textarea, select');
843
+ (autoFocus || firstInput)?.focus();
720
844
  }
721
845
  function closeDrawer() {
722
846
  const backdrop = $('#drawer-backdrop');
@@ -1125,9 +1249,14 @@ const infiniteObserver = new IntersectionObserver(async (entries) => {
1125
1249
  setLoading(sentinel, true, action, params);
1126
1250
  try {
1127
1251
  const response = await api.call(action, params);
1128
- const target = $(targetSelector);
1129
- if (target && response.html) {
1130
- swap(target, response.html, swapMode, sentinel);
1252
+ if (response.html) {
1253
+ // For infinite scroll, always use the specified target (not auto-detect from HTML)
1254
+ const target = $(targetSelector);
1255
+ if (target) {
1256
+ // Handle single html string for infinite scroll (array not typically used here)
1257
+ const htmlStr = Array.isArray(response.html) ? response.html.join('') : response.html;
1258
+ swap(target, htmlStr, swapMode, sentinel);
1259
+ }
1131
1260
  // Save scroll state after content is loaded
1132
1261
  requestAnimationFrame(() => {
1133
1262
  saveScrollState(targetSelector, action);
@@ -1186,9 +1315,14 @@ document.addEventListener('click', async (e) => {
1186
1315
  setLoading(trigger, true, action, params);
1187
1316
  try {
1188
1317
  const response = await api.call(action, params);
1189
- const targetEl = $(targetSelector);
1190
- if (targetEl && response.html) {
1191
- swap(targetEl, response.html, swapMode, trigger);
1318
+ if (response.html) {
1319
+ // For load more, always use the specified target (not auto-detect from HTML)
1320
+ const targetEl = $(targetSelector);
1321
+ if (targetEl) {
1322
+ // Handle single html string for load more (array not typically used here)
1323
+ const htmlStr = Array.isArray(response.html) ? response.html.join('') : response.html;
1324
+ swap(targetEl, htmlStr, swapMode, trigger);
1325
+ }
1192
1326
  // Save scroll state after content is loaded
1193
1327
  requestAnimationFrame(() => {
1194
1328
  saveScrollState(targetSelector, action);
@@ -1372,13 +1506,8 @@ document.addEventListener('click', async (e) => {
1372
1506
  location.href = response.redirect;
1373
1507
  return;
1374
1508
  }
1375
- // Handle HTML (if present)
1376
- if (response.html && targetSelector) {
1377
- const target = $(targetSelector);
1378
- if (target) {
1379
- swap(target, response.html, swapMode, link);
1380
- }
1381
- }
1509
+ // Handle HTML (if present) - supports single string or array
1510
+ handleHtmlResponse(response, targetSelector, swapMode, link);
1382
1511
  // Execute script (if present)
1383
1512
  if (response.script) {
1384
1513
  executeScript(response.script);
@@ -1428,13 +1557,20 @@ document.addEventListener('submit', async (e) => {
1428
1557
  location.href = response.redirect;
1429
1558
  return;
1430
1559
  }
1431
- // Handle HTML (if present)
1432
- if (response.html && targetSelector) {
1433
- const target = $(targetSelector);
1434
- if (target) {
1435
- swap(target, response.html, swapMode);
1436
- }
1560
+ // Handle modal (if present)
1561
+ if (response.modal) {
1562
+ const modalData = typeof response.modal === 'string'
1563
+ ? { html: response.modal } : response.modal;
1564
+ openModal(modalData.html, modalData.size || 'medium', modalData.spacing);
1437
1565
  }
1566
+ // Handle drawer (if present)
1567
+ if (response.drawer) {
1568
+ const drawerData = typeof response.drawer === 'string'
1569
+ ? { html: response.drawer } : response.drawer;
1570
+ openDrawer(drawerData.html, drawerData.position || 'right', drawerData.size || 'medium', drawerData.spacing);
1571
+ }
1572
+ // Handle HTML (if present) - supports single string or array
1573
+ handleHtmlResponse(response, targetSelector, swapMode);
1438
1574
  // Execute script (if present)
1439
1575
  if (response.script) {
1440
1576
  executeScript(response.script);
@@ -1483,7 +1619,10 @@ function setupValidation(el) {
1483
1619
  if (response.html) {
1484
1620
  const target = $(targetSelector);
1485
1621
  if (target) {
1486
- morph(target, response.html);
1622
+ // For validation, use first item if array, otherwise use as-is
1623
+ const htmlStr = Array.isArray(response.html) ? response.html[0] : response.html;
1624
+ if (htmlStr)
1625
+ morph(target, htmlStr);
1487
1626
  }
1488
1627
  }
1489
1628
  // Execute script (if present)
@@ -1533,7 +1672,10 @@ const deferObserver = new IntersectionObserver(async (entries) => {
1533
1672
  if (response.html) {
1534
1673
  const target = targetSelector ? $(targetSelector) : el;
1535
1674
  if (target) {
1536
- swap(target, response.html, swapMode);
1675
+ // For deferred loading, use first item if array, otherwise use as-is
1676
+ const htmlStr = Array.isArray(response.html) ? response.html[0] : response.html;
1677
+ if (htmlStr)
1678
+ swap(target, htmlStr, swapMode);
1537
1679
  }
1538
1680
  }
1539
1681
  // Execute script (if present)
@@ -1589,7 +1731,10 @@ function startPolling(el) {
1589
1731
  if (response.html) {
1590
1732
  const target = targetSelector ? $(targetSelector) : el;
1591
1733
  if (target) {
1592
- swap(target, response.html, swapMode);
1734
+ // For polling, use first item if array, otherwise use as-is
1735
+ const htmlStr = Array.isArray(response.html) ? response.html[0] : response.html;
1736
+ if (htmlStr)
1737
+ swap(target, htmlStr, swapMode);
1593
1738
  }
1594
1739
  }
1595
1740
  // Execute script (if present)
@@ -1845,20 +1990,27 @@ window.beam = new Proxy(beamUtils, {
1845
1990
  location.href = response.redirect;
1846
1991
  return response;
1847
1992
  }
1993
+ // Handle modal (if present)
1994
+ if (response.modal) {
1995
+ const modalData = typeof response.modal === 'string'
1996
+ ? { html: response.modal } : response.modal;
1997
+ openModal(modalData.html, modalData.size || 'medium', modalData.spacing);
1998
+ }
1999
+ // Handle drawer (if present)
2000
+ if (response.drawer) {
2001
+ const drawerData = typeof response.drawer === 'string'
2002
+ ? { html: response.drawer } : response.drawer;
2003
+ openDrawer(drawerData.html, drawerData.position || 'right', drawerData.size || 'medium', drawerData.spacing);
2004
+ }
1848
2005
  // Normalize options: string is shorthand for { target: string }
1849
2006
  const opts = typeof options === 'string'
1850
2007
  ? { target: options }
1851
2008
  : (options || {});
1852
2009
  // Server target/swap override frontend options
1853
- const targetSelector = response.target || opts.target;
2010
+ const targetSelector = response.target || opts.target || null;
1854
2011
  const swapMode = response.swap || opts.swap || 'morph';
1855
- // Handle HTML swap if target provided
1856
- if (response.html && targetSelector) {
1857
- const targetEl = document.querySelector(targetSelector);
1858
- if (targetEl) {
1859
- swap(targetEl, response.html, swapMode);
1860
- }
1861
- }
2012
+ // Handle HTML swap - supports single string or array
2013
+ handleHtmlResponse(response, targetSelector, swapMode);
1862
2014
  // Execute script if present
1863
2015
  if (response.script) {
1864
2016
  executeScript(response.script);
package/dist/collect.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActionHandler, ModalHandler, DrawerHandler } from './types';
1
+ import type { ActionHandler } from './types';
2
2
  /**
3
3
  * Type for glob import results from import.meta.glob
4
4
  */
@@ -18,51 +18,5 @@ type GlobImport = Record<string, Record<string, unknown>>;
18
18
  * - `./actions/cart.tsx` exports `addToCart` → `addToCart`
19
19
  */
20
20
  export declare function collectActions<TEnv = object>(glob: GlobImport): Record<string, ActionHandler<TEnv>>;
21
- /**
22
- * Collects modal handlers from glob imports.
23
- *
24
- * @example
25
- * ```typescript
26
- * const modals = collectModals<Env>(
27
- * import.meta.glob('./modals/*.tsx', { eager: true })
28
- * )
29
- * ```
30
- */
31
- export declare function collectModals<TEnv = object>(glob: GlobImport): Record<string, ModalHandler<TEnv>>;
32
- /**
33
- * Collects drawer handlers from glob imports.
34
- *
35
- * @example
36
- * ```typescript
37
- * const drawers = collectDrawers<Env>(
38
- * import.meta.glob('./drawers/*.tsx', { eager: true })
39
- * )
40
- * ```
41
- */
42
- export declare function collectDrawers<TEnv = object>(glob: GlobImport): Record<string, DrawerHandler<TEnv>>;
43
- /**
44
- * Collects all handlers (actions, modals, drawers) from glob imports.
45
- * This is a convenience function that collects all three at once.
46
- *
47
- * @example
48
- * ```typescript
49
- * const { actions, modals, drawers } = collectHandlers<Env>({
50
- * actions: import.meta.glob('./actions/*.tsx', { eager: true }),
51
- * modals: import.meta.glob('./modals/*.tsx', { eager: true }),
52
- * drawers: import.meta.glob('./drawers/*.tsx', { eager: true }),
53
- * })
54
- *
55
- * export const beam = createBeam<Env>({ actions, modals, drawers })
56
- * ```
57
- */
58
- export declare function collectHandlers<TEnv = object>(globs: {
59
- actions?: GlobImport;
60
- modals?: GlobImport;
61
- drawers?: GlobImport;
62
- }): {
63
- actions: Record<string, ActionHandler<TEnv>>;
64
- modals: Record<string, ModalHandler<TEnv>>;
65
- drawers: Record<string, DrawerHandler<TEnv>>;
66
- };
67
21
  export {};
68
22
  //# sourceMappingURL=collect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEzE;;GAEG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAEzD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAG,MAAM,EAC1C,IAAI,EAAE,UAAU,GACf,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAarC;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,IAAI,GAAG,MAAM,EACzC,IAAI,EAAE,UAAU,GACf,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAYpC;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAG,MAAM,EAC1C,IAAI,EAAE,UAAU,GACf,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAYrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAG,MAAM,EAAE,KAAK,EAAE;IACpD,OAAO,CAAC,EAAE,UAAU,CAAA;IACpB,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,OAAO,CAAC,EAAE,UAAU,CAAA;CACrB,GAAG;IACF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;IAC5C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAA;IAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAA;CAC7C,CAMA"}
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../src/collect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C;;GAEG;AACH,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAEzD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAG,MAAM,EAC1C,IAAI,EAAE,UAAU,GACf,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAarC"}
package/dist/collect.js CHANGED
@@ -24,67 +24,3 @@ export function collectActions(glob) {
24
24
  }
25
25
  return handlers;
26
26
  }
27
- /**
28
- * Collects modal handlers from glob imports.
29
- *
30
- * @example
31
- * ```typescript
32
- * const modals = collectModals<Env>(
33
- * import.meta.glob('./modals/*.tsx', { eager: true })
34
- * )
35
- * ```
36
- */
37
- export function collectModals(glob) {
38
- const handlers = {};
39
- for (const [, module] of Object.entries(glob)) {
40
- for (const [exportName, exportValue] of Object.entries(module)) {
41
- if (typeof exportValue === 'function' && exportName !== 'default') {
42
- handlers[exportName] = exportValue;
43
- }
44
- }
45
- }
46
- return handlers;
47
- }
48
- /**
49
- * Collects drawer handlers from glob imports.
50
- *
51
- * @example
52
- * ```typescript
53
- * const drawers = collectDrawers<Env>(
54
- * import.meta.glob('./drawers/*.tsx', { eager: true })
55
- * )
56
- * ```
57
- */
58
- export function collectDrawers(glob) {
59
- const handlers = {};
60
- for (const [, module] of Object.entries(glob)) {
61
- for (const [exportName, exportValue] of Object.entries(module)) {
62
- if (typeof exportValue === 'function' && exportName !== 'default') {
63
- handlers[exportName] = exportValue;
64
- }
65
- }
66
- }
67
- return handlers;
68
- }
69
- /**
70
- * Collects all handlers (actions, modals, drawers) from glob imports.
71
- * This is a convenience function that collects all three at once.
72
- *
73
- * @example
74
- * ```typescript
75
- * const { actions, modals, drawers } = collectHandlers<Env>({
76
- * actions: import.meta.glob('./actions/*.tsx', { eager: true }),
77
- * modals: import.meta.glob('./modals/*.tsx', { eager: true }),
78
- * drawers: import.meta.glob('./drawers/*.tsx', { eager: true }),
79
- * })
80
- *
81
- * export const beam = createBeam<Env>({ actions, modals, drawers })
82
- * ```
83
- */
84
- export function collectHandlers(globs) {
85
- return {
86
- actions: globs.actions ? collectActions(globs.actions) : {},
87
- modals: globs.modals ? collectModals(globs.modals) : {},
88
- drawers: globs.drawers ? collectDrawers(globs.drawers) : {},
89
- };
90
- }