retold-data-service 2.1.5 → 2.1.6

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.
@@ -1530,12 +1530,18 @@ fResolve(pResult);}/**
1530
1530
  * a rect-like { left, top, width, height } anchor (handy for context menus).
1531
1531
  * @param {object} pOptions
1532
1532
  * @param {Array} pOptions.items - [{ Hash, Label, Style?, Disabled?, Tooltip?, Icon?, Separator? }]
1533
- * @param {string} [pOptions.align] - 'left'|'right' (default 'left')
1533
+ * @param {string} [pOptions.ContentHTML] - Free-form HTML body for the popover, rendered
1534
+ * verbatim via innerHTML INSTEAD of building a menu from items[]. When set, the element is
1535
+ * a plain anchored popover (no role=menu / keyboard item nav); outside-click, Escape,
1536
+ * auto-flip and reposition still apply. Sanitize untrusted content. items is ignored.
1537
+ * @param {string} [pOptions.align] - 'left'|'right'|'center' (default 'left')
1534
1538
  * @param {string} [pOptions.position]- 'auto'|'below'|'above' (default 'auto')
1535
1539
  * @param {string} [pOptions.minWidth]- CSS minWidth (default: anchor width if known, else '160px')
1540
+ * @param {string} [pOptions.maxWidth]- CSS maxWidth (default unset; the base menu caps at 360px,
1541
+ * the --content variant uncaps — set this for wide rich-content popovers)
1536
1542
  * @param {string} [pOptions.maxHeight]- CSS maxHeight (default '60vh')
1537
1543
  * @param {string} [pOptions.className]- extra class(es) for the menu element
1538
- * @param {boolean} [pOptions.closeOnSelect] - default true
1544
+ * @param {boolean} [pOptions.closeOnSelect] - default true (no-op in ContentHTML mode)
1539
1545
  * @param {function} [pOptions.onSelect]- called with (Hash, Item) on selection
1540
1546
  * @param {function} [pOptions.onClose] - called after dismiss
1541
1547
  * @returns {Promise<{Hash: string, Item: object}|null>}
@@ -1559,7 +1565,21 @@ setTimeout(()=>{this._focusFirstEnabled(tmpMenu);},0);this._activeMenu={element:
1559
1565
  // ─────────────────────────────────────────────
1560
1566
  _resolveAnchor(pAnchor){if(!pAnchor){return null;}if(typeof pAnchor==='string'){return document.querySelector(pAnchor);}if(pAnchor.nodeType===1){return pAnchor;}// rect-like — no element to attach focus / outside-click ignore to,
1561
1567
  // but that's fine, the caller knows what they're doing.
1562
- return null;}_anchorRect(pAnchor,pAnchorEl){if(pAnchorEl&&typeof pAnchorEl.getBoundingClientRect==='function'){return pAnchorEl.getBoundingClientRect();}if(pAnchor&&typeof pAnchor==='object'&&typeof pAnchor.left==='number'&&typeof pAnchor.top==='number'){return{left:pAnchor.left,top:pAnchor.top,width:pAnchor.width||0,height:pAnchor.height||0,right:pAnchor.left+(pAnchor.width||0),bottom:pAnchor.top+(pAnchor.height||0)};}return null;}_buildMenu(pItems,pOptions){let tmpId=this._modal._nextId();let tmpMenu=document.createElement('div');tmpMenu.className='pict-modal-dropdown';if(pOptions.className){tmpMenu.className+=' '+pOptions.className;}tmpMenu.id='pict-modal-dropdown-'+tmpId;tmpMenu.setAttribute('role','menu');tmpMenu.style.maxHeight=pOptions.maxHeight;let tmpHtml='';for(let i=0;i<pItems.length;i++){let tmpItem=pItems[i];if(tmpItem.Separator){tmpHtml+='<div class="pict-modal-dropdown-separator" role="separator"></div>';continue;}if(tmpItem.Header){tmpHtml+='<div class="pict-modal-dropdown-header">'+this._escapeHTML(tmpItem.Header)+'</div>';continue;}let tmpCls='pict-modal-dropdown-item';if(tmpItem.Style){tmpCls+=' pict-modal-dropdown-item--'+tmpItem.Style;}if(tmpItem.Disabled){tmpCls+=' pict-modal-dropdown-item--disabled';}let tmpAttrs=''+' data-pict-modal-dropdown-item'+' data-index="'+i+'"'+' data-hash="'+this._escapeHTML(tmpItem.Hash||'')+'"'+' role="menuitem"'+' tabindex="-1"';if(tmpItem.Disabled){tmpAttrs+=' aria-disabled="true" data-disabled';}if(tmpItem.Tooltip){tmpAttrs+=' title="'+this._escapeHTML(tmpItem.Tooltip)+'"';}let tmpIcon=tmpItem.Icon?'<span class="pict-modal-dropdown-item-icon">'+tmpItem.Icon+'</span>':'';let tmpHint=tmpItem.Hint?'<span class="pict-modal-dropdown-item-hint">'+this._escapeHTML(tmpItem.Hint)+'</span>':'';tmpHtml+='<div class="'+tmpCls+'"'+tmpAttrs+'>'+tmpIcon+'<span class="pict-modal-dropdown-item-label">'+this._escapeHTML(tmpItem.Label||'')+'</span>'+tmpHint+'</div>';}tmpMenu.innerHTML=tmpHtml;return tmpMenu;}_positionMenu(pMenu,pAnchorRect,pOptions){// Apply min-width before measuring so the menu's natural size accounts
1568
+ return null;}_anchorRect(pAnchor,pAnchorEl){if(pAnchorEl&&typeof pAnchorEl.getBoundingClientRect==='function'){return pAnchorEl.getBoundingClientRect();}if(pAnchor&&typeof pAnchor==='object'&&typeof pAnchor.left==='number'&&typeof pAnchor.top==='number'){return{left:pAnchor.left,top:pAnchor.top,width:pAnchor.width||0,height:pAnchor.height||0,right:pAnchor.left+(pAnchor.width||0),bottom:pAnchor.top+(pAnchor.height||0)};}return null;}/**
1569
+ * True when the value is usable as ContentHTML — a primitive string or a
1570
+ * boxed String object (some template engines hand back `new String(...)`,
1571
+ * which is `typeof 'object'` and would otherwise slip past the guard).
1572
+ *
1573
+ * @param {*} pValue
1574
+ * @returns {boolean}
1575
+ */_isContentHTML(pValue){return typeof pValue==='string'||pValue instanceof String;}_buildMenu(pItems,pOptions){let tmpId=this._modal._nextId();let tmpMenu=document.createElement('div');tmpMenu.className='pict-modal-dropdown';// Free-form content popovers carry a modifier so the host can reset the
1576
+ // menu-item chrome (padding / max-width) and style the body itself.
1577
+ if(this._isContentHTML(pOptions.ContentHTML)){tmpMenu.className+=' pict-modal-dropdown--content';}if(pOptions.className){tmpMenu.className+=' '+pOptions.className;}tmpMenu.id='pict-modal-dropdown-'+tmpId;tmpMenu.style.maxHeight=pOptions.maxHeight;if(pOptions.maxWidth){tmpMenu.style.maxWidth=pOptions.maxWidth;}// ContentHTML mode: render the caller's HTML verbatim instead of building
1578
+ // a menu from items[]. This is a free-form anchored popover (e.g. a rich
1579
+ // info card, or a pre-rendered template menu) — not a role=menu list, so
1580
+ // we skip the menu role and the per-item keyboard semantics. Outside-click
1581
+ // / Escape / auto-flip / reposition all still apply from dropdown().
1582
+ if(this._isContentHTML(pOptions.ContentHTML)){tmpMenu.innerHTML=pOptions.ContentHTML;return tmpMenu;}tmpMenu.setAttribute('role','menu');let tmpHtml='';for(let i=0;i<pItems.length;i++){let tmpItem=pItems[i];if(tmpItem.Separator){tmpHtml+='<div class="pict-modal-dropdown-separator" role="separator"></div>';continue;}if(tmpItem.Header){tmpHtml+='<div class="pict-modal-dropdown-header">'+this._escapeHTML(tmpItem.Header)+'</div>';continue;}let tmpCls='pict-modal-dropdown-item';if(tmpItem.Style){tmpCls+=' pict-modal-dropdown-item--'+tmpItem.Style;}if(tmpItem.Disabled){tmpCls+=' pict-modal-dropdown-item--disabled';}let tmpAttrs=''+' data-pict-modal-dropdown-item'+' data-index="'+i+'"'+' data-hash="'+this._escapeHTML(tmpItem.Hash||'')+'"'+' role="menuitem"'+' tabindex="-1"';if(tmpItem.Disabled){tmpAttrs+=' aria-disabled="true" data-disabled';}if(tmpItem.Tooltip){tmpAttrs+=' title="'+this._escapeHTML(tmpItem.Tooltip)+'"';}let tmpIcon=tmpItem.Icon?'<span class="pict-modal-dropdown-item-icon">'+tmpItem.Icon+'</span>':'';let tmpHint=tmpItem.Hint?'<span class="pict-modal-dropdown-item-hint">'+this._escapeHTML(tmpItem.Hint)+'</span>':'';tmpHtml+='<div class="'+tmpCls+'"'+tmpAttrs+'>'+tmpIcon+'<span class="pict-modal-dropdown-item-label">'+this._escapeHTML(tmpItem.Label||'')+'</span>'+tmpHint+'</div>';}tmpMenu.innerHTML=tmpHtml;return tmpMenu;}_positionMenu(pMenu,pAnchorRect,pOptions){// Apply min-width before measuring so the menu's natural size accounts
1563
1583
  // for the constraint.
1564
1584
  let tmpMinWidth=pOptions.minWidth||(pAnchorRect.width>=80?Math.ceil(pAnchorRect.width)+'px':'160px');pMenu.style.minWidth=tmpMinWidth;// Measure after attaching.
1565
1585
  let tmpMenuRect=pMenu.getBoundingClientRect();let tmpVw=window.innerWidth||document.documentElement.clientWidth;let tmpVh=window.innerHeight||document.documentElement.clientHeight;let tmpGap=4;// breathing room between anchor and menu
@@ -1945,9 +1965,11 @@ class PictModalShellManager{constructor(pModalSection){this._modal=pModalSection
1945
1965
  * Show a toast notification.
1946
1966
  *
1947
1967
  * @param {string} pMessage - Toast message text
1948
- * @param {object} [pOptions] - Options (type, duration, position, dismissible)
1968
+ * @param {object} [pOptions] - Options (type, duration, position, dismissible, allowHTML)
1969
+ * @param {boolean} [pOptions.allowHTML=false] - When true, render pMessage as raw HTML instead of escaping it. Only pass trusted markup.
1949
1970
  * @returns {{ dismiss: function }} Handle with dismiss method
1950
- */toast(pMessage,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultToastOptions,pOptions);let tmpContainer=this._getContainer(tmpOptions.position);let tmpId=this._modal._nextId();let tmpToast=document.createElement('div');tmpToast.className='pict-modal-toast pict-modal-toast--'+tmpOptions.type;tmpToast.id='pict-modal-toast-'+tmpId;let tmpContent='<span class="pict-modal-toast-message">'+this._escapeHTML(pMessage)+'</span>';if(tmpOptions.dismissible){tmpContent+='<button class="pict-modal-toast-dismiss" aria-label="Dismiss">&times;</button>';}tmpToast.innerHTML=tmpContent;// Create handle
1971
+ */toast(pMessage,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultToastOptions,pOptions);let tmpContainer=this._getContainer(tmpOptions.position);let tmpId=this._modal._nextId();let tmpToast=document.createElement('div');tmpToast.className='pict-modal-toast pict-modal-toast--'+tmpOptions.type;tmpToast.id='pict-modal-toast-'+tmpId;// Escape by default; render raw markup only when the caller opts in with allowHTML (trusted content).
1972
+ let tmpMessageMarkup=tmpOptions.allowHTML===true?pMessage:this._escapeHTML(pMessage);let tmpContent='<span class="pict-modal-toast-message">'+tmpMessageMarkup+'</span>';if(tmpOptions.dismissible){tmpContent+='<button class="pict-modal-toast-dismiss" aria-label="Dismiss">&times;</button>';}tmpToast.innerHTML=tmpContent;// Create handle
1951
1973
  let tmpDismissed=false;let tmpTimeoutHandle=null;let tmpDismiss=()=>{if(tmpDismissed){return;}tmpDismissed=true;if(tmpTimeoutHandle){clearTimeout(tmpTimeoutHandle);}// Exit animation
1952
1974
  tmpToast.classList.remove('pict-modal-visible');tmpToast.classList.add('pict-modal-toast-exit');// Remove from active list
1953
1975
  this._modal._activeToasts=this._modal._activeToasts.filter(pEntry=>{return pEntry.element!==tmpToast;});// Remove from DOM after transition
@@ -1993,6 +2015,19 @@ if(tmpOptions.duration>0){tmpTimeoutHandle=setTimeout(tmpDismiss,tmpOptions.dura
1993
2015
  * @param {object} [pOptions] - Options (position, delay, maxWidth, interactive)
1994
2016
  * @returns {{ destroy: function }} Handle to remove the tooltip
1995
2017
  */richTooltip(pElement,pHTMLContent,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultTooltipOptions,pOptions);return this._attachTooltip(pElement,pHTMLContent,true,tmpOptions);}/**
2018
+ * Attach a pinnable rich HTML tooltip to an element.
2019
+ *
2020
+ * Behaves like richTooltip() on hover/focus, but a click on the element
2021
+ * toggles a pinned state: while pinned the tooltip stays open (it does not
2022
+ * hide on mouseleave/focusout) and follows its anchor on scroll/resize.
2023
+ * This is opt-in sugar over richTooltip() with `{ pinnable: true }` — the
2024
+ * default tooltip()/richTooltip() behavior is unchanged.
2025
+ *
2026
+ * @param {HTMLElement} pElement - Target element
2027
+ * @param {string} pHTMLContent - HTML content for the tooltip
2028
+ * @param {object} [pOptions] - Options (position, delay, maxWidth, interactive, startPinned, onPinChange)
2029
+ * @returns {{ destroy: function, pin: function, unpin: function, isPinned: function }} Handle
2030
+ */pinnableTooltip(pElement,pHTMLContent,pOptions){let tmpOptions=Object.assign({},this._modal.options.DefaultTooltipOptions,pOptions,{pinnable:true});return this._attachTooltip(pElement,pHTMLContent,true,tmpOptions);}/**
1996
2031
  * Internal: attach tooltip event listeners to an element.
1997
2032
  *
1998
2033
  * @param {HTMLElement} pElement
@@ -2000,18 +2035,46 @@ if(tmpOptions.duration>0){tmpTimeoutHandle=setTimeout(tmpDismiss,tmpOptions.dura
2000
2035
  * @param {boolean} pIsHTML
2001
2036
  * @param {object} pOptions
2002
2037
  * @returns {{ destroy: function }}
2003
- */_attachTooltip(pElement,pContent,pIsHTML,pOptions){let tmpTooltipElement=null;let tmpShowTimeout=null;let tmpHideTimeout=null;let tmpDestroyed=false;let tmpId=this._modal._nextId();let tmpShow=()=>{if(tmpDestroyed||tmpTooltipElement){return;}tmpTooltipElement=document.createElement('div');tmpTooltipElement.className='pict-modal-tooltip pict-modal-tooltip--'+pOptions.position;tmpTooltipElement.id='pict-modal-tooltip-'+tmpId;tmpTooltipElement.setAttribute('role','tooltip');tmpTooltipElement.style.maxWidth=pOptions.maxWidth;if(pOptions.interactive){tmpTooltipElement.classList.add('pict-modal-tooltip-interactive');}// Arrow
2038
+ */_attachTooltip(pElement,pContent,pIsHTML,pOptions){let tmpTooltipElement=null;let tmpShowTimeout=null;let tmpHideTimeout=null;let tmpDestroyed=false;let tmpId=this._modal._nextId();// Pin state — only meaningful when pOptions.pinnable is set. A pinned
2039
+ // tooltip stays visible (transient hide is suppressed) and follows its
2040
+ // anchor on scroll/resize.
2041
+ let tmpPinned=false;let tmpShow=()=>{if(tmpDestroyed||tmpTooltipElement){return;}tmpTooltipElement=document.createElement('div');tmpTooltipElement.className='pict-modal-tooltip pict-modal-tooltip--'+pOptions.position;tmpTooltipElement.id='pict-modal-tooltip-'+tmpId;tmpTooltipElement.setAttribute('role','tooltip');tmpTooltipElement.style.maxWidth=pOptions.maxWidth;if(pOptions.interactive){tmpTooltipElement.classList.add('pict-modal-tooltip-interactive');}// Optional consumer-supplied class(es) on the tooltip element, e.g.
2042
+ // to theme the bubble + arrow by overriding the --pict-modal-tooltip-*
2043
+ // custom properties for a specific tooltip.
2044
+ if(pOptions.className){let tmpExtraClasses=String(pOptions.className).split(/\s+/);for(let i=0;i<tmpExtraClasses.length;i++){if(tmpExtraClasses[i]){tmpTooltipElement.classList.add(tmpExtraClasses[i]);}}}// Arrow
2004
2045
  let tmpArrow=document.createElement('div');tmpArrow.className='pict-modal-tooltip-arrow';// Content
2005
2046
  let tmpContentDiv=document.createElement('div');if(pIsHTML){tmpContentDiv.innerHTML=pContent;}else{tmpContentDiv.textContent=pContent;}tmpTooltipElement.appendChild(tmpArrow);tmpTooltipElement.appendChild(tmpContentDiv);document.body.appendChild(tmpTooltipElement);// Set aria-describedby on target
2006
2047
  pElement.setAttribute('aria-describedby',tmpTooltipElement.id);// Position
2007
- this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);// Animate in
2008
- void tmpTooltipElement.offsetHeight;tmpTooltipElement.classList.add('pict-modal-visible');// Track
2048
+ this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);// Animate in — but only paint when the anchor is actually rendered.
2049
+ // A pinned / startPinned tooltip whose anchor lives in a hidden
2050
+ // container (e.g. an inactive tab panel) would otherwise show at the
2051
+ // clamped corner as an orphan. It is revealed later by tmpReposition
2052
+ // once the anchor gains a layout box (see the ResizeObserver below).
2053
+ void tmpTooltipElement.offsetHeight;if(this._isElementRendered(pElement)){tmpTooltipElement.classList.add('pict-modal-visible');}// Track
2009
2054
  this._modal._activeTooltips.push({element:tmpTooltipElement,targetElement:pElement,destroy:tmpDestroy});// For interactive tooltips, allow hovering over the tooltip itself
2010
- if(pOptions.interactive&&tmpTooltipElement){tmpTooltipElement.addEventListener('mouseenter',()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}});tmpTooltipElement.addEventListener('mouseleave',()=>{tmpHide();});}};let tmpHide=()=>{if(!tmpTooltipElement){return;}tmpTooltipElement.classList.remove('pict-modal-visible');let tmpEl=tmpTooltipElement;tmpTooltipElement=null;// Remove aria
2055
+ if(pOptions.interactive&&tmpTooltipElement){tmpTooltipElement.addEventListener('mouseenter',()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}});tmpTooltipElement.addEventListener('mouseleave',()=>{if(!tmpPinned){tmpHide();}});}// Reflect pinned state on a freshly-(re)created element.
2056
+ if(tmpPinned&&tmpTooltipElement){tmpTooltipElement.classList.add('pict-modal-tooltip-pinned');}};let tmpHide=()=>{if(!tmpTooltipElement){return;}tmpTooltipElement.classList.remove('pict-modal-visible');let tmpEl=tmpTooltipElement;tmpTooltipElement=null;// Remove aria
2011
2057
  pElement.removeAttribute('aria-describedby');// Remove from tracking
2012
- this._modal._activeTooltips=this._modal._activeTooltips.filter(pEntry=>{return pEntry.element!==tmpEl;});setTimeout(()=>{if(tmpEl.parentNode){tmpEl.parentNode.removeChild(tmpEl);}},220);};let tmpOnMouseEnter=()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnMouseLeave=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// Small delay before hiding to allow moving to interactive tooltip
2013
- if(pOptions.interactive){tmpHideTimeout=setTimeout(tmpHide,100);}else{tmpHide();}};let tmpOnFocusIn=()=>{tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnFocusOut=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}tmpHide();};// Attach listeners
2014
- pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListener('mouseleave',tmpOnMouseLeave);pElement.addEventListener('focusin',tmpOnFocusIn);pElement.addEventListener('focusout',tmpOnFocusOut);let tmpDestroy=()=>{if(tmpDestroyed){return;}tmpDestroyed=true;if(tmpShowTimeout){clearTimeout(tmpShowTimeout);}if(tmpHideTimeout){clearTimeout(tmpHideTimeout);}tmpHide();pElement.removeEventListener('mouseenter',tmpOnMouseEnter);pElement.removeEventListener('mouseleave',tmpOnMouseLeave);pElement.removeEventListener('focusin',tmpOnFocusIn);pElement.removeEventListener('focusout',tmpOnFocusOut);};return{destroy:tmpDestroy};}/**
2058
+ this._modal._activeTooltips=this._modal._activeTooltips.filter(pEntry=>{return pEntry.element!==tmpEl;});setTimeout(()=>{if(tmpEl.parentNode){tmpEl.parentNode.removeChild(tmpEl);}},220);};let tmpOnMouseEnter=()=>{if(tmpHideTimeout){clearTimeout(tmpHideTimeout);tmpHideTimeout=null;}tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnMouseLeave=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// A pinned tooltip stays open regardless of pointer.
2059
+ if(tmpPinned){return;}// Small delay before hiding to allow moving to interactive tooltip
2060
+ if(pOptions.interactive){tmpHideTimeout=setTimeout(tmpHide,100);}else{tmpHide();}};let tmpOnFocusIn=()=>{tmpShowTimeout=setTimeout(tmpShow,pOptions.delay);};let tmpOnFocusOut=()=>{if(tmpShowTimeout){clearTimeout(tmpShowTimeout);tmpShowTimeout=null;}// A pinned tooltip stays open regardless of focus.
2061
+ if(tmpPinned){return;}tmpHide();};// -- Pin lifecycle (opt-in via pOptions.pinnable) --
2062
+ // Keep a pinned tooltip glued to its anchor as the page scrolls/resizes.
2063
+ // The element is position:fixed and portaled to <body>, so it does not
2064
+ // move with the document on its own. When the anchor scrolls out of the
2065
+ // viewport we fade the tooltip out (without dropping the pin) and bring
2066
+ // it back when the anchor returns.
2067
+ let tmpResizeObserver=null;let tmpReposition=()=>{if(!tmpTooltipElement){return;}let tmpRect=pElement.getBoundingClientRect();// Rendered (has a layout box) AND within the viewport. A hidden anchor
2068
+ // (display:none, or inside a hidden tab panel) has no box, so the
2069
+ // tooltip is hidden rather than stranded at the clamped corner.
2070
+ let tmpInView=this._isElementRendered(pElement)&&tmpRect.bottom>0&&tmpRect.top<window.innerHeight&&tmpRect.right>0&&tmpRect.left<window.innerWidth;if(tmpInView){this._positionTooltip(tmpTooltipElement,pElement,pOptions.position);tmpTooltipElement.classList.add('pict-modal-visible');}else{tmpTooltipElement.classList.remove('pict-modal-visible');}};let tmpAddRepositionListeners=()=>{// `true` (capture) so scrolls inside any nested container reposition too.
2071
+ window.addEventListener('scroll',tmpReposition,true);window.addEventListener('resize',tmpReposition);// A ResizeObserver on the anchor catches it being shown/hidden (e.g. a
2072
+ // tab panel toggling display) — transitions the window scroll/resize
2073
+ // listeners miss — so a pinned tooltip appears the moment its anchor
2074
+ // gains a layout box and hides again when it loses one.
2075
+ if(typeof ResizeObserver!=='undefined'){tmpResizeObserver=new ResizeObserver(()=>tmpReposition());tmpResizeObserver.observe(pElement);}};let tmpRemoveRepositionListeners=()=>{window.removeEventListener('scroll',tmpReposition,true);window.removeEventListener('resize',tmpReposition);if(tmpResizeObserver){tmpResizeObserver.disconnect();tmpResizeObserver=null;}};let tmpPin=()=>{if(tmpPinned||tmpDestroyed){return;}tmpPinned=true;if(!tmpTooltipElement){tmpShow();}if(tmpTooltipElement){tmpTooltipElement.classList.add('pict-modal-tooltip-pinned');}tmpAddRepositionListeners();if(typeof pOptions.onPinChange==='function'){pOptions.onPinChange(true,pElement);}};let tmpUnpin=()=>{if(!tmpPinned){return;}tmpPinned=false;tmpRemoveRepositionListeners();if(tmpTooltipElement){tmpTooltipElement.classList.remove('pict-modal-tooltip-pinned');}tmpHide();if(typeof pOptions.onPinChange==='function'){pOptions.onPinChange(false,pElement);}};let tmpOnClick=pEvent=>{if(pEvent){pEvent.preventDefault();pEvent.stopPropagation();}if(tmpPinned){tmpUnpin();}else{tmpPin();}};// Attach listeners
2076
+ pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListener('mouseleave',tmpOnMouseLeave);pElement.addEventListener('focusin',tmpOnFocusIn);pElement.addEventListener('focusout',tmpOnFocusOut);if(pOptions.pinnable){pElement.addEventListener('click',tmpOnClick);}let tmpDestroy=()=>{if(tmpDestroyed){return;}tmpDestroyed=true;if(tmpShowTimeout){clearTimeout(tmpShowTimeout);}if(tmpHideTimeout){clearTimeout(tmpHideTimeout);}tmpRemoveRepositionListeners();tmpPinned=false;tmpHide();pElement.removeEventListener('mouseenter',tmpOnMouseEnter);pElement.removeEventListener('mouseleave',tmpOnMouseLeave);pElement.removeEventListener('focusin',tmpOnFocusIn);pElement.removeEventListener('focusout',tmpOnFocusOut);if(pOptions.pinnable){pElement.removeEventListener('click',tmpOnClick);}};// Optionally render already-pinned (explicit consumer opt-in).
2077
+ if(pOptions.pinnable&&pOptions.startPinned){tmpPin();}return{destroy:tmpDestroy,pin:tmpPin,unpin:tmpUnpin,isPinned:()=>{return tmpPinned;}};}/**
2015
2078
  * Position a tooltip element relative to the target element.
2016
2079
  * Flips direction if the tooltip would overflow the viewport.
2017
2080
  *
@@ -2022,6 +2085,14 @@ pElement.addEventListener('mouseenter',tmpOnMouseEnter);pElement.addEventListene
2022
2085
  if(tmpPosition==='top'&&tmpTargetRect.top<tmpTooltipRect.height+tmpGap){tmpPosition='bottom';}else if(tmpPosition==='bottom'&&window.innerHeight-tmpTargetRect.bottom<tmpTooltipRect.height+tmpGap){tmpPosition='top';}else if(tmpPosition==='left'&&tmpTargetRect.left<tmpTooltipRect.width+tmpGap){tmpPosition='right';}else if(tmpPosition==='right'&&window.innerWidth-tmpTargetRect.right<tmpTooltipRect.width+tmpGap){tmpPosition='left';}// Update class for arrow direction
2023
2086
  pTooltip.className=pTooltip.className.replace(/pict-modal-tooltip--\w+/,'pict-modal-tooltip--'+tmpPosition);let tmpTop=0;let tmpLeft=0;switch(tmpPosition){case'top':tmpTop=tmpTargetRect.top-tmpTooltipRect.height-tmpGap;tmpLeft=tmpTargetRect.left+tmpTargetRect.width/2-tmpTooltipRect.width/2;break;case'bottom':tmpTop=tmpTargetRect.bottom+tmpGap;tmpLeft=tmpTargetRect.left+tmpTargetRect.width/2-tmpTooltipRect.width/2;break;case'left':tmpTop=tmpTargetRect.top+tmpTargetRect.height/2-tmpTooltipRect.height/2;tmpLeft=tmpTargetRect.left-tmpTooltipRect.width-tmpGap;break;case'right':tmpTop=tmpTargetRect.top+tmpTargetRect.height/2-tmpTooltipRect.height/2;tmpLeft=tmpTargetRect.right+tmpGap;break;}// Clamp to viewport
2024
2087
  tmpLeft=Math.max(4,Math.min(tmpLeft,window.innerWidth-tmpTooltipRect.width-4));tmpTop=Math.max(4,Math.min(tmpTop,window.innerHeight-tmpTooltipRect.height-4));pTooltip.style.top=tmpTop+'px';pTooltip.style.left=tmpLeft+'px';}/**
2088
+ * Whether an element is currently rendered (has a layout box). Returns false
2089
+ * for a display:none element or one inside a display:none ancestor (e.g. an
2090
+ * inactive tab panel) — in which case a pinned tooltip should stay hidden
2091
+ * until the anchor reappears.
2092
+ *
2093
+ * @param {HTMLElement} pElement
2094
+ * @returns {boolean}
2095
+ */_isElementRendered(pElement){return!!(pElement&&typeof pElement.getClientRects==='function'&&pElement.getClientRects().length>0);}/**
2025
2096
  * Dismiss all active tooltips.
2026
2097
  */dismissAll(){let tmpTooltips=this._modal._activeTooltips.slice();for(let i=0;i<tmpTooltips.length;i++){tmpTooltips[i].destroy();}}}module.exports=PictModalTooltip;},{}],27:[function(require,module,exports){/**
2027
2098
  * Pict-Modal-Window
@@ -2076,7 +2147,7 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2076
2147
  *
2077
2148
  * @param {string} pText
2078
2149
  * @returns {string}
2079
- */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],28:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/`
2150
+ */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],28:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false,"pinnable":false,"startPinned":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true,"allowHTML":false},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/`
2080
2151
  /* pict-section-modal */
2081
2152
  .pict-modal-root
2082
2153
  {
@@ -2127,6 +2198,7 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2127
2198
  --pict-modal-tooltip-fg: var(--theme-color-text-primary, #ffffff);
2128
2199
  --pict-modal-tooltip-border-radius:4px;
2129
2200
  --pict-modal-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
2201
+ --pict-modal-tooltip-pinned-ring: var(--theme-color-brand-primary, #2E7D74);
2130
2202
 
2131
2203
  /* Dropdown */
2132
2204
  --pict-modal-dropdown-bg: var(--theme-color-background-panel, #ffffff);
@@ -2489,6 +2561,14 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2489
2561
  opacity: 1;
2490
2562
  }
2491
2563
 
2564
+ /* Pinned tooltips stay open and can be interacted with; a subtle ring
2565
+ distinguishes a pinned tooltip from a transient hover tooltip. */
2566
+ .pict-modal-tooltip.pict-modal-tooltip-pinned
2567
+ {
2568
+ pointer-events: auto;
2569
+ box-shadow: var(--pict-modal-tooltip-shadow), 0 0 0 1px var(--pict-modal-tooltip-pinned-ring);
2570
+ }
2571
+
2492
2572
  .pict-modal-tooltip-arrow
2493
2573
  {
2494
2574
  position: absolute;
@@ -2552,6 +2632,16 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
2552
2632
  transform var(--pict-modal-transition-duration) ease;
2553
2633
  }
2554
2634
 
2635
+ /* Free-form content popovers keep the dropdown chrome (bg / border / shadow /
2636
+ flip / dismiss) but hand sizing + inner padding to the injected content, so a
2637
+ pre-rendered template menu or a wide rich card isn't boxed by the menu
2638
+ defaults. Cap width per-call via the maxWidth option. */
2639
+ .pict-modal-dropdown.pict-modal-dropdown--content
2640
+ {
2641
+ max-width: none;
2642
+ padding: 0;
2643
+ }
2644
+
2555
2645
  .pict-modal-dropdown.pict-modal-dropdown--above { transform: translateY(4px); }
2556
2646
 
2557
2647
  .pict-modal-dropdown.pict-modal-visible
@@ -3482,7 +3572,16 @@ if(typeof document!=='undefined'&&document.body){if(!document.body.classList.con
3482
3572
  * @param {string} pHTMLContent - HTML content
3483
3573
  * @param {object} [pOptions] - Options { position, delay, maxWidth, interactive }
3484
3574
  * @returns {{ destroy: function }}
3485
- */richTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.richTooltip(pElement,pHTMLContent,pOptions);}// -- Toast API --
3575
+ */richTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.richTooltip(pElement,pHTMLContent,pOptions);}/**
3576
+ * Attach a pinnable rich HTML tooltip to an element. Hover/focus behaves
3577
+ * like richTooltip(); a click on the element toggles a pinned state that
3578
+ * keeps the tooltip open and follows the anchor on scroll/resize.
3579
+ *
3580
+ * @param {HTMLElement} pElement - Target element
3581
+ * @param {string} pHTMLContent - HTML content
3582
+ * @param {object} [pOptions] - Options { position, delay, maxWidth, interactive, startPinned, onPinChange }
3583
+ * @returns {{ destroy: function, pin: function, unpin: function, isPinned: function }}
3584
+ */pinnableTooltip(pElement,pHTMLContent,pOptions){return this._tooltip.pinnableTooltip(pElement,pHTMLContent,pOptions);}// -- Toast API --
3486
3585
  /**
3487
3586
  * Show a toast notification.
3488
3587
  *
@@ -3492,13 +3591,16 @@ if(typeof document!=='undefined'&&document.body){if(!document.body.classList.con
3492
3591
  */toast(pMessage,pOptions){return this._toast.toast(pMessage,pOptions);}// -- Dropdown API --
3493
3592
  /**
3494
3593
  * Open an anchor-positioned dropdown menu (no backdrop, click-outside
3495
- * dismisses). Useful for nav menus and split-button addenda.
3594
+ * dismisses). Useful for nav menus and split-button addenda. Pass
3595
+ * `ContentHTML` instead of `items` to render a free-form anchored popover
3596
+ * (rich card, pre-rendered template menu) with the same dismiss/flip behavior.
3496
3597
  *
3497
3598
  * @param {HTMLElement|string|object} pAnchor - Element, CSS selector, or
3498
3599
  * { left, top, width, height } rect for context-menu style anchoring.
3499
- * @param {object} pOptions - { items, align, position, minWidth, maxHeight,
3500
- * className, closeOnSelect, onSelect, onClose }
3501
- * @returns {Promise<{Hash, Item}|null>} Selection or null on dismiss.
3600
+ * @param {object} pOptions - { items | ContentHTML, align, position, minWidth,
3601
+ * maxWidth, maxHeight, className, closeOnSelect, onSelect, onClose }
3602
+ * @returns {Promise<{Hash, Item}|null>} Selection or null on dismiss
3603
+ * (always resolves null in ContentHTML mode).
3502
3604
  */dropdown(pAnchor,pOptions){return this._dropdown.dropdown(pAnchor,pOptions);}/**
3503
3605
  * Dismiss any open dropdown.
3504
3606
  */dismissDropdowns(){this._dropdown.dismissAll();}// -- Panel API --
@@ -5533,7 +5635,7 @@ return cachedClearTimeout.call(null,marker);}catch(e){// same as above but when
5533
5635
  // Some versions of I.E. have different rules for clearTimeout vs setTimeout
5534
5636
  return cachedClearTimeout.call(this,marker);}}}var queue=[];var draining=false;var currentQueue;var queueIndex=-1;function cleanUpNextTick(){if(!draining||!currentQueue){return;}draining=false;if(currentQueue.length){queue=currentQueue.concat(queue);}else{queueIndex=-1;}if(queue.length){drainQueue();}}function drainQueue(){if(draining){return;}var timeout=runTimeout(cleanUpNextTick);draining=true;var len=queue.length;while(len){currentQueue=queue;queue=[];while(++queueIndex<len){if(currentQueue){currentQueue[queueIndex].run();}}queueIndex=-1;len=queue.length;}currentQueue=null;draining=false;runClearTimeout(timeout);}process.nextTick=function(fun){var args=new Array(arguments.length-1);if(arguments.length>1){for(var i=1;i<arguments.length;i++){args[i-1]=arguments[i];}}queue.push(new Item(fun,args));if(queue.length===1&&!draining){runTimeout(drainQueue);}};// v8 likes predictible objects
5535
5637
  function Item(fun,array){this.fun=fun;this.array=array;}Item.prototype.run=function(){this.fun.apply(null,this.array);};process.title='browser';process.browser=true;process.env={};process.argv=[];process.version='';// empty string to avoid regexp issues
5536
- process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.prependListener=noop;process.prependOnceListener=noop;process.listeners=function(name){return[];};process.binding=function(name){throw new Error('process.binding is not supported');};process.cwd=function(){return'/';};process.chdir=function(dir){throw new Error('process.chdir is not supported');};process.umask=function(){return 0;};},{}],93:[function(require,module,exports){module.exports={"name":"retold-data-service","version":"2.1.5","description":"Serve up a whole model!","main":"source/Retold-Data-Service.js","bin":{"retold-data-service-clone":"bin/retold-data-service-clone.js"},"scripts":{"start":"node bin/retold-data-service-clone.js","coverage":"npx quack coverage","test":"npx quack test","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module retold-data-service --favicons source/services/comprehension-loader/web/favicons && cp -r source/services/comprehension-loader/web/favicons source/services/data-cloner/web/favicons","build":"node build-all.js","build:cloner":"npx quack build","build:loader":"node -e \"require('fs').writeFileSync('.quackage.json', require('fs').readFileSync('.quackage-comprehension-loader.json', 'utf8'))\" && npx quack build","prepublishOnly":"npm run build","build-test-model":"cd test && npx stricture -i model/ddl/BookStore.ddl","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t retold-data-service-image:local","docker-dev-run":"docker run -it -d --name retold-data-service-dev -p 44444:8080 -p 43306:3306 -p 48086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/retold-data-service\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold-data-service-image:local","docker-dev-shell":"docker exec -it retold-data-service-dev /bin/bash","docker-service-build":"docker build ./ -f Dockerfile_Service -t retold-data-service-server-image:local","docker-service-run-test":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" -u \"$(id -u):$(id -g)\" retold-data-service-server-image:local","docker-service-run":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" retold-data-service-server-image:local","docker-service-shell":"docker exec -it retold-data-service /bin/bash","test:integration":"node test/run-integration-tests.js","test:integration:no-browser":"node test/run-integration-tests.js --skip-puppeteer","test:all":"npx quack test && node test/run-integration-tests.js --skip-puppeteer","postversion":"npx quack release postversion","postpublish":"npx quack release postpublish","publish:docker":"npx quack release publish --image","release:patch":"npx quack release patch","release:minor":"npx quack release minor","release:major":"npx quack release major","release:patch:image":"npx quack release patch --image","release:minor:image":"npx quack release minor --image","release:major:image":"npx quack release major --image"},"mocha":{"spec":["test/RetoldDataService_tests.js","test/Bundles_smoke_tests.js","test/ComprehensionLoader_smoke_tests.js","test/DataCloner_smoke_tests.js"],"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"repository":{"type":"git","url":"https://github.com/fable-retold/retold-data-service.git"},"keywords":["entity","behavior","api"],"author":"Steven Velozo <steven@velozo.com> (http://velozo.com/)","license":"MIT","bugs":{"url":"https://github.com/fable-retold/retold-data-service/issues"},"homepage":"https://github.com/fable-retold/retold-data-service","devDependencies":{"chai":"^4.5.0","jsdom":"^25.0.1","meadow-connection-sqlite":"^1.0.20","mocha":"^11.0.1","pict-docuserve":"^1.4.19","puppeteer":"^24.40.0","quackage":"^1.3.0","stricture":"^4.0.6","supertest":"^7.2.2"},"dependencies":{"bibliograph":"^1.0.0","fable":"^3.1.75","fable-serviceproviderbase":"^3.0.19","meadow":"^2.0.43","meadow-connection-manager":"^1.1.5","meadow-connection-mysql":"^1.0.19","meadow-endpoints":"^4.0.22","meadow-integration":"^1.0.42","meadow-migrationmanager":"^1.0.4","orator":"^6.1.2","orator-http-proxy":"^1.0.5","orator-serviceserver-restify":"^2.0.11","orator-static-server":"^2.1.4","pict":"^1.0.372","pict-provider-theme":"^1.1.2","pict-section-connection-form":"^1.0.0","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.1.4","pict-section-theme":"^1.1.1","pict-sessionmanager":"^1.0.2","stricture":"^4.0.6"},"retold":{"brand":{"Hash":"retold-data-service","Name":"Retold Data Service","Tagline":"Schema-driven data movement and comprehension","Palette":"ocean","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-data-service-filled-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#frame-retold-data-service-filled-light)\"><rect x=\"20\" y=\"20\" width=\"56\" height=\"56\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<path d=\"M 48 30 L 70 48 L 48 66 L 26 48 Z\" fill=\"#e36b59\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RDS</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-light)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-dark\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#67c6de\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-dark)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>","Colors":{"Primary":"#23a6c7","Secondary":"#e36b59","PrimaryLight":"#23a6c7","PrimaryDark":"#67c6de","SecondaryLight":"#e36b59","SecondaryDark":"#edb3aa"}}}};},{}],94:[function(require,module,exports){'use strict';// Located at source/services/. Apps live one level deeper at
5638
+ process.versions={};function noop(){}process.on=noop;process.addListener=noop;process.once=noop;process.off=noop;process.removeListener=noop;process.removeAllListeners=noop;process.emit=noop;process.prependListener=noop;process.prependOnceListener=noop;process.listeners=function(name){return[];};process.binding=function(name){throw new Error('process.binding is not supported');};process.cwd=function(){return'/';};process.chdir=function(dir){throw new Error('process.chdir is not supported');};process.umask=function(){return 0;};},{}],93:[function(require,module,exports){module.exports={"name":"retold-data-service","version":"2.1.6","description":"Serve up a whole model!","main":"source/Retold-Data-Service.js","bin":{"retold-data-service-clone":"bin/retold-data-service-clone.js"},"scripts":{"start":"node bin/retold-data-service-clone.js","coverage":"npx quack coverage","test":"npx quack test","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module retold-data-service --favicons source/services/comprehension-loader/web/favicons && cp -r source/services/comprehension-loader/web/favicons source/services/data-cloner/web/favicons","build":"node build-all.js","build:cloner":"npx quack build","build:loader":"node -e \"require('fs').writeFileSync('.quackage.json', require('fs').readFileSync('.quackage-comprehension-loader.json', 'utf8'))\" && npx quack build","prepublishOnly":"npm run build","build-test-model":"cd test && npx stricture -i model/ddl/BookStore.ddl","docker-dev-build":"docker build ./ -f Dockerfile_LUXURYCode -t retold-data-service-image:local","docker-dev-run":"docker run -it -d --name retold-data-service-dev -p 44444:8080 -p 43306:3306 -p 48086:8086 -v \"$PWD/.config:/home/coder/.config\" -v \"$PWD:/home/coder/retold-data-service\" -u \"$(id -u):$(id -g)\" -e \"DOCKER_USER=$USER\" retold-data-service-image:local","docker-dev-shell":"docker exec -it retold-data-service-dev /bin/bash","docker-service-build":"docker build ./ -f Dockerfile_Service -t retold-data-service-server-image:local","docker-service-run-test":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" -u \"$(id -u):$(id -g)\" retold-data-service-server-image:local","docker-service-run":"docker run -it --init -d --name retold-data-service -p 8086:8086 -p 43306:3306 -v \"$(pwd):/retold-data-service:z\" retold-data-service-server-image:local","docker-service-shell":"docker exec -it retold-data-service /bin/bash","test:integration":"node test/run-integration-tests.js","test:integration:no-browser":"node test/run-integration-tests.js --skip-puppeteer","test:all":"npx quack test && node test/run-integration-tests.js --skip-puppeteer","postversion":"npx quack release postversion","postpublish":"npx quack release postpublish","publish:docker":"npx quack release publish --image","release:patch":"npx quack release patch","release:minor":"npx quack release minor","release:major":"npx quack release major","release:patch:image":"npx quack release patch --image","release:minor:image":"npx quack release minor --image","release:major:image":"npx quack release major --image"},"mocha":{"spec":["test/RetoldDataService_tests.js","test/Bundles_smoke_tests.js","test/ComprehensionLoader_smoke_tests.js","test/DataCloner_smoke_tests.js"],"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"repository":{"type":"git","url":"https://github.com/fable-retold/retold-data-service.git"},"keywords":["entity","behavior","api"],"author":"Steven Velozo <steven@velozo.com> (http://velozo.com/)","license":"MIT","bugs":{"url":"https://github.com/fable-retold/retold-data-service/issues"},"homepage":"https://github.com/fable-retold/retold-data-service","devDependencies":{"chai":"^4.5.0","jsdom":"^25.0.1","meadow-connection-sqlite":"^1.0.21","mocha":"^11.7.6","pict-docuserve":"^1.4.19","puppeteer":"^24.40.0","quackage":"^1.3.0","stricture":"^4.0.6","supertest":"^7.2.2"},"dependencies":{"bibliograph":"^1.0.0","fable":"^3.1.80","fable-serviceproviderbase":"^3.0.19","meadow":"^2.0.47","meadow-connection-manager":"^1.1.5","meadow-connection-mysql":"^1.0.20","meadow-endpoints":"^4.0.22","meadow-integration":"^1.1.3","meadow-migrationmanager":"^1.0.5","orator":"^6.1.2","orator-http-proxy":"^1.0.5","orator-serviceserver-restify":"^2.0.11","orator-static-server":"^2.1.4","pict":"^1.0.393","pict-provider-theme":"^1.1.2","pict-section-connection-form":"^1.0.0","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.3.2","pict-section-theme":"^1.1.1","pict-sessionmanager":"^1.0.2","stricture":"^4.0.6"},"retold":{"brand":{"Hash":"retold-data-service","Name":"Retold Data Service","Tagline":"Schema-driven data movement and comprehension","Palette":"ocean","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-retold-data-service-filled-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#frame-retold-data-service-filled-light)\"><rect x=\"20\" y=\"20\" width=\"56\" height=\"56\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<path d=\"M 48 30 L 70 48 L 48 66 L 26 48 Z\" fill=\"#e36b59\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">RDS</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-light\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#23a6c7\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-light)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">R</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-retold-data-service-dark\">\n\t\t\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 48.00 2.00 L 87.84 25.00 L 87.84 71.00 L 48.00 94.00 L 8.16 71.00 L 8.16 25.00 Z\" fill=\"#67c6de\"/>\n\t\t<g clip-path=\"url(#fav-retold-data-service-dark)\"><rect x=\"16\" y=\"16\" width=\"64\" height=\"64\" rx=\"10\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">R</text>\n\t</svg>","Colors":{"Primary":"#23a6c7","Secondary":"#e36b59","PrimaryLight":"#23a6c7","PrimaryDark":"#67c6de","SecondaryLight":"#e36b59","SecondaryDark":"#edb3aa"}}}};},{}],94:[function(require,module,exports){'use strict';// Located at source/services/. Apps live one level deeper at
5537
5639
  // source/services/<app>/pict-app/. The package.json is two levels up.
5538
5640
  const tmpPackage=require('../../package.json');if(!tmpPackage.retold||!tmpPackage.retold.brand){throw new Error('retold-data-service: package.json is missing retold.brand — '+'run `npm run brand` (which calls pict-section-theme-brand) before building');}module.exports=tmpPackage.retold.brand;},{"../../package.json":93}],95:[function(require,module,exports){module.exports={"Name":"Retold Data Cloner","Hash":"DataCloner","MainViewportViewIdentifier":"DataCloner-Layout","MainViewportDestinationAddress":"#DataCloner-Application-Container","MainViewportDefaultDataAddress":"AppData.DataCloner","pict_configuration":{"Product":"DataCloner"},"AutoRenderMainViewportViewAfterInitialize":false};},{}],96:[function(require,module,exports){const libPictApplication=require('pict-application');const libProvider=require('./providers/Pict-Provider-DataCloner.js');const libViewLayout=require('./views/PictView-DataCloner-Layout.js');const libViewConnection=require('./views/PictView-DataCloner-Connection.js');const libViewSession=require('./views/PictView-DataCloner-Session.js');const libViewSchema=require('./views/PictView-DataCloner-Schema.js');const libViewDeploy=require('./views/PictView-DataCloner-Deploy.js');const libViewSync=require('./views/PictView-DataCloner-Sync.js');const libViewExport=require('./views/PictView-DataCloner-Export.js');const libViewViewData=require('./views/PictView-DataCloner-ViewData.js');const libViewHistogram=require('pict-section-histogram');const libViewConnectionForm=require('pict-section-connection-form');const libPictSectionModal=require('pict-section-modal');const libPictSectionTheme=require('pict-section-theme');const libBrand=require('../../RetoldDataService-Brand.js');const libViewShell=require('./views/PictView-DataCloner-Shell.js');const libViewTopBarNav=require('./views/PictView-DataCloner-TopBar-Nav.js');const libViewTopBarUser=require('./views/PictView-DataCloner-TopBar-User.js');const libViewStatusBar=require('./views/PictView-DataCloner-StatusBar.js');const libViewStatusDetail=require('./views/PictView-DataCloner-StatusDetail.js');const libViewSettings=require('./views/PictView-DataCloner-SettingsPanel.js');class DataClonerApplication extends libPictApplication{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// 1. Modal section (provides shell + panels + modal API).
5539
5641
  this.pict.addView('Pict-Section-Modal',libPictSectionModal.default_configuration,libPictSectionModal);// 2. Provider + existing section views.