@krollins/blueprint 0.1.13 → 0.1.15

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 (50) hide show
  1. package/README.md +9 -3
  2. package/README.npm.md +9 -3
  3. package/dist/components/accordion.js.map +1 -1
  4. package/dist/components/badge/badge.d.ts.map +1 -1
  5. package/dist/components/badge.js.map +1 -1
  6. package/dist/components/breadcrumb.js.map +1 -1
  7. package/dist/components/card.js.map +1 -1
  8. package/dist/components/checkbox.js +0 -1
  9. package/dist/components/checkbox.js.map +1 -1
  10. package/dist/components/code-block/code-block.d.ts +143 -0
  11. package/dist/components/code-block/code-block.d.ts.map +1 -0
  12. package/dist/components/code-block/code-block.style.d.ts +2 -0
  13. package/dist/components/code-block/code-block.style.d.ts.map +1 -0
  14. package/dist/components/code-block.js +581 -0
  15. package/dist/components/code-block.js.map +1 -0
  16. package/dist/components/color-picker/color-picker.d.ts.map +1 -1
  17. package/dist/components/color-picker.js.map +1 -1
  18. package/dist/components/date-picker.js.map +1 -1
  19. package/dist/components/divider.js.map +1 -1
  20. package/dist/components/drawer.js.map +1 -1
  21. package/dist/components/dropdown.js.map +1 -1
  22. package/dist/components/file-upload.js.map +1 -1
  23. package/dist/components/index.d.ts +3 -0
  24. package/dist/components/index.d.ts.map +1 -1
  25. package/dist/components/menu.js.map +1 -1
  26. package/dist/components/multi-select.js.map +1 -1
  27. package/dist/components/notification.js.map +1 -1
  28. package/dist/components/pagination.js.map +1 -1
  29. package/dist/components/popover.js.map +1 -1
  30. package/dist/components/radio.js.map +1 -1
  31. package/dist/components/select.js.map +1 -1
  32. package/dist/components/skeleton.js.map +1 -1
  33. package/dist/components/stepper.js.map +1 -1
  34. package/dist/components/switch.js +0 -1
  35. package/dist/components/switch.js.map +1 -1
  36. package/dist/components/table.js.map +1 -1
  37. package/dist/components/tabs.js.map +1 -1
  38. package/dist/components/tag/tag.d.ts.map +1 -1
  39. package/dist/components/tag.js.map +1 -1
  40. package/dist/components/textarea.js.map +1 -1
  41. package/dist/components/time-picker.js.map +1 -1
  42. package/dist/components/tree.js.map +1 -1
  43. package/dist/index.js +31 -28
  44. package/dist/index.js.map +1 -1
  45. package/dist/shared/boolean-converter-XDGfS9LC.js.map +1 -1
  46. package/dist/shared/debounce-BckY30Sf.js.map +1 -1
  47. package/dist/shared/memoize-DlOFy-92.js.map +1 -1
  48. package/dist/shared/slider-BNt5TITl.js.map +1 -1
  49. package/dist/utilities/memoize.d.ts.map +1 -1
  50. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"file-upload.js","sources":["../../source/components/file-upload/file-upload.style.ts","../../source/components/file-upload/file-upload.ts"],"sourcesContent":["import { css } from 'lit';\r\n\r\nexport const fileUploadStyles = css`\r\n /* Base styles */\r\n :host {\r\n display: block;\r\n }\r\n\r\n .file-upload {\r\n font-family: var(--bp-font-family);\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--bp-spacing-md);\r\n }\r\n\r\n /* Hidden file input - standard sr-only pattern */\r\n input[type='file'] {\r\n position: absolute;\r\n width: var(--bp-spacing-0-5);\r\n height: var(--bp-spacing-0-5);\r\n padding: var(--bp-spacing-0);\r\n margin: calc(var(--bp-spacing-0-5) * -1);\r\n overflow: hidden;\r\n clip: rect(0, 0, 0, 0);\r\n white-space: nowrap;\r\n border: 0;\r\n }\r\n\r\n /* Visually hidden but accessible - standard sr-only pattern */\r\n .visually-hidden {\r\n position: absolute;\r\n width: var(--bp-spacing-0-5);\r\n height: var(--bp-spacing-0-5);\r\n padding: var(--bp-spacing-0);\r\n margin: calc(var(--bp-spacing-0-5) * -1);\r\n overflow: hidden;\r\n clip: rect(0, 0, 0, 0);\r\n white-space: nowrap;\r\n border: 0;\r\n }\r\n\r\n /* Dropzone */\r\n .file-upload__dropzone {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n gap: var(--bp-spacing-sm);\r\n padding: var(--bp-spacing-xl);\r\n border: var(--bp-focus-width) dashed var(--bp-color-border);\r\n border-radius: var(--bp-border-radius-lg);\r\n background-color: var(--bp-color-surface);\r\n cursor: pointer;\r\n transition:\r\n border-color var(--bp-transition-fast),\r\n background-color var(--bp-transition-fast);\r\n text-align: center;\r\n }\r\n\r\n .file-upload__dropzone:hover:not(.file-upload__dropzone--disabled) {\r\n border-color: var(--bp-color-primary);\r\n background-color: var(--bp-color-surface-elevated);\r\n }\r\n\r\n .file-upload__dropzone:focus-visible {\r\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\r\n outline-offset: var(--bp-focus-offset);\r\n border-color: var(--bp-color-primary);\r\n }\r\n\r\n .file-upload__dropzone:active:not(.file-upload__dropzone--disabled) {\r\n transform: scale(0.995);\r\n }\r\n\r\n /* Drag over state */\r\n .file-upload__dropzone--drag-over {\r\n border-color: var(--bp-color-primary);\r\n background-color: var(--bp-color-surface-elevated);\r\n border-style: solid;\r\n }\r\n\r\n /* Disabled state */\r\n .file-upload__dropzone--disabled {\r\n opacity: var(--bp-opacity-disabled);\r\n cursor: not-allowed;\r\n background-color: var(--bp-color-surface-subdued);\r\n }\r\n\r\n /* Icon */\r\n .file-upload__icon {\r\n width: var(--bp-spacing-2xl);\r\n height: var(--bp-spacing-2xl);\r\n color: var(--bp-color-text-muted);\r\n transition: color var(--bp-transition-fast);\r\n }\r\n\r\n .file-upload__dropzone:hover:not(.file-upload__dropzone--disabled)\r\n .file-upload__icon,\r\n .file-upload__dropzone--drag-over .file-upload__icon {\r\n color: var(--bp-color-primary);\r\n }\r\n\r\n /* Label */\r\n .file-upload__label {\r\n font-size: var(--bp-font-size-base);\r\n font-weight: var(--bp-font-weight-medium);\r\n color: var(--bp-color-text);\r\n line-height: var(--bp-line-height-normal);\r\n }\r\n\r\n /* Description */\r\n .file-upload__description {\r\n font-size: var(--bp-font-size-sm);\r\n color: var(--bp-color-text-muted);\r\n line-height: var(--bp-line-height-normal);\r\n }\r\n\r\n /* Variants */\r\n .file-upload__dropzone--success {\r\n border-color: var(--bp-color-success);\r\n }\r\n\r\n .file-upload__dropzone--success:hover:not(.file-upload__dropzone--disabled) {\r\n border-color: var(--bp-color-success);\r\n }\r\n\r\n .file-upload__dropzone--error {\r\n border-color: var(--bp-color-error);\r\n }\r\n\r\n .file-upload__dropzone--error:hover:not(.file-upload__dropzone--disabled) {\r\n border-color: var(--bp-color-error);\r\n }\r\n\r\n .file-upload__dropzone--warning {\r\n border-color: var(--bp-color-warning);\r\n }\r\n\r\n .file-upload__dropzone--warning:hover:not(.file-upload__dropzone--disabled) {\r\n border-color: var(--bp-color-warning);\r\n }\r\n\r\n /* Size variants */\r\n .file-upload__dropzone--sm {\r\n padding: var(--bp-spacing-lg);\r\n gap: var(--bp-spacing-xs);\r\n }\r\n\r\n .file-upload__dropzone--sm .file-upload__icon {\r\n width: var(--bp-spacing-xl);\r\n height: var(--bp-spacing-xl);\r\n }\r\n\r\n .file-upload__dropzone--sm .file-upload__label {\r\n font-size: var(--bp-font-size-sm);\r\n }\r\n\r\n .file-upload__dropzone--sm .file-upload__description {\r\n font-size: var(--bp-font-size-xs);\r\n }\r\n\r\n .file-upload__dropzone--md {\r\n padding: var(--bp-spacing-xl);\r\n }\r\n\r\n .file-upload__dropzone--lg {\r\n padding: var(--bp-spacing-2xl);\r\n gap: var(--bp-spacing-md);\r\n }\r\n\r\n .file-upload__dropzone--lg .file-upload__icon {\r\n width: var(--bp-spacing-10);\r\n height: var(--bp-spacing-10);\r\n }\r\n\r\n .file-upload__dropzone--lg .file-upload__label {\r\n font-size: var(--bp-font-size-lg);\r\n }\r\n\r\n /* File list */\r\n .file-upload__file-list {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--bp-spacing-sm);\r\n }\r\n\r\n .file-upload__file-item {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--bp-spacing-md);\r\n padding: var(--bp-spacing-md);\r\n background-color: var(--bp-color-surface);\r\n border: var(--bp-border-width) solid var(--bp-color-border);\r\n border-radius: var(--bp-border-radius-md);\r\n transition:\r\n background-color var(--bp-transition-fast),\r\n border-color var(--bp-transition-fast),\r\n transform var(--bp-transition-fast);\r\n }\r\n\r\n .file-upload__file-item:hover {\r\n background-color: var(--bp-color-surface-elevated);\r\n border-color: var(--bp-color-border-strong);\r\n }\r\n\r\n .file-upload__file-item:active {\r\n transform: scale(0.99);\r\n }\r\n\r\n /* File preview */\r\n .file-upload__preview {\r\n width: var(--bp-spacing-10);\r\n height: var(--bp-spacing-10);\r\n object-fit: cover;\r\n border-radius: var(--bp-border-radius-sm);\r\n flex-shrink: 0;\r\n }\r\n\r\n .file-upload__file-icon {\r\n width: var(--bp-spacing-10);\r\n height: var(--bp-spacing-10);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n flex-shrink: 0;\r\n color: var(--bp-color-text-muted);\r\n transition: color var(--bp-transition-fast);\r\n }\r\n\r\n .file-upload__file-icon svg {\r\n width: var(--bp-spacing-6);\r\n height: var(--bp-spacing-6);\r\n }\r\n\r\n /* File info */\r\n .file-upload__file-info {\r\n display: flex;\r\n flex-direction: column;\r\n gap: var(--bp-spacing-2xs);\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .file-upload__file-name {\r\n font-size: var(--bp-font-size-sm);\r\n font-weight: var(--bp-font-weight-medium);\r\n color: var(--bp-color-text);\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n line-height: var(--bp-line-height-normal);\r\n }\r\n\r\n .file-upload__file-size {\r\n font-size: var(--bp-font-size-xs);\r\n color: var(--bp-color-text-muted);\r\n line-height: var(--bp-line-height-normal);\r\n }\r\n\r\n /* Remove button */\r\n .file-upload__remove-button {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--bp-spacing-6);\r\n height: var(--bp-spacing-6);\r\n padding: 0;\r\n border: none;\r\n background: transparent;\r\n border-radius: var(--bp-border-radius-sm);\r\n color: var(--bp-color-text-muted);\r\n cursor: pointer;\r\n transition:\r\n background-color var(--bp-transition-fast),\r\n color var(--bp-transition-fast);\r\n flex-shrink: 0;\r\n }\r\n\r\n .file-upload__remove-button:hover:not(:disabled) {\r\n background-color: var(--bp-color-error);\r\n color: var(--bp-color-text-inverse);\r\n }\r\n\r\n .file-upload__remove-button:focus-visible {\r\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\r\n outline-offset: var(--bp-focus-offset);\r\n }\r\n\r\n .file-upload__remove-button:disabled {\r\n cursor: not-allowed;\r\n opacity: var(--bp-opacity-disabled);\r\n }\r\n\r\n .file-upload__remove-button svg {\r\n width: var(--bp-spacing-4);\r\n height: var(--bp-spacing-4);\r\n }\r\n\r\n /* Message */\r\n .file-upload__message {\r\n font-size: var(--bp-font-size-sm);\r\n color: var(--bp-color-text-muted);\r\n line-height: var(--bp-line-height-normal);\r\n }\r\n\r\n .file-upload__message--success {\r\n color: var(--bp-color-success);\r\n }\r\n\r\n .file-upload__message--error {\r\n color: var(--bp-color-error);\r\n }\r\n\r\n .file-upload__message--warning {\r\n color: var(--bp-color-warning);\r\n }\r\n`;\r\n","import { LitElement, html, nothing } from 'lit';\r\nimport { customElement, property, state, query } from 'lit/decorators.js';\r\nimport { classMap } from 'lit/directives/class-map.js';\r\nimport { fileUploadStyles } from './file-upload.style.js';\r\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\r\n\r\n/**\r\n * File information object returned in events\r\n */\r\nexport interface FileInfo {\r\n /** Original File object */\r\n file: File;\r\n /** File name */\r\n name: string;\r\n /** File size in bytes */\r\n size: number;\r\n /** MIME type */\r\n type: string;\r\n /** Unique identifier */\r\n id: string;\r\n /** Preview URL for images */\r\n previewUrl?: string;\r\n /** Upload progress (0-100) */\r\n progress?: number;\r\n /** Upload status */\r\n status?: 'pending' | 'uploading' | 'complete' | 'error';\r\n /** Error message if upload failed */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * A file upload component with drag-and-drop support.\r\n *\r\n * @element bp-file-upload\r\n *\r\n * @fires bp-change - Fired when files are added or removed\r\n * @fires bp-file-added - Fired when a file is added\r\n * @fires bp-file-removed - Fired when a file is removed\r\n * @fires bp-file-rejected - Fired when a file is rejected (wrong type/size)\r\n *\r\n * @csspart dropzone - The drop zone container\r\n * @csspart input - The hidden file input\r\n * @csspart label - The label text\r\n * @csspart description - The description text\r\n * @csspart icon - The upload icon\r\n * @csspart file-list - The file list container\r\n * @csspart file-item - Individual file item\r\n * @csspart file-name - File name text\r\n * @csspart file-size - File size text\r\n * @csspart file-remove - Remove file button\r\n */\r\n@customElement('bp-file-upload')\r\nexport class BpFileUpload extends LitElement {\r\n /** Name attribute for form submission */\r\n @property({ type: String }) declare name: string;\r\n\r\n /** Label text displayed in the drop zone */\r\n @property({ type: String }) declare label: string;\r\n\r\n /** Description text displayed below the label */\r\n @property({ type: String }) declare description: string;\r\n\r\n /** Accepted file types (comma-separated MIME types or extensions) */\r\n @property({ type: String }) declare accept: string;\r\n\r\n /** Whether multiple files can be selected */\r\n @property({ type: Boolean }) declare multiple: boolean;\r\n\r\n /** Maximum file size in bytes */\r\n @property({ type: Number }) declare maxSize: number;\r\n\r\n /** Maximum number of files allowed */\r\n @property({ type: Number }) declare maxFiles: number;\r\n\r\n /** Whether the component is disabled */\r\n @property({ type: Boolean, reflect: true }) declare disabled: boolean;\r\n\r\n /** Whether a file is required */\r\n @property({ type: Boolean }) declare required: boolean;\r\n\r\n /** Visual variant for validation states */\r\n @property({ type: String }) declare variant:\r\n | 'default'\r\n | 'success'\r\n | 'error'\r\n | 'warning';\r\n\r\n /** Helper or error message text */\r\n @property({ type: String }) declare message: string;\r\n\r\n /** Size variant */\r\n @property({ type: String }) declare size: 'sm' | 'md' | 'lg';\r\n\r\n /** Whether to show file previews for images */\r\n @property({ converter: booleanConverter, reflect: true })\r\n declare showPreviews: boolean;\r\n\r\n /** Whether drag is currently over the drop zone */\r\n @state() private isDragOver = false;\r\n\r\n /** List of selected files */\r\n @state() private files: FileInfo[] = [];\r\n\r\n /** Reference to the hidden file input */\r\n @query('input[type=\"file\"]') private fileInput!: HTMLInputElement;\r\n\r\n static styles = [fileUploadStyles];\r\n\r\n constructor() {\r\n super();\r\n this.name = '';\r\n this.label = 'Drop files here or click to upload';\r\n this.description = '';\r\n this.accept = '';\r\n this.multiple = false;\r\n this.maxSize = 0;\r\n this.maxFiles = 0;\r\n this.disabled = false;\r\n this.required = false;\r\n this.variant = 'default';\r\n this.message = '';\r\n this.size = 'md';\r\n this.showPreviews = true;\r\n }\r\n\r\n /**\r\n * Get the list of selected files\r\n */\r\n getFiles(): FileInfo[] {\r\n return [...this.files];\r\n }\r\n\r\n /**\r\n * Clear all selected files\r\n */\r\n clearFiles(): void {\r\n // Revoke object URLs to prevent memory leaks\r\n this.files.forEach((fileInfo) => {\r\n if (fileInfo.previewUrl) {\r\n URL.revokeObjectURL(fileInfo.previewUrl);\r\n }\r\n });\r\n this.files = [];\r\n if (this.fileInput) {\r\n this.fileInput.value = '';\r\n }\r\n this.dispatchChangeEvent();\r\n }\r\n\r\n /**\r\n * Remove a specific file by ID\r\n */\r\n removeFile(fileId: string): void {\r\n const fileIndex = this.files.findIndex((f) => f.id === fileId);\r\n if (fileIndex !== -1) {\r\n const removedFile = this.files[fileIndex];\r\n if (removedFile.previewUrl) {\r\n URL.revokeObjectURL(removedFile.previewUrl);\r\n }\r\n this.files = this.files.filter((f) => f.id !== fileId);\r\n this.dispatchEvent(\r\n new CustomEvent('bp-file-removed', {\r\n detail: { file: removedFile },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n this.dispatchChangeEvent();\r\n }\r\n }\r\n\r\n private handleClick(): void {\r\n if (!this.disabled) {\r\n this.fileInput?.click();\r\n }\r\n }\r\n\r\n private handleKeyDown(event: globalThis.KeyboardEvent): void {\r\n if (this.disabled) return;\r\n\r\n if (event.key === 'Enter' || event.key === ' ') {\r\n event.preventDefault();\r\n this.fileInput?.click();\r\n }\r\n }\r\n\r\n private handleInputChange(event: Event): void {\r\n const input = event.target as HTMLInputElement;\r\n if (input.files) {\r\n this.processFiles(Array.from(input.files));\r\n }\r\n }\r\n\r\n private handleDragEnter(event: DragEvent): void {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n if (!this.disabled) {\r\n this.isDragOver = true;\r\n }\r\n }\r\n\r\n private handleDragOver(event: DragEvent): void {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n if (!this.disabled && event.dataTransfer) {\r\n event.dataTransfer.dropEffect = 'copy';\r\n }\r\n }\r\n\r\n private handleDragLeave(event: DragEvent): void {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n // Only set isDragOver to false if we're leaving the dropzone entirely\r\n const relatedTarget = event.relatedTarget as Node | null;\r\n if (!this.contains(relatedTarget)) {\r\n this.isDragOver = false;\r\n }\r\n }\r\n\r\n private handleDrop(event: DragEvent): void {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.isDragOver = false;\r\n\r\n if (this.disabled) return;\r\n\r\n const dataTransfer = event.dataTransfer;\r\n if (dataTransfer?.files) {\r\n this.processFiles(Array.from(dataTransfer.files));\r\n }\r\n }\r\n\r\n private processFiles(newFiles: File[]): void {\r\n const validFiles: FileInfo[] = [];\r\n\r\n for (const file of newFiles) {\r\n // Check if max files limit is reached\r\n if (\r\n this.maxFiles > 0 &&\r\n this.files.length + validFiles.length >= this.maxFiles\r\n ) {\r\n this.dispatchRejectEvent(file, 'Maximum number of files exceeded');\r\n continue;\r\n }\r\n\r\n // Check file type\r\n if (this.accept && !this.isFileTypeAccepted(file)) {\r\n this.dispatchRejectEvent(file, 'File type not accepted');\r\n continue;\r\n }\r\n\r\n // Check file size\r\n if (this.maxSize > 0 && file.size > this.maxSize) {\r\n this.dispatchRejectEvent(file, 'File size exceeds limit');\r\n continue;\r\n }\r\n\r\n // Create file info object\r\n const fileInfo: FileInfo = {\r\n file,\r\n name: file.name,\r\n size: file.size,\r\n type: file.type,\r\n id: this.generateFileId(),\r\n status: 'pending',\r\n progress: 0,\r\n };\r\n\r\n // Generate preview for images\r\n if (this.showPreviews && file.type.startsWith('image/')) {\r\n fileInfo.previewUrl = URL.createObjectURL(file);\r\n }\r\n\r\n validFiles.push(fileInfo);\r\n\r\n this.dispatchEvent(\r\n new CustomEvent('bp-file-added', {\r\n detail: { file: fileInfo },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n }\r\n\r\n if (validFiles.length > 0) {\r\n if (this.multiple) {\r\n this.files = [...this.files, ...validFiles];\r\n } else {\r\n // Single file mode - replace existing file\r\n this.files.forEach((existingFile) => {\r\n if (existingFile.previewUrl) {\r\n URL.revokeObjectURL(existingFile.previewUrl);\r\n }\r\n });\r\n this.files = validFiles.slice(0, 1);\r\n }\r\n this.dispatchChangeEvent();\r\n }\r\n }\r\n\r\n private isFileTypeAccepted(file: File): boolean {\r\n if (!this.accept) return true;\r\n\r\n const acceptedTypes = this.accept\r\n .split(',')\r\n .map((type) => type.trim().toLowerCase());\r\n const fileType = file.type.toLowerCase();\r\n const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();\r\n\r\n return acceptedTypes.some((accepted) => {\r\n // Check MIME type match\r\n if (accepted === fileType) return true;\r\n // Check extension match\r\n if (accepted === fileExtension) return true;\r\n // Check wildcard MIME type (e.g., image/*)\r\n if (accepted.endsWith('/*')) {\r\n const category = accepted.slice(0, -2);\r\n return fileType.startsWith(category + '/');\r\n }\r\n return false;\r\n });\r\n }\r\n\r\n private dispatchChangeEvent(): void {\r\n this.dispatchEvent(\r\n new CustomEvent('bp-change', {\r\n detail: { files: this.getFiles() },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n }\r\n\r\n private dispatchRejectEvent(file: File, reason: string): void {\r\n this.dispatchEvent(\r\n new CustomEvent('bp-file-rejected', {\r\n detail: { file, reason },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n }\r\n\r\n private generateFileId(): string {\r\n return `file-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\r\n }\r\n\r\n private formatFileSize(bytes: number): string {\r\n if (bytes === 0) return '0 B';\r\n const units = ['B', 'KB', 'MB', 'GB'];\r\n const exponent = Math.min(\r\n Math.floor(Math.log(bytes) / Math.log(1024)),\r\n units.length - 1\r\n );\r\n const size = bytes / Math.pow(1024, exponent);\r\n return `${size.toFixed(exponent > 0 ? 1 : 0)} ${units[exponent]}`;\r\n }\r\n\r\n private handleRemoveFile(event: Event, fileId: string): void {\r\n event.stopPropagation();\r\n this.removeFile(fileId);\r\n }\r\n\r\n private renderUploadIcon() {\r\n return html`\r\n <svg\r\n class=\"file-upload__icon\"\r\n part=\"icon\"\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\"\r\n aria-hidden=\"true\"\r\n >\r\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\r\n <polyline points=\"17 8 12 3 7 8\" />\r\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\r\n </svg>\r\n `;\r\n }\r\n\r\n private renderFileList() {\r\n if (this.files.length === 0) return nothing;\r\n\r\n return html`\r\n <div\r\n class=\"file-upload__file-list\"\r\n part=\"file-list\"\r\n role=\"list\"\r\n aria-label=\"Selected files\"\r\n >\r\n ${this.files.map(\r\n (fileInfo) => html`\r\n <div\r\n class=\"file-upload__file-item\"\r\n part=\"file-item\"\r\n role=\"listitem\"\r\n >\r\n ${fileInfo.previewUrl\r\n ? html`\r\n <img\r\n class=\"file-upload__preview\"\r\n src=\"${fileInfo.previewUrl}\"\r\n alt=\"Preview of ${fileInfo.name}\"\r\n />\r\n `\r\n : html`\r\n <div class=\"file-upload__file-icon\" aria-hidden=\"true\">\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path\r\n d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\r\n />\r\n <polyline points=\"14 2 14 8 20 8\" />\r\n </svg>\r\n </div>\r\n `}\r\n <div class=\"file-upload__file-info\">\r\n <span class=\"file-upload__file-name\" part=\"file-name\"\r\n >${fileInfo.name}</span\r\n >\r\n <span class=\"file-upload__file-size\" part=\"file-size\"\r\n >${this.formatFileSize(fileInfo.size)}</span\r\n >\r\n </div>\r\n <button\r\n type=\"button\"\r\n class=\"file-upload__remove-button\"\r\n part=\"file-remove\"\r\n @click=${(e: Event) => this.handleRemoveFile(e, fileInfo.id)}\r\n aria-label=\"Remove ${fileInfo.name}\"\r\n ?disabled=${this.disabled}\r\n >\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\r\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\r\n </svg>\r\n </button>\r\n </div>\r\n `\r\n )}\r\n </div>\r\n `;\r\n }\r\n\r\n render() {\r\n const dropzoneClasses = {\r\n 'file-upload__dropzone': true,\r\n 'file-upload__dropzone--drag-over': this.isDragOver,\r\n 'file-upload__dropzone--disabled': this.disabled,\r\n 'file-upload__dropzone--has-files': this.files.length > 0,\r\n [`file-upload__dropzone--${this.variant}`]: this.variant !== 'default',\r\n [`file-upload__dropzone--${this.size}`]: true,\r\n };\r\n\r\n const acceptDescription = this.accept\r\n ? `Accepted file types: ${this.accept}`\r\n : '';\r\n const sizeDescription =\r\n this.maxSize > 0\r\n ? `Maximum file size: ${this.formatFileSize(this.maxSize)}`\r\n : '';\r\n\r\n return html`\r\n <div class=\"file-upload\">\r\n <div\r\n class=${classMap(dropzoneClasses)}\r\n part=\"dropzone\"\r\n role=\"button\"\r\n tabindex=${this.disabled ? -1 : 0}\r\n aria-disabled=${this.disabled}\r\n aria-describedby=\"file-upload-description\"\r\n @click=${this.handleClick}\r\n @keydown=${this.handleKeyDown}\r\n @dragenter=${this.handleDragEnter}\r\n @dragover=${this.handleDragOver}\r\n @dragleave=${this.handleDragLeave}\r\n @drop=${this.handleDrop}\r\n >\r\n <input\r\n type=\"file\"\r\n part=\"input\"\r\n .name=${this.name}\r\n .accept=${this.accept}\r\n ?multiple=${this.multiple}\r\n ?disabled=${this.disabled}\r\n ?required=${this.required}\r\n @change=${this.handleInputChange}\r\n aria-hidden=\"true\"\r\n tabindex=\"-1\"\r\n />\r\n\r\n ${this.renderUploadIcon()}\r\n\r\n <span class=\"file-upload__label\" part=\"label\">${this.label}</span>\r\n\r\n ${this.description\r\n ? html`<span class=\"file-upload__description\" part=\"description\"\r\n >${this.description}</span\r\n >`\r\n : nothing}\r\n </div>\r\n\r\n <span id=\"file-upload-description\" class=\"visually-hidden\">\r\n ${acceptDescription} ${sizeDescription}\r\n </span>\r\n\r\n ${this.renderFileList()}\r\n ${this.message\r\n ? html`<div\r\n class=\"file-upload__message file-upload__message--${this.variant}\"\r\n part=\"message\"\r\n >\r\n ${this.message}\r\n </div>`\r\n : nothing}\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'bp-file-upload': BpFileUpload;\r\n }\r\n}\r\n"],"names":["fileUploadStyles","css","BpFileUpload","LitElement","fileInfo","fileId","fileIndex","f","removedFile","event","input","relatedTarget","dataTransfer","newFiles","validFiles","file","existingFile","acceptedTypes","type","fileType","fileExtension","accepted","category","reason","bytes","units","exponent","html","nothing","e","dropzoneClasses","acceptDescription","sizeDescription","classMap","__decorateClass","property","booleanConverter","state","query","customElement"],"mappings":";;;;AAEO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
