@lifecorner/angular-ui-kit 3.5.1 → 3.6.1

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 (85) hide show
  1. package/README.md +2 -1
  2. package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs +4 -1
  3. package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs.map +1 -1
  4. package/fesm2022/lifecorner-angular-ui-kit-alert.mjs +16 -1
  5. package/fesm2022/lifecorner-angular-ui-kit-alert.mjs.map +1 -1
  6. package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs +4 -1
  7. package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs.map +1 -1
  8. package/fesm2022/lifecorner-angular-ui-kit-button.mjs +4 -4
  9. package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -1
  10. package/fesm2022/lifecorner-angular-ui-kit-callout.mjs +16 -1
  11. package/fesm2022/lifecorner-angular-ui-kit-callout.mjs.map +1 -1
  12. package/fesm2022/lifecorner-angular-ui-kit-chat.mjs +14 -1
  13. package/fesm2022/lifecorner-angular-ui-kit-chat.mjs.map +1 -1
  14. package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs +46 -32
  15. package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs.map +1 -1
  16. package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs +4 -1
  17. package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs.map +1 -1
  18. package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs +4 -1
  19. package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs.map +1 -1
  20. package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs +4 -1
  21. package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs.map +1 -1
  22. package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs +4 -1
  23. package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs.map +1 -1
  24. package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs +14 -1
  25. package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs.map +1 -1
  26. package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs +4 -1
  27. package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs.map +1 -1
  28. package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs +4 -0
  29. package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs.map +1 -1
  30. package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs +4 -1
  31. package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs.map +1 -1
  32. package/fesm2022/lifecorner-angular-ui-kit-footer.mjs +4 -1
  33. package/fesm2022/lifecorner-angular-ui-kit-footer.mjs.map +1 -1
  34. package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs +14 -1
  35. package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs.map +1 -1
  36. package/fesm2022/lifecorner-angular-ui-kit-header.mjs +18 -1
  37. package/fesm2022/lifecorner-angular-ui-kit-header.mjs.map +1 -1
  38. package/fesm2022/lifecorner-angular-ui-kit-icon.mjs +186 -275
  39. package/fesm2022/lifecorner-angular-ui-kit-icon.mjs.map +1 -1
  40. package/fesm2022/lifecorner-angular-ui-kit-icons.mjs +803 -0
  41. package/fesm2022/lifecorner-angular-ui-kit-icons.mjs.map +1 -0
  42. package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs +297 -0
  43. package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs.map +1 -0
  44. package/fesm2022/lifecorner-angular-ui-kit-internal-navigation.mjs +38 -0
  45. package/fesm2022/lifecorner-angular-ui-kit-internal-navigation.mjs.map +1 -0
  46. package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs +4 -1
  47. package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs.map +1 -1
  48. package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +4 -1
  49. package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -1
  50. package/fesm2022/lifecorner-angular-ui-kit-modal.mjs +4 -1
  51. package/fesm2022/lifecorner-angular-ui-kit-modal.mjs.map +1 -1
  52. package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs +12 -1
  53. package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs.map +1 -1
  54. package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +14 -1
  55. package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
  56. package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs +4 -1
  57. package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs.map +1 -1
  58. package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs +4 -1
  59. package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs.map +1 -1
  60. package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs +12 -1
  61. package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs.map +1 -1
  62. package/fesm2022/lifecorner-angular-ui-kit-rating.mjs +4 -1
  63. package/fesm2022/lifecorner-angular-ui-kit-rating.mjs.map +1 -1
  64. package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs +4 -1
  65. package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs.map +1 -1
  66. package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs +262 -0
  67. package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs.map +1 -0
  68. package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs +18 -40
  69. package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs.map +1 -1
  70. package/fesm2022/lifecorner-angular-ui-kit-table.mjs +4 -1
  71. package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
  72. package/fesm2022/lifecorner-angular-ui-kit-toast.mjs +16 -1
  73. package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -1
  74. package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs +18 -1
  75. package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs.map +1 -1
  76. package/fesm2022/lifecorner-angular-ui-kit.mjs +2 -0
  77. package/package.json +17 -1
  78. package/types/lifecorner-angular-ui-kit-code-block.d.ts +10 -4
  79. package/types/lifecorner-angular-ui-kit-icon.d.ts +125 -5
  80. package/types/lifecorner-angular-ui-kit-icons.d.ts +140 -0
  81. package/types/lifecorner-angular-ui-kit-internal-icon-set.d.ts +31 -0
  82. package/types/lifecorner-angular-ui-kit-internal-navigation.d.ts +28 -0
  83. package/types/lifecorner-angular-ui-kit-sidenav-placeholder.d.ts +163 -0
  84. package/types/lifecorner-angular-ui-kit-sidenav.d.ts +2 -1
  85. package/types/lifecorner-angular-ui-kit.d.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-code-block.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/code-block/code-block.component.ts","../../../../libs/angular-ui-kit/src/lib/code-block/code-block.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n inject,\n input,\n computed,\n signal,\n} from '@angular/core';\nimport { DomSanitizer, SafeHtml } from '@angular/platform-browser';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\n\nexport type CodeBlockLanguage =\n | 'typescript'\n | 'javascript'\n | 'html'\n | 'css'\n | 'scss'\n | 'json'\n | 'bash'\n | 'python'\n | 'java'\n | 'text';\n\ninterface TokenRule {\n pattern: RegExp;\n className: string;\n}\n\nconst SHARED_RULES: TokenRule[] = [\n // Strings (double/single/backtick)\n { pattern: /`(?:[^`\\\\]|\\\\.)*`/g, className: 'token-string' },\n { pattern: /\"(?:[^\"\\\\]|\\\\.)*\"/g, className: 'token-string' },\n { pattern: /'(?:[^'\\\\]|\\\\.)*'/g, className: 'token-string' },\n // Numbers\n { pattern: /\\b\\d+(?:\\.\\d+)?\\b/g, className: 'token-number' },\n];\n\nconst LANGUAGE_RULES: Record<string, TokenRule[]> = {\n typescript: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:import|export|from|const|let|var|function|return|if|else|for|while|class|interface|type|enum|extends|implements|new|this|super|async|await|yield|of|in|as|is|readonly|public|private|protected|static|abstract|override|get|set|constructor|declare|namespace|module|require)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:string|number|boolean|void|null|undefined|never|any|unknown|object|symbol|bigint)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:true|false|null|undefined|NaN|Infinity)\\b/g, className: 'token-constant' },\n { pattern: /(?<=\\b(?:class|interface|type|enum|extends|implements)\\s+)\\w+/g, className: 'token-type' },\n ],\n javascript: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\b(?:import|export|from|const|let|var|function|return|if|else|for|while|class|extends|new|this|super|async|await|yield|of|in|typeof|instanceof|delete|throw|try|catch|finally|switch|case|default|break|continue|do)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:true|false|null|undefined|NaN|Infinity)\\b/g, className: 'token-constant' },\n ],\n html: [\n { pattern: /<!--[\\s\\S]*?-->/g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /&lt;\\/?[\\w-]+/g, className: 'token-tag' },\n { pattern: /\\/?&gt;/g, className: 'token-tag' },\n { pattern: /\\b[\\w-]+(?==)/g, className: 'token-attr' },\n ],\n css: [\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /[.#][\\w-]+/g, className: 'token-selector' },\n { pattern: /\\b(?:px|rem|em|%|vh|vw|s|ms|deg|fr)\\b/g, className: 'token-unit' },\n { pattern: /[\\w-]+(?=\\s*:)/g, className: 'token-property' },\n ],\n scss: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\$[\\w-]+/g, className: 'token-variable' },\n { pattern: /@(?:use|forward|import|mixin|include|extend|if|else|each|for|while|function|return)\\b/g, className: 'token-keyword' },\n { pattern: /&/g, className: 'token-selector' },\n { pattern: /[.#][\\w-]+/g, className: 'token-selector' },\n ],\n json: [\n ...SHARED_RULES,\n { pattern: /\\b(?:true|false|null)\\b/g, className: 'token-constant' },\n { pattern: /\"(?:[^\"\\\\]|\\\\.)*\"(?=\\s*:)/g, className: 'token-property' },\n ],\n bash: [\n { pattern: /#.*$/gm, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\$[\\w{][\\w}]*/g, className: 'token-variable' },\n { pattern: /\\b(?:if|then|else|elif|fi|for|do|done|while|until|case|esac|function|in|select|time|coproc)\\b/g, className: 'token-keyword' },\n { pattern: /(?:^|\\s)(?:npm|npx|yarn|pnpm|git|cd|ls|mkdir|rm|cp|mv|echo|cat|grep|find|sed|awk|curl|wget|docker|node|python|pip|brew|apt|sudo)\\b/g, className: 'token-builtin' },\n { pattern: /--?[\\w-]+/g, className: 'token-flag' },\n ],\n python: [\n { pattern: /#.*$/gm, className: 'token-comment' },\n { pattern: /\"\"\"[\\s\\S]*?\"\"\"/g, className: 'token-string' },\n { pattern: /'''[\\s\\S]*?'''/g, className: 'token-string' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:def|class|import|from|as|return|if|elif|else|for|while|break|continue|pass|raise|try|except|finally|with|yield|lambda|assert|del|global|nonlocal|async|await|in|not|and|or|is)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:True|False|None)\\b/g, className: 'token-constant' },\n { pattern: /\\b(?:str|int|float|bool|list|dict|tuple|set|bytes|type|object|Exception|ValueError|TypeError|KeyError|IndexError|AttributeError|RuntimeError|StopIteration)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:print|len|range|enumerate|zip|map|filter|sorted|reversed|isinstance|issubclass|hasattr|getattr|setattr|super|property|staticmethod|classmethod|open|input)\\b/g, className: 'token-builtin' },\n { pattern: /\\bself\\b/g, className: 'token-variable' },\n ],\n java: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:abstract|assert|break|case|catch|class|continue|default|do|else|enum|extends|final|finally|for|if|implements|import|instanceof|interface|native|new|package|private|protected|public|return|static|strictfp|super|switch|synchronized|this|throw|throws|transient|try|volatile|while|var|record|sealed|permits|yield)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:true|false|null)\\b/g, className: 'token-constant' },\n { pattern: /\\b(?:void|int|long|short|byte|float|double|char|boolean|String|Integer|Long|Double|Float|Boolean|Character|Object|Class|List|Map|Set|ArrayList|HashMap|HashSet|Optional|Stream|Collectors)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:System|Math|Arrays|Collections|Objects|Thread|Runnable)\\b/g, className: 'token-builtin' },\n ],\n};\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;');\n}\n\nfunction highlightCode(code: string, language: string): string {\n const escaped = escapeHtml(code);\n const rules = LANGUAGE_RULES[language];\n if (!rules) return escaped;\n\n // Collect all matches with positions\n const tokens: { start: number; end: number; className: string; text: string }[] = [];\n\n for (const rule of rules) {\n const regex = new RegExp(rule.pattern.source, rule.pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(escaped)) !== null) {\n tokens.push({\n start: match.index,\n end: match.index + match[0].length,\n className: rule.className,\n text: match[0],\n });\n }\n }\n\n // Sort by start position, longer matches first for same position\n tokens.sort((a, b) => a.start - b.start || b.end - a.end);\n\n // Remove overlapping tokens (keep first/longest)\n const filtered: typeof tokens = [];\n let lastEnd = 0;\n for (const token of tokens) {\n if (token.start >= lastEnd) {\n filtered.push(token);\n lastEnd = token.end;\n }\n }\n\n // Build highlighted string\n let result = '';\n let cursor = 0;\n for (const token of filtered) {\n if (token.start > cursor) {\n result += escaped.slice(cursor, token.start);\n }\n result += `<span class=\"${token.className}\">${token.text}</span>`;\n cursor = token.end;\n }\n result += escaped.slice(cursor);\n\n return result;\n}\n\n@Component({\n selector: 'lc-code-block',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './code-block.component.html',\n styleUrls: ['./code-block.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Code block component for displaying syntax-highlighted source code.\n *\n * Features:\n * - Syntax highlighting for 10+ languages (TypeScript, Python, Java, etc.)\n * - Optional line numbers\n * - Copy-to-clipboard button\n * - Optional header with filename and language label\n * - Dark-mode compatible color scheme\n *\n * @example\n * ```html\n * <lc-code-block [code]=\"source\" language=\"typescript\" [showLineNumbers]=\"true\" />\n * ```\n */\nexport class CodeBlockComponent {\n /** Code content to display */\n code = input.required<string>();\n\n /** Language label */\n language = input<CodeBlockLanguage>('text');\n\n /** Optional filename to display */\n filename = input<string>();\n\n /** Whether to show line numbers */\n showLineNumbers = input<boolean>(true);\n\n /** Whether to show copy button */\n showCopy = input<boolean>(true);\n\n /** Whether the code block has a header bar */\n showHeader = input<boolean>(true);\n\n /** Visible label of the copy button. */\n copyLabel = input('Copy');\n\n /** Accessible name of the copy button. */\n copyAriaLabel = input('Copy code');\n\n /** Label of the copy button after copying (also its accessible name). */\n copiedLabel = input('Copied');\n\n /** Announced to screen readers after copying. */\n copiedAnnouncement = input('Copied to clipboard');\n\n protected copied = signal(false);\n\n private readonly sanitizer = inject(DomSanitizer);\n\n protected highlightedLines = computed<SafeHtml[]>(() => {\n const highlighted = highlightCode(this.code(), this.language());\n return highlighted.split('\\n').map(line =>\n this.sanitizer.bypassSecurityTrustHtml(line || '&nbsp;')\n );\n });\n\n protected lineNumbers = computed(() => {\n return this.code().split('\\n').map((_, i) => i + 1);\n });\n\n protected headerLabel = computed(() => {\n return this.filename() || this.language();\n });\n\n protected codeClasses = computed(() => {\n return ['code-block', `code-block--${this.language()}`].join(' ');\n });\n\n protected async copyToClipboard(): Promise<void> {\n try {\n await navigator.clipboard.writeText(this.code());\n this.copied.set(true);\n setTimeout(() => this.copied.set(false), 2000);\n } catch {\n // Fallback: just ignore if clipboard API not available\n }\n }\n}\n","<div [class]=\"codeClasses()\">\n @if (showHeader()) {\n <div class=\"code-block__header\">\n <span class=\"code-block__language\">{{ headerLabel() }}</span>\n @if (showCopy()) {\n <button\n type=\"button\"\n class=\"code-block__copy\"\n [attr.aria-label]=\"copied() ? copiedLabel() : copyAriaLabel()\"\n (click)=\"copyToClipboard()\"\n >\n @if (copied()) {\n <lc-icon name=\"check\" size=\"sm\" />\n <span>{{ copiedLabel() }}</span>\n } @else {\n <lc-icon name=\"clipboard-document\" size=\"sm\" />\n <span>{{ copyLabel() }}</span>\n }\n </button>\n <span class=\"code-block__live\" role=\"status\" aria-live=\"polite\">{{ copied() ? copiedAnnouncement() : '' }}</span>\n }\n </div>\n }\n <div class=\"code-block__body\">\n <pre class=\"code-block__pre\"><code class=\"code-block__code\">@for (line of highlightedLines(); track $index; let i = $index) {<span class=\"code-block__line\">@if (showLineNumbers()) {<span class=\"code-block__line-number\">{{ lineNumbers()[i] }}</span>}<span class=\"code-block__line-content\" [innerHTML]=\"line\"></span></span>\n}</code></pre>\n </div>\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-code-block.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/code-block/code-block.component.ts","../../../../libs/angular-ui-kit/src/lib/code-block/code-block.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n computed,\n signal,\n} from '@angular/core';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHECK } from '@lifecorner/angular-ui-kit/icons';\n\nexport type CodeBlockLanguage =\n | 'typescript'\n | 'javascript'\n | 'html'\n | 'css'\n | 'scss'\n | 'json'\n | 'bash'\n | 'python'\n | 'java'\n | 'text';\n\ninterface TokenRule {\n pattern: RegExp;\n className: string;\n}\n\nconst SHARED_RULES: TokenRule[] = [\n // Strings (double/single/backtick)\n { pattern: /`(?:[^`\\\\]|\\\\.)*`/g, className: 'token-string' },\n { pattern: /\"(?:[^\"\\\\]|\\\\.)*\"/g, className: 'token-string' },\n { pattern: /'(?:[^'\\\\]|\\\\.)*'/g, className: 'token-string' },\n // Numbers\n { pattern: /\\b\\d+(?:\\.\\d+)?\\b/g, className: 'token-number' },\n];\n\nconst LANGUAGE_RULES: Record<string, TokenRule[]> = {\n typescript: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:import|export|from|const|let|var|function|return|if|else|for|while|class|interface|type|enum|extends|implements|new|this|super|async|await|yield|of|in|as|is|readonly|public|private|protected|static|abstract|override|get|set|constructor|declare|namespace|module|require)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:string|number|boolean|void|null|undefined|never|any|unknown|object|symbol|bigint)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:true|false|null|undefined|NaN|Infinity)\\b/g, className: 'token-constant' },\n { pattern: /(?<=\\b(?:class|interface|type|enum|extends|implements)\\s+)\\w+/g, className: 'token-type' },\n ],\n javascript: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\b(?:import|export|from|const|let|var|function|return|if|else|for|while|class|extends|new|this|super|async|await|yield|of|in|typeof|instanceof|delete|throw|try|catch|finally|switch|case|default|break|continue|do)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:true|false|null|undefined|NaN|Infinity)\\b/g, className: 'token-constant' },\n ],\n // The tokenizer reads the raw source (3.6.1): `<` and `>` instead of the\n // `&lt;`/`&gt;` the escaped text had. Up to 3.6.0 an html comment rule ran on\n // that escaped text and never matched; it is gone, so comments stay plain.\n html: [\n ...SHARED_RULES,\n { pattern: /<\\/?[\\w-]+/g, className: 'token-tag' },\n { pattern: /\\/?>/g, className: 'token-tag' },\n { pattern: /\\b[\\w-]+(?==)/g, className: 'token-attr' },\n ],\n css: [\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /[.#][\\w-]+/g, className: 'token-selector' },\n { pattern: /\\b(?:px|rem|em|%|vh|vw|s|ms|deg|fr)\\b/g, className: 'token-unit' },\n { pattern: /[\\w-]+(?=\\s*:)/g, className: 'token-property' },\n ],\n scss: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\$[\\w-]+/g, className: 'token-variable' },\n { pattern: /@(?:use|forward|import|mixin|include|extend|if|else|each|for|while|function|return)\\b/g, className: 'token-keyword' },\n { pattern: /&/g, className: 'token-selector' },\n { pattern: /[.#][\\w-]+/g, className: 'token-selector' },\n ],\n json: [\n ...SHARED_RULES,\n { pattern: /\\b(?:true|false|null)\\b/g, className: 'token-constant' },\n { pattern: /\"(?:[^\"\\\\]|\\\\.)*\"(?=\\s*:)/g, className: 'token-property' },\n ],\n bash: [\n { pattern: /#.*$/gm, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /\\$[\\w{][\\w}]*/g, className: 'token-variable' },\n { pattern: /\\b(?:if|then|else|elif|fi|for|do|done|while|until|case|esac|function|in|select|time|coproc)\\b/g, className: 'token-keyword' },\n { pattern: /(?:^|\\s)(?:npm|npx|yarn|pnpm|git|cd|ls|mkdir|rm|cp|mv|echo|cat|grep|find|sed|awk|curl|wget|docker|node|python|pip|brew|apt|sudo)\\b/g, className: 'token-builtin' },\n { pattern: /--?[\\w-]+/g, className: 'token-flag' },\n ],\n python: [\n { pattern: /#.*$/gm, className: 'token-comment' },\n { pattern: /\"\"\"[\\s\\S]*?\"\"\"/g, className: 'token-string' },\n { pattern: /'''[\\s\\S]*?'''/g, className: 'token-string' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:def|class|import|from|as|return|if|elif|else|for|while|break|continue|pass|raise|try|except|finally|with|yield|lambda|assert|del|global|nonlocal|async|await|in|not|and|or|is)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:True|False|None)\\b/g, className: 'token-constant' },\n { pattern: /\\b(?:str|int|float|bool|list|dict|tuple|set|bytes|type|object|Exception|ValueError|TypeError|KeyError|IndexError|AttributeError|RuntimeError|StopIteration)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:print|len|range|enumerate|zip|map|filter|sorted|reversed|isinstance|issubclass|hasattr|getattr|setattr|super|property|staticmethod|classmethod|open|input)\\b/g, className: 'token-builtin' },\n { pattern: /\\bself\\b/g, className: 'token-variable' },\n ],\n java: [\n { pattern: /\\/\\/.*$/gm, className: 'token-comment' },\n { pattern: /\\/\\*[\\s\\S]*?\\*\\//g, className: 'token-comment' },\n ...SHARED_RULES,\n { pattern: /@\\w+/g, className: 'token-decorator' },\n { pattern: /\\b(?:abstract|assert|break|case|catch|class|continue|default|do|else|enum|extends|final|finally|for|if|implements|import|instanceof|interface|native|new|package|private|protected|public|return|static|strictfp|super|switch|synchronized|this|throw|throws|transient|try|volatile|while|var|record|sealed|permits|yield)\\b/g, className: 'token-keyword' },\n { pattern: /\\b(?:true|false|null)\\b/g, className: 'token-constant' },\n { pattern: /\\b(?:void|int|long|short|byte|float|double|char|boolean|String|Integer|Long|Double|Float|Boolean|Character|Object|Class|List|Map|Set|ArrayList|HashMap|HashSet|Optional|Stream|Collectors)\\b/g, className: 'token-type' },\n { pattern: /\\b(?:System|Math|Arrays|Collections|Objects|Thread|Runnable)\\b/g, className: 'token-builtin' },\n ],\n};\n\n/** A run of source text; `className` is one `token-*` class, or `null` for plain text. */\ninterface CodeSegment {\n readonly text: string;\n readonly className: string | null;\n}\n\n/** One rendered line: its segments in order. */\ntype CodeLine = readonly CodeSegment[];\n\n/**\n * What an empty line renders: U+00A0, the glyph the `&nbsp;` of 3.6.0\n * produced, so the line keeps its height and a selection its text.\n */\nconst EMPTY_LINE: CodeLine = [{ text: String.fromCharCode(0xa0), className: null }];\n\n/** Matches of the language's rules on the raw source, sorted, without overlaps. */\nfunction tokenize(code: string, language: string): { start: number; end: number; className: string }[] {\n const rules = LANGUAGE_RULES[language];\n if (!rules) return [];\n\n // Collect all matches with positions\n const tokens: { start: number; end: number; className: string }[] = [];\n\n for (const rule of rules) {\n const regex = new RegExp(rule.pattern.source, rule.pattern.flags);\n let match: RegExpExecArray | null;\n while ((match = regex.exec(code)) !== null) {\n tokens.push({\n start: match.index,\n end: match.index + match[0].length,\n className: rule.className,\n });\n }\n }\n\n // Sort by start position, longer matches first for same position\n tokens.sort((a, b) => a.start - b.start || b.end - a.end);\n\n // Remove overlapping tokens (keep first/longest)\n const filtered: typeof tokens = [];\n let lastEnd = 0;\n for (const token of tokens) {\n if (token.start >= lastEnd) {\n filtered.push(token);\n lastEnd = token.end;\n }\n }\n return filtered;\n}\n\n/**\n * The highlighted source as lines of text segments, rendered by the template\n * as text nodes and `<span class=\"token-…\">` elements: no markup string, so\n * nothing for Trusted Types to block and nothing in the source is parsed.\n *\n * A token that runs across a line break keeps its class on the part before\n * the first break only; the later parts are plain, as the HTML parser closed\n * the open span at each line end up to 3.6.0.\n */\nfunction highlightLines(code: string, language: string): CodeLine[] {\n const lines: CodeSegment[][] = [[]];\n const append = (text: string, className: string | null) => {\n text.split('\\n').forEach((part, i) => {\n if (i > 0) lines.push([]);\n if (!part) return;\n const line = lines[lines.length - 1];\n const cls = i === 0 ? className : null;\n const last = line[line.length - 1];\n if (cls === null && last?.className === null) {\n line[line.length - 1] = { text: last.text + part, className: null };\n } else {\n line.push({ text: part, className: cls });\n }\n });\n };\n\n let cursor = 0;\n for (const token of tokenize(code, language)) {\n append(code.slice(cursor, token.start), null);\n append(code.slice(token.start, token.end), token.className);\n cursor = token.end;\n }\n append(code.slice(cursor), null);\n\n return lines.map(line => (line.length ? line : EMPTY_LINE));\n}\n\n@Component({\n selector: 'lc-code-block',\n standalone: true,\n imports: [IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CHECK])],\n templateUrl: './code-block.component.html',\n styleUrls: ['./code-block.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Code block component for displaying syntax-highlighted source code.\n *\n * Features:\n * - Syntax highlighting for 10+ languages (TypeScript, Python, Java, etc.)\n * - Optional line numbers\n * - Copy-to-clipboard button\n * - Optional header with filename and language label\n * - Dark-mode compatible color scheme\n *\n * @example\n * ```html\n * <lc-code-block [code]=\"source\" language=\"typescript\" [showLineNumbers]=\"true\" />\n * ```\n */\nexport class CodeBlockComponent {\n /** Code content to display */\n code = input.required<string>();\n\n /** Language label */\n language = input<CodeBlockLanguage>('text');\n\n /** Optional filename to display */\n filename = input<string>();\n\n /** Whether to show line numbers */\n showLineNumbers = input<boolean>(true);\n\n /** Whether to show copy button */\n showCopy = input<boolean>(true);\n\n /** Whether the code block has a header bar */\n showHeader = input<boolean>(true);\n\n /** Visible label of the copy button. */\n copyLabel = input('Copy');\n\n /** Accessible name of the copy button. */\n copyAriaLabel = input('Copy code');\n\n /** Label of the copy button after copying (also its accessible name). */\n copiedLabel = input('Copied');\n\n /** Announced to screen readers after copying. */\n copiedAnnouncement = input('Copied to clipboard');\n\n protected copied = signal(false);\n\n protected highlightedLines = computed<CodeLine[]>(() =>\n highlightLines(this.code(), this.language())\n );\n\n protected lineNumbers = computed(() => {\n return this.code().split('\\n').map((_, i) => i + 1);\n });\n\n protected headerLabel = computed(() => {\n return this.filename() || this.language();\n });\n\n protected codeClasses = computed(() => {\n return ['code-block', `code-block--${this.language()}`].join(' ');\n });\n\n protected async copyToClipboard(): Promise<void> {\n try {\n await navigator.clipboard.writeText(this.code());\n this.copied.set(true);\n setTimeout(() => this.copied.set(false), 2000);\n } catch {\n // Fallback: just ignore if clipboard API not available\n }\n }\n}\n","<div [class]=\"codeClasses()\">\n @if (showHeader()) {\n <div class=\"code-block__header\">\n <span class=\"code-block__language\">{{ headerLabel() }}</span>\n @if (showCopy()) {\n <button\n type=\"button\"\n class=\"code-block__copy\"\n [attr.aria-label]=\"copied() ? copiedLabel() : copyAriaLabel()\"\n (click)=\"copyToClipboard()\"\n >\n @if (copied()) {\n <lc-icon name=\"check\" size=\"sm\" [decorative]=\"true\" />\n <span>{{ copiedLabel() }}</span>\n } @else {\n <lc-icon name=\"clipboard-document\" size=\"sm\" [decorative]=\"true\" />\n <span>{{ copyLabel() }}</span>\n }\n </button>\n <span class=\"code-block__live\" role=\"status\" aria-live=\"polite\">{{ copied() ? copiedAnnouncement() : '' }}</span>\n }\n </div>\n }\n <div class=\"code-block__body\">\n <pre class=\"code-block__pre\"><code class=\"code-block__code\">@for (line of highlightedLines(); track $index; let i = $index) {<span class=\"code-block__line\">@if (showLineNumbers()) {<span class=\"code-block__line-number\">{{ lineNumbers()[i] }}</span>}<span class=\"code-block__line-content\">@for (segment of line; track $index) {@if (segment.className) {<span [attr.class]=\"segment.className\">{{ segment.text }}</span>}@else{{{ segment.text }}}}</span></span>\n}</code></pre>\n </div>\n</div>\n"],"mappings":"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"}
@@ -5,7 +5,8 @@ import { NG_VALUE_ACCESSOR } from "@angular/forms";
5
5
  import * as i1 from "@angular/cdk/overlay";
6
6
  import { OverlayModule } from "@angular/cdk/overlay";
7
7
  import { Subject, catchError, debounce, defer, of, switchMap, timer } from "rxjs";
8
- import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
8
+ import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
9
+ import { ICON_PLUS, ICON_X_MARK } from "@lifecorner/angular-ui-kit/icons";
9
10
  import { SpinnerComponent } from "@lifecorner/angular-ui-kit/spinner";
10
11
  import { ChipComponent } from "@lifecorner/angular-ui-kit/chip";
11
12
  var ComboboxComponent = class ComboboxComponent {
@@ -494,6 +495,7 @@ var ComboboxComponent = class ComboboxComponent {
494
495
  outputs: ["remove", "chipClick"]
495
496
  }
496
497
  ],
498
+ viewProviders: [ɵprovideKitIcons([ICON_X_MARK, ICON_PLUS])],
497
499
  changeDetection: i0.ChangeDetectionStrategy.OnPush
498
500
  });
