@upbound/monarch-blocks 0.1.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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/cel-filter-bar.d.ts +187 -0
  4. package/dist/cel-filter-bar.js +1850 -0
  5. package/dist/cel-filter-bar.js.map +1 -0
  6. package/dist/chart.d.ts +52 -0
  7. package/dist/chart.js +332 -0
  8. package/dist/chart.js.map +1 -0
  9. package/dist/chat-interface.d.ts +143 -0
  10. package/dist/chat-interface.js +676 -0
  11. package/dist/chat-interface.js.map +1 -0
  12. package/dist/code-block.d.ts +21 -0
  13. package/dist/code-block.js +201 -0
  14. package/dist/code-block.js.map +1 -0
  15. package/dist/data-table.d.ts +505 -0
  16. package/dist/data-table.js +4725 -0
  17. package/dist/data-table.js.map +1 -0
  18. package/dist/filter-bar.d.ts +80 -0
  19. package/dist/filter-bar.js +590 -0
  20. package/dist/filter-bar.js.map +1 -0
  21. package/dist/floating-widget.d.ts +36 -0
  22. package/dist/floating-widget.js +218 -0
  23. package/dist/floating-widget.js.map +1 -0
  24. package/dist/index.d.ts +18 -0
  25. package/dist/index.js +6217 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/page-header.d.ts +12 -0
  28. package/dist/page-header.js +120 -0
  29. package/dist/page-header.js.map +1 -0
  30. package/dist/relative-time.d.ts +60 -0
  31. package/dist/relative-time.js +328 -0
  32. package/dist/relative-time.js.map +1 -0
  33. package/dist/section-header.d.ts +11 -0
  34. package/dist/section-header.js +123 -0
  35. package/dist/section-header.js.map +1 -0
  36. package/dist/section-nav.d.ts +50 -0
  37. package/dist/section-nav.js +143 -0
  38. package/dist/section-nav.js.map +1 -0
  39. package/dist/timeline.d.ts +8 -0
  40. package/dist/timeline.js +95 -0
  41. package/dist/timeline.js.map +1 -0
  42. package/dist/types-BULiU2qC.d.ts +170 -0
  43. package/package.json +58 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/filter-bar/filter-bar.tsx","../src/lib/utils.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport { type DateRange } from 'react-day-picker';\nimport { Icon } from '@upbound/monarch-core';\n\nimport { cn } from '@/lib/utils';\nimport { Badge } from '@upbound/monarch-core';\nimport { Button } from '@upbound/monarch-core';\nimport { ButtonGroup, ButtonGroupText } from '@upbound/monarch-core';\nimport { Calendar } from '@upbound/monarch-core';\nimport {\n Combobox,\n ComboboxChip,\n ComboboxClearAll,\n ComboboxContent,\n ComboboxEmpty,\n ComboboxInput,\n ComboboxItem,\n ComboboxList,\n ComboboxSelectedChips,\n ComboboxSeparator,\n ComboboxTrigger,\n ComboboxValue,\n} from '@upbound/monarch-core';\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuTrigger,\n} from '@upbound/monarch-core';\nimport { Input } from '@upbound/monarch-core';\nimport { Label } from '@upbound/monarch-core';\nimport { Popover, PopoverContent, PopoverTrigger } from '@upbound/monarch-core';\n\n// ── Types ─────────────────────────────────────────────\n\ntype FilterType = 'checkbox' | 'radio' | 'text' | 'multiText' | 'date';\n\ninterface FilterOption {\n value: string;\n label: string;\n icon?: React.ReactNode;\n}\n\ninterface FilterDefinitionBase {\n key: string;\n label: string;\n}\n\ninterface CheckboxFilterDefinition extends FilterDefinitionBase {\n type?: 'checkbox';\n options: FilterOption[];\n /**\n * When `true`, the chip's value popup becomes a searchable Combobox\n * (multi-select with a search input). Use for long option lists where a\n * basic dropdown becomes hard to scan. When `false` or omitted, the chip\n * uses the standard checkbox dropdown.\n */\n searchable?: boolean;\n}\n\ninterface RadioFilterDefinition extends FilterDefinitionBase {\n type: 'radio';\n options: FilterOption[];\n /** Same searchable-Combobox swap as `CheckboxFilterDefinition`, constrained to a single selection. */\n searchable?: boolean;\n}\n\ninterface TextFilterDefinition extends FilterDefinitionBase {\n type: 'text';\n placeholder?: string;\n}\n\ninterface MultiTextFilterDefinition extends FilterDefinitionBase {\n type: 'multiText';\n placeholder?: string;\n}\n\ninterface DateFilterDefinition extends FilterDefinitionBase {\n type: 'date';\n /**\n * `true` always shows Start/End time inputs, `false` never shows them,\n * and omitted auto-detects from whether the current value already carries\n * a non-midnight time component.\n */\n includeTime?: boolean;\n}\n\ntype FilterDefinition =\n | CheckboxFilterDefinition\n | RadioFilterDefinition\n | TextFilterDefinition\n | MultiTextFilterDefinition\n | DateFilterDefinition;\n\ntype CheckboxFilterValue = string[];\ntype RadioFilterValue = string;\ntype TextFilterValue = string;\ntype MultiTextFilterValue = string[];\ntype DateFilterValue = { startDate: Date | null; endDate: Date | null };\ntype FilterValue = CheckboxFilterValue | RadioFilterValue | TextFilterValue | MultiTextFilterValue | DateFilterValue;\n\ninterface ActiveFilter {\n key: string;\n value?: FilterValue;\n}\n\n// ── Value helpers ─────────────────────────────────────\n\nfunction asCheckboxValue(value: FilterValue | undefined): CheckboxFilterValue {\n return Array.isArray(value) ? value : [];\n}\n\nfunction asRadioValue(value: FilterValue | undefined): RadioFilterValue {\n return typeof value === 'string' ? value : '';\n}\n\nfunction asTextValue(value: FilterValue | undefined): TextFilterValue {\n return typeof value === 'string' ? value : '';\n}\n\nfunction asMultiTextValue(value: FilterValue | undefined): MultiTextFilterValue {\n return Array.isArray(value) ? value : [];\n}\n\nfunction asDateValue(value: FilterValue | undefined): DateFilterValue {\n if (value && typeof value === 'object' && !Array.isArray(value)) return value as DateFilterValue;\n return { startDate: null, endDate: null };\n}\n\nfunction hasExplicitTime(date: Date | null): boolean {\n if (!date) return false;\n return date.getHours() !== 0 || date.getMinutes() !== 0;\n}\n\nfunction formatTimeForInput(date: Date | null): string {\n if (!date) return '';\n return `${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`;\n}\n\nfunction applyTimeToDate(date: Date, time: string): Date {\n const [hours, minutes] = time.split(':').map(Number);\n const next = new Date(date);\n next.setHours(hours || 0, minutes || 0, 0, 0);\n return next;\n}\n\nfunction formatDateLabel(date: Date): string {\n return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n}\n\n// ── FilterBar ─────────────────────────────────────────\n\ninterface FilterBarProps extends React.ComponentProps<'div'> {\n filters: FilterDefinition[];\n activeFilters: ActiveFilter[];\n onAddFilter: (key: string) => void;\n onRemoveFilter: (key: string) => void;\n onChangeFilter: (key: string, value: FilterValue) => void;\n}\n\nfunction FilterBar({\n filters,\n activeFilters,\n onAddFilter,\n onRemoveFilter,\n onChangeFilter,\n className,\n children,\n ...props\n}: FilterBarProps) {\n const usedKeys = new Set(activeFilters.map(f => f.key));\n const availableFilters = filters.filter(f => !usedKeys.has(f.key));\n const shouldShowFilters = availableFilters.length > 0 || activeFilters.length > 0;\n\n // Tracks the most recently added filter so its chip can open its value\n // popup immediately, without waiting for a second click.\n const [pendingOpenKey, setPendingOpenKey] = React.useState<string | null>(null);\n\n function handleAddFilter(key: string) {\n onAddFilter(key);\n setPendingOpenKey(key);\n }\n\n return (\n <div\n data-slot=\"filter-bar\"\n data-visible-filters={shouldShowFilters}\n className={cn('flex flex-wrap items-center gap-2', className)}\n {...props}\n >\n {/* Add filter button */}\n {availableFilters.length > 0 && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\">\n <Icon name=\"plus\" data-icon=\"inline-start\" />\n Add filter\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n align=\"start\"\n className=\"w-48\"\n // Picking a filter here immediately auto-opens its chip's own\n // value popup, which grabs focus for itself (autoFocus input, or\n // the popup's first item). Radix's default close behavior moves\n // focus back to this menu's trigger once its close animation\n // finishes — a hair after the new popup opens in a real browser\n // — which yanks focus out of that popup and, being non-modal,\n // makes it treat that as an outside interaction and dismiss\n // itself. Suppress the auto-return so the new popup keeps focus.\n onCloseAutoFocus={e => e.preventDefault()}\n >\n {availableFilters.map(filter => (\n <DropdownMenuItem key={filter.key} onSelect={() => handleAddFilter(filter.key)}>\n {filter.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n\n {/* Active filter chips */}\n {activeFilters.map(active => {\n const definition = filters.find(f => f.key === active.key);\n if (!definition) return null;\n return (\n <FilterChip\n key={active.key}\n definition={definition}\n value={active.value}\n autoOpen={active.key === pendingOpenKey}\n onChangeValue={value => onChangeFilter(active.key, value)}\n onRemove={() => onRemoveFilter(active.key)}\n />\n );\n })}\n\n {/* Children (count, actions) — sit immediately after the last chip\n with the same `gap-2` spacing. With the parent's `flex-wrap`, a\n long row of chips will push the action onto the next line instead\n of stretching across an empty horizontal void. */}\n {children}\n </div>\n );\n}\n\n// ── FilterChip (dispatcher) ────────────────────────────\n\ninterface FilterChipProps {\n definition: FilterDefinition;\n value: FilterValue | undefined;\n /** Opens the chip's value popup as soon as it mounts — used right after the filter is added. */\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}\n\nfunction FilterChip({ definition, value, autoOpen, onChangeValue, onRemove }: FilterChipProps) {\n const type = definition.type ?? 'checkbox';\n\n switch (type) {\n case 'checkbox':\n return (\n <CheckboxFilterChip\n definition={definition as CheckboxFilterDefinition}\n value={value}\n autoOpen={autoOpen}\n onChangeValue={onChangeValue}\n onRemove={onRemove}\n />\n );\n case 'radio':\n return (\n <RadioFilterChip\n definition={definition as RadioFilterDefinition}\n value={value}\n autoOpen={autoOpen}\n onChangeValue={onChangeValue}\n onRemove={onRemove}\n />\n );\n case 'text':\n return (\n <TextFilterChip\n definition={definition as TextFilterDefinition}\n value={value}\n autoOpen={autoOpen}\n onChangeValue={onChangeValue}\n onRemove={onRemove}\n />\n );\n case 'multiText':\n return (\n <MultiTextFilterChip\n definition={definition as MultiTextFilterDefinition}\n value={value}\n autoOpen={autoOpen}\n onChangeValue={onChangeValue}\n onRemove={onRemove}\n />\n );\n case 'date':\n return (\n <DateFilterChip\n definition={definition as DateFilterDefinition}\n value={value}\n autoOpen={autoOpen}\n onChangeValue={onChangeValue}\n onRemove={onRemove}\n />\n );\n }\n}\n\n// ── Shared chip chrome ─────────────────────────────────\n\nfunction FilterChipRemoveButton({ label, onRemove }: { label: string; onRemove: () => void }) {\n return (\n <Button variant=\"outline\" size=\"icon\" aria-label={`Remove ${label} filter`} onClick={onRemove}>\n <Icon name=\"xmark\" />\n </Button>\n );\n}\n\n// ── Checkbox chip ──────────────────────────────────────\n\nfunction CheckboxFilterChip({\n definition,\n value,\n autoOpen,\n onChangeValue,\n onRemove,\n}: {\n definition: CheckboxFilterDefinition;\n value: FilterValue | undefined;\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}) {\n const { label, options, searchable = false } = definition;\n const values = asCheckboxValue(value);\n const displayLabel =\n values.length === 0\n ? 'Any'\n : values.length === 1\n ? (options.find(o => o.value === values[0])?.label ?? values[0])\n : `${values.length} selected`;\n\n function toggle(optionValue: string) {\n const next = values.includes(optionValue) ? values.filter(v => v !== optionValue) : [...values, optionValue];\n onChangeValue(next);\n }\n\n return (\n <ButtonGroup>\n <ButtonGroupText>{label}</ButtonGroupText>\n {searchable ? (\n <Combobox\n items={options}\n itemToStringValue={(item: FilterOption) => item.label}\n multiple\n defaultOpen={autoOpen}\n value={options.filter(o => values.includes(o.value))}\n onValueChange={(selected: FilterOption[]) => onChangeValue(selected.map(s => s.value))}\n >\n <ComboboxTrigger\n render={<Button variant=\"outline\" className=\"gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)\" />}\n >\n <span className={values.length === 0 ? 'text-muted-foreground' : ''}>{displayLabel}</span>\n </ComboboxTrigger>\n <ComboboxContent className=\"min-w-64\" collisionAvoidance={{ side: 'none', align: 'shift' }}>\n <ComboboxInput showTrigger={false} placeholder={`Search ${label.toLowerCase()}…`} />\n {values.length > 0 && (\n <>\n <ComboboxSelectedChips>\n <ComboboxValue>\n {(selected: FilterOption[]) => (\n <>\n {selected.map(item => (\n <ComboboxChip key={item.value}>{item.label}</ComboboxChip>\n ))}\n </>\n )}\n </ComboboxValue>\n <ComboboxClearAll onClick={() => onChangeValue([])} />\n </ComboboxSelectedChips>\n <ComboboxSeparator />\n </>\n )}\n <ComboboxEmpty>No {label.toLowerCase()} found.</ComboboxEmpty>\n <ComboboxList>\n {(item: FilterOption) => (\n <ComboboxItem key={item.value} value={item}>\n {item.icon}\n {item.label}\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n ) : (\n <DropdownMenu defaultOpen={autoOpen}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" className=\"gap-1 font-normal\">\n <span className={values.length === 0 ? 'text-muted-foreground' : ''}>{displayLabel}</span>\n <Icon name=\"chevron-down\" size=\"sm\" className=\"text-muted-foreground\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n {options.map(opt => (\n <DropdownMenuCheckboxItem\n key={opt.value}\n checked={values.includes(opt.value)}\n onCheckedChange={() => toggle(opt.value)}\n >\n {opt.icon}\n {opt.label}\n </DropdownMenuCheckboxItem>\n ))}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <FilterChipRemoveButton label={label} onRemove={onRemove} />\n </ButtonGroup>\n );\n}\n\n// ── Radio chip ─────────────────────────────────────────\n\nfunction RadioFilterChip({\n definition,\n value,\n autoOpen,\n onChangeValue,\n onRemove,\n}: {\n definition: RadioFilterDefinition;\n value: FilterValue | undefined;\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}) {\n const { label, options, searchable = false } = definition;\n const selectedValue = asRadioValue(value);\n const displayLabel = selectedValue ? (options.find(o => o.value === selectedValue)?.label ?? selectedValue) : 'Any';\n const selected = options.find(o => o.value === selectedValue) ?? null;\n\n return (\n <ButtonGroup>\n <ButtonGroupText>{label}</ButtonGroupText>\n {searchable ? (\n <Combobox\n items={options}\n itemToStringValue={(item: FilterOption) => item.label}\n defaultOpen={autoOpen}\n value={selected}\n onValueChange={(next: FilterOption | null) => onChangeValue(next?.value ?? '')}\n >\n <ComboboxTrigger\n render={<Button variant=\"outline\" className=\"gap-1 font-normal [&>svg:last-child]:size-(--icon-sm)\" />}\n >\n <span className={selectedValue ? '' : 'text-muted-foreground'}>{displayLabel}</span>\n </ComboboxTrigger>\n <ComboboxContent className=\"min-w-64\" collisionAvoidance={{ side: 'none', align: 'shift' }}>\n <ComboboxInput showTrigger={false} placeholder={`Search ${label.toLowerCase()}…`} />\n <ComboboxEmpty>No {label.toLowerCase()} found.</ComboboxEmpty>\n <ComboboxList>\n {(item: FilterOption) => (\n <ComboboxItem key={item.value} value={item}>\n {item.icon}\n {item.label}\n </ComboboxItem>\n )}\n </ComboboxList>\n </ComboboxContent>\n </Combobox>\n ) : (\n <DropdownMenu defaultOpen={autoOpen}>\n <DropdownMenuTrigger asChild>\n <Button variant=\"outline\" className=\"gap-1 font-normal\">\n <span className={selectedValue ? '' : 'text-muted-foreground'}>{displayLabel}</span>\n <Icon name=\"chevron-down\" size=\"sm\" className=\"text-muted-foreground\" />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"w-48\">\n <DropdownMenuRadioGroup value={selectedValue} onValueChange={onChangeValue}>\n {options.map(opt => (\n <DropdownMenuRadioItem key={opt.value} value={opt.value}>\n {opt.icon}\n {opt.label}\n </DropdownMenuRadioItem>\n ))}\n </DropdownMenuRadioGroup>\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n <FilterChipRemoveButton label={label} onRemove={onRemove} />\n </ButtonGroup>\n );\n}\n\n// ── Text chip ──────────────────────────────────────────\n\nfunction TextFilterChip({\n definition,\n value,\n autoOpen,\n onChangeValue,\n onRemove,\n}: {\n definition: TextFilterDefinition;\n value: FilterValue | undefined;\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}) {\n const { label, placeholder } = definition;\n const text = asTextValue(value);\n const [open, setOpen] = React.useState(!!autoOpen);\n\n return (\n <ButtonGroup>\n <ButtonGroupText>{label}</ButtonGroupText>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className=\"gap-1 font-normal\">\n <span className={text ? '' : 'text-muted-foreground'}>{text || 'Any'}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\">\n <Input\n autoFocus\n value={text}\n placeholder={placeholder ?? 'Enter a value…'}\n onChange={e => onChangeValue(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') setOpen(false);\n }}\n />\n </PopoverContent>\n </Popover>\n <FilterChipRemoveButton label={label} onRemove={onRemove} />\n </ButtonGroup>\n );\n}\n\n// ── MultiText chip ─────────────────────────────────────\n\nfunction MultiTextFilterChip({\n definition,\n value,\n autoOpen,\n onChangeValue,\n onRemove,\n}: {\n definition: MultiTextFilterDefinition;\n value: FilterValue | undefined;\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}) {\n const { label, placeholder } = definition;\n const tokens = asMultiTextValue(value);\n const [draft, setDraft] = React.useState('');\n const displayLabel = tokens.length === 0 ? 'Any' : tokens.length === 1 ? tokens[0] : `${tokens.length} values`;\n\n function addToken() {\n const token = draft.trim();\n if (!token || tokens.includes(token)) {\n setDraft('');\n return;\n }\n onChangeValue([...tokens, token]);\n setDraft('');\n }\n\n function removeToken(token: string) {\n onChangeValue(tokens.filter(t => t !== token));\n }\n\n return (\n <ButtonGroup>\n <ButtonGroupText>{label}</ButtonGroupText>\n <Popover defaultOpen={autoOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className=\"gap-1 font-normal\">\n <span className={tokens.length === 0 ? 'text-muted-foreground' : ''}>{displayLabel}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\">\n <div className=\"flex flex-col gap-2\">\n {tokens.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {tokens.map(token => (\n <Badge key={token} variant=\"secondary\" className=\"gap-1\">\n {token}\n <button\n type=\"button\"\n aria-label={`Remove ${token}`}\n onClick={() => removeToken(token)}\n className=\"cursor-pointer\"\n >\n <Icon name=\"xmark\" size=\"xs\" />\n </button>\n </Badge>\n ))}\n </div>\n )}\n <Input\n autoFocus\n value={draft}\n placeholder={placeholder ?? 'Type a value, press Enter…'}\n onChange={e => setDraft(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.preventDefault();\n addToken();\n } else if (e.key === 'Backspace' && draft === '' && tokens.length > 0) {\n removeToken(tokens[tokens.length - 1]);\n }\n }}\n />\n </div>\n </PopoverContent>\n </Popover>\n <FilterChipRemoveButton label={label} onRemove={onRemove} />\n </ButtonGroup>\n );\n}\n\n// ── Date chip ──────────────────────────────────────────\n\nfunction DateFilterChip({\n definition,\n value,\n autoOpen,\n onChangeValue,\n onRemove,\n}: {\n definition: DateFilterDefinition;\n value: FilterValue | undefined;\n autoOpen?: boolean;\n onChangeValue: (value: FilterValue) => void;\n onRemove: () => void;\n}) {\n const { label, includeTime } = definition;\n const { startDate, endDate } = asDateValue(value);\n const showTimeInputs = includeTime ?? (hasExplicitTime(startDate) || hasExplicitTime(endDate));\n\n const displayLabel = !startDate\n ? 'Any'\n : !endDate || startDate.getTime() === endDate.getTime()\n ? formatDateLabel(startDate)\n : `${formatDateLabel(startDate)} – ${formatDateLabel(endDate)}`;\n\n function pickRange(range: DateRange | undefined) {\n if (!range?.from) {\n onChangeValue({ startDate: null, endDate: null });\n return;\n }\n onChangeValue({ startDate: range.from, endDate: range.to ?? range.from });\n }\n\n function pickStartTime(time: string) {\n if (!startDate) return;\n onChangeValue({ startDate: applyTimeToDate(startDate, time), endDate });\n }\n\n function pickEndTime(time: string) {\n if (!endDate) return;\n onChangeValue({ startDate, endDate: applyTimeToDate(endDate, time) });\n }\n\n return (\n <ButtonGroup>\n <ButtonGroupText>{label}</ButtonGroupText>\n <Popover defaultOpen={autoOpen}>\n <PopoverTrigger asChild>\n <Button variant=\"outline\" className=\"gap-1 font-normal\">\n <span className={startDate ? '' : 'text-muted-foreground'}>{displayLabel}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-fit\">\n <div className=\"flex flex-col gap-2\">\n <Calendar\n mode=\"range\"\n selected={{ from: startDate ?? undefined, to: endDate ?? undefined }}\n onSelect={pickRange}\n />\n {showTimeInputs && (\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex w-full items-center gap-2\">\n <Label\n htmlFor={`${definition.key}-start-time`}\n className=\"text-body-sm text-muted-foreground w-10 shrink-0\"\n >\n Start\n </Label>\n <Input\n id={`${definition.key}-start-time`}\n type=\"time\"\n className=\"w-full\"\n value={formatTimeForInput(startDate)}\n onChange={e => pickStartTime(e.target.value)}\n disabled={!startDate}\n />\n </div>\n <div className=\"flex w-full items-center gap-2\">\n <Label\n htmlFor={`${definition.key}-end-time`}\n className=\"text-body-sm text-muted-foreground w-10 shrink-0\"\n >\n End\n </Label>\n <Input\n id={`${definition.key}-end-time`}\n type=\"time\"\n className=\"w-full\"\n value={formatTimeForInput(endDate)}\n onChange={e => pickEndTime(e.target.value)}\n disabled={!endDate}\n />\n </div>\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n <FilterChipRemoveButton label={label} onRemove={onRemove} />\n </ButtonGroup>\n );\n}\n\nexport {\n FilterBar,\n FilterChip,\n type FilterType,\n type FilterDefinition,\n type CheckboxFilterDefinition,\n type RadioFilterDefinition,\n type TextFilterDefinition,\n type MultiTextFilterDefinition,\n type DateFilterDefinition,\n type ActiveFilter,\n type FilterOption,\n type FilterValue,\n type CheckboxFilterValue,\n type RadioFilterValue,\n type TextFilterValue,\n type MultiTextFilterValue,\n type DateFilterValue,\n type FilterBarProps,\n};\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":"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","names":["_a"]}