1
+ {"version":3,"file":"file-upload.js","sources":["../../source/components/file-upload/file-upload.style.ts","../../source/components/file-upload/file-upload.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const fileUploadStyles = css`\n /* Base styles */\n :host {\n display: block;\n }\n\n .file-upload {\n font-family: var(--bp-font-family);\n display: flex;\n flex-direction: column;\n gap: var(--bp-spacing-md);\n }\n\n /* Hidden file input - standard sr-only pattern */\n input[type='file'] {\n position: absolute;\n width: var(--bp-spacing-0-5);\n height: var(--bp-spacing-0-5);\n padding: var(--bp-spacing-0);\n margin: calc(var(--bp-spacing-0-5) * -1);\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* Visually hidden but accessible - standard sr-only pattern */\n .visually-hidden {\n position: absolute;\n width: var(--bp-spacing-0-5);\n height: var(--bp-spacing-0-5);\n padding: var(--bp-spacing-0);\n margin: calc(var(--bp-spacing-0-5) * -1);\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* Dropzone */\n .file-upload__dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--bp-spacing-sm);\n padding: var(--bp-spacing-xl);\n border: var(--bp-focus-width) dashed var(--bp-color-border);\n border-radius: var(--bp-border-radius-lg);\n background-color: var(--bp-color-surface);\n cursor: pointer;\n transition:\n border-color var(--bp-transition-fast),\n background-color var(--bp-transition-fast);\n text-align: center;\n }\n\n .file-upload__dropzone:hover:not(.file-upload__dropzone--disabled) {\n border-color: var(--bp-color-primary);\n background-color: var(--bp-color-surface-elevated);\n }\n\n .file-upload__dropzone:focus-visible {\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\n outline-offset: var(--bp-focus-offset);\n border-color: var(--bp-color-primary);\n }\n\n .file-upload__dropzone:active:not(.file-upload__dropzone--disabled) {\n transform: scale(0.995);\n }\n\n /* Drag over state */\n .file-upload__dropzone--drag-over {\n border-color: var(--bp-color-primary);\n background-color: var(--bp-color-surface-elevated);\n border-style: solid;\n }\n\n /* Disabled state */\n .file-upload__dropzone--disabled {\n opacity: var(--bp-opacity-disabled);\n cursor: not-allowed;\n background-color: var(--bp-color-surface-subdued);\n }\n\n /* Icon */\n .file-upload__icon {\n width: var(--bp-spacing-2xl);\n height: var(--bp-spacing-2xl);\n color: var(--bp-color-text-muted);\n transition: color var(--bp-transition-fast);\n }\n\n .file-upload__dropzone:hover:not(.file-upload__dropzone--disabled)\n .file-upload__icon,\n .file-upload__dropzone--drag-over .file-upload__icon {\n color: var(--bp-color-primary);\n }\n\n /* Label */\n .file-upload__label {\n font-size: var(--bp-font-size-base);\n font-weight: var(--bp-font-weight-medium);\n color: var(--bp-color-text);\n line-height: var(--bp-line-height-normal);\n }\n\n /* Description */\n .file-upload__description {\n font-size: var(--bp-font-size-sm);\n color: var(--bp-color-text-muted);\n line-height: var(--bp-line-height-normal);\n }\n\n /* Variants */\n .file-upload__dropzone--success {\n border-color: var(--bp-color-success);\n }\n\n .file-upload__dropzone--success:hover:not(.file-upload__dropzone--disabled) {\n border-color: var(--bp-color-success);\n }\n\n .file-upload__dropzone--error {\n border-color: var(--bp-color-error);\n }\n\n .file-upload__dropzone--error:hover:not(.file-upload__dropzone--disabled) {\n border-color: var(--bp-color-error);\n }\n\n .file-upload__dropzone--warning {\n border-color: var(--bp-color-warning);\n }\n\n .file-upload__dropzone--warning:hover:not(.file-upload__dropzone--disabled) {\n border-color: var(--bp-color-warning);\n }\n\n /* Size variants */\n .file-upload__dropzone--sm {\n padding: var(--bp-spacing-lg);\n gap: var(--bp-spacing-xs);\n }\n\n .file-upload__dropzone--sm .file-upload__icon {\n width: var(--bp-spacing-xl);\n height: var(--bp-spacing-xl);\n }\n\n .file-upload__dropzone--sm .file-upload__label {\n font-size: var(--bp-font-size-sm);\n }\n\n .file-upload__dropzone--sm .file-upload__description {\n font-size: var(--bp-font-size-xs);\n }\n\n .file-upload__dropzone--md {\n padding: var(--bp-spacing-xl);\n }\n\n .file-upload__dropzone--lg {\n padding: var(--bp-spacing-2xl);\n gap: var(--bp-spacing-md);\n }\n\n .file-upload__dropzone--lg .file-upload__icon {\n width: var(--bp-spacing-10);\n height: var(--bp-spacing-10);\n }\n\n .file-upload__dropzone--lg .file-upload__label {\n font-size: var(--bp-font-size-lg);\n }\n\n /* File list */\n .file-upload__file-list {\n display: flex;\n flex-direction: column;\n gap: var(--bp-spacing-sm);\n }\n\n .file-upload__file-item {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-md);\n padding: var(--bp-spacing-md);\n background-color: var(--bp-color-surface);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n transition:\n background-color var(--bp-transition-fast),\n border-color var(--bp-transition-fast),\n transform var(--bp-transition-fast);\n }\n\n .file-upload__file-item:hover {\n background-color: var(--bp-color-surface-elevated);\n border-color: var(--bp-color-border-strong);\n }\n\n .file-upload__file-item:active {\n transform: scale(0.99);\n }\n\n /* File preview */\n .file-upload__preview {\n width: var(--bp-spacing-10);\n height: var(--bp-spacing-10);\n object-fit: cover;\n border-radius: var(--bp-border-radius-sm);\n flex-shrink: 0;\n }\n\n .file-upload__file-icon {\n width: var(--bp-spacing-10);\n height: var(--bp-spacing-10);\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: var(--bp-color-text-muted);\n transition: color var(--bp-transition-fast);\n }\n\n .file-upload__file-icon svg {\n width: var(--bp-spacing-6);\n height: var(--bp-spacing-6);\n }\n\n /* File info */\n .file-upload__file-info {\n display: flex;\n flex-direction: column;\n gap: var(--bp-spacing-2xs);\n flex: 1;\n min-width: 0;\n }\n\n .file-upload__file-name {\n font-size: var(--bp-font-size-sm);\n font-weight: var(--bp-font-weight-medium);\n color: var(--bp-color-text);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n line-height: var(--bp-line-height-normal);\n }\n\n .file-upload__file-size {\n font-size: var(--bp-font-size-xs);\n color: var(--bp-color-text-muted);\n line-height: var(--bp-line-height-normal);\n }\n\n /* Remove button */\n .file-upload__remove-button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-6);\n height: var(--bp-spacing-6);\n padding: 0;\n border: none;\n background: transparent;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-text-muted);\n cursor: pointer;\n transition:\n background-color var(--bp-transition-fast),\n color var(--bp-transition-fast);\n flex-shrink: 0;\n }\n\n .file-upload__remove-button:hover:not(:disabled) {\n background-color: var(--bp-color-error);\n color: var(--bp-color-text-inverse);\n }\n\n .file-upload__remove-button:focus-visible {\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\n outline-offset: var(--bp-focus-offset);\n }\n\n .file-upload__remove-button:disabled {\n cursor: not-allowed;\n opacity: var(--bp-opacity-disabled);\n }\n\n .file-upload__remove-button svg {\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n }\n\n /* Message */\n .file-upload__message {\n font-size: var(--bp-font-size-sm);\n color: var(--bp-color-text-muted);\n line-height: var(--bp-line-height-normal);\n }\n\n .file-upload__message--success {\n color: var(--bp-color-success);\n }\n\n .file-upload__message--error {\n color: var(--bp-color-error);\n }\n\n .file-upload__message--warning {\n color: var(--bp-color-warning);\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { fileUploadStyles } from './file-upload.style.js';\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\n\n/**\n * File information object returned in events\n */\nexport interface FileInfo {\n /** Original File object */\n file: File;\n /** File name */\n name: string;\n /** File size in bytes */\n size: number;\n /** MIME type */\n type: string;\n /** Unique identifier */\n id: string;\n /** Preview URL for images */\n previewUrl?: string;\n /** Upload progress (0-100) */\n progress?: number;\n /** Upload status */\n status?: 'pending' | 'uploading' | 'complete' | 'error';\n /** Error message if upload failed */\n error?: string;\n}\n\n/**\n * A file upload component with drag-and-drop support.\n *\n * @element bp-file-upload\n *\n * @fires bp-change - Fired when files are added or removed\n * @fires bp-file-added - Fired when a file is added\n * @fires bp-file-removed - Fired when a file is removed\n * @fires bp-file-rejected - Fired when a file is rejected (wrong type/size)\n *\n * @csspart dropzone - The drop zone container\n * @csspart input - The hidden file input\n * @csspart label - The label text\n * @csspart description - The description text\n * @csspart icon - The upload icon\n * @csspart file-list - The file list container\n * @csspart file-item - Individual file item\n * @csspart file-name - File name text\n * @csspart file-size - File size text\n * @csspart file-remove - Remove file button\n */\n@customElement('bp-file-upload')\nexport class BpFileUpload extends LitElement {\n /** Name attribute for form submission */\n @property({ type: String }) declare name: string;\n\n /** Label text displayed in the drop zone */\n @property({ type: String }) declare label: string;\n\n /** Description text displayed below the label */\n @property({ type: String }) declare description: string;\n\n /** Accepted file types (comma-separated MIME types or extensions) */\n @property({ type: String }) declare accept: string;\n\n /** Whether multiple files can be selected */\n @property({ type: Boolean }) declare multiple: boolean;\n\n /** Maximum file size in bytes */\n @property({ type: Number }) declare maxSize: number;\n\n /** Maximum number of files allowed */\n @property({ type: Number }) declare maxFiles: number;\n\n /** Whether the component is disabled */\n @property({ type: Boolean, reflect: true }) declare disabled: boolean;\n\n /** Whether a file is required */\n @property({ type: Boolean }) declare required: boolean;\n\n /** Visual variant for validation states */\n @property({ type: String }) declare variant:\n | 'default'\n | 'success'\n | 'error'\n | 'warning';\n\n /** Helper or error message text */\n @property({ type: String }) declare message: string;\n\n /** Size variant */\n @property({ type: String }) declare size: 'sm' | 'md' | 'lg';\n\n /** Whether to show file previews for images */\n @property({ converter: booleanConverter, reflect: true })\n declare showPreviews: boolean;\n\n /** Whether drag is currently over the drop zone */\n @state() private isDragOver = false;\n\n /** List of selected files */\n @state() private files: FileInfo[] = [];\n\n /** Reference to the hidden file input */\n @query('input[type=\"file\"]') private fileInput!: HTMLInputElement;\n\n static styles = [fileUploadStyles];\n\n constructor() {\n super();\n this.name = '';\n this.label = 'Drop files here or click to upload';\n this.description = '';\n this.accept = '';\n this.multiple = false;\n this.maxSize = 0;\n this.maxFiles = 0;\n this.disabled = false;\n this.required = false;\n this.variant = 'default';\n this.message = '';\n this.size = 'md';\n this.showPreviews = true;\n }\n\n /**\n * Get the list of selected files\n */\n getFiles(): FileInfo[] {\n return [...this.files];\n }\n\n /**\n * Clear all selected files\n */\n clearFiles(): void {\n // Revoke object URLs to prevent memory leaks\n this.files.forEach((fileInfo) => {\n if (fileInfo.previewUrl) {\n URL.revokeObjectURL(fileInfo.previewUrl);\n }\n });\n this.files = [];\n if (this.fileInput) {\n this.fileInput.value = '';\n }\n this.dispatchChangeEvent();\n }\n\n /**\n * Remove a specific file by ID\n */\n removeFile(fileId: string): void {\n const fileIndex = this.files.findIndex((f) => f.id === fileId);\n if (fileIndex !== -1) {\n const removedFile = this.files[fileIndex];\n if (removedFile.previewUrl) {\n URL.revokeObjectURL(removedFile.previewUrl);\n }\n this.files = this.files.filter((f) => f.id !== fileId);\n this.dispatchEvent(\n new CustomEvent('bp-file-removed', {\n detail: { file: removedFile },\n bubbles: true,\n composed: true,\n })\n );\n this.dispatchChangeEvent();\n }\n }\n\n private handleClick(): void {\n if (!this.disabled) {\n this.fileInput?.click();\n }\n }\n\n private handleKeyDown(event: globalThis.KeyboardEvent): void {\n if (this.disabled) return;\n\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.fileInput?.click();\n }\n }\n\n private handleInputChange(event: Event): void {\n const input = event.target as HTMLInputElement;\n if (input.files) {\n this.processFiles(Array.from(input.files));\n }\n }\n\n private handleDragEnter(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n if (!this.disabled) {\n this.isDragOver = true;\n }\n }\n\n private handleDragOver(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n if (!this.disabled && event.dataTransfer) {\n event.dataTransfer.dropEffect = 'copy';\n }\n }\n\n private handleDragLeave(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n // Only set isDragOver to false if we're leaving the dropzone entirely\n const relatedTarget = event.relatedTarget as Node | null;\n if (!this.contains(relatedTarget)) {\n this.isDragOver = false;\n }\n }\n\n private handleDrop(event: DragEvent): void {\n event.preventDefault();\n event.stopPropagation();\n this.isDragOver = false;\n\n if (this.disabled) return;\n\n const dataTransfer = event.dataTransfer;\n if (dataTransfer?.files) {\n this.processFiles(Array.from(dataTransfer.files));\n }\n }\n\n private processFiles(newFiles: File[]): void {\n const validFiles: FileInfo[] = [];\n\n for (const file of newFiles) {\n // Check if max files limit is reached\n if (\n this.maxFiles > 0 &&\n this.files.length + validFiles.length >= this.maxFiles\n ) {\n this.dispatchRejectEvent(file, 'Maximum number of files exceeded');\n continue;\n }\n\n // Check file type\n if (this.accept && !this.isFileTypeAccepted(file)) {\n this.dispatchRejectEvent(file, 'File type not accepted');\n continue;\n }\n\n // Check file size\n if (this.maxSize > 0 && file.size > this.maxSize) {\n this.dispatchRejectEvent(file, 'File size exceeds limit');\n continue;\n }\n\n // Create file info object\n const fileInfo: FileInfo = {\n file,\n name: file.name,\n size: file.size,\n type: file.type,\n id: this.generateFileId(),\n status: 'pending',\n progress: 0,\n };\n\n // Generate preview for images\n if (this.showPreviews && file.type.startsWith('image/')) {\n fileInfo.previewUrl = URL.createObjectURL(file);\n }\n\n validFiles.push(fileInfo);\n\n this.dispatchEvent(\n new CustomEvent('bp-file-added', {\n detail: { file: fileInfo },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n if (validFiles.length > 0) {\n if (this.multiple) {\n this.files = [...this.files, ...validFiles];\n } else {\n // Single file mode - replace existing file\n this.files.forEach((existingFile) => {\n if (existingFile.previewUrl) {\n URL.revokeObjectURL(existingFile.previewUrl);\n }\n });\n this.files = validFiles.slice(0, 1);\n }\n this.dispatchChangeEvent();\n }\n }\n\n private isFileTypeAccepted(file: File): boolean {\n if (!this.accept) return true;\n\n const acceptedTypes = this.accept\n .split(',')\n .map((type) => type.trim().toLowerCase());\n const fileType = file.type.toLowerCase();\n const fileExtension = '.' + file.name.split('.').pop()?.toLowerCase();\n\n return acceptedTypes.some((accepted) => {\n // Check MIME type match\n if (accepted === fileType) return true;\n // Check extension match\n if (accepted === fileExtension) return true;\n // Check wildcard MIME type (e.g., image/*)\n if (accepted.endsWith('/*')) {\n const category = accepted.slice(0, -2);\n return fileType.startsWith(category + '/');\n }\n return false;\n });\n }\n\n private dispatchChangeEvent(): void {\n this.dispatchEvent(\n new CustomEvent('bp-change', {\n detail: { files: this.getFiles() },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private dispatchRejectEvent(file: File, reason: string): void {\n this.dispatchEvent(\n new CustomEvent('bp-file-rejected', {\n detail: { file, reason },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private generateFileId(): string {\n return `file-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;\n }\n\n private formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n const units = ['B', 'KB', 'MB', 'GB'];\n const exponent = Math.min(\n Math.floor(Math.log(bytes) / Math.log(1024)),\n units.length - 1\n );\n const size = bytes / Math.pow(1024, exponent);\n return `${size.toFixed(exponent > 0 ? 1 : 0)} ${units[exponent]}`;\n }\n\n private handleRemoveFile(event: Event, fileId: string): void {\n event.stopPropagation();\n this.removeFile(fileId);\n }\n\n private renderUploadIcon() {\n return html`\n <svg\n class=\"file-upload__icon\"\n part=\"icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\" />\n <polyline points=\"17 8 12 3 7 8\" />\n <line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\" />\n </svg>\n `;\n }\n\n private renderFileList() {\n if (this.files.length === 0) return nothing;\n\n return html`\n <div\n class=\"file-upload__file-list\"\n part=\"file-list\"\n role=\"list\"\n aria-label=\"Selected files\"\n >\n ${this.files.map(\n (fileInfo) => html`\n <div\n class=\"file-upload__file-item\"\n part=\"file-item\"\n role=\"listitem\"\n >\n ${fileInfo.previewUrl\n ? html`\n <img\n class=\"file-upload__preview\"\n src=\"${fileInfo.previewUrl}\"\n alt=\"Preview of ${fileInfo.name}\"\n />\n `\n : html`\n <div class=\"file-upload__file-icon\" aria-hidden=\"true\">\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path\n d=\"M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z\"\n />\n <polyline points=\"14 2 14 8 20 8\" />\n </svg>\n </div>\n `}\n <div class=\"file-upload__file-info\">\n <span class=\"file-upload__file-name\" part=\"file-name\"\n >${fileInfo.name}</span\n >\n <span class=\"file-upload__file-size\" part=\"file-size\"\n >${this.formatFileSize(fileInfo.size)}</span\n >\n </div>\n <button\n type=\"button\"\n class=\"file-upload__remove-button\"\n part=\"file-remove\"\n @click=${(e: Event) => this.handleRemoveFile(e, fileInfo.id)}\n aria-label=\"Remove ${fileInfo.name}\"\n ?disabled=${this.disabled}\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n </button>\n </div>\n `\n )}\n </div>\n `;\n }\n\n render() {\n const dropzoneClasses = {\n 'file-upload__dropzone': true,\n 'file-upload__dropzone--drag-over': this.isDragOver,\n 'file-upload__dropzone--disabled': this.disabled,\n 'file-upload__dropzone--has-files': this.files.length > 0,\n [`file-upload__dropzone--${this.variant}`]: this.variant !== 'default',\n [`file-upload__dropzone--${this.size}`]: true,\n };\n\n const acceptDescription = this.accept\n ? `Accepted file types: ${this.accept}`\n : '';\n const sizeDescription =\n this.maxSize > 0\n ? `Maximum file size: ${this.formatFileSize(this.maxSize)}`\n : '';\n\n return html`\n <div class=\"file-upload\">\n <div\n class=${classMap(dropzoneClasses)}\n part=\"dropzone\"\n role=\"button\"\n tabindex=${this.disabled ? -1 : 0}\n aria-disabled=${this.disabled}\n aria-describedby=\"file-upload-description\"\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n @dragenter=${this.handleDragEnter}\n @dragover=${this.handleDragOver}\n @dragleave=${this.handleDragLeave}\n @drop=${this.handleDrop}\n >\n <input\n type=\"file\"\n part=\"input\"\n .name=${this.name}\n .accept=${this.accept}\n ?multiple=${this.multiple}\n ?disabled=${this.disabled}\n ?required=${this.required}\n @change=${this.handleInputChange}\n aria-hidden=\"true\"\n tabindex=\"-1\"\n />\n\n ${this.renderUploadIcon()}\n\n <span class=\"file-upload__label\" part=\"label\">${this.label}</span>\n\n ${this.description\n ? html`<span class=\"file-upload__description\" part=\"description\"\n >${this.description}</span\n >`\n : nothing}\n </div>\n\n <span id=\"file-upload-description\" class=\"visually-hidden\">\n ${acceptDescription} ${sizeDescription}\n </span>\n\n ${this.renderFileList()}\n ${this.message\n ? html`<div\n class=\"file-upload__message file-upload__message--${this.variant}\"\n part=\"message\"\n >\n ${this.message}\n </div>`\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bp-file-upload': BpFileUpload;\n }\n}\n"],"names":["fileUploadStyles","css","BpFileUpload","LitElement","fileInfo","fileId","fileIndex","f","removedFile","event","input","relatedTarget","dataTransfer","newFiles","validFiles","file","existingFile","acceptedTypes","type","fileType","fileExtension","accepted","category","reason","bytes","units","exponent","html","nothing","e","dropzoneClasses","acceptDescription","sizeDescription","classMap","__decorateClass","property","booleanConverter","state","query","customElement"],"mappings":";;;;AAEO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
@@ -42,4 +42,7 @@ export { BpDrawer, type DrawerPlacement, type DrawerSize, } from './drawer/drawe
42
42
  export { BpPopover, type PopoverPlacement, type PopoverTrigger, } from './popover/popover.js';
43
43
  export { BpColorPicker } from './color-picker/color-picker.js';
44
44
  export { BpStepper } from './stepper/stepper.js';
45
+ export { BpCodeBlock } from './code-block/code-block.js';
46
+ export type { CodeBlockHighlightAdapter, HighlightResult, } from './code-block/code-block.js';
47
+ export { plainTextAdapter } from './code-block/code-block.js';
45
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/components/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../source/components/index.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","sources":["../../source/components/menu/menu.style.ts","../../source/components/menu/menu.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menuStyles = css`\n /* Base styles - Menu Container */\n :host {\n display: block;\n }\n\n .menu {\n display: flex;\n flex-direction: column;\n min-width: 200px;\n padding: var(--bp-spacing-xs) 0;\n margin: 0;\n background-color: var(--bp-color-surface-elevated);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n box-shadow: var(--bp-shadow-lg);\n font-family: var(--bp-font-sans);\n list-style: none;\n outline: none;\n }\n\n /* Menu Sizes */\n .menu--sm {\n min-width: 160px;\n }\n\n .menu--lg {\n min-width: 280px;\n }\n\n /* Menu Item Base */\n .menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n margin: 0 var(--bp-spacing-xs);\n min-height: 40px;\n border-radius: var(--bp-border-radius-sm);\n background-color: transparent;\n color: var(--bp-color-text);\n font-family: var(--bp-font-sans);\n font-size: var(--bp-font-size-base);\n font-weight: var(--bp-font-weight-normal);\n line-height: var(--bp-line-height-normal);\n text-decoration: none;\n cursor: pointer;\n transition:\n background-color var(--bp-transition-fast),\n transform var(--bp-transition-fast);\n user-select: none;\n outline: none;\n }\n\n /* Menu Item Sizes */\n .menu-item--sm {\n padding: var(--bp-spacing-sm) var(--bp-spacing-sm);\n min-height: 36px;\n font-size: var(--bp-font-size-sm);\n }\n\n .menu-item--lg {\n padding: var(--bp-spacing-md) var(--bp-spacing-lg);\n min-height: 48px;\n font-size: var(--bp-font-size-lg);\n }\n\n /* Menu Item States */\n .menu-item:hover:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n }\n\n .menu-item:focus-visible:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-primary);\n outline-offset: var(--bp-focus-offset);\n }\n\n .menu-item:active:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n transform: scale(0.98);\n }\n\n .menu-item--selected {\n background-color: var(--bp-color-surface);\n font-weight: var(--bp-font-weight-medium);\n }\n\n .menu-item--selected::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background-color: var(--bp-color-primary);\n border-radius: 0 var(--bp-border-radius-sm) var(--bp-border-radius-sm) 0;\n }\n\n .menu-item--disabled {\n color: var(--bp-color-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n /* Menu Item Parts */\n .menu-item__prefix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .menu-item__prefix:empty {\n display: none;\n }\n\n .menu-item__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .menu-item__suffix {\n display: inline-flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n flex-shrink: 0;\n margin-left: auto;\n }\n\n .menu-item__suffix:empty {\n display: none;\n }\n\n .menu-item__shortcut {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-sm);\n font-family: var(--bp-font-mono);\n padding: 2px var(--bp-spacing-xs);\n background-color: var(--bp-color-surface);\n border-radius: var(--bp-border-radius-sm);\n border: var(--bp-border-width) solid var(--bp-color-border);\n }\n\n .menu-item__arrow {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-lg);\n line-height: 1;\n }\n\n /* Menu Divider */\n .menu-divider {\n height: var(--bp-border-width);\n margin: var(--bp-spacing-sm) var(--bp-spacing-sm);\n background-color: var(--bp-color-border);\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\nimport { menuStyles } from './menu.style.js';\r\n\r\nexport type MenuSize = 'sm' | 'md' | 'lg';\r\n\r\n/**\r\n * A menu container component for displaying a list of actions or options.\r\n *\r\n * @fires bp-menu-select - Dispatched when a menu item is selected\r\n *\r\n * @slot - Menu items (bp-menu-item, bp-menu-divider)\r\n *\r\n * @csspart container - The menu container element\r\n */\r\n@customElement('bp-menu')\r\nexport class BpMenu extends LitElement {\r\n /** Size variant for all menu items */\r\n @property({ type: String }) declare size: MenuSize;\r\n\r\n /** Current focused item index for keyboard navigation */\r\n @state() private focusedIndex = -1;\r\n\r\n static styles = [menuStyles];\r\n\r\n constructor() {\r\n super();\r\n this.size = 'md';\r\n }\r\n\r\n private handleFocusIn = (event: FocusEvent) => {\r\n const target = event.target as BpMenuItem;\r\n const items = this.menuItems;\r\n this.focusedIndex = items.indexOf(target);\r\n };\r\n\r\n connectedCallback() {\r\n super.connectedCallback();\r\n this.addEventListener('focusin', this.handleFocusIn);\r\n }\r\n\r\n disconnectedCallback() {\r\n super.disconnectedCallback();\r\n this.removeEventListener('focusin', this.handleFocusIn);\r\n }\r\n\r\n /**\r\n * Gets all non-divider menu items from the default slot.\r\n * @returns Array of bp-menu-item elements\r\n */\r\n private get menuItems(): BpMenuItem[] {\r\n const slot = this.shadowRoot?.querySelector('slot');\r\n if (!slot) return [];\r\n return slot\r\n .assignedElements()\r\n .filter((el): el is BpMenuItem => el.tagName === 'BP-MENU-ITEM');\r\n }\r\n\r\n /**\r\n * Handles keyboard navigation within the menu.\r\n * Supports ArrowDown, ArrowUp, Home, and End keys.\r\n */\r\n private handleKeyDown(event: KeyboardEvent) {\r\n const items = this.menuItems.filter((item) => !item.disabled);\r\n if (items.length === 0) return;\r\n\r\n switch (event.key) {\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n this.focusedIndex = Math.min(this.focusedIndex + 1, items.length - 1);\r\n items[this.focusedIndex]?.focus();\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n this.focusedIndex = Math.max(this.focusedIndex - 1, 0);\r\n items[this.focusedIndex]?.focus();\r\n break;\r\n case 'Home':\r\n event.preventDefault();\r\n this.focusedIndex = 0;\r\n items[0]?.focus();\r\n break;\r\n case 'End':\r\n event.preventDefault();\r\n this.focusedIndex = items.length - 1;\r\n items[items.length - 1]?.focus();\r\n break;\r\n }\r\n }\r\n\r\n private handleSlotChange() {\r\n // Update size on all menu items\r\n this.menuItems.forEach((item) => {\r\n item.size = this.size;\r\n });\r\n }\r\n\r\n render() {\r\n return html`\r\n <div\r\n class=\"menu menu--${this.size}\"\r\n part=\"container\"\r\n role=\"menu\"\r\n @keydown=${this.handleKeyDown}\r\n >\r\n <slot @slotchange=${this.handleSlotChange}></slot>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\n/**\r\n * A menu item component for use within bp-menu.\r\n *\r\n * @fires bp-select - Dispatched when the item is selected\r\n *\r\n * @slot - Item label content\r\n * @slot prefix - Content before the label (typically an icon)\r\n * @slot suffix - Content after the label (typically a shortcut or arrow)\r\n *\r\n * @csspart base - The menu item container\r\n * @csspart prefix - The prefix slot container\r\n * @csspart label - The label container\r\n * @csspart suffix - The suffix slot container\r\n */\r\n@customElement('bp-menu-item')\r\nexport class BpMenuItem extends LitElement {\r\n /** The value associated with this menu item */\r\n @property({ type: String }) declare value: string;\r\n\r\n /** Whether the item is disabled */\r\n @property({ type: Boolean }) declare disabled: boolean;\r\n\r\n /** Whether the item is selected/active */\r\n @property({ type: Boolean }) declare selected: boolean;\r\n\r\n /** Whether the item has a submenu */\r\n @property({ type: Boolean, attribute: 'has-submenu' })\r\n declare hasSubmenu: boolean;\r\n\r\n /** Size variant (inherited from parent menu) */\r\n @property({ type: String }) declare size: MenuSize;\r\n\r\n /** Keyboard shortcut hint to display */\r\n @property({ type: String }) declare shortcut: string;\r\n\r\n static styles = [menuStyles];\r\n\r\n constructor() {\r\n super();\r\n this.value = '';\r\n this.disabled = false;\r\n this.selected = false;\r\n this.hasSubmenu = false;\r\n this.size = 'md';\r\n this.shortcut = '';\r\n }\r\n\r\n focus() {\r\n const button = this.shadowRoot?.querySelector('.menu-item') as HTMLElement;\r\n button?.focus();\r\n }\r\n\r\n private handleActivate() {\r\n if (this.disabled) return;\r\n\r\n this.dispatchEvent(\r\n new CustomEvent('bp-menu-select', {\r\n detail: { value: this.value },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n }\r\n\r\n private handleClick(event: MouseEvent) {\r\n if (this.disabled) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n return;\r\n }\r\n\r\n this.handleActivate();\r\n }\r\n\r\n private handleKeyDown(event: KeyboardEvent) {\r\n if (event.key === 'Enter' || event.key === ' ') {\r\n event.preventDefault();\r\n this.handleActivate();\r\n }\r\n }\r\n\r\n render() {\r\n return html`\r\n <div\r\n class=\"menu-item menu-item--${this.size} ${this.disabled\r\n ? 'menu-item--disabled'\r\n : ''} ${this.selected ? 'menu-item--selected' : ''}\"\r\n part=\"base\"\r\n role=\"menuitem\"\r\n tabindex=${this.disabled ? -1 : 0}\r\n aria-disabled=${this.disabled}\r\n aria-current=${this.selected ? 'page' : 'false'}\r\n @click=${this.handleClick}\r\n @keydown=${this.handleKeyDown}\r\n >\r\n <span class=\"menu-item__prefix\" part=\"prefix\">\r\n <slot name=\"prefix\"></slot>\r\n </span>\r\n <span class=\"menu-item__label\" part=\"label\">\r\n <slot></slot>\r\n </span>\r\n <span class=\"menu-item__suffix\" part=\"suffix\">\r\n ${this.shortcut\r\n ? html`<span class=\"menu-item__shortcut\">${this.shortcut}</span>`\r\n : nothing}\r\n <slot name=\"suffix\"></slot>\r\n ${this.hasSubmenu\r\n ? html`<span class=\"menu-item__arrow\">›</span>`\r\n : nothing}\r\n </span>\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\n/**\r\n * A divider for visually separating menu items.\r\n *\r\n * @csspart divider - The divider element\r\n */\r\n@customElement('bp-menu-divider')\r\nexport class BpMenuDivider extends LitElement {\r\n static styles = [menuStyles];\r\n\r\n render() {\r\n return html`<div\r\n class=\"menu-divider\"\r\n part=\"divider\"\r\n role=\"separator\"\r\n ></div>`;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'bp-menu': BpMenu;\r\n 'bp-menu-item': BpMenuItem;\r\n 'bp-menu-divider': BpMenuDivider;\r\n }\r\n}\r\n"],"names":["menuStyles","css","BpMenu","LitElement","event","target","items","slot","el","item","html","__decorateClass","property","state","customElement","BpMenuItem","nothing","BpMenuDivider"],"mappings":";;AAEO,MAAMA,IAAaC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACcnB,IAAMC,IAAN,cAAqBC,EAAW;AAAA,EASrC,cAAc;AACZ,UAAA,GALO,KAAQ,eAAe,IAShC,KAAQ,gBAAgB,CAACC,MAAsB;AAC7C,YAAMC,IAASD,EAAM,QACfE,IAAQ,KAAK;AACnB,WAAK,eAAeA,EAAM,QAAQD,CAAM;AAAA,IAC1C,GAPE,KAAK,OAAO;AAAA,EACd;AAAA,EAQA,oBAAoB;AAClB,UAAM,kBAAA,GACN,KAAK,iBAAiB,WAAW,KAAK,aAAa;AAAA,EACrD;AAAA,EAEA,uBAAuB;AACrB,UAAM,qBAAA,GACN,KAAK,oBAAoB,WAAW,KAAK,aAAa;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAY,YAA0B;AACpC,UAAME,IAAO,KAAK,YAAY,cAAc,MAAM;AAClD,WAAKA,IACEA,EACJ,mBACA,OAAO,CAACC,MAAyBA,EAAG,YAAY,cAAc,IAH/C,CAAA;AAAA,EAIpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,cAAcJ,GAAsB;AAC1C,UAAME,IAAQ,KAAK,UAAU,OAAO,CAACG,MAAS,CAACA,EAAK,QAAQ;AAC5D,QAAIH,EAAM,WAAW;AAErB,cAAQF,EAAM,KAAA;AAAA,QACZ,KAAK;AACH,UAAAA,EAAM,eAAA,GACN,KAAK,eAAe,KAAK,IAAI,KAAK,eAAe,GAAGE,EAAM,SAAS,CAAC,GACpEA,EAAM,KAAK,YAAY,GAAG,MAAA;AAC1B;AAAA,QACF,KAAK;AACH,UAAAF,EAAM,eAAA,GACN,KAAK,eAAe,KAAK,IAAI,KAAK,eAAe,GAAG,CAAC,GACrDE,EAAM,KAAK,YAAY,GAAG,MAAA;AAC1B;AAAA,QACF,KAAK;AACH,UAAAF,EAAM,eAAA,GACN,KAAK,eAAe,GACpBE,EAAM,CAAC,GAAG,MAAA;AACV;AAAA,QACF,KAAK;AACH,UAAAF,EAAM,eAAA,GACN,KAAK,eAAeE,EAAM,SAAS,GACnCA,EAAMA,EAAM,SAAS,CAAC,GAAG,MAAA;AACzB;AAAA,MAAA;AAAA,EAEN;AAAA,EAEQ,mBAAmB;AAEzB,SAAK,UAAU,QAAQ,CAACG,MAAS;AAC/B,MAAAA,EAAK,OAAO,KAAK;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,SAAS;AACP,WAAOC;AAAA;AAAA,4BAEiB,KAAK,IAAI;AAAA;AAAA;AAAA,mBAGlB,KAAK,aAAa;AAAA;AAAA,4BAET,KAAK,gBAAgB;AAAA;AAAA;AAAA,EAG/C;AACF;AA7FaR,EAOJ,SAAS,CAACF,CAAU;AALSW,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAFfV,EAEyB,WAAA,QAAA,CAAA;AAGnBS,EAAA;AAAA,EAAhBE,EAAA;AAAM,GALIX,EAKM,WAAA,gBAAA,CAAA;AALNA,IAANS,EAAA;AAAA,EADNG,EAAc,SAAS;AAAA,GACXZ,CAAA;AA8GN,IAAMa,IAAN,cAAyBZ,EAAW;AAAA,EAsBzC,cAAc;AACZ,UAAA,GACA,KAAK,QAAQ,IACb,KAAK,WAAW,IAChB,KAAK,WAAW,IAChB,KAAK,aAAa,IAClB,KAAK,OAAO,MACZ,KAAK,WAAW;AAAA,EAClB;AAAA,EAEA,QAAQ;AAEN,IADe,KAAK,YAAY,cAAc,YAAY,GAClD,MAAA;AAAA,EACV;AAAA,EAEQ,iBAAiB;AACvB,IAAI,KAAK,YAET,KAAK;AAAA,MACH,IAAI,YAAY,kBAAkB;AAAA,QAChC,QAAQ,EAAE,OAAO,KAAK,MAAA;AAAA,QACtB,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAAA,EAEL;AAAA,EAEQ,YAAYC,GAAmB;AACrC,QAAI,KAAK,UAAU;AACjB,MAAAA,EAAM,eAAA,GACNA,EAAM,gBAAA;AACN;AAAA,IACF;AAEA,SAAK,eAAA;AAAA,EACP;AAAA,EAEQ,cAAcA,GAAsB;AAC1C,KAAIA,EAAM,QAAQ,WAAWA,EAAM,QAAQ,SACzCA,EAAM,eAAA,GACN,KAAK,eAAA;AAAA,EAET;AAAA,EAEA,SAAS;AACP,WAAOM;AAAA;AAAA,sCAE2B,KAAK,IAAI,IAAI,KAAK,WAC5C,wBACA,EAAE,IAAI,KAAK,WAAW,wBAAwB,EAAE;AAAA;AAAA;AAAA,mBAGzC,KAAK,WAAW,KAAK,CAAC;AAAA,wBACjB,KAAK,QAAQ;AAAA,uBACd,KAAK,WAAW,SAAS,OAAO;AAAA,iBACtC,KAAK,WAAW;AAAA,mBACd,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASzB,KAAK,WACHA,sCAAyC,KAAK,QAAQ,YACtDM,CAAO;AAAA;AAAA,YAET,KAAK,aACHN,6CACAM,CAAO;AAAA;AAAA;AAAA;AAAA,EAInB;AACF;AAlGaD,EAoBJ,SAAS,CAACf,CAAU;AAlBSW,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAFfG,EAEyB,WAAA,SAAA,CAAA;AAGCJ,EAAA;AAAA,EAApCC,EAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GALhBG,EAK0B,WAAA,YAAA,CAAA;AAGAJ,EAAA;AAAA,EAApCC,EAAS,EAAE,MAAM,QAAA,CAAS;AAAA,GARhBG,EAQ0B,WAAA,YAAA,CAAA;AAI7BJ,EAAA;AAAA,EADPC,EAAS,EAAE,MAAM,SAAS,WAAW,eAAe;AAAA,GAX1CG,EAYH,WAAA,cAAA,CAAA;AAG4BJ,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAffG,EAeyB,WAAA,QAAA,CAAA;AAGAJ,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAlBfG,EAkByB,WAAA,YAAA,CAAA;AAlBzBA,IAANJ,EAAA;AAAA,EADNG,EAAc,cAAc;AAAA,GAChBC,CAAA;AA0GN,IAAME,IAAN,cAA4Bd,EAAW;AAAA,EAG5C,SAAS;AACP,WAAOO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKT;AACF;AAVaO,EACJ,SAAS,CAACjB,CAAU;AADhBiB,IAANN,EAAA;AAAA,EADNG,EAAc,iBAAiB;AAAA,GACnBG,CAAA;"}
1
+ {"version":3,"file":"menu.js","sources":["../../source/components/menu/menu.style.ts","../../source/components/menu/menu.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const menuStyles = css`\n /* Base styles - Menu Container */\n :host {\n display: block;\n }\n\n .menu {\n display: flex;\n flex-direction: column;\n min-width: 200px;\n padding: var(--bp-spacing-xs) 0;\n margin: 0;\n background-color: var(--bp-color-surface-elevated);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n box-shadow: var(--bp-shadow-lg);\n font-family: var(--bp-font-sans);\n list-style: none;\n outline: none;\n }\n\n /* Menu Sizes */\n .menu--sm {\n min-width: 160px;\n }\n\n .menu--lg {\n min-width: 280px;\n }\n\n /* Menu Item Base */\n .menu-item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n margin: 0 var(--bp-spacing-xs);\n min-height: 40px;\n border-radius: var(--bp-border-radius-sm);\n background-color: transparent;\n color: var(--bp-color-text);\n font-family: var(--bp-font-sans);\n font-size: var(--bp-font-size-base);\n font-weight: var(--bp-font-weight-normal);\n line-height: var(--bp-line-height-normal);\n text-decoration: none;\n cursor: pointer;\n transition:\n background-color var(--bp-transition-fast),\n transform var(--bp-transition-fast);\n user-select: none;\n outline: none;\n }\n\n /* Menu Item Sizes */\n .menu-item--sm {\n padding: var(--bp-spacing-sm) var(--bp-spacing-sm);\n min-height: 36px;\n font-size: var(--bp-font-size-sm);\n }\n\n .menu-item--lg {\n padding: var(--bp-spacing-md) var(--bp-spacing-lg);\n min-height: 48px;\n font-size: var(--bp-font-size-lg);\n }\n\n /* Menu Item States */\n .menu-item:hover:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n }\n\n .menu-item:focus-visible:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-primary);\n outline-offset: var(--bp-focus-offset);\n }\n\n .menu-item:active:not(.menu-item--disabled) {\n background-color: var(--bp-color-surface);\n transform: scale(0.98);\n }\n\n .menu-item--selected {\n background-color: var(--bp-color-surface);\n font-weight: var(--bp-font-weight-medium);\n }\n\n .menu-item--selected::before {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n width: 3px;\n background-color: var(--bp-color-primary);\n border-radius: 0 var(--bp-border-radius-sm) var(--bp-border-radius-sm) 0;\n }\n\n .menu-item--disabled {\n color: var(--bp-color-text-muted);\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n /* Menu Item Parts */\n .menu-item__prefix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .menu-item__prefix:empty {\n display: none;\n }\n\n .menu-item__label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .menu-item__suffix {\n display: inline-flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n flex-shrink: 0;\n margin-left: auto;\n }\n\n .menu-item__suffix:empty {\n display: none;\n }\n\n .menu-item__shortcut {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-sm);\n font-family: var(--bp-font-mono);\n padding: 2px var(--bp-spacing-xs);\n background-color: var(--bp-color-surface);\n border-radius: var(--bp-border-radius-sm);\n border: var(--bp-border-width) solid var(--bp-color-border);\n }\n\n .menu-item__arrow {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-lg);\n line-height: 1;\n }\n\n /* Menu Divider */\n .menu-divider {\n height: var(--bp-border-width);\n margin: var(--bp-spacing-sm) var(--bp-spacing-sm);\n background-color: var(--bp-color-border);\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { menuStyles } from './menu.style.js';\n\nexport type MenuSize = 'sm' | 'md' | 'lg';\n\n/**\n * A menu container component for displaying a list of actions or options.\n *\n * @fires bp-menu-select - Dispatched when a menu item is selected\n *\n * @slot - Menu items (bp-menu-item, bp-menu-divider)\n *\n * @csspart container - The menu container element\n */\n@customElement('bp-menu')\nexport class BpMenu extends LitElement {\n /** Size variant for all menu items */\n @property({ type: String }) declare size: MenuSize;\n\n /** Current focused item index for keyboard navigation */\n @state() private focusedIndex = -1;\n\n static styles = [menuStyles];\n\n constructor() {\n super();\n this.size = 'md';\n }\n\n private handleFocusIn = (event: FocusEvent) => {\n const target = event.target as BpMenuItem;\n const items = this.menuItems;\n this.focusedIndex = items.indexOf(target);\n };\n\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('focusin', this.handleFocusIn);\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('focusin', this.handleFocusIn);\n }\n\n /**\n * Gets all non-divider menu items from the default slot.\n * @returns Array of bp-menu-item elements\n */\n private get menuItems(): BpMenuItem[] {\n const slot = this.shadowRoot?.querySelector('slot');\n if (!slot) return [];\n return slot\n .assignedElements()\n .filter((el): el is BpMenuItem => el.tagName === 'BP-MENU-ITEM');\n }\n\n /**\n * Handles keyboard navigation within the menu.\n * Supports ArrowDown, ArrowUp, Home, and End keys.\n */\n private handleKeyDown(event: KeyboardEvent) {\n const items = this.menuItems.filter((item) => !item.disabled);\n if (items.length === 0) return;\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.focusedIndex = Math.min(this.focusedIndex + 1, items.length - 1);\n items[this.focusedIndex]?.focus();\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusedIndex = Math.max(this.focusedIndex - 1, 0);\n items[this.focusedIndex]?.focus();\n break;\n case 'Home':\n event.preventDefault();\n this.focusedIndex = 0;\n items[0]?.focus();\n break;\n case 'End':\n event.preventDefault();\n this.focusedIndex = items.length - 1;\n items[items.length - 1]?.focus();\n break;\n }\n }\n\n private handleSlotChange() {\n // Update size on all menu items\n this.menuItems.forEach((item) => {\n item.size = this.size;\n });\n }\n\n render() {\n return html`\n <div\n class=\"menu menu--${this.size}\"\n part=\"container\"\n role=\"menu\"\n @keydown=${this.handleKeyDown}\n >\n <slot @slotchange=${this.handleSlotChange}></slot>\n </div>\n `;\n }\n}\n\n/**\n * A menu item component for use within bp-menu.\n *\n * @fires bp-select - Dispatched when the item is selected\n *\n * @slot - Item label content\n * @slot prefix - Content before the label (typically an icon)\n * @slot suffix - Content after the label (typically a shortcut or arrow)\n *\n * @csspart base - The menu item container\n * @csspart prefix - The prefix slot container\n * @csspart label - The label container\n * @csspart suffix - The suffix slot container\n */\n@customElement('bp-menu-item')\nexport class BpMenuItem extends LitElement {\n /** The value associated with this menu item */\n @property({ type: String }) declare value: string;\n\n /** Whether the item is disabled */\n @property({ type: Boolean }) declare disabled: boolean;\n\n /** Whether the item is selected/active */\n @property({ type: Boolean }) declare selected: boolean;\n\n /** Whether the item has a submenu */\n @property({ type: Boolean, attribute: 'has-submenu' })\n declare hasSubmenu: boolean;\n\n /** Size variant (inherited from parent menu) */\n @property({ type: String }) declare size: MenuSize;\n\n /** Keyboard shortcut hint to display */\n @property({ type: String }) declare shortcut: string;\n\n static styles = [menuStyles];\n\n constructor() {\n super();\n this.value = '';\n this.disabled = false;\n this.selected = false;\n this.hasSubmenu = false;\n this.size = 'md';\n this.shortcut = '';\n }\n\n focus() {\n const button = this.shadowRoot?.querySelector('.menu-item') as HTMLElement;\n button?.focus();\n }\n\n private handleActivate() {\n if (this.disabled) return;\n\n this.dispatchEvent(\n new CustomEvent('bp-menu-select', {\n detail: { value: this.value },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleClick(event: MouseEvent) {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n this.handleActivate();\n }\n\n private handleKeyDown(event: KeyboardEvent) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.handleActivate();\n }\n }\n\n render() {\n return html`\n <div\n class=\"menu-item menu-item--${this.size} ${this.disabled\n ? 'menu-item--disabled'\n : ''} ${this.selected ? 'menu-item--selected' : ''}\"\n part=\"base\"\n role=\"menuitem\"\n tabindex=${this.disabled ? -1 : 0}\n aria-disabled=${this.disabled}\n aria-current=${this.selected ? 'page' : 'false'}\n @click=${this.handleClick}\n @keydown=${this.handleKeyDown}\n >\n <span class=\"menu-item__prefix\" part=\"prefix\">\n <slot name=\"prefix\"></slot>\n </span>\n <span class=\"menu-item__label\" part=\"label\">\n <slot></slot>\n </span>\n <span class=\"menu-item__suffix\" part=\"suffix\">\n ${this.shortcut\n ? html`<span class=\"menu-item__shortcut\">${this.shortcut}</span>`\n : nothing}\n <slot name=\"suffix\"></slot>\n ${this.hasSubmenu\n ? html`<span class=\"menu-item__arrow\">›</span>`\n : nothing}\n </span>\n </div>\n `;\n }\n}\n\n/**\n * A divider for visually separating menu items.\n *\n * @csspart divider - The divider element\n */\n@customElement('bp-menu-divider')\nexport class BpMenuDivider extends LitElement {\n static styles = [menuStyles];\n\n render() {\n return html`<div\n class=\"menu-divider\"\n part=\"divider\"\n role=\"separator\"\n ></div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bp-menu': BpMenu;\n 'bp-menu-item': BpMenuItem;\n 'bp-menu-divider': BpMenuDivider;\n }\n}\n"],"names":["menuStyles","css","BpMenu","LitElement","event","target","items","slot","el","item","html","__decorateClass","property","state","customElement","BpMenuItem","nothing","BpMenuDivider"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"multi-select.js","sources":["../../source/components/multi-select/multi-select.style.ts","../../source/components/multi-select/multi-select.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const multiSelectStyles = css`\n /* Base styles */\n :host {\n display: block;\n font-family: var(--bp-font-family);\n }\n\n .multi-select {\n position: relative;\n width: 100%;\n }\n\n .multi-select__control {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--bp-spacing-sm);\n min-height: var(--bp-spacing-10);\n padding: var(--bp-spacing-xs) var(--bp-spacing-sm);\n background-color: var(--bp-color-surface);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n cursor: pointer;\n transition: border-color var(--bp-transition-fast);\n }\n\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-primary);\n }\n\n .multi-select__control:focus-visible {\n outline: var(--bp-focus-width) solid var(--bp-color-focus);\n outline-offset: var(--bp-focus-width);\n }\n\n .multi-select__value-container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--bp-spacing-xs);\n flex: 1;\n min-width: 0;\n }\n\n .multi-select__placeholder {\n color: var(--bp-color-text-muted);\n user-select: none;\n }\n\n .multi-select__tag {\n display: inline-flex;\n align-items: center;\n gap: var(--bp-spacing-xs);\n padding: var(--bp-spacing-2xs) var(--bp-spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 8%,\n transparent\n );\n color: var(--bp-color-primary);\n border: none;\n border-radius: var(--bp-border-radius-md);\n font-size: var(--bp-font-size-sm);\n max-width: 100%;\n }\n\n .multi-select__tag-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .multi-select__tag-remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-primary);\n cursor: pointer;\n font-size: var(--bp-font-size-lg);\n line-height: 1;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__tag-remove:hover {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 15%,\n transparent\n );\n color: var(--bp-color-primary);\n }\n\n .multi-select__tag-remove:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .multi-select__indicators {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-xs);\n flex-shrink: 0;\n }\n\n .multi-select__clear {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-6);\n height: var(--bp-spacing-6);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-text-muted);\n cursor: pointer;\n font-size: var(--bp-font-size-xl);\n line-height: 1;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__clear:hover {\n background-color: var(--bp-color-surface-subdued);\n color: var(--bp-color-text);\n }\n\n .multi-select__clear:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .multi-select__dropdown-indicator {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-xs);\n transition: transform var(--bp-transition-fast);\n user-select: none;\n }\n\n .multi-select--open .multi-select__dropdown-indicator {\n transform: rotate(180deg);\n }\n\n .multi-select__dropdown {\n position: absolute;\n top: calc(100% + var(--bp-spacing-xs));\n left: 0;\n right: 0;\n z-index: var(--bp-z-dropdown);\n background-color: var(--bp-color-surface);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n box-shadow: var(--bp-shadow-md);\n max-height: calc(var(--bp-spacing-10) * 6);\n overflow-y: auto;\n opacity: 0;\n visibility: hidden;\n transform: translateY(calc(-1 * var(--bp-spacing-md)));\n transition:\n opacity var(--bp-transition-fast),\n transform var(--bp-transition-fast),\n visibility var(--bp-transition-fast);\n contain: layout style paint;\n }\n\n .multi-select--open .multi-select__dropdown {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .multi-select__options {\n list-style: none;\n margin: 0;\n padding: var(--bp-spacing-2xs);\n }\n\n .multi-select__option {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n cursor: pointer;\n border-radius: var(--bp-border-radius-md);\n transition:\n background-color var(--bp-transition-fast),\n color var(--bp-transition-fast);\n }\n\n .multi-select__option:hover {\n background-color: var(--bp-color-surface-elevated);\n }\n\n .multi-select__option--focused {\n background-color: var(--bp-color-surface-subdued);\n outline: var(--bp-focus-width) solid var(--bp-color-primary);\n outline-offset: calc(-1 * var(--bp-focus-width));\n }\n\n .multi-select__option--selected {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 8%,\n transparent\n );\n color: var(--bp-color-primary);\n }\n\n .multi-select__option--selected:hover {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 12%,\n transparent\n );\n }\n\n .multi-select__option--empty {\n color: var(--bp-color-text-muted);\n cursor: default;\n text-align: center;\n padding: var(--bp-spacing-xl) var(--bp-spacing-lg);\n font-style: italic;\n }\n\n .multi-select__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-sm);\n font-size: var(--bp-font-size-xs);\n flex-shrink: 0;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__option--selected .multi-select__checkbox {\n border-color: var(--bp-color-primary);\n background-color: var(--bp-color-primary);\n color: var(--bp-color-text-inverse);\n }\n\n .multi-select__option-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Sizes */\n .multi-select--sm .multi-select__control {\n min-height: var(--bp-spacing-8);\n padding: var(--bp-spacing-2xs) var(--bp-spacing-xs);\n font-size: var(--bp-font-size-sm);\n }\n\n .multi-select--sm .multi-select__tag {\n padding: var(--bp-spacing-0-5) var(--bp-spacing-2xs);\n font-size: var(--bp-font-size-xs);\n }\n\n .multi-select--lg .multi-select__control {\n min-height: var(--bp-spacing-12);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n font-size: var(--bp-font-size-lg);\n }\n\n .multi-select--lg .multi-select__tag {\n padding: var(--bp-spacing-xs) var(--bp-spacing-sm);\n font-size: var(--bp-font-size-base);\n }\n\n /* Variants */\n .multi-select--default .multi-select__control {\n border-color: var(--bp-color-border);\n }\n\n .multi-select--success .multi-select__control {\n border-color: var(--bp-color-success);\n }\n\n .multi-select--error .multi-select__control {\n border-color: var(--bp-color-error);\n }\n\n .multi-select--warning .multi-select__control {\n border-color: var(--bp-color-warning);\n }\n\n .multi-select--info .multi-select__control {\n border-color: var(--bp-color-info);\n }\n\n .multi-select--success\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-success);\n }\n\n .multi-select--error\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-error);\n }\n\n .multi-select--warning\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-warning);\n }\n\n .multi-select--info\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-info);\n }\n\n /* States */\n .multi-select--disabled .multi-select__control {\n background-color: var(--bp-color-surface-subdued);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .multi-select--disabled .multi-select__placeholder {\n color: var(--bp-color-text-muted);\n }\n\n /* Hide slot */\n slot {\n display: none;\n }\n\n /* Hide hidden inputs */\n input[type='hidden'] {\n display: none;\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\nimport { classMap } from 'lit/directives/class-map.js';\r\nimport { repeat } from 'lit/directives/repeat.js';\r\nimport { multiSelectStyles } from './multi-select.style.js';\r\nimport { memoizeOne } from '../../utilities/memoize.js';\r\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\r\n\r\nexport type MultiSelectSize = 'sm' | 'md' | 'lg';\r\nexport type MultiSelectVariant =\r\n | 'default'\r\n | 'success'\r\n | 'error'\r\n | 'warning'\r\n | 'info';\r\n\r\nexport interface MultiSelectOption {\r\n value: string;\r\n label: string;\r\n}\r\n\r\n@customElement('bp-multi-select')\r\nexport class BpMultiSelect extends LitElement {\r\n /** The current selected values as an array */\r\n @property({ type: Array }) declare value: string[];\r\n\r\n /** Name attribute for form submission */\r\n @property({ type: String }) declare name: string;\r\n\r\n /** Placeholder text when no values are selected */\r\n @property({ type: String }) declare placeholder: string;\r\n\r\n /** Whether the multi-select is disabled */\r\n @property({ type: Boolean, reflect: true }) declare disabled: boolean;\r\n\r\n /** Whether the multi-select is required */\r\n @property({ type: Boolean, reflect: true }) declare required: boolean;\r\n\r\n /** Size variant of the multi-select */\r\n @property({ type: String, reflect: true }) declare size: MultiSelectSize;\r\n\r\n /** Visual variant for validation states */\r\n @property({ type: String, reflect: true })\r\n declare variant: MultiSelectVariant;\r\n\r\n /** Maximum number of selections allowed (0 = unlimited) */\r\n @property({ type: Number, attribute: 'max-selections' })\r\n declare maxSelections: number;\r\n\r\n /** Whether to show a clear all button */\r\n @property({ converter: booleanConverter }) declare clearable: boolean;\r\n\r\n /** Whether the dropdown is currently open */\r\n @state() private isOpen = false;\r\n\r\n /** Index of the focused option for keyboard navigation */\r\n @state() private focusedIndex = -1;\r\n\r\n /** Cached options from slotted elements */\r\n @state() private cachedOptions: MultiSelectOption[] = [];\r\n\r\n /**\r\n * Memoized label lookup map for efficient tag rendering.\r\n * Only recomputes when cachedOptions reference changes.\r\n */\r\n private computeLabelMap = memoizeOne(\r\n (options: MultiSelectOption[]): Map<string, string> => {\r\n const map = new Map<string, string>();\r\n for (const opt of options) {\r\n map.set(opt.value, opt.label);\r\n }\r\n return map;\r\n }\r\n );\r\n\r\n static styles = [multiSelectStyles];\r\n\r\n constructor() {\r\n super();\r\n this.value = [];\r\n this.name = '';\r\n this.placeholder = 'Select options';\r\n this.disabled = false;\r\n this.required = false;\r\n this.size = 'md';\r\n this.variant = 'default';\r\n this.maxSelections = 0;\r\n this.clearable = true;\r\n }\r\n\r\n connectedCallback() {\r\n super.connectedCallback();\r\n document.addEventListener('click', this.handleDocumentClick, {\r\n passive: true,\r\n });\r\n // Initialize cached options and pre-selected values after first render\r\n this.updateComplete.then(() => {\r\n this.cachedOptions = this.getOptions();\r\n this.initializeSelectedValues();\r\n });\r\n }\r\n\r\n disconnectedCallback() {\r\n super.disconnectedCallback();\r\n document.removeEventListener('click', this.handleDocumentClick, {\r\n passive: true,\r\n } as EventListenerOptions);\r\n }\r\n\r\n private handleDocumentClick = (event: MouseEvent) => {\r\n if (!this.contains(event.target as globalThis.Node)) {\r\n this.isOpen = false;\r\n this.focusedIndex = -1;\r\n }\r\n };\r\n\r\n private handleToggle = (event?: Event) => {\r\n event?.stopPropagation();\r\n if (this.disabled) return;\r\n this.isOpen = !this.isOpen;\r\n if (this.isOpen) {\r\n this.focusedIndex = 0;\r\n }\r\n };\r\n\r\n private getOptions(): MultiSelectOption[] {\r\n const slot = this.shadowRoot?.querySelector('slot');\r\n const assignedElements = slot?.assignedElements() || [];\r\n const options = assignedElements.filter(\r\n (el): el is globalThis.HTMLOptionElement => el.tagName === 'OPTION'\r\n );\r\n\r\n return options.map((option) => ({\r\n value: option.value || option.textContent || '',\r\n label: option.textContent || '',\r\n }));\r\n }\r\n\r\n /**\r\n * Handle slot changes by refreshing the cached options.\r\n */\r\n private handleSlotChange = () => {\r\n this.cachedOptions = this.getOptions();\r\n this.initializeSelectedValues();\r\n };\r\n\r\n /**\r\n * Read the `selected` attribute from slotted <option> elements\r\n * and set the initial value array if no values are already set.\r\n */\r\n private initializeSelectedValues() {\r\n if (this.value.length > 0) return;\r\n\r\n const slot = this.shadowRoot?.querySelector('slot');\r\n const assignedElements = slot?.assignedElements() || [];\r\n const selectedValues = assignedElements\r\n .filter(\r\n (el): el is globalThis.HTMLOptionElement =>\r\n el.tagName === 'OPTION' && el.hasAttribute('selected')\r\n )\r\n .map((el) => el.value || el.textContent || '');\r\n\r\n if (selectedValues.length > 0) {\r\n this.value = selectedValues;\r\n }\r\n }\r\n\r\n private isSelected(value: string): boolean {\r\n return this.value.includes(value);\r\n }\r\n\r\n private dispatchChangeEvent(newValue: string[], previousValue: string[]) {\r\n this.dispatchEvent(\r\n new CustomEvent('bp-change', {\r\n detail: {\r\n value: newValue,\r\n previousValue,\r\n },\r\n bubbles: true,\r\n composed: true,\r\n })\r\n );\r\n }\r\n\r\n private handleOptionClick = (option: MultiSelectOption) => {\r\n if (this.disabled) return;\r\n\r\n const previousValue = [...this.value];\r\n let newValue: string[];\r\n\r\n if (this.isSelected(option.value)) {\r\n // Deselect — but prevent removing the last item when not clearable\r\n newValue = this.value.filter((v) => v !== option.value);\r\n if (!this.clearable && newValue.length === 0) {\r\n return;\r\n }\r\n } else {\r\n // Select (check max selections)\r\n if (this.maxSelections > 0 && this.value.length >= this.maxSelections) {\r\n return;\r\n }\r\n newValue = [...this.value, option.value];\r\n }\r\n\r\n this.value = newValue;\r\n this.dispatchChangeEvent(newValue, previousValue);\r\n };\r\n\r\n private handleRemoveTag = (value: string, event: Event) => {\r\n event.stopPropagation();\r\n if (this.disabled) return;\r\n\r\n const previousValue = [...this.value];\r\n const newValue = this.value.filter((v) => v !== value);\r\n this.value = newValue;\r\n this.dispatchChangeEvent(newValue, previousValue);\r\n };\r\n\r\n private handleClearAll = (event: Event) => {\r\n event.stopPropagation();\r\n if (this.disabled) return;\r\n\r\n const previousValue = [...this.value];\r\n const newValue: string[] = [];\r\n this.value = newValue;\r\n this.dispatchChangeEvent(newValue, previousValue);\r\n };\r\n\r\n private handleKeyDown = (event: globalThis.KeyboardEvent) => {\r\n if (this.disabled) return;\r\n\r\n const options = this.cachedOptions;\r\n\r\n switch (event.key) {\r\n case 'Enter':\r\n case ' ':\r\n event.preventDefault();\r\n if (this.isOpen && this.focusedIndex >= 0) {\r\n const option = options[this.focusedIndex];\r\n if (option) {\r\n this.handleOptionClick(option);\r\n }\r\n } else {\r\n this.handleToggle();\r\n }\r\n break;\r\n case 'Escape':\r\n event.preventDefault();\r\n this.isOpen = false;\r\n this.focusedIndex = -1;\r\n break;\r\n case 'ArrowDown':\r\n event.preventDefault();\r\n if (!this.isOpen) {\r\n this.isOpen = true;\r\n this.focusedIndex = 0;\r\n } else {\r\n this.focusedIndex = Math.min(\r\n this.focusedIndex + 1,\r\n options.length - 1\r\n );\r\n }\r\n break;\r\n case 'ArrowUp':\r\n event.preventDefault();\r\n if (!this.isOpen) {\r\n this.isOpen = true;\r\n this.focusedIndex = options.length - 1;\r\n } else {\r\n this.focusedIndex = Math.max(this.focusedIndex - 1, 0);\r\n }\r\n break;\r\n }\r\n };\r\n\r\n private getLabelForValue(value: string): string {\r\n const labelMap = this.computeLabelMap(this.cachedOptions);\r\n return labelMap.get(value) || value;\r\n }\r\n\r\n private renderDropdown() {\r\n const options = this.cachedOptions;\r\n\r\n return html`\r\n <div class=\"multi-select__dropdown\" part=\"dropdown\">\r\n <ul\r\n class=\"multi-select__options\"\r\n role=\"listbox\"\r\n aria-multiselectable=\"true\"\r\n >\r\n ${options.length === 0\r\n ? html`<li class=\"multi-select__option multi-select__option--empty\">\r\n No options available\r\n </li>`\r\n : repeat(\r\n options,\r\n (opt) => opt.value,\r\n (opt, index) => {\r\n const selected = this.isSelected(opt.value);\r\n const focused = index === this.focusedIndex;\r\n return html`\r\n <li\r\n class=${classMap({\r\n 'multi-select__option': true,\r\n 'multi-select__option--selected': selected,\r\n 'multi-select__option--focused': focused,\r\n })}\r\n role=\"option\"\r\n aria-selected=${selected}\r\n @click=${() => this.handleOptionClick(opt)}\r\n part=\"option ${selected ? 'option-selected' : ''}\"\r\n >\r\n <span class=\"multi-select__checkbox\">\r\n ${selected ? '\\u2713' : ''}\r\n </span>\r\n <span class=\"multi-select__option-label\"\r\n >${opt.label}</span\r\n >\r\n </li>\r\n `;\r\n }\r\n )}\r\n </ul>\r\n </div>\r\n `;\r\n }\r\n\r\n render() {\r\n const hasSelection = this.value.length > 0;\r\n\r\n return html`\r\n <div\r\n class=${classMap({\r\n 'multi-select': true,\r\n 'multi-select--open': this.isOpen,\r\n 'multi-select--disabled': this.disabled,\r\n [`multi-select--${this.size}`]: true,\r\n [`multi-select--${this.variant}`]: true,\r\n })}\r\n >\r\n <div\r\n class=\"multi-select__control\"\r\n @click=${this.handleToggle}\r\n @keydown=${this.handleKeyDown}\r\n tabindex=${this.disabled ? '-1' : '0'}\r\n role=\"combobox\"\r\n aria-haspopup=\"listbox\"\r\n aria-expanded=${this.isOpen}\r\n aria-disabled=${this.disabled}\r\n part=\"control\"\r\n >\r\n <div class=\"multi-select__value-container\">\r\n ${hasSelection\r\n ? repeat(\r\n this.value,\r\n (v) => v,\r\n (v) => html`\r\n <span class=\"multi-select__tag\" part=\"tag\">\r\n <span class=\"multi-select__tag-label\">\r\n ${this.getLabelForValue(v)}\r\n </span>\r\n ${this.clearable\r\n ? html`<button\r\n type=\"button\"\r\n class=\"multi-select__tag-remove\"\r\n @click=${(e: Event) => this.handleRemoveTag(v, e)}\r\n aria-label=\"Remove ${this.getLabelForValue(v)}\"\r\n tabindex=\"-1\"\r\n ?disabled=${this.disabled}\r\n >\r\n ×\r\n </button>`\r\n : nothing}\r\n </span>\r\n `\r\n )\r\n : html`<span class=\"multi-select__placeholder\"\r\n >${this.placeholder}</span\r\n >`}\r\n </div>\r\n\r\n <div class=\"multi-select__indicators\">\r\n ${this.clearable && hasSelection\r\n ? html`\r\n <button\r\n type=\"button\"\r\n class=\"multi-select__clear\"\r\n @click=${this.handleClearAll}\r\n aria-label=\"Clear all selections\"\r\n tabindex=\"-1\"\r\n ?disabled=${this.disabled}\r\n part=\"clear-button\"\r\n >\r\n ×\r\n </button>\r\n `\r\n : ''}\r\n <span class=\"multi-select__dropdown-indicator\" part=\"indicator\">\r\n ▼\r\n </span>\r\n </div>\r\n </div>\r\n\r\n ${this.isOpen ? this.renderDropdown() : nothing}\r\n\r\n <!-- Hidden slot for options -->\r\n <slot @slotchange=${this.handleSlotChange}></slot>\r\n\r\n <!-- Hidden inputs for form submission -->\r\n ${this.value.map(\r\n (v) => html`\r\n <input type=\"hidden\" name=\"${this.name}\" value=\"${v}\" />\r\n `\r\n )}\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'bp-multi-select': BpMultiSelect;\r\n }\r\n}\r\n"],"names":["multiSelectStyles","css","BpMultiSelect","LitElement","memoizeOne","options","map","opt","event","option","previousValue","newValue","v","value","el","selectedValues","html","repeat","index","selected","focused","classMap","hasSelection","e","nothing","__decorateClass","property","booleanConverter","state","customElement"],"mappings":";;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACoB1B,IAAMC,IAAN,cAA4BC,EAAW;AAAA,EAuD5C,cAAc;AACZ,UAAA,GAzBO,KAAQ,SAAS,IAGjB,KAAQ,eAAe,IAGvB,KAAQ,gBAAqC,CAAA,GAMtD,KAAQ,kBAAkBC;AAAA,MACxB,CAACC,MAAsD;AACrD,cAAMC,wBAAU,IAAA;AAChB,mBAAWC,KAAOF;AAChB,UAAAC,EAAI,IAAIC,EAAI,OAAOA,EAAI,KAAK;AAE9B,eAAOD;AAAA,MACT;AAAA,IAAA,GAqCF,KAAQ,sBAAsB,CAACE,MAAsB;AACnD,MAAK,KAAK,SAASA,EAAM,MAAyB,MAChD,KAAK,SAAS,IACd,KAAK,eAAe;AAAA,IAExB,GAEA,KAAQ,eAAe,CAACA,MAAkB;AAExC,MADAA,GAAO,gBAAA,GACH,MAAK,aACT,KAAK,SAAS,CAAC,KAAK,QAChB,KAAK,WACP,KAAK,eAAe;AAAA,IAExB,GAkBA,KAAQ,mBAAmB,MAAM;AAC/B,WAAK,gBAAgB,KAAK,WAAA,GAC1B,KAAK,yBAAA;AAAA,IACP,GAwCA,KAAQ,oBAAoB,CAACC,MAA8B;AACzD,UAAI,KAAK,SAAU;AAEnB,YAAMC,IAAgB,CAAC,GAAG,KAAK,KAAK;AACpC,UAAIC;AAEJ,UAAI,KAAK,WAAWF,EAAO,KAAK;AAG9B,YADAE,IAAW,KAAK,MAAM,OAAO,CAACC,MAAMA,MAAMH,EAAO,KAAK,GAClD,CAAC,KAAK,aAAaE,EAAS,WAAW;AACzC;AAAA,aAEG;AAEL,YAAI,KAAK,gBAAgB,KAAK,KAAK,MAAM,UAAU,KAAK;AACtD;AAEF,QAAAA,IAAW,CAAC,GAAG,KAAK,OAAOF,EAAO,KAAK;AAAA,MACzC;AAEA,WAAK,QAAQE,GACb,KAAK,oBAAoBA,GAAUD,CAAa;AAAA,IAClD,GAEA,KAAQ,kBAAkB,CAACG,GAAeL,MAAiB;AAEzD,UADAA,EAAM,gBAAA,GACF,KAAK,SAAU;AAEnB,YAAME,IAAgB,CAAC,GAAG,KAAK,KAAK,GAC9BC,IAAW,KAAK,MAAM,OAAO,CAACC,MAAMA,MAAMC,CAAK;AACrD,WAAK,QAAQF,GACb,KAAK,oBAAoBA,GAAUD,CAAa;AAAA,IAClD,GAEA,KAAQ,iBAAiB,CAACF,MAAiB;AAEzC,UADAA,EAAM,gBAAA,GACF,KAAK,SAAU;AAEnB,YAAME,IAAgB,CAAC,GAAG,KAAK,KAAK,GAC9BC,IAAqB,CAAA;AAC3B,WAAK,QAAQA,GACb,KAAK,oBAAoBA,GAAUD,CAAa;AAAA,IAClD,GAEA,KAAQ,gBAAgB,CAACF,MAAoC;AAC3D,UAAI,KAAK,SAAU;AAEnB,YAAMH,IAAU,KAAK;AAErB,cAAQG,EAAM,KAAA;AAAA,QACZ,KAAK;AAAA,QACL,KAAK;AAEH,cADAA,EAAM,eAAA,GACF,KAAK,UAAU,KAAK,gBAAgB,GAAG;AACzC,kBAAMC,IAASJ,EAAQ,KAAK,YAAY;AACxC,YAAII,KACF,KAAK,kBAAkBA,CAAM;AAAA,UAEjC;AACE,iBAAK,aAAA;AAEP;AAAA,QACF,KAAK;AACH,UAAAD,EAAM,eAAA,GACN,KAAK,SAAS,IACd,KAAK,eAAe;AACpB;AAAA,QACF,KAAK;AACH,UAAAA,EAAM,eAAA,GACD,KAAK,SAIR,KAAK,eAAe,KAAK;AAAA,YACvB,KAAK,eAAe;AAAA,YACpBH,EAAQ,SAAS;AAAA,UAAA,KALnB,KAAK,SAAS,IACd,KAAK,eAAe;AAOtB;AAAA,QACF,KAAK;AACH,UAAAG,EAAM,eAAA,GACD,KAAK,SAIR,KAAK,eAAe,KAAK,IAAI,KAAK,eAAe,GAAG,CAAC,KAHrD,KAAK,SAAS,IACd,KAAK,eAAeH,EAAQ,SAAS;AAIvC;AAAA,MAAA;AAAA,IAEN,GAlME,KAAK,QAAQ,CAAA,GACb,KAAK,OAAO,IACZ,KAAK,cAAc,kBACnB,KAAK,WAAW,IAChB,KAAK,WAAW,IAChB,KAAK,OAAO,MACZ,KAAK,UAAU,WACf,KAAK,gBAAgB,GACrB,KAAK,YAAY;AAAA,EACnB;AAAA,EAEA,oBAAoB;AAClB,UAAM,kBAAA,GACN,SAAS,iBAAiB,SAAS,KAAK,qBAAqB;AAAA,MAC3D,SAAS;AAAA,IAAA,CACV,GAED,KAAK,eAAe,KAAK,MAAM;AAC7B,WAAK,gBAAgB,KAAK,WAAA,GAC1B,KAAK,yBAAA;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAEA,uBAAuB;AACrB,UAAM,qBAAA,GACN,SAAS,oBAAoB,SAAS,KAAK,qBAAqB;AAAA,MAC9D,SAAS;AAAA,IAAA,CACc;AAAA,EAC3B;AAAA,EAkBQ,aAAkC;AAOxC,YANa,KAAK,YAAY,cAAc,MAAM,GACnB,iBAAA,KAAsB,CAAA,GACpB;AAAA,MAC/B,CAACS,MAA2CA,EAAG,YAAY;AAAA,IAAA,EAG9C,IAAI,CAACL,OAAY;AAAA,MAC9B,OAAOA,EAAO,SAASA,EAAO,eAAe;AAAA,MAC7C,OAAOA,EAAO,eAAe;AAAA,IAAA,EAC7B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA,EAcQ,2BAA2B;AACjC,QAAI,KAAK,MAAM,SAAS,EAAG;AAI3B,UAAMM,KAFO,KAAK,YAAY,cAAc,MAAM,GACnB,iBAAA,KAAsB,CAAA,GAElD;AAAA,MACC,CAACD,MACCA,EAAG,YAAY,YAAYA,EAAG,aAAa,UAAU;AAAA,IAAA,EAExD,IAAI,CAACA,MAAOA,EAAG,SAASA,EAAG,eAAe,EAAE;AAE/C,IAAIC,EAAe,SAAS,MAC1B,KAAK,QAAQA;AAAA,EAEjB;AAAA,EAEQ,WAAWF,GAAwB;AACzC,WAAO,KAAK,MAAM,SAASA,CAAK;AAAA,EAClC;AAAA,EAEQ,oBAAoBF,GAAoBD,GAAyB;AACvE,SAAK;AAAA,MACH,IAAI,YAAY,aAAa;AAAA,QAC3B,QAAQ;AAAA,UACN,OAAOC;AAAA,UACP,eAAAD;AAAA,QAAA;AAAA,QAEF,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAAA,EAEL;AAAA,EA6FQ,iBAAiBG,GAAuB;AAE9C,WADiB,KAAK,gBAAgB,KAAK,aAAa,EACxC,IAAIA,CAAK,KAAKA;AAAA,EAChC;AAAA,EAEQ,iBAAiB;AACvB,UAAMR,IAAU,KAAK;AAErB,WAAOW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOCX,EAAQ,WAAW,IACjBW;AAAA;AAAA,uBAGAC;AAAA,MACEZ;AAAA,MACA,CAACE,MAAQA,EAAI;AAAA,MACb,CAACA,GAAKW,MAAU;AACd,cAAMC,IAAW,KAAK,WAAWZ,EAAI,KAAK,GACpCa,IAAUF,MAAU,KAAK;AAC/B,eAAOF;AAAA;AAAA,8BAEKK,EAAS;AAAA,UACf,wBAAwB;AAAA,UACxB,kCAAkCF;AAAA,UAClC,iCAAiCC;AAAA,QAAA,CAClC,CAAC;AAAA;AAAA,sCAEcD,CAAQ;AAAA,+BACf,MAAM,KAAK,kBAAkBZ,CAAG,CAAC;AAAA,qCAC3BY,IAAW,oBAAoB,EAAE;AAAA;AAAA;AAAA,0BAG5CA,IAAW,MAAW,EAAE;AAAA;AAAA;AAAA,2BAGvBZ,EAAI,KAAK;AAAA;AAAA;AAAA;AAAA,MAIpB;AAAA,IAAA,CACD;AAAA;AAAA;AAAA;AAAA,EAIb;AAAA,EAEA,SAAS;AACP,UAAMe,IAAe,KAAK,MAAM,SAAS;AAEzC,WAAON;AAAA;AAAA,gBAEKK,EAAS;AAAA,MACf,gBAAgB;AAAA,MAChB,sBAAsB,KAAK;AAAA,MAC3B,0BAA0B,KAAK;AAAA,MAC/B,CAAC,iBAAiB,KAAK,IAAI,EAAE,GAAG;AAAA,MAChC,CAAC,iBAAiB,KAAK,OAAO,EAAE,GAAG;AAAA,IAAA,CACpC,CAAC;AAAA;AAAA;AAAA;AAAA,mBAIS,KAAK,YAAY;AAAA,qBACf,KAAK,aAAa;AAAA,qBAClB,KAAK,WAAW,OAAO,GAAG;AAAA;AAAA;AAAA,0BAGrB,KAAK,MAAM;AAAA,0BACX,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,cAIzBC,IACEL;AAAA,MACE,KAAK;AAAA,MACL,CAACL,MAAMA;AAAA,MACP,CAACA,MAAMI;AAAA;AAAA;AAAA,0BAGC,KAAK,iBAAiBJ,CAAC,CAAC;AAAA;AAAA,wBAE1B,KAAK,YACHI;AAAA;AAAA;AAAA,qCAGW,CAACO,MAAa,KAAK,gBAAgBX,GAAGW,CAAC,CAAC;AAAA,iDAC5B,KAAK,iBAAiBX,CAAC,CAAC;AAAA;AAAA,wCAEjC,KAAK,QAAQ;AAAA;AAAA;AAAA,uCAI3BY,CAAO;AAAA;AAAA;AAAA,IAAA,IAIjBR;AAAA,qBACK,KAAK,WAAW;AAAA,kBACnB;AAAA;AAAA;AAAA;AAAA,cAIJ,KAAK,aAAaM,IAChBN;AAAA;AAAA;AAAA;AAAA,6BAIa,KAAK,cAAc;AAAA;AAAA;AAAA,gCAGhB,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,oBAM7B,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAOR,KAAK,SAAS,KAAK,eAAA,IAAmBQ,CAAO;AAAA;AAAA;AAAA,4BAG3B,KAAK,gBAAgB;AAAA;AAAA;AAAA,UAGvC,KAAK,MAAM;AAAA,MACX,CAACZ,MAAMI;AAAA,yCACwB,KAAK,IAAI,YAAYJ,CAAC;AAAA;AAAA,IAAA,CAEtD;AAAA;AAAA;AAAA,EAGP;AACF;AA3YaV,EAqDJ,SAAS,CAACF,CAAiB;AAnDCyB,EAAA;AAAA,EAAlCC,EAAS,EAAE,MAAM,MAAA,CAAO;AAAA,GAFdxB,EAEwB,WAAA,SAAA,CAAA;AAGCuB,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GALfxB,EAKyB,WAAA,QAAA,CAAA;AAGAuB,EAAA;AAAA,EAAnCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfxB,EAQyB,WAAA,eAAA,CAAA;AAGgBuB,EAAA;AAAA,EAAnDC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAX/BxB,EAWyC,WAAA,YAAA,CAAA;AAGAuB,EAAA;AAAA,EAAnDC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAd/BxB,EAcyC,WAAA,YAAA,CAAA;AAGDuB,EAAA;AAAA,EAAlDC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAjB9BxB,EAiBwC,WAAA,QAAA,CAAA;AAI3CuB,EAAA;AAAA,EADPC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GApB9BxB,EAqBH,WAAA,WAAA,CAAA;AAIAuB,EAAA;AAAA,EADPC,EAAS,EAAE,MAAM,QAAQ,WAAW,kBAAkB;AAAA,GAxB5CxB,EAyBH,WAAA,iBAAA,CAAA;AAG2CuB,EAAA;AAAA,EAAlDC,EAAS,EAAE,WAAWC,EAAA,CAAkB;AAAA,GA5B9BzB,EA4BwC,WAAA,aAAA,CAAA;AAGlCuB,EAAA;AAAA,EAAhBG,EAAA;AAAM,GA/BI1B,EA+BM,WAAA,UAAA,CAAA;AAGAuB,EAAA;AAAA,EAAhBG,EAAA;AAAM,GAlCI1B,EAkCM,WAAA,gBAAA,CAAA;AAGAuB,EAAA;AAAA,EAAhBG,EAAA;AAAM,GArCI1B,EAqCM,WAAA,iBAAA,CAAA;AArCNA,IAANuB,EAAA;AAAA,EADNI,EAAc,iBAAiB;AAAA,GACnB3B,CAAA;"}
1
+ {"version":3,"file":"multi-select.js","sources":["../../source/components/multi-select/multi-select.style.ts","../../source/components/multi-select/multi-select.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const multiSelectStyles = css`\n /* Base styles */\n :host {\n display: block;\n font-family: var(--bp-font-family);\n }\n\n .multi-select {\n position: relative;\n width: 100%;\n }\n\n .multi-select__control {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--bp-spacing-sm);\n min-height: var(--bp-spacing-10);\n padding: var(--bp-spacing-xs) var(--bp-spacing-sm);\n background-color: var(--bp-color-surface);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n cursor: pointer;\n transition: border-color var(--bp-transition-fast);\n }\n\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-primary);\n }\n\n .multi-select__control:focus-visible {\n outline: var(--bp-focus-width) solid var(--bp-color-focus);\n outline-offset: var(--bp-focus-width);\n }\n\n .multi-select__value-container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--bp-spacing-xs);\n flex: 1;\n min-width: 0;\n }\n\n .multi-select__placeholder {\n color: var(--bp-color-text-muted);\n user-select: none;\n }\n\n .multi-select__tag {\n display: inline-flex;\n align-items: center;\n gap: var(--bp-spacing-xs);\n padding: var(--bp-spacing-2xs) var(--bp-spacing-xs);\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 8%,\n transparent\n );\n color: var(--bp-color-primary);\n border: none;\n border-radius: var(--bp-border-radius-md);\n font-size: var(--bp-font-size-sm);\n max-width: 100%;\n }\n\n .multi-select__tag-label {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .multi-select__tag-remove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-primary);\n cursor: pointer;\n font-size: var(--bp-font-size-lg);\n line-height: 1;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__tag-remove:hover {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 15%,\n transparent\n );\n color: var(--bp-color-primary);\n }\n\n .multi-select__tag-remove:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .multi-select__indicators {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-xs);\n flex-shrink: 0;\n }\n\n .multi-select__clear {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-6);\n height: var(--bp-spacing-6);\n padding: 0;\n background: transparent;\n border: none;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-text-muted);\n cursor: pointer;\n font-size: var(--bp-font-size-xl);\n line-height: 1;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__clear:hover {\n background-color: var(--bp-color-surface-subdued);\n color: var(--bp-color-text);\n }\n\n .multi-select__clear:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n }\n\n .multi-select__dropdown-indicator {\n color: var(--bp-color-text-muted);\n font-size: var(--bp-font-size-xs);\n transition: transform var(--bp-transition-fast);\n user-select: none;\n }\n\n .multi-select--open .multi-select__dropdown-indicator {\n transform: rotate(180deg);\n }\n\n .multi-select__dropdown {\n position: absolute;\n top: calc(100% + var(--bp-spacing-xs));\n left: 0;\n right: 0;\n z-index: var(--bp-z-dropdown);\n background-color: var(--bp-color-surface);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-md);\n box-shadow: var(--bp-shadow-md);\n max-height: calc(var(--bp-spacing-10) * 6);\n overflow-y: auto;\n opacity: 0;\n visibility: hidden;\n transform: translateY(calc(-1 * var(--bp-spacing-md)));\n transition:\n opacity var(--bp-transition-fast),\n transform var(--bp-transition-fast),\n visibility var(--bp-transition-fast);\n contain: layout style paint;\n }\n\n .multi-select--open .multi-select__dropdown {\n opacity: 1;\n visibility: visible;\n transform: translateY(0);\n }\n\n .multi-select__options {\n list-style: none;\n margin: 0;\n padding: var(--bp-spacing-2xs);\n }\n\n .multi-select__option {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-sm);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n cursor: pointer;\n border-radius: var(--bp-border-radius-md);\n transition:\n background-color var(--bp-transition-fast),\n color var(--bp-transition-fast);\n }\n\n .multi-select__option:hover {\n background-color: var(--bp-color-surface-elevated);\n }\n\n .multi-select__option--focused {\n background-color: var(--bp-color-surface-subdued);\n outline: var(--bp-focus-width) solid var(--bp-color-primary);\n outline-offset: calc(-1 * var(--bp-focus-width));\n }\n\n .multi-select__option--selected {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 8%,\n transparent\n );\n color: var(--bp-color-primary);\n }\n\n .multi-select__option--selected:hover {\n background-color: color-mix(\n in srgb,\n var(--bp-color-primary) 12%,\n transparent\n );\n }\n\n .multi-select__option--empty {\n color: var(--bp-color-text-muted);\n cursor: default;\n text-align: center;\n padding: var(--bp-spacing-xl) var(--bp-spacing-lg);\n font-style: italic;\n }\n\n .multi-select__checkbox {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-sm);\n font-size: var(--bp-font-size-xs);\n flex-shrink: 0;\n transition: all var(--bp-transition-fast);\n }\n\n .multi-select__option--selected .multi-select__checkbox {\n border-color: var(--bp-color-primary);\n background-color: var(--bp-color-primary);\n color: var(--bp-color-text-inverse);\n }\n\n .multi-select__option-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Sizes */\n .multi-select--sm .multi-select__control {\n min-height: var(--bp-spacing-8);\n padding: var(--bp-spacing-2xs) var(--bp-spacing-xs);\n font-size: var(--bp-font-size-sm);\n }\n\n .multi-select--sm .multi-select__tag {\n padding: var(--bp-spacing-0-5) var(--bp-spacing-2xs);\n font-size: var(--bp-font-size-xs);\n }\n\n .multi-select--lg .multi-select__control {\n min-height: var(--bp-spacing-12);\n padding: var(--bp-spacing-sm) var(--bp-spacing-md);\n font-size: var(--bp-font-size-lg);\n }\n\n .multi-select--lg .multi-select__tag {\n padding: var(--bp-spacing-xs) var(--bp-spacing-sm);\n font-size: var(--bp-font-size-base);\n }\n\n /* Variants */\n .multi-select--default .multi-select__control {\n border-color: var(--bp-color-border);\n }\n\n .multi-select--success .multi-select__control {\n border-color: var(--bp-color-success);\n }\n\n .multi-select--error .multi-select__control {\n border-color: var(--bp-color-error);\n }\n\n .multi-select--warning .multi-select__control {\n border-color: var(--bp-color-warning);\n }\n\n .multi-select--info .multi-select__control {\n border-color: var(--bp-color-info);\n }\n\n .multi-select--success\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-success);\n }\n\n .multi-select--error\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-error);\n }\n\n .multi-select--warning\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-warning);\n }\n\n .multi-select--info\n .multi-select__control:hover:not(\n .multi-select--disabled .multi-select__control\n ) {\n border-color: var(--bp-color-info);\n }\n\n /* States */\n .multi-select--disabled .multi-select__control {\n background-color: var(--bp-color-surface-subdued);\n cursor: not-allowed;\n opacity: 0.6;\n }\n\n .multi-select--disabled .multi-select__placeholder {\n color: var(--bp-color-text-muted);\n }\n\n /* Hide slot */\n slot {\n display: none;\n }\n\n /* Hide hidden inputs */\n input[type='hidden'] {\n display: none;\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { multiSelectStyles } from './multi-select.style.js';\nimport { memoizeOne } from '../../utilities/memoize.js';\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\n\nexport type MultiSelectSize = 'sm' | 'md' | 'lg';\nexport type MultiSelectVariant =\n | 'default'\n | 'success'\n | 'error'\n | 'warning'\n | 'info';\n\nexport interface MultiSelectOption {\n value: string;\n label: string;\n}\n\n@customElement('bp-multi-select')\nexport class BpMultiSelect extends LitElement {\n /** The current selected values as an array */\n @property({ type: Array }) declare value: string[];\n\n /** Name attribute for form submission */\n @property({ type: String }) declare name: string;\n\n /** Placeholder text when no values are selected */\n @property({ type: String }) declare placeholder: string;\n\n /** Whether the multi-select is disabled */\n @property({ type: Boolean, reflect: true }) declare disabled: boolean;\n\n /** Whether the multi-select is required */\n @property({ type: Boolean, reflect: true }) declare required: boolean;\n\n /** Size variant of the multi-select */\n @property({ type: String, reflect: true }) declare size: MultiSelectSize;\n\n /** Visual variant for validation states */\n @property({ type: String, reflect: true })\n declare variant: MultiSelectVariant;\n\n /** Maximum number of selections allowed (0 = unlimited) */\n @property({ type: Number, attribute: 'max-selections' })\n declare maxSelections: number;\n\n /** Whether to show a clear all button */\n @property({ converter: booleanConverter }) declare clearable: boolean;\n\n /** Whether the dropdown is currently open */\n @state() private isOpen = false;\n\n /** Index of the focused option for keyboard navigation */\n @state() private focusedIndex = -1;\n\n /** Cached options from slotted elements */\n @state() private cachedOptions: MultiSelectOption[] = [];\n\n /**\n * Memoized label lookup map for efficient tag rendering.\n * Only recomputes when cachedOptions reference changes.\n */\n private computeLabelMap = memoizeOne(\n (options: MultiSelectOption[]): Map<string, string> => {\n const map = new Map<string, string>();\n for (const opt of options) {\n map.set(opt.value, opt.label);\n }\n return map;\n }\n );\n\n static styles = [multiSelectStyles];\n\n constructor() {\n super();\n this.value = [];\n this.name = '';\n this.placeholder = 'Select options';\n this.disabled = false;\n this.required = false;\n this.size = 'md';\n this.variant = 'default';\n this.maxSelections = 0;\n this.clearable = true;\n }\n\n connectedCallback() {\n super.connectedCallback();\n document.addEventListener('click', this.handleDocumentClick, {\n passive: true,\n });\n // Initialize cached options and pre-selected values after first render\n this.updateComplete.then(() => {\n this.cachedOptions = this.getOptions();\n this.initializeSelectedValues();\n });\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n document.removeEventListener('click', this.handleDocumentClick, {\n passive: true,\n } as EventListenerOptions);\n }\n\n private handleDocumentClick = (event: MouseEvent) => {\n if (!this.contains(event.target as globalThis.Node)) {\n this.isOpen = false;\n this.focusedIndex = -1;\n }\n };\n\n private handleToggle = (event?: Event) => {\n event?.stopPropagation();\n if (this.disabled) return;\n this.isOpen = !this.isOpen;\n if (this.isOpen) {\n this.focusedIndex = 0;\n }\n };\n\n private getOptions(): MultiSelectOption[] {\n const slot = this.shadowRoot?.querySelector('slot');\n const assignedElements = slot?.assignedElements() || [];\n const options = assignedElements.filter(\n (el): el is globalThis.HTMLOptionElement => el.tagName === 'OPTION'\n );\n\n return options.map((option) => ({\n value: option.value || option.textContent || '',\n label: option.textContent || '',\n }));\n }\n\n /**\n * Handle slot changes by refreshing the cached options.\n */\n private handleSlotChange = () => {\n this.cachedOptions = this.getOptions();\n this.initializeSelectedValues();\n };\n\n /**\n * Read the `selected` attribute from slotted <option> elements\n * and set the initial value array if no values are already set.\n */\n private initializeSelectedValues() {\n if (this.value.length > 0) return;\n\n const slot = this.shadowRoot?.querySelector('slot');\n const assignedElements = slot?.assignedElements() || [];\n const selectedValues = assignedElements\n .filter(\n (el): el is globalThis.HTMLOptionElement =>\n el.tagName === 'OPTION' && el.hasAttribute('selected')\n )\n .map((el) => el.value || el.textContent || '');\n\n if (selectedValues.length > 0) {\n this.value = selectedValues;\n }\n }\n\n private isSelected(value: string): boolean {\n return this.value.includes(value);\n }\n\n private dispatchChangeEvent(newValue: string[], previousValue: string[]) {\n this.dispatchEvent(\n new CustomEvent('bp-change', {\n detail: {\n value: newValue,\n previousValue,\n },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleOptionClick = (option: MultiSelectOption) => {\n if (this.disabled) return;\n\n const previousValue = [...this.value];\n let newValue: string[];\n\n if (this.isSelected(option.value)) {\n // Deselect — but prevent removing the last item when not clearable\n newValue = this.value.filter((v) => v !== option.value);\n if (!this.clearable && newValue.length === 0) {\n return;\n }\n } else {\n // Select (check max selections)\n if (this.maxSelections > 0 && this.value.length >= this.maxSelections) {\n return;\n }\n newValue = [...this.value, option.value];\n }\n\n this.value = newValue;\n this.dispatchChangeEvent(newValue, previousValue);\n };\n\n private handleRemoveTag = (value: string, event: Event) => {\n event.stopPropagation();\n if (this.disabled) return;\n\n const previousValue = [...this.value];\n const newValue = this.value.filter((v) => v !== value);\n this.value = newValue;\n this.dispatchChangeEvent(newValue, previousValue);\n };\n\n private handleClearAll = (event: Event) => {\n event.stopPropagation();\n if (this.disabled) return;\n\n const previousValue = [...this.value];\n const newValue: string[] = [];\n this.value = newValue;\n this.dispatchChangeEvent(newValue, previousValue);\n };\n\n private handleKeyDown = (event: globalThis.KeyboardEvent) => {\n if (this.disabled) return;\n\n const options = this.cachedOptions;\n\n switch (event.key) {\n case 'Enter':\n case ' ':\n event.preventDefault();\n if (this.isOpen && this.focusedIndex >= 0) {\n const option = options[this.focusedIndex];\n if (option) {\n this.handleOptionClick(option);\n }\n } else {\n this.handleToggle();\n }\n break;\n case 'Escape':\n event.preventDefault();\n this.isOpen = false;\n this.focusedIndex = -1;\n break;\n case 'ArrowDown':\n event.preventDefault();\n if (!this.isOpen) {\n this.isOpen = true;\n this.focusedIndex = 0;\n } else {\n this.focusedIndex = Math.min(\n this.focusedIndex + 1,\n options.length - 1\n );\n }\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (!this.isOpen) {\n this.isOpen = true;\n this.focusedIndex = options.length - 1;\n } else {\n this.focusedIndex = Math.max(this.focusedIndex - 1, 0);\n }\n break;\n }\n };\n\n private getLabelForValue(value: string): string {\n const labelMap = this.computeLabelMap(this.cachedOptions);\n return labelMap.get(value) || value;\n }\n\n private renderDropdown() {\n const options = this.cachedOptions;\n\n return html`\n <div class=\"multi-select__dropdown\" part=\"dropdown\">\n <ul\n class=\"multi-select__options\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n >\n ${options.length === 0\n ? html`<li class=\"multi-select__option multi-select__option--empty\">\n No options available\n </li>`\n : repeat(\n options,\n (opt) => opt.value,\n (opt, index) => {\n const selected = this.isSelected(opt.value);\n const focused = index === this.focusedIndex;\n return html`\n <li\n class=${classMap({\n 'multi-select__option': true,\n 'multi-select__option--selected': selected,\n 'multi-select__option--focused': focused,\n })}\n role=\"option\"\n aria-selected=${selected}\n @click=${() => this.handleOptionClick(opt)}\n part=\"option ${selected ? 'option-selected' : ''}\"\n >\n <span class=\"multi-select__checkbox\">\n ${selected ? '\\u2713' : ''}\n </span>\n <span class=\"multi-select__option-label\"\n >${opt.label}</span\n >\n </li>\n `;\n }\n )}\n </ul>\n </div>\n `;\n }\n\n render() {\n const hasSelection = this.value.length > 0;\n\n return html`\n <div\n class=${classMap({\n 'multi-select': true,\n 'multi-select--open': this.isOpen,\n 'multi-select--disabled': this.disabled,\n [`multi-select--${this.size}`]: true,\n [`multi-select--${this.variant}`]: true,\n })}\n >\n <div\n class=\"multi-select__control\"\n @click=${this.handleToggle}\n @keydown=${this.handleKeyDown}\n tabindex=${this.disabled ? '-1' : '0'}\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n aria-expanded=${this.isOpen}\n aria-disabled=${this.disabled}\n part=\"control\"\n >\n <div class=\"multi-select__value-container\">\n ${hasSelection\n ? repeat(\n this.value,\n (v) => v,\n (v) => html`\n <span class=\"multi-select__tag\" part=\"tag\">\n <span class=\"multi-select__tag-label\">\n ${this.getLabelForValue(v)}\n </span>\n ${this.clearable\n ? html`<button\n type=\"button\"\n class=\"multi-select__tag-remove\"\n @click=${(e: Event) => this.handleRemoveTag(v, e)}\n aria-label=\"Remove ${this.getLabelForValue(v)}\"\n tabindex=\"-1\"\n ?disabled=${this.disabled}\n >\n ×\n </button>`\n : nothing}\n </span>\n `\n )\n : html`<span class=\"multi-select__placeholder\"\n >${this.placeholder}</span\n >`}\n </div>\n\n <div class=\"multi-select__indicators\">\n ${this.clearable && hasSelection\n ? html`\n <button\n type=\"button\"\n class=\"multi-select__clear\"\n @click=${this.handleClearAll}\n aria-label=\"Clear all selections\"\n tabindex=\"-1\"\n ?disabled=${this.disabled}\n part=\"clear-button\"\n >\n ×\n </button>\n `\n : ''}\n <span class=\"multi-select__dropdown-indicator\" part=\"indicator\">\n ▼\n </span>\n </div>\n </div>\n\n ${this.isOpen ? this.renderDropdown() : nothing}\n\n <!-- Hidden slot for options -->\n <slot @slotchange=${this.handleSlotChange}></slot>\n\n <!-- Hidden inputs for form submission -->\n ${this.value.map(\n (v) => html`\n <input type=\"hidden\" name=\"${this.name}\" value=\"${v}\" />\n `\n )}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bp-multi-select': BpMultiSelect;\n }\n}\n"],"names":["multiSelectStyles","css","BpMultiSelect","LitElement","memoizeOne","options","map","opt","event","option","previousValue","newValue","v","value","el","selectedValues","html","repeat","index","selected","focused","classMap","hasSelection","e","nothing","__decorateClass","property","booleanConverter","state","customElement"],"mappings":";;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
@@ -1 +1 @@
1
- {"version":3,"file":"notification.js","sources":["../../source/components/notification/notification.style.ts","../../source/components/notification/notification.ts"],"sourcesContent":["import { css } from 'lit';\r\n\r\nexport const notificationStyles = css`\r\n /* Base styles */\r\n :host {\r\n display: block;\r\n }\r\n\r\n .notification {\r\n display: flex;\r\n align-items: flex-start;\r\n gap: var(--bp-spacing-3);\r\n padding: var(--bp-spacing-4);\r\n background-color: var(--bp-color-surface-elevated);\r\n border: var(--bp-border-width) solid var(--bp-color-border);\r\n border-radius: var(--bp-border-radius-lg);\r\n box-shadow: var(--bp-shadow-lg);\r\n font-family: var(--bp-font-sans);\r\n font-size: var(--bp-font-size-sm);\r\n line-height: var(--bp-line-height-normal);\r\n color: var(--bp-color-text);\r\n max-width: 400px;\r\n min-width: 300px;\r\n animation: notification-slide-in var(--bp-duration-fast) var(--bp-ease-out);\r\n }\r\n\r\n @keyframes notification-slide-in {\r\n from {\r\n opacity: 0;\r\n transform: translateY(calc(-1 * var(--bp-spacing-2)));\r\n }\r\n to {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n }\r\n\r\n @keyframes notification-slide-out {\r\n from {\r\n opacity: 1;\r\n transform: translateY(0);\r\n }\r\n to {\r\n opacity: 0;\r\n transform: translateY(calc(-1 * var(--bp-spacing-2)));\r\n }\r\n }\r\n\r\n .notification--exiting {\r\n animation: notification-slide-out var(--bp-duration-fast) var(--bp-ease-in)\r\n forwards;\r\n }\r\n\r\n @media (prefers-reduced-motion: reduce) {\r\n .notification {\r\n animation: none;\r\n }\r\n\r\n .notification--exiting {\r\n animation: none;\r\n opacity: 0;\r\n }\r\n }\r\n\r\n /* Icon */\r\n .notification__icon {\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n\r\n .notification__icon svg {\r\n width: 100%;\r\n height: 100%;\r\n }\r\n\r\n /* Content */\r\n .notification__content {\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n .notification__title {\r\n font-weight: var(--bp-font-weight-semibold);\r\n margin-bottom: var(--bp-spacing-1);\r\n color: var(--bp-color-text-strong);\r\n }\r\n\r\n .notification__message {\r\n color: var(--bp-color-text-muted);\r\n }\r\n\r\n /* Action */\r\n .notification__action {\r\n display: flex;\r\n align-items: center;\r\n gap: var(--bp-spacing-1);\r\n }\r\n\r\n .notification__action:empty {\r\n display: none;\r\n }\r\n\r\n /* Close button */\r\n .notification__close {\r\n flex-shrink: 0;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n width: var(--bp-spacing-11);\r\n height: var(--bp-spacing-11);\r\n padding: 0;\r\n margin: calc(-1 * var(--bp-spacing-2));\r\n background: none;\r\n border: none;\r\n border-radius: var(--bp-border-radius-sm);\r\n color: var(--bp-color-text-muted);\r\n cursor: pointer;\r\n transition:\r\n color var(--bp-transition-fast),\r\n background-color var(--bp-transition-fast);\r\n }\r\n\r\n .notification__close:hover {\r\n color: var(--bp-color-text);\r\n background-color: var(--bp-color-surface-subdued);\r\n }\r\n\r\n .notification__close:focus-visible {\r\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\r\n outline-offset: var(--bp-focus-offset);\r\n }\r\n\r\n .notification__close svg {\r\n width: var(--bp-spacing-4);\r\n height: var(--bp-spacing-4);\r\n }\r\n\r\n /* Variants */\r\n .notification--info {\r\n border-left: var(--bp-spacing-1) solid var(--bp-color-info);\r\n }\r\n\r\n .notification--info .notification__icon {\r\n color: var(--bp-color-info);\r\n }\r\n\r\n .notification--success {\r\n border-left: var(--bp-spacing-1) solid var(--bp-color-success);\r\n }\r\n\r\n .notification--success .notification__icon {\r\n color: var(--bp-color-success);\r\n }\r\n\r\n .notification--warning {\r\n border-left: var(--bp-spacing-1) solid var(--bp-color-warning);\r\n }\r\n\r\n .notification--warning .notification__icon {\r\n color: var(--bp-color-warning);\r\n }\r\n\r\n .notification--error {\r\n border-left: var(--bp-spacing-1) solid var(--bp-color-error);\r\n }\r\n\r\n .notification--error .notification__icon {\r\n color: var(--bp-color-error);\r\n }\r\n\r\n /* Position variants */\r\n .notification--top-left,\r\n .notification--top-center,\r\n .notification--top-right,\r\n .notification--bottom-left,\r\n .notification--bottom-center,\r\n .notification--bottom-right {\r\n position: fixed;\r\n z-index: 10000;\r\n margin: var(--bp-spacing-4);\r\n }\r\n\r\n .notification--top-left {\r\n top: 0;\r\n left: 0;\r\n }\r\n\r\n .notification--top-center {\r\n top: 0;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n }\r\n\r\n .notification--top-right {\r\n top: 0;\r\n right: 0;\r\n }\r\n\r\n .notification--bottom-left {\r\n bottom: 0;\r\n left: 0;\r\n }\r\n\r\n .notification--bottom-center {\r\n bottom: 0;\r\n left: 50%;\r\n transform: translateX(-50%);\r\n }\r\n\r\n .notification--bottom-right {\r\n bottom: 0;\r\n right: 0;\r\n }\r\n`;\r\n","import { LitElement, html, nothing } from 'lit';\r\nimport { customElement, property, state } from 'lit/decorators.js';\r\nimport { notificationStyles } from './notification.style.js';\r\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\r\nimport '../icon/icon.js';\r\n\r\n/**\r\n * A notification/toast component for displaying non-blocking messages.\r\n * Notifications can be dismissed manually or auto-close after a duration.\r\n *\r\n * @fires bp-close - Dispatched when the notification is closed\r\n * @fires bp-show - Dispatched when the notification becomes visible\r\n * @fires bp-hide - Dispatched when the notification is hidden\r\n *\r\n * @slot - Default slot for notification content\r\n * @slot icon - Custom icon to display\r\n * @slot action - Action buttons or links\r\n *\r\n * @csspart base - The notification container\r\n * @csspart icon - The icon container\r\n * @csspart content - The content area\r\n * @csspart message - The message text container\r\n * @csspart action - The action slot container\r\n * @csspart close-button - The close button\r\n */\r\n@customElement('bp-notification')\r\nexport class BpNotification extends LitElement {\r\n /** The notification variant */\r\n @property({\r\n type: String,\r\n reflect: true,\r\n converter: {\r\n fromAttribute: (value: string | null) => {\r\n const valid = ['info', 'success', 'warning', 'error'];\r\n return value && valid.includes(value) ? value : 'info';\r\n },\r\n },\r\n })\r\n declare variant: 'info' | 'success' | 'warning' | 'error';\r\n\r\n /** Whether the notification is visible */\r\n @property({ type: Boolean, reflect: true }) declare open: boolean;\r\n\r\n /** Whether the notification can be dismissed */\r\n @property({ converter: booleanConverter, reflect: true })\r\n declare closable: boolean;\r\n\r\n /** Duration in milliseconds before auto-close (0 = no auto-close) */\r\n @property({ type: Number }) declare duration: number;\r\n\r\n /** Title of the notification */\r\n @property({ type: String }) declare title: string;\r\n\r\n /** Message content of the notification */\r\n @property({ type: String }) declare message: string;\r\n\r\n /**\r\n * Position of the notification on screen.\r\n * Note: For multiple notifications, consider using a container component.\r\n */\r\n @property({\r\n type: String,\r\n converter: {\r\n fromAttribute: (value: string | null) => {\r\n const valid = [\r\n 'top-left',\r\n 'top-center',\r\n 'top-right',\r\n 'bottom-left',\r\n 'bottom-center',\r\n 'bottom-right',\r\n ];\r\n return value && valid.includes(value) ? value : 'top-right';\r\n },\r\n },\r\n })\r\n declare position:\r\n | 'top-left'\r\n | 'top-center'\r\n | 'top-right'\r\n | 'bottom-left'\r\n | 'bottom-center'\r\n | 'bottom-right';\r\n\r\n @state() private autoCloseTimer: number | null = null;\r\n @state() private remainingTime: number = 0;\r\n @state() private timerPaused: boolean = false;\r\n @state() private isExiting: boolean = false;\r\n\r\n static styles = [notificationStyles];\r\n\r\n constructor() {\r\n super();\r\n this.variant = 'info';\r\n this.open = false;\r\n this.closable = true;\r\n this.duration = 0;\r\n this.title = '';\r\n this.message = '';\r\n this.position = 'top-right';\r\n }\r\n\r\n updated(changedProperties: Map<string, unknown>) {\r\n if (changedProperties.has('open')) {\r\n if (this.open) {\r\n this.handleOpen();\r\n } else {\r\n this.handleClose();\r\n }\r\n }\r\n\r\n if (changedProperties.has('duration') && this.open) {\r\n this.startAutoCloseTimer();\r\n }\r\n }\r\n\r\n disconnectedCallback() {\r\n super.disconnectedCallback();\r\n this.clearAutoCloseTimer();\r\n }\r\n\r\n /** Show the notification */\r\n show() {\r\n if (this.open) return;\r\n this.open = true;\r\n }\r\n\r\n /** Hide the notification */\r\n hide() {\r\n if (!this.open) return;\r\n this.open = false;\r\n }\r\n\r\n /**\r\n * Handles the notification opening.\r\n * Dispatches bp-show event, starts auto-close timer, and manages focus.\r\n */\r\n private handleOpen() {\r\n this.isExiting = false;\r\n this.dispatchEvent(\r\n new CustomEvent('bp-show', { bubbles: true, composed: true })\r\n );\r\n this.startAutoCloseTimer();\r\n\r\n // Focus close button for accessibility\r\n this.updateComplete.then(() => {\r\n if (this.closable) {\r\n const closeButton = this.shadowRoot?.querySelector(\r\n '.notification__close'\r\n ) as HTMLElement;\r\n closeButton?.focus();\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Handles the notification closing.\r\n * Clears auto-close timer and dispatches bp-hide event.\r\n */\r\n private handleClose() {\r\n this.clearAutoCloseTimer();\r\n this.dispatchEvent(\r\n new CustomEvent('bp-hide', { bubbles: true, composed: true })\r\n );\r\n }\r\n\r\n /**\r\n * Starts the auto-close timer based on the duration property.\r\n * Timer can be paused/resumed with pauseAutoCloseTimer/resumeAutoCloseTimer.\r\n */\r\n private startAutoCloseTimer() {\r\n this.clearAutoCloseTimer();\r\n\r\n if (this.duration > 0 && !this.timerPaused) {\r\n this.remainingTime = this.duration;\r\n this.autoCloseTimer = window.setTimeout(() => {\r\n this.hide();\r\n }, this.duration);\r\n }\r\n }\r\n\r\n /**\r\n * Clears the auto-close timer if it exists.\r\n */\r\n private clearAutoCloseTimer() {\r\n if (this.autoCloseTimer) {\r\n window.clearTimeout(this.autoCloseTimer);\r\n this.autoCloseTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Pauses the auto-close timer when user hovers or focuses.\r\n * Allows users to read content or interact with actions.\r\n */\r\n private pauseAutoCloseTimer() {\r\n if (this.autoCloseTimer && this.duration > 0) {\r\n this.timerPaused = true;\r\n window.clearTimeout(this.autoCloseTimer);\r\n this.autoCloseTimer = null;\r\n }\r\n }\r\n\r\n /**\r\n * Resumes the auto-close timer with remaining time.\r\n */\r\n private resumeAutoCloseTimer() {\r\n if (this.timerPaused && this.duration > 0) {\r\n this.timerPaused = false;\r\n this.autoCloseTimer = window.setTimeout(() => {\r\n this.hide();\r\n }, this.remainingTime);\r\n }\r\n }\r\n\r\n /**\r\n * Handles close button click.\r\n * Hides notification and dispatches bp-close event.\r\n */\r\n private handleCloseClick() {\r\n this.hide();\r\n this.dispatchEvent(\r\n new CustomEvent('bp-close', { bubbles: true, composed: true })\r\n );\r\n }\r\n\r\n /**\r\n * Handles keyboard events.\r\n * Closes notification on Escape key if closable.\r\n */\r\n private handleKeydown(event: KeyboardEvent) {\r\n if (event.key === 'Escape' && this.closable) {\r\n this.handleCloseClick();\r\n }\r\n }\r\n\r\n /**\r\n * Returns the default icon for the notification variant.\r\n * Uses the bp-icon component for consistency with the design system.\r\n */\r\n private getDefaultIcon() {\r\n const iconMap = {\r\n success: 'check',\r\n warning: 'warning-circle',\r\n error: 'cross',\r\n info: 'info-circle',\r\n } as const;\r\n return html`<bp-icon name=${iconMap[this.variant]} size=\"md\"></bp-icon>`;\r\n }\r\n\r\n render() {\r\n if (!this.open) {\r\n return nothing;\r\n }\r\n\r\n return html`\r\n <div\r\n class=\"notification notification--${this.variant} notification--${this\r\n .position} ${this.isExiting\r\n ? 'notification--exiting'\r\n : 'notification--entering'}\"\r\n part=\"base\"\r\n role=\"alert\"\r\n aria-live=${this.variant === 'error' ? 'assertive' : 'polite'}\r\n @keydown=${this.handleKeydown}\r\n @mouseenter=${this.pauseAutoCloseTimer}\r\n @mouseleave=${this.resumeAutoCloseTimer}\r\n @focusin=${this.pauseAutoCloseTimer}\r\n @focusout=${this.resumeAutoCloseTimer}\r\n >\r\n <div class=\"notification__icon\" part=\"icon\">\r\n <slot name=\"icon\">${this.getDefaultIcon()}</slot>\r\n </div>\r\n\r\n <div class=\"notification__content\" part=\"content\">\r\n ${this.title\r\n ? html`<div class=\"notification__title\">${this.title}</div>`\r\n : nothing}\r\n <div class=\"notification__message\" part=\"message\">\r\n ${this.message || html`<slot></slot>`}\r\n </div>\r\n </div>\r\n\r\n <div class=\"notification__action\" part=\"action\">\r\n <slot name=\"action\"></slot>\r\n </div>\r\n\r\n ${this.closable\r\n ? html`\r\n <button\r\n type=\"button\"\r\n class=\"notification__close\"\r\n part=\"close-button\"\r\n aria-label=\"Close notification\"\r\n @click=${this.handleCloseClick}\r\n >\r\n <svg\r\n viewBox=\"0 0 24 24\"\r\n fill=\"none\"\r\n stroke=\"currentColor\"\r\n stroke-width=\"2\"\r\n >\r\n <path d=\"M18 6L6 18M6 6l12 12\" />\r\n </svg>\r\n </button>\r\n `\r\n : nothing}\r\n </div>\r\n `;\r\n }\r\n}\r\n\r\ndeclare global {\r\n interface HTMLElementTagNameMap {\r\n 'bp-notification': BpNotification;\r\n }\r\n}\r\n"],"names":["notificationStyles","css","BpNotification","LitElement","changedProperties","event","html","nothing","__decorateClass","property","value","booleanConverter","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"notification.js","sources":["../../source/components/notification/notification.style.ts","../../source/components/notification/notification.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const notificationStyles = css`\n /* Base styles */\n :host {\n display: block;\n }\n\n .notification {\n display: flex;\n align-items: flex-start;\n gap: var(--bp-spacing-3);\n padding: var(--bp-spacing-4);\n background-color: var(--bp-color-surface-elevated);\n border: var(--bp-border-width) solid var(--bp-color-border);\n border-radius: var(--bp-border-radius-lg);\n box-shadow: var(--bp-shadow-lg);\n font-family: var(--bp-font-sans);\n font-size: var(--bp-font-size-sm);\n line-height: var(--bp-line-height-normal);\n color: var(--bp-color-text);\n max-width: 400px;\n min-width: 300px;\n animation: notification-slide-in var(--bp-duration-fast) var(--bp-ease-out);\n }\n\n @keyframes notification-slide-in {\n from {\n opacity: 0;\n transform: translateY(calc(-1 * var(--bp-spacing-2)));\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes notification-slide-out {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(calc(-1 * var(--bp-spacing-2)));\n }\n }\n\n .notification--exiting {\n animation: notification-slide-out var(--bp-duration-fast) var(--bp-ease-in)\n forwards;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .notification {\n animation: none;\n }\n\n .notification--exiting {\n animation: none;\n opacity: 0;\n }\n }\n\n /* Icon */\n .notification__icon {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .notification__icon svg {\n width: 100%;\n height: 100%;\n }\n\n /* Content */\n .notification__content {\n flex: 1;\n min-width: 0;\n }\n\n .notification__title {\n font-weight: var(--bp-font-weight-semibold);\n margin-bottom: var(--bp-spacing-1);\n color: var(--bp-color-text-strong);\n }\n\n .notification__message {\n color: var(--bp-color-text-muted);\n }\n\n /* Action */\n .notification__action {\n display: flex;\n align-items: center;\n gap: var(--bp-spacing-1);\n }\n\n .notification__action:empty {\n display: none;\n }\n\n /* Close button */\n .notification__close {\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--bp-spacing-11);\n height: var(--bp-spacing-11);\n padding: 0;\n margin: calc(-1 * var(--bp-spacing-2));\n background: none;\n border: none;\n border-radius: var(--bp-border-radius-sm);\n color: var(--bp-color-text-muted);\n cursor: pointer;\n transition:\n color var(--bp-transition-fast),\n background-color var(--bp-transition-fast);\n }\n\n .notification__close:hover {\n color: var(--bp-color-text);\n background-color: var(--bp-color-surface-subdued);\n }\n\n .notification__close:focus-visible {\n outline: var(--bp-focus-width) var(--bp-focus-style) var(--bp-color-focus);\n outline-offset: var(--bp-focus-offset);\n }\n\n .notification__close svg {\n width: var(--bp-spacing-4);\n height: var(--bp-spacing-4);\n }\n\n /* Variants */\n .notification--info {\n border-left: var(--bp-spacing-1) solid var(--bp-color-info);\n }\n\n .notification--info .notification__icon {\n color: var(--bp-color-info);\n }\n\n .notification--success {\n border-left: var(--bp-spacing-1) solid var(--bp-color-success);\n }\n\n .notification--success .notification__icon {\n color: var(--bp-color-success);\n }\n\n .notification--warning {\n border-left: var(--bp-spacing-1) solid var(--bp-color-warning);\n }\n\n .notification--warning .notification__icon {\n color: var(--bp-color-warning);\n }\n\n .notification--error {\n border-left: var(--bp-spacing-1) solid var(--bp-color-error);\n }\n\n .notification--error .notification__icon {\n color: var(--bp-color-error);\n }\n\n /* Position variants */\n .notification--top-left,\n .notification--top-center,\n .notification--top-right,\n .notification--bottom-left,\n .notification--bottom-center,\n .notification--bottom-right {\n position: fixed;\n z-index: 10000;\n margin: var(--bp-spacing-4);\n }\n\n .notification--top-left {\n top: 0;\n left: 0;\n }\n\n .notification--top-center {\n top: 0;\n left: 50%;\n transform: translateX(-50%);\n }\n\n .notification--top-right {\n top: 0;\n right: 0;\n }\n\n .notification--bottom-left {\n bottom: 0;\n left: 0;\n }\n\n .notification--bottom-center {\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n }\n\n .notification--bottom-right {\n bottom: 0;\n right: 0;\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { notificationStyles } from './notification.style.js';\nimport { booleanConverter } from '../../utilities/boolean-converter.js';\nimport '../icon/icon.js';\n\n/**\n * A notification/toast component for displaying non-blocking messages.\n * Notifications can be dismissed manually or auto-close after a duration.\n *\n * @fires bp-close - Dispatched when the notification is closed\n * @fires bp-show - Dispatched when the notification becomes visible\n * @fires bp-hide - Dispatched when the notification is hidden\n *\n * @slot - Default slot for notification content\n * @slot icon - Custom icon to display\n * @slot action - Action buttons or links\n *\n * @csspart base - The notification container\n * @csspart icon - The icon container\n * @csspart content - The content area\n * @csspart message - The message text container\n * @csspart action - The action slot container\n * @csspart close-button - The close button\n */\n@customElement('bp-notification')\nexport class BpNotification extends LitElement {\n /** The notification variant */\n @property({\n type: String,\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => {\n const valid = ['info', 'success', 'warning', 'error'];\n return value && valid.includes(value) ? value : 'info';\n },\n },\n })\n declare variant: 'info' | 'success' | 'warning' | 'error';\n\n /** Whether the notification is visible */\n @property({ type: Boolean, reflect: true }) declare open: boolean;\n\n /** Whether the notification can be dismissed */\n @property({ converter: booleanConverter, reflect: true })\n declare closable: boolean;\n\n /** Duration in milliseconds before auto-close (0 = no auto-close) */\n @property({ type: Number }) declare duration: number;\n\n /** Title of the notification */\n @property({ type: String }) declare title: string;\n\n /** Message content of the notification */\n @property({ type: String }) declare message: string;\n\n /**\n * Position of the notification on screen.\n * Note: For multiple notifications, consider using a container component.\n */\n @property({\n type: String,\n converter: {\n fromAttribute: (value: string | null) => {\n const valid = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n ];\n return value && valid.includes(value) ? value : 'top-right';\n },\n },\n })\n declare position:\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\n @state() private autoCloseTimer: number | null = null;\n @state() private remainingTime: number = 0;\n @state() private timerPaused: boolean = false;\n @state() private isExiting: boolean = false;\n\n static styles = [notificationStyles];\n\n constructor() {\n super();\n this.variant = 'info';\n this.open = false;\n this.closable = true;\n this.duration = 0;\n this.title = '';\n this.message = '';\n this.position = 'top-right';\n }\n\n updated(changedProperties: Map<string, unknown>) {\n if (changedProperties.has('open')) {\n if (this.open) {\n this.handleOpen();\n } else {\n this.handleClose();\n }\n }\n\n if (changedProperties.has('duration') && this.open) {\n this.startAutoCloseTimer();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this.clearAutoCloseTimer();\n }\n\n /** Show the notification */\n show() {\n if (this.open) return;\n this.open = true;\n }\n\n /** Hide the notification */\n hide() {\n if (!this.open) return;\n this.open = false;\n }\n\n /**\n * Handles the notification opening.\n * Dispatches bp-show event, starts auto-close timer, and manages focus.\n */\n private handleOpen() {\n this.isExiting = false;\n this.dispatchEvent(\n new CustomEvent('bp-show', { bubbles: true, composed: true })\n );\n this.startAutoCloseTimer();\n\n // Focus close button for accessibility\n this.updateComplete.then(() => {\n if (this.closable) {\n const closeButton = this.shadowRoot?.querySelector(\n '.notification__close'\n ) as HTMLElement;\n closeButton?.focus();\n }\n });\n }\n\n /**\n * Handles the notification closing.\n * Clears auto-close timer and dispatches bp-hide event.\n */\n private handleClose() {\n this.clearAutoCloseTimer();\n this.dispatchEvent(\n new CustomEvent('bp-hide', { bubbles: true, composed: true })\n );\n }\n\n /**\n * Starts the auto-close timer based on the duration property.\n * Timer can be paused/resumed with pauseAutoCloseTimer/resumeAutoCloseTimer.\n */\n private startAutoCloseTimer() {\n this.clearAutoCloseTimer();\n\n if (this.duration > 0 && !this.timerPaused) {\n this.remainingTime = this.duration;\n this.autoCloseTimer = window.setTimeout(() => {\n this.hide();\n }, this.duration);\n }\n }\n\n /**\n * Clears the auto-close timer if it exists.\n */\n private clearAutoCloseTimer() {\n if (this.autoCloseTimer) {\n window.clearTimeout(this.autoCloseTimer);\n this.autoCloseTimer = null;\n }\n }\n\n /**\n * Pauses the auto-close timer when user hovers or focuses.\n * Allows users to read content or interact with actions.\n */\n private pauseAutoCloseTimer() {\n if (this.autoCloseTimer && this.duration > 0) {\n this.timerPaused = true;\n window.clearTimeout(this.autoCloseTimer);\n this.autoCloseTimer = null;\n }\n }\n\n /**\n * Resumes the auto-close timer with remaining time.\n */\n private resumeAutoCloseTimer() {\n if (this.timerPaused && this.duration > 0) {\n this.timerPaused = false;\n this.autoCloseTimer = window.setTimeout(() => {\n this.hide();\n }, this.remainingTime);\n }\n }\n\n /**\n * Handles close button click.\n * Hides notification and dispatches bp-close event.\n */\n private handleCloseClick() {\n this.hide();\n this.dispatchEvent(\n new CustomEvent('bp-close', { bubbles: true, composed: true })\n );\n }\n\n /**\n * Handles keyboard events.\n * Closes notification on Escape key if closable.\n */\n private handleKeydown(event: KeyboardEvent) {\n if (event.key === 'Escape' && this.closable) {\n this.handleCloseClick();\n }\n }\n\n /**\n * Returns the default icon for the notification variant.\n * Uses the bp-icon component for consistency with the design system.\n */\n private getDefaultIcon() {\n const iconMap = {\n success: 'check',\n warning: 'warning-circle',\n error: 'cross',\n info: 'info-circle',\n } as const;\n return html`<bp-icon name=${iconMap[this.variant]} size=\"md\"></bp-icon>`;\n }\n\n render() {\n if (!this.open) {\n return nothing;\n }\n\n return html`\n <div\n class=\"notification notification--${this.variant} notification--${this\n .position} ${this.isExiting\n ? 'notification--exiting'\n : 'notification--entering'}\"\n part=\"base\"\n role=\"alert\"\n aria-live=${this.variant === 'error' ? 'assertive' : 'polite'}\n @keydown=${this.handleKeydown}\n @mouseenter=${this.pauseAutoCloseTimer}\n @mouseleave=${this.resumeAutoCloseTimer}\n @focusin=${this.pauseAutoCloseTimer}\n @focusout=${this.resumeAutoCloseTimer}\n >\n <div class=\"notification__icon\" part=\"icon\">\n <slot name=\"icon\">${this.getDefaultIcon()}</slot>\n </div>\n\n <div class=\"notification__content\" part=\"content\">\n ${this.title\n ? html`<div class=\"notification__title\">${this.title}</div>`\n : nothing}\n <div class=\"notification__message\" part=\"message\">\n ${this.message || html`<slot></slot>`}\n </div>\n </div>\n\n <div class=\"notification__action\" part=\"action\">\n <slot name=\"action\"></slot>\n </div>\n\n ${this.closable\n ? html`\n <button\n type=\"button\"\n class=\"notification__close\"\n part=\"close-button\"\n aria-label=\"Close notification\"\n @click=${this.handleCloseClick}\n >\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n >\n <path d=\"M18 6L6 18M6 6l12 12\" />\n </svg>\n </button>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bp-notification': BpNotification;\n }\n}\n"],"names":["notificationStyles","css","BpNotification","LitElement","changedProperties","event","html","nothing","__decorateClass","property","value","booleanConverter","state","customElement"],"mappings":"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"}