@brightspot/ui 1.2.0 → 1.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 (134) hide show
  1. package/dist/components/copy-to-clipboard/CopyToClipboard.d.ts +57 -0
  2. package/dist/components/copy-to-clipboard/CopyToClipboard.d.ts.map +1 -0
  3. package/dist/components/copy-to-clipboard/CopyToClipboard.js +84 -0
  4. package/dist/components/copy-to-clipboard/CopyToClipboard.js.map +1 -0
  5. package/dist/custom-elements.json +114 -0
  6. package/dist/global.d.ts +10 -0
  7. package/dist/storybook/assets/{Avatar.stories-BlxrclP0.js → Avatar.stories-DrhezTR1.js} +2 -2
  8. package/dist/storybook/assets/{AvatarGroup.stories-E3VUvBae.js → AvatarGroup.stories-DrlxT-mF.js} +1 -1
  9. package/dist/storybook/assets/{Badge.stories-f4YvPz0W.js → Badge.stories-DtJcBfOR.js} +1 -1
  10. package/dist/storybook/assets/{Button.stories-N66xrq4q.js → Button.stories-BKUfLgSY.js} +1 -1
  11. package/dist/storybook/assets/{CircularProgress.stories-zWyELtfc.js → CircularProgress.stories-dpmD-XJT.js} +1 -1
  12. package/dist/storybook/assets/ClipboardMixin.stories-C0pnQ7BY.js +228 -0
  13. package/dist/storybook/assets/Color-64QXVMR3-Dnd9S2a1.js +1 -0
  14. package/dist/storybook/assets/{Colors.stories-nEoNeHhf.js → Colors.stories-bKK25qgF.js} +1 -1
  15. package/dist/storybook/assets/ComponentStatesMixin-C2HZ9ZFb.js +1 -0
  16. package/dist/storybook/assets/ComponentStatesMixin.stories-9mRp2zuB.js +313 -0
  17. package/dist/storybook/assets/CopyToClipboard.stories-BW3oaT1i.js +277 -0
  18. package/dist/storybook/assets/Debounce.stories-BXx3CKvQ.js +199 -0
  19. package/dist/storybook/assets/{Events.stories-BP3ensxX.js → Events.stories-PBeiuWQn.js} +1 -1
  20. package/dist/storybook/assets/{Heading.stories-DGqWaBpi.js → Heading.stories-Djkl0MoC.js} +1 -1
  21. package/dist/storybook/assets/{Icon.stories-BWWjh4NZ.js → Icon.stories-Cam1fyud.js} +1 -1
  22. package/dist/storybook/assets/{LinearProgress.stories-DMVolkoE.js → LinearProgress.stories-BDNoYIJu.js} +1 -1
  23. package/dist/storybook/assets/Rtc.stories-BrTAIAi1.js +281 -0
  24. package/dist/storybook/assets/{ScrollShadow.stories-BmwSRNje.js → ScrollShadow.stories-DHcKhkag.js} +1 -1
  25. package/dist/storybook/assets/{Throttle.stories-DBj-9rhV.js → Throttle.stories-cSYT_BXu.js} +1 -1
  26. package/dist/storybook/assets/{WithTooltip-SK46ZJ2J-DW4NXFWt.js → WithTooltip-SK46ZJ2J-Df0E-KJO.js} +43 -43
  27. package/dist/storybook/assets/_commonjsHelpers-CqkleIqs.js +1 -0
  28. package/dist/storybook/assets/formatter-OMEEQ6HG-DFa_WTfb.js +1 -0
  29. package/dist/storybook/assets/{iframe-CxsKJSj-.css → iframe-BMxUFmpF.css} +1 -1
  30. package/dist/storybook/assets/{iframe-Z4F0Cgki.js → iframe-lTczLWsL.js} +76 -76
  31. package/dist/storybook/assets/index-yMswRDPh.js +1 -0
  32. package/dist/storybook/assets/onFind-C6olvKHR.js +1 -0
  33. package/dist/storybook/assets/onFind.stories-DfW54CDE.js +284 -0
  34. package/dist/storybook/assets/onRemove.stories-C7W9KyRr.js +234 -0
  35. package/dist/storybook/assets/onVisible.stories-CIl6R0q4.js +187 -0
  36. package/dist/storybook/assets/syntaxhighlighter-CAVLW7PM-DoI0ixeu.js +6 -0
  37. package/dist/storybook/iframe.html +2 -2
  38. package/dist/storybook/index.json +1 -1
  39. package/dist/storybook/project.json +1 -1
  40. package/dist/tailwind-plugin-button.js +3 -0
  41. package/dist/tailwind-plugin-button.js.map +1 -1
  42. package/dist/tailwind-plugin-button.ts +4 -0
  43. package/dist/util/ClipboardMixin.d.ts +39 -0
  44. package/dist/util/ClipboardMixin.d.ts.map +1 -0
  45. package/dist/util/ClipboardMixin.js +77 -0
  46. package/dist/util/ClipboardMixin.js.map +1 -0
  47. package/dist/util/ComponentStatesMixin.d.ts +54 -0
  48. package/dist/util/ComponentStatesMixin.d.ts.map +1 -0
  49. package/dist/util/ComponentStatesMixin.js +58 -0
  50. package/dist/util/ComponentStatesMixin.js.map +1 -0
  51. package/dist/util/EventEmitterMixin.d.ts +5 -3
  52. package/dist/util/EventEmitterMixin.d.ts.map +1 -1
  53. package/dist/util/EventEmitterMixin.js.map +1 -1
  54. package/dist/util/Socket.d.ts +29 -0
  55. package/dist/util/Socket.d.ts.map +1 -0
  56. package/dist/util/Socket.js +153 -0
  57. package/dist/util/Socket.js.map +1 -0
  58. package/dist/util/Tether.d.ts +18 -0
  59. package/dist/util/Tether.d.ts.map +1 -0
  60. package/dist/util/Tether.js +102 -0
  61. package/dist/util/Tether.js.map +1 -0
  62. package/dist/util/TetherLayout.d.ts +12 -0
  63. package/dist/util/TetherLayout.d.ts.map +1 -0
  64. package/dist/util/TetherLayout.js +121 -0
  65. package/dist/util/TetherLayout.js.map +1 -0
  66. package/dist/util/debounce.d.ts +3 -0
  67. package/dist/util/debounce.d.ts.map +1 -0
  68. package/dist/util/debounce.js +15 -0
  69. package/dist/util/debounce.js.map +1 -0
  70. package/dist/util/focusable.d.ts +9 -0
  71. package/dist/util/focusable.d.ts.map +1 -0
  72. package/dist/util/focusable.js +19 -0
  73. package/dist/util/focusable.js.map +1 -0
  74. package/dist/util/getComponentKey.d.ts +2 -0
  75. package/dist/util/getComponentKey.d.ts.map +1 -0
  76. package/dist/util/getComponentKey.js +21 -0
  77. package/dist/util/getComponentKey.js.map +1 -0
  78. package/dist/util/keyboard.d.ts +8 -0
  79. package/dist/util/keyboard.d.ts.map +1 -0
  80. package/dist/util/keyboard.js +138 -0
  81. package/dist/util/keyboard.js.map +1 -0
  82. package/dist/util/noise.d.ts +6 -0
  83. package/dist/util/noise.d.ts.map +1 -0
  84. package/dist/util/noise.js +43 -0
  85. package/dist/util/noise.js.map +1 -0
  86. package/dist/util/onFind.d.ts +11 -0
  87. package/dist/util/onFind.d.ts.map +1 -0
  88. package/dist/util/onFind.js +210 -0
  89. package/dist/util/onFind.js.map +1 -0
  90. package/dist/util/onFindOnce.d.ts +3 -0
  91. package/dist/util/onFindOnce.d.ts.map +1 -0
  92. package/dist/util/onFindOnce.js +25 -0
  93. package/dist/util/onFindOnce.js.map +1 -0
  94. package/dist/util/onRTEReady.d.ts +22 -0
  95. package/dist/util/onRTEReady.d.ts.map +1 -0
  96. package/dist/util/onRTEReady.js +69 -0
  97. package/dist/util/onRTEReady.js.map +1 -0
  98. package/dist/util/onRemove.d.ts +7 -0
  99. package/dist/util/onRemove.d.ts.map +1 -0
  100. package/dist/util/onRemove.js +24 -0
  101. package/dist/util/onRemove.js.map +1 -0
  102. package/dist/util/onVisible.d.ts +3 -0
  103. package/dist/util/onVisible.d.ts.map +1 -0
  104. package/dist/util/onVisible.js +22 -0
  105. package/dist/util/onVisible.js.map +1 -0
  106. package/dist/util/previousUntil.d.ts +2 -0
  107. package/dist/util/previousUntil.d.ts.map +1 -0
  108. package/dist/util/previousUntil.js +21 -0
  109. package/dist/util/previousUntil.js.map +1 -0
  110. package/dist/util/repaint.d.ts +3 -0
  111. package/dist/util/repaint.d.ts.map +1 -0
  112. package/dist/util/repaint.js +14 -0
  113. package/dist/util/repaint.js.map +1 -0
  114. package/dist/util/rtc.d.ts +10 -0
  115. package/dist/util/rtc.d.ts.map +1 -0
  116. package/dist/util/rtc.js +184 -0
  117. package/dist/util/rtc.js.map +1 -0
  118. package/dist/util/storage.d.ts +6 -0
  119. package/dist/util/storage.d.ts.map +1 -0
  120. package/dist/util/storage.js +18 -0
  121. package/dist/util/storage.js.map +1 -0
  122. package/dist/util/transition.d.ts +2 -0
  123. package/dist/util/transition.d.ts.map +1 -0
  124. package/dist/util/transition.js +4 -0
  125. package/dist/util/transition.js.map +1 -0
  126. package/dist/util/types.d.ts +10 -0
  127. package/dist/util/types.d.ts.map +1 -0
  128. package/dist/util/types.js +2 -0
  129. package/dist/util/types.js.map +1 -0
  130. package/package.json +7 -2
  131. package/dist/storybook/assets/Color-64QXVMR3-B3Y5c9dl.js +0 -1
  132. package/dist/storybook/assets/formatter-OMEEQ6HG-BBn014aZ.js +0 -1
  133. package/dist/storybook/assets/index-BUj5S-B7.js +0 -1
  134. package/dist/storybook/assets/syntaxhighlighter-CAVLW7PM-CsQveU1N.js +0 -6
