snice 7.1.0 → 7.1.1

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 (177) hide show
  1. package/README.md +5 -0
  2. package/adapters/react/SniceProvider.js +1 -1
  3. package/adapters/react/SniceRouter.js +1 -1
  4. package/adapters/react/matchRoute.js +1 -1
  5. package/adapters/react/useRequestHandler.js +1 -1
  6. package/dist/cdn/accordion/snice-accordion.js +1 -1
  7. package/dist/cdn/action-bar/snice-action-bar.js +1 -1
  8. package/dist/cdn/activity-feed/snice-activity-feed.js +1 -1
  9. package/dist/cdn/alert/snice-alert.js +1 -1
  10. package/dist/cdn/app-tiles/snice-app-tiles.js +1 -1
  11. package/dist/cdn/approval-flow/snice-approval-flow.js +1 -1
  12. package/dist/cdn/audio-recorder/snice-audio-recorder.js +1 -1
  13. package/dist/cdn/availability/snice-availability.js +1 -1
  14. package/dist/cdn/avatar/snice-avatar.js +1 -1
  15. package/dist/cdn/avatar-group/snice-avatar-group.js +1 -1
  16. package/dist/cdn/badge/snice-badge.js +1 -1
  17. package/dist/cdn/banner/snice-banner.js +1 -1
  18. package/dist/cdn/binpack/snice-binpack.js +1 -1
  19. package/dist/cdn/book/snice-book.js +1 -1
  20. package/dist/cdn/booking/snice-booking.js +1 -1
  21. package/dist/cdn/breadcrumbs/snice-breadcrumbs.js +1 -1
  22. package/dist/cdn/button/snice-button.js +1 -1
  23. package/dist/cdn/calendar/snice-calendar.js +1 -1
  24. package/dist/cdn/camera/snice-camera.js +1 -1
  25. package/dist/cdn/camera-annotate/snice-camera-annotate.js +1 -1
  26. package/dist/cdn/candlestick/snice-candlestick.js +1 -1
  27. package/dist/cdn/card/snice-card.js +1 -1
  28. package/dist/cdn/carousel/snice-carousel.js +1 -1
  29. package/dist/cdn/cart/snice-cart.js +1 -1
  30. package/dist/cdn/chart/snice-chart.js +1 -1
  31. package/dist/cdn/chat/snice-chat.js +1 -1
  32. package/dist/cdn/checkbox/snice-checkbox.js +1 -1
  33. package/dist/cdn/chip/snice-chip.js +1 -1
  34. package/dist/cdn/code-block/snice-code-block.js +1 -1
  35. package/dist/cdn/color-display/snice-color-display.js +1 -1
  36. package/dist/cdn/color-picker/snice-color-picker.js +1 -1
  37. package/dist/cdn/command-palette/snice-command-palette.js +1 -1
  38. package/dist/cdn/comments/snice-comments.js +1 -1
  39. package/dist/cdn/countdown/snice-countdown.js +1 -1
  40. package/dist/cdn/cropper/snice-cropper.js +1 -1
  41. package/dist/cdn/data-card/snice-data-card.js +1 -1
  42. package/dist/cdn/date-picker/snice-date-picker.js +1 -1
  43. package/dist/cdn/date-range-picker/snice-date-range-picker.js +1 -1
  44. package/dist/cdn/date-time-picker/snice-date-time-picker.js +1 -1
  45. package/dist/cdn/diff/snice-diff.js +1 -1
  46. package/dist/cdn/divider/snice-divider.js +1 -1
  47. package/dist/cdn/doc/snice-doc.js +1 -1
  48. package/dist/cdn/draw/snice-draw.js +1 -1
  49. package/dist/cdn/drawer/snice-drawer.js +1 -1
  50. package/dist/cdn/empty-state/snice-empty-state.js +1 -1
  51. package/dist/cdn/estimate/snice-estimate.js +1 -1
  52. package/dist/cdn/file-gallery/snice-file-gallery.js +1 -1
  53. package/dist/cdn/file-upload/snice-file-upload.js +1 -1
  54. package/dist/cdn/flip-card/snice-flip-card.js +1 -1
  55. package/dist/cdn/flow/snice-flow.js +1 -1
  56. package/dist/cdn/form-layout/snice-form-layout.js +1 -1
  57. package/dist/cdn/funnel/snice-funnel.js +1 -1
  58. package/dist/cdn/gantt/snice-gantt.js +1 -1
  59. package/dist/cdn/gauge/snice-gauge.js +1 -1
  60. package/dist/cdn/grid/snice-grid.js +1 -1
  61. package/dist/cdn/heatmap/snice-heatmap.js +1 -1
  62. package/dist/cdn/image/snice-image.js +1 -1
  63. package/dist/cdn/input/snice-input.js +1 -1
  64. package/dist/cdn/invoice/snice-invoice.js +1 -1
  65. package/dist/cdn/kanban/snice-kanban.js +1 -1
  66. package/dist/cdn/key-value/snice-key-value.js +1 -1
  67. package/dist/cdn/kpi/snice-kpi.js +1 -1
  68. package/dist/cdn/layout/snice-layout.js +1 -1
  69. package/dist/cdn/leaderboard/snice-leaderboard.js +1 -1
  70. package/dist/cdn/link/snice-link.js +1 -1
  71. package/dist/cdn/link-preview/snice-link-preview.js +1 -1
  72. package/dist/cdn/list/snice-list.js +1 -1
  73. package/dist/cdn/location/snice-location.js +1 -1
  74. package/dist/cdn/login/snice-login.js +1 -1
  75. package/dist/cdn/map/snice-map.js +1 -1
  76. package/dist/cdn/markdown/snice-markdown.js +1 -1
  77. package/dist/cdn/masonry/snice-masonry.js +1 -1
  78. package/dist/cdn/menu/snice-menu.js +1 -1
  79. package/dist/cdn/message-strip/snice-message-strip.js +1 -1
  80. package/dist/cdn/modal/snice-modal.js +1 -1
  81. package/dist/cdn/music-player/snice-music-player.js +1 -1
  82. package/dist/cdn/nav/snice-nav.js +1 -1
  83. package/dist/cdn/network-graph/snice-network-graph.js +1 -1
  84. package/dist/cdn/notification-center/snice-notification-center.js +1 -1
  85. package/dist/cdn/order-tracker/snice-order-tracker.js +1 -1
  86. package/dist/cdn/org-chart/snice-org-chart.js +1 -1
  87. package/dist/cdn/pagination/snice-pagination.js +1 -1
  88. package/dist/cdn/paint/snice-paint.js +1 -1
  89. package/dist/cdn/pdf-viewer/snice-pdf-viewer.js +1 -1
  90. package/dist/cdn/permission-matrix/snice-permission-matrix.js +1 -1
  91. package/dist/cdn/podcast-player/snice-podcast-player.js +1 -1
  92. package/dist/cdn/popover/snice-popover.js +1 -1
  93. package/dist/cdn/pricing-table/snice-pricing-table.js +1 -1
  94. package/dist/cdn/product-card/snice-product-card.js +1 -1
  95. package/dist/cdn/progress/snice-progress.js +1 -1
  96. package/dist/cdn/progress-ring/snice-progress-ring.js +1 -1
  97. package/dist/cdn/qr-code/snice-qr-code.js +1 -1
  98. package/dist/cdn/qr-reader/snice-qr-reader.js +1 -1
  99. package/dist/cdn/radio/snice-radio.js +1 -1
  100. package/dist/cdn/range-slider/snice-range-slider.js +1 -1
  101. package/dist/cdn/rating/snice-rating.js +1 -1
  102. package/dist/cdn/receipt/snice-receipt.js +1 -1
  103. package/dist/cdn/recipe/snice-recipe.js +1 -1
  104. package/dist/cdn/runtime/README.md +2 -2
  105. package/dist/cdn/runtime/snice-runtime.esm.js +114 -15
  106. package/dist/cdn/runtime/snice-runtime.esm.js.map +1 -1
  107. package/dist/cdn/runtime/snice-runtime.esm.min.js +1 -1
  108. package/dist/cdn/runtime/snice-runtime.esm.min.js.map +1 -1
  109. package/dist/cdn/runtime/snice-runtime.js +114 -15
  110. package/dist/cdn/runtime/snice-runtime.js.map +1 -1
  111. package/dist/cdn/runtime/snice-runtime.min.js +1 -1
  112. package/dist/cdn/runtime/snice-runtime.min.js.map +1 -1
  113. package/dist/cdn/sankey/snice-sankey.js +1 -1
  114. package/dist/cdn/segmented-control/snice-segmented-control.js +1 -1
  115. package/dist/cdn/select/snice-select.js +1 -1
  116. package/dist/cdn/skeleton/snice-skeleton.js +1 -1
  117. package/dist/cdn/slider/snice-slider.js +1 -1
  118. package/dist/cdn/sortable/snice-sortable.js +1 -1
  119. package/dist/cdn/sparkline/snice-sparkline.js +1 -1
  120. package/dist/cdn/spinner/snice-spinner.js +1 -1
  121. package/dist/cdn/split-button/snice-split-button.js +1 -1
  122. package/dist/cdn/split-pane/snice-split-pane.js +1 -1
  123. package/dist/cdn/spotlight/snice-spotlight.js +1 -1
  124. package/dist/cdn/stat-group/snice-stat-group.js +1 -1
  125. package/dist/cdn/step-input/snice-step-input.js +1 -1
  126. package/dist/cdn/stepper/snice-stepper.js +1 -1
  127. package/dist/cdn/switch/snice-switch.js +1 -1
  128. package/dist/cdn/table/snice-table.esm.js +1 -1
  129. package/dist/cdn/table/snice-table.js +1 -1
  130. package/dist/cdn/tabs/snice-tabs.js +1 -1
  131. package/dist/cdn/tag/snice-tag.js +1 -1
  132. package/dist/cdn/tag-input/snice-tag-input.js +1 -1
  133. package/dist/cdn/terminal/snice-terminal.js +1 -1
  134. package/dist/cdn/testimonial/snice-testimonial.js +1 -1
  135. package/dist/cdn/textarea/snice-textarea.js +1 -1
  136. package/dist/cdn/time-picker/snice-time-picker.js +1 -1
  137. package/dist/cdn/time-range-picker/snice-time-range-picker.js +1 -1
  138. package/dist/cdn/timeline/snice-timeline.js +1 -1
  139. package/dist/cdn/timer/snice-timer.js +1 -1
  140. package/dist/cdn/toast/snice-toast.js +1 -1
  141. package/dist/cdn/tooltip/snice-tooltip.js +1 -1
  142. package/dist/cdn/tree/snice-tree.js +1 -1
  143. package/dist/cdn/treemap/snice-treemap.js +1 -1
  144. package/dist/cdn/user-card/snice-user-card.js +1 -1
  145. package/dist/cdn/video-player/snice-video-player.js +1 -1
  146. package/dist/cdn/virtual-scroller/snice-virtual-scroller.js +1 -1
  147. package/dist/cdn/waterfall/snice-waterfall.js +1 -1
  148. package/dist/cdn/weather/snice-weather.js +1 -1
  149. package/dist/cdn/work-order/snice-work-order.js +1 -1
  150. package/dist/controller.d.ts +5 -0
  151. package/dist/index.cjs +111 -12
  152. package/dist/index.cjs.map +1 -1
  153. package/dist/index.esm.js +111 -12
  154. package/dist/index.esm.js.map +1 -1
  155. package/dist/index.iife.js +111 -12
  156. package/dist/index.iife.js.map +1 -1
  157. package/dist/parts.d.ts +2 -2
  158. package/dist/react/SniceProvider.js +1 -1
  159. package/dist/react/SniceRouter.js +1 -1
  160. package/dist/react/index.js +1 -1
  161. package/dist/react/matchRoute.js +1 -1
  162. package/dist/react/useRequestHandler.js +1 -1
  163. package/dist/symbols.cjs +9 -1
  164. package/dist/symbols.cjs.map +1 -1
  165. package/dist/symbols.d.ts +2 -0
  166. package/dist/symbols.esm.js +8 -2
  167. package/dist/symbols.esm.js.map +1 -1
  168. package/dist/transitions.cjs +1 -1
  169. package/dist/transitions.esm.js +1 -1
  170. package/docs/ai/architecture.md +1 -1
  171. package/docs/ai/bindings.md +1 -1
  172. package/docs/ai/controllers.md +1 -1
  173. package/docs/ai/decorators.md +1 -1
  174. package/docs/ai/patterns.md +4 -3
  175. package/docs/bindings.md +1 -1
  176. package/docs/controllers.md +8 -2
  177. package/package.json +1 -1
