snice 7.6.0 → 7.8.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 (228) hide show
  1. package/adapters/react/SniceProvider.js +1 -1
  2. package/adapters/react/SniceRouter.js +1 -1
  3. package/adapters/react/calendar.d.ts +1 -0
  4. package/adapters/react/calendar.d.ts.map +1 -1
  5. package/adapters/react/calendar.js +1 -1
  6. package/adapters/react/calendar.js.map +1 -1
  7. package/adapters/react/calendar.tsx +2 -1
  8. package/adapters/react/matchRoute.js +1 -1
  9. package/adapters/react/useRequestHandler.js +1 -1
  10. package/bin/analyzer-contracts.js +8 -2
  11. package/custom-elements.json +15 -1
  12. package/dist/cdn/accordion/snice-accordion.js +1 -1
  13. package/dist/cdn/action-bar/snice-action-bar.js +1 -1
  14. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  15. package/dist/cdn/alert/snice-alert.js +1 -1
  16. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  17. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  18. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  19. package/dist/cdn/availability/snice-availability.js +1 -1
  20. package/dist/cdn/avatar/snice-avatar.js +1 -1
  21. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  22. package/dist/cdn/badge/snice-badge.js +1 -1
  23. package/dist/cdn/banner/snice-banner.js +1 -1
  24. package/dist/cdn/binpack/snice-binpack.js +1 -1
  25. package/dist/cdn/book/snice-book.js +1 -1
  26. package/dist/cdn/booking/snice-booking.js +1 -1
  27. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  28. package/dist/cdn/button/snice-button.js +2 -2
  29. package/dist/cdn/button/snice-button.js.map +1 -1
  30. package/dist/cdn/button/snice-button.min.js +1 -1
  31. package/dist/cdn/button/snice-button.min.js.map +1 -1
  32. package/dist/cdn/calendar/README.md +2 -2
  33. package/dist/cdn/calendar/snice-calendar.js +26 -2
  34. package/dist/cdn/calendar/snice-calendar.js.map +1 -1
  35. package/dist/cdn/calendar/snice-calendar.min.js +2 -2
  36. package/dist/cdn/calendar/snice-calendar.min.js.map +1 -1
  37. package/dist/cdn/camera/snice-camera.js +1 -1
  38. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  39. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  40. package/dist/cdn/card/snice-card.js +1 -1
  41. package/dist/cdn/carousel/snice-carousel.js +1 -1
  42. package/dist/cdn/cart/snice-cart.js +1 -1
  43. package/dist/cdn/chart/snice-chart.js +1 -1
  44. package/dist/cdn/chat/snice-chat.js +1 -1
  45. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  46. package/dist/cdn/chip/snice-chip.js +1 -1
  47. package/dist/cdn/code-block/snice-code-block.js +1 -1
  48. package/dist/cdn/color-display/snice-color-display.js +1 -1
  49. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  50. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  51. package/dist/cdn/comments/snice-comments.js +1 -1
  52. package/dist/cdn/countdown/snice-countdown.js +1 -1
  53. package/dist/cdn/cropper/snice-cropper.js +1 -1
  54. package/dist/cdn/data-card/snice-data-card.js +1 -1
  55. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  56. package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
  57. package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
  58. package/dist/cdn/diff/snice-diff.js +1 -1
  59. package/dist/cdn/divider/snice-divider.js +1 -1
  60. package/dist/cdn/doc/snice-doc.js +1 -1
  61. package/dist/cdn/draw/snice-draw.js +1 -1
  62. package/dist/cdn/drawer/snice-drawer.js +1 -1
  63. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  64. package/dist/cdn/estimate/snice-estimate.js +1 -1
  65. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  66. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  67. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  68. package/dist/cdn/flow/snice-flow.js +1 -1
  69. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  70. package/dist/cdn/funnel/snice-funnel.js +1 -1
  71. package/dist/cdn/gantt/snice-gantt.js +1 -1
  72. package/dist/cdn/gauge/snice-gauge.js +1 -1
  73. package/dist/cdn/grid/snice-grid.js +1 -1
  74. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  75. package/dist/cdn/image/snice-image.js +1 -1
  76. package/dist/cdn/input/snice-input.js +1 -1
  77. package/dist/cdn/invoice/snice-invoice.js +1 -1
  78. package/dist/cdn/kanban/snice-kanban.js +1 -1
  79. package/dist/cdn/key-value/snice-key-value.js +1 -1
  80. package/dist/cdn/kpi/snice-kpi.js +1 -1
  81. package/dist/cdn/layout/snice-layout.js +1 -1
  82. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  83. package/dist/cdn/link/snice-link.js +1 -1
  84. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  85. package/dist/cdn/list/snice-list.js +1 -1
  86. package/dist/cdn/location/snice-location.js +1 -1
  87. package/dist/cdn/login/README.md +1 -1
  88. package/dist/cdn/login/snice-login.js +2 -2
  89. package/dist/cdn/login/snice-login.js.map +1 -1
  90. package/dist/cdn/login/snice-login.min.js +1 -1
  91. package/dist/cdn/login/snice-login.min.js.map +1 -1
  92. package/dist/cdn/map/snice-map.js +1 -1
  93. package/dist/cdn/markdown/snice-markdown.js +1 -1
  94. package/dist/cdn/masonry/snice-masonry.js +1 -1
  95. package/dist/cdn/menu/snice-menu.js +1 -1
  96. package/dist/cdn/message-strip/snice-message-strip.js +1 -1
  97. package/dist/cdn/modal/snice-modal.js +1 -1
  98. package/dist/cdn/music-player/snice-music-player.js +1 -1
  99. package/dist/cdn/nav/snice-nav.js +1 -1
  100. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  101. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  102. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  103. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  104. package/dist/cdn/pagination/snice-pagination.js +1 -1
  105. package/dist/cdn/paint/snice-paint.js +1 -1
  106. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  107. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  108. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  109. package/dist/cdn/popover/snice-popover.js +1 -1
  110. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  111. package/dist/cdn/product-card/snice-product-card.js +1 -1
  112. package/dist/cdn/progress/snice-progress.js +1 -1
  113. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  114. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  115. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  116. package/dist/cdn/radio/snice-radio.js +1 -1
  117. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  118. package/dist/cdn/rating/snice-rating.js +1 -1
  119. package/dist/cdn/receipt/snice-receipt.js +1 -1
  120. package/dist/cdn/recipe/snice-recipe.js +1 -1
  121. package/dist/cdn/runtime/README.md +2 -2
  122. package/dist/cdn/runtime/snice-runtime.esm.js +130 -31
  123. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  124. package/dist/cdn/runtime/snice-runtime.esm.min.js +1 -1
  125. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  126. package/dist/cdn/runtime/snice-runtime.js +130 -31
  127. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  128. package/dist/cdn/runtime/snice-runtime.min.js +1 -1
  129. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  130. package/dist/cdn/sankey/snice-sankey.js +1 -1
  131. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  132. package/dist/cdn/select/snice-select.js +1 -1
  133. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  134. package/dist/cdn/slider/snice-slider.js +1 -1
  135. package/dist/cdn/sortable/snice-sortable.js +1 -1
  136. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  137. package/dist/cdn/spinner/snice-spinner.js +1 -1
  138. package/dist/cdn/split-button/snice-split-button.js +1 -1
  139. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  140. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  141. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  142. package/dist/cdn/step-input/snice-step-input.js +1 -1
  143. package/dist/cdn/stepper/snice-stepper.js +1 -1
  144. package/dist/cdn/switch/snice-switch.js +1 -1
  145. package/dist/cdn/table/README.md +2 -2
  146. package/dist/cdn/table/snice-table.esm.js +227 -36
  147. package/dist/cdn/table/snice-table.esm.js.map +1 -1
  148. package/dist/cdn/table/snice-table.esm.min.js +69 -48
  149. package/dist/cdn/table/snice-table.esm.min.js.map +1 -1
  150. package/dist/cdn/table/snice-table.js +226 -35
  151. package/dist/cdn/table/snice-table.js.map +1 -1
  152. package/dist/cdn/table/snice-table.min.js +47 -26
  153. package/dist/cdn/table/snice-table.min.js.map +1 -1
  154. package/dist/cdn/tabs/snice-tabs.js +1 -1
  155. package/dist/cdn/tag/snice-tag.js +1 -1
  156. package/dist/cdn/tag-input/README.md +2 -2
  157. package/dist/cdn/tag-input/snice-tag-input.js +10 -16
  158. package/dist/cdn/tag-input/snice-tag-input.js.map +1 -1
  159. package/dist/cdn/tag-input/snice-tag-input.min.js +2 -2
  160. package/dist/cdn/tag-input/snice-tag-input.min.js.map +1 -1
  161. package/dist/cdn/terminal/snice-terminal.js +1 -1
  162. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  163. package/dist/cdn/textarea/snice-textarea.js +1 -1
  164. package/dist/cdn/time-picker/snice-time-picker.js +1 -1
  165. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  166. package/dist/cdn/timeline/snice-timeline.js +1 -1
  167. package/dist/cdn/timer/snice-timer.js +1 -1
  168. package/dist/cdn/toast/snice-toast.js +1 -1
  169. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  170. package/dist/cdn/tree/snice-tree.js +1 -1
  171. package/dist/cdn/treemap/snice-treemap.js +1 -1
  172. package/dist/cdn/user-card/snice-user-card.js +1 -1
  173. package/dist/cdn/video-player/snice-video-player.js +1 -1
  174. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  175. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  176. package/dist/cdn/weather/snice-weather.js +1 -1
  177. package/dist/cdn/work-order/snice-work-order.js +1 -1
  178. package/dist/components/button/snice-button.js +1 -1
  179. package/dist/components/button/snice-button.js.map +1 -1
  180. package/dist/components/calendar/snice-calendar.d.ts +2 -0
  181. package/dist/components/calendar/snice-calendar.js +25 -1
  182. package/dist/components/calendar/snice-calendar.js.map +1 -1
  183. package/dist/components/table/snice-row.d.ts +6 -0
  184. package/dist/components/table/snice-row.js +11 -3
  185. package/dist/components/table/snice-row.js.map +1 -1
  186. package/dist/components/table/snice-table.d.ts +40 -3
  187. package/dist/components/table/snice-table.js +157 -17
  188. package/dist/components/table/snice-table.js.map +1 -1
  189. package/dist/components/table/table-cell-presentation.d.ts +11 -0
  190. package/dist/components/table/table-cell-presentation.js +25 -8
  191. package/dist/components/table/table-cell-presentation.js.map +1 -1
  192. package/dist/components/table/table-export.d.ts +6 -0
  193. package/dist/components/table/table-export.js +11 -2
  194. package/dist/components/table/table-export.js.map +1 -1
  195. package/dist/components/table/table-keyboard.js +1 -1
  196. package/dist/components/table/table-keyboard.js.map +1 -1
  197. package/dist/components/table/table-master-detail.d.ts +11 -2
  198. package/dist/components/table/table-master-detail.js +20 -3
  199. package/dist/components/table/table-master-detail.js.map +1 -1
  200. package/dist/components/tag-input/snice-tag-input.d.ts +2 -2
  201. package/dist/components/tag-input/snice-tag-input.js +9 -15
  202. package/dist/components/tag-input/snice-tag-input.js.map +1 -1
  203. package/dist/index.cjs +127 -28
  204. package/dist/index.cjs.map +1 -1
  205. package/dist/index.esm.js +127 -28
  206. package/dist/index.esm.js.map +1 -1
  207. package/dist/index.iife.js +127 -28
  208. package/dist/index.iife.js.map +1 -1
  209. package/dist/react/SniceProvider.js +1 -1
  210. package/dist/react/SniceRouter.js +1 -1
  211. package/dist/react/index.js +1 -1
  212. package/dist/react/matchRoute.js +1 -1
  213. package/dist/react/useRequestHandler.js +1 -1
  214. package/dist/request-response.d.ts +24 -1
  215. package/dist/symbols.cjs +1 -1
  216. package/dist/symbols.esm.js +1 -1
  217. package/dist/testing-dom.cjs +1 -1
  218. package/dist/testing-dom.esm.js +1 -1
  219. package/dist/transitions.cjs +1 -1
  220. package/dist/transitions.esm.js +1 -1
  221. package/docs/ai/DEVELOPMENT.md +1 -1
  222. package/docs/ai/components/calendar.md +8 -0
  223. package/docs/ai/components/tag-input.md +4 -0
  224. package/docs/ai/controllers.md +22 -6
  225. package/docs/components/calendar.md +24 -0
  226. package/docs/components/tag-input.md +6 -1
  227. package/docs/controllers.md +57 -6
  228. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.5.1
