@vielzeug/refine 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/async.cjs +11 -11
  2. package/dist/async.cjs.map +1 -1
  3. package/dist/async.js +1 -2
  4. package/dist/async.js.map +1 -1
  5. package/dist/calendar.cjs +26 -26
  6. package/dist/calendar.cjs.map +1 -1
  7. package/dist/calendar.js +4 -5
  8. package/dist/calendar.js.map +1 -1
  9. package/dist/checkbox-group.cjs +9 -9
  10. package/dist/checkbox-group.cjs.map +1 -1
  11. package/dist/checkbox-group.js +1 -2
  12. package/dist/checkbox-group.js.map +1 -1
  13. package/dist/code-window.cjs +4 -4
  14. package/dist/code-window.cjs.map +1 -1
  15. package/dist/code-window.js +1 -2
  16. package/dist/code-window.js.map +1 -1
  17. package/dist/command-palette.cjs +6 -6
  18. package/dist/command-palette.cjs.map +1 -1
  19. package/dist/command-palette.js +46 -47
  20. package/dist/command-palette.js.map +1 -1
  21. package/dist/content/code-window/code-window.d.ts.map +1 -1
  22. package/dist/content/icon/icon.d.ts.map +1 -1
  23. package/dist/custom-elements.json +3716 -3716
  24. package/dist/datagrid.cjs +2 -2
  25. package/dist/datagrid.js +206 -206
  26. package/dist/datagrid.js.map +1 -1
  27. package/dist/disclosure/tab-panel/tab-panel.d.ts.map +1 -1
  28. package/dist/feedback/async/async.d.ts.map +1 -1
  29. package/dist/feedback/progress/progress.d.ts.map +1 -1
  30. package/dist/file-input.cjs +49 -49
  31. package/dist/file-input.cjs.map +1 -1
  32. package/dist/file-input.js +1 -2
  33. package/dist/file-input.js.map +1 -1
  34. package/dist/icon.cjs +1 -1
  35. package/dist/icon.cjs.map +1 -1
  36. package/dist/icon.js +1 -2
  37. package/dist/icon.js.map +1 -1
  38. package/dist/input.cjs +2 -2
  39. package/dist/input.js +6 -6
  40. package/dist/inputs/calendar/calendar.d.ts.map +1 -1
  41. package/dist/message-composer.cjs +2 -2
  42. package/dist/message-composer.js +6 -6
  43. package/dist/progress.cjs +13 -13
  44. package/dist/progress.cjs.map +1 -1
  45. package/dist/progress.js +3 -4
  46. package/dist/progress.js.map +1 -1
  47. package/dist/radio-group.cjs +11 -11
  48. package/dist/radio-group.cjs.map +1 -1
  49. package/dist/radio-group.js +1 -2
  50. package/dist/radio-group.js.map +1 -1
  51. package/dist/refine.cjs +197 -197
  52. package/dist/refine.cjs.map +1 -1
  53. package/dist/refine.iife.js +258 -258
  54. package/dist/refine.iife.js.map +1 -1
  55. package/dist/refine.js +225 -225
  56. package/dist/refine.js.map +1 -1
  57. package/dist/tab-panel.cjs +7 -7
  58. package/dist/tab-panel.cjs.map +1 -1
  59. package/dist/tab-panel.js +3 -4
  60. package/dist/tab-panel.js.map +1 -1
  61. package/dist/testing/index.d.ts +15 -60
  62. package/dist/testing/index.d.ts.map +1 -1
  63. package/dist/testing.cjs +1 -1
  64. package/dist/testing.cjs.map +1 -1
  65. package/dist/testing.js +7 -24
  66. package/dist/testing.js.map +1 -1
  67. package/dist/textarea.cjs +2 -2
  68. package/dist/textarea.js +6 -6
  69. package/package.json +6 -5
  70. package/dist/keymap/dist/_dev.cjs +0 -2
  71. package/dist/keymap/dist/_dev.cjs.map +0 -1
  72. package/dist/keymap/dist/_dev.js +0 -4
  73. package/dist/keymap/dist/_dev.js.map +0 -1
  74. package/dist/keymap/dist/format.cjs +0 -1
  75. package/dist/keymap/dist/format.js +0 -1
  76. package/dist/keymap/dist/index.cjs +0 -1
  77. package/dist/keymap/dist/index.js +0 -4
  78. package/dist/keymap/dist/keymap.cjs +0 -2
  79. package/dist/keymap/dist/keymap.cjs.map +0 -1
  80. package/dist/keymap/dist/keymap.js +0 -221
  81. package/dist/keymap/dist/keymap.js.map +0 -1
  82. package/dist/keymap/dist/layer.cjs +0 -1
  83. package/dist/keymap/dist/layer.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.js","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { define, html, prop, bind, useEmit } from '@vielzeug/ore';\nimport { styleMap } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { Temporal, format } from '@vielzeug/tempo';\n\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\n\nimport '../../content/icon/icon';\nimport '../../feedback/badge/badge';\nimport { createDatePickerControl, parseIso, toIsoString, type DatePickerView } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration — it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout — large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling — external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, tz: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers — all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Day-cell keyboard navigation (full ARIA grid pattern) ─────────────────\n\n function handleDayKeydown(e: KeyboardEvent): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid-days');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>('.cal-cell-day'));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelectDay(cell.dataset.iso ?? '');\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + 7];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - 7];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / 7) * 7]; // first cell in same row\n } else if (e.key === 'End') {\n target = allCells[Math.floor(idx / 7) * 7 + 6]; // last cell in same row\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Month/year-cell keyboard navigation (fixed 4-column grid) ─────────────\n\n function handleGridKeydown(e: KeyboardEvent, cellSelector: string, columns: number, onSelect: () => void): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>(cellSelector));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect();\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + columns];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - columns];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / columns) * columns];\n } else if (e.key === 'End') {\n target = allCells[Math.min(Math.floor(idx / columns) * columns + columns - 1, allCells.length - 1)];\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n :aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span><span class=\"cal-label-sep\" aria-hidden=\"true\">/</span\n ><span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n :aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`<div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>`,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n :aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n return html`<div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``\n }\n </div>`;\n }\n\n return html`<div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>`\n : html``\n }\n </div>`;\n }}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n :aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"calendar.js","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { define, html, prop, bind, useEmit, styleMap } from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { Temporal, format } from '@vielzeug/tempo';\n\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\n\nimport '../../content/icon/icon';\nimport '../../feedback/badge/badge';\nimport { createDatePickerControl, parseIso, toIsoString, type DatePickerView } from '../../headless';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration — it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout — large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling — external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, tz: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers — all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Day-cell keyboard navigation (full ARIA grid pattern) ─────────────────\n\n function handleDayKeydown(e: KeyboardEvent): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid-days');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>('.cal-cell-day'));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleSelectDay(cell.dataset.iso ?? '');\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + 7];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - 7];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / 7) * 7]; // first cell in same row\n } else if (e.key === 'End') {\n target = allCells[Math.floor(idx / 7) * 7 + 6]; // last cell in same row\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Month/year-cell keyboard navigation (fixed 4-column grid) ─────────────\n\n function handleGridKeydown(e: KeyboardEvent, cellSelector: string, columns: number, onSelect: () => void): void {\n const cell = e.currentTarget as HTMLElement;\n const grid = cell.closest('.cal-grid');\n\n if (!grid) return;\n\n const allCells = Array.from(grid.querySelectorAll<HTMLElement>(cellSelector));\n const idx = allCells.indexOf(cell);\n\n if (idx === -1) return;\n\n let target: HTMLElement | undefined;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onSelect();\n\n return;\n } else if (e.key === 'ArrowRight') {\n target = allCells[idx + 1];\n } else if (e.key === 'ArrowLeft') {\n target = allCells[idx - 1];\n } else if (e.key === 'ArrowDown') {\n target = allCells[idx + columns];\n } else if (e.key === 'ArrowUp') {\n target = allCells[idx - columns];\n } else if (e.key === 'Home') {\n target = allCells[Math.floor(idx / columns) * columns];\n } else if (e.key === 'End') {\n target = allCells[Math.min(Math.floor(idx / columns) * columns + columns - 1, allCells.length - 1)];\n } else {\n return;\n }\n\n e.preventDefault();\n target?.focus();\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n :aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span><span class=\"cal-label-sep\" aria-hidden=\"true\">/</span\n ><span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n :aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`<div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>`,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n :aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n return html`<div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``\n }\n </div>`;\n }\n\n return html`<div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) =>\n html`<ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n :style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>`,\n )}\n ${\n overflow > 0\n ? html`<span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>`\n : html``\n }\n </div>`;\n }}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n :aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) =>\n html`<div role=\"row\">\n ${row.map(\n (cell) =>\n html`<div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n :aria-selected=\"${() => String(cell.isSelected)}\"\n :aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>`,\n )}\n </div>`,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -1,18 +1,18 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/states.css.cjs"),t=require("./shared/prop-bundles.cjs"),n=require("./headless/ore.cjs"),r=require("./headless/choice-field.cjs"),i=require("./headless/light-dom.cjs"),a=require("./inputs/shared/form-context.cjs"),o=require("./inputs/checkbox-group/checkbox-group.css.cjs");let s=require("@vielzeug/ore"),c=require("@vielzeug/ore/directives"),l=require("@vielzeug/ripple"),u=require("@vielzeug/ore/forms");var d=(0,s.createContext)(`CheckboxGroupContext`),f=`ore-checkbox-group`;(0,s.define)(f,{formAssociated:!0,props:{...t.themableBundle,...t.sizableBundle,...t.disablableBundle,error:s.prop.string(),helper:s.prop.string(),label:s.prop.string(),name:s.prop.string(),orientation:s.prop.string(`vertical`),required:s.prop.bool(!1),values:{...s.prop.string(),reflect:!1}},setup(e){let t=(0,s.getHost)(),o=(0,s.useEmit)(),f=(0,s.useSlots)(),p=s.watchEffect,m=(0,s.inject)(a.FORM_CTX),h=a.useFormContext(e,m),g=r.createChoiceField({disabled:h.disabled,error:e.error,helper:e.helper,multiple:(0,l.signal)(!0),prefix:`checkbox-group`,required:e.required,signal:n.lifecycleSignal(s.onCleanup),validateOn:m?.validateOn,value:e.values});g.attachFormField((0,u.useField)({disabled:g.disabled,onReset:g.reset,toFormValue:e=>e,validationMessage:g.validationMessage,validity:g.validity,value:g.formValue}));let _=g.selectedValues,v=()=>i.getLightChildrenByTag(t,`ore-checkbox`),y=e=>i.getChoiceLabel(v(),e),b=e=>{let t=_.value,n=t.map(y);o(`change`,{labels:n,originalEvent:e,values:t})},x=(e,t)=>{g.toggleValue(e),g.triggerValidation(`change`),b(t)};(0,s.provide)(d,{color:e.color,disabled:(0,l.computed)(()=>!!e.disabled.value),size:e.size,toggle:x,values:_});let S=()=>{let t=_.value,n=e.color.value,r=e.size.value,i=e.disabled.value,a=v();for(let e of a){let a=e.getAttribute(`value`)??``;e.toggleAttribute(`checked`,t.includes(a)),n?e.setAttribute(`color`,n):e.removeAttribute(`color`),r?e.setAttribute(`size`,r):e.removeAttribute(`size`),e.toggleAttribute(`disabled`,!!i)}};p(()=>{f.elements().value,S()}),p(()=>{f.elements().value;let e=v().map(e=>{let t=t=>{t.stopPropagation();let n=(e.getAttribute(`value`)??``).trim();n&&x(n,t)};return e.addEventListener(`change`,t),()=>{e.removeEventListener(`change`,t)}});return()=>{for(let t of e)t()}});let C=(0,s.createStableId)(`checkbox-group-legend`),w=`${C}-error`,T=`${C}-helper`,E=()=>!!e.error.value,D=()=>!!e.helper.value&&!E();return(0,s.bind)({attr:{size:h.size,values:g.formValue}}),s.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/states.css.cjs"),t=require("./shared/prop-bundles.cjs"),n=require("./headless/ore.cjs"),r=require("./headless/choice-field.cjs"),i=require("./headless/light-dom.cjs"),a=require("./inputs/shared/form-context.cjs"),o=require("./inputs/checkbox-group/checkbox-group.css.cjs");let s=require("@vielzeug/ore"),c=require("@vielzeug/ripple"),l=require("@vielzeug/ore/forms");var u=(0,s.createContext)(`CheckboxGroupContext`),d=`ore-checkbox-group`;(0,s.define)(d,{formAssociated:!0,props:{...t.themableBundle,...t.sizableBundle,...t.disablableBundle,error:s.prop.string(),helper:s.prop.string(),label:s.prop.string(),name:s.prop.string(),orientation:s.prop.string(`vertical`),required:s.prop.bool(!1),values:{...s.prop.string(),reflect:!1}},setup(e){let t=(0,s.getHost)(),o=(0,s.useEmit)(),d=(0,s.useSlots)(),f=s.watchEffect,p=(0,s.inject)(a.FORM_CTX),m=a.useFormContext(e,p),h=r.createChoiceField({disabled:m.disabled,error:e.error,helper:e.helper,multiple:(0,c.signal)(!0),prefix:`checkbox-group`,required:e.required,signal:n.lifecycleSignal(s.onCleanup),validateOn:p?.validateOn,value:e.values});h.attachFormField((0,l.useField)({disabled:h.disabled,onReset:h.reset,toFormValue:e=>e,validationMessage:h.validationMessage,validity:h.validity,value:h.formValue}));let g=h.selectedValues,_=()=>i.getLightChildrenByTag(t,`ore-checkbox`),v=e=>i.getChoiceLabel(_(),e),y=e=>{let t=g.value,n=t.map(v);o(`change`,{labels:n,originalEvent:e,values:t})},b=(e,t)=>{h.toggleValue(e),h.triggerValidation(`change`),y(t)};(0,s.provide)(u,{color:e.color,disabled:(0,c.computed)(()=>!!e.disabled.value),size:e.size,toggle:b,values:g});let x=()=>{let t=g.value,n=e.color.value,r=e.size.value,i=e.disabled.value,a=_();for(let e of a){let a=e.getAttribute(`value`)??``;e.toggleAttribute(`checked`,t.includes(a)),n?e.setAttribute(`color`,n):e.removeAttribute(`color`),r?e.setAttribute(`size`,r):e.removeAttribute(`size`),e.toggleAttribute(`disabled`,!!i)}};f(()=>{d.elements().value,x()}),f(()=>{d.elements().value;let e=_().map(e=>{let t=t=>{t.stopPropagation();let n=(e.getAttribute(`value`)??``).trim();n&&b(n,t)};return e.addEventListener(`change`,t),()=>{e.removeEventListener(`change`,t)}});return()=>{for(let t of e)t()}});let S=(0,s.createStableId)(`checkbox-group-legend`),C=`${S}-error`,w=`${S}-helper`,T=()=>!!e.error.value,E=()=>!!e.helper.value&&!T();return(0,s.bind)({attr:{size:m.size,values:h.formValue}}),s.html`