499
501
  };
@@ -513,6 +515,7 @@ i0.ɵɵngDeclareClassMetadata({
513
515
  SpinnerComponent,
514
516
  ChipComponent
515
517
  ],
518
+ viewProviders: [ɵprovideKitIcons([ICON_X_MARK, ICON_PLUS])],
516
519
  changeDetection: ChangeDetectionStrategy.OnPush,
517
520
  providers: [{
518
521
  provide: NG_VALUE_ACCESSOR,
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-combobox.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.ts","../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n afterRenderEffect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { Observable, Subject, catchError, debounce, defer, of, switchMap, timer } from 'rxjs';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { SpinnerComponent } from '@lifecorner/angular-ui-kit/spinner';\nimport { ChipComponent } from '@lifecorner/angular-ui-kit/chip';\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n description?: string;\n icon?: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport type ComboboxValue = ComboboxOption | ComboboxOption[] | null;\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/**\n * Combobox / async autocomplete component.\n *\n * Supports free-text input with sync/async option suggestions,\n * single/multiple selection, create new entries, and keyboard navigation.\n * The suggestion list is rendered in a CDK overlay so it is never clipped\n * by `overflow: hidden` ancestors (cards, modals, table cells).\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(value)]=\"assignee\"\n * allowCreate\n * />\n * ```\n */\n@Component({\n selector: 'lc-combobox',\n standalone: true,\n imports: [OverlayModule, IconComponent, SpinnerComponent, ChipComponent],\n templateUrl: './combobox.component.html',\n styleUrls: ['./combobox.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => ComboboxComponent),\n multi: true,\n },\n ],\n})\nexport class ComboboxComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids so label/listbox/options can be linked via ARIA */\n readonly inputId = `lc-combobox-${++ComboboxComponent.nextId}`;\n readonly listboxId = `${this.inputId}-listbox`;\n protected readonly createOptionId = `${this.listboxId}-create`;\n\n private readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputEl');\n private readonly dropdownEl = viewChild<ElementRef<HTMLElement>>('dropdownEl');\n\n private readonly elRef = inject(ElementRef);\n private readonly querySubject = new Subject<string>();\n\n /** Sync options */\n readonly options = input<ComboboxOption[]>([]);\n\n /** Async option loader */\n readonly loadOptions = input<((query: string) => Observable<ComboboxOption[]>)>();\n\n /** Debounce for async queries */\n readonly debounceMs = input<number>(250);\n\n /** Minimum characters before triggering search */\n readonly minChars = input<number>(1);\n\n /** Placeholder text */\n readonly placeholder = input<string>('Search…');\n\n /** Label */\n readonly label = input<string>();\n\n /** Helper text */\n readonly helperText = input<string>();\n\n /** Error message */\n readonly error = input<string>();\n\n /** Disabled state */\n readonly disabled = input<boolean>(false);\n\n /** Allow multiple selections */\n readonly multiple = input<boolean>(false);\n\n /** Allow creating new entries */\n readonly allowCreate = input<boolean>(false);\n\n /** Show loading spinner (controlled) */\n readonly loading = input<boolean>(false);\n\n /** Empty state message */\n readonly emptyMessage = input<string>('No results');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Label before the query in the \"create\" option (`allowCreate`): `Create \"query\"`. */\n readonly createOptionLabel = input('Create');\n\n /** Size */\n readonly size = input<ComboboxSize>('md');\n\n /** Value change event */\n readonly valueChange = output<ComboboxValue>();\n\n /** Query change event */\n readonly queryChange = output<string>();\n\n /** Option selected event */\n readonly optionSelected = output<ComboboxOption>();\n\n /** Created event (allowCreate) */\n readonly created = output<string>();\n\n /** Internal state */\n protected query = signal('');\n protected isOpen = signal(false);\n protected highlightedIndex = signal(-1);\n protected asyncOptions = signal<ComboboxOption[]>([]);\n protected isLoading = signal(false);\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n /** Selected values */\n protected selectedSingle = signal<ComboboxOption | null>(null);\n protected selectedMultiple = signal<ComboboxOption[]>([]);\n\n /** Resolved visible options */\n protected visibleOptions = computed(() => {\n const q = this.query().toLowerCase();\n const loader = this.loadOptions();\n\n let opts: ComboboxOption[];\n if (loader) {\n opts = this.asyncOptions();\n } else {\n opts = this.options();\n if (q.length >= this.minChars()) {\n opts = opts.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.value.toLowerCase().includes(q) ||\n (o.description && o.description.toLowerCase().includes(q))\n );\n }\n }\n\n // Remove already selected in multiple mode\n if (this.multiple()) {\n const selected = new Set(this.selectedMultiple().map((s) => s.value));\n opts = opts.filter((o) => !selected.has(o.value));\n }\n\n return opts;\n });\n\n /** Grouped options */\n protected groupedOptions = computed(() => {\n const opts = this.visibleOptions();\n const groups = new Map<string, ComboboxOption[]>();\n\n for (const opt of opts) {\n const group = opt.group || '';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push(opt);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({\n label,\n items,\n }));\n });\n\n /** Flat list for keyboard nav */\n protected flatOptions = computed(() => {\n return this.groupedOptions().flatMap((g) => g.items);\n });\n\n /** Whether to show \"Create\" option */\n protected showCreateOption = computed(() => {\n if (!this.allowCreate()) return false;\n const q = this.query().trim();\n if (!q) return false;\n const exact = this.visibleOptions().some(\n (o) => o.label.toLowerCase() === q.toLowerCase()\n );\n return !exact;\n });\n\n /** id of the highlighted option — announced via aria-activedescendant */\n protected readonly activeDescendantId = computed(() => {\n if (!this.isOpen()) return null;\n const i = this.highlightedIndex();\n if (i < 0) return null;\n if (i === this.flatOptions().length) {\n return this.showCreateOption() ? this.createOptionId : null;\n }\n return i < this.flatOptions().length ? this.optionId(i) : null;\n });\n\n /** ids referenced by aria-describedby (helper / error) */\n protected readonly describedBy = computed(() => {\n if (this.error()) return `${this.inputId}-error`;\n if (this.helperText()) return `${this.inputId}-helper`;\n return null;\n });\n\n /** Container classes */\n protected containerClasses = computed(() => {\n const classes = [`lc-combobox`, `lc-combobox--${this.size()}`];\n if (this.isDisabled()) classes.push('lc-combobox--disabled');\n if (this.error()) classes.push('lc-combobox--error');\n if (this.isOpen()) classes.push('lc-combobox--open');\n return classes.join(' ');\n });\n\n protected optionId(index: number): string {\n return `${this.listboxId}-opt-${index}`;\n }\n\n // ControlValueAccessor\n private onChange: (value: ComboboxValue) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n constructor() {\n // Async loading pipe. `debounce` (not `debounceTime`) reads the signal per\n // emission, so `debounceMs` is honoured after inputs are populated.\n this.querySubject\n .pipe(\n debounce(() => timer(this.debounceMs())),\n switchMap((q) => {\n const loader = this.loadOptions();\n if (!loader || q.length < this.minChars()) {\n return of([] as ComboboxOption[]);\n }\n this.isLoading.set(true);\n // `defer` turns a synchronously throwing loader into an error\n // notification; `catchError` keeps the pipe alive for the next query.\n return defer(() => loader(q)).pipe(catchError(() => of([] as ComboboxOption[])));\n }),\n takeUntilDestroyed()\n )\n .subscribe((results) => {\n this.asyncOptions.set(results);\n this.isLoading.set(false);\n });\n\n // Keep the highlighted option visible while navigating with the keyboard\n // (after render, so the option element exists in the overlay pane).\n afterRenderEffect(() => {\n const id = this.activeDescendantId();\n if (!id) return;\n untracked(() => {\n // ids are generated from a counter, so no CSS escaping is needed\n this.dropdownEl()\n ?.nativeElement.querySelector<HTMLElement>(`#${id}`)\n ?.scrollIntoView?.({ block: 'nearest' });\n });\n });\n }\n\n writeValue(value: ComboboxValue): void {\n if (this.multiple()) {\n this.selectedMultiple.set(Array.isArray(value) ? value : []);\n } else {\n const single = value && !Array.isArray(value) ? value : null;\n this.selectedSingle.set(single);\n this.query.set(single ? single.label : '');\n }\n }\n\n registerOnChange(fn: (value: ComboboxValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n /**\n * Clear the current selection and query. Emits `null` (single) or `[]`\n * (multiple) exactly once, like a user-initiated deselect.\n */\n clear(): void {\n this.query.set('');\n this.highlightedIndex.set(-1);\n this.isOpen.set(false);\n const value: ComboboxValue = this.multiple() ? [] : null;\n if (this.multiple()) {\n this.selectedMultiple.set([]);\n } else {\n this.selectedSingle.set(null);\n }\n this.onChange(value);\n this.valueChange.emit(value);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onInputChange(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.query.set(value);\n this.queryChange.emit(value);\n this.highlightedIndex.set(-1);\n\n if (this.loadOptions()) {\n this.querySubject.next(value);\n }\n\n if (value.length >= this.minChars()) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputFocus(): void {\n if (this.query().length >= this.minChars() || this.options().length > 0) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputBlur(): void {\n this.onTouched();\n // Delay to allow click on dropdown\n setTimeout(() => this.isOpen.set(false), 200);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const flat = this.flatOptions();\n const total = flat.length + (this.showCreateOption() ? 1 : 0);\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.isOpen.set(true);\n if (total > 0) this.highlightedIndex.update((i) => (i + 1) % total);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (total > 0) this.highlightedIndex.update((i) => (i - 1 + total) % total);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.highlightedIndex() >= 0) {\n if (this.highlightedIndex() === flat.length && this.showCreateOption()) {\n this.onCreateNew();\n } else {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n } else if (this.showCreateOption()) {\n this.onCreateNew();\n }\n break;\n case 'Escape':\n if (this.isOpen()) {\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n // Escape consumed by the list — an enclosing modal must not close too.\n event.stopPropagation();\n }\n break;\n case 'Tab':\n if (this.highlightedIndex() >= 0 && this.isOpen()) {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n this.isOpen.set(false);\n break;\n case 'Backspace':\n if (this.multiple() && !this.query() && this.selectedMultiple().length > 0) {\n this.removeSelected(this.selectedMultiple()[this.selectedMultiple().length - 1]);\n }\n break;\n }\n }\n\n protected selectOption(option: ComboboxOption): void {\n if (this.multiple()) {\n this.selectedMultiple.update((sel) => [...sel, option]);\n this.query.set('');\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n } else {\n this.selectedSingle.set(option);\n this.query.set(option.label);\n this.onChange(option);\n this.valueChange.emit(option);\n }\n this.optionSelected.emit(option);\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n }\n\n protected removeSelected(option: ComboboxOption): void {\n if (this.isDisabled()) return;\n this.selectedMultiple.update((sel) =>\n sel.filter((s) => s.value !== option.value)\n );\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onCreateNew(): void {\n const q = this.query().trim();\n if (!q) return;\n const newOption: ComboboxOption = { value: q, label: q };\n this.created.emit(q);\n this.selectOption(newOption);\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n const target = event.target as Node | null;\n // The dropdown lives in the CDK overlay container, outside the host element.\n if (\n !this.elRef.nativeElement.contains(target) &&\n !this.dropdownEl()?.nativeElement.contains(target)\n ) {\n this.isOpen.set(false);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <div #inputWrapper class=\"lc-combobox__input-wrapper\">\n <!-- Selected chips (multiple mode) -->\n @if (multiple()) {\n @for (sel of selectedMultiple(); track sel.value) {\n <lc-chip\n [removable]=\"!isDisabled()\"\n size=\"sm\"\n (remove)=\"removeSelected(sel)\"\n >{{ sel.label }}</lc-chip>\n }\n }\n\n <input\n #inputEl\n type=\"text\"\n class=\"lc-combobox__input\"\n [id]=\"inputId\"\n [placeholder]=\"multiple() && selectedMultiple().length > 0 ? '' : placeholder()\"\n [value]=\"query()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-invalid]=\"error() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (isLoading() || loading()) {\n <lc-spinner size=\"sm\" class=\"lc-combobox__spinner\" />\n } @else if (!multiple() && selectedSingle()) {\n <button\n type=\"button\"\n class=\"lc-combobox__clear\"\n [disabled]=\"isDisabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onClearClick()\"\n tabindex=\"-1\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" />\n </button>\n }\n </div>\n\n <!-- Dropdown: rendered in the CDK overlay container so overflow-hidden\n ancestors cannot clip it. Focus stays in the input (mousedown is\n prevented on the panel), keyboard nav uses aria-activedescendant. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"inputWrapper\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayMatchWidth]=\"true\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n #dropdownEl\n class=\"lc-combobox__dropdown\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n >\n @for (group of groupedOptions(); track group.label) {\n @if (group.label) {\n <div class=\"lc-combobox__group-header\" role=\"presentation\">{{ group.label }}</div>\n }\n @for (option of group.items; track option.value) {\n @let idx = flatOptions().indexOf(option);\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option\"\n [class.lc-combobox__option--highlighted]=\"idx === highlightedIndex()\"\n [class.lc-combobox__option--disabled]=\"option.disabled\"\n role=\"option\"\n [id]=\"optionId(idx)\"\n [attr.aria-selected]=\"idx === highlightedIndex()\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"!option.disabled && selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(idx)\"\n >\n @if (option.icon) {\n <lc-icon [name]=\"option.icon\" size=\"sm\" class=\"lc-combobox__option-icon\" />\n }\n <div class=\"lc-combobox__option-content\">\n <span class=\"lc-combobox__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"lc-combobox__option-desc\">{{ option.description }}</span>\n }\n </div>\n </div>\n }\n }\n\n @if (showCreateOption()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option lc-combobox__option--create\"\n [class.lc-combobox__option--highlighted]=\"highlightedIndex() === flatOptions().length\"\n role=\"option\"\n [id]=\"createOptionId\"\n [attr.aria-selected]=\"highlightedIndex() === flatOptions().length\"\n (click)=\"onCreateNew()\"\n (mouseenter)=\"highlightedIndex.set(flatOptions().length)\"\n >\n <lc-icon name=\"plus\" size=\"sm\" />\n <span>{{ createOptionLabel() }} \"{{ query() }}\"</span>\n </div>\n }\n\n @if (visibleOptions().length === 0 && !showCreateOption() && !isLoading() && !loading()) {\n <div class=\"lc-combobox__empty\">{{ emptyMessage() }}</div>\n }\n </div>\n </ng-template>\n\n @if (helperText() && !error()) {\n <span class=\"lc-combobox__helper\" [id]=\"inputId + '-helper'\">{{ helperText() }}</span>\n }\n @if (error()) {\n <span class=\"lc-combobox__error\" [id]=\"inputId + '-error'\" role=\"alert\">{{ error() }}</span>\n }\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-combobox.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.ts","../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n afterRenderEffect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { Observable, Subject, catchError, debounce, defer, of, switchMap, timer } from 'rxjs';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_PLUS, ICON_X_MARK } from '@lifecorner/angular-ui-kit/icons';\nimport { SpinnerComponent } from '@lifecorner/angular-ui-kit/spinner';\nimport { ChipComponent } from '@lifecorner/angular-ui-kit/chip';\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n description?: string;\n icon?: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport type ComboboxValue = ComboboxOption | ComboboxOption[] | null;\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/**\n * Combobox / async autocomplete component.\n *\n * Supports free-text input with sync/async option suggestions,\n * single/multiple selection, create new entries, and keyboard navigation.\n * The suggestion list is rendered in a CDK overlay so it is never clipped\n * by `overflow: hidden` ancestors (cards, modals, table cells).\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(value)]=\"assignee\"\n * allowCreate\n * />\n * ```\n */\n@Component({\n selector: 'lc-combobox',\n standalone: true,\n imports: [OverlayModule, IconComponent, SpinnerComponent, ChipComponent],\n viewProviders: [ɵprovideKitIcons([ICON_X_MARK, ICON_PLUS])],\n templateUrl: './combobox.component.html',\n styleUrls: ['./combobox.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => ComboboxComponent),\n multi: true,\n },\n ],\n})\nexport class ComboboxComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids so label/listbox/options can be linked via ARIA */\n readonly inputId = `lc-combobox-${++ComboboxComponent.nextId}`;\n readonly listboxId = `${this.inputId}-listbox`;\n protected readonly createOptionId = `${this.listboxId}-create`;\n\n private readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputEl');\n private readonly dropdownEl = viewChild<ElementRef<HTMLElement>>('dropdownEl');\n\n private readonly elRef = inject(ElementRef);\n private readonly querySubject = new Subject<string>();\n\n /** Sync options */\n readonly options = input<ComboboxOption[]>([]);\n\n /** Async option loader */\n readonly loadOptions = input<((query: string) => Observable<ComboboxOption[]>)>();\n\n /** Debounce for async queries */\n readonly debounceMs = input<number>(250);\n\n /** Minimum characters before triggering search */\n readonly minChars = input<number>(1);\n\n /** Placeholder text */\n readonly placeholder = input<string>('Search…');\n\n /** Label */\n readonly label = input<string>();\n\n /** Helper text */\n readonly helperText = input<string>();\n\n /** Error message */\n readonly error = input<string>();\n\n /** Disabled state */\n readonly disabled = input<boolean>(false);\n\n /** Allow multiple selections */\n readonly multiple = input<boolean>(false);\n\n /** Allow creating new entries */\n readonly allowCreate = input<boolean>(false);\n\n /** Show loading spinner (controlled) */\n readonly loading = input<boolean>(false);\n\n /** Empty state message */\n readonly emptyMessage = input<string>('No results');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Label before the query in the \"create\" option (`allowCreate`): `Create \"query\"`. */\n readonly createOptionLabel = input('Create');\n\n /** Size */\n readonly size = input<ComboboxSize>('md');\n\n /** Value change event */\n readonly valueChange = output<ComboboxValue>();\n\n /** Query change event */\n readonly queryChange = output<string>();\n\n /** Option selected event */\n readonly optionSelected = output<ComboboxOption>();\n\n /** Created event (allowCreate) */\n readonly created = output<string>();\n\n /** Internal state */\n protected query = signal('');\n protected isOpen = signal(false);\n protected highlightedIndex = signal(-1);\n protected asyncOptions = signal<ComboboxOption[]>([]);\n protected isLoading = signal(false);\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n /** Selected values */\n protected selectedSingle = signal<ComboboxOption | null>(null);\n protected selectedMultiple = signal<ComboboxOption[]>([]);\n\n /** Resolved visible options */\n protected visibleOptions = computed(() => {\n const q = this.query().toLowerCase();\n const loader = this.loadOptions();\n\n let opts: ComboboxOption[];\n if (loader) {\n opts = this.asyncOptions();\n } else {\n opts = this.options();\n if (q.length >= this.minChars()) {\n opts = opts.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.value.toLowerCase().includes(q) ||\n (o.description && o.description.toLowerCase().includes(q))\n );\n }\n }\n\n // Remove already selected in multiple mode\n if (this.multiple()) {\n const selected = new Set(this.selectedMultiple().map((s) => s.value));\n opts = opts.filter((o) => !selected.has(o.value));\n }\n\n return opts;\n });\n\n /** Grouped options */\n protected groupedOptions = computed(() => {\n const opts = this.visibleOptions();\n const groups = new Map<string, ComboboxOption[]>();\n\n for (const opt of opts) {\n const group = opt.group || '';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push(opt);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({\n label,\n items,\n }));\n });\n\n /** Flat list for keyboard nav */\n protected flatOptions = computed(() => {\n return this.groupedOptions().flatMap((g) => g.items);\n });\n\n /** Whether to show \"Create\" option */\n protected showCreateOption = computed(() => {\n if (!this.allowCreate()) return false;\n const q = this.query().trim();\n if (!q) return false;\n const exact = this.visibleOptions().some(\n (o) => o.label.toLowerCase() === q.toLowerCase()\n );\n return !exact;\n });\n\n /** id of the highlighted option — announced via aria-activedescendant */\n protected readonly activeDescendantId = computed(() => {\n if (!this.isOpen()) return null;\n const i = this.highlightedIndex();\n if (i < 0) return null;\n if (i === this.flatOptions().length) {\n return this.showCreateOption() ? this.createOptionId : null;\n }\n return i < this.flatOptions().length ? this.optionId(i) : null;\n });\n\n /** ids referenced by aria-describedby (helper / error) */\n protected readonly describedBy = computed(() => {\n if (this.error()) return `${this.inputId}-error`;\n if (this.helperText()) return `${this.inputId}-helper`;\n return null;\n });\n\n /** Container classes */\n protected containerClasses = computed(() => {\n const classes = [`lc-combobox`, `lc-combobox--${this.size()}`];\n if (this.isDisabled()) classes.push('lc-combobox--disabled');\n if (this.error()) classes.push('lc-combobox--error');\n if (this.isOpen()) classes.push('lc-combobox--open');\n return classes.join(' ');\n });\n\n protected optionId(index: number): string {\n return `${this.listboxId}-opt-${index}`;\n }\n\n // ControlValueAccessor\n private onChange: (value: ComboboxValue) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n constructor() {\n // Async loading pipe. `debounce` (not `debounceTime`) reads the signal per\n // emission, so `debounceMs` is honoured after inputs are populated.\n this.querySubject\n .pipe(\n debounce(() => timer(this.debounceMs())),\n switchMap((q) => {\n const loader = this.loadOptions();\n if (!loader || q.length < this.minChars()) {\n return of([] as ComboboxOption[]);\n }\n this.isLoading.set(true);\n // `defer` turns a synchronously throwing loader into an error\n // notification; `catchError` keeps the pipe alive for the next query.\n return defer(() => loader(q)).pipe(catchError(() => of([] as ComboboxOption[])));\n }),\n takeUntilDestroyed()\n )\n .subscribe((results) => {\n this.asyncOptions.set(results);\n this.isLoading.set(false);\n });\n\n // Keep the highlighted option visible while navigating with the keyboard\n // (after render, so the option element exists in the overlay pane).\n afterRenderEffect(() => {\n const id = this.activeDescendantId();\n if (!id) return;\n untracked(() => {\n // ids are generated from a counter, so no CSS escaping is needed\n this.dropdownEl()\n ?.nativeElement.querySelector<HTMLElement>(`#${id}`)\n ?.scrollIntoView?.({ block: 'nearest' });\n });\n });\n }\n\n writeValue(value: ComboboxValue): void {\n if (this.multiple()) {\n this.selectedMultiple.set(Array.isArray(value) ? value : []);\n } else {\n const single = value && !Array.isArray(value) ? value : null;\n this.selectedSingle.set(single);\n this.query.set(single ? single.label : '');\n }\n }\n\n registerOnChange(fn: (value: ComboboxValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n /**\n * Clear the current selection and query. Emits `null` (single) or `[]`\n * (multiple) exactly once, like a user-initiated deselect.\n */\n clear(): void {\n this.query.set('');\n this.highlightedIndex.set(-1);\n this.isOpen.set(false);\n const value: ComboboxValue = this.multiple() ? [] : null;\n if (this.multiple()) {\n this.selectedMultiple.set([]);\n } else {\n this.selectedSingle.set(null);\n }\n this.onChange(value);\n this.valueChange.emit(value);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onInputChange(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.query.set(value);\n this.queryChange.emit(value);\n this.highlightedIndex.set(-1);\n\n if (this.loadOptions()) {\n this.querySubject.next(value);\n }\n\n if (value.length >= this.minChars()) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputFocus(): void {\n if (this.query().length >= this.minChars() || this.options().length > 0) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputBlur(): void {\n this.onTouched();\n // Delay to allow click on dropdown\n setTimeout(() => this.isOpen.set(false), 200);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const flat = this.flatOptions();\n const total = flat.length + (this.showCreateOption() ? 1 : 0);\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.isOpen.set(true);\n if (total > 0) this.highlightedIndex.update((i) => (i + 1) % total);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (total > 0) this.highlightedIndex.update((i) => (i - 1 + total) % total);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.highlightedIndex() >= 0) {\n if (this.highlightedIndex() === flat.length && this.showCreateOption()) {\n this.onCreateNew();\n } else {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n } else if (this.showCreateOption()) {\n this.onCreateNew();\n }\n break;\n case 'Escape':\n if (this.isOpen()) {\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n // Escape consumed by the list — an enclosing modal must not close too.\n event.stopPropagation();\n }\n break;\n case 'Tab':\n if (this.highlightedIndex() >= 0 && this.isOpen()) {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n this.isOpen.set(false);\n break;\n case 'Backspace':\n if (this.multiple() && !this.query() && this.selectedMultiple().length > 0) {\n this.removeSelected(this.selectedMultiple()[this.selectedMultiple().length - 1]);\n }\n break;\n }\n }\n\n protected selectOption(option: ComboboxOption): void {\n if (this.multiple()) {\n this.selectedMultiple.update((sel) => [...sel, option]);\n this.query.set('');\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n } else {\n this.selectedSingle.set(option);\n this.query.set(option.label);\n this.onChange(option);\n this.valueChange.emit(option);\n }\n this.optionSelected.emit(option);\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n }\n\n protected removeSelected(option: ComboboxOption): void {\n if (this.isDisabled()) return;\n this.selectedMultiple.update((sel) =>\n sel.filter((s) => s.value !== option.value)\n );\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onCreateNew(): void {\n const q = this.query().trim();\n if (!q) return;\n const newOption: ComboboxOption = { value: q, label: q };\n this.created.emit(q);\n this.selectOption(newOption);\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n const target = event.target as Node | null;\n // The dropdown lives in the CDK overlay container, outside the host element.\n if (\n !this.elRef.nativeElement.contains(target) &&\n !this.dropdownEl()?.nativeElement.contains(target)\n ) {\n this.isOpen.set(false);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <div #inputWrapper class=\"lc-combobox__input-wrapper\">\n <!-- Selected chips (multiple mode) -->\n @if (multiple()) {\n @for (sel of selectedMultiple(); track sel.value) {\n <lc-chip\n [removable]=\"!isDisabled()\"\n size=\"sm\"\n (remove)=\"removeSelected(sel)\"\n >{{ sel.label }}</lc-chip>\n }\n }\n\n <input\n #inputEl\n type=\"text\"\n class=\"lc-combobox__input\"\n [id]=\"inputId\"\n [placeholder]=\"multiple() && selectedMultiple().length > 0 ? '' : placeholder()\"\n [value]=\"query()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-invalid]=\"error() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (isLoading() || loading()) {\n <lc-spinner size=\"sm\" class=\"lc-combobox__spinner\" />\n } @else if (!multiple() && selectedSingle()) {\n <button\n type=\"button\"\n class=\"lc-combobox__clear\"\n [disabled]=\"isDisabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onClearClick()\"\n tabindex=\"-1\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" />\n </button>\n }\n </div>\n\n <!-- Dropdown: rendered in the CDK overlay container so overflow-hidden\n ancestors cannot clip it. Focus stays in the input (mousedown is\n prevented on the panel), keyboard nav uses aria-activedescendant. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"inputWrapper\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayMatchWidth]=\"true\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n #dropdownEl\n class=\"lc-combobox__dropdown\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n >\n @for (group of groupedOptions(); track group.label) {\n @if (group.label) {\n <div class=\"lc-combobox__group-header\" role=\"presentation\">{{ group.label }}</div>\n }\n @for (option of group.items; track option.value) {\n @let idx = flatOptions().indexOf(option);\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option\"\n [class.lc-combobox__option--highlighted]=\"idx === highlightedIndex()\"\n [class.lc-combobox__option--disabled]=\"option.disabled\"\n role=\"option\"\n [id]=\"optionId(idx)\"\n [attr.aria-selected]=\"idx === highlightedIndex()\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"!option.disabled && selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(idx)\"\n >\n @if (option.icon) {\n <lc-icon [name]=\"option.icon\" size=\"sm\" class=\"lc-combobox__option-icon\" />\n }\n <div class=\"lc-combobox__option-content\">\n <span class=\"lc-combobox__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"lc-combobox__option-desc\">{{ option.description }}</span>\n }\n </div>\n </div>\n }\n }\n\n @if (showCreateOption()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option lc-combobox__option--create\"\n [class.lc-combobox__option--highlighted]=\"highlightedIndex() === flatOptions().length\"\n role=\"option\"\n [id]=\"createOptionId\"\n [attr.aria-selected]=\"highlightedIndex() === flatOptions().length\"\n (click)=\"onCreateNew()\"\n (mouseenter)=\"highlightedIndex.set(flatOptions().length)\"\n >\n <lc-icon name=\"plus\" size=\"sm\" />\n <span>{{ createOptionLabel() }} \"{{ query() }}\"</span>\n </div>\n }\n\n @if (visibleOptions().length === 0 && !showCreateOption() && !isLoading() && !loading()) {\n <div class=\"lc-combobox__empty\">{{ emptyMessage() }}</div>\n }\n </div>\n </ng-template>\n\n @if (helperText() && !error()) {\n <span class=\"lc-combobox__helper\" [id]=\"inputId + '-helper'\">{{ helperText() }}</span>\n }\n @if (error()) {\n <span class=\"lc-combobox__error\" [id]=\"inputId + '-error'\" role=\"alert\">{{ error() }}</span>\n }\n</div>\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ApplicationRef, ChangeDetectionStrategy, Component, EnvironmentInjector, Injectable, computed, createComponent, effect, inject, input, output, signal } from "@angular/core";
3
3
  import { FormsModule } from "@angular/forms";
4
- import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
4
+ import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
5
+ import { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from "@lifecorner/angular-ui-kit/icons";
5
6
  import { ButtonComponent } from "@lifecorner/angular-ui-kit/button";
6
7
  import { InputComponent } from "@lifecorner/angular-ui-kit/input";
7
8
  import { ModalComponent } from "@lifecorner/angular-ui-kit/modal";
@@ -280,6 +281,7 @@ var ConfirmDialogComponent = class ConfirmDialogComponent {
280
281
  ]
281
282
  }
282
283
  ],
284
+ viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],
283
285
  changeDetection: i0.ChangeDetectionStrategy.OnPush
284
286
  });
