{"version":3,"file":"BqTooltip-DQEEhhZp.cjs","names":[],"sources":["../src/components/tooltip/BqTooltip.ts"],"sourcesContent":["/**\r\n * Tooltip component - contextual popup on hover/focus.\r\n * @element bq-tooltip\r\n * @prop {string} content   - Tooltip text\r\n * @prop {string} placement - top | bottom | left | right\r\n * @prop {number} delay     - Show delay in ms\r\n * @slot - The trigger element\r\n */\r\nimport type { ComponentDefinition } from '@bquery/bquery/component';\r\nimport { component, html } from '@bquery/bquery/component';\r\nimport { escapeHtml } from '@bquery/bquery/security';\r\nimport { uniqueId } from '../../utils/dom.js';\r\nimport { getBaseStyles } from '../../utils/styles.js';\r\n\r\ntype BqTooltipProps = { content: string; placement: string; delay: number };\r\ntype BqTooltipState = { visible: boolean; uid: string };\r\n\r\nfunction addDescribedBy(element: HTMLElement, tooltipId: string): void {\r\n  const current = element.getAttribute('aria-describedby');\r\n  const tokens = new Set((current ?? '').split(/\\s+/).filter(Boolean));\r\n  tokens.add(tooltipId);\r\n  element.setAttribute('aria-describedby', Array.from(tokens).join(' '));\r\n}\r\n\r\nfunction removeDescribedBy(element: HTMLElement, tooltipId: string): void {\r\n  const current = element.getAttribute('aria-describedby');\r\n  if (!current) return;\r\n  const tokens = current\r\n    .split(/\\s+/)\r\n    .filter((token) => token && token !== tooltipId);\r\n  if (tokens.length > 0) {\r\n    element.setAttribute('aria-describedby', tokens.join(' '));\r\n    return;\r\n  }\r\n  element.removeAttribute('aria-describedby');\r\n}\r\n\r\nconst definition: ComponentDefinition<BqTooltipProps, BqTooltipState> = {\r\n  props: {\r\n    content: { type: String, default: '' },\r\n    placement: { type: String, default: 'top' },\r\n    delay: { type: Number, default: 200 },\r\n  },\r\n  state: { visible: false, uid: '' },\r\n  styles: `\r\n    ${getBaseStyles()}\r\n    :host { display: inline-block; position: relative; }\r\n    .tip {\r\n      position: absolute; z-index: var(--bq-z-tooltip,700);\r\n      background: var(--bq-color-secondary-900,#0f172a); color: #fff;\r\n      font-family: var(--bq-font-family-sans); font-size: var(--bq-font-size-sm,0.875rem);\r\n      padding: 0.375rem 0.625rem; border-radius: var(--bq-radius-md,0.375rem);\r\n      white-space: nowrap; pointer-events: none;\r\n      opacity: 0; transition: opacity var(--bq-duration-fast);\r\n    }\r\n    .tip[data-visible=\"true\"] { opacity: 1; }\r\n    .tip[data-placement=\"top\"]    { bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); }\r\n    .tip[data-placement=\"bottom\"] { top:  calc(100% + 6px); left: 50%; transform: translateX(-50%); }\r\n    .tip[data-placement=\"left\"]   { right: calc(100% + 6px); top: 50%; transform: translateY(-50%); }\r\n    .tip[data-placement=\"right\"]  { left:  calc(100% + 6px); top: 50%; transform: translateY(-50%); }\r\n    @media (prefers-reduced-motion: reduce) {\r\n      .tip { transition: none; }\r\n    }\r\n  `,\r\n  connected() {\r\n    type BQEl = HTMLElement & {\r\n      setState(k: 'visible' | 'uid', v: unknown): void;\r\n      getState<T>(k: string): T;\r\n    };\r\n    const self = this as unknown as BQEl;\r\n    const internalState = self as unknown as Record<string, unknown>;\r\n    if (!self.getState<string>('uid')) {\r\n      self.setState('uid', uniqueId('bq-tooltip'));\r\n    }\r\n    const clearShowTimer = () => {\r\n      const timer = internalState['_showTimer'] as\r\n        | ReturnType<typeof setTimeout>\r\n        | null\r\n        | undefined;\r\n      if (timer) {\r\n        clearTimeout(timer);\r\n      }\r\n      internalState['_showTimer'] = null;\r\n    };\r\n    const show = () => {\r\n      clearShowTimer();\r\n      const d = parseInt(self.getAttribute('delay') ?? '200', 10);\r\n      internalState['_showTimer'] = setTimeout(() => {\r\n        internalState['_showTimer'] = null;\r\n        self.setState('visible', true);\r\n      }, d);\r\n    };\r\n    const hide = () => {\r\n      clearShowTimer();\r\n      self.setState('visible', false);\r\n    };\r\n    const kh = (e: Event) => {\r\n      if ((e as KeyboardEvent).key === 'Escape') hide();\r\n    };\r\n    const syncTrigger = () => {\r\n      const state = self as unknown as Record<string, unknown>;\r\n      const tooltipId = self.getState<string>('uid');\r\n      const previous =\r\n        (state['_triggerElements'] as HTMLElement[] | undefined) ?? [];\r\n      previous.forEach((element) => removeDescribedBy(element, tooltipId));\r\n\r\n      const slot = self.shadowRoot?.querySelector(\r\n        'slot'\r\n      ) as HTMLSlotElement | null;\r\n      if (!slot) {\r\n        state['_triggerElements'] = [];\r\n        return;\r\n      }\r\n\r\n      const content = self.getAttribute('content')?.trim() ?? '';\r\n      const next = slot\r\n        .assignedElements({ flatten: true })\r\n        .filter(\r\n          (element): element is HTMLElement => element instanceof HTMLElement\r\n        );\r\n\r\n      if (content) {\r\n        next.forEach((element) => addDescribedBy(element, tooltipId));\r\n      }\r\n      state['_triggerElements'] = next;\r\n    };\r\n    internalState['_show'] = show;\r\n    internalState['_hide'] = hide;\r\n    internalState['_kh'] = kh;\r\n    internalState['_syncTrigger'] = syncTrigger;\r\n    internalState['_clearShowTimer'] = clearShowTimer;\r\n    self.addEventListener('mouseenter', show);\r\n    self.addEventListener('mouseleave', hide);\r\n    self.addEventListener('focusin', show);\r\n    self.addEventListener('focusout', hide);\r\n    document.addEventListener('keydown', kh);\r\n    queueMicrotask(() => {\r\n      if (!self.isConnected) return;\r\n      const slot = self.shadowRoot?.querySelector(\r\n        'slot'\r\n      ) as HTMLSlotElement | null;\r\n      if (!slot) return;\r\n      slot.addEventListener('slotchange', syncTrigger);\r\n      internalState['_slot'] = slot;\r\n      syncTrigger();\r\n    });\r\n  },\r\n  disconnected() {\r\n    const self = this as unknown as Record<string, unknown>;\r\n    const show = self['_show'] as EventListener;\r\n    const hide = self['_hide'] as EventListener;\r\n    const kh = self['_kh'] as EventListener;\r\n    const slot = self['_slot'] as HTMLSlotElement | undefined;\r\n    const syncTrigger = self['_syncTrigger'] as EventListener | undefined;\r\n    const clearShowTimer = self['_clearShowTimer'] as (() => void) | undefined;\r\n    const triggerElements =\r\n      (self['_triggerElements'] as HTMLElement[] | undefined) ?? [];\r\n    const tooltipId =\r\n      (this as unknown as { getState?<T>(key: string): T }).getState?.<string>(\r\n        'uid'\r\n      ) ?? this.id;\r\n    clearShowTimer?.();\r\n    this.removeEventListener('mouseenter', show);\r\n    this.removeEventListener('mouseleave', hide);\r\n    this.removeEventListener('focusin', show);\r\n    this.removeEventListener('focusout', hide);\r\n    document.removeEventListener('keydown', kh);\r\n    if (slot && syncTrigger)\r\n      slot.removeEventListener('slotchange', syncTrigger);\r\n    triggerElements.forEach((element) => removeDescribedBy(element, tooltipId));\r\n  },\r\n  updated() {\r\n    const syncTrigger = (this as unknown as Record<string, unknown>)[\r\n      '_syncTrigger'\r\n    ] as (() => void) | undefined;\r\n    syncTrigger?.();\r\n  },\r\n  render({ props, state }) {\r\n    const visible = Boolean(state['visible']);\r\n    const uid = state['uid'] || 'bq-tooltip';\r\n    return html`\r\n      <slot></slot>\r\n      <div\r\n        id=\"${escapeHtml(uid)}\"\r\n        part=\"tooltip\"\r\n        class=\"tip\"\r\n        role=\"tooltip\"\r\n        aria-hidden=\"${visible ? 'false' : 'true'}\"\r\n        data-placement=\"${escapeHtml(props.placement)}\"\r\n        data-visible=\"${visible ? 'true' : 'false'}\"\r\n      >\r\n        ${escapeHtml(props.content)}\r\n      </div>\r\n    `;\r\n  },\r\n};\r\n\r\ncomponent<BqTooltipProps, BqTooltipState>('bq-tooltip', definition);\r\n"],"mappings":"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"}