2
2
  <fieldset
3
3
  role="group"
4
4
  aria-required="${()=>String(!!e.required.value)}"
5
- aria-invalid="${()=>String(E())}"
6
- aria-errormessage="${()=>E()?w:null}"
7
- aria-describedby="${()=>E()?w:D()?T:null}">
8
- <legend id="${C}" ?hidden=${()=>!e.label.value}>
9
- ${e.label}${(0,c.when)(()=>!!e.required.value,()=>s.html`<span aria-hidden="true"> *</span>`)}
5
+ aria-invalid="${()=>String(T())}"
6
+ aria-errormessage="${()=>T()?C:null}"
7
+ aria-describedby="${()=>T()?C:E()?w:null}">
8
+ <legend id="${S}" ?hidden=${()=>!e.label.value}>
9
+ ${e.label}${(0,s.when)(()=>!!e.required.value,()=>s.html`<span aria-hidden="true"> *</span>`)}
10
10
  </legend>
11
11
  <div class="checkbox-group-items" part="items">
12
12
  <slot></slot>
13
13
  </div>
14
- <div class="error-text" id="${w}" role="alert" ?hidden=${()=>!E()}>${e.error}</div>
15
- <div class="helper-text" id="${T}" ?hidden=${()=>!D()}>${e.helper}</div>
14
+ <div class="error-text" id="${C}" role="alert" ?hidden=${()=>!T()}>${e.error}</div>
15
+ <div class="helper-text" id="${w}" ?hidden=${()=>!E()}>${e.helper}</div>
16
16
  </fieldset>
