@vielzeug/refine 3.2.1 → 3.3.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 (153) hide show
  1. package/dist/alert.cjs +3 -3
  2. package/dist/alert.cjs.map +1 -1
  3. package/dist/alert.js +11 -4
  4. package/dist/alert.js.map +1 -1
  5. package/dist/chip.cjs +9 -9
  6. package/dist/chip.cjs.map +1 -1
  7. package/dist/chip.js +38 -35
  8. package/dist/chip.js.map +1 -1
  9. package/dist/command-palette.cjs +5 -5
  10. package/dist/command-palette.cjs.map +1 -1
  11. package/dist/command-palette.js +5 -5
  12. package/dist/command-palette.js.map +1 -1
  13. package/dist/content/card/card.css.cjs +1 -1
  14. package/dist/content/card/card.css.cjs.map +1 -1
  15. package/dist/content/card/card.css.js +1 -1
  16. package/dist/content/card/card.css.js.map +1 -1
  17. package/dist/content/index.d.ts +4 -0
  18. package/dist/content/index.d.ts.map +1 -1
  19. package/dist/content/keyboard-key/keyboard-key.css.cjs +2 -0
  20. package/dist/content/keyboard-key/keyboard-key.css.cjs.map +1 -0
  21. package/dist/content/keyboard-key/keyboard-key.css.js +6 -0
  22. package/dist/content/keyboard-key/keyboard-key.css.js.map +1 -0
  23. package/dist/content/keyboard-key/keyboard-key.d.ts +12 -0
  24. package/dist/content/keyboard-key/keyboard-key.d.ts.map +1 -0
  25. package/dist/content/keyboard-key/keyboard-shortcut.css.cjs +2 -0
  26. package/dist/content/keyboard-key/keyboard-shortcut.css.cjs.map +1 -0
  27. package/dist/content/keyboard-key/keyboard-shortcut.css.js +6 -0
  28. package/dist/content/keyboard-key/keyboard-shortcut.css.js.map +1 -0
  29. package/dist/content/qr-code/qr-code.css.cjs +2 -0
  30. package/dist/content/qr-code/qr-code.css.cjs.map +1 -0
  31. package/dist/content/qr-code/qr-code.css.js +6 -0
  32. package/dist/content/qr-code/qr-code.css.js.map +1 -0
  33. package/dist/content/qr-code/qr-code.d.ts +74 -0
  34. package/dist/content/qr-code/qr-code.d.ts.map +1 -0
  35. package/dist/core/positioner.cjs +1 -1
  36. package/dist/core/positioner.cjs.map +1 -1
  37. package/dist/core/positioner.d.ts +4 -1
  38. package/dist/core/positioner.d.ts.map +1 -1
  39. package/dist/core/positioner.js +10 -5
  40. package/dist/core/positioner.js.map +1 -1
  41. package/dist/counter.cjs +91 -0
  42. package/dist/counter.cjs.map +1 -0
  43. package/dist/counter.js +180 -0
  44. package/dist/counter.js.map +1 -0
  45. package/dist/custom-elements.json +793 -17
  46. package/dist/disclosure/tabs/tabs.css.cjs +1 -1
  47. package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
  48. package/dist/disclosure/tabs/tabs.css.js +1 -1
  49. package/dist/disclosure/tabs/tabs.css.js.map +1 -1
  50. package/dist/feedback/alert/alert.d.ts +8 -1
  51. package/dist/feedback/alert/alert.d.ts.map +1 -1
  52. package/dist/feedback/chip/chip.css.cjs +1 -1
  53. package/dist/feedback/chip/chip.css.cjs.map +1 -1
  54. package/dist/feedback/chip/chip.css.js +1 -1
  55. package/dist/feedback/chip/chip.css.js.map +1 -1
  56. package/dist/feedback/chip/chip.d.ts +6 -2
  57. package/dist/feedback/chip/chip.d.ts.map +1 -1
  58. package/dist/feedback/progress/progress.css.cjs +1 -1
  59. package/dist/feedback/progress/progress.css.cjs.map +1 -1
  60. package/dist/feedback/progress/progress.css.js +1 -1
  61. package/dist/feedback/progress/progress.css.js.map +1 -1
  62. package/dist/feedback/progress/progress.d.ts +6 -0
  63. package/dist/feedback/progress/progress.d.ts.map +1 -1
  64. package/dist/feedback/toast/toast.css.cjs +1 -1
  65. package/dist/feedback/toast/toast.css.cjs.map +1 -1
  66. package/dist/feedback/toast/toast.css.js +1 -1
  67. package/dist/feedback/toast/toast.css.js.map +1 -1
  68. package/dist/feedback/toast/toast.d.ts.map +1 -1
  69. package/dist/frameworks/elements.d.ts +1 -1
  70. package/dist/inputs/button/button.css.cjs +1 -1
  71. package/dist/inputs/button/button.css.cjs.map +1 -1
  72. package/dist/inputs/button/button.css.js +1 -1
  73. package/dist/inputs/button/button.css.js.map +1 -1
  74. package/dist/inputs/combobox/combobox.css.cjs +1 -1
  75. package/dist/inputs/combobox/combobox.css.cjs.map +1 -1
  76. package/dist/inputs/combobox/combobox.css.js +1 -1
  77. package/dist/inputs/combobox/combobox.css.js.map +1 -1
  78. package/dist/inputs/counter/counter.css.cjs +2 -0
  79. package/dist/inputs/counter/counter.css.cjs.map +1 -0
  80. package/dist/inputs/counter/counter.css.js +6 -0
  81. package/dist/inputs/counter/counter.css.js.map +1 -0
  82. package/dist/inputs/counter/counter.d.ts +100 -0
  83. package/dist/inputs/counter/counter.d.ts.map +1 -0
  84. package/dist/inputs/date-picker/date-picker.css.cjs +1 -1
  85. package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
  86. package/dist/inputs/date-picker/date-picker.css.js +1 -1
  87. package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
  88. package/dist/inputs/index.d.ts +4 -0
  89. package/dist/inputs/index.d.ts.map +1 -1
  90. package/dist/inputs/input/input.css.cjs +1 -1
  91. package/dist/inputs/input/input.css.cjs.map +1 -1
  92. package/dist/inputs/input/input.css.js +1 -1
  93. package/dist/inputs/input/input.css.js.map +1 -1
  94. package/dist/inputs/number-input/number-input.css.cjs +1 -1
  95. package/dist/inputs/number-input/number-input.css.cjs.map +1 -1
  96. package/dist/inputs/number-input/number-input.css.js +1 -1
  97. package/dist/inputs/number-input/number-input.css.js.map +1 -1
  98. package/dist/inputs/qr-scanner/qr-scanner.css.cjs +2 -0
  99. package/dist/inputs/qr-scanner/qr-scanner.css.cjs.map +1 -0
  100. package/dist/inputs/qr-scanner/qr-scanner.css.js +6 -0
  101. package/dist/inputs/qr-scanner/qr-scanner.css.js.map +1 -0
  102. package/dist/inputs/qr-scanner/qr-scanner.d.ts +87 -0
  103. package/dist/inputs/qr-scanner/qr-scanner.d.ts.map +1 -0
  104. package/dist/inputs/select/select.css.cjs +1 -1
  105. package/dist/inputs/select/select.css.cjs.map +1 -1
  106. package/dist/inputs/select/select.css.js +1 -1
  107. package/dist/inputs/select/select.css.js.map +1 -1
  108. package/dist/inputs/slider/slider.css.cjs +1 -1
  109. package/dist/inputs/slider/slider.css.cjs.map +1 -1
  110. package/dist/inputs/slider/slider.css.js +1 -1
  111. package/dist/inputs/slider/slider.css.js.map +1 -1
  112. package/dist/keyboard-key.cjs +9 -0
  113. package/dist/keyboard-key.cjs.map +1 -0
  114. package/dist/keyboard-key.js +36 -0
  115. package/dist/keyboard-key.js.map +1 -0
  116. package/dist/menu.cjs +1 -1
  117. package/dist/menu.cjs.map +1 -1
  118. package/dist/menu.js +2 -1
  119. package/dist/menu.js.map +1 -1
  120. package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
  121. package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
  122. package/dist/overlay/command-palette/command-palette.css.js +1 -1
  123. package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
  124. package/dist/overlay/command-palette/command-palette.d.ts +1 -0
  125. package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
  126. package/dist/progress.cjs +14 -6
  127. package/dist/progress.cjs.map +1 -1
  128. package/dist/progress.js +19 -7
  129. package/dist/progress.js.map +1 -1
  130. package/dist/qr-code.cjs +15 -0
  131. package/dist/qr-code.cjs.map +1 -0
  132. package/dist/qr-code.js +70 -0
  133. package/dist/qr-code.js.map +1 -0
  134. package/dist/qr-scanner.cjs +46 -0
  135. package/dist/qr-scanner.cjs.map +1 -0
  136. package/dist/qr-scanner.js +129 -0
  137. package/dist/qr-scanner.js.map +1 -0
  138. package/dist/refine.cjs +365 -199
  139. package/dist/refine.cjs.map +1 -1
  140. package/dist/refine.iife.js +393 -227
  141. package/dist/refine.iife.js.map +1 -1
  142. package/dist/refine.js +740 -574
  143. package/dist/refine.js.map +1 -1
  144. package/dist/tabs.cjs +2 -2
  145. package/dist/tabs.cjs.map +1 -1
  146. package/dist/tabs.js +37 -34
  147. package/dist/tabs.js.map +1 -1
  148. package/dist/toast.cjs +44 -39
  149. package/dist/toast.cjs.map +1 -1
  150. package/dist/toast.js +132 -117
  151. package/dist/toast.js.map +1 -1
  152. package/dist/types/elements.d.ts +9 -0
  153. package/package.json +35 -2
