import { defineWebComponent } from './define'; import { Coachmark, type CoachmarkController } from '../components/coachmark'; import { wireDisclosure } from './disclosure'; interface Props extends Record { /** Drive/observe open state (Shoelace-style: settable + reflected to the `open` * attribute; the element still self-manages). Set `el.open = true`, or * ``; listen for `kai-open-change`. */ open?: boolean; /** Initial open state on mount (uncontrolled seed). */ defaultOpen?: boolean; /** The bold title. Named `headline` because `title` collides with the global * `HTMLElement.title` attribute (it throws at registration). */ headline?: string; /** A small badge pill beside the headline (e.g. "New"). */ badge?: string; /** Floating placement relative to the anchor (default `bottom`). */ placement?: string; /** Color tone: `primary` (default, theme accent), `info` (blue), `success` * (green), `warning` (amber), or `error` (red) — reusing the kit's tool hues. */ tone?: 'primary' | 'info' | 'success' | 'warning' | 'error'; /** Render the arrow that points at the anchor (default `true`). Set * `arrow="false"` for a plain bubble with no pointer. */ arrow?: boolean; } /** Events fired by ``. */ interface Events { /** The × dismiss button was pressed. The consumer records that this hint was * seen so it won't show again. */ 'kai-dismiss': Record; /** The coachmark opened or closed (a method, the ×, or a driven `open`). */ 'kai-open-change': { open: boolean }; } /** * `` — an anchored onboarding hint bubble with an arrow. It WRAPS * a trigger (the default slot) and points a primary-colored bubble at it: a small * `badge` pill, a bold `headline`, the `content` slot body, and a dismiss ×. * * ```html * * * Chat with Claude or switch to Cowork from here. * * * ``` * * Open state is the standard disclosure surface: settable+reflecting `open`, * `kai-open-change`, and `show()`/`hide()`/`toggle()`; seed with `default-open`. * Parts: `bubble` · `arrow` · `badge` · `title` · `dismiss`. */ defineWebComponent('kai-coachmark', { open: undefined, defaultOpen: undefined, headline: undefined, badge: undefined, placement: undefined, tone: undefined, arrow: true, }, (props, ctx) => { const { flag, dispatch } = ctx; let api: CoachmarkController | undefined; // The standard disclosure surface: settable+reflecting `open`, kai-open-change, // show/hide/toggle. See ./disclosure. This is the SOLE emitter of kai-open-change. wireDisclosure(ctx, () => api, () => props.open); // headline/badge are scalar string props (NOT slots) — pass through directly so // the component's own `Show when={…}` gating drives whether each region renders. // The body is the `content` slot; an empty `` renders nothing. return ( } controllerRef={(a) => (api = a)} onDismiss={() => dispatch('kai-dismiss', {})} > ); });