17
- `},styles:[e.disabledStateMixin,o.default]}),exports.CHECKBOX_GROUP_CTX=d,exports.CHECKBOX_GROUP_TAG=f;
17
+ `},styles:[e.disabledStateMixin,o.default]}),exports.CHECKBOX_GROUP_CTX=u,exports.CHECKBOX_GROUP_TAG=d;
18
18
  //# sourceMappingURL=checkbox-group.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox-group.cjs","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n inject,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: fCtxProps.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"checkbox-group.cjs","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n inject,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: fCtxProps.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -5,8 +5,7 @@ import { createChoiceField as a } from "./headless/choice-field.js";
5
5
  import { getChoiceLabel as o, getLightChildrenByTag as s } from "./headless/light-dom.js";
6
6
  import { FORM_CTX as c, useFormContext as l } from "./inputs/shared/form-context.js";
7
7
  import u from "./inputs/checkbox-group/checkbox-group.css.js";
8
- import { bind as d, createContext as f, createStableId as p, define as m, getHost as h, html as g, inject as _, onCleanup as v, prop as y, provide as b, useEmit as x, useSlots as S, watchEffect as C } from "@vielzeug/ore";
9
- import { when as w } from "@vielzeug/ore/directives";
8
+ import { bind as d, createContext as f, createStableId as p, define as m, getHost as h, html as g, inject as _, onCleanup as v, prop as y, provide as b, useEmit as x, useSlots as S, watchEffect as C, when as w } from "@vielzeug/ore";
10
9
  import { computed as T, signal as E } from "@vielzeug/ripple";
11
10
  import { useField as D } from "@vielzeug/ore/forms";
12
11
  //#region src/inputs/checkbox-group/checkbox-group.ts