@@ -0,0 +1,36 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import * as React from 'react';
3
+
4
+ type FloatingWidgetState = {
5
+ isOpen: boolean;
6
+ isCollapsed: boolean;
7
+ isExpanded: boolean;
8
+ open: () => void;
9
+ close: () => void;
10
+ toggle: () => void;
11
+ collapse: () => void;
12
+ restore: () => void;
13
+ expand: () => void;
14
+ shrink: () => void;
15
+ toggleExpand: () => void;
16
+ };
17
+ declare function FloatingWidgetProvider({ children }: {
18
+ children: React.ReactNode;
19
+ }): react_jsx_runtime.JSX.Element;
20
+ declare function useFloatingWidget(): FloatingWidgetState;
21
+ interface FloatingWidgetProps {
22
+ /** Title shown in the header bar. */
23
+ title?: string;
24
+ /** Optional single-line subtitle rendered under the title. When present the
25
+ * header expands vertically to make room; when absent the header stays on
26
+ * its default single-line height. */
27
+ subtitle?: string;
28
+ /** Optional menu items rendered in the `···` kebab dropdown. */
29
+ menuItems?: React.ReactNode;
30
+ /** Body content — typically a `ChatThread` for AI chat, but any surface fits. */
31
+ children?: React.ReactNode;
32
+ className?: string;
33
+ }
34
+ declare function FloatingWidget({ title, subtitle, menuItems, children, className }: FloatingWidgetProps): react_jsx_runtime.JSX.Element | null;
35
+
36
+ export { FloatingWidget, FloatingWidgetProvider, useFloatingWidget };
@@ -0,0 +1,218 @@
1
+ "use client";
2
+
3
+ // src/floating-widget.tsx
4
+ import * as React from "react";
5
+
6
+ // src/lib/utils.ts
7
+ import { clsx } from "clsx";
8
+ import { extendTailwindMerge } from "tailwind-merge";
9
+ var twMerge = extendTailwindMerge({
10
+ extend: {
11
+ classGroups: {
12
+ "font-size": [
13
+ {
14
+ text: [
15
+ "display-hero",
16
+ "display-kpi-sm",
17
+ "display-kpi",
18
+ "display-kpi-lg",
19
+ "display-feature",
20
+ "h1",
21
+ "h2",
22
+ "h3",
23
+ "h4",
24
+ "body-lg",
25
+ "body",
26
+ "body-sm",
27
+ "caption",
28
+ "eyebrow"
29
+ ]
30
+ }
31
+ ]
32
+ }
33
+ }
34
+ });
35
+ function cn(...inputs) {
36
+ return twMerge(clsx(inputs));
37
+ }
38
+
39
+ // src/floating-widget.tsx
40
+ import { Button } from "@upbound/monarch-core";
41
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from "@upbound/monarch-core";
42
+ import { Icon } from "@upbound/monarch-core";
43
+ import { Kbd } from "@upbound/monarch-core";
44
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@upbound/monarch-core";
45
+ import { jsx, jsxs } from "react/jsx-runtime";
46
+ var FloatingWidgetContext = React.createContext(null);
47
+ function FloatingWidgetProvider({ children }) {
48
+ const [isOpen, setIsOpen] = React.useState(false);
49
+ const [isCollapsed, setIsCollapsed] = React.useState(false);
50
+ const [isExpanded, setIsExpanded] = React.useState(false);
51
+ const value = React.useMemo(
52
+ () => ({
53
+ isOpen,
54
+ isCollapsed,
55
+ isExpanded,
56
+ open: () => {
57
+ setIsOpen(true);
58
+ setIsCollapsed(false);
59
+ },
60
+ close: () => {
61
+ setIsOpen(false);
62
+ setIsCollapsed(false);
63
+ setIsExpanded(false);
64
+ },
65
+ toggle: () => {
66
+ setIsOpen((prev) => !prev);
67
+ setIsCollapsed(false);
68
+ },
69
+ collapse: () => setIsCollapsed(true),
70
+ restore: () => setIsCollapsed(false),
71
+ expand: () => {
72
+ setIsExpanded(true);
73
+ setIsCollapsed(false);
74
+ },
75
+ shrink: () => setIsExpanded(false),
76
+ toggleExpand: () => {
77
+ setIsExpanded((prev) => !prev);
78
+ setIsCollapsed(false);
79
+ }
80
+ }),
81
+ [isOpen, isCollapsed, isExpanded]
82
+ );
83
+ return /* @__PURE__ */ jsx(FloatingWidgetContext.Provider, { value, children });
84
+ }
85
+ function useFloatingWidget() {
86
+ const ctx = React.useContext(FloatingWidgetContext);
87
+ if (!ctx) {
88
+ throw new Error("useFloatingWidget must be used inside <FloatingWidgetProvider>.");
89
+ }
90
+ return ctx;
91
+ }
92
+ function FloatingWidget({ title = "Ask AI", subtitle, menuItems, children, className }) {
93
+ const { isOpen, isCollapsed, isExpanded, close, collapse, restore, toggleExpand } = useFloatingWidget();
94
+ const [dragWidth, setDragWidth] = React.useState(null);
95
+ const [isDragging, setIsDragging] = React.useState(false);
96
+ React.useEffect(() => {
97
+ setDragWidth(null);
98
+ }, [isExpanded]);
99
+ const MIN_WIDTH = 420;
100
+ const widgetRef = React.useRef(null);
101
+ const handleResizeMouseDown = React.useCallback((e) => {
102
+ var _a, _b;
103
+ e.preventDefault();
104
+ setIsDragging(true);
105
+ const startX = e.clientX;
106
+ const startWidth = (_b = (_a = widgetRef.current) == null ? void 0 : _a.getBoundingClientRect().width) != null ? _b : MIN_WIDTH;
107
+ const maxWidth = window.innerWidth - 32;
108
+ function onMove(moveEvent) {
109
+ moveEvent.preventDefault();
110
+ const next = Math.max(MIN_WIDTH, Math.min(maxWidth, startWidth + (startX - moveEvent.clientX)));
111
+ setDragWidth(next);
112
+ }
113
+ function onUp() {
114
+ window.removeEventListener("mousemove", onMove);
115
+ window.removeEventListener("mouseup", onUp);
116
+ setIsDragging(false);
117
+ }
118
+ window.addEventListener("mousemove", onMove);
119
+ window.addEventListener("mouseup", onUp);
120
+ }, []);
121
+ React.useEffect(() => {
122
+ if (!isOpen) return;
123
+ function handleKeydown(e) {
124
+ if (e.key === "Escape") {
125
+ close();
126
+ }
127
+ }
128
+ document.addEventListener("keydown", handleKeydown);
129
+ return () => document.removeEventListener("keydown", handleKeydown);
130
+ }, [isOpen, close]);
131
+ if (!isOpen) return null;
132
+ const dragStyle = dragWidth != null && !isCollapsed ? { width: `${dragWidth}px`, minWidth: `${MIN_WIDTH}px` } : void 0;
133
+ return /* @__PURE__ */ jsxs(
134
+ "div",
135
+ {
136
+ ref: widgetRef,
137
+ role: "dialog",
138
+ "aria-modal": "false",
139
+ "aria-label": title,
140
+ style: dragStyle,
141
+ className: cn(
142
+ // Position: bottom-right anchor with viewport padding; fullscreen on mobile
143
+ "bg-background fixed inset-x-0 top-0 bottom-0 z-50 flex flex-col shadow-xl",
144
+ // Kill text selection app-wide (bubbles up via body handler? No — we
145
+ // apply it locally to the widget; the drag handler stops propagation
146
+ // via preventDefault which prevents the browser from initiating
147
+ // selection while the pointer moves.
148
+ isDragging && "select-none",
149
+ // `overflow-hidden` clips children to the rounded corners so the chat
150
+ // input's edges don't square off the bottom of the widget.
151
+ "sm:inset-x-auto sm:top-auto sm:right-4 sm:bottom-4 sm:overflow-hidden sm:rounded-xl sm:border",
152
+ // Size: open = full panel; collapsed = title-bar sliver; expanded = larger panel
153
+ isCollapsed ? "sm:h-auto sm:w-80" : isExpanded ? "sm:h-[calc(100vh-2rem)] sm:w-[720px]" : "sm:h-[640px] sm:max-h-[calc(100vh-2rem)] sm:w-[420px]",
154
+ className
155
+ ),
156
+ children: [
157
+ !isCollapsed && /* @__PURE__ */ jsxs(Tooltip, { children: [
158
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
159
+ "div",
160
+ {
161
+ role: "separator",
162
+ "aria-orientation": "vertical",
163
+ "aria-label": "Resize widget",
164
+ onMouseDown: handleResizeMouseDown,
165
+ className: "group absolute inset-y-0 left-0 z-20 hidden w-3 cursor-col-resize touch-none items-center justify-center bg-transparent select-none sm:flex",
166
+ children: /* @__PURE__ */ jsx("div", { className: "bg-border h-12 w-1 shrink-0 rounded-lg opacity-0 transition-opacity duration-150 group-hover:opacity-100" })
167
+ }
168
+ ) }),
169
+ /* @__PURE__ */ jsx(TooltipContent, { side: "left", children: "Resize" })
170
+ ] }),
171
+ /* @__PURE__ */ jsxs("header", { className: "flex min-h-12 shrink-0 items-center gap-1 border-b px-3 py-2", children: [
172
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-1 flex-col justify-center", children: [
173
+ /* @__PURE__ */ jsx("span", { className: "text-body truncate font-medium", children: title }),
174
+ subtitle && /* @__PURE__ */ jsx("span", { className: "text-body-sm text-muted-foreground truncate", children: subtitle })
175
+ ] }),
176
+ menuItems && !isCollapsed && /* @__PURE__ */ jsxs(Tooltip, { children: [
177
+ /* @__PURE__ */ jsxs(DropdownMenu, { children: [
178
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "More options", children: /* @__PURE__ */ jsx(Icon, { name: "ellipsis-vertical" }) }) }) }),
179
+ /* @__PURE__ */ jsx(DropdownMenuContent, { align: "end", children: menuItems })
180
+ ] }),
181
+ /* @__PURE__ */ jsx(TooltipContent, { children: "More options" })
182
+ ] }),
183
+ !isCollapsed && /* @__PURE__ */ jsxs(Tooltip, { children: [
184
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
185
+ Button,
186
+ {
187
+ variant: "ghost",
188
+ size: "icon-sm",
189
+ onClick: toggleExpand,
190
+ "aria-label": isExpanded ? "Shrink widget" : "Expand widget",
191
+ children: /* @__PURE__ */ jsx(Icon, { name: isExpanded ? "shrink" : "arrow-up-right-and-arrow-down-left-from-center" })
192
+ }
193
+ ) }),
194
+ /* @__PURE__ */ jsx(TooltipContent, { children: isExpanded ? "Shrink widget" : "Expand widget" })
195
+ ] }),
196
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
197
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: isCollapsed ? /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: restore, "aria-label": "Restore widget", children: /* @__PURE__ */ jsx(Icon, { name: "window-maximize" }) }) : /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: collapse, "aria-label": "Minimize widget", children: /* @__PURE__ */ jsx(Icon, { name: "minus" }) }) }),
198
+ /* @__PURE__ */ jsx(TooltipContent, { children: isCollapsed ? "Restore widget" : "Minimize widget" })
199
+ ] }),
200
+ /* @__PURE__ */ jsxs(Tooltip, { children: [
201
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "ghost", size: "icon-sm", onClick: close, "aria-label": "Close widget", children: /* @__PURE__ */ jsx(Icon, { name: "xmark" }) }) }),
202
+ /* @__PURE__ */ jsxs(TooltipContent, { children: [
203
+ "Close widget",
204
+ /* @__PURE__ */ jsx(Kbd, { children: "Esc" })
205
+ ] })
206
+ ] })
207
+ ] }),
208
+ !isCollapsed && /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children })
209
+ ]
210
+ }
211
+ );
212
+ }
213
+ export {
214
+ FloatingWidget,
215
+ FloatingWidgetProvider,
216
+ useFloatingWidget
217
+ };
218
+ //# sourceMappingURL=floating-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/floating-widget.tsx","../src/lib/utils.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\n\nimport { cn } from '@/lib/utils';\nimport { Button } from '@upbound/monarch-core';\nimport { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger } from '@upbound/monarch-core';\nimport { Icon } from '@upbound/monarch-core';\nimport { Kbd } from '@upbound/monarch-core';\nimport { Tooltip, TooltipContent, TooltipTrigger } from '@upbound/monarch-core';\n\n// ---------------------------------------------------------------------------\n// Context — global open/collapsed state\n// ---------------------------------------------------------------------------\n//\n// `FloatingWidget` is a singleton — one instance per app, mounted at the root\n// layout. Any consumer (e.g. a button in the header) calls `useFloatingWidget()`\n// to toggle it. State is in-memory only for now; can be promoted to storage\n// later without changing the consumer API.\n\ntype FloatingWidgetState = {\n isOpen: boolean;\n isCollapsed: boolean;\n isExpanded: boolean;\n open: () => void;\n close: () => void;\n toggle: () => void;\n collapse: () => void;\n restore: () => void;\n expand: () => void;\n shrink: () => void;\n toggleExpand: () => void;\n};\n\nconst FloatingWidgetContext = React.createContext<FloatingWidgetState | null>(null);\n\nexport function FloatingWidgetProvider({ children }: { children: React.ReactNode }) {\n const [isOpen, setIsOpen] = React.useState(false);\n const [isCollapsed, setIsCollapsed] = React.useState(false);\n const [isExpanded, setIsExpanded] = React.useState(false);\n\n const value = React.useMemo<FloatingWidgetState>(\n () => ({\n isOpen,\n isCollapsed,\n isExpanded,\n open: () => {\n setIsOpen(true);\n setIsCollapsed(false);\n },\n close: () => {\n setIsOpen(false);\n setIsCollapsed(false);\n setIsExpanded(false);\n },\n toggle: () => {\n setIsOpen(prev => !prev);\n setIsCollapsed(false);\n },\n collapse: () => setIsCollapsed(true),\n restore: () => setIsCollapsed(false),\n expand: () => {\n setIsExpanded(true);\n setIsCollapsed(false);\n },\n shrink: () => setIsExpanded(false),\n toggleExpand: () => {\n setIsExpanded(prev => !prev);\n setIsCollapsed(false);\n },\n }),\n [isOpen, isCollapsed, isExpanded],\n );\n\n return <FloatingWidgetContext.Provider value={value}>{children}</FloatingWidgetContext.Provider>;\n}\n\nexport function useFloatingWidget() {\n const ctx = React.useContext(FloatingWidgetContext);\n if (!ctx) {\n throw new Error('useFloatingWidget must be used inside <FloatingWidgetProvider>.');\n }\n return ctx;\n}\n\n// ---------------------------------------------------------------------------\n// FloatingWidget — the surface\n// ---------------------------------------------------------------------------\n//\n// A persistent, modeless floating panel anchored to the bottom-right of the\n// viewport. Two visible states:\n// - **open**: full panel (~420×640 desktop, fullscreen on mobile)\n// - **collapsed**: toast-sized sliver showing just the title bar\n// When `isOpen` is false the widget is unmounted entirely.\n//\n// `FloatingWidget` doesn't prescribe the body content — chat, help, or\n// notification surfaces all drop in via `children`. Caller is responsible for\n// the body's internal layout (e.g. wrapping in `ChatThread`).\n\ninterface FloatingWidgetProps {\n /** Title shown in the header bar. */\n title?: string;\n /** Optional single-line subtitle rendered under the title. When present the\n * header expands vertically to make room; when absent the header stays on\n * its default single-line height. */\n subtitle?: string;\n /** Optional menu items rendered in the `···` kebab dropdown. */\n menuItems?: React.ReactNode;\n /** Body content — typically a `ChatThread` for AI chat, but any surface fits. */\n children?: React.ReactNode;\n className?: string;\n}\n\nexport function FloatingWidget({ title = 'Ask AI', subtitle, menuItems, children, className }: FloatingWidgetProps) {\n const { isOpen, isCollapsed, isExpanded, close, collapse, restore, toggleExpand } = useFloatingWidget();\n\n // User-dragged custom width. When set, overrides the compact/expanded\n // widths. Reset whenever isExpanded toggles (button-driven size change =\n // user intent shift back to preset sizes).\n const [dragWidth, setDragWidth] = React.useState<number | null>(null);\n const [isDragging, setIsDragging] = React.useState(false);\n React.useEffect(() => {\n setDragWidth(null);\n }, [isExpanded]);\n\n const MIN_WIDTH = 420;\n const widgetRef = React.useRef<HTMLDivElement | null>(null);\n\n // Drag-to-resize handler bound as a React prop on the handle. Uses window\n // listeners during the drag so the pointer stream continues when the cursor\n // leaves the thin handle strip; `preventDefault` on mousedown suppresses\n // text-selection. Bound as a React handler (not native addEventListener) so\n // that Radix's Slot merges it with `TooltipTrigger`'s own listeners cleanly.\n const handleResizeMouseDown = React.useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n e.preventDefault();\n setIsDragging(true);\n const startX = e.clientX;\n const startWidth = widgetRef.current?.getBoundingClientRect().width ?? MIN_WIDTH;\n const maxWidth = window.innerWidth - 32;\n\n function onMove(moveEvent: MouseEvent) {\n moveEvent.preventDefault();\n const next = Math.max(MIN_WIDTH, Math.min(maxWidth, startWidth + (startX - moveEvent.clientX)));\n setDragWidth(next);\n }\n function onUp() {\n window.removeEventListener('mousemove', onMove);\n window.removeEventListener('mouseup', onUp);\n setIsDragging(false);\n }\n window.addEventListener('mousemove', onMove);\n window.addEventListener('mouseup', onUp);\n }, []);\n\n // Esc closes the widget when open. Matches the Esc kbd hint shown in the\n // close button's tooltip. Listener only attached while open.\n React.useEffect(() => {\n if (!isOpen) return;\n function handleKeydown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n close();\n }\n }\n document.addEventListener('keydown', handleKeydown);\n return () => document.removeEventListener('keydown', handleKeydown);\n }, [isOpen, close]);\n\n if (!isOpen) return null;\n\n // Custom drag width takes precedence over compact/expanded class-based\n // widths. Only applies to the ≥sm layout; mobile stays fullscreen via\n // inset-x-0. The min-width guard mirrors MIN_WIDTH so any browser resize\n // that shrinks viewport below the current drag width doesn't visually clip.\n const dragStyle: React.CSSProperties | undefined =\n dragWidth != null && !isCollapsed ? { width: `${dragWidth}px`, minWidth: `${MIN_WIDTH}px` } : undefined;\n\n return (\n <div\n ref={widgetRef}\n role=\"dialog\"\n aria-modal=\"false\"\n aria-label={title}\n style={dragStyle}\n className={cn(\n // Position: bottom-right anchor with viewport padding; fullscreen on mobile\n 'bg-background fixed inset-x-0 top-0 bottom-0 z-50 flex flex-col shadow-xl',\n // Kill text selection app-wide (bubbles up via body handler? No — we\n // apply it locally to the widget; the drag handler stops propagation\n // via preventDefault which prevents the browser from initiating\n // selection while the pointer moves.\n isDragging && 'select-none',\n // `overflow-hidden` clips children to the rounded corners so the chat\n // input's edges don't square off the bottom of the widget.\n 'sm:inset-x-auto sm:top-auto sm:right-4 sm:bottom-4 sm:overflow-hidden sm:rounded-xl sm:border',\n // Size: open = full panel; collapsed = title-bar sliver; expanded = larger panel\n isCollapsed\n ? 'sm:h-auto sm:w-80'\n : isExpanded\n ? 'sm:h-[calc(100vh-2rem)] sm:w-[720px]'\n : 'sm:h-[640px] sm:max-h-[calc(100vh-2rem)] sm:w-[420px]',\n className,\n )}\n >\n {/* Resize handle — 12px hit area with a hover-revealed centered\n vertical bar. Bar sits at 48px tall (twice the Resizable primitive's\n `h-6`, per this surface's larger scale) and fades in on hover so\n the affordance stays visually calm until the user aims for it. */}\n {!isCollapsed && (\n <Tooltip>\n <TooltipTrigger asChild>\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label=\"Resize widget\"\n onMouseDown={handleResizeMouseDown}\n className=\"group absolute inset-y-0 left-0 z-20 hidden w-3 cursor-col-resize touch-none items-center justify-center bg-transparent select-none sm:flex\"\n >\n <div className=\"bg-border h-12 w-1 shrink-0 rounded-lg opacity-0 transition-opacity duration-150 group-hover:opacity-100\" />\n </div>\n </TooltipTrigger>\n <TooltipContent side=\"left\">Resize</TooltipContent>\n </Tooltip>\n )}\n\n {/* Header — always visible. Provides title + optional subtitle + window\n controls. When `subtitle` is passed, the title/subtitle stack occupies\n two lines; otherwise the header keeps its default single-line\n rhythm. */}\n <header className=\"flex min-h-12 shrink-0 items-center gap-1 border-b px-3 py-2\">\n <div className=\"flex min-w-0 flex-1 flex-col justify-center\">\n <span className=\"text-body truncate font-medium\">{title}</span>\n {subtitle && <span className=\"text-body-sm text-muted-foreground truncate\">{subtitle}</span>}\n </div>\n\n {/* Kebab — extra actions; only rendered when menuItems are provided */}\n {menuItems && !isCollapsed && (\n <Tooltip>\n <DropdownMenu>\n <TooltipTrigger asChild>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"More options\">\n <Icon name=\"ellipsis-vertical\" />\n </Button>\n </DropdownMenuTrigger>\n </TooltipTrigger>\n <DropdownMenuContent align=\"end\">{menuItems}</DropdownMenuContent>\n </DropdownMenu>\n <TooltipContent>More options</TooltipContent>\n </Tooltip>\n )}\n\n {/* Expand / Shrink — toggles the widget between compact (420×640) and\n expanded (720 × viewport height). Placed before Minimize so window-\n management controls (minimize → close) sit together on the trailing\n edge, matching macOS/Windows traffic-light ordering. */}\n {!isCollapsed && (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n variant=\"ghost\"\n size=\"icon-sm\"\n onClick={toggleExpand}\n aria-label={isExpanded ? 'Shrink widget' : 'Expand widget'}\n >\n <Icon name={isExpanded ? 'shrink' : 'arrow-up-right-and-arrow-down-left-from-center'} />\n </Button>\n </TooltipTrigger>\n <TooltipContent>{isExpanded ? 'Shrink widget' : 'Expand widget'}</TooltipContent>\n </Tooltip>\n )}\n\n {/* Minimize / Restore — paired next to Close for a conventional\n \"minimize | close\" window-controls grouping. */}\n <Tooltip>\n <TooltipTrigger asChild>\n {isCollapsed ? (\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={restore} aria-label=\"Restore widget\">\n <Icon name=\"window-maximize\" />\n </Button>\n ) : (\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={collapse} aria-label=\"Minimize widget\">\n <Icon name=\"minus\" />\n </Button>\n )}\n </TooltipTrigger>\n <TooltipContent>{isCollapsed ? 'Restore widget' : 'Minimize widget'}</TooltipContent>\n </Tooltip>\n\n {/* Close — Esc keyboard shortcut wired via the keydown handler above */}\n <Tooltip>\n <TooltipTrigger asChild>\n <Button variant=\"ghost\" size=\"icon-sm\" onClick={close} aria-label=\"Close widget\">\n <Icon name=\"xmark\" />\n </Button>\n </TooltipTrigger>\n <TooltipContent>\n Close widget\n <Kbd>Esc</Kbd>\n </TooltipContent>\n </Tooltip>\n </header>\n\n {/* Body — hidden when collapsed; consumer-provided content otherwise */}\n {!isCollapsed && <div className=\"flex min-h-0 flex-1 flex-col\">{children}</div>}\n </div>\n );\n}\n","import { clsx, type ClassValue } from 'clsx';\nimport { extendTailwindMerge } from 'tailwind-merge';\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n 'font-size': [\n {\n text: [\n 'display-hero',\n 'display-kpi-sm',\n 'display-kpi',\n 'display-kpi-lg',\n 'display-feature',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'body-lg',\n 'body',\n 'body-sm',\n 'caption',\n 'eyebrow',\n ],\n },\n ],\n },\n },\n});\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,18 @@
1
+ export { CelFilterBar, RELATIVE_DURATION_PRESET_VALUES, allowsMultipleConditions, appendCondition, applyDisplayRules, applyOperatorChange, calendarDayStartInstant, celStringLiteral, compileCelFilterTree, computeIsEmitReady, createCelNodeId, createDefaultCondition, createEmptyCelFilterTree, dateBoundaryForOperator, denormalizeColumnIdWithReservedNames, escapeCelString, formatCalendarDateUtc, formatInstantLabel, getAllowedOperators, getColumnEmitOn, getDefaultOperator, getOperatorLabel, getQuantifierLabel, isDateRangeOperator, isDateRelativeOperator, isDateWindowOperator, isMultiTextColumn, isRealCalendarDay, isRelativeDateCelValue, isRelativeDurationPreset, mergeContextualIntoCelTree, parseCalendarDate, readDateCelValue, readMapKeyCelValue, readMultiTextCelValue, readTimeOfDay, removeConditionById, replaceCondition, resolveColumnDefinition, resolveFilterShape, validateCondition, withTimeOfDay } from './cel-filter-bar.js';
2
+ export { C as CelColumnDefinition, a as CelColumnOption, b as CelConditionValue, c as CelFilterBarProps, d as CelFilterCondition, e as CelFilterGroup, f as CelFilterSchema, g as CelFilterTree, h as CelOperator, i as CelRestrictedOptionSelectPayload, j as CheckboxCelValue, k as CompileResult, D as DateCelValue, M as MapKeyCelValue, l as MultiTextCelValue, P as PillActiveSurface, R as RadioCelValue, m as RelativeDurationPreset, V as ValidationIssue, n as isCelFilterCondition, o as isCelFilterGroup, p as isCheckboxCelValue, q as isDateCelValue, r as isMapKeyCelValue, s as isMultiTextCelValue } from './types-BULiU2qC.js';
3
+ export { ChartAction, ChartConfig, ChartContainer, ChartDescription, ChartFooter, ChartHeader, ChartLegend, ChartLegendContent, ChartStyle, ChartTitle, ChartTooltip, ChartTooltipContent } from './chart.js';
4
+ export { ChatInput, ChatInputProps, ChatInterface, ChatInterfaceProps, ChatMessage, ChatMessageBubble, ChatRoutine, ChatSession, ChatSessionList, ChatSessionListProps, ChatThread, ChatThreadProps, ChatToolCall } from './chat-interface.js';
5
+ export { CodeBlock, CodeBlockBody, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader } from './code-block.js';
6
+ export { CellContextualFilter, CellContextualFilterProps, ColumnOptions, ColumnOptionsProps, ContextualMenuAction, DataTable, DataTableBody, DataTableCelFilterConfig, DataTableCell, DataTableEmptyConfig, DataTableEmptyView, DataTableExpandedRow, DataTableGroupRow, DataTableHeader, DataTablePagination, DataTablePaginationConfig, DataTablePaginationProps, DataTableProps, DataTableRow, DataTableRowProps, DataTableSkeletonBody, DataTableValueCell, DataTableValueCellProps, ExpandButton, RowActionItem, RowActions, RowCountRelation, StickyHeaderConfig, TableHookOptions, TableLayout, TimestampCell, ViewFilter, ViewFilterProps, defaultEmptyConfig, defaultErrorConfig, defaultNoFilterFoundConfig, getActionsColumnDefinition, getExpandColumnDefinition, normalizePageSizeOptions } from './data-table.js';
7
+ export { ActiveFilter, CheckboxFilterDefinition, CheckboxFilterValue, DateFilterDefinition, DateFilterValue, FilterBar, FilterBarProps, FilterChip, FilterDefinition, FilterOption, FilterType, FilterValue, MultiTextFilterDefinition, MultiTextFilterValue, RadioFilterDefinition, RadioFilterValue, TextFilterDefinition, TextFilterValue } from './filter-bar.js';
8
+ export { FloatingWidget, FloatingWidgetProvider, useFloatingWidget } from './floating-widget.js';
9
+ export { PageHeader, PageHeaderActions, PageHeaderAvatar, PageHeaderContent, PageHeaderDescription, PageHeaderMeta, PageHeaderTabs, PageHeaderTitle } from './page-header.js';
10
+ export { AbsoluteTimestamp, AbsoluteTimestampProps, ElapsedTime, ElapsedTimeProps, RelativeTime, RelativeTimeProps } from './relative-time.js';
11
+ export { SectionHeader, SectionHeaderActions, SectionHeaderContent, SectionHeaderDescription, SectionHeaderMeta, SectionHeaderTabs, SectionHeaderTitle } from './section-header.js';
12
+ export { SectionNav, SectionNavGroup, SectionNavGroupLabel, SectionNavItem, SectionNavItemDescription, SectionNavList, SectionNavSub } from './section-nav.js';
13
+ export { Timeline, TimelineItem } from './timeline.js';
14
+ import 'react/jsx-runtime';
15
+ import 'react';
16
+ import 'recharts';
17
+ import '@tanstack/react-table';
18
+ import '@upbound/monarch-core';