2
+ * snice v7.7.0
3
3
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
4
4
  * (c) 2024
5
5
  * Released under the MIT License.
@@ -8,7 +8,7 @@ var Snice = (function (exports) {
8
8
  'use strict';
9
9
 
10
10
  /*!
11
- * snice v7.5.1
11
+ * snice v7.7.0
12
12
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
13
13
  * (c) 2024
14
14
  * Released under the MIT License.
@@ -1566,17 +1566,33 @@ var Snice = (function (exports) {
1566
1566
  });
1567
1567
  };
1568
1568
  }
1569
- // Helper to setup response handlers for elements and controllers
1570
- function setupResponseHandlers(instance, element) {
1569
+ // Which handler descriptors an instance has already registered, so a second
1570
+ // setup pass only picks up what the first one deferred.
1571
+ const registeredHandlers = new WeakMap();
1572
+ /**
1573
+ * Helper to setup response handlers for elements and controllers.
1574
+ *
1575
+ * Safe to call more than once for the same instance: a handler already
1576
+ * registered is skipped rather than double-bound.
1577
+ */
1578
+ function setupResponseHandlers(instance, element, options) {
1571
1579
  const handlers = instance.constructor[CHANNEL_HANDLERS];
1572
1580
  if (!handlers)
1573
1581
  return;
1582
+ const claim = options?.claim;
1583
+ let registered = registeredHandlers.get(instance);
1584
+ if (!registered) {
1585
+ registered = new Set();
1586
+ registeredHandlers.set(instance, registered);
1587
+ }
1574
1588
  // Store cleanup functions
1575
1589
  // Initialize cleanup object if needed
1576
1590
  if (!instance[CLEANUP]) {
1577
1591
  instance[CLEANUP] = { events: [], channels: [] };
1578
1592
  }
1579
1593
  for (const handler of handlers) {
1594
+ if (registered.has(handler))
1595
+ continue;
1580
1596
  const boundMethod = handler.method.bind(instance);
1581
1597
  const eventName = `@request/${handler.channelName}`;
1582
1598
  // Create timing variables for debounce/throttle per handler
@@ -1660,7 +1676,10 @@ var Snice = (function (exports) {
1660
1676
  // Clear the discovery timeout immediately - we found a handler
1661
1677
  discovery.resolve();
1662
1678
  // Call the timed responder method and handle the result
1663
- Promise.resolve(timedMethod(payload))
1679
+ const answer = claim
1680
+ ? Promise.resolve(claim()).then(() => timedMethod(payload))
1681
+ : Promise.resolve(timedMethod(payload));
1682
+ answer
1664
1683
  .then(result => {
1665
1684
  data.resolve(result);
1666
1685
  })
@@ -1675,10 +1694,17 @@ var Snice = (function (exports) {
1675
1694
  responseTarget = requireDaemonTarget(instance, handler.options.daemon);
1676
1695
  }
1677
1696
  catch (error) {
1697
+ // The app context reaches a controller through its host element, so it
1698
+ // can be unreachable while the host is still disconnected. Leave the
1699
+ // handler for the later pass instead of dropping it permanently.
1700
+ if (options?.deferUnresolvableDaemons)
1701
+ continue;
1678
1702
  console.warn(`[snice/@respond] ${error.message} Responder "${handler.channelName}" skipped.`);
1703
+ registered.add(handler);
1679
1704
  continue;
1680
1705
  }
1681
1706
  }
1707
+ registered.add(handler);
1682
1708
  responseTarget.addEventListener(eventName, responseHandler);
1683
1709
  instance[CLEANUP].channels.push(() => {
1684
1710
  responseTarget.removeEventListener(eventName, responseHandler);
@@ -1687,6 +1713,7 @@ var Snice = (function (exports) {
1687
1713
  }
1688
1714
  // Helper to cleanup response handlers
1689
1715
  function cleanupResponseHandlers(instance) {
1716
+ registeredHandlers.delete(instance);
1690
1717
  if (instance[CLEANUP]?.channels) {
1691
1718
  for (const cleanup of instance[CLEANUP].channels) {
1692
1719
  cleanup();
@@ -1812,6 +1839,8 @@ var Snice = (function (exports) {
1812
1839
  * Use in elements or controllers to listen to DOM events or custom events
1813
1840
  */
1814
1841
  const ON_HANDLERS = getSymbol('on-handlers');
1842
+ // Per-decoration-site counter — see the registration identity note in `on()`.
1843
+ let registrationCount = 0;
1815
1844
  /**
1816
1845
  * @on decorator for listening to events
1817
1846
  *
@@ -1873,18 +1902,42 @@ var Snice = (function (exports) {
1873
1902
  if (!selector && opts.target) {
1874
1903
  selector = opts.target;
1875
1904
  }
1905
+ const eventNames = Array.isArray(eventName) ? eventName : [eventName];
1906
+ // Registration identity — derived from EVERY decorator argument, so no
1907
+ // option can be forgotten here and silently collapse two distinct stacked
1908
+ // @on decorators into one (that is how { debounce: 300 } stacked on a plain
1909
+ // @on for the same event used to lose one of its two registrations).
1910
+ // Options are serialized generically (sorted, so literal key order doesn't
1911
+ // matter); values that can't be compared by value — an EventTarget or a
1912
+ // resolver function passed as `scope` — fall back to this decoration site's
1913
+ // own id, which is stable across instances but unique per @on application.
1914
+ const siteId = `site:${++registrationCount}`;
1915
+ let optionSignature = '';
1916
+ let hasOpaqueOption = false;
1917
+ for (const key of Object.keys(opts).sort()) {
1918
+ const value = opts[key];
1919
+ if (value === undefined)
1920
+ continue;
1921
+ if (value !== null && (typeof value === 'object' || typeof value === 'function')) {
1922
+ hasOpaqueOption = true;
1923
+ continue;
1924
+ }
1925
+ optionSignature += `${key}=${String(value)};`;
1926
+ }
1927
+ const argumentKey = `${eventNames.join(',')}::${selector ?? ''}::${optionSignature}${hasOpaqueOption ? `::${siteId}` : ''}`;
1876
1928
  return function (originalMethod, context) {
1877
1929
  const methodName = context.name;
1930
+ // Same decoration, same method name → same registration. A subclass that
1931
+ // re-declares an identically decorated method must NOT add a second
1932
+ // listener on top of the one its parent's initializer already registered.
1933
+ const registrationKey = `${methodName}::${argumentKey}`;
1878
1934
  context.addInitializer(function () {
1879
1935
  const constructor = this.constructor;
1880
- // Dedup by registration identity (method + events + selector), NOT by
1881
- // method reference alone stacked @on decorators share one method and
1882
- // must each register. Use hasOwnProperty so subclasses get their OWN
1883
- // Set instead of inheriting otherwise parent and child share state
1884
- // and child registrations pollute parent (and vice versa) via the
1885
- // prototype chain.
1886
- const eventNames = Array.isArray(eventName) ? eventName : [eventName];
1887
- const registrationKey = `${methodName}::${eventNames.join(',')}::${selector ?? ''}::daemon:${opts.daemon ?? ''}::light:${opts.light ?? ''}::shadow:${opts.shadow ?? ''}`;
1936
+ // Dedup by registration identity, NOT by method reference stacked @on
1937
+ // decorators share one method and must each register. Use hasOwnProperty
1938
+ // so subclasses get their OWN Set instead of inheriting — otherwise
1939
+ // parent and child share state and child registrations pollute parent
1940
+ // (and vice versa) via the prototype chain.
1888
1941
  if (!Object.prototype.hasOwnProperty.call(constructor, ON_METHODS)) {
1889
1942
  constructor[ON_METHODS] = new Set();
1890
1943
  }
@@ -2899,6 +2952,35 @@ var Snice = (function (exports) {
2899
2952
  // MutationObservers are guarded from treating it as a string attachment.
2900
2953
  restoreDirectControllerAttribute(element);
2901
2954
  }
2955
+ // @respond handlers are installed before the readiness gate below, exactly
2956
+ // as elements install theirs in connectedCallback. A child's mount-time
2957
+ // @request can be the very thing keeping the host from becoming ready, so
2958
+ // the responder has to be reachable while `ready` is still pending. Such a
2959
+ // request also releases the gate — it proves the host subtree is live and
2960
+ // that something is blocked on this attachment — and is answered once
2961
+ // attach() and the remaining setup have run.
2962
+ //
2963
+ // A `@respond({ daemon })` handler resolves its target through the host's app
2964
+ // context, which is unreachable while the host is still disconnected (attach
2965
+ // before appendChild). Those are deferred here and registered by the second
2966
+ // pass past the gate, where they behaved correctly before this ordering.
2967
+ let requestClaimed = false;
2968
+ let releaseReadyGate;
2969
+ let completeAttach;
2970
+ let failAttach;
2971
+ const attached = new Promise((resolve, reject) => {
2972
+ completeAttach = resolve;
2973
+ failAttach = reject;
2974
+ });
2975
+ attached.catch(() => { }); // No requester when nothing was claimed
2976
+ setupResponseHandlers(controllerInstance, element, {
2977
+ deferUnresolvableDaemons: true,
2978
+ claim: () => {
2979
+ requestClaimed = true;
2980
+ releaseReadyGate?.();
2981
+ return attached;
2982
+ },
2983
+ });
2902
2984
  // Normally a controller waits for its host's full initialization. The sole
2903
2985
  // exception is attachController(host, ...) from that host's own @ready
2904
2986
  // handler: awaiting ready there would wait on the current handler itself.
@@ -2911,6 +2993,11 @@ var Snice = (function (exports) {
2911
2993
  try {
2912
2994
  await Promise.race([
2913
2995
  element.ready,
2996
+ new Promise(resolve => {
2997
+ if (requestClaimed)
2998
+ return resolve();
2999
+ releaseReadyGate = resolve;
3000
+ }),
2914
3001
  new Promise((_, reject) => {
2915
3002
  const onAbort = () => {
2916
3003
  // Tagged so fire-and-forget call sites can tell this designed
@@ -2929,8 +3016,10 @@ var Snice = (function (exports) {
2929
3016
  }
2930
3017
  catch (error) {
2931
3018
  // Attach never got past `ready` (aborted or deadline). Roll back the
2932
- // stored references so a later attach does not short-circuit against an
2933
- // instance whose attach() never ran.
3019
+ // stored references and the early responders so a later attach does not
3020
+ // short-circuit against an instance whose attach() never ran.
3021
+ cleanupResponseHandlers(controllerInstance);
3022
+ failAttach(error);
2934
3023
  if (element[CONTROLLER_KEY] === controllerInstance) {
2935
3024
  if (typeof controller !== 'string') {
2936
3025
  writeControllerAttribute(element, null);
@@ -2952,20 +3041,30 @@ var Snice = (function (exports) {
2952
3041
  }
2953
3042
  // Past `ready` — mark the controller so detach knows attach was actually run.
2954
3043
  controllerInstance[CONTROLLER_ATTACHED] = true;
2955
- // Run attach in the controller's scope
2956
- await scope.runOperation(async () => {
2957
- await controllerInstance.attach(element);
2958
- });
2959
- // @context has the same managed lifecycle on controllers as @on,
2960
- // @observe and @respond. Catch up controllers whose async attach completed
2961
- // after the Router announced the current navigation.
2962
- await setupContextHandler(controllerInstance, 'microtask');
2963
- // Setup @observe observers for controller
2964
- setupObservers(controllerInstance, element);
2965
- // Setup @channel handlers for controller
2966
- setupResponseHandlers(controllerInstance, element);
2967
- // Setup @on event handlers for controller
2968
- setupEventHandlers(controllerInstance, element);
3044
+ try {
3045
+ // Run attach in the controller's scope
3046
+ await scope.runOperation(async () => {
3047
+ await controllerInstance.attach(element);
3048
+ });
3049
+ // @context has the same managed lifecycle on controllers as @on,
3050
+ // @observe and @respond. Catch up controllers whose async attach completed
3051
+ // after the Router announced the current navigation.
3052
+ await setupContextHandler(controllerInstance, 'microtask');
3053
+ // Setup @observe observers for controller
3054
+ setupObservers(controllerInstance, element);
3055
+ // Second @respond pass: registers only what the pre-gate pass deferred —
3056
+ // daemon-scoped responders whose app context was not resolvable yet.
3057
+ setupResponseHandlers(controllerInstance, element);
3058
+ // Setup @on event handlers for controller
3059
+ setupEventHandlers(controllerInstance, element);
3060
+ }
3061
+ catch (error) {
3062
+ // A claimed request must not wait on an attachment that never completed.
3063
+ failAttach(error);
3064
+ throw error;
3065
+ }
3066
+ // Answer whatever was claimed while the host was still becoming ready.
3067
+ completeAttach();
2969
3068
  element.dispatchEvent(new CustomEvent('controller-attached', {
2970
3069
  detail: { name: controllerName, controller: controllerInstance }
2971
3070
  }));
@@ -10170,7 +10269,7 @@ var Snice = (function (exports) {
10170
10269
  }
10171
10270
 
10172
10271
  /*!
10173
- * snice v7.5.1
10272
+ * snice v7.7.0
10174
10273
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
10175
10274
  * (c) 2024
10176
10275
  * Released under the MIT License.
@@ -10192,7 +10291,7 @@ var Snice = (function (exports) {
10192
10291
  globalThis.snice.pendingControllerAttachments ??= new Map();
10193
10292
 
10194
10293
  /*!
10195
- * snice v7.5.1
10294
+ * snice v7.7.0
10196
10295
  * A decorator-driven web component library with routing, controllers, daemons, and 130+ UI components. For better coding-agent results, run npx snice init-ai.
10197
10296
  * (c) 2024
10198
10297
  * Released under the MIT License.