@@ -1 +1 @@
1
- {"version":3,"file":"checkbox-group.js","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n inject,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: fCtxProps.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"checkbox-group.js","names":[],"sources":["../src/inputs/checkbox-group/checkbox-group.ts"],"sourcesContent":["import {\n createContext,\n createStableId,\n define,\n html,\n inject,\n prop,\n bind,\n getHost,\n onCleanup,\n provide,\n useEmit,\n useSlots,\n watchEffect,\n when,\n} from '@vielzeug/ore';\nimport { useField } from '@vielzeug/ore/forms';\nimport { computed, type Readable, signal } from '@vielzeug/ripple';\n\nimport type { ComponentSize, ThemeColor } from '../../types';\n\nimport {\n type ChoiceChangeDetail,\n lifecycleSignal,\n createChoiceField,\n getChoiceLabel,\n getLightChildrenByTag,\n} from '../../headless';\nimport { disablableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { disabledStateMixin } from '../../styles';\nimport { FORM_CTX, useFormContext } from '../shared/form-context';\nimport componentStyles from './checkbox-group.css?inline';\n\n// ─── Context ──────────────────────────────────────────────────────────────────\n\nexport type CheckboxGroupContext = {\n color: Readable<ThemeColor | undefined>;\n disabled: Readable<boolean>;\n size: Readable<ComponentSize | undefined>;\n toggle: (value: string, originalEvent?: Event) => void;\n values: Readable<string[]>;\n};\n\nexport const CHECKBOX_GROUP_CTX = createContext<CheckboxGroupContext>('CheckboxGroupContext');\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type OreCheckboxGroupProps = {\n /** Theme color — propagated to all child ore-checkbox elements */\n color?: ThemeColor;\n /** Disable all checkboxes in the group */\n disabled?: boolean;\n /** Error message shown below the group */\n error?: string;\n /** Helper text shown below the group */\n helper?: string;\n /** Legend / label for the fieldset. Required for accessibility. */\n label?: string;\n /** Form field name used during submission */\n name?: string;\n /** Layout direction of the checkbox options */\n orientation?: 'vertical' | 'horizontal';\n /** Mark the group as required */\n required?: boolean;\n /** Size — propagated to all child ore-checkbox elements */\n size?: ComponentSize;\n /** Comma-separated list of currently checked values */\n values?: string;\n};\n\nexport type OreCheckboxGroupEvents = {\n change: ChoiceChangeDetail;\n};\n\n/**\n * A fieldset wrapper that groups `ore-checkbox` elements, provides shared\n * `color` and `size` via context, and manages multi-value selection state.\n *\n * @element ore-checkbox-group\n *\n * @attr {string} label - Legend text (required for a11y)\n * @attr {string} values - Comma-separated list of checked values\n * @attr {boolean} disabled - Disable all checkboxes in the group\n * @attr {string} error - Error message\n * @attr {string} helper - Helper text\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} orientation - Layout: 'vertical' | 'horizontal'\n * @attr {boolean} required - Required field\n *\n * @fires change - Emitted when selection changes. detail: { value: string, values: string[], labels: string[], originalEvent?: Event }\n *\n * @slot - Place `ore-checkbox` elements here\n *\n * @cssprop --checkbox-group-direction - Flex direction of the items list ('row' | 'column')\n * @cssprop --checkbox-group-gap - Gap between checkbox items\n * @part items - Items container.\n * @example\n * ```html\n * <ore-checkbox-group name=\"fruits\" label=\"Favourite fruits\" required>\n * <ore-checkbox value=\"apple\">Apple</ore-checkbox>\n * <ore-checkbox value=\"banana\">Banana</ore-checkbox>\n * <ore-checkbox value=\"cherry\">Cherry</ore-checkbox>\n * </ore-checkbox-group>\n * <ore-checkbox-group name=\"options\" orientation=\"horizontal\" color=\"primary\">\n * <ore-checkbox value=\"a\">Option A</ore-checkbox>\n * <ore-checkbox value=\"b\">Option B</ore-checkbox>\n * </ore-checkbox-group>\n * ```\n */\nexport const CHECKBOX_GROUP_TAG = 'ore-checkbox-group' as const;\ndefine<OreCheckboxGroupProps>(CHECKBOX_GROUP_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n error: prop.string(),\n helper: prop.string(),\n label: prop.string(),\n name: prop.string(),\n orientation: prop.string('vertical'),\n required: prop.bool(false),\n // Not auto-reflected (`reflect: false`) — the derived, interaction-updated selection\n // (`choice.formValue`) is the single writer for this attribute, via `bind()` below;\n // letting `prop.string()`'s own default reflection also write the raw incoming value\n // would leave two effects racing to set the same attribute from different sources.\n values: { ...prop.string(), reflect: false },\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCheckboxGroupEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const formCtx = inject(FORM_CTX);\n const fCtxProps = useFormContext(props, formCtx);\n\n const choice = createChoiceField({\n disabled: fCtxProps.disabled,\n error: props.error,\n helper: props.helper,\n multiple: signal(true),\n prefix: 'checkbox-group',\n required: props.required,\n signal: lifecycleSignal(onCleanup),\n validateOn: formCtx?.validateOn,\n value: props.values,\n });\n\n choice.attachFormField(\n useField<string>({\n disabled: choice.disabled,\n onReset: choice.reset,\n toFormValue: (v) => v,\n validationMessage: choice.validationMessage,\n validity: choice.validity,\n value: choice.formValue,\n }),\n );\n\n const checkedValues = choice.selectedValues;\n\n const getCheckboxes = (): HTMLElement[] => getLightChildrenByTag(el, 'ore-checkbox');\n const getLabelForValue = (value: string): string => getChoiceLabel(getCheckboxes(), value);\n const emitChange = (originalEvent?: Event) => {\n const values = checkedValues.value;\n\n const labels = values.map(getLabelForValue);\n\n emit('change', { labels, originalEvent, values });\n };\n\n const toggleCheckbox = (val: string, originalEvent?: Event) => {\n choice.toggleValue(val);\n choice.triggerValidation('change');\n emitChange(originalEvent);\n };\n\n provide(CHECKBOX_GROUP_CTX, {\n color: props.color,\n disabled: computed(() => Boolean(props.disabled.value)),\n size: props.size,\n toggle: toggleCheckbox,\n values: checkedValues,\n });\n\n // Sync checked state + color/size/disabled onto slotted ore-checkbox children\n const syncChildren = () => {\n const values = checkedValues.value;\n const color = props.color.value;\n const size = props.size.value;\n const disabled = props.disabled.value;\n const checkboxes = getCheckboxes();\n\n for (const checkbox of checkboxes) {\n const val = checkbox.getAttribute('value') ?? '';\n\n checkbox.toggleAttribute('checked', values.includes(val));\n\n if (color) checkbox.setAttribute('color', color);\n else checkbox.removeAttribute('color');\n\n if (size) checkbox.setAttribute('size', size);\n else checkbox.removeAttribute('size');\n\n checkbox.toggleAttribute('disabled', Boolean(disabled));\n }\n };\n\n watch(() => {\n void slots.elements().value;\n syncChildren();\n });\n\n watch(() => {\n void slots.elements().value;\n\n const listeners = getCheckboxes().map((checkbox) => {\n const handler = (event: Event) => {\n event.stopPropagation();\n\n const val = (checkbox.getAttribute('value') ?? '').trim();\n\n if (!val) return;\n\n toggleCheckbox(val, event);\n };\n\n checkbox.addEventListener('change', handler);\n\n return () => {\n checkbox.removeEventListener('change', handler);\n };\n });\n\n return () => {\n for (const dispose of listeners) dispose();\n };\n });\n\n const legendId = createStableId('checkbox-group-legend');\n const errorId = `${legendId}-error`;\n const helperId = `${legendId}-helper`;\n const hasError = () => Boolean(props.error.value);\n const hasHelper = () => Boolean(props.helper.value) && !hasError();\n\n // Reactive, not a one-off `el.setAttribute()` inside the click handler: the host's `values`\n // attribute must stay in sync with the selection regardless of *why* it changed (a click,\n // or `reset()` on ancestor form reset — neither of which should need its own copy of this).\n bind({ attr: { size: fCtxProps.size, values: choice.formValue } });\n\n return html`\n <fieldset\n role=\"group\"\n aria-required=\"${() => String(Boolean(props.required.value))}\"\n aria-invalid=\"${() => String(hasError())}\"\n aria-errormessage=\"${() => (hasError() ? errorId : null)}\"\n aria-describedby=\"${() => (hasError() ? errorId : hasHelper() ? helperId : null)}\">\n <legend id=\"${legendId}\" ?hidden=${() => !props.label.value}>\n ${props.label}${when(\n () => Boolean(props.required.value),\n () => html`<span aria-hidden=\"true\"> *</span>`,\n )}\n </legend>\n <div class=\"checkbox-group-items\" part=\"items\">\n <slot></slot>\n </div>\n <div class=\"error-text\" id=\"${errorId}\" role=\"alert\" ?hidden=${() => !hasError()}>${props.error}</div>\n <div class=\"helper-text\" id=\"${helperId}\" ?hidden=${() => !hasHelper()}>${props.helper}</div>\n </fieldset>\n `;\n },\n styles: [disabledStateMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./content/code-window/code-window.css.cjs");let t=require("@vielzeug/ore"),n=require("@vielzeug/ore/directives"),r=require("@vielzeug/ripple");var i=`ore-code-window`;(0,t.define)(i,{props:{filename:t.prop.string(),lang:t.prop.string(`ts`),title:t.prop.string(`MCP tool call`),variant:t.prop.oneOf([`code`,`chat`],`code`)},setup(e){let i=(0,r.computed)(()=>e.variant.value===`code`),a=(0,r.computed)(()=>!!e.filename.value);return t.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./content/code-window/code-window.css.cjs");let t=require("@vielzeug/ore"),n=require("@vielzeug/ripple");var r=`ore-code-window`;(0,t.define)(r,{props:{filename:t.prop.string(),lang:t.prop.string(`ts`),title:t.prop.string(`MCP tool call`),variant:t.prop.oneOf([`code`,`chat`],`code`)},setup(e){let r=(0,n.computed)(()=>e.variant.value===`code`),i=(0,n.computed)(()=>!!e.filename.value);return t.html`
2
2
  <div class="window" part="window">
3
3
  <div class="header" part="header">
4
- ${(0,n.when)(i,()=>t.html`
4
+ ${(0,t.when)(r,()=>t.html`
5
5
  <span class="lang" part="lang">${e.lang}</span>
6
- ${(0,n.when)(a,()=>t.html`<span class="filename" part="filename">${e.filename}</span>`)}
6
+ ${(0,t.when)(i,()=>t.html`<span class="filename" part="filename">${e.filename}</span>`)}
7
7
  `,()=>t.html`
8
8
  <div class="dots" part="dots" aria-hidden="true"><span></span><span></span><span></span></div>
9
9
  <span class="title" part="title">${e.title}</span>
@@ -15,5 +15,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
15
15
  <slot></slot>
16
16
  </div>
17
17
  </div>
18
- `},styles:[e.default]}),exports.CODE_WINDOW_TAG=i;
18
+ `},styles:[e.default]}),exports.CODE_WINDOW_TAG=r;
19
19
  //# sourceMappingURL=code-window.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"code-window.cjs","names":[],"sources":["../src/content/code-window/code-window.ts"],"sourcesContent":["import { define, html, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\n\nimport componentStyles from './code-window.css?inline';\n\n/** `ore-code-window` variant */\nexport type CodeWindowVariant = 'code' | 'chat';\n\n/** `ore-code-window` component properties */\nexport type OreCodeWindowProps = {\n /** Filename label shown after the language badge (`variant=\"code\"` only) */\n filename?: string;\n /** Language badge text, e.g. `\"ts\"`, `\"sh\"` (`variant=\"code\"` only) */\n lang?: string;\n /** Title string shown beside the traffic-light dots (`variant=\"chat\"` only) */\n title?: string;\n /**\n * `\"code\"` (default) — header shows a language badge + filename.\n * `\"chat\"` — header shows traffic-light dots + a title.\n */\n variant?: CodeWindowVariant;\n};\n\n/**\n * A styled window chrome for code blocks and AI/MCP conversation flows.\n *\n * Two variants:\n * - `variant=\"code\"` (default) — language badge + optional filename header.\n * - `variant=\"chat\"` — traffic-light dots + title header.\n *\n * @element ore-code-window\n *\n * @attr {'code'|'chat'} variant - Window style variant\n * @attr {string} lang - Language badge label (variant=\"code\" only)\n * @attr {string} filename - Filename shown next to the badge (variant=\"code\" only)\n * @attr {string} title - Label beside the dots (variant=\"chat\" only)\n *\n * @slot - Main body content (code, conversation turns, or any markup)\n * @slot header-end - Optional content appended to the trailing edge of the header\n *\n * @cssprop --code-window-bg - Window background color\n * @cssprop --code-window-header-bg - Header background color\n * @cssprop --code-window-border-color - Border color\n * @cssprop --code-window-radius - Border radius\n * @cssprop --code-window-shadow - Box shadow\n * @cssprop --code-window-body-padding - Body slot padding\n *\n * @part window - The root window element\n * @part header - The header bar\n * @part lang - The language badge (`variant=\"code\"`)\n * @part filename - The filename label (`variant=\"code\"`)\n * @part dots - The traffic-light dot container (`variant=\"chat\"`)\n * @part title - The title label (`variant=\"chat\"`)\n * @part body - The body container wrapping the default slot\n *\n * @example\n * ```html\n * <ore-code-window lang=\"ts\" filename=\"app.ts\">\n * <pre>const x = 1;</pre>\n * </ore-code-window>\n *\n * <ore-code-window variant=\"chat\" title=\"MCP tool call\">\n * <!-- conversation turns go here -->\n * </ore-code-window>\n * ```\n */\nexport const CODE_WINDOW_TAG = 'ore-code-window' as const;\ndefine<OreCodeWindowProps>(CODE_WINDOW_TAG, {\n props: {\n filename: prop.string(),\n lang: prop.string('ts'),\n title: prop.string('MCP tool call'),\n variant: prop.oneOf(['code', 'chat'] as const, 'code'),\n },\n setup(props) {\n const isCode = computed(() => props.variant.value === 'code');\n const hasFilename = computed(() => Boolean(props.filename.value));\n\n return html`\n <div class=\"window\" part=\"window\">\n <div class=\"header\" part=\"header\">\n ${when(\n isCode,\n () => html`\n <span class=\"lang\" part=\"lang\">${props.lang}</span>\n ${when(hasFilename, () => html`<span class=\"filename\" part=\"filename\">${props.filename}</span>`)}\n `,\n () => html`\n <div class=\"dots\" part=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <span class=\"title\" part=\"title\">${props.title}</span>\n `,\n )}\n <div class=\"header-spacer\"></div>\n <slot name=\"header-end\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n </div>\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"mOAmEA,IAAa,EAAkB,+BACJ,EAAiB,CAC1C,MAAO,CACL,SAAU,EAAA,KAAK,OAAO,EACtB,KAAM,EAAA,KAAK,OAAO,IAAI,EACtB,MAAO,EAAA,KAAK,OAAO,eAAe,EAClC,QAAS,EAAA,KAAK,MAAM,CAAC,OAAQ,MAAM,EAAY,MAAM,CACvD,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAA,EAAA,SAAA,KAAwB,EAAM,QAAQ,QAAU,MAAM,EACtD,GAAA,EAAA,EAAA,SAAA,KAA6B,EAAQ,EAAM,SAAS,KAAM,EAEhE,MAAO,GAAA,IAAI;;;uBAIH,MACM,EAAA,IAAI;+CACyB,EAAM,KAAK;2BACrC,MAAmB,EAAA,IAAI,0CAA0C,EAAM,SAAS,QAAQ,EAAE;kBAE7F,EAAA,IAAI;;iDAE2B,EAAM,MAAM;aAEnD,EAAE;;;;;;;;KASV,EACA,OAAQ,CAAC,EAAA,OAAe,CAC1B,CAAC"}
1
+ {"version":3,"file":"code-window.cjs","names":[],"sources":["../src/content/code-window/code-window.ts"],"sourcesContent":["import { define, html, prop, when } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport componentStyles from './code-window.css?inline';\n\n/** `ore-code-window` variant */\nexport type CodeWindowVariant = 'code' | 'chat';\n\n/** `ore-code-window` component properties */\nexport type OreCodeWindowProps = {\n /** Filename label shown after the language badge (`variant=\"code\"` only) */\n filename?: string;\n /** Language badge text, e.g. `\"ts\"`, `\"sh\"` (`variant=\"code\"` only) */\n lang?: string;\n /** Title string shown beside the traffic-light dots (`variant=\"chat\"` only) */\n title?: string;\n /**\n * `\"code\"` (default) — header shows a language badge + filename.\n * `\"chat\"` — header shows traffic-light dots + a title.\n */\n variant?: CodeWindowVariant;\n};\n\n/**\n * A styled window chrome for code blocks and AI/MCP conversation flows.\n *\n * Two variants:\n * - `variant=\"code\"` (default) — language badge + optional filename header.\n * - `variant=\"chat\"` — traffic-light dots + title header.\n *\n * @element ore-code-window\n *\n * @attr {'code'|'chat'} variant - Window style variant\n * @attr {string} lang - Language badge label (variant=\"code\" only)\n * @attr {string} filename - Filename shown next to the badge (variant=\"code\" only)\n * @attr {string} title - Label beside the dots (variant=\"chat\" only)\n *\n * @slot - Main body content (code, conversation turns, or any markup)\n * @slot header-end - Optional content appended to the trailing edge of the header\n *\n * @cssprop --code-window-bg - Window background color\n * @cssprop --code-window-header-bg - Header background color\n * @cssprop --code-window-border-color - Border color\n * @cssprop --code-window-radius - Border radius\n * @cssprop --code-window-shadow - Box shadow\n * @cssprop --code-window-body-padding - Body slot padding\n *\n * @part window - The root window element\n * @part header - The header bar\n * @part lang - The language badge (`variant=\"code\"`)\n * @part filename - The filename label (`variant=\"code\"`)\n * @part dots - The traffic-light dot container (`variant=\"chat\"`)\n * @part title - The title label (`variant=\"chat\"`)\n * @part body - The body container wrapping the default slot\n *\n * @example\n * ```html\n * <ore-code-window lang=\"ts\" filename=\"app.ts\">\n * <pre>const x = 1;</pre>\n * </ore-code-window>\n *\n * <ore-code-window variant=\"chat\" title=\"MCP tool call\">\n * <!-- conversation turns go here -->\n * </ore-code-window>\n * ```\n */\nexport const CODE_WINDOW_TAG = 'ore-code-window' as const;\ndefine<OreCodeWindowProps>(CODE_WINDOW_TAG, {\n props: {\n filename: prop.string(),\n lang: prop.string('ts'),\n title: prop.string('MCP tool call'),\n variant: prop.oneOf(['code', 'chat'] as const, 'code'),\n },\n setup(props) {\n const isCode = computed(() => props.variant.value === 'code');\n const hasFilename = computed(() => Boolean(props.filename.value));\n\n return html`\n <div class=\"window\" part=\"window\">\n <div class=\"header\" part=\"header\">\n ${when(\n isCode,\n () => html`\n <span class=\"lang\" part=\"lang\">${props.lang}</span>\n ${when(hasFilename, () => html`<span class=\"filename\" part=\"filename\">${props.filename}</span>`)}\n `,\n () => html`\n <div class=\"dots\" part=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <span class=\"title\" part=\"title\">${props.title}</span>\n `,\n )}\n <div class=\"header-spacer\"></div>\n <slot name=\"header-end\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n </div>\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"6LAkEA,IAAa,EAAkB,+BACJ,EAAiB,CAC1C,MAAO,CACL,SAAU,EAAA,KAAK,OAAO,EACtB,KAAM,EAAA,KAAK,OAAO,IAAI,EACtB,MAAO,EAAA,KAAK,OAAO,eAAe,EAClC,QAAS,EAAA,KAAK,MAAM,CAAC,OAAQ,MAAM,EAAY,MAAM,CACvD,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAA,EAAA,SAAA,KAAwB,EAAM,QAAQ,QAAU,MAAM,EACtD,GAAA,EAAA,EAAA,SAAA,KAA6B,EAAQ,EAAM,SAAS,KAAM,EAEhE,MAAO,GAAA,IAAI;;;uBAIH,MACM,EAAA,IAAI;+CACyB,EAAM,KAAK;2BACrC,MAAmB,EAAA,IAAI,0CAA0C,EAAM,SAAS,QAAQ,EAAE;kBAE7F,EAAA,IAAI;;iDAE2B,EAAM,MAAM;aAEnD,EAAE;;;;;;;;KASV,EACA,OAAQ,CAAC,EAAA,OAAe,CAC1B,CAAC"}
@@ -1,6 +1,5 @@
1
1
  import e from "./content/code-window/code-window.css.js";
2
- import { define as t, html as n, prop as r } from "@vielzeug/ore";
3
- import { when as i } from "@vielzeug/ore/directives";
2
+ import { define as t, html as n, prop as r, when as i } from "@vielzeug/ore";
4
3
  import { computed as a } from "@vielzeug/ripple";
5
4
  //#region src/content/code-window/code-window.ts
6
5
  var o = "ore-code-window";
@@ -1 +1 @@
1
- {"version":3,"file":"code-window.js","names":[],"sources":["../src/content/code-window/code-window.ts"],"sourcesContent":["import { define, html, prop } from '@vielzeug/ore';\nimport { when } from '@vielzeug/ore/directives';\nimport { computed } from '@vielzeug/ripple';\n\nimport componentStyles from './code-window.css?inline';\n\n/** `ore-code-window` variant */\nexport type CodeWindowVariant = 'code' | 'chat';\n\n/** `ore-code-window` component properties */\nexport type OreCodeWindowProps = {\n /** Filename label shown after the language badge (`variant=\"code\"` only) */\n filename?: string;\n /** Language badge text, e.g. `\"ts\"`, `\"sh\"` (`variant=\"code\"` only) */\n lang?: string;\n /** Title string shown beside the traffic-light dots (`variant=\"chat\"` only) */\n title?: string;\n /**\n * `\"code\"` (default) — header shows a language badge + filename.\n * `\"chat\"` — header shows traffic-light dots + a title.\n */\n variant?: CodeWindowVariant;\n};\n\n/**\n * A styled window chrome for code blocks and AI/MCP conversation flows.\n *\n * Two variants:\n * - `variant=\"code\"` (default) — language badge + optional filename header.\n * - `variant=\"chat\"` — traffic-light dots + title header.\n *\n * @element ore-code-window\n *\n * @attr {'code'|'chat'} variant - Window style variant\n * @attr {string} lang - Language badge label (variant=\"code\" only)\n * @attr {string} filename - Filename shown next to the badge (variant=\"code\" only)\n * @attr {string} title - Label beside the dots (variant=\"chat\" only)\n *\n * @slot - Main body content (code, conversation turns, or any markup)\n * @slot header-end - Optional content appended to the trailing edge of the header\n *\n * @cssprop --code-window-bg - Window background color\n * @cssprop --code-window-header-bg - Header background color\n * @cssprop --code-window-border-color - Border color\n * @cssprop --code-window-radius - Border radius\n * @cssprop --code-window-shadow - Box shadow\n * @cssprop --code-window-body-padding - Body slot padding\n *\n * @part window - The root window element\n * @part header - The header bar\n * @part lang - The language badge (`variant=\"code\"`)\n * @part filename - The filename label (`variant=\"code\"`)\n * @part dots - The traffic-light dot container (`variant=\"chat\"`)\n * @part title - The title label (`variant=\"chat\"`)\n * @part body - The body container wrapping the default slot\n *\n * @example\n * ```html\n * <ore-code-window lang=\"ts\" filename=\"app.ts\">\n * <pre>const x = 1;</pre>\n * </ore-code-window>\n *\n * <ore-code-window variant=\"chat\" title=\"MCP tool call\">\n * <!-- conversation turns go here -->\n * </ore-code-window>\n * ```\n */\nexport const CODE_WINDOW_TAG = 'ore-code-window' as const;\ndefine<OreCodeWindowProps>(CODE_WINDOW_TAG, {\n props: {\n filename: prop.string(),\n lang: prop.string('ts'),\n title: prop.string('MCP tool call'),\n variant: prop.oneOf(['code', 'chat'] as const, 'code'),\n },\n setup(props) {\n const isCode = computed(() => props.variant.value === 'code');\n const hasFilename = computed(() => Boolean(props.filename.value));\n\n return html`\n <div class=\"window\" part=\"window\">\n <div class=\"header\" part=\"header\">\n ${when(\n isCode,\n () => html`\n <span class=\"lang\" part=\"lang\">${props.lang}</span>\n ${when(hasFilename, () => html`<span class=\"filename\" part=\"filename\">${props.filename}</span>`)}\n `,\n () => html`\n <div class=\"dots\" part=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <span class=\"title\" part=\"title\">${props.title}</span>\n `,\n )}\n <div class=\"header-spacer\"></div>\n <slot name=\"header-end\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n </div>\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":";;;;;AAmEA,IAAa,IAAkB;AAC/B,EAA2B,GAAiB;CAC1C,OAAO;EACL,UAAU,EAAK,OAAO;EACtB,MAAM,EAAK,OAAO,IAAI;EACtB,OAAO,EAAK,OAAO,eAAe;EAClC,SAAS,EAAK,MAAM,CAAC,QAAQ,MAAM,GAAY,MAAM;CACvD;CACA,MAAM,GAAO;EACX,IAAM,IAAS,QAAe,EAAM,QAAQ,UAAU,MAAM,GACtD,IAAc,QAAe,EAAQ,EAAM,SAAS,KAAM;EAEhE,OAAO,CAAI;;;YAGH,EACA,SACM,CAAI;+CACyB,EAAM,KAAK;gBAC1C,EAAK,SAAmB,CAAI,0CAA0C,EAAM,SAAS,QAAQ,EAAE;qBAE7F,CAAI;;iDAE2B,EAAM,MAAM;aAEnD,EAAE;;;;;;;;;CASV;CACA,QAAQ,CAAC,CAAe;AAC1B,CAAC"}
1
+ {"version":3,"file":"code-window.js","names":[],"sources":["../src/content/code-window/code-window.ts"],"sourcesContent":["import { define, html, prop, when } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport componentStyles from './code-window.css?inline';\n\n/** `ore-code-window` variant */\nexport type CodeWindowVariant = 'code' | 'chat';\n\n/** `ore-code-window` component properties */\nexport type OreCodeWindowProps = {\n /** Filename label shown after the language badge (`variant=\"code\"` only) */\n filename?: string;\n /** Language badge text, e.g. `\"ts\"`, `\"sh\"` (`variant=\"code\"` only) */\n lang?: string;\n /** Title string shown beside the traffic-light dots (`variant=\"chat\"` only) */\n title?: string;\n /**\n * `\"code\"` (default) — header shows a language badge + filename.\n * `\"chat\"` — header shows traffic-light dots + a title.\n */\n variant?: CodeWindowVariant;\n};\n\n/**\n * A styled window chrome for code blocks and AI/MCP conversation flows.\n *\n * Two variants:\n * - `variant=\"code\"` (default) — language badge + optional filename header.\n * - `variant=\"chat\"` — traffic-light dots + title header.\n *\n * @element ore-code-window\n *\n * @attr {'code'|'chat'} variant - Window style variant\n * @attr {string} lang - Language badge label (variant=\"code\" only)\n * @attr {string} filename - Filename shown next to the badge (variant=\"code\" only)\n * @attr {string} title - Label beside the dots (variant=\"chat\" only)\n *\n * @slot - Main body content (code, conversation turns, or any markup)\n * @slot header-end - Optional content appended to the trailing edge of the header\n *\n * @cssprop --code-window-bg - Window background color\n * @cssprop --code-window-header-bg - Header background color\n * @cssprop --code-window-border-color - Border color\n * @cssprop --code-window-radius - Border radius\n * @cssprop --code-window-shadow - Box shadow\n * @cssprop --code-window-body-padding - Body slot padding\n *\n * @part window - The root window element\n * @part header - The header bar\n * @part lang - The language badge (`variant=\"code\"`)\n * @part filename - The filename label (`variant=\"code\"`)\n * @part dots - The traffic-light dot container (`variant=\"chat\"`)\n * @part title - The title label (`variant=\"chat\"`)\n * @part body - The body container wrapping the default slot\n *\n * @example\n * ```html\n * <ore-code-window lang=\"ts\" filename=\"app.ts\">\n * <pre>const x = 1;</pre>\n * </ore-code-window>\n *\n * <ore-code-window variant=\"chat\" title=\"MCP tool call\">\n * <!-- conversation turns go here -->\n * </ore-code-window>\n * ```\n */\nexport const CODE_WINDOW_TAG = 'ore-code-window' as const;\ndefine<OreCodeWindowProps>(CODE_WINDOW_TAG, {\n props: {\n filename: prop.string(),\n lang: prop.string('ts'),\n title: prop.string('MCP tool call'),\n variant: prop.oneOf(['code', 'chat'] as const, 'code'),\n },\n setup(props) {\n const isCode = computed(() => props.variant.value === 'code');\n const hasFilename = computed(() => Boolean(props.filename.value));\n\n return html`\n <div class=\"window\" part=\"window\">\n <div class=\"header\" part=\"header\">\n ${when(\n isCode,\n () => html`\n <span class=\"lang\" part=\"lang\">${props.lang}</span>\n ${when(hasFilename, () => html`<span class=\"filename\" part=\"filename\">${props.filename}</span>`)}\n `,\n () => html`\n <div class=\"dots\" part=\"dots\" aria-hidden=\"true\"><span></span><span></span><span></span></div>\n <span class=\"title\" part=\"title\">${props.title}</span>\n `,\n )}\n <div class=\"header-spacer\"></div>\n <slot name=\"header-end\"></slot>\n </div>\n <div class=\"body\" part=\"body\">\n <slot></slot>\n </div>\n </div>\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":";;;;AAkEA,IAAa,IAAkB;AAC/B,EAA2B,GAAiB;CAC1C,OAAO;EACL,UAAU,EAAK,OAAO;EACtB,MAAM,EAAK,OAAO,IAAI;EACtB,OAAO,EAAK,OAAO,eAAe;EAClC,SAAS,EAAK,MAAM,CAAC,QAAQ,MAAM,GAAY,MAAM;CACvD;CACA,MAAM,GAAO;EACX,IAAM,IAAS,QAAe,EAAM,QAAQ,UAAU,MAAM,GACtD,IAAc,QAAe,EAAQ,EAAM,SAAS,KAAM;EAEhE,OAAO,CAAI;;;YAGH,EACA,SACM,CAAI;+CACyB,EAAM,KAAK;gBAC1C,EAAK,SAAmB,CAAI,0CAA0C,EAAM,SAAS,QAAQ,EAAE;qBAE7F,CAAI;;iDAE2B,EAAM,MAAM;aAEnD,EAAE;;;;;;;;;CASV;CACA,QAAQ,CAAC,CAAe;AAC1B,CAAC"}
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./_dev.cjs"),n=require("./headless/ore.cjs"),r=require("./headless/nav.cjs"),i=require("./headless/announcer.cjs"),a=require("./keymap/dist/keymap.cjs");require("./keymap/dist/index.cjs");const o=require("./overlay/shared/use-dialog.cjs"),s=require("./overlay/command-palette/command-palette-items.cjs"),c=require("./overlay/command-palette/command-palette.css.cjs");let l=require("@vielzeug/ore"),u=require("@vielzeug/ripple");var d=`ore-command-palette-item`;(0,l.define)(d,{setup(){return l.html``}});var f=`ore-command-palette`;(0,l.define)(f,{props:{"empty-text":l.prop.string(`No results found.`),items:l.prop.data(),"keep-open-on-select":l.prop.bool(!1),label:l.prop.string(`Command palette`),loading:l.prop.bool(!1),"no-filter":l.prop.bool(!1),open:l.prop.bool(!1),placeholder:l.prop.string(`Type a command or search…`),shortcut:l.prop.string(`mod+k`)},setup(e){let c=(0,l.getHost)(),d=(0,l.useEmit)(),f=n.lifecycleSignal(l.onCleanup),p=(0,l.ref)(),m=(0,l.ref)(),h=`cmdk-listbox`,g=null,_=(0,u.signal)(``),v=(0,u.signal)([]),y=()=>{v.value=s.parseSlottedItems([...c.children])};y();let b=new MutationObserver(y);b.observe(c,{characterData:!0,childList:!0,subtree:!0}),(0,l.onCleanup)(()=>b.disconnect());let x=(0,u.computed)(()=>{let t=e.items.value;return Array.isArray(t)?t.map(s.normalizeItem):v.value}),S=(0,u.computed)(()=>s.filterItems(x.value,_.value,!!e[`no-filter`].value)),C=(0,u.computed)(()=>s.buildRows(S.value)),w=r.createListControl({getItems:()=>S.value,isItemDisabled:e=>e.disabled,onNavigate:()=>{g?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},signal:f}),{focusedIndex:T}=w,E=()=>{_.value=``,w.reset()},{closeWithAnimation:D,overlay:O,requestClose:k,setupNativeListeners:A}=o.useDialogControl({dialogRef:p,getPanelEl:()=>p.value?.querySelector(`.panel`),host:c,initialFocus:(0,u.computed)(()=>`.search-input`),isPersistent:()=>!1,onCleanup:l.onCleanup,onEvent:l.onEvent,onNativeClose:e=>{d(`close`,{reason:e}),E()},onOpen:e=>{d(`open`,{reason:e}),w.navigate(`first`)},openProp:e.open,performClose:()=>D(),returnFocus:(0,u.computed)(()=>!0)}),j=a.createKeymap();j.mount(window),(0,l.onCleanup)(()=>j.dispose());let M=null;(0,u.watch)(e.shortcut,e=>{M?.(),M=null;let n=(e??``).trim();if(n)try{M=j.bind(n,()=>{O.toggle(`keyboard`,`trigger`)})}catch(e){t.warn(`invalid "shortcut" value "${n}" — ${e instanceof Error?e.message:String(e)}`)}},{immediate:!0}),(0,l.onMounted)(()=>{A()});function N(t){t.disabled||(d(`select`,{item:t,label:t.label,value:t.value}),e[`keep-open-on-select`].value?m.value?.focus():k(`trigger`))}function P(t){let n=t.target.value;_.value=n,w.navigate(`first`),d(`search`,{query:n});let r=S.value.length;i.announce(r===0?e[`empty-text`].value:`${r} result${r===1?``:`s`} found`)}function F(e){if(!w.handleKeydown(e)&&e.key===`Enter`){let t=w.getActiveItem()??S.value.find(e=>!e.disabled);t&&(e.preventDefault(),N(t))}}return l.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./_dev.cjs"),n=require("./headless/ore.cjs"),r=require("./headless/nav.cjs"),i=require("./headless/announcer.cjs"),a=require("./overlay/shared/use-dialog.cjs"),o=require("./overlay/command-palette/command-palette-items.cjs"),s=require("./overlay/command-palette/command-palette.css.cjs");let c=require("@vielzeug/ore"),l=require("@vielzeug/ripple"),u=require("@vielzeug/keymap");var d=`ore-command-palette-item`;(0,c.define)(d,{setup(){return c.html``}});var f=`ore-command-palette`;(0,c.define)(f,{props:{"empty-text":c.prop.string(`No results found.`),items:c.prop.data(),"keep-open-on-select":c.prop.bool(!1),label:c.prop.string(`Command palette`),loading:c.prop.bool(!1),"no-filter":c.prop.bool(!1),open:c.prop.bool(!1),placeholder:c.prop.string(`Type a command or search…`),shortcut:c.prop.string(`mod+k`)},setup(e){let s=(0,c.getHost)(),d=(0,c.useEmit)(),f=n.lifecycleSignal(c.onCleanup),p=(0,c.ref)(),m=(0,c.ref)(),h=`cmdk-listbox`,g=null,_=(0,l.signal)(``),v=(0,l.signal)([]),y=()=>{v.value=o.parseSlottedItems([...s.children])};y();let b=new MutationObserver(y);b.observe(s,{characterData:!0,childList:!0,subtree:!0}),(0,c.onCleanup)(()=>b.disconnect());let x=(0,l.computed)(()=>{let t=e.items.value;return Array.isArray(t)?t.map(o.normalizeItem):v.value}),S=(0,l.computed)(()=>o.filterItems(x.value,_.value,!!e[`no-filter`].value)),C=(0,l.computed)(()=>o.buildRows(S.value)),w=r.createListControl({getItems:()=>S.value,isItemDisabled:e=>e.disabled,onNavigate:()=>{g?.querySelector(`[data-focused]`)?.scrollIntoView({block:`nearest`})},signal:f}),{focusedIndex:T}=w,E=()=>{_.value=``,w.reset()},{closeWithAnimation:D,overlay:O,requestClose:k,setupNativeListeners:A}=a.useDialogControl({dialogRef:p,getPanelEl:()=>p.value?.querySelector(`.panel`),host:s,initialFocus:(0,l.computed)(()=>`.search-input`),isPersistent:()=>!1,onCleanup:c.onCleanup,onEvent:c.onEvent,onNativeClose:e=>{d(`close`,{reason:e}),E()},onOpen:e=>{d(`open`,{reason:e}),w.navigate(`first`)},openProp:e.open,performClose:()=>D(),returnFocus:(0,l.computed)(()=>!0)}),j=(0,u.createKeymap)();j.mount(window),(0,c.onCleanup)(()=>j.dispose());let M=null;(0,l.watch)(e.shortcut,e=>{M?.(),M=null;let n=(e??``).trim();if(n)try{M=j.bind(n,()=>{O.toggle(`keyboard`,`trigger`)})}catch(e){t.warn(`invalid "shortcut" value "${n}" — ${e instanceof Error?e.message:String(e)}`)}},{immediate:!0}),(0,c.onMounted)(()=>{A()});function N(t){t.disabled||(d(`select`,{item:t,label:t.label,value:t.value}),e[`keep-open-on-select`].value?m.value?.focus():k(`trigger`))}function P(t){let n=t.target.value;_.value=n,w.navigate(`first`),d(`search`,{query:n});let r=S.value.length;i.announce(r===0?e[`empty-text`].value:`${r} result${r===1?``:`s`} found`)}function F(e){if(!w.handleKeydown(e)&&e.key===`Enter`){let t=w.getActiveItem()??S.value.find(e=>!e.disabled);t&&(e.preventDefault(),N(t))}}return c.html`
2
2
  <dialog ref="${p}" class="dialog" part="dialog" aria-label="${e.label}" aria-modal="true">
3
3
  <div class="panel" part="panel">
4
4
  <div class="search" part="search">
@@ -31,7 +31,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
31
31
  <div class="empty" role="presentation" ?hidden="${()=>e.loading.value||C.value.length>0}">
32
32
  ${()=>e[`empty-text`].value}
33
33
  </div>
34
- ${()=>C.value.map(e=>e.type===`group`?l.html`<div class="group-heading" role="presentation">${e.group}</div>`:l.html`<div
34
+ ${()=>C.value.map(e=>e.type===`group`?c.html`<div class="group-heading" role="presentation">${e.group}</div>`:c.html`<div
35
35
  class="item"
36
36
  part="item"
37
37
  role="option"
@@ -42,12 +42,12 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
42
42
  ?data-disabled="${()=>e.item.disabled}"
43
43
  @click="${t=>{t.stopPropagation(),N(e.item)}}"
44
44
  @pointerenter="${()=>{w.set(e.idx)}}">
45
- ${e.item.icon?l.html`<span class="item-icon" aria-hidden="true"
45
+ ${e.item.icon?c.html`<span class="item-icon" aria-hidden="true"
46
46
  ><ore-icon name="${e.item.icon}" size="16"></ore-icon
47
47
  ></span>`:``}
48
48
  <span class="item-label">${e.item.label}</span>
49
- ${e.item.shortcut?l.html`<span class="item-shortcut"
50
- >${s.splitShortcutKeys(e.item.shortcut).map(e=>l.html`<kbd>${e}</kbd>`)}</span
49
+ ${e.item.shortcut?c.html`<span class="item-shortcut"
50
+ >${o.splitShortcutKeys(e.item.shortcut).map(e=>c.html`<kbd>${e}</kbd>`)}</span
51
51
  >`:``}
52
52
  </div>`)}
53
53
  </div>
@@ -58,5 +58,5 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
58
58
  </div>
59
59
  </div>
60
60
  </dialog>
61
- `},styles:[e.reducedMotionMixin,c.default]}),exports.COMMAND_PALETTE_ITEM_TAG=d,exports.COMMAND_PALETTE_TAG=f;
61
+ `},styles:[e.reducedMotionMixin,s.default]}),exports.COMMAND_PALETTE_ITEM_TAG=d,exports.COMMAND_PALETTE_TAG=f;
62
62
  //# sourceMappingURL=command-palette.cjs.map