package/dist/tabs.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/theme.css.cjs"),t=require("./core/keyboard.cjs"),n=require("./core/ore.cjs"),r=require("./core/direction.cjs"),i=require("./core/nav.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./disclosure/tabs/tabs.css.cjs");let s=require("@vielzeug/ore"),c=require("@vielzeug/ripple");var l=(0,s.createContext)(`TabsContext`),u=`ore-tabs`;(0,s.define)(u,{props:{...a.themableBundle,...a.sizableBundle,activation:s.prop.oneOf([`auto`,`manual`],`auto`),density:s.prop.oneOf([`compact`,`default`],`default`),label:s.prop.string(),orientation:s.prop.oneOf([`horizontal`,`vertical`],`horizontal`),value:s.prop.string(),variant:s.prop.string()},setup(e){let a=(0,s.getHost)(),o=(0,s.useEmit)(),u=a.shadowRoot,d=(0,s.ref)(),f=(0,s.ref)(),p=(0,c.signal)(e.value.value),m=()=>e.activation.value===`manual`,h=()=>e.orientation.value===`vertical`;(0,s.bind)({attr:{value:()=>p.value??null}});let g=()=>[...a.querySelectorAll(`:scope > ore-tab-item[slot="tabs"]`)],_=()=>g().filter(e=>!e.hasAttribute(`disabled`)),v=e=>{e&&(e.shadowRoot?.querySelector(`[role="tab"]`)??e).focus()},y=(e,t=!1)=>{p.value=e,t&&e&&o(`change`,{value:e})},b=()=>{let e=g();if(e.length===0)return;let t=p.value;if(t&&e.some(e=>e.getAttribute(`value`)===t&&!e.hasAttribute(`disabled`)))return;let n=e.find(e=>!e.hasAttribute(`disabled`))?.getAttribute(`value`)??void 0;y(n,!1)};(0,c.watch)(e.value,e=>{p.value=e,b()});let x=i.createListControl({direction:()=>r.elementDirection(a),getItems:()=>_(),loop:!0,onNavigate:({item:e})=>{if(v(e),!m()){let t=e.getAttribute(`value`);t&&y(t,!0)}},orientation:()=>h()?`vertical`:`both`,signal:n.lifecycleSignal(s.onCleanup)});(0,s.provide)(l,{color:e.color,density:(0,c.computed)(()=>e.density.value??`default`),orientation:(0,c.computed)(()=>e.orientation.value??`horizontal`),size:e.size,value:p,variant:e.variant});let S=e=>{let t=f.value,n=d.value;if(!t||!n||!e)return;let r=e.getBoundingClientRect(),i=n.getBoundingClientRect();if(h()){let e=r.top-i.top+n.scrollTop;t.style.transition=`none`,t.style.height=`${r.height}px`,t.style.width=``,t.style.left=`0`,t.style.top=`0`,t.offsetWidth,t.style.transition=``,t.style.transform=`translateY(${e}px)`}else{let e=r.left-i.left+n.scrollLeft;t.style.transition=`none`,t.style.width=`${r.width}px`,t.style.height=``,t.style.top=``,t.style.left=`0`,t.offsetWidth,t.style.transition=``,t.style.transform=`translateX(${e}px)`}},C=()=>{let e=p.value;if(!e)return;let t=g().find(t=>t.getAttribute(`value`)===e);S(t)};(0,c.watch)(p,()=>{requestAnimationFrame(C)});let w=e=>{let t=e.composedPath().find(e=>e instanceof HTMLElement&&e.localName===`ore-tab-item`);if(!t||t.hasAttribute(`disabled`)||t.closest(`ore-tabs`)!==a)return;let n=t.getAttribute(`value`);n&&n!==p.value&&y(n,!0)},T=t.createInteraction({disabled:(0,c.computed)(()=>!m()),onPress:()=>{let e=_().find(e=>e===document.activeElement||e.shadowRoot?.activeElement===document.activeElement)?.getAttribute(`value`);e&&e!==p.value&&y(e,!0)}});return(0,s.bind)({on:{click:w,keydown:e=>{let t=_();if(t.length===0)return;let n=e.composedPath().find(e=>e instanceof HTMLElement&&e.localName===`ore-tab-item`)??t.find(e=>e.getAttribute(`value`)===p.value),r=n?t.indexOf(n):-1;r>=0&&x.set(r),!x.handleKeydown(e)&&T.handleKeydown(e)}}}),(0,s.onMounted)(()=>{let e=()=>{b(),C()},t=u?.querySelector(`slot[name="tabs"]`);return t&&t.addEventListener(`slotchange`,e),e(),requestAnimationFrame(e),()=>{t&&t.removeEventListener(`slotchange`,e)}}),s.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/theme.css.cjs"),t=require("./core/keyboard.cjs"),n=require("./core/ore.cjs"),r=require("./core/direction.cjs"),i=require("./core/nav.cjs"),a=require("./shared/prop-bundles.cjs"),o=require("./disclosure/tabs/tabs.css.cjs");let s=require("@vielzeug/ore"),c=require("@vielzeug/ripple");var l=(0,s.createContext)(`TabsContext`),u=`ore-tabs`;(0,s.define)(u,{props:{...a.themableBundle,...a.sizableBundle,activation:s.prop.oneOf([`auto`,`manual`],`auto`),density:s.prop.oneOf([`compact`,`default`],`default`),label:s.prop.string(),orientation:s.prop.oneOf([`horizontal`,`vertical`],`horizontal`),value:s.prop.string(),variant:s.prop.string()},setup(e){let a=(0,s.getHost)(),o=(0,s.useEmit)(),u=a.shadowRoot,d=(0,s.ref)(),f=(0,s.ref)(),p=(0,c.signal)(e.value.value),m=(0,c.signal)(!1),h=()=>e.activation.value===`manual`,g=()=>e.orientation.value===`vertical`;(0,s.bind)({attr:{"data-has-panels":()=>m.value?``:null,value:()=>p.value??null}});let _=()=>[...a.querySelectorAll(`:scope > ore-tab-item[slot="tabs"]`)],v=()=>_().filter(e=>!e.hasAttribute(`disabled`)),y=e=>{e&&(e.shadowRoot?.querySelector(`[role="tab"]`)??e).focus()},b=(e,t=!1)=>{p.value=e,t&&e&&o(`change`,{value:e})},x=()=>{let e=_();if(e.length===0)return;let t=p.value;if(t&&e.some(e=>e.getAttribute(`value`)===t&&!e.hasAttribute(`disabled`)))return;let n=e.find(e=>!e.hasAttribute(`disabled`))?.getAttribute(`value`)??void 0;b(n,!1)};(0,c.watch)(e.value,e=>{p.value=e,x()});let S=i.createListControl({direction:()=>r.elementDirection(a),getItems:()=>v(),loop:!0,onNavigate:({item:e})=>{if(y(e),!h()){let t=e.getAttribute(`value`);t&&b(t,!0)}},orientation:()=>g()?`vertical`:`both`,signal:n.lifecycleSignal(s.onCleanup)});(0,s.provide)(l,{color:e.color,density:(0,c.computed)(()=>e.density.value??`default`),orientation:(0,c.computed)(()=>e.orientation.value??`horizontal`),size:e.size,value:p,variant:e.variant});let C=e=>{let t=f.value,n=d.value;if(!t||!n||!e)return;let r=e.getBoundingClientRect(),i=n.getBoundingClientRect();if(g()){let e=r.top-i.top+n.scrollTop;t.style.transition=`none`,t.style.height=`${r.height}px`,t.style.width=``,t.style.left=`0`,t.style.top=`0`,t.offsetWidth,t.style.transition=``,t.style.transform=`translateY(${e}px)`}else{let e=r.left-i.left+n.scrollLeft;t.style.transition=`none`,t.style.width=`${r.width}px`,t.style.height=``,t.style.top=``,t.style.left=`0`,t.offsetWidth,t.style.transition=``,t.style.transform=`translateX(${e}px)`}},w=()=>{let e=p.value;if(!e)return;let t=_().find(t=>t.getAttribute(`value`)===e);C(t)};(0,c.watch)(p,()=>{requestAnimationFrame(w)});let T=e=>{let t=e.composedPath().find(e=>e instanceof HTMLElement&&e.localName===`ore-tab-item`);if(!t||t.hasAttribute(`disabled`)||t.closest(`ore-tabs`)!==a)return;let n=t.getAttribute(`value`);n&&n!==p.value&&b(n,!0)},E=t.createInteraction({disabled:(0,c.computed)(()=>!h()),onPress:()=>{let e=v().find(e=>e===document.activeElement||e.shadowRoot?.activeElement===document.activeElement)?.getAttribute(`value`);e&&e!==p.value&&b(e,!0)}});return(0,s.bind)({on:{click:T,keydown:e=>{let t=v();if(t.length===0)return;let n=e.composedPath().find(e=>e instanceof HTMLElement&&e.localName===`ore-tab-item`)??t.find(e=>e.getAttribute(`value`)===p.value),r=n?t.indexOf(n):-1;r>=0&&S.set(r),!S.handleKeydown(e)&&E.handleKeydown(e)}}}),(0,s.onMounted)(()=>{let e=u?.querySelector(`slot[name="tabs"]`),t=u?.querySelector(`slot:not([name])`),n=()=>{x(),m.value=t?.assignedElements().some(e=>e.localName===`ore-tab-panel`)??!1,w()};return e?.addEventListener(`slotchange`,n),t?.addEventListener(`slotchange`,n),n(),requestAnimationFrame(n),()=>{e?.removeEventListener(`slotchange`,n),t?.removeEventListener(`slotchange`,n)}}),s.html`
2
2
  <div class="tablist-wrapper">
3
3
  <div
4
4
  role="tablist"
@@ -10,7 +10,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
10
10
  </div>
11
11
  <div class="indicator" ref="${f}" part="indicator"></div>
12
12
  </div>
13
- <div class="panels" part="panels">
13
+ <div class="panels" part="panels" ?hidden="${()=>!m.value}">
14
14
  <slot></slot>
15
15
  </div>
16
16
  `},styles:[e.colorThemeMixin,o.default]}),exports.TABS_CTX=l,exports.TABS_TAG=u;