285
287
  };
@@ -300,6 +302,7 @@ i0.ɵɵngDeclareClassMetadata({
300
302
  ModalComponent,
301
303
  InputComponent
302
304
  ],
305
+ viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],
303
306
  changeDetection: ChangeDetectionStrategy.OnPush,
304
307
  template: "<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n",
305
308
  styles: [".lc-confirm__header{display:flex;align-items:center;gap:.5rem}.lc-confirm__header h2{margin:0;font-size:var(--font-size-lg, 1.125rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-confirm__message{margin:0;color:var(--color-text-secondary, #4b5563);font-size:var(--font-size-sm, .875rem);line-height:1.6}.lc-confirm__preview{margin-top:1rem}.lc-confirm__preview:empty{display:none}.lc-confirm__require-text{margin-top:1rem}.lc-confirm__footer{display:flex;gap:.5rem;justify-content:flex-end}\n"]
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from '@lifecorner/angular-ui-kit/icons';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, DestroyRef, inject, input, output, signal, viewChild } from "@angular/core";
3
3
  import { ButtonComponent } from "@lifecorner/angular-ui-kit/button";
4
- import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
4
+ import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
5
+ import { ICON_CHECK } from "@lifecorner/angular-ui-kit/icons";
5
6
  import { InputComponent } from "@lifecorner/angular-ui-kit/input";