@@ -0,0 +1 @@
1
+ import{R as o}from"./WithTooltip-SK46ZJ2J-Df0E-KJO.js";import"./preload-helper-PPVm8Dsz.js";import"./iframe-lTczLWsL.js";import"./_commonjsHelpers-CqkleIqs.js";const e={},c=o.createContext(e);function m(t){const n=o.useContext(c);return o.useMemo(function(){return typeof t=="function"?t(n):{...n,...t}},[n,t])}function s(t){let n;return t.disableParentContext?n=typeof t.components=="function"?t.components(e):t.components||e:n=m(t.components),o.createElement(c.Provider,{value:n},t.children)}export{s as MDXProvider,m as useMDXComponents};
@@ -0,0 +1 @@
1
+ import{g as J}from"./_commonjsHelpers-CqkleIqs.js";var b={exports:{}},K=b.exports,P;function X(){return P||(P=1,(function(r){(function(n,e){r.exports?r.exports=e():n.log=e()})(K,function(){var n=function(){},e="undefined",o=typeof window!==e&&typeof window.navigator!==e&&/Trident\/|MSIE /.test(window.navigator.userAgent),a=["trace","debug","info","warn","error"],s={},f=null;function I(l,c){var t=l[c];if(typeof t.bind=="function")return t.bind(l);try{return Function.prototype.bind.call(t,l)}catch{return function(){return Function.prototype.apply.apply(t,[l,arguments])}}}function q(){console.log&&(console.log.apply?console.log.apply(console,arguments):Function.prototype.apply.apply(console.log,[console,arguments])),console.trace&&console.trace()}function _(l){return l==="debug"&&(l="log"),typeof console===e?!1:l==="trace"&&o?q:console[l]!==void 0?I(console,l):console.log!==void 0?I(console,"log"):n}function v(){for(var l=this.getLevel(),c=0;c<a.length;c++){var t=a[c];this[t]=c<l?n:this.methodFactory(t,l,this.name)}if(this.log=this.debug,typeof console===e&&l<this.levels.SILENT)return"No console available for logging"}function W(l){return function(){typeof console!==e&&(v.call(this),this[l].apply(this,arguments))}}function $(l,c,t){return _(l)||W.apply(this,arguments)}function F(l,c){var t=this,w,E,d,g="loglevel";typeof l=="string"?g+=":"+l:typeof l=="symbol"&&(g=void 0);function z(i){var u=(a[i]||"silent").toUpperCase();if(!(typeof window===e||!g)){try{window.localStorage[g]=u;return}catch{}try{window.document.cookie=encodeURIComponent(g)+"="+u+";"}catch{}}}function M(){var i;if(!(typeof window===e||!g)){try{i=window.localStorage[g]}catch{}if(typeof i===e)try{var u=window.document.cookie,m=encodeURIComponent(g),S=u.indexOf(m+"=");S!==-1&&(i=/^([^;]+)/.exec(u.slice(S+m.length+1))[1])}catch{}return t.levels[i]===void 0&&(i=void 0),i}}function G(){if(!(typeof window===e||!g)){try{window.localStorage.removeItem(g)}catch{}try{window.document.cookie=encodeURIComponent(g)+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC"}catch{}}}function h(i){var u=i;if(typeof u=="string"&&t.levels[u.toUpperCase()]!==void 0&&(u=t.levels[u.toUpperCase()]),typeof u=="number"&&u>=0&&u<=t.levels.SILENT)return u;throw new TypeError("log.setLevel() called with invalid level: "+i)}t.name=l,t.levels={TRACE:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,SILENT:5},t.methodFactory=c||$,t.getLevel=function(){return d??E??w},t.setLevel=function(i,u){return d=h(i),u!==!1&&z(d),v.call(t)},t.setDefaultLevel=function(i){E=h(i),M()||t.setLevel(i,!1)},t.resetLevel=function(){d=null,G(),v.call(t)},t.enableAll=function(i){t.setLevel(t.levels.TRACE,i)},t.disableAll=function(i){t.setLevel(t.levels.SILENT,i)},t.rebuild=function(){if(f!==t&&(w=h(f.getLevel())),v.call(t),f===t)for(var i in s)s[i].rebuild()},w=h(f?f.getLevel():"WARN");var R=M();R!=null&&(d=h(R)),v.call(t)}f=new F,f.getLogger=function(c){if(typeof c!="symbol"&&typeof c!="string"||c==="")throw new TypeError("You must supply a name when creating a logger.");var t=s[c];return t||(t=s[c]=new F(c,f.methodFactory)),t};var B=typeof window!==e?window.log:void 0;return f.noConflict=function(){return typeof window!==e&&window.log===f&&(window.log=B),f},f.getLoggers=function(){return s},f.default=f,f})})(b)),b.exports}var Y=X();const H=J(Y);let Q=0;class Z{#r;#e;#t;#l;#o;constructor(n,e,o){this.#r=n,this.#e=`data-ofc${Q++}`,Array.isArray(e)||(e=[e]),this.#t=e.map(e.some(s=>s.indexOf(",")>-1)?s=>s:s=>`${s}:not([${this.#e}])`).join(","),this.#l=o;const a=e.map(s=>s.trim()).filter(s=>s.indexOf(" ")<0&&s.indexOf(",")<0);a.length===e.length&&(this.#o=a)}addTriggerElements(n,e){if(this.#r.contains(e)){e.matches(this.#t)&&n.push(e);for(const o of e.querySelectorAll(this.#t))n.push(o)}}trigger(n){if(document.readyState!=="loading")if(this.#o&&Array.isArray(n))for(const e of n)this.#o.some(o=>e.matches(o))&&this.#n(e);else for(const e of this.#r.querySelectorAll(this.#t))this.#n(e)}#n(n){if(!D(n)&&!n.hasAttribute(this.#e)){n.setAttribute(this.#e,"");try{this.#l(n)}catch(e){H.error("Failed callback!",n,e)}}}}let x=!1,C=!1,p=!1,y=[],A;const T=[];function D(r){return r instanceof Element?r.closest(".CIG-wordCount")!==null||r.closest(".ContentEdit-previewDisplay")!==null||r.closest(".ContentLabel")!==null||r.closest(".PreviewFrame-typeDisplay")!==null||r.closest(".ProseMirrorToolbar")!==null||r.closest(".ProseMirror")!==null||r.closest(".ProseMirrorContainer")!==null||r.closest(".ProseMirror-fullscreen-container")!==null||r.closest(".ProseMirror-comments")!==null||r.closest(".RichTextEditor")!==null||r.closest(".WorkInProgressSaveStatus")!==null||r.closest("#aria-live-container")!==null||r.closest(".widget-urlsAutomatic")!==null:!1}const N=Array.prototype.every,O=r=>r.nodeType===Node.TEXT_NODE;function L(r){if(x){C=!0;return}const n=Array.isArray(r),e=[];if(n){for(const o of r){const a=o.target;if(!D(a))switch(o.type){case"attributes":o.oldValue!==a.getAttribute(o.attributeName)&&e.push(o);break;case"childList":(!N.call(o.addedNodes,O)||!N.call(o.removedNodes,O))&&e.push(o);break}}if(e.length===0)return}if(e.length>500&&(p=!0),!p)if(n)for(const o of e){const a=o.target;switch(o.type){case"attributes":y.push(a);break;case"childList":for(const s of T)s.addTriggerElements(y,a);break}}else p=!0;(p||y.length>0)&&!A&&(A=window.requestAnimationFrame(()=>{const o=p?void 0:y;p=!1,y=[],A=0,T.forEach(a=>a.trigger(o))}))}function U(){document.documentElement.hidden=!1,L(),new MutationObserver(L).observe(document,{attributes:!0,attributeFilter:["class","data-bsp-autosubmit","data-chart-type","data-code-type","data-internal-name","data-tab","name","rel","target"],attributeOldValue:!0,childList:!0,subtree:!0})}document.documentElement.hidden=!0;document.readyState==="loading"?document.addEventListener("DOMContentLoaded",U):U();function k(r,n,e){let o,a;typeof e<"u"?(o=r,a=n):(o=document,a=r,e=n);const s=new Z(o,a,e);s.trigger(),T.push(s)}k.triggerCallbacks=L;k.pause=()=>{x=!0};k.resume=()=>{x=!1,C&&(C=!1,setTimeout(L,100))};export{k as o};
@@ -0,0 +1,284 @@
1
+ import{x as r}from"./iframe-lTczLWsL.js";import{o as l}from"./onFind-C6olvKHR.js";import"./preload-helper-PPVm8Dsz.js";import"./_commonjsHelpers-CqkleIqs.js";const v={title:"Utilities/onFind",tags:["autodocs"],parameters:{docs:{subtitle:"The `onFind` utility observes DOM mutations and executes callbacks when elements matching specified selectors appear. Uses MutationObserver internally to efficiently track element additions and attribute changes."},controls:{expanded:!0}},argTypes:{selector:{control:{type:"text"},description:"CSS selector to watch for"}},args:{selector:".dynamic-item"}},i={render:m=>{const t=`onfind-${Math.random().toString(36).substring(2,9)}`,c=`.dynamic-item-${t}`;let o=0,a=0;const d=()=>{const e=document.getElementById(`${t}-items-count`),n=document.getElementById(`${t}-found-count`);e&&(e.textContent=String(o)),n&&(n.textContent=String(a))};return l(c,e=>{a++,d(),e.classList.add("ring-2","ring-success-500")}),r`
2
+ <div class="space-y-4">
3
+ <div class="text-base">
4
+ <p class="mb-2">
5
+ Click "Add Item" to dynamically create elements. The onFind observer detects them and highlights them with a
6
+ green border.
7
+ </p>
8
+ </div>
9
+
10
+ <div class="flex gap-2">
11
+ <button @click=${()=>{o++;const e=document.getElementById(`${t}-container`);if(e){const n=document.createElement("div");n.className=`dynamic-item-${t} rounded border bg-white p-4`,n.textContent=`Item ${o}`,e.appendChild(n)}d()}} class="bg-primary-500 hover:bg-primary-600 rounded px-4 py-2 text-white">
12
+ Add Item
13
+ </button>
14
+ <button @click=${()=>{o=0,a=0;const e=document.getElementById(`${t}-container`);e&&(e.innerHTML=""),d()}} class="rounded bg-gray-200 px-4 py-2 hover:bg-gray-300">Clear All</button>
15
+ </div>
16
+
17
+ <div id="${t}-container" class="min-h-32 space-y-2 rounded border-2 border-gray-300 bg-gray-50 p-4">
18
+ <div class="text-sm text-gray-500">Items will appear here...</div>
19
+ </div>
20
+
21
+ <div class="flex justify-around">
22
+ <div>
23
+ <div class="text-xs text-gray-500">Items created</div>
24
+ <div id="${t}-items-count" class="text-2xl font-bold text-gray-900">0</div>
25
+ </div>
26
+ <div>
27
+ <div class="text-xs text-gray-500">Items detected by onFind</div>
28
+ <div id="${t}-found-count" class="text-primary-600 text-2xl font-bold">0</div>
29
+ </div>
30
+ </div>
31
+ </div>
32
+ `},parameters:{docs:{description:{story:"Interactive example showing onFind detecting dynamically added elements. Elements are automatically highlighted when detected."}}}},s={render:()=>r`
33
+ <div class="space-y-4 text-sm">
34
+ <div>
35
+ <h3 class="mb-2 font-bold">Basic Usage</h3>
36
+ <pre
37
+ class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"
38
+ ><code>import onFind from '@brightspot/ui/dist/util/onFind.js'
39
+
40
+ // Watch for elements globally
41
+ onFind('.my-component', (element) => {
42
+ console.log('Found element:', element)
43
+ // Initialize component
44
+ })
45
+
46
+ // Watch within a specific root element
47
+ const container = document.querySelector('#container')
48
+ onFind(container, '.my-widget', (element) => {
49
+ // Initialize widget
50
+ })</code></pre>
51
+ </div>
52
+
53
+ <div>
54
+ <h3 class="mb-2 font-bold">Multiple Selectors</h3>
55
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Watch for multiple selectors at once
56
+ onFind(['.button', '.input', '.select'], (element) => {
57
+ if (element.matches('.button')) {
58
+ // Handle button
59
+ } else if (element.matches('.input')) {
60
+ // Handle input
61
+ }
62
+ })</code></pre>
63
+ </div>
64
+
65
+ <div>
66
+ <h3 class="mb-2 font-bold">Pause and Resume</h3>
67
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Pause observations temporarily
68
+ onFind.pause()
69
+
70
+ // Make bulk DOM changes without triggering callbacks
71
+ // ...
72
+
73
+ // Resume observations
74
+ onFind.resume()</code></pre>
75
+ </div>
76
+
77
+ <div>
78
+ <h3 class="mb-2 font-bold">Common Use Cases</h3>
79
+ <ul class="list-inside list-disc space-y-1 text-gray-700">
80
+ <li>Initialize components when they appear in the DOM</li>
81
+ <li>Attach event listeners to dynamically created elements</li>
82
+ <li>Enhance server-rendered content progressively</li>
83
+ <li>Detect and respond to attribute changes</li>
84
+ <li>Apply transformations to newly added content</li>
85
+ </ul>
86
+ </div>
87
+
88
+ <div>
89
+ <h3 class="mb-2 font-bold">Parameters</h3>
90
+ <ul class="space-y-2">
91
+ <li>
92
+ <code class="rounded bg-gray-200 px-1">root</code> (ParentNode, optional): Root element to observe. Defaults
93
+ to document.
94
+ </li>
95
+ <li>
96
+ <code class="rounded bg-gray-200 px-1">selectors</code> (string | string[]): CSS selector(s) to watch for
97
+ </li>
98
+ <li>
99
+ <code class="rounded bg-gray-200 px-1">fn</code> (function): Callback executed when matching elements are
100
+ found
101
+ </li>
102
+ </ul>
103
+ </div>
104
+
105
+ <div>
106
+ <h3 class="mb-2 font-bold">How It Works</h3>
107
+ <p class="text-gray-700">
108
+ onFind uses MutationObserver to efficiently watch for DOM changes. Each callback is executed only once per
109
+ element using data attributes to track already-processed elements. The observer watches for childList
110
+ mutations and specific attribute changes, with built-in blacklisting for editor containers.
111
+ </p>
112
+ </div>
113
+ </div>
114
+ `,parameters:{docs:{description:{story:"Code examples and documentation for using the onFind utility."}}}};i.parameters={...i.parameters,docs:{...i.parameters?.docs,source:{originalSource:`{
115
+ render: args => {
116
+ const instanceId = \`onfind-\${Math.random().toString(36).substring(2, 9)}\`;
117
+ const uniqueSelector = \`.dynamic-item-\${instanceId}\`;
118
+ let itemCount = 0;
119
+ let foundCount = 0;
120
+ const updateCounts = () => {
121
+ const itemsEl = document.getElementById(\`\${instanceId}-items-count\`);
122
+ const foundEl = document.getElementById(\`\${instanceId}-found-count\`);
123
+ if (itemsEl) itemsEl.textContent = String(itemCount);
124
+ if (foundEl) foundEl.textContent = String(foundCount);
125
+ };
126
+
127
+ // Set up onFind observer for dynamic items with unique selector
128
+ onFind(uniqueSelector, (element: HTMLElement) => {
129
+ foundCount++;
130
+ updateCounts();
131
+ element.classList.add('ring-2', 'ring-success-500');
132
+ });
133
+ const addItem = () => {
134
+ itemCount++;
135
+ const container = document.getElementById(\`\${instanceId}-container\`);
136
+ if (container) {
137
+ const item = document.createElement('div');
138
+ item.className = \`dynamic-item-\${instanceId} rounded border bg-white p-4\`;
139
+ item.textContent = \`Item \${itemCount}\`;
140
+ container.appendChild(item);
141
+ }
142
+ updateCounts();
143
+ };
144
+ const clearItems = () => {
145
+ itemCount = 0;
146
+ foundCount = 0;
147
+ const container = document.getElementById(\`\${instanceId}-container\`);
148
+ if (container) {
149
+ container.innerHTML = '';
150
+ }
151
+ updateCounts();
152
+ };
153
+ return html\`
154
+ <div class="space-y-4">
155
+ <div class="text-base">
156
+ <p class="mb-2">
157
+ Click "Add Item" to dynamically create elements. The onFind observer detects them and highlights them with a
158
+ green border.
159
+ </p>
160
+ </div>
161
+
162
+ <div class="flex gap-2">
163
+ <button @click=\${addItem} class="bg-primary-500 hover:bg-primary-600 rounded px-4 py-2 text-white">
164
+ Add Item
165
+ </button>
166
+ <button @click=\${clearItems} class="rounded bg-gray-200 px-4 py-2 hover:bg-gray-300">Clear All</button>
167
+ </div>
168
+
169
+ <div id="\${instanceId}-container" class="min-h-32 space-y-2 rounded border-2 border-gray-300 bg-gray-50 p-4">
170
+ <div class="text-sm text-gray-500">Items will appear here...</div>
171
+ </div>
172
+
173
+ <div class="flex justify-around">
174
+ <div>
175
+ <div class="text-xs text-gray-500">Items created</div>
176
+ <div id="\${instanceId}-items-count" class="text-2xl font-bold text-gray-900">0</div>
177
+ </div>
178
+ <div>
179
+ <div class="text-xs text-gray-500">Items detected by onFind</div>
180
+ <div id="\${instanceId}-found-count" class="text-primary-600 text-2xl font-bold">0</div>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ \`;
185
+ },
186
+ parameters: {
187
+ docs: {
188
+ description: {
189
+ story: \`Interactive example showing onFind detecting dynamically added elements. Elements are automatically highlighted when detected.\`
190
+ }
191
+ }
192
+ }
193
+ }`,...i.parameters?.docs?.source}}};s.parameters={...s.parameters,docs:{...s.parameters?.docs,source:{originalSource:`{
194
+ render: () => html\`
195
+ <div class="space-y-4 text-sm">
196
+ <div>
197
+ <h3 class="mb-2 font-bold">Basic Usage</h3>
198
+ <pre
199
+ class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"
200
+ ><code>import onFind from '@brightspot/ui/dist/util/onFind.js'
201
+
202
+ // Watch for elements globally
203
+ onFind('.my-component', (element) => {
204
+ console.log('Found element:', element)
205
+ // Initialize component
206
+ })
207
+
208
+ // Watch within a specific root element
209
+ const container = document.querySelector('#container')
210
+ onFind(container, '.my-widget', (element) => {
211
+ // Initialize widget
212
+ })</code></pre>
213
+ </div>
214
+
215
+ <div>
216
+ <h3 class="mb-2 font-bold">Multiple Selectors</h3>
217
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Watch for multiple selectors at once
218
+ onFind(['.button', '.input', '.select'], (element) => {
219
+ if (element.matches('.button')) {
220
+ // Handle button
221
+ } else if (element.matches('.input')) {
222
+ // Handle input
223
+ }
224
+ })</code></pre>
225
+ </div>
226
+
227
+ <div>
228
+ <h3 class="mb-2 font-bold">Pause and Resume</h3>
229
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Pause observations temporarily
230
+ onFind.pause()
231
+
232
+ // Make bulk DOM changes without triggering callbacks
233
+ // ...
234
+
235
+ // Resume observations
236
+ onFind.resume()</code></pre>
237
+ </div>
238
+
239
+ <div>
240
+ <h3 class="mb-2 font-bold">Common Use Cases</h3>
241
+ <ul class="list-inside list-disc space-y-1 text-gray-700">
242
+ <li>Initialize components when they appear in the DOM</li>
243
+ <li>Attach event listeners to dynamically created elements</li>
244
+ <li>Enhance server-rendered content progressively</li>
245
+ <li>Detect and respond to attribute changes</li>
246
+ <li>Apply transformations to newly added content</li>
247
+ </ul>
248
+ </div>
249
+
250
+ <div>
251
+ <h3 class="mb-2 font-bold">Parameters</h3>
252
+ <ul class="space-y-2">
253
+ <li>
254
+ <code class="rounded bg-gray-200 px-1">root</code> (ParentNode, optional): Root element to observe. Defaults
255
+ to document.
256
+ </li>
257
+ <li>
258
+ <code class="rounded bg-gray-200 px-1">selectors</code> (string | string[]): CSS selector(s) to watch for
259
+ </li>
260
+ <li>
261
+ <code class="rounded bg-gray-200 px-1">fn</code> (function): Callback executed when matching elements are
262
+ found
263
+ </li>
264
+ </ul>
265
+ </div>
266
+
267
+ <div>
268
+ <h3 class="mb-2 font-bold">How It Works</h3>
269
+ <p class="text-gray-700">
270
+ onFind uses MutationObserver to efficiently watch for DOM changes. Each callback is executed only once per
271
+ element using data attributes to track already-processed elements. The observer watches for childList
272
+ mutations and specific attribute changes, with built-in blacklisting for editor containers.
273
+ </p>
274
+ </div>
275
+ </div>
276
+ \`,
277
+ parameters: {
278
+ docs: {
279
+ description: {
280
+ story: \`Code examples and documentation for using the onFind utility.\`
281
+ }
282
+ }
283
+ }
284
+ }`,...s.parameters?.docs?.source}}};const f=["Interactive","UsageExample"];export{i as Interactive,s as UsageExample,f as __namedExportsOrder,v as default};
@@ -0,0 +1,234 @@
1
+ import{x as p}from"./iframe-lTczLWsL.js";import"./preload-helper-PPVm8Dsz.js";let l=!1;function m(e,o){const s=new MutationObserver(r=>{for(const v of r)for(const n of v.removedNodes)n.contains(e)&&!l&&(s.disconnect(),o())});s.observe(document,{childList:!0,subtree:!0})}m.pause=()=>{l=!0};m.resume=()=>{l=!1};const b={title:"Utilities/onRemove",tags:["autodocs"],parameters:{docs:{subtitle:"The `onRemove` utility triggers a callback when a DOM element is removed from the document. Uses MutationObserver to watch for removals, with global pause/resume support."},controls:{expanded:!0}},argTypes:{selector:{control:{type:"text"},description:"CSS selector of element to watch"}},args:{selector:".watched-item"}},i={render:()=>{const e=`onremove-${Math.random().toString(36).substring(2,9)}`;let o=0,s=0;const r=()=>{const n=document.getElementById(`${e}-items-count`),t=document.getElementById(`${e}-removed-count`);n&&(n.textContent=String(o)),t&&(t.textContent=String(s))};return p`
2
+ <div class="space-y-4">
3
+ <div class="text-base">
4
+ <p class="mb-2">
5
+ Click "Add Item" to create elements, then click "Remove" on each item. The onRemove callback detects
6
+ removals and logs them.
7
+ </p>
8
+ </div>
9
+
10
+ <div class="flex gap-2">
11
+ <button @click=${()=>{o++;const n=document.getElementById(`${e}-container`);if(!n)return;const t=document.createElement("div"),u=o;t.className="flex items-center justify-between rounded border bg-white p-4",t.innerHTML=`<span>Item ${u}</span>`;const d=document.createElement("button");d.className="rounded bg-red-100 px-2 py-1 text-xs text-red-700 hover:bg-red-200",d.textContent="Remove",d.addEventListener("click",()=>t.remove()),t.appendChild(d),n.appendChild(t),m(t,()=>{s++,o--,r();const g=document.getElementById(`${e}-log`);if(g){const c=document.createElement("div");c.className="text-sm text-gray-600",c.textContent=`Item ${u} removed at ${new Date().toLocaleTimeString()}`,g.prepend(c)}}),r()}} class="bg-primary-500 hover:bg-primary-600 rounded px-4 py-2 text-white">
12
+ Add Item
13
+ </button>
14
+ </div>
15
+
16
+ <div id="${e}-container" class="min-h-32 space-y-2 rounded border-2 border-gray-300 bg-gray-50 p-4">
17
+ <div class="text-sm text-gray-500">Items will appear here...</div>
18
+ </div>
19
+
20
+ <div class="flex justify-around">
21
+ <div>
22
+ <div class="text-xs text-gray-500">Active items</div>
23
+ <div id="${e}-items-count" class="text-2xl font-bold text-gray-900">0</div>
24
+ </div>
25
+ <div>
26
+ <div class="text-xs text-gray-500">Removals detected</div>
27
+ <div id="${e}-removed-count" class="text-primary-600 text-2xl font-bold">0</div>
28
+ </div>
29
+ </div>
30
+
31
+ <div>
32
+ <h4 class="mb-1 text-xs font-bold text-gray-500">Removal Log</h4>
33
+ <div id="${e}-log" class="max-h-32 overflow-y-auto rounded border border-gray-200 bg-gray-50 p-2">
34
+ <div class="text-sm text-gray-400">No removals yet.</div>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ `},parameters:{docs:{description:{story:"Interactive example showing onRemove detecting when elements are removed from the DOM. Add items, then remove them to see the callback fire."}}}},a={render:()=>p`
39
+ <div class="space-y-4 text-sm">
40
+ <div>
41
+ <h3 class="mb-2 font-bold">Basic Usage</h3>
42
+ <pre
43
+ class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"
44
+ ><code>import onRemove from '@brightspot/ui/dist/util/onRemove.js'
45
+
46
+ // Clean up when element is removed
47
+ const widget = document.querySelector('.my-widget')
48
+ onRemove(widget, () => {
49
+ console.log('Widget was removed')
50
+ // Tear down event listeners, intervals, etc.
51
+ })</code></pre>
52
+ </div>
53
+
54
+ <div>
55
+ <h3 class="mb-2 font-bold">Pause and Resume</h3>
56
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Pause during bulk DOM operations
57
+ onRemove.pause()
58
+
59
+ // Move elements around without triggering callbacks
60
+ container.innerHTML = ''
61
+ container.append(...reorderedElements)
62
+
63
+ // Resume watching
64
+ onRemove.resume()</code></pre>
65
+ </div>
66
+
67
+ <div>
68
+ <h3 class="mb-2 font-bold">Common Use Cases</h3>
69
+ <ul class="list-inside list-disc space-y-1 text-gray-700">
70
+ <li>Cleaning up event listeners when elements are removed</li>
71
+ <li>Cancelling intervals or timeouts tied to DOM elements</li>
72
+ <li>Disconnecting observers or WebSocket connections</li>
73
+ <li>Releasing resources when components are destroyed</li>
74
+ </ul>
75
+ </div>
76
+
77
+ <div>
78
+ <h3 class="mb-2 font-bold">Parameters</h3>
79
+ <ul class="space-y-2">
80
+ <li><code class="rounded bg-gray-200 px-1">element</code> (Element): The DOM element to watch for removal</li>
81
+ <li>
82
+ <code class="rounded bg-gray-200 px-1">callback</code> (function): Called once when the element is removed
83
+ from the document
84
+ </li>
85
+ </ul>
86
+ </div>
87
+ </div>
88
+ `,parameters:{docs:{description:{story:"Code examples and documentation for using the onRemove utility."}}}};i.parameters={...i.parameters,docs:{...i.parameters?.docs,source:{originalSource:`{
89
+ render: () => {
90
+ const instanceId = \`onremove-\${Math.random().toString(36).substring(2, 9)}\`;
91
+ let itemCount = 0;
92
+ let removeCount = 0;
93
+ const updateCounts = () => {
94
+ const itemsEl = document.getElementById(\`\${instanceId}-items-count\`);
95
+ const removedEl = document.getElementById(\`\${instanceId}-removed-count\`);
96
+ if (itemsEl) itemsEl.textContent = String(itemCount);
97
+ if (removedEl) removedEl.textContent = String(removeCount);
98
+ };
99
+ const addItem = () => {
100
+ itemCount++;
101
+ const container = document.getElementById(\`\${instanceId}-container\`);
102
+ if (!container) return;
103
+ const item = document.createElement('div');
104
+ const itemNum = itemCount;
105
+ item.className = 'flex items-center justify-between rounded border bg-white p-4';
106
+ item.innerHTML = \`<span>Item \${itemNum}</span>\`;
107
+ const removeBtn = document.createElement('button');
108
+ removeBtn.className = 'rounded bg-red-100 px-2 py-1 text-xs text-red-700 hover:bg-red-200';
109
+ removeBtn.textContent = 'Remove';
110
+ removeBtn.addEventListener('click', () => item.remove());
111
+ item.appendChild(removeBtn);
112
+ container.appendChild(item);
113
+
114
+ // Watch for this element's removal
115
+ onRemove(item, () => {
116
+ removeCount++;
117
+ itemCount--;
118
+ updateCounts();
119
+ const log = document.getElementById(\`\${instanceId}-log\`);
120
+ if (log) {
121
+ const entry = document.createElement('div');
122
+ entry.className = 'text-sm text-gray-600';
123
+ entry.textContent = \`Item \${itemNum} removed at \${new Date().toLocaleTimeString()}\`;
124
+ log.prepend(entry);
125
+ }
126
+ });
127
+ updateCounts();
128
+ };
129
+ return html\`
130
+ <div class="space-y-4">
131
+ <div class="text-base">
132
+ <p class="mb-2">
133
+ Click "Add Item" to create elements, then click "Remove" on each item. The onRemove callback detects
134
+ removals and logs them.
135
+ </p>
136
+ </div>
137
+
138
+ <div class="flex gap-2">
139
+ <button @click=\${addItem} class="bg-primary-500 hover:bg-primary-600 rounded px-4 py-2 text-white">
140
+ Add Item
141
+ </button>
142
+ </div>
143
+
144
+ <div id="\${instanceId}-container" class="min-h-32 space-y-2 rounded border-2 border-gray-300 bg-gray-50 p-4">
145
+ <div class="text-sm text-gray-500">Items will appear here...</div>
146
+ </div>
147
+
148
+ <div class="flex justify-around">
149
+ <div>
150
+ <div class="text-xs text-gray-500">Active items</div>
151
+ <div id="\${instanceId}-items-count" class="text-2xl font-bold text-gray-900">0</div>
152
+ </div>
153
+ <div>
154
+ <div class="text-xs text-gray-500">Removals detected</div>
155
+ <div id="\${instanceId}-removed-count" class="text-primary-600 text-2xl font-bold">0</div>
156
+ </div>
157
+ </div>
158
+
159
+ <div>
160
+ <h4 class="mb-1 text-xs font-bold text-gray-500">Removal Log</h4>
161
+ <div id="\${instanceId}-log" class="max-h-32 overflow-y-auto rounded border border-gray-200 bg-gray-50 p-2">
162
+ <div class="text-sm text-gray-400">No removals yet.</div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+ \`;
167
+ },
168
+ parameters: {
169
+ docs: {
170
+ description: {
171
+ story: \`Interactive example showing onRemove detecting when elements are removed from the DOM. Add items, then remove them to see the callback fire.\`
172
+ }
173
+ }
174
+ }
175
+ }`,...i.parameters?.docs?.source}}};a.parameters={...a.parameters,docs:{...a.parameters?.docs,source:{originalSource:`{
176
+ render: () => html\`
177
+ <div class="space-y-4 text-sm">
178
+ <div>
179
+ <h3 class="mb-2 font-bold">Basic Usage</h3>
180
+ <pre
181
+ class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"
182
+ ><code>import onRemove from '@brightspot/ui/dist/util/onRemove.js'
183
+
184
+ // Clean up when element is removed
185
+ const widget = document.querySelector('.my-widget')
186
+ onRemove(widget, () => {
187
+ console.log('Widget was removed')
188
+ // Tear down event listeners, intervals, etc.
189
+ })</code></pre>
190
+ </div>
191
+
192
+ <div>
193
+ <h3 class="mb-2 font-bold">Pause and Resume</h3>
194
+ <pre class="overflow-x-auto rounded bg-gray-900 p-4 text-gray-100"><code>// Pause during bulk DOM operations
195
+ onRemove.pause()
196
+
197
+ // Move elements around without triggering callbacks
198
+ container.innerHTML = ''
199
+ container.append(...reorderedElements)
200
+
201
+ // Resume watching
202
+ onRemove.resume()</code></pre>
203
+ </div>
204
+
205
+ <div>
206
+ <h3 class="mb-2 font-bold">Common Use Cases</h3>
207
+ <ul class="list-inside list-disc space-y-1 text-gray-700">
208
+ <li>Cleaning up event listeners when elements are removed</li>
209
+ <li>Cancelling intervals or timeouts tied to DOM elements</li>
210
+ <li>Disconnecting observers or WebSocket connections</li>
211
+ <li>Releasing resources when components are destroyed</li>
212
+ </ul>
213
+ </div>
214
+
215
+ <div>
216
+ <h3 class="mb-2 font-bold">Parameters</h3>
217
+ <ul class="space-y-2">
218
+ <li><code class="rounded bg-gray-200 px-1">element</code> (Element): The DOM element to watch for removal</li>
219
+ <li>
220
+ <code class="rounded bg-gray-200 px-1">callback</code> (function): Called once when the element is removed
221
+ from the document
222
+ </li>
223
+ </ul>
224
+ </div>
225
+ </div>
226
+ \`,
227
+ parameters: {
228
+ docs: {
229
+ description: {
230
+ story: \`Code examples and documentation for using the onRemove utility.\`
231
+ }
232
+ }
233
+ }
234
+ }`,...a.parameters?.docs?.source}}};const y=["Interactive","UsageExample"];export{i as Interactive,a as UsageExample,y as __namedExportsOrder,b as default};