package/dist/tabs.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.cjs","names":[],"sources":["../src/disclosure/tabs/tabs.ts"],"sourcesContent":["import {\n bind,\n createContext,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n provide,\n ref,\n useEmit,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { createInteraction, createListControl, elementDirection, lifecycleSignal } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport styles from './tabs.css?inline';\n\n/** Context provided by ore-tabs to its ore-tab-item and ore-tab-panel children. */\nexport type TabsContext = {\n color: Readable<ThemeColor | undefined>;\n density: Readable<'compact' | 'default'>;\n orientation: Readable<'horizontal' | 'vertical'>;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n variant: Readable<VisualVariant | undefined>;\n};\n/** Injection key for the tabs context. */\nexport const TABS_CTX = createContext<TabsContext>('TabsContext');\n\nexport type OreTabsEvents = {\n change: { value: string };\n};\n\nexport type OreTabsProps = {\n /**\n * Keyboard activation mode.\n * - `'auto'` (default): Selecting a tab on arrow-key focus immediately activates it (ARIA recommendation for most cases).\n * - `'manual'`: Arrow keys only move focus; the user must press Enter or Space to activate the focused tab.\n */\n activation?: 'auto' | 'manual';\n /** Theme color */\n color?: ThemeColor;\n /** Spatial density; compact renders a 24px tab control for dense interfaces. */\n density?: 'compact' | 'default';\n /** Accessible label for the tablist (passed as aria-label). Use when there is no visible heading labelling the tabs. */\n label?: string;\n /** Tab list orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Component size */\n size?: ComponentSize;\n /** Currently selected tab value */\n value?: string;\n /** Visual style variant */\n variant?: VisualVariant;\n};\n\n/**\n * Tabs container. Manages tab selection and syncs state to child tab items and panels.\n *\n * @element ore-tabs\n * @element ore-tab-item - Child element for tab buttons (auto-discovered)\n * @element ore-tab-panel - Child element for tab content (auto-discovered)\n *\n * @attr {string} value - The value of the currently selected tab\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} density - Spatial density: 'default' | 'compact'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @fires change - Emitted when the active tab changes with detail: { value: string }\n *\n * @slot tabs - Place `ore-tab-item` elements here\n * @slot - Place `ore-tab-panel` elements here\n *\n * @cssprop --tabs-radius - Border radius of the tablist container and panels\n * @cssprop --tabs-transition - Transition duration/easing for the active indicator\n * @cssprop --tabs-indicator-color - Color of the sliding active indicator line\n * @cssprop --tabs-bg - Background of the host element (flat variant)\n * @cssprop --tabs-tablist-bg - Tablist container background (solid/frost variants)\n * @cssprop --tabs-tablist-border-color - Tablist container border color\n * @part tablist - Container that holds the slotted tab items\n * @part indicator - Active tab indicator element\n * @part panels - Container that holds tab panel content\n * @example\n * ```html\n * <ore-tabs value=\"tab1\" variant=\"bordered\">\n * <ore-tab-item slot=\"tabs\" value=\"tab1\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"tab2\">Settings</ore-tab-item>\n * <ore-tab-panel value=\"tab1\"><p>Overview content</p></ore-tab-panel>\n * <ore-tab-panel value=\"tab2\"><p>Settings content</p></ore-tab-panel>\n * </ore-tabs>\n * ```\n */\nexport const TABS_TAG = 'ore-tabs' as const;\ndefine<OreTabsProps>(TABS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n activation: prop.oneOf(['auto', 'manual'] as const, 'auto'),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n value: prop.string(),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreTabsEvents>();\n\n const shadowRoot = el.shadowRoot;\n const tablistRef = ref<HTMLElement>();\n const indicatorRef = ref<HTMLElement>();\n const selectedValue = signal<string | undefined>(props.value.value);\n const isManualActivation = () => props.activation.value === 'manual';\n const isVertical = () => props.orientation.value === 'vertical';\n\n bind({\n attr: {\n value: () => selectedValue.value ?? null,\n },\n });\n\n const getTabs = () => [...el.querySelectorAll<HTMLElement>(':scope > ore-tab-item[slot=\"tabs\"]')];\n const getEnabledTabs = () => getTabs().filter((t) => !t.hasAttribute('disabled'));\n const focusTab = (tab: HTMLElement | undefined) => {\n if (!tab) return;\n\n const focusable = tab.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? tab;\n\n focusable.focus();\n };\n\n // ────────────────────────────────────────────────────────────────\n // Selection State Management\n // ────────────────────────────────────────────────────────────────\n\n const setSelection = (value: string | undefined, shouldEmit = false) => {\n selectedValue.value = value;\n\n if (shouldEmit && value) emit('change', { value });\n };\n\n const ensureSelection = () => {\n const tabs = getTabs();\n\n if (tabs.length === 0) return; // No tabs yet, keep current selection\n\n const current = selectedValue.value;\n const hasCurrent = current\n ? tabs.some((tab) => tab.getAttribute('value') === current && !tab.hasAttribute('disabled'))\n : false;\n\n if (hasCurrent) return;\n\n const firstEnabled = tabs.find((tab) => !tab.hasAttribute('disabled'))?.getAttribute('value') ?? undefined;\n\n setSelection(firstEnabled, false);\n };\n\n watch(props.value, (value) => {\n selectedValue.value = value;\n ensureSelection();\n });\n\n // ────────────────────────────────────────────────────────────────\n // List Control for Keyboard Navigation\n // ────────────────────────────────────────────────────────────────\n\n const listControl = createListControl({\n direction: () => elementDirection(el),\n getItems: () => getEnabledTabs(),\n loop: true,\n onNavigate: ({ item }) => {\n focusTab(item);\n\n if (!isManualActivation()) {\n const value = item.getAttribute('value');\n\n if (value) setSelection(value, true);\n }\n },\n orientation: () => (isVertical() ? 'vertical' : 'both'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ────────────────────────────────────────────────────────────────\n // Context & Indicator Management\n // ────────────────────────────────────────────────────────────────\n\n provide(TABS_CTX, {\n color: props.color,\n density: computed(() => props.density.value ?? 'default'),\n orientation: computed(() => props.orientation.value ?? 'horizontal'),\n size: props.size,\n value: selectedValue,\n variant: props.variant,\n });\n\n const moveIndicator = (activeTab: HTMLElement | undefined) => {\n const indicator = indicatorRef.value;\n const tablist = tablistRef.value;\n\n if (!indicator || !tablist || !activeTab) return;\n\n const tabRect = activeTab.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (isVertical()) {\n const y = tabRect.top - listRect.top + tablist.scrollTop;\n\n indicator.style.transition = 'none';\n indicator.style.height = `${tabRect.height}px`;\n indicator.style.width = '';\n indicator.style.left = '0';\n indicator.style.top = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateY(${y}px)`;\n } else {\n const x = tabRect.left - listRect.left + tablist.scrollLeft;\n\n indicator.style.transition = 'none';\n indicator.style.width = `${tabRect.width}px`;\n indicator.style.height = '';\n indicator.style.top = '';\n indicator.style.left = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateX(${x}px)`;\n }\n };\n\n const updateIndicator = () => {\n const value = selectedValue.value;\n\n if (!value) return;\n\n const activeTab = getTabs().find((t) => t.getAttribute('value') === value);\n\n moveIndicator(activeTab);\n };\n\n watch(selectedValue, () => {\n requestAnimationFrame(updateIndicator);\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const handleTabClick = (e: Event) => {\n const tab = e\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item');\n\n if (!tab || tab.hasAttribute('disabled')) return;\n\n // Guard: only respond to tab-items that belong to THIS tabs instance\n if (tab.closest('ore-tabs') !== el) return;\n\n const value = tab.getAttribute('value');\n\n if (!value || value === selectedValue.value) return;\n\n setSelection(value, true);\n };\n\n const activateFocusedTab = (): void => {\n const tabs = getEnabledTabs();\n const focusedTab = tabs.find(\n (tab) => tab === document.activeElement || tab.shadowRoot?.activeElement === document.activeElement,\n );\n const focusedValue = focusedTab?.getAttribute('value');\n\n if (focusedValue && focusedValue !== selectedValue.value) setSelection(focusedValue, true);\n };\n\n const manualActivationPress = createInteraction({\n disabled: computed(() => !isManualActivation()),\n onPress: activateFocusedTab,\n });\n\n const handleKeydown = (e: KeyboardEvent) => {\n const tabs = getEnabledTabs();\n\n if (tabs.length === 0) return;\n\n const path = e.composedPath();\n const activeTabFromEvent = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item',\n );\n\n const tabFromEvent = activeTabFromEvent ?? tabs.find((t) => t.getAttribute('value') === selectedValue.value);\n const focused = tabFromEvent ? tabs.indexOf(tabFromEvent) : -1;\n\n if (focused >= 0) listControl.set(focused);\n\n if (listControl.handleKeydown(e)) return;\n\n manualActivationPress.handleKeydown(e);\n };\n\n bind({\n on: {\n click: handleTabClick,\n keydown: handleKeydown,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const syncSelection = () => {\n ensureSelection();\n updateIndicator();\n };\n\n const tabsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tabs\"]');\n\n if (tabsSlot) {\n tabsSlot.addEventListener('slotchange', syncSelection);\n }\n\n syncSelection();\n requestAnimationFrame(syncSelection);\n\n return () => {\n if (tabsSlot) {\n tabsSlot.removeEventListener('slotchange', syncSelection);\n }\n };\n });\n\n return html`\n <div class=\"tablist-wrapper\">\n <div\n role=\"tablist\"\n ref=\"${tablistRef}\"\n part=\"tablist\"\n aria-orientation=\"${props.orientation}\"\n aria-label=\"${props.label}\">\n <slot name=\"tabs\"></slot>\n </div>\n <div class=\"indicator\" ref=\"${indicatorRef}\" part=\"indicator\"></div>\n </div>\n <div class=\"panels\" part=\"panels\">\n <slot></slot>\n </div>\n `;\n },\n styles: [colorThemeMixin, styles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"tabs.cjs","names":[],"sources":["../src/disclosure/tabs/tabs.ts"],"sourcesContent":["import {\n bind,\n createContext,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n provide,\n ref,\n useEmit,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { createInteraction, createListControl, elementDirection, lifecycleSignal } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport styles from './tabs.css?inline';\n\n/** Context provided by ore-tabs to its ore-tab-item and ore-tab-panel children. */\nexport type TabsContext = {\n color: Readable<ThemeColor | undefined>;\n density: Readable<'compact' | 'default'>;\n orientation: Readable<'horizontal' | 'vertical'>;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n variant: Readable<VisualVariant | undefined>;\n};\n/** Injection key for the tabs context. */\nexport const TABS_CTX = createContext<TabsContext>('TabsContext');\n\nexport type OreTabsEvents = {\n change: { value: string };\n};\n\nexport type OreTabsProps = {\n /**\n * Keyboard activation mode.\n * - `'auto'` (default): Selecting a tab on arrow-key focus immediately activates it (ARIA recommendation for most cases).\n * - `'manual'`: Arrow keys only move focus; the user must press Enter or Space to activate the focused tab.\n */\n activation?: 'auto' | 'manual';\n /** Theme color */\n color?: ThemeColor;\n /** Spatial density; compact renders a 24px tab control for dense interfaces. */\n density?: 'compact' | 'default';\n /** Accessible label for the tablist (passed as aria-label). Use when there is no visible heading labelling the tabs. */\n label?: string;\n /** Tab list orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Component size */\n size?: ComponentSize;\n /** Currently selected tab value */\n value?: string;\n /** Visual style variant */\n variant?: VisualVariant;\n};\n\n/**\n * Tabs container. Manages tab selection and syncs state to child tab items and panels.\n *\n * @element ore-tabs\n * @element ore-tab-item - Child element for tab buttons (auto-discovered)\n * @element ore-tab-panel - Child element for tab content (auto-discovered)\n *\n * @attr {string} value - The value of the currently selected tab\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} density - Spatial density: 'default' | 'compact'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @fires change - Emitted when the active tab changes with detail: { value: string }\n *\n * @slot tabs - Place `ore-tab-item` elements here\n * @slot - Place `ore-tab-panel` elements here\n *\n * @cssprop --tabs-radius - Border radius of the tablist container and panels\n * @cssprop --tabs-transition - Transition duration/easing for the active indicator\n * @cssprop --tabs-indicator-color - Color of the sliding active indicator line\n * @cssprop --tabs-bg - Background of the host element (flat variant)\n * @cssprop --tabs-tablist-bg - Tablist container background (solid/frost variants)\n * @cssprop --tabs-tablist-border-color - Tablist container border color\n * @part tablist - Container that holds the slotted tab items\n * @part indicator - Active tab indicator element\n * @part panels - Container that holds tab panel content\n * @example\n * ```html\n * <ore-tabs value=\"tab1\" variant=\"bordered\">\n * <ore-tab-item slot=\"tabs\" value=\"tab1\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"tab2\">Settings</ore-tab-item>\n * <ore-tab-panel value=\"tab1\"><p>Overview content</p></ore-tab-panel>\n * <ore-tab-panel value=\"tab2\"><p>Settings content</p></ore-tab-panel>\n * </ore-tabs>\n * ```\n */\nexport const TABS_TAG = 'ore-tabs' as const;\ndefine<OreTabsProps>(TABS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n activation: prop.oneOf(['auto', 'manual'] as const, 'auto'),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n value: prop.string(),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreTabsEvents>();\n\n const shadowRoot = el.shadowRoot;\n const tablistRef = ref<HTMLElement>();\n const indicatorRef = ref<HTMLElement>();\n const selectedValue = signal<string | undefined>(props.value.value);\n const hasPanels = signal(false);\n const isManualActivation = () => props.activation.value === 'manual';\n const isVertical = () => props.orientation.value === 'vertical';\n\n bind({\n attr: {\n 'data-has-panels': () => (hasPanels.value ? '' : null),\n value: () => selectedValue.value ?? null,\n },\n });\n\n const getTabs = () => [...el.querySelectorAll<HTMLElement>(':scope > ore-tab-item[slot=\"tabs\"]')];\n const getEnabledTabs = () => getTabs().filter((t) => !t.hasAttribute('disabled'));\n const focusTab = (tab: HTMLElement | undefined) => {\n if (!tab) return;\n\n const focusable = tab.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? tab;\n\n focusable.focus();\n };\n\n // ────────────────────────────────────────────────────────────────\n // Selection State Management\n // ────────────────────────────────────────────────────────────────\n\n const setSelection = (value: string | undefined, shouldEmit = false) => {\n selectedValue.value = value;\n\n if (shouldEmit && value) emit('change', { value });\n };\n\n const ensureSelection = () => {\n const tabs = getTabs();\n\n if (tabs.length === 0) return; // No tabs yet, keep current selection\n\n const current = selectedValue.value;\n const hasCurrent = current\n ? tabs.some((tab) => tab.getAttribute('value') === current && !tab.hasAttribute('disabled'))\n : false;\n\n if (hasCurrent) return;\n\n const firstEnabled = tabs.find((tab) => !tab.hasAttribute('disabled'))?.getAttribute('value') ?? undefined;\n\n setSelection(firstEnabled, false);\n };\n\n watch(props.value, (value) => {\n selectedValue.value = value;\n ensureSelection();\n });\n\n // ────────────────────────────────────────────────────────────────\n // List Control for Keyboard Navigation\n // ────────────────────────────────────────────────────────────────\n\n const listControl = createListControl({\n direction: () => elementDirection(el),\n getItems: () => getEnabledTabs(),\n loop: true,\n onNavigate: ({ item }) => {\n focusTab(item);\n\n if (!isManualActivation()) {\n const value = item.getAttribute('value');\n\n if (value) setSelection(value, true);\n }\n },\n orientation: () => (isVertical() ? 'vertical' : 'both'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ────────────────────────────────────────────────────────────────\n // Context & Indicator Management\n // ────────────────────────────────────────────────────────────────\n\n provide(TABS_CTX, {\n color: props.color,\n density: computed(() => props.density.value ?? 'default'),\n orientation: computed(() => props.orientation.value ?? 'horizontal'),\n size: props.size,\n value: selectedValue,\n variant: props.variant,\n });\n\n const moveIndicator = (activeTab: HTMLElement | undefined) => {\n const indicator = indicatorRef.value;\n const tablist = tablistRef.value;\n\n if (!indicator || !tablist || !activeTab) return;\n\n const tabRect = activeTab.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (isVertical()) {\n const y = tabRect.top - listRect.top + tablist.scrollTop;\n\n indicator.style.transition = 'none';\n indicator.style.height = `${tabRect.height}px`;\n indicator.style.width = '';\n indicator.style.left = '0';\n indicator.style.top = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateY(${y}px)`;\n } else {\n const x = tabRect.left - listRect.left + tablist.scrollLeft;\n\n indicator.style.transition = 'none';\n indicator.style.width = `${tabRect.width}px`;\n indicator.style.height = '';\n indicator.style.top = '';\n indicator.style.left = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateX(${x}px)`;\n }\n };\n\n const updateIndicator = () => {\n const value = selectedValue.value;\n\n if (!value) return;\n\n const activeTab = getTabs().find((t) => t.getAttribute('value') === value);\n\n moveIndicator(activeTab);\n };\n\n watch(selectedValue, () => {\n requestAnimationFrame(updateIndicator);\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const handleTabClick = (e: Event) => {\n const tab = e\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item');\n\n if (!tab || tab.hasAttribute('disabled')) return;\n\n // Guard: only respond to tab-items that belong to THIS tabs instance\n if (tab.closest('ore-tabs') !== el) return;\n\n const value = tab.getAttribute('value');\n\n if (!value || value === selectedValue.value) return;\n\n setSelection(value, true);\n };\n\n const activateFocusedTab = (): void => {\n const tabs = getEnabledTabs();\n const focusedTab = tabs.find(\n (tab) => tab === document.activeElement || tab.shadowRoot?.activeElement === document.activeElement,\n );\n const focusedValue = focusedTab?.getAttribute('value');\n\n if (focusedValue && focusedValue !== selectedValue.value) setSelection(focusedValue, true);\n };\n\n const manualActivationPress = createInteraction({\n disabled: computed(() => !isManualActivation()),\n onPress: activateFocusedTab,\n });\n\n const handleKeydown = (e: KeyboardEvent) => {\n const tabs = getEnabledTabs();\n\n if (tabs.length === 0) return;\n\n const path = e.composedPath();\n const activeTabFromEvent = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item',\n );\n\n const tabFromEvent = activeTabFromEvent ?? tabs.find((t) => t.getAttribute('value') === selectedValue.value);\n const focused = tabFromEvent ? tabs.indexOf(tabFromEvent) : -1;\n\n if (focused >= 0) listControl.set(focused);\n\n if (listControl.handleKeydown(e)) return;\n\n manualActivationPress.handleKeydown(e);\n };\n\n bind({\n on: {\n click: handleTabClick,\n keydown: handleKeydown,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const tabsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tabs\"]');\n const panelsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n const sync = () => {\n ensureSelection();\n hasPanels.value = panelsSlot?.assignedElements().some((child) => child.localName === 'ore-tab-panel') ?? false;\n updateIndicator();\n };\n\n tabsSlot?.addEventListener('slotchange', sync);\n panelsSlot?.addEventListener('slotchange', sync);\n\n sync();\n requestAnimationFrame(sync);\n\n return () => {\n tabsSlot?.removeEventListener('slotchange', sync);\n panelsSlot?.removeEventListener('slotchange', sync);\n };\n });\n\n return html`\n <div class=\"tablist-wrapper\">\n <div\n role=\"tablist\"\n ref=\"${tablistRef}\"\n part=\"tablist\"\n aria-orientation=\"${props.orientation}\"\n aria-label=\"${props.label}\">\n <slot name=\"tabs\"></slot>\n </div>\n <div class=\"indicator\" ref=\"${indicatorRef}\" part=\"indicator\"></div>\n </div>\n <div class=\"panels\" part=\"panels\" ?hidden=\"${() => !hasPanels.value}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [colorThemeMixin, styles],\n});\n"],"mappings":"+XA8BA,IAAa,GAAA,EAAW,EAAA,cAAA,CAA2B,aAAa,EAkEnD,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,WAAY,EAAA,KAAK,MAAM,CAAC,OAAQ,QAAQ,EAAY,MAAM,EAC1D,QAAS,EAAA,KAAK,MAAM,CAAC,UAAW,SAAS,EAAY,SAAS,EAC9D,MAAO,EAAA,KAAK,OAAO,EACnB,YAAa,EAAA,KAAK,MAAM,CAAC,aAAc,UAAU,EAAY,YAAY,EACzE,MAAO,EAAA,KAAK,OAAO,EACnB,QAAS,EAAA,KAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAAuB,EAE9B,EAAa,EAAG,WAChB,GAAA,EAAa,EAAA,IAAA,CAAiB,EAC9B,GAAA,EAAe,EAAA,IAAA,CAAiB,EAChC,GAAA,EAAgB,EAAA,OAAA,CAA2B,EAAM,MAAM,KAAK,EAC5D,GAAA,EAAY,EAAA,OAAA,CAAO,EAAK,EACxB,MAA2B,EAAM,WAAW,QAAU,SACtD,MAAmB,EAAM,YAAY,QAAU,YAErD,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,sBAA0B,EAAU,MAAQ,GAAK,KACjD,UAAa,EAAc,OAAS,IACtC,CACF,CAAC,EAED,IAAM,MAAgB,CAAC,GAAG,EAAG,iBAA8B,oCAAoC,CAAC,EAC1F,MAAuB,EAAQ,CAAC,CAAC,OAAQ,GAAM,CAAC,EAAE,aAAa,UAAU,CAAC,EAC1E,EAAY,GAAiC,CAC5C,IAEa,EAAI,YAAY,cAA2B,cAAc,GAAK,EAAA,CAEtE,MAAM,CAClB,EAMM,GAAgB,EAA2B,EAAa,KAAU,CACtE,EAAc,MAAQ,EAElB,GAAc,GAAO,EAAK,SAAU,CAAE,OAAM,CAAC,CACnD,EAEM,MAAwB,CAC5B,IAAM,EAAO,EAAQ,EAErB,GAAI,EAAK,SAAW,EAAG,OAEvB,IAAM,EAAU,EAAc,MAK9B,GAJmB,GACf,EAAK,KAAM,GAAQ,EAAI,aAAa,OAAO,IAAM,GAAW,CAAC,EAAI,aAAa,UAAU,CAAC,EAG7E,OAEhB,IAAM,EAAe,EAAK,KAAM,GAAQ,CAAC,EAAI,aAAa,UAAU,CAAC,CAAC,EAAE,aAAa,OAAO,GAAK,IAAA,GAEjG,EAAa,EAAc,EAAK,CAClC,GAEA,EAAA,EAAA,MAAA,CAAM,EAAM,MAAQ,GAAU,CAC5B,EAAc,MAAQ,EACtB,EAAgB,CAClB,CAAC,EAMD,IAAM,EAAc,EAAA,kBAAkB,CACpC,cAAiB,EAAA,iBAAiB,CAAE,EACpC,aAAgB,EAAe,EAC/B,KAAM,GACN,YAAa,CAAE,UAAW,CAGxB,GAFA,EAAS,CAAI,EAET,CAAC,EAAmB,EAAG,CACzB,IAAM,EAAQ,EAAK,aAAa,OAAO,EAEnC,GAAO,EAAa,EAAO,EAAI,CACrC,CACF,EACA,gBAAoB,EAAW,EAAI,WAAa,OAChD,OAAQ,EAAA,gBAAgB,EAAA,SAAS,CACnC,CAAC,GAMD,EAAA,EAAA,QAAA,CAAQ,EAAU,CAChB,MAAO,EAAM,MACb,SAAA,EAAS,EAAA,SAAA,KAAe,EAAM,QAAQ,OAAS,SAAS,EACxD,aAAA,EAAa,EAAA,SAAA,KAAe,EAAM,YAAY,OAAS,YAAY,EACnE,KAAM,EAAM,KACZ,MAAO,EACP,QAAS,EAAM,OACjB,CAAC,EAED,IAAM,EAAiB,GAAuC,CAC5D,IAAM,EAAY,EAAa,MACzB,EAAU,EAAW,MAE3B,GAAI,CAAC,GAAa,CAAC,GAAW,CAAC,EAAW,OAE1C,IAAM,EAAU,EAAU,sBAAsB,EAC1C,EAAW,EAAQ,sBAAsB,EAE/C,GAAI,EAAW,EAAG,CAChB,IAAM,EAAI,EAAQ,IAAM,EAAS,IAAM,EAAQ,UAE/C,EAAU,MAAM,WAAa,OAC7B,EAAU,MAAM,OAAS,GAAG,EAAQ,OAAO,IAC3C,EAAU,MAAM,MAAQ,GACxB,EAAU,MAAM,KAAO,IACvB,EAAU,MAAM,IAAM,IACtB,EAAe,YACf,EAAU,MAAM,WAAa,GAC7B,EAAU,MAAM,UAAY,cAAc,EAAE,IAC9C,KAAO,CACL,IAAM,EAAI,EAAQ,KAAO,EAAS,KAAO,EAAQ,WAEjD,EAAU,MAAM,WAAa,OAC7B,EAAU,MAAM,MAAQ,GAAG,EAAQ,MAAM,IACzC,EAAU,MAAM,OAAS,GACzB,EAAU,MAAM,IAAM,GACtB,EAAU,MAAM,KAAO,IACvB,EAAe,YACf,EAAU,MAAM,WAAa,GAC7B,EAAU,MAAM,UAAY,cAAc,EAAE,IAC9C,CACF,EAEM,MAAwB,CAC5B,IAAM,EAAQ,EAAc,MAE5B,GAAI,CAAC,EAAO,OAEZ,IAAM,EAAY,EAAQ,CAAC,CAAC,KAAM,GAAM,EAAE,aAAa,OAAO,IAAM,CAAK,EAEzE,EAAc,CAAS,CACzB,GAEA,EAAA,EAAA,MAAA,CAAM,MAAqB,CACzB,sBAAsB,CAAe,CACvC,CAAC,EAMD,IAAM,EAAkB,GAAa,CACnC,IAAM,EAAM,EACT,aAAa,CAAC,CACd,KAAM,GAA8B,aAAgB,aAAe,EAAK,YAAc,cAAc,EAKvG,GAHI,CAAC,GAAO,EAAI,aAAa,UAAU,GAGnC,EAAI,QAAQ,UAAU,IAAM,EAAI,OAEpC,IAAM,EAAQ,EAAI,aAAa,OAAO,EAEjC,GAAS,IAAU,EAAc,OAEtC,EAAa,EAAO,EAAI,CAC1B,EAYM,EAAwB,EAAA,kBAAkB,CAC9C,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAmB,CAAC,EAC9C,YAZqC,CAKrC,IAAM,EAJO,EACM,CAAA,CAAK,KACrB,GAAQ,IAAQ,SAAS,eAAiB,EAAI,YAAY,gBAAkB,SAAS,aAEnE,CAAA,EAAY,aAAa,OAAO,EAEjD,GAAgB,IAAiB,EAAc,OAAO,EAAa,EAAc,EAAI,CAC3F,CAKA,CAAC,EAsDD,OAhCA,EAAA,EAAA,KAAA,CAAK,CACH,GAAI,CACF,MAAO,EACP,QAvBmB,GAAqB,CAC1C,IAAM,EAAO,EAAe,EAE5B,GAAI,EAAK,SAAW,EAAG,OAOvB,IAAM,EALO,EAAE,aACY,CAAA,CAAK,KAC7B,GAA8B,aAAgB,aAAe,EAAK,YAAc,cAG9D,GAAsB,EAAK,KAAM,GAAM,EAAE,aAAa,OAAO,IAAM,EAAc,KAAK,EACrG,EAAU,EAAe,EAAK,QAAQ,CAAY,EAAI,GAExD,GAAW,GAAG,EAAY,IAAI,CAAO,EAErC,GAAY,cAAc,CAAC,GAE/B,EAAsB,cAAc,CAAC,CACvC,CAME,CACF,CAAC,GAMD,EAAA,EAAA,UAAA,KAAgB,CACd,IAAM,EAAW,GAAY,cAA+B,mBAAmB,EACzE,EAAa,GAAY,cAA+B,kBAAkB,EAC1E,MAAa,CACjB,EAAgB,EAChB,EAAU,MAAQ,GAAY,iBAAiB,CAAC,CAAC,KAAM,GAAU,EAAM,YAAc,eAAe,GAAK,GACzG,EAAgB,CAClB,EAQA,OANA,GAAU,iBAAiB,aAAc,CAAI,EAC7C,GAAY,iBAAiB,aAAc,CAAI,EAE/C,EAAK,EACL,sBAAsB,CAAI,MAEb,CACX,GAAU,oBAAoB,aAAc,CAAI,EAChD,GAAY,oBAAoB,aAAc,CAAI,CACpD,CACF,CAAC,EAEM,EAAA,IAAI;;;;iBAIE,EAAW;;8BAEE,EAAM,YAAY;wBACxB,EAAM,MAAM;;;sCAGE,EAAa;;uDAEM,CAAC,EAAU,MAAM;;;KAIxE,EACA,OAAQ,CAAC,EAAA,gBAAiB,EAAA,OAAM,CAClC,CAAC"}
package/dist/tabs.js CHANGED
@@ -21,34 +21,37 @@ u(C, {
21
21
  variant: h.string()
22
22
  },
23
23
  setup(e) {
24
- let a = d(), o = v(), s = a.shadowRoot, l = _(), u = _(), h = b(e.value.value), C = () => e.activation.value === "manual", w = () => e.orientation.value === "vertical";
25
- c({ attr: { value: () => h.value ?? null } });
26
- let T = () => [...a.querySelectorAll(":scope > ore-tab-item[slot=\"tabs\"]")], E = () => T().filter((e) => !e.hasAttribute("disabled")), D = (e) => {
24
+ let a = d(), o = v(), s = a.shadowRoot, l = _(), u = _(), h = b(e.value.value), C = b(!1), w = () => e.activation.value === "manual", T = () => e.orientation.value === "vertical";
25
+ c({ attr: {
26
+ "data-has-panels": () => C.value ? "" : null,
27
+ value: () => h.value ?? null
28
+ } });
29
+ let E = () => [...a.querySelectorAll(":scope > ore-tab-item[slot=\"tabs\"]")], D = () => E().filter((e) => !e.hasAttribute("disabled")), O = (e) => {
27
30
  e && (e.shadowRoot?.querySelector("[role=\"tab\"]") ?? e).focus();
28
- }, O = (e, t = !1) => {
31
+ }, k = (e, t = !1) => {
29
32
  h.value = e, t && e && o("change", { value: e });
30
- }, k = () => {
31
- let e = T();
33
+ }, A = () => {
34
+ let e = E();
32
35
  if (e.length === 0) return;
33
36
  let t = h.value;
34
37
  if (t && e.some((e) => e.getAttribute("value") === t && !e.hasAttribute("disabled"))) return;
35
38
  let n = e.find((e) => !e.hasAttribute("disabled"))?.getAttribute("value") ?? void 0;
36
- O(n, !1);
39
+ k(n, !1);
37
40
  };
38
41
  x(e.value, (e) => {
39
- h.value = e, k();
42
+ h.value = e, A();
40
43
  });
41
- let A = i({
44
+ let j = i({
42
45
  direction: () => r(a),
43
- getItems: () => E(),
46
+ getItems: () => D(),
44
47
  loop: !0,
45
48
  onNavigate: ({ item: e }) => {
46
- if (D(e), !C()) {
49
+ if (O(e), !w()) {
47
50
  let t = e.getAttribute("value");
48
- t && O(t, !0);
51
+ t && k(t, !0);
49
52
  }
50
53
  },
51
- orientation: () => w() ? "vertical" : "both",
54
+ orientation: () => T() ? "vertical" : "both",
52
55
  signal: n(p)
53
56
  });
54
57
  g(S, {
@@ -59,52 +62,52 @@ u(C, {
59
62
  value: h,
60
63
  variant: e.variant
61
64
  });
62
- let j = (e) => {
65
+ let M = (e) => {
63
66
  let t = u.value, n = l.value;
64
67
  if (!t || !n || !e) return;
65
68
  let r = e.getBoundingClientRect(), i = n.getBoundingClientRect();
66
- if (w()) {
69
+ if (T()) {
67
70
  let e = r.top - i.top + n.scrollTop;
68
71
  t.style.transition = "none", t.style.height = `${r.height}px`, t.style.width = "", t.style.left = "0", t.style.top = "0", t.offsetWidth, t.style.transition = "", t.style.transform = `translateY(${e}px)`;
69
72
  } else {
70
73
  let e = r.left - i.left + n.scrollLeft;
71
74
  t.style.transition = "none", t.style.width = `${r.width}px`, t.style.height = "", t.style.top = "", t.style.left = "0", t.offsetWidth, t.style.transition = "", t.style.transform = `translateX(${e}px)`;
72
75
  }
73
- }, M = () => {
76
+ }, N = () => {
74
77
  let e = h.value;
75
78
  if (!e) return;
76
- let t = T().find((t) => t.getAttribute("value") === e);
77
- j(t);
79
+ let t = E().find((t) => t.getAttribute("value") === e);
80
+ M(t);
78
81
  };
79
82
  x(h, () => {
80
- requestAnimationFrame(M);
83
+ requestAnimationFrame(N);
81
84
  });
82
- let N = (e) => {
85
+ let P = (e) => {
83
86
  let t = e.composedPath().find((e) => e instanceof HTMLElement && e.localName === "ore-tab-item");
84
87
  if (!t || t.hasAttribute("disabled") || t.closest("ore-tabs") !== a) return;
85
88
  let n = t.getAttribute("value");
86
- n && n !== h.value && O(n, !0);
87
- }, P = t({
88
- disabled: y(() => !C()),
89
+ n && n !== h.value && k(n, !0);
90
+ }, F = t({
91
+ disabled: y(() => !w()),
89
92
  onPress: () => {
90
- let e = E().find((e) => e === document.activeElement || e.shadowRoot?.activeElement === document.activeElement)?.getAttribute("value");
91
- e && e !== h.value && O(e, !0);
93
+ let e = D().find((e) => e === document.activeElement || e.shadowRoot?.activeElement === document.activeElement)?.getAttribute("value");
94
+ e && e !== h.value && k(e, !0);
92
95
  }
93
96
  });
94
97
  return c({ on: {
95
- click: N,
98
+ click: P,
96
99
  keydown: (e) => {
97
- let t = E();
100
+ let t = D();
98
101
  if (t.length === 0) return;
99
102
  let n = e.composedPath().find((e) => e instanceof HTMLElement && e.localName === "ore-tab-item") ?? t.find((e) => e.getAttribute("value") === h.value), r = n ? t.indexOf(n) : -1;
100
- r >= 0 && A.set(r), !A.handleKeydown(e) && P.handleKeydown(e);
103
+ r >= 0 && j.set(r), !j.handleKeydown(e) && F.handleKeydown(e);
101
104
  }
102
105
  } }), m(() => {
103
- let e = () => {
104
- k(), M();
105
- }, t = s?.querySelector("slot[name=\"tabs\"]");
106
- return t && t.addEventListener("slotchange", e), e(), requestAnimationFrame(e), () => {
107
- t && t.removeEventListener("slotchange", e);
106
+ let e = s?.querySelector("slot[name=\"tabs\"]"), t = s?.querySelector("slot:not([name])"), n = () => {
107
+ A(), C.value = t?.assignedElements().some((e) => e.localName === "ore-tab-panel") ?? !1, N();
108
+ };
109
+ return e?.addEventListener("slotchange", n), t?.addEventListener("slotchange", n), n(), requestAnimationFrame(n), () => {
110
+ e?.removeEventListener("slotchange", n), t?.removeEventListener("slotchange", n);
108
111
  };
109
112
  }), f`
110
113
  <div class="tablist-wrapper">
@@ -118,7 +121,7 @@ u(C, {
118
121
  </div>
119
122
  <div class="indicator" ref="${u}" part="indicator"></div>
120
123
  </div>
121
- <div class="panels" part="panels">
124
+ <div class="panels" part="panels" ?hidden="${() => !C.value}">
122
125
  <slot></slot>
123
126
  </div>
124
127
  `;
package/dist/tabs.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","names":[],"sources":["../src/disclosure/tabs/tabs.ts"],"sourcesContent":["import {\n bind,\n createContext,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n provide,\n ref,\n useEmit,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { createInteraction, createListControl, elementDirection, lifecycleSignal } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport styles from './tabs.css?inline';\n\n/** Context provided by ore-tabs to its ore-tab-item and ore-tab-panel children. */\nexport type TabsContext = {\n color: Readable<ThemeColor | undefined>;\n density: Readable<'compact' | 'default'>;\n orientation: Readable<'horizontal' | 'vertical'>;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n variant: Readable<VisualVariant | undefined>;\n};\n/** Injection key for the tabs context. */\nexport const TABS_CTX = createContext<TabsContext>('TabsContext');\n\nexport type OreTabsEvents = {\n change: { value: string };\n};\n\nexport type OreTabsProps = {\n /**\n * Keyboard activation mode.\n * - `'auto'` (default): Selecting a tab on arrow-key focus immediately activates it (ARIA recommendation for most cases).\n * - `'manual'`: Arrow keys only move focus; the user must press Enter or Space to activate the focused tab.\n */\n activation?: 'auto' | 'manual';\n /** Theme color */\n color?: ThemeColor;\n /** Spatial density; compact renders a 24px tab control for dense interfaces. */\n density?: 'compact' | 'default';\n /** Accessible label for the tablist (passed as aria-label). Use when there is no visible heading labelling the tabs. */\n label?: string;\n /** Tab list orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Component size */\n size?: ComponentSize;\n /** Currently selected tab value */\n value?: string;\n /** Visual style variant */\n variant?: VisualVariant;\n};\n\n/**\n * Tabs container. Manages tab selection and syncs state to child tab items and panels.\n *\n * @element ore-tabs\n * @element ore-tab-item - Child element for tab buttons (auto-discovered)\n * @element ore-tab-panel - Child element for tab content (auto-discovered)\n *\n * @attr {string} value - The value of the currently selected tab\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} density - Spatial density: 'default' | 'compact'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @fires change - Emitted when the active tab changes with detail: { value: string }\n *\n * @slot tabs - Place `ore-tab-item` elements here\n * @slot - Place `ore-tab-panel` elements here\n *\n * @cssprop --tabs-radius - Border radius of the tablist container and panels\n * @cssprop --tabs-transition - Transition duration/easing for the active indicator\n * @cssprop --tabs-indicator-color - Color of the sliding active indicator line\n * @cssprop --tabs-bg - Background of the host element (flat variant)\n * @cssprop --tabs-tablist-bg - Tablist container background (solid/frost variants)\n * @cssprop --tabs-tablist-border-color - Tablist container border color\n * @part tablist - Container that holds the slotted tab items\n * @part indicator - Active tab indicator element\n * @part panels - Container that holds tab panel content\n * @example\n * ```html\n * <ore-tabs value=\"tab1\" variant=\"bordered\">\n * <ore-tab-item slot=\"tabs\" value=\"tab1\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"tab2\">Settings</ore-tab-item>\n * <ore-tab-panel value=\"tab1\"><p>Overview content</p></ore-tab-panel>\n * <ore-tab-panel value=\"tab2\"><p>Settings content</p></ore-tab-panel>\n * </ore-tabs>\n * ```\n */\nexport const TABS_TAG = 'ore-tabs' as const;\ndefine<OreTabsProps>(TABS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n activation: prop.oneOf(['auto', 'manual'] as const, 'auto'),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n value: prop.string(),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreTabsEvents>();\n\n const shadowRoot = el.shadowRoot;\n const tablistRef = ref<HTMLElement>();\n const indicatorRef = ref<HTMLElement>();\n const selectedValue = signal<string | undefined>(props.value.value);\n const isManualActivation = () => props.activation.value === 'manual';\n const isVertical = () => props.orientation.value === 'vertical';\n\n bind({\n attr: {\n value: () => selectedValue.value ?? null,\n },\n });\n\n const getTabs = () => [...el.querySelectorAll<HTMLElement>(':scope > ore-tab-item[slot=\"tabs\"]')];\n const getEnabledTabs = () => getTabs().filter((t) => !t.hasAttribute('disabled'));\n const focusTab = (tab: HTMLElement | undefined) => {\n if (!tab) return;\n\n const focusable = tab.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? tab;\n\n focusable.focus();\n };\n\n // ────────────────────────────────────────────────────────────────\n // Selection State Management\n // ────────────────────────────────────────────────────────────────\n\n const setSelection = (value: string | undefined, shouldEmit = false) => {\n selectedValue.value = value;\n\n if (shouldEmit && value) emit('change', { value });\n };\n\n const ensureSelection = () => {\n const tabs = getTabs();\n\n if (tabs.length === 0) return; // No tabs yet, keep current selection\n\n const current = selectedValue.value;\n const hasCurrent = current\n ? tabs.some((tab) => tab.getAttribute('value') === current && !tab.hasAttribute('disabled'))\n : false;\n\n if (hasCurrent) return;\n\n const firstEnabled = tabs.find((tab) => !tab.hasAttribute('disabled'))?.getAttribute('value') ?? undefined;\n\n setSelection(firstEnabled, false);\n };\n\n watch(props.value, (value) => {\n selectedValue.value = value;\n ensureSelection();\n });\n\n // ────────────────────────────────────────────────────────────────\n // List Control for Keyboard Navigation\n // ────────────────────────────────────────────────────────────────\n\n const listControl = createListControl({\n direction: () => elementDirection(el),\n getItems: () => getEnabledTabs(),\n loop: true,\n onNavigate: ({ item }) => {\n focusTab(item);\n\n if (!isManualActivation()) {\n const value = item.getAttribute('value');\n\n if (value) setSelection(value, true);\n }\n },\n orientation: () => (isVertical() ? 'vertical' : 'both'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ────────────────────────────────────────────────────────────────\n // Context & Indicator Management\n // ────────────────────────────────────────────────────────────────\n\n provide(TABS_CTX, {\n color: props.color,\n density: computed(() => props.density.value ?? 'default'),\n orientation: computed(() => props.orientation.value ?? 'horizontal'),\n size: props.size,\n value: selectedValue,\n variant: props.variant,\n });\n\n const moveIndicator = (activeTab: HTMLElement | undefined) => {\n const indicator = indicatorRef.value;\n const tablist = tablistRef.value;\n\n if (!indicator || !tablist || !activeTab) return;\n\n const tabRect = activeTab.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (isVertical()) {\n const y = tabRect.top - listRect.top + tablist.scrollTop;\n\n indicator.style.transition = 'none';\n indicator.style.height = `${tabRect.height}px`;\n indicator.style.width = '';\n indicator.style.left = '0';\n indicator.style.top = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateY(${y}px)`;\n } else {\n const x = tabRect.left - listRect.left + tablist.scrollLeft;\n\n indicator.style.transition = 'none';\n indicator.style.width = `${tabRect.width}px`;\n indicator.style.height = '';\n indicator.style.top = '';\n indicator.style.left = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateX(${x}px)`;\n }\n };\n\n const updateIndicator = () => {\n const value = selectedValue.value;\n\n if (!value) return;\n\n const activeTab = getTabs().find((t) => t.getAttribute('value') === value);\n\n moveIndicator(activeTab);\n };\n\n watch(selectedValue, () => {\n requestAnimationFrame(updateIndicator);\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const handleTabClick = (e: Event) => {\n const tab = e\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item');\n\n if (!tab || tab.hasAttribute('disabled')) return;\n\n // Guard: only respond to tab-items that belong to THIS tabs instance\n if (tab.closest('ore-tabs') !== el) return;\n\n const value = tab.getAttribute('value');\n\n if (!value || value === selectedValue.value) return;\n\n setSelection(value, true);\n };\n\n const activateFocusedTab = (): void => {\n const tabs = getEnabledTabs();\n const focusedTab = tabs.find(\n (tab) => tab === document.activeElement || tab.shadowRoot?.activeElement === document.activeElement,\n );\n const focusedValue = focusedTab?.getAttribute('value');\n\n if (focusedValue && focusedValue !== selectedValue.value) setSelection(focusedValue, true);\n };\n\n const manualActivationPress = createInteraction({\n disabled: computed(() => !isManualActivation()),\n onPress: activateFocusedTab,\n });\n\n const handleKeydown = (e: KeyboardEvent) => {\n const tabs = getEnabledTabs();\n\n if (tabs.length === 0) return;\n\n const path = e.composedPath();\n const activeTabFromEvent = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item',\n );\n\n const tabFromEvent = activeTabFromEvent ?? tabs.find((t) => t.getAttribute('value') === selectedValue.value);\n const focused = tabFromEvent ? tabs.indexOf(tabFromEvent) : -1;\n\n if (focused >= 0) listControl.set(focused);\n\n if (listControl.handleKeydown(e)) return;\n\n manualActivationPress.handleKeydown(e);\n };\n\n bind({\n on: {\n click: handleTabClick,\n keydown: handleKeydown,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const syncSelection = () => {\n ensureSelection();\n updateIndicator();\n };\n\n const tabsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tabs\"]');\n\n if (tabsSlot) {\n tabsSlot.addEventListener('slotchange', syncSelection);\n }\n\n syncSelection();\n requestAnimationFrame(syncSelection);\n\n return () => {\n if (tabsSlot) {\n tabsSlot.removeEventListener('slotchange', syncSelection);\n }\n };\n });\n\n return html`\n <div class=\"tablist-wrapper\">\n <div\n role=\"tablist\"\n ref=\"${tablistRef}\"\n part=\"tablist\"\n aria-orientation=\"${props.orientation}\"\n aria-label=\"${props.label}\">\n <slot name=\"tabs\"></slot>\n </div>\n <div class=\"indicator\" ref=\"${indicatorRef}\" part=\"indicator\"></div>\n </div>\n <div class=\"panels\" part=\"panels\">\n <slot></slot>\n </div>\n `;\n },\n styles: [colorThemeMixin, styles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"tabs.js","names":[],"sources":["../src/disclosure/tabs/tabs.ts"],"sourcesContent":["import {\n bind,\n createContext,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n provide,\n ref,\n useEmit,\n} from '@vielzeug/ore';\nimport { computed, type Readable, signal, watch } from '@vielzeug/ripple';\nimport { createInteraction, createListControl, elementDirection, lifecycleSignal } from '../../core';\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport styles from './tabs.css?inline';\n\n/** Context provided by ore-tabs to its ore-tab-item and ore-tab-panel children. */\nexport type TabsContext = {\n color: Readable<ThemeColor | undefined>;\n density: Readable<'compact' | 'default'>;\n orientation: Readable<'horizontal' | 'vertical'>;\n size: Readable<ComponentSize | undefined>;\n value: Readable<string | undefined>;\n variant: Readable<VisualVariant | undefined>;\n};\n/** Injection key for the tabs context. */\nexport const TABS_CTX = createContext<TabsContext>('TabsContext');\n\nexport type OreTabsEvents = {\n change: { value: string };\n};\n\nexport type OreTabsProps = {\n /**\n * Keyboard activation mode.\n * - `'auto'` (default): Selecting a tab on arrow-key focus immediately activates it (ARIA recommendation for most cases).\n * - `'manual'`: Arrow keys only move focus; the user must press Enter or Space to activate the focused tab.\n */\n activation?: 'auto' | 'manual';\n /** Theme color */\n color?: ThemeColor;\n /** Spatial density; compact renders a 24px tab control for dense interfaces. */\n density?: 'compact' | 'default';\n /** Accessible label for the tablist (passed as aria-label). Use when there is no visible heading labelling the tabs. */\n label?: string;\n /** Tab list orientation */\n orientation?: 'horizontal' | 'vertical';\n /** Component size */\n size?: ComponentSize;\n /** Currently selected tab value */\n value?: string;\n /** Visual style variant */\n variant?: VisualVariant;\n};\n\n/**\n * Tabs container. Manages tab selection and syncs state to child tab items and panels.\n *\n * @element ore-tabs\n * @element ore-tab-item - Child element for tab buttons (auto-discovered)\n * @element ore-tab-panel - Child element for tab content (auto-discovered)\n *\n * @attr {string} value - The value of the currently selected tab\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n * @attr {string} density - Spatial density: 'default' | 'compact'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @fires change - Emitted when the active tab changes with detail: { value: string }\n *\n * @slot tabs - Place `ore-tab-item` elements here\n * @slot - Place `ore-tab-panel` elements here\n *\n * @cssprop --tabs-radius - Border radius of the tablist container and panels\n * @cssprop --tabs-transition - Transition duration/easing for the active indicator\n * @cssprop --tabs-indicator-color - Color of the sliding active indicator line\n * @cssprop --tabs-bg - Background of the host element (flat variant)\n * @cssprop --tabs-tablist-bg - Tablist container background (solid/frost variants)\n * @cssprop --tabs-tablist-border-color - Tablist container border color\n * @part tablist - Container that holds the slotted tab items\n * @part indicator - Active tab indicator element\n * @part panels - Container that holds tab panel content\n * @example\n * ```html\n * <ore-tabs value=\"tab1\" variant=\"bordered\">\n * <ore-tab-item slot=\"tabs\" value=\"tab1\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"tab2\">Settings</ore-tab-item>\n * <ore-tab-panel value=\"tab1\"><p>Overview content</p></ore-tab-panel>\n * <ore-tab-panel value=\"tab2\"><p>Settings content</p></ore-tab-panel>\n * </ore-tabs>\n * ```\n */\nexport const TABS_TAG = 'ore-tabs' as const;\ndefine<OreTabsProps>(TABS_TAG, {\n props: {\n ...themableBundle,\n ...sizableBundle,\n activation: prop.oneOf(['auto', 'manual'] as const, 'auto'),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n label: prop.string(),\n orientation: prop.oneOf(['horizontal', 'vertical'] as const, 'horizontal'),\n value: prop.string(),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreTabsEvents>();\n\n const shadowRoot = el.shadowRoot;\n const tablistRef = ref<HTMLElement>();\n const indicatorRef = ref<HTMLElement>();\n const selectedValue = signal<string | undefined>(props.value.value);\n const hasPanels = signal(false);\n const isManualActivation = () => props.activation.value === 'manual';\n const isVertical = () => props.orientation.value === 'vertical';\n\n bind({\n attr: {\n 'data-has-panels': () => (hasPanels.value ? '' : null),\n value: () => selectedValue.value ?? null,\n },\n });\n\n const getTabs = () => [...el.querySelectorAll<HTMLElement>(':scope > ore-tab-item[slot=\"tabs\"]')];\n const getEnabledTabs = () => getTabs().filter((t) => !t.hasAttribute('disabled'));\n const focusTab = (tab: HTMLElement | undefined) => {\n if (!tab) return;\n\n const focusable = tab.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? tab;\n\n focusable.focus();\n };\n\n // ────────────────────────────────────────────────────────────────\n // Selection State Management\n // ────────────────────────────────────────────────────────────────\n\n const setSelection = (value: string | undefined, shouldEmit = false) => {\n selectedValue.value = value;\n\n if (shouldEmit && value) emit('change', { value });\n };\n\n const ensureSelection = () => {\n const tabs = getTabs();\n\n if (tabs.length === 0) return; // No tabs yet, keep current selection\n\n const current = selectedValue.value;\n const hasCurrent = current\n ? tabs.some((tab) => tab.getAttribute('value') === current && !tab.hasAttribute('disabled'))\n : false;\n\n if (hasCurrent) return;\n\n const firstEnabled = tabs.find((tab) => !tab.hasAttribute('disabled'))?.getAttribute('value') ?? undefined;\n\n setSelection(firstEnabled, false);\n };\n\n watch(props.value, (value) => {\n selectedValue.value = value;\n ensureSelection();\n });\n\n // ────────────────────────────────────────────────────────────────\n // List Control for Keyboard Navigation\n // ────────────────────────────────────────────────────────────────\n\n const listControl = createListControl({\n direction: () => elementDirection(el),\n getItems: () => getEnabledTabs(),\n loop: true,\n onNavigate: ({ item }) => {\n focusTab(item);\n\n if (!isManualActivation()) {\n const value = item.getAttribute('value');\n\n if (value) setSelection(value, true);\n }\n },\n orientation: () => (isVertical() ? 'vertical' : 'both'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ────────────────────────────────────────────────────────────────\n // Context & Indicator Management\n // ────────────────────────────────────────────────────────────────\n\n provide(TABS_CTX, {\n color: props.color,\n density: computed(() => props.density.value ?? 'default'),\n orientation: computed(() => props.orientation.value ?? 'horizontal'),\n size: props.size,\n value: selectedValue,\n variant: props.variant,\n });\n\n const moveIndicator = (activeTab: HTMLElement | undefined) => {\n const indicator = indicatorRef.value;\n const tablist = tablistRef.value;\n\n if (!indicator || !tablist || !activeTab) return;\n\n const tabRect = activeTab.getBoundingClientRect();\n const listRect = tablist.getBoundingClientRect();\n\n if (isVertical()) {\n const y = tabRect.top - listRect.top + tablist.scrollTop;\n\n indicator.style.transition = 'none';\n indicator.style.height = `${tabRect.height}px`;\n indicator.style.width = '';\n indicator.style.left = '0';\n indicator.style.top = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateY(${y}px)`;\n } else {\n const x = tabRect.left - listRect.left + tablist.scrollLeft;\n\n indicator.style.transition = 'none';\n indicator.style.width = `${tabRect.width}px`;\n indicator.style.height = '';\n indicator.style.top = '';\n indicator.style.left = '0';\n void indicator.offsetWidth;\n indicator.style.transition = '';\n indicator.style.transform = `translateX(${x}px)`;\n }\n };\n\n const updateIndicator = () => {\n const value = selectedValue.value;\n\n if (!value) return;\n\n const activeTab = getTabs().find((t) => t.getAttribute('value') === value);\n\n moveIndicator(activeTab);\n };\n\n watch(selectedValue, () => {\n requestAnimationFrame(updateIndicator);\n });\n\n // ────────────────────────────────────────────────────────────────\n // Event Handlers\n // ────────────────────────────────────────────────────────────────\n\n const handleTabClick = (e: Event) => {\n const tab = e\n .composedPath()\n .find((node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item');\n\n if (!tab || tab.hasAttribute('disabled')) return;\n\n // Guard: only respond to tab-items that belong to THIS tabs instance\n if (tab.closest('ore-tabs') !== el) return;\n\n const value = tab.getAttribute('value');\n\n if (!value || value === selectedValue.value) return;\n\n setSelection(value, true);\n };\n\n const activateFocusedTab = (): void => {\n const tabs = getEnabledTabs();\n const focusedTab = tabs.find(\n (tab) => tab === document.activeElement || tab.shadowRoot?.activeElement === document.activeElement,\n );\n const focusedValue = focusedTab?.getAttribute('value');\n\n if (focusedValue && focusedValue !== selectedValue.value) setSelection(focusedValue, true);\n };\n\n const manualActivationPress = createInteraction({\n disabled: computed(() => !isManualActivation()),\n onPress: activateFocusedTab,\n });\n\n const handleKeydown = (e: KeyboardEvent) => {\n const tabs = getEnabledTabs();\n\n if (tabs.length === 0) return;\n\n const path = e.composedPath();\n const activeTabFromEvent = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.localName === 'ore-tab-item',\n );\n\n const tabFromEvent = activeTabFromEvent ?? tabs.find((t) => t.getAttribute('value') === selectedValue.value);\n const focused = tabFromEvent ? tabs.indexOf(tabFromEvent) : -1;\n\n if (focused >= 0) listControl.set(focused);\n\n if (listControl.handleKeydown(e)) return;\n\n manualActivationPress.handleKeydown(e);\n };\n\n bind({\n on: {\n click: handleTabClick,\n keydown: handleKeydown,\n },\n });\n\n // ────────────────────────────────────────────────────────────────\n // Lifecycle\n // ────────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const tabsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"tabs\"]');\n const panelsSlot = shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n const sync = () => {\n ensureSelection();\n hasPanels.value = panelsSlot?.assignedElements().some((child) => child.localName === 'ore-tab-panel') ?? false;\n updateIndicator();\n };\n\n tabsSlot?.addEventListener('slotchange', sync);\n panelsSlot?.addEventListener('slotchange', sync);\n\n sync();\n requestAnimationFrame(sync);\n\n return () => {\n tabsSlot?.removeEventListener('slotchange', sync);\n panelsSlot?.removeEventListener('slotchange', sync);\n };\n });\n\n return html`\n <div class=\"tablist-wrapper\">\n <div\n role=\"tablist\"\n ref=\"${tablistRef}\"\n part=\"tablist\"\n aria-orientation=\"${props.orientation}\"\n aria-label=\"${props.label}\">\n <slot name=\"tabs\"></slot>\n </div>\n <div class=\"indicator\" ref=\"${indicatorRef}\" part=\"indicator\"></div>\n </div>\n <div class=\"panels\" part=\"panels\" ?hidden=\"${() => !hasPanels.value}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [colorThemeMixin, styles],\n});\n"],"mappings":"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"}
package/dist/toast.cjs CHANGED
@@ -1,45 +1,50 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs");require("./_dev.cjs");const t=require("./feedback/toast/toast.css.cjs");let n=require("@vielzeug/ore"),r=require("@vielzeug/ripple"),i=require("@vielzeug/gesture");var a=300,o=class{#e=(0,r.signal)([]);#t=new Set;#n=new Set;#r=!1;#i=5;add(e){if(this.#r)return e.id??crypto.randomUUID();let t=e.id??crypto.randomUUID(),n=this.#e.value.filter(e=>e.phase!==`exiting`),r=n.length-(this.#i-1);if(r>0)for(let e of n.slice(0,r))this.dismiss(e.id);let i={dismissible:!0,duration:5e3,...e,exitTimeoutId:null,id:t,phase:`entering`,timer:null};return this.#l([...this.#e.value,i]),this.#o({id:t,type:`add`}),requestAnimationFrame(()=>{this.#s(t)?.phase===`entering`&&this.#u(t,{phase:`active`})}),i.duration>0&&this.#c(t,i.duration),t}clear(){for(let e of this.#e.value)e.phase!==`exiting`&&this.dismiss(e.id)}dispose(){if(!this.#r){this.#r=!0;for(let e of this.#e.value)e.timer&&clearTimeout(e.timer.timeoutId),e.exitTimeoutId&&clearTimeout(e.exitTimeoutId);this.#l([]),this.#t.clear(),this.#n.clear()}}dismiss(e){let t=this.#s(e);!t||t.phase===`exiting`||this.#r||(this.#u(e,{...this.#a(t),phase:`exiting`}),this.scheduleFinalization(e,350))}finalize(e){let t=this.#s(e);!t||this.#r||(t.timer&&clearTimeout(t.timer.timeoutId),t.exitTimeoutId&&clearTimeout(t.exitTimeoutId),this.#l(this.#e.value.filter(t=>t.id!==e)),t.onDismiss?.(),this.#o({id:e,type:`dismiss`}))}pauseTimers(){this.#r||this.#l(this.#e.value.map(e=>e.timer?(clearTimeout(e.timer.timeoutId),{...e,timer:{...e.timer,remaining:Math.max(0,e.timer.remaining-(Date.now()-e.timer.startedAt))}}):e))}resumeTimers(){if(!this.#r)for(let e of this.#e.value)e.phase===`active`&&e.timer&&e.timer.remaining>0&&this.#c(e.id,e.timer.remaining)}scheduleFinalization(e,t){let n=this.#s(e);if(n?.phase!==`exiting`||this.#r)return;n.exitTimeoutId&&clearTimeout(n.exitTimeoutId);let r=setTimeout(()=>this.finalize(e),t);this.#u(e,{exitTimeoutId:r})}setMax(e){e!=null&&(this.#i=Math.max(1,e))}subscribe(e){return e(this.#e.value),this.#t.add(e),()=>this.#t.delete(e)}subscribeEvents(e){return this.#n.add(e),()=>this.#n.delete(e)}update(e,t){let n=this.#s(e);if(!n||this.#r)return;let r=t.duration===void 0?n:this.#a(n);this.#u(e,{...r,...t,id:e}),t.duration!==void 0&&t.duration>0&&this.#c(e,t.duration)}#a(e){return e.timer&&clearTimeout(e.timer.timeoutId),{...e,timer:null}}#o(e){for(let t of this.#n)t(e)}#s(e){return this.#e.value.find(t=>t.id===e)}#c(e,t){if(t<=0||this.#r)return;let n=setTimeout(()=>this.dismiss(e),t);this.#u(e,{timer:{remaining:t,startedAt:Date.now(),timeoutId:n}})}#l(e){this.#e.value=e;for(let t of this.#t)t(e)}#u(e,t){this.#l(this.#e.value.map(n=>n.id===e?{...n,...t}:n))}},s=new WeakMap,c=new WeakMap,l=(e,t)=>{c.set(e,t),s.get(e)?.bind(t)};function u(e,t){return e.actions?.length?n.html`
2
- <div slot="actions" class="toast-actions">
3
- ${e.actions.map(r=>n.html`
4
- <ore-button
5
- size="sm"
6
- color=${r.color||e.color||`primary`}
7
- variant=${r.variant||`solid`}
8
- @click=${()=>{r.onClick?.(),t()}}>
9
- ${r.label}
10
- </ore-button>
11
- `)}
12
- </div>
13
- `:``}var d=`ore-toast`;(0,n.define)(d,{props:{max:n.prop.number(5),position:n.prop.oneOf([`top-left`,`top-center`,`top-right`,`bottom-left`,`bottom-center`,`bottom-right`],`bottom-right`)},setup(){let e=(0,n.getHost)(),t=(0,n.useEmit)(),o=(0,n.ref)(),l=(0,r.signal)([]),d=(0,r.signal)(!1),f=(0,r.signal)(!1),p=(0,r.computed)(()=>d.value||f.value),m=new Map,h=new Map,g=new Set,_,v=null,y=()=>{},b=()=>{},x=e=>e.querySelector(`.toast-inner`),S=e=>{h.get(e)?.(),h.delete(e)},C=e=>{g.delete(e),v?.finalize(e)},w=(e,t)=>{let n=()=>l.value.find(t=>t.id===e)?.dismissible??!0,r=()=>{let e=x(t);e&&(e.style.transition=``,e.style.transform=``,e.style.opacity=``)};return(0,i.createPanGesture)(t,{axis:`x`,disabled:()=>!n(),onEnd:({distance:n,reason:i})=>{if(i!==`release`||Math.abs(n)<48){r();return}let a=x(t);if(!a||!v)return;g.add(e),v.dismiss(e);let o=()=>C(e);if(window.matchMedia(`(prefers-reduced-motion: reduce)`).matches){a.style.opacity=`0`,o();return}let s=n>=0?1:-1;a.style.transition=`transform 0.22s ease-out, opacity 0.22s ease-out`,a.offsetWidth,a.style.transform=`translateX(${s*120}%)`,a.style.opacity=`0`;let c=e=>{e.target===a&&e.propertyName===`transform`&&(a.removeEventListener(`transitionend`,c),o())};a.addEventListener(`transitionend`,c),v.scheduleFinalization(e,300)},onMove:({distance:e})=>{let n=x(t);n&&(n.style.transition=`none`,n.style.transform=`translateX(${e}px)`,n.style.opacity=String(Math.max(0,1-Math.abs(e)/200)))},pointerCapture:!1,shouldStart:e=>!e.composedPath().some(e=>e instanceof Element&&e.matches(`button, a, input, select, textarea, ore-button`))})},T=e=>{!v||h.has(e)||g.has(e)||requestAnimationFrame(()=>{if(!v||h.has(e)||g.has(e))return;let t=o.value?.querySelector(`[data-toast-id="${e}"] .toast-inner`);if(!t){v.scheduleFinalization(e,a);return}t.offsetHeight;let n=parseFloat(getComputedStyle(t).transitionDuration)*1e3,r=Number.isFinite(n)&&n>0?n:a,i=t=>{t.target?.closest?.(`[data-toast-id="${e}"]`)&&(S(e),v?.finalize(e))};h.set(e,()=>o.value?.removeEventListener(`transitionend`,i)),o.value?.addEventListener(`transitionend`,i),v.scheduleFinalization(e,r+50)})},E=()=>{let e=new Set(l.value.map(e=>e.id));for(let[t,n]of m)e.has(t)||(n.gesture.dispose(),m.delete(t),S(t),g.delete(t));for(let e of l.value){let t=o.value?.querySelector(`[data-toast-id="${e.id}"]`),n=m.get(e.id);t&&n?.element!==t&&(n?.gesture.dispose(),m.set(e.id,{element:t,gesture:w(e.id,t)})),e.phase===`exiting`&&T(e.id)}};(0,r.watch)(l,()=>{E(),_!==void 0&&cancelAnimationFrame(_),_=requestAnimationFrame(()=>{_=void 0,E()})}),(0,r.watch)(p,e=>{e?v?.pauseTimers():v?.resumeTimers()});let D=e=>{v!==e&&(y(),b(),v=e,y=v.subscribe(e=>{l.value=e}),b=v.subscribeEvents(e=>t(e.type,{id:e.id})),p.value&&v.pauseTimers())},O=e=>{let t=()=>v?.dismiss(e.id);return n.html`
14
- <div
15
- class="toast-wrapper"
16
- data-toast-id=${e.id}
17
- part="toast-wrapper">
18
- <div class="${()=>`toast-inner${e.phase===`active`?``:` ${e.phase}`}`}" part="toast-inner">
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs");require("./_dev.cjs");const t=require("./feedback/toast/toast.css.cjs");let n=require("@vielzeug/ore"),r=require("@vielzeug/ripple"),i=require("@vielzeug/gesture");var a=200,o=class{#e=(0,r.signal)([]);#t=new Set;#n=new Set;#r=!1;#i=5;add(e){if(this.#r)return e.id??crypto.randomUUID();let t=e.id??crypto.randomUUID(),n=this.#e.value.filter(e=>e.phase!==`exiting`),r=n.length-(this.#i-1);if(r>0)for(let e of n.slice(0,r))this.dismiss(e.id);let i={dismissible:!0,duration:5e3,...e,exitTimeoutId:null,id:t,phase:`entering`,timer:null};return this.#l([...this.#e.value,i]),this.#o({id:t,type:`add`}),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.#s(t)?.phase===`entering`&&this.#u(t,{phase:`active`})})}),i.duration>0&&this.#c(t,i.duration),t}clear(){for(let e of this.#e.value)e.phase!==`exiting`&&this.dismiss(e.id)}dispose(){if(!this.#r){this.#r=!0;for(let e of this.#e.value)e.timer&&clearTimeout(e.timer.timeoutId),e.exitTimeoutId&&clearTimeout(e.exitTimeoutId);this.#l([]),this.#t.clear(),this.#n.clear()}}dismiss(e){let t=this.#s(e);!t||t.phase===`exiting`||this.#r||(this.#u(e,{...this.#a(t),phase:`exiting`}),this.scheduleFinalization(e,250))}finalize(e){let t=this.#s(e);!t||this.#r||(t.timer&&clearTimeout(t.timer.timeoutId),t.exitTimeoutId&&clearTimeout(t.exitTimeoutId),this.#l(this.#e.value.filter(t=>t.id!==e)),t.onDismiss?.(),this.#o({id:e,type:`dismiss`}))}pauseTimers(){this.#r||this.#l(this.#e.value.map(e=>e.timer?(clearTimeout(e.timer.timeoutId),{...e,timer:{...e.timer,remaining:Math.max(0,e.timer.remaining-(Date.now()-e.timer.startedAt))}}):e))}resumeTimers(){if(!this.#r)for(let e of this.#e.value)e.phase===`active`&&e.timer&&e.timer.remaining>0&&this.#c(e.id,e.timer.remaining)}scheduleFinalization(e,t){let n=this.#s(e);if(n?.phase!==`exiting`||this.#r)return;n.exitTimeoutId&&clearTimeout(n.exitTimeoutId);let r=setTimeout(()=>this.finalize(e),t);this.#u(e,{exitTimeoutId:r})}setMax(e){e!=null&&(this.#i=Math.max(1,e))}subscribe(e){return e(this.#e.value),this.#t.add(e),()=>this.#t.delete(e)}subscribeEvents(e){return this.#n.add(e),()=>this.#n.delete(e)}update(e,t){let n=this.#s(e);if(!n||this.#r)return;let r=t.duration===void 0?n:this.#a(n);this.#u(e,{...r,...t,id:e}),t.duration!==void 0&&t.duration>0&&this.#c(e,t.duration)}#a(e){return e.timer&&clearTimeout(e.timer.timeoutId),{...e,timer:null}}#o(e){for(let t of this.#n)t(e)}#s(e){return this.#e.value.find(t=>t.id===e)}#c(e,t){if(t<=0||this.#r)return;let n=setTimeout(()=>this.dismiss(e),t);this.#u(e,{timer:{remaining:t,startedAt:Date.now(),timeoutId:n}})}#l(e){this.#e.value=e;for(let t of this.#t)t(e)}#u(e,t){this.#l(this.#e.value.map(n=>n.id===e?{...n,...t}:n))}},s=new WeakMap,c=new WeakMap,l=(e,t)=>{c.set(e,t),s.get(e)?.bind(t)},u=[],d=e=>e.urgency??(e.color===`error`?`assertive`:`polite`);function f(e,t){let i=(0,r.computed)(()=>e.value.actions??u);return n.html`
2
+ ${()=>i.value.length?n.html`
3
+ <div slot="actions" class="toast-actions">
4
+ ${(0,n.each)(()=>i.value,(e,t)=>`${t}:${e.label}`,r=>n.html`
5
+ <ore-button
6
+ size="sm"
7
+ color=${()=>r.value.color||e.value.color||`primary`}
8
+ variant=${()=>r.value.variant||`flat`}
9
+ @click=${()=>{r.value.onClick?.(),t()}}>
10
+ ${()=>r.value.label}
11
+ </ore-button>
12
+ `)}
13
+ </div>
14
+ `:``}
15
+ `}var p=`ore-toast`;(0,n.define)(p,{props:{max:n.prop.number(5),position:n.prop.oneOf([`top-left`,`top-center`,`top-right`,`bottom-left`,`bottom-center`,`bottom-right`],`bottom-right`)},setup(){let e=(0,n.getHost)(),t=(0,n.useEmit)(),o=(0,n.ref)(),l=(0,r.signal)([]),u=(0,r.signal)(!1),p=(0,r.signal)(!1),m=(0,r.computed)(()=>u.value||p.value),h=new Map,g=new Map,_=new Set,v,y=null,b=()=>{},x=()=>{},S=e=>e.querySelector(`.toast-inner`),C=e=>{g.get(e)?.(),g.delete(e)},w=e=>{_.delete(e),y?.finalize(e)},T=(e,t)=>{let n=()=>l.value.find(t=>t.id===e)?.dismissible??!0,r=()=>{let e=S(t);e&&(e.style.transition=``,e.style.transform=``,e.style.opacity=``)};return(0,i.createPanGesture)(t,{axis:`x`,disabled:()=>!n(),onEnd:({distance:n,reason:i})=>{if(i!==`release`||Math.abs(n)<48){r();return}let a=S(t);if(!a||!y)return;_.add(e),y.dismiss(e);let o=()=>w(e);if(window.matchMedia(`(prefers-reduced-motion: reduce)`).matches){a.style.opacity=`0`,o();return}let s=n>=0?1:-1;a.style.transition=`transform 0.22s ease-out, opacity 0.22s ease-out`,a.offsetWidth,a.style.transform=`translateX(${s*120}%)`,a.style.opacity=`0`;let c=e=>{e.target===a&&e.propertyName===`transform`&&(a.removeEventListener(`transitionend`,c),o())};a.addEventListener(`transitionend`,c),y.scheduleFinalization(e,300)},onMove:({distance:e})=>{let n=S(t);n&&(n.style.transition=`none`,n.style.transform=`translateX(${e}px)`,n.style.opacity=String(Math.max(0,1-Math.abs(e)/200)))},pointerCapture:!1,shouldStart:e=>!e.composedPath().some(e=>e instanceof Element&&e.matches(`button, a, input, select, textarea, ore-button`))})},E=e=>{!y||g.has(e)||_.has(e)||requestAnimationFrame(()=>{if(!y||g.has(e)||_.has(e))return;let t=o.value?.querySelector(`[data-toast-id="${e}"] .toast-inner`);if(!t){y.scheduleFinalization(e,a);return}t.offsetHeight;let n=parseFloat(getComputedStyle(t).transitionDuration)*1e3,r=Number.isFinite(n)&&n>0?n:a,i=t=>{t.target?.closest?.(`[data-toast-id="${e}"]`)&&(C(e),y?.finalize(e))};g.set(e,()=>o.value?.removeEventListener(`transitionend`,i)),o.value?.addEventListener(`transitionend`,i),y.scheduleFinalization(e,r+50)})},D=()=>{let e=new Set(l.value.map(e=>e.id));for(let[t,n]of h)e.has(t)||(n.gesture.dispose(),h.delete(t),C(t),_.delete(t));for(let e of l.value){let t=o.value?.querySelector(`[data-toast-id="${e.id}"]`),n=h.get(e.id);t&&n?.element!==t&&(n?.gesture.dispose(),h.set(e.id,{element:t,gesture:T(e.id,t)})),e.phase===`exiting`&&E(e.id)}};(0,r.watch)(l,()=>{D(),v!==void 0&&cancelAnimationFrame(v),v=requestAnimationFrame(()=>{v=void 0,D()})}),(0,r.watch)(m,e=>{e?y?.pauseTimers():y?.resumeTimers()});let O=e=>{y!==e&&(b(),x(),y=e,b=y.subscribe(e=>{l.value=e}),x=y.subscribeEvents(e=>t(e.type,{id:e.id})),m.value&&y.pauseTimers())},k=e=>{if(e.key!==`Escape`)return;let t=e.composedPath().find(e=>e instanceof HTMLElement&&e.classList.contains(`toast-wrapper`))?.dataset.toastId,n=t?l.value.find(e=>e.id===t):void 0;n?.dismissible&&(e.preventDefault(),e.stopPropagation(),y?.dismiss(n.id))},A=e=>{let t=e.value.id,i=()=>y?.dismiss(t),a=(0,r.computed)(()=>e.value.meta??``),o=(0,r.computed)(()=>`toast-inner${e.value.phase===`active`?``:` ${e.value.phase}`}`),s=(0,r.computed)(()=>`--_toast-accent: var(--color-${e.value.color||`primary`}); --_toast-radius: var(--rounded-${e.value.rounded||`md`})`),c=(0,r.computed)(()=>{let{duration:t,timer:n}=e.value;return!n||t<=0?``:`--_toast-duration: ${t}ms; --_toast-elapsed: -${Math.max(0,t-n.remaining)}ms`});return n.html`
16
+ <div class="toast-wrapper" data-toast-id=${t} part="toast-wrapper">
17
+ <div class=${()=>o.value} style=${()=>s.value} part="toast-inner">
19
18
  <ore-alert
20
- color=${e.color||(e.urgency===`assertive`?`error`:`primary`)}
21
- variant=${e.variant||`solid`}
22
- size=${e.size||`md`}
23
- rounded=${e.rounded||`md`}
24
- ?horizontal=${e.horizontal}
25
- heading=${e.heading||``}
26
- ?dismissible=${e.dismissible}
27
- @dismiss=${t}>
28
- ${e.meta?n.html`
29
- <span slot="meta">${e.meta}</span>
30
- `:``}
31
- ${e.message} ${u(e,t)}
19
+ embedded
20
+ color=${()=>e.value.color||(d(e.value)===`assertive`?`error`:`primary`)}
21
+ variant=${()=>e.value.variant||`solid`}
22
+ size=${()=>e.value.size||`md`}
23
+ rounded=${()=>e.value.rounded||`md`}
24
+ ?horizontal=${()=>!!e.value.horizontal}
25
+ heading=${()=>e.value.heading||null}
26
+ ?dismissible=${()=>e.value.dismissible}
27
+ @dismiss=${i}>
28
+ <span slot="meta" ?hidden=${()=>!a.value}>${()=>a.value}</span>
29
+ ${()=>e.value.message} ${f(e,i)}
32
30
  </ore-alert>
31
+ <div
32
+ class="toast-progress"
33
+ part="progress"
34
+ style=${()=>c.value}
35
+ ?hidden=${()=>!c.value}
36
+ aria-hidden="true"></div>
33
37
  </div>
34
38
  </div>
35
- `};(0,n.onMounted)(()=>{s.set(e,{bind:D,unbind(){y(),b(),v=null,l.value=[]}});let t=c.get(e);t&&D(t)}),(0,n.onCleanup)(()=>{s.get(e)?.unbind(),s.delete(e),_!==void 0&&cancelAnimationFrame(_);for(let e of m.values())e.gesture.dispose();m.clear();for(let e of h.keys())S(e)});let k=e=>e.urgency??(e.color===`error`?`assertive`:`polite`),A=(0,r.computed)(()=>l.value.filter(e=>k(e)===`polite`)),j=(0,r.computed)(()=>l.value.filter(e=>k(e)===`assertive`));return n.html`
39
+ `};(0,n.onMounted)(()=>{s.set(e,{bind:O,unbind(){b(),x(),y=null,l.value=[]}});let t=c.get(e);t&&O(t)}),(0,n.onCleanup)(()=>{s.get(e)?.unbind(),s.delete(e),v!==void 0&&cancelAnimationFrame(v);for(let e of h.values())e.gesture.dispose();h.clear();for(let e of g.keys())C(e)});let j=(0,r.computed)(()=>l.value.filter(e=>d(e)===`polite`)),M=(0,r.computed)(()=>l.value.filter(e=>d(e)===`assertive`)),N=e=>e.id;return n.html`
36
40
  <div
37
- class="toast-container"
41
+ class=${()=>`toast-container${m.value?` paused`:``}`}
38
42
  ref=${o}
39
- @pointerenter=${()=>{d.value=!0,e.classList.add(`hovered`)}}
40
- @pointerleave=${()=>{d.value=!1,e.classList.remove(`hovered`)}}
41
- @focusin=${()=>{f.value=!0}}
42
- @focusout=${()=>{f.value=!1}}
43
+ @pointerenter=${()=>{u.value=!0}}
44
+ @pointerleave=${()=>{u.value=!1}}
45
+ @focusin=${()=>{p.value=!0}}
46
+ @focusout=${()=>{p.value=!1}}
47
+ @keydown=${k}
43
48
  part="container">
44
49
  <div
45
50
  role="region"
@@ -48,7 +53,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
48
53
  aria-atomic="false"
49
54
  aria-label="Notifications"
50
55
  class="toast-live-region">
51
- ${()=>A.value.map(O)}
56
+ ${(0,n.each)(j,N,A)}
52
57
  </div>
53
58
  <div
54
59
  role="region"
@@ -57,9 +62,9 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
57
62
  aria-atomic="false"
58
63
  aria-label="Critical notifications"
59
64
  class="toast-live-region">
60
- ${()=>j.value.map(O)}
65
+ ${(0,n.each)(M,N,A)}
61
66
  </div>
62
67
  <slot></slot>
63
68
  </div>
64
- `},styles:[e.reducedMotionMixin,t.default]});var f=new WeakMap;function p(e=document.body){let t=f.get(e);if(t)return t;let n=new o,r=new AbortController,i=!1,a=!1,s=null,c=null,u=()=>!i,p=e,m=()=>{if(!u())return null;if(c?.isConnected)return c;if(c=p.querySelector(d),c||(c=document.createElement(d),s?.position&&c.setAttribute(`position`,s.position),s?.max!=null&&c.setAttribute(`max`,String(s.max)),p.appendChild(c)),s?.max!=null)n.setMax(s.max);else{let e=Number(c.getAttribute(`max`));Number.isFinite(e)&&e>0&&n.setMax(e)}return s=null,a=!0,l(c,n),c},h=()=>!!m(),g={add(e){return h()?n.add(e):e.id??crypto.randomUUID()},clear(){h()&&n.clear()},configure(e){a||(s={...s,...e})},dismiss(e){h()&&n.dismiss(e)},get disposalSignal(){return r.signal},dispose(){i||(i=!0,r.abort(),n.dispose(),f.get(e)===g&&f.delete(e))},get disposed(){return i},error(e,t){return g.add({color:`error`,...t,message:e})},info(e,t){return g.add({color:`info`,...t,message:e})},async promise(e,t){let n=g.add({color:`primary`,dismissible:!1,duration:0,message:t.loading});try{let r=await e;return g.update(n,{color:`success`,dismissible:!0,duration:5e3,message:typeof t.success==`function`?t.success(r):t.success}),r}catch(e){throw g.update(n,{color:`error`,dismissible:!0,duration:5e3,message:typeof t.error==`function`?t.error(e):t.error}),e}},success(e,t){return g.add({color:`success`,...t,message:e})},[Symbol.dispose](){g.dispose()},update(e,t){h()&&n.update(e,t)},warning(e,t){return g.add({color:`warning`,...t,message:e})}};return f.set(e,g),g}var m=p();exports.TOAST_TAG=d,exports.createToastService=p,exports.toast=m;
69
+ `},styles:[e.reducedMotionMixin,t.default]});var m=new WeakMap;function h(e=document.body){let t=m.get(e);if(t)return t;let n=new o,r=new AbortController,i=!1,a=!1,s=null,c=null,u=()=>!i,d=e,f=()=>{if(!u())return null;if(c?.isConnected)return c;if(c=d.querySelector(p),c||(c=document.createElement(p),s?.position&&c.setAttribute(`position`,s.position),s?.max!=null&&c.setAttribute(`max`,String(s.max)),d.appendChild(c)),s?.max!=null)n.setMax(s.max);else{let e=Number(c.getAttribute(`max`));Number.isFinite(e)&&e>0&&n.setMax(e)}return s=null,a=!0,l(c,n),c},h=()=>!!f(),g={add(e){return h()?n.add(e):e.id??crypto.randomUUID()},clear(){h()&&n.clear()},configure(e){a||(s={...s,...e})},dismiss(e){h()&&n.dismiss(e)},get disposalSignal(){return r.signal},dispose(){i||(i=!0,r.abort(),n.dispose(),m.get(e)===g&&m.delete(e))},get disposed(){return i},error(e,t){return g.add({color:`error`,...t,message:e})},info(e,t){return g.add({color:`info`,...t,message:e})},async promise(e,t){let n=g.add({color:`primary`,dismissible:!1,duration:0,message:t.loading});try{let r=await e;return g.update(n,{color:`success`,dismissible:!0,duration:5e3,message:typeof t.success==`function`?t.success(r):t.success}),r}catch(e){throw g.update(n,{color:`error`,dismissible:!0,duration:5e3,message:typeof t.error==`function`?t.error(e):t.error}),e}},success(e,t){return g.add({color:`success`,...t,message:e})},[Symbol.dispose](){g.dispose()},update(e,t){h()&&n.update(e,t)},warning(e,t){return g.add({color:`warning`,...t,message:e})}};return m.set(e,g),g}var g=h();exports.TOAST_TAG=p,exports.createToastService=h,exports.toast=g;
65
70
  //# sourceMappingURL=toast.cjs.map