6
7
  const CONFIRMATION_MS = 2e3;
7
8
  var CopyFieldComponent = class CopyFieldComponent {
@@ -201,6 +202,7 @@ var CopyFieldComponent = class CopyFieldComponent {
201
202
  ]
202
203
  }
203
204
  ],
205
+ viewProviders: [ɵprovideKitIcons([ICON_CHECK])],
204
206
  changeDetection: i0.ChangeDetectionStrategy.OnPush
205
207
  });
206
208
  };
@@ -218,6 +220,7 @@ i0.ɵɵngDeclareClassMetadata({
218
220
  ButtonComponent,
219
221
  IconComponent
220
222
  ],
223
+ viewProviders: [ɵprovideKitIcons([ICON_CHECK])],
221
224
  changeDetection: ChangeDetectionStrategy.OnPush,
222
225
  template: "<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n",
223
226
  styles: [":host{display:block;width:100%}.lc-copy-field{position:relative;display:flex;gap:var(--lc-density-gap-sm, .5rem)}.lc-copy-field--stacked{flex-direction:column}.lc-copy-field--inline{flex-direction:row;align-items:flex-end}.lc-copy-field--inline .lc-copy-field__value{flex:1;min-width:0}.lc-copy-field--inline .lc-copy-field__action{flex:none}.lc-copy-field__live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"]
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHECK } from '@lifecorner/angular-ui-kit/icons';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CHECK])],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, ElementRef, HostListener, afterRenderEffect, computed, forwardRef, inject, input, output, signal, untracked, viewChild } from "@angular/core";
3
3
  import { NG_VALUE_ACCESSOR } from "@angular/forms";
4
- import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
4
+ import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
5
+ import { ICON_CALENDAR } from "@lifecorner/angular-ui-kit/icons";
5
6
  const REFERENCE_WEEK = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i));
6
7
  var DateRangePickerComponent = class DateRangePickerComponent {
7
8
  static nextId = 0;
@@ -341,6 +342,7 @@ var DateRangePickerComponent = class DateRangePickerComponent {
341
342
  "strict"
342
343
  ]
343
344
  }],
345
+ viewProviders: [ɵprovideKitIcons([ICON_CALENDAR])],
344
346
  changeDetection: i0.ChangeDetectionStrategy.OnPush
345
347
  });
346
348
  };
@@ -355,6 +357,7 @@ i0.ɵɵngDeclareClassMetadata({
355
357
  selector: "lc-date-range-picker",
356
358
  standalone: true,
357
359
  imports: [IconComponent],
360
+ viewProviders: [ɵprovideKitIcons([ICON_CALENDAR])],
358
361
  changeDetection: ChangeDetectionStrategy.OnPush,
359
362
  providers: [{
360
363
  provide: NG_VALUE_ACCESSOR,