package/dist/index.esm.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * snice v7.0.3
2
+ * snice v7.1.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.
@@ -60,9 +60,15 @@ const CONTROLLER_NAME_KEY = getSymbol('controller-name');
60
60
  const CONTROLLER_ID = getSymbol('controller-id');
61
61
  const CONTROLLER_OPERATIONS = getSymbol('controller-operations');
62
62
  const NATIVE_CONTROLLER = getSymbol('native-controller');
63
+ // Decorator name stored on the class so direct class bindings can expose the
64
+ // same useful DOM label without resolving the controller through the registry.
65
+ const CONTROLLER_REGISTRY_NAME = getSymbol('controller-registry-name');
63
66
  // Set while a controller CLASS (not a registry name) is attached — the
64
67
  // attribute/MutationObserver channel must not attach over or detach it.
65
68
  const DIRECT_CONTROLLER = getSymbol('direct-controller');
69
+ // Guards framework-authored diagnostic controller attribute writes from the
70
+ // synchronous custom-element attributeChangedCallback path.
71
+ const CONTROLLER_ATTRIBUTE_SYNC = getSymbol('controller-attribute-sync');
66
72
  // A controller class bound by a template before the custom element was
67
73
  // defined/upgraded. Picked up by connectedCallback on first initialization.
68
74
  const PENDING_CONTROLLER_BINDING = getSymbol('pending-controller-binding');
@@ -2120,6 +2126,12 @@ function controller(name) {
2120
2126
  registry.set(name, constructor);
2121
2127
  // Mark as controller class for channel decorator detection
2122
2128
  constructor.prototype[IS_CONTROLLER_CLASS] = true;
2129
+ // Preserve the registry name on the class. Direct class attachments still
2130
+ // skip registry lookup; this is only their inspectable DOM label.
2131
+ Object.defineProperty(constructor, CONTROLLER_REGISTRY_NAME, {
2132
+ value: name,
2133
+ configurable: true
2134
+ });
2123
2135
  const pending = snice.pendingControllerAttachments.get(name);
2124
2136
  if (pending) {
2125
2137
  snice.pendingControllerAttachments.delete(name);
@@ -2191,6 +2203,52 @@ function controllerLabel(controller) {
2191
2203
  ? controller
2192
2204
  : (controller?.name || '(anonymous controller class)');
2193
2205
  }
2206
+ /** Registry/decorator name used for a direct class attachment's DOM marker. */
2207
+ function directControllerAttributeName(controllerClass) {
2208
+ const registeredName = Object.prototype.hasOwnProperty.call(controllerClass, CONTROLLER_REGISTRY_NAME)
2209
+ ? controllerClass[CONTROLLER_REGISTRY_NAME]
2210
+ : undefined;
2211
+ return typeof registeredName === 'string'
2212
+ ? registeredName
2213
+ : controllerLabel(controllerClass);
2214
+ }
2215
+ /**
2216
+ * Write the inspectable controller marker without feeding it back into the
2217
+ * custom-element attribute channel. Native MutationObservers are asynchronous
2218
+ * and are excluded independently by DIRECT_CONTROLLER.
2219
+ */
2220
+ function writeControllerAttribute(element, value) {
2221
+ if (value === null) {
2222
+ if (!element.hasAttribute('controller'))
2223
+ return;
2224
+ }
2225
+ else if (element.getAttribute('controller') === value) {
2226
+ return;
2227
+ }
2228
+ element[CONTROLLER_ATTRIBUTE_SYNC] = true;
2229
+ try {
2230
+ if (value === null)
2231
+ element.removeAttribute('controller');
2232
+ else
2233
+ element.setAttribute('controller', value);
2234
+ }
2235
+ finally {
2236
+ delete element[CONTROLLER_ATTRIBUTE_SYNC];
2237
+ }
2238
+ }
2239
+ /**
2240
+ * Restore the diagnostic attribute for an attached class controller. Returns
2241
+ * true when the direct class channel owns the element.
2242
+ */
2243
+ function restoreDirectControllerAttribute(element) {
2244
+ if (!element[DIRECT_CONTROLLER])
2245
+ return false;
2246
+ const source = element[CONTROLLER_NAME_KEY];
2247
+ if (typeof source !== 'function')
2248
+ return false;
2249
+ writeControllerAttribute(element, directControllerAttributeName(source));
2250
+ return true;
2251
+ }
2194
2252
  /**
2195
2253
  * Attaches a controller to an element
2196
2254
  * @param element The element to attach the controller to
@@ -2220,11 +2278,26 @@ async function attachController(element, controller) {
2220
2278
  }
2221
2279
  if (existingSource === controller && existingController) {
2222
2280
  // Already attached and controller exists (name or class reference match)
2281
+ if (typeof controller !== 'string') {
2282
+ restoreDirectControllerAttribute(element);
2283
+ }
2223
2284
  return;
2224
2285
  }
2225
2286
  // If there's an existing controller, detach it first
2226
2287
  if (existingController) {
2227
2288
  await detachController(element);
2289
+ // Light-DOM reconciliation can issue commit() and reconnected() requests
2290
+ // for the same class while the previous controller is still detaching.
2291
+ // If the other request already installed that exact source, this request
2292
+ // is redundant. Different sources retain the established rapid-switch
2293
+ // behavior and continue through the normal replacement path.
2294
+ const replacement = element[CONTROLLER_KEY];
2295
+ const replacementSource = element[CONTROLLER_NAME_KEY];
2296
+ if (replacement && replacementSource === controller) {
2297
+ if (typeof controller !== 'string')
2298
+ restoreDirectControllerAttribute(element);
2299
+ return;
2300
+ }
2228
2301
  }
2229
2302
  let ControllerClass;
2230
2303
  if (typeof controller === 'string') {
@@ -2240,13 +2313,16 @@ async function attachController(element, controller) {
2240
2313
  }
2241
2314
  else {
2242
2315
  ControllerClass = controller;
2243
- // The class channel owns the element from here on: the attribute /
2244
- // MutationObserver channel goes inert and its bookkeeping is dropped.
2245
- element[DIRECT_CONTROLLER] = true;
2246
- delete element[NATIVE_CONTROLLER];
2247
2316
  }
2248
2317
  // Create controller instance with unique ID and scope
2249
2318
  const controllerInstance = new ControllerClass();
2319
+ if (typeof controller !== 'string') {
2320
+ // Construction succeeded, so the class channel can safely take ownership.
2321
+ // Setting this before construction would leave a stale observer guard when
2322
+ // a controller constructor throws.
2323
+ element[DIRECT_CONTROLLER] = true;
2324
+ delete element[NATIVE_CONTROLLER];
2325
+ }
2250
2326
  snice.controllerIdCounter += 1;
2251
2327
  const controllerId = snice.controllerIdCounter;
2252
2328
  const scope = new ControllerScope();
@@ -2265,6 +2341,12 @@ async function attachController(element, controller) {
2265
2341
  element[CONTROLLER_KEY] = controllerInstance;
2266
2342
  element[CONTROLLER_NAME_KEY] = controller;
2267
2343
  element[CONTROLLER_OPERATIONS] = scope;
2344
+ if (typeof controller !== 'string') {
2345
+ // The class reference remains the sole attachment authority. This
2346
+ // attribute is diagnostic only; custom-element callbacks and native
2347
+ // MutationObservers are guarded from treating it as a string attachment.
2348
+ restoreDirectControllerAttribute(element);
2349
+ }
2268
2350
  // Wait for element to be ready. Race against abort (detachController) and
2269
2351
  // a 30s deadline so a caller that forgets to append the element gets a
2270
2352
  // clear error instead of an unresolvable promise.
@@ -2296,6 +2378,9 @@ async function attachController(element, controller) {
2296
2378
  // attached — otherwise a later attach short-circuits as "already attached"
2297
2379
  // and a detach would run detach() on it.
2298
2380
  if (element[CONTROLLER_KEY] === controllerInstance) {
2381
+ if (typeof controller !== 'string') {
2382
+ writeControllerAttribute(element, null);
2383
+ }
2299
2384
  delete element[CONTROLLER_KEY];
2300
2385
  delete element[CONTROLLER_NAME_KEY];
2301
2386
  delete element[CONTROLLER_OPERATIONS];
@@ -2347,6 +2432,12 @@ async function detachController(element) {
2347
2432
  // controller reassignment) finds no instance and returns, instead of running
2348
2433
  // detach() a second time on the same controller. The rest of this function
2349
2434
  // works off the locals captured above.
2435
+ if (typeof controllerSource === 'function') {
2436
+ // Remove the class channel's diagnostic marker while its guards are still
2437
+ // active. A queued native MutationObserver therefore sees no attribute and
2438
+ // cannot resurrect a registry attachment after detach.
2439
+ writeControllerAttribute(element, null);
2440
+ }
2350
2441
  delete element[CONTROLLER_KEY];
2351
2442
  delete element[CONTROLLER_NAME_KEY];
2352
2443
  delete element[CONTROLLER_OPERATIONS];
@@ -2421,8 +2512,12 @@ function useNativeElementControllers() {
2421
2512
  // attachController(el, Class)). The class channel owns the element:
2422
2513
  // attribute writes must not attach over it, and insertion sweeps must
2423
2514
  // not detach it.
2424
- if (element[DIRECT_CONTROLLER])
2515
+ if (element[DIRECT_CONTROLLER]) {
2516
+ // External writes cannot replace a class binding. Keep the DOM marker
2517
+ // honest about the class that is actually attached.
2518
+ restoreDirectControllerAttribute(element);
2425
2519
  return;
2520
+ }
2426
2521
  const controllerName = element.getAttribute('controller');
2427
2522
  const currentControllerName = element[NATIVE_CONTROLLER];
2428
2523
  // No change
@@ -4660,8 +4755,8 @@ class PropertyPart extends Part {
4660
4755
  * Accepts a controller class decorated with @controller (attached directly,
4661
4756
  * no registry lookup) or a registry name string (delegated to the attribute
4662
4757
  * channel with the exact semantics of a static controller="name"). While a
4663
- * class is bound it owns the element: the attribute/MutationObserver channel
4664
- * is inert until the class is unbound.
4758
+ * class is bound it owns the element: the decorator name is reflected for
4759
+ * inspection, while the attribute/MutationObserver attach channel stays inert.
4665
4760
  *
4666
4761
  * Renders commit while the tree is detached and connect afterwards, so
4667
4762
  * attachment happens on reconnected()/connected commits; every hook is
@@ -4700,10 +4795,6 @@ class ControllerPart extends Part {
4700
4795
  }
4701
4796
  }
4702
4797
  if (typeof next === 'function') {
4703
- // Class binding takes over — drop any attribute so the string channel
4704
- // cannot fight it.
4705
- if (this.element.hasAttribute('controller'))
4706
- this.element.removeAttribute('controller');
4707
4798
  if (this.isConnected) {
4708
4799
  this._apply(next);
4709
4800
  }
@@ -6775,6 +6866,14 @@ function applyElementFunctionality(constructor) {
6775
6866
  constructor.prototype.attributeChangedCallback = function (name, oldValue, newValue) {
6776
6867
  originalAttributeChangedCallback?.call(this, name, oldValue, newValue);
6777
6868
  if (name === 'controller') {
6869
+ // A class attachment reflects its decorator name for DOM diagnostics,
6870
+ // but the class reference remains the only attachment authority.
6871
+ if (this[CONTROLLER_ATTRIBUTE_SYNC])
6872
+ return;
6873
+ if (this[DIRECT_CONTROLLER]) {
6874
+ restoreDirectControllerAttribute(this);
6875
+ return;
6876
+ }
6778
6877
  this.controller = newValue;
6779
6878
  return;
6780
6879
  }