@caribeng/ui 22.2.0 → 22.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +93 -11
  2. package/fesm2022/caribeng-ui-accordion.mjs +2 -2
  3. package/fesm2022/caribeng-ui-avatar.mjs +2 -2
  4. package/fesm2022/caribeng-ui-badge.mjs +8 -2
  5. package/fesm2022/caribeng-ui-breadcrumb.mjs +13 -6
  6. package/fesm2022/caribeng-ui-chart.mjs +8 -5
  7. package/fesm2022/caribeng-ui-chat.mjs +1303 -0
  8. package/fesm2022/caribeng-ui-code-block.mjs +332 -0
  9. package/fesm2022/caribeng-ui-colorpicker.mjs +99 -5
  10. package/fesm2022/caribeng-ui-command-palette.mjs +476 -0
  11. package/fesm2022/caribeng-ui-confirmdialog.mjs +78 -13
  12. package/fesm2022/caribeng-ui-confirmpopup.mjs +91 -16
  13. package/fesm2022/caribeng-ui-contextmenu.mjs +8 -4
  14. package/fesm2022/caribeng-ui-copy-button.mjs +230 -0
  15. package/fesm2022/caribeng-ui-dataview.mjs +4 -1
  16. package/fesm2022/caribeng-ui-dock.mjs +52 -12
  17. package/fesm2022/caribeng-ui-drawer.mjs +9 -4
  18. package/fesm2022/caribeng-ui-editor.mjs +21 -0
  19. package/fesm2022/caribeng-ui-fieldset.mjs +2 -2
  20. package/fesm2022/caribeng-ui-file-card.mjs +134 -17
  21. package/fesm2022/caribeng-ui-folder-card.mjs +122 -12
  22. package/fesm2022/caribeng-ui-inlinemessage.mjs +2 -2
  23. package/fesm2022/caribeng-ui-inputmask.mjs +8 -2
  24. package/fesm2022/caribeng-ui-kanban.mjs +4612 -0
  25. package/fesm2022/caribeng-ui-kbd.mjs +122 -0
  26. package/fesm2022/caribeng-ui-megamenu.mjs +13 -9
  27. package/fesm2022/caribeng-ui-mentions.mjs +495 -0
  28. package/fesm2022/caribeng-ui-menu.mjs +8 -4
  29. package/fesm2022/caribeng-ui-menubar.mjs +9 -5
  30. package/fesm2022/caribeng-ui-message.mjs +6 -3
  31. package/fesm2022/caribeng-ui-organizationchart.mjs +6 -10
  32. package/fesm2022/caribeng-ui-panel.mjs +6 -6
  33. package/fesm2022/caribeng-ui-panelmenu.mjs +9 -6
  34. package/fesm2022/caribeng-ui-phone-input.mjs +688 -0
  35. package/fesm2022/caribeng-ui-pricing.mjs +263 -69
  36. package/fesm2022/caribeng-ui-qrcode.mjs +564 -0
  37. package/fesm2022/caribeng-ui-ripple.mjs +2 -0
  38. package/fesm2022/caribeng-ui-scrolltop.mjs +3 -1
  39. package/fesm2022/caribeng-ui-sidebar.mjs +573 -0
  40. package/fesm2022/caribeng-ui-stepper.mjs +10 -3
  41. package/fesm2022/caribeng-ui-table.mjs +10 -4
  42. package/fesm2022/caribeng-ui-tabmenu.mjs +8 -4
  43. package/fesm2022/caribeng-ui-tieredmenu.mjs +109 -19
  44. package/fesm2022/caribeng-ui.mjs +388 -1
  45. package/package.json +42 -2
  46. package/schematics/collection.json +5 -0
  47. package/schematics/migrate-from-primeng/core-icons.json +1 -0
  48. package/schematics/migrate-from-primeng/icons.js +269 -0
  49. package/schematics/migrate-from-primeng/index.js +290 -0
  50. package/schematics/migrate-from-primeng/mappings/button.js +93 -0
  51. package/schematics/migrate-from-primeng/mappings/card.js +33 -0
  52. package/schematics/migrate-from-primeng/mappings/checkbox.js +44 -0
  53. package/schematics/migrate-from-primeng/mappings/confirm.js +221 -0
  54. package/schematics/migrate-from-primeng/mappings/datepicker.js +121 -0
  55. package/schematics/migrate-from-primeng/mappings/dialog.js +84 -0
  56. package/schematics/migrate-from-primeng/mappings/index.js +88 -0
  57. package/schematics/migrate-from-primeng/mappings/inputnumber.js +62 -0
  58. package/schematics/migrate-from-primeng/mappings/inputtext.js +60 -0
  59. package/schematics/migrate-from-primeng/mappings/menu.js +468 -0
  60. package/schematics/migrate-from-primeng/mappings/multiselect.js +49 -0
  61. package/schematics/migrate-from-primeng/mappings/radiobutton.js +22 -0
  62. package/schematics/migrate-from-primeng/mappings/rules.js +206 -0
  63. package/schematics/migrate-from-primeng/mappings/select.js +97 -0
  64. package/schematics/migrate-from-primeng/mappings/service-calls.js +100 -0
  65. package/schematics/migrate-from-primeng/mappings/table.js +613 -0
  66. package/schematics/migrate-from-primeng/mappings/tabs.js +225 -0
  67. package/schematics/migrate-from-primeng/mappings/tag.js +29 -0
  68. package/schematics/migrate-from-primeng/mappings/textarea.js +44 -0
  69. package/schematics/migrate-from-primeng/mappings/toast.js +173 -0
  70. package/schematics/migrate-from-primeng/mappings/toggleswitch.js +37 -0
  71. package/schematics/migrate-from-primeng/mappings/tooltip.js +44 -0
  72. package/schematics/migrate-from-primeng/mappings/types.js +10 -0
  73. package/schematics/migrate-from-primeng/report.js +79 -0
  74. package/schematics/migrate-from-primeng/schema.js +2 -0
  75. package/schematics/migrate-from-primeng/schema.json +34 -0
  76. package/schematics/migrate-from-primeng/template.js +387 -0
  77. package/schematics/migrate-from-primeng/todo.js +5 -0
  78. package/schematics/migrate-from-primeng/typescript.js +442 -0
  79. package/schematics/migrate-from-primeng/workspace.js +117 -0
  80. package/schematics/ng-add/index.js +16 -1
  81. package/types/caribeng-ui-badge.d.ts +3 -1
  82. package/types/caribeng-ui-breadcrumb.d.ts +8 -0
  83. package/types/caribeng-ui-chart.d.ts +3 -1
  84. package/types/caribeng-ui-chat.d.ts +299 -0
  85. package/types/caribeng-ui-code-block.d.ts +65 -0
  86. package/types/caribeng-ui-colorpicker.d.ts +5 -1
  87. package/types/caribeng-ui-command-palette.d.ts +133 -0
  88. package/types/caribeng-ui-confirmdialog.d.ts +34 -2
  89. package/types/caribeng-ui-confirmpopup.d.ts +39 -2
  90. package/types/caribeng-ui-contextmenu.d.ts +7 -0
  91. package/types/caribeng-ui-copy-button.d.ts +90 -0
  92. package/types/caribeng-ui-dataview.d.ts +2 -0
  93. package/types/caribeng-ui-dock.d.ts +13 -1
  94. package/types/caribeng-ui-drawer.d.ts +3 -1
  95. package/types/caribeng-ui-file-card.d.ts +27 -2
  96. package/types/caribeng-ui-folder-card.d.ts +27 -5
  97. package/types/caribeng-ui-inputmask.d.ts +3 -1
  98. package/types/caribeng-ui-kanban.d.ts +783 -0
  99. package/types/caribeng-ui-kbd.d.ts +36 -0
  100. package/types/caribeng-ui-megamenu.d.ts +11 -0
  101. package/types/caribeng-ui-mentions.d.ts +127 -0
  102. package/types/caribeng-ui-menu.d.ts +7 -0
  103. package/types/caribeng-ui-menubar.d.ts +7 -0
  104. package/types/caribeng-ui-message.d.ts +2 -0
  105. package/types/caribeng-ui-panelmenu.d.ts +7 -0
  106. package/types/caribeng-ui-phone-input.d.ts +168 -0
  107. package/types/caribeng-ui-pricing.d.ts +41 -4
  108. package/types/caribeng-ui-qrcode.d.ts +88 -0
  109. package/types/caribeng-ui-sidebar.d.ts +167 -0
  110. package/types/caribeng-ui-stepper.d.ts +2 -0
  111. package/types/caribeng-ui-table.d.ts +1 -1
  112. package/types/caribeng-ui-tabmenu.d.ts +7 -0
  113. package/types/caribeng-ui-tieredmenu.d.ts +17 -1
  114. package/types/caribeng-ui.d.ts +276 -2
  115. package/styles/caribeng.css +0 -380
  116. package/styles/scss/_mixins.scss +0 -46
  117. package/styles/scss/_overlay.scss +0 -15
  118. package/styles/scss/_tokens.scss +0 -267
  119. package/styles/scss/_utilities.scss +0 -73
  120. package/styles/scss/_variables.scss +0 -33
  121. package/styles/scss/index.scss +0 -16
@@ -0,0 +1,332 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, booleanAttribute, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { CbCopyButton } from '@caribeng/ui/copy-button';
4
+
5
+ /*
6
+ * Resaltado de sintaxis propio de CaribeNG, ligero y sin dependencias.
7
+ * Devuelve tokens (no HTML): quien los pinta decide cómo, sin innerHTML.
8
+ * Lenguajes: TypeScript/JavaScript, HTML/XML (y plantillas Angular), CSS/SCSS,
9
+ * JSON, Bash, Python y SQL. Un lenguaje desconocido se devuelve como texto.
10
+ */
11
+ const words = (list) => new RegExp(`\\b(?:${list.trim().split(/\s+/).join('|')})\\b`, 'y');
12
+ const STRING_DQ = /"(?:\\.|[^"\\\n])*"?/y;
13
+ const STRING_SQ = /'(?:\\.|[^'\\\n])*'?/y;
14
+ const NUMBER = /\b(?:0x[\da-fA-F_]+|0b[01_]+|\d[\d_]*(?:\.\d[\d_]*)?(?:[eE][+-]?\d+)?n?)\b/y;
15
+ const SPACE = /\s+/y;
16
+ const JS = [
17
+ ['comment', /\/\/.*/y],
18
+ ['comment', /\/\*[\s\S]*?(?:\*\/|$)/y],
19
+ ['string', /`(?:\\[\s\S]|[^`\\])*`?/y],
20
+ ['string', STRING_DQ],
21
+ ['string', STRING_SQ],
22
+ ['keyword', /@[A-Za-z_]\w*/y],
23
+ [
24
+ 'keyword',
25
+ words(`abstract as async await break case catch class const constructor continue debugger declare default delete do else enum
26
+ export extends finally for from function get if implements import in instanceof interface is keyof let namespace new of
27
+ override private protected public readonly return satisfies set static super switch throw try type typeof var void while with yield`),
28
+ ],
29
+ ['builtin', words('true false null undefined this NaN Infinity console window document Math JSON Promise Array Object String Number Boolean Date Map Set Error any unknown never string number boolean symbol bigint')],
30
+ ['number', NUMBER],
31
+ ['function', /[A-Za-z_$][\w$]*(?=\s*(?:<[^>()]*>)?\()/y],
32
+ ['variable', /[A-Za-z_$][\w$]*/y],
33
+ ['operator', /=>|\?\?=?|\?\.|\.{3}|[=!]==?|[<>]=?|&&|\|\||[-+*/%&|^~!?:=]+/y],
34
+ ['punctuation', /[{}()[\];,.<>]/y],
35
+ ];
36
+ const HTML = [
37
+ // Dentro de una etiqueta: atributos, valores y cierre.
38
+ ['tag', /\/?>/y, { in: 'tag', exit: true }],
39
+ ['string', /"[^"]*"?/y, { in: 'tag' }],
40
+ ['string', /'[^']*'?/y, { in: 'tag' }],
41
+ ['operator', /=/y, { in: 'tag' }],
42
+ ['attr', /[^\s=/>"']+/y, { in: 'tag' }],
43
+ // Fuera: comentarios, etiquetas, interpolación y bloques de control de Angular.
44
+ ['comment', /<!--[\s\S]*?(?:-->|$)/y],
45
+ ['keyword', /<!DOCTYPE[^>]*>/iy],
46
+ ['tag', /<\/?[A-Za-z][\w:.-]*/y, { enter: 'tag' }],
47
+ ['variable', /\{\{[\s\S]*?(?:\}\}|$)/y],
48
+ ['keyword', /@(?:if|else if|else|for|empty|switch|case|default|defer|placeholder|loading|let)\b/y],
49
+ ['plain', /[^<{@\s]+/y],
50
+ ];
51
+ const CSS = [
52
+ ['comment', /\/\*[\s\S]*?(?:\*\/|$)/y],
53
+ ['comment', /\/\/.*/y],
54
+ ['string', STRING_DQ],
55
+ ['string', STRING_SQ],
56
+ ['keyword', /@[\w-]+/y],
57
+ ['variable', /--[\w-]+|\$[\w-]+/y],
58
+ ['number', /#[\da-fA-F]{3,8}\b/y],
59
+ ['number', /-?(?:\d+\.?\d*|\.\d+)(?:px|rem|em|%|vh|vw|vmin|vmax|s|ms|deg|fr|ch|ex|dvh|svh|lh)?\b/y],
60
+ ['function', /[\w-]+(?=\()/y],
61
+ ['property', /[\w-]+(?=\s*:(?!:))/y],
62
+ ['keyword', words('!important important')],
63
+ ['punctuation', /[{}()[\];:,>+~*]/y],
64
+ ['plain', /[\w-]+|[.#&]/y],
65
+ ];
66
+ const JSON_RULES = [
67
+ ['property', /"(?:\\.|[^"\\\n])*"(?=\s*:)/y],
68
+ ['string', STRING_DQ],
69
+ ['number', /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/y],
70
+ ['builtin', words('true false null')],
71
+ ['punctuation', /[{}[\]:,]/y],
72
+ ];
73
+ const BASH = [
74
+ ['comment', /#.*/y],
75
+ ['string', STRING_DQ],
76
+ ['string', STRING_SQ],
77
+ ['variable', /\$\{[^}]*\}?|\$[\w@#?*!$-]/y],
78
+ ['keyword', words('if then else elif fi for while until do done case esac in function return export local readonly unset source exit')],
79
+ ['builtin', words('echo cd ls cat cp mv rm mkdir touch grep sed awk curl wget sudo npm npx pnpm yarn node ng nx git docker kubectl')],
80
+ ['attr', /(?<=\s)--?[\w-]+/y],
81
+ ['number', /\b\d+\b/y],
82
+ ['operator', /&&|\|\||[|&;<>]+|=/y],
83
+ ];
84
+ const PYTHON = [
85
+ ['comment', /#.*/y],
86
+ ['string', /[rbfu]{0,2}(?:"""[\s\S]*?(?:"""|$)|'''[\s\S]*?(?:'''|$))/iy],
87
+ ['string', /[rbfu]{0,2}(?:"(?:\\.|[^"\\\n])*"?|'(?:\\.|[^'\\\n])*'?)/iy],
88
+ ['keyword', /@[A-Za-z_][\w.]*/y],
89
+ ['keyword', words('and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal not or pass raise return try while with yield match case')],
90
+ ['builtin', words('True False None self print len range dict list set tuple str int float bool open super isinstance enumerate zip map filter')],
91
+ ['number', NUMBER],
92
+ ['function', /[A-Za-z_]\w*(?=\s*\()/y],
93
+ ['variable', /[A-Za-z_]\w*/y],
94
+ ['operator', /\*\*=?|\/\/=?|->|[-+*/%@&|^~<>!=]=?/y],
95
+ ['punctuation', /[{}()[\];,.:]/y],
96
+ ];
97
+ const SQL = [
98
+ ['comment', /--.*/y],
99
+ ['comment', /\/\*[\s\S]*?(?:\*\/|$)/y],
100
+ ['string', STRING_SQ],
101
+ ['property', /"(?:[^"]|"")*"?/y],
102
+ [
103
+ 'keyword',
104
+ new RegExp(`\\b(?:${'select from where and or not insert into values update set delete create table alter drop index view join left right inner outer full on as group by order having limit offset distinct union all case when then else end is null in between like exists primary key foreign references default returning with desc asc'.split(' ').join('|')})\\b`, 'iy'),
105
+ ],
106
+ ['function', /[A-Za-z_]\w*(?=\s*\()/y],
107
+ ['number', /\b\d+(?:\.\d+)?\b/y],
108
+ ['operator', /<>|[<>!]=?|[-+*/%=|]+/y],
109
+ ['punctuation', /[(),;.]/y],
110
+ ];
111
+ const LANGUAGES = {
112
+ ts: JS,
113
+ typescript: JS,
114
+ js: JS,
115
+ javascript: JS,
116
+ jsx: JS,
117
+ tsx: JS,
118
+ mjs: JS,
119
+ html: HTML,
120
+ xml: HTML,
121
+ svg: HTML,
122
+ angular: HTML,
123
+ css: CSS,
124
+ scss: CSS,
125
+ sass: CSS,
126
+ less: CSS,
127
+ json: JSON_RULES,
128
+ jsonc: JSON_RULES,
129
+ bash: BASH,
130
+ sh: BASH,
131
+ shell: BASH,
132
+ zsh: BASH,
133
+ console: BASH,
134
+ py: PYTHON,
135
+ python: PYTHON,
136
+ sql: SQL,
137
+ };
138
+ /** Nombre visible de un lenguaje ("ts" → "TypeScript"). */
139
+ function cbCodeLanguageLabel(language) {
140
+ const key = language.toLowerCase();
141
+ const names = {
142
+ ts: 'TypeScript', typescript: 'TypeScript', tsx: 'TSX', js: 'JavaScript', javascript: 'JavaScript', jsx: 'JSX', mjs: 'JavaScript',
143
+ html: 'HTML', xml: 'XML', svg: 'SVG', angular: 'Angular', css: 'CSS', scss: 'SCSS', sass: 'Sass', less: 'Less',
144
+ json: 'JSON', jsonc: 'JSON', bash: 'Bash', sh: 'Shell', shell: 'Shell', zsh: 'Zsh', console: 'Consola',
145
+ py: 'Python', python: 'Python', sql: 'SQL', text: 'Texto', txt: 'Texto', plaintext: 'Texto',
146
+ };
147
+ return names[key] ?? language;
148
+ }
149
+ /** Si hay reglas de resaltado para el lenguaje. */
150
+ function cbCodeSupports(language) {
151
+ return !!LANGUAGES[language.toLowerCase()];
152
+ }
153
+ function tokenize(code, rules) {
154
+ const tokens = [];
155
+ const push = (type, text) => {
156
+ const last = tokens[tokens.length - 1];
157
+ if (last && last.type === type && (type === 'plain' || type === 'punctuation'))
158
+ tokens[tokens.length - 1] = { type, text: last.text + text };
159
+ else
160
+ tokens.push({ type, text });
161
+ };
162
+ let pos = 0;
163
+ let state = null;
164
+ outer: while (pos < code.length) {
165
+ SPACE.lastIndex = pos;
166
+ const space = SPACE.exec(code);
167
+ if (space) {
168
+ push('plain', space[0]);
169
+ pos += space[0].length;
170
+ continue;
171
+ }
172
+ for (const [type, re, opts] of rules) {
173
+ // Las reglas sin `in` solo valen en el estado inicial.
174
+ if ((opts?.in ?? null) !== state)
175
+ continue;
176
+ re.lastIndex = pos;
177
+ const m = re.exec(code);
178
+ if (m && m[0].length) {
179
+ push(type, m[0]);
180
+ pos += m[0].length;
181
+ if (opts?.enter)
182
+ state = opts.enter;
183
+ if (opts?.exit)
184
+ state = null;
185
+ continue outer;
186
+ }
187
+ }
188
+ push('plain', code[pos]);
189
+ pos++;
190
+ }
191
+ return tokens;
192
+ }
193
+ /**
194
+ * Tokeniza `code` y lo reparte en líneas (los comentarios y strings de varias
195
+ * líneas se parten en cada salto). Lenguaje desconocido = texto plano.
196
+ */
197
+ function cbHighlight(code, language = '') {
198
+ const source = (code ?? '').replace(/\r\n?/g, '\n');
199
+ const rules = LANGUAGES[language.toLowerCase()];
200
+ const tokens = rules ? tokenize(source, rules) : [{ type: 'plain', text: source }];
201
+ const lines = [[]];
202
+ for (const token of tokens) {
203
+ const parts = token.text.split('\n');
204
+ parts.forEach((part, i) => {
205
+ if (i > 0)
206
+ lines.push([]);
207
+ if (part)
208
+ lines[lines.length - 1].push({ type: token.type, text: part });
209
+ });
210
+ }
211
+ return lines;
212
+ }
213
+ /** Interpreta `"1,3-5"` o `[1, 3, 4, 5]` como conjunto de números de línea. */
214
+ function cbParseLineSet(value) {
215
+ if (!value)
216
+ return new Set();
217
+ if (Array.isArray(value))
218
+ return new Set(value);
219
+ const set = new Set();
220
+ for (const part of String(value).split(',')) {
221
+ const [a, b] = part.split('-').map((n) => Number(n.trim()));
222
+ if (!Number.isFinite(a))
223
+ continue;
224
+ const end = Number.isFinite(b) ? b : a;
225
+ for (let n = Math.min(a, end); n <= Math.max(a, end); n++)
226
+ set.add(n);
227
+ }
228
+ return set;
229
+ }
230
+
231
+ /**
232
+ * Bloque de código de CaribeNG con resaltado de sintaxis propio (sin
233
+ * dependencias), nombre de archivo o lenguaje, botón de copiar, números de
234
+ * línea y líneas destacadas. Sigue el tema claro u oscuro.
235
+ *
236
+ * El código se pinta como texto (tokens), nunca como HTML.
237
+ *
238
+ * @example
239
+ * ```html
240
+ * <cb-code-block language="ts" filename="app.config.ts" [code]="codigo" lineNumbers highlightLines="3-4" />
241
+ * ```
242
+ */
243
+ class CbCodeBlock {
244
+ constructor() {
245
+ /** Código a mostrar. */
246
+ this.code = input('', /* @ts-ignore */
247
+ ...(ngDevMode ? [{ debugName: "code" }] : /* istanbul ignore next */ []));
248
+ /** Lenguaje (`ts`, `html`, `css`, `json`, `bash`, `python`, `sql`…). Desconocido = texto. */
249
+ this.language = input('', /* @ts-ignore */
250
+ ...(ngDevMode ? [{ debugName: "language" }] : /* istanbul ignore next */ []));
251
+ /** Nombre de archivo en la cabecera (en lugar del lenguaje). */
252
+ this.filename = input('', /* @ts-ignore */
253
+ ...(ngDevMode ? [{ debugName: "filename" }] : /* istanbul ignore next */ []));
254
+ this.lineNumbers = input(false, { ...(ngDevMode ? { debugName: "lineNumbers" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
255
+ /** Número de la primera línea. */
256
+ this.startLine = input(1, /* @ts-ignore */
257
+ ...(ngDevMode ? [{ debugName: "startLine" }] : /* istanbul ignore next */ []));
258
+ /** Líneas destacadas: `"2,5-7"` o `[2, 5, 6, 7]`. */
259
+ this.highlightLines = input('', /* @ts-ignore */
260
+ ...(ngDevMode ? [{ debugName: "highlightLines" }] : /* istanbul ignore next */ []));
261
+ /** Parte las líneas largas en lugar de hacer scroll horizontal. */
262
+ this.wrap = input(false, { ...(ngDevMode ? { debugName: "wrap" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
263
+ this.copyable = input(true, { ...(ngDevMode ? { debugName: "copyable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
264
+ /** Muestra la cabecera (lenguaje o archivo y copiar). */
265
+ this.header = input(true, { ...(ngDevMode ? { debugName: "header" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
266
+ /** Alto máximo con scroll (`20rem`). */
267
+ this.maxHeight = input('', /* @ts-ignore */
268
+ ...(ngDevMode ? [{ debugName: "maxHeight" }] : /* istanbul ignore next */ []));
269
+ /** Nombre del bloque. Por defecto, el archivo o el lenguaje. */
270
+ this.ariaLabel = input(undefined, /* @ts-ignore */
271
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
272
+ /** Tokens por línea (sin la línea vacía final que deja un salto de línea al terminar). */
273
+ this.lines = computed(() => cbHighlight(this.code().replace(/\n$/, ''), this.language()), /* @ts-ignore */
274
+ ...(ngDevMode ? [{ debugName: "lines" }] : /* istanbul ignore next */ []));
275
+ this.highlighted = computed(() => cbParseLineSet(this.highlightLines()), /* @ts-ignore */
276
+ ...(ngDevMode ? [{ debugName: "highlighted" }] : /* istanbul ignore next */ []));
277
+ this.languageLabel = computed(() => (this.language() ? cbCodeLanguageLabel(this.language()) : ''), /* @ts-ignore */
278
+ ...(ngDevMode ? [{ debugName: "languageLabel" }] : /* istanbul ignore next */ []));
279
+ this.showHeader = computed(() => this.header() && (!!this.filename() || !!this.language() || this.copyable()), /* @ts-ignore */
280
+ ...(ngDevMode ? [{ debugName: "showHeader" }] : /* istanbul ignore next */ []));
281
+ }
282
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbCodeBlock, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
283
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: CbCodeBlock, isStandalone: true, selector: "cb-code-block", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: false, transformFunction: null }, language: { classPropertyName: "language", publicName: "language", isSignal: true, isRequired: false, transformFunction: null }, filename: { classPropertyName: "filename", publicName: "filename", isSignal: true, isRequired: false, transformFunction: null }, lineNumbers: { classPropertyName: "lineNumbers", publicName: "lineNumbers", isSignal: true, isRequired: false, transformFunction: null }, startLine: { classPropertyName: "startLine", publicName: "startLine", isSignal: true, isRequired: false, transformFunction: null }, highlightLines: { classPropertyName: "highlightLines", publicName: "highlightLines", isSignal: true, isRequired: false, transformFunction: null }, wrap: { classPropertyName: "wrap", publicName: "wrap", isSignal: true, isRequired: false, transformFunction: null }, copyable: { classPropertyName: "copyable", publicName: "copyable", isSignal: true, isRequired: false, transformFunction: null }, header: { classPropertyName: "header", publicName: "header", isSignal: true, isRequired: false, transformFunction: null }, maxHeight: { classPropertyName: "maxHeight", publicName: "maxHeight", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.cb-code-block--wrap": "wrap()", "class.cb-code-block--numbers": "lineNumbers()" }, classAttribute: "cb-code-block" }, ngImport: i0, template: `
284
+ @if (showHeader()) {
285
+ <div class="cb-code-block__header">
286
+ <span class="cb-code-block__title">{{ filename() || languageLabel() }}</span>
287
+ @if (copyable()) {
288
+ <cb-copy-button class="cb-code-block__copy" [value]="code()" size="sm" />
289
+ }
290
+ </div>
291
+ }
292
+ <pre
293
+ class="cb-code-block__pre"
294
+ tabindex="0"
295
+ [style.max-height]="maxHeight() || null"
296
+ [attr.aria-label]="ariaLabel() ?? (filename() || languageLabel() || null)"
297
+ ><!-- En una línea: dentro de <pre> cada espacio cuenta. --><code class="cb-code-block__code">@for (line of lines(); track $index; let i = $index) {<span class="cb-code-block__line" [class.cb-code-block__line--hl]="highlighted().has(i + startLine())">@if (lineNumbers()) {<span class="cb-code-block__ln" aria-hidden="true">{{ i + startLine() }}</span>}<span class="cb-code-block__text">@for (token of line; track $index) {<span [class]="token.type === 'plain' ? null : 'cb-tok cb-tok-' + token.type">{{ token.text }}</span>}</span></span>}</code></pre>
298
+ `, isInline: true, styles: [":host{--cb-code-bg: #f6f8fa;--cb-code-fg: #1f2328;--cb-code-border: var(--cb-color-border);--cb-code-muted: #6e7781;--cb-code-hl: rgb(234 179 8 / .16);--cb-tok-keyword: #cf222e;--cb-tok-builtin: #0550ae;--cb-tok-string: #0a3069;--cb-tok-number: #0550ae;--cb-tok-comment: #6e7781;--cb-tok-function: #8250df;--cb-tok-operator: #cf222e;--cb-tok-punctuation: #57606a;--cb-tok-tag: #116329;--cb-tok-attr: #0550ae;--cb-tok-property: #0550ae;--cb-tok-variable: #1f2328;display:block;overflow:hidden;border:1px solid var(--cb-code-border);border-radius:var(--cb-radius-md, 8px);background:var(--cb-code-bg);color:var(--cb-code-fg);font-family:var(--cb-font-sans)}:host-context([data-theme=\"dark\"]){--cb-code-bg: #0d1117;--cb-code-fg: #e6edf3;--cb-code-muted: #8b949e;--cb-code-hl: rgb(234 179 8 / .14);--cb-tok-keyword: #ff7b72;--cb-tok-builtin: #79c0ff;--cb-tok-string: #a5d6ff;--cb-tok-number: #79c0ff;--cb-tok-comment: #8b949e;--cb-tok-function: #d2a8ff;--cb-tok-operator: #ff7b72;--cb-tok-punctuation: #b1bac4;--cb-tok-tag: #7ee787;--cb-tok-attr: #79c0ff;--cb-tok-property: #79c0ff;--cb-tok-variable: #e6edf3}.cb-code-block__header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;min-height:2.25rem;padding:.125rem .25rem .125rem .875rem;border-bottom:1px solid var(--cb-code-border);color:var(--cb-code-muted);font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500)}.cb-code-block__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cb-code-block__pre{margin:0;padding:.75rem 0;overflow:auto;font-family:var(--cb-font-mono);font-size:.8125rem;line-height:1.6;tab-size:2}.cb-code-block__pre:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:-2px}.cb-code-block__code{display:block;min-width:fit-content;font:inherit}.cb-code-block__line{display:flex;padding:0 1rem}.cb-code-block__line--hl{background:var(--cb-code-hl);box-shadow:inset 3px 0 #eab308cc}.cb-code-block__ln{flex:none;min-width:2ch;margin-right:1rem;color:var(--cb-code-muted);text-align:right;-webkit-user-select:none;user-select:none}.cb-code-block__text{white-space:pre}.cb-code-block__text:empty:before{content:\" \"}:host(.cb-code-block--wrap) .cb-code-block__code{min-width:0}:host(.cb-code-block--wrap) .cb-code-block__text{white-space:pre-wrap;overflow-wrap:anywhere}.cb-tok-keyword{color:var(--cb-tok-keyword)}.cb-tok-builtin{color:var(--cb-tok-builtin)}.cb-tok-string{color:var(--cb-tok-string)}.cb-tok-number{color:var(--cb-tok-number)}.cb-tok-comment{color:var(--cb-tok-comment);font-style:italic}.cb-tok-function{color:var(--cb-tok-function)}.cb-tok-operator{color:var(--cb-tok-operator)}.cb-tok-punctuation{color:var(--cb-tok-punctuation)}.cb-tok-tag{color:var(--cb-tok-tag)}.cb-tok-attr{color:var(--cb-tok-attr)}.cb-tok-property{color:var(--cb-tok-property)}.cb-tok-variable{color:var(--cb-tok-variable)}\n"], dependencies: [{ kind: "component", type: CbCopyButton, selector: "cb-copy-button", inputs: ["value", "showLabel", "label", "copiedLabel", "timeout", "variant", "severity", "size", "disabled"], outputs: ["copied", "copyError"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
299
+ }
300
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbCodeBlock, decorators: [{
301
+ type: Component,
302
+ args: [{ selector: 'cb-code-block', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, imports: [CbCopyButton], host: {
303
+ class: 'cb-code-block',
304
+ '[class.cb-code-block--wrap]': 'wrap()',
305
+ '[class.cb-code-block--numbers]': 'lineNumbers()',
306
+ }, template: `
307
+ @if (showHeader()) {
308
+ <div class="cb-code-block__header">
309
+ <span class="cb-code-block__title">{{ filename() || languageLabel() }}</span>
310
+ @if (copyable()) {
311
+ <cb-copy-button class="cb-code-block__copy" [value]="code()" size="sm" />
312
+ }
313
+ </div>
314
+ }
315
+ <pre
316
+ class="cb-code-block__pre"
317
+ tabindex="0"
318
+ [style.max-height]="maxHeight() || null"
319
+ [attr.aria-label]="ariaLabel() ?? (filename() || languageLabel() || null)"
320
+ ><!-- En una línea: dentro de <pre> cada espacio cuenta. --><code class="cb-code-block__code">@for (line of lines(); track $index; let i = $index) {<span class="cb-code-block__line" [class.cb-code-block__line--hl]="highlighted().has(i + startLine())">@if (lineNumbers()) {<span class="cb-code-block__ln" aria-hidden="true">{{ i + startLine() }}</span>}<span class="cb-code-block__text">@for (token of line; track $index) {<span [class]="token.type === 'plain' ? null : 'cb-tok cb-tok-' + token.type">{{ token.text }}</span>}</span></span>}</code></pre>
321
+ `, styles: [":host{--cb-code-bg: #f6f8fa;--cb-code-fg: #1f2328;--cb-code-border: var(--cb-color-border);--cb-code-muted: #6e7781;--cb-code-hl: rgb(234 179 8 / .16);--cb-tok-keyword: #cf222e;--cb-tok-builtin: #0550ae;--cb-tok-string: #0a3069;--cb-tok-number: #0550ae;--cb-tok-comment: #6e7781;--cb-tok-function: #8250df;--cb-tok-operator: #cf222e;--cb-tok-punctuation: #57606a;--cb-tok-tag: #116329;--cb-tok-attr: #0550ae;--cb-tok-property: #0550ae;--cb-tok-variable: #1f2328;display:block;overflow:hidden;border:1px solid var(--cb-code-border);border-radius:var(--cb-radius-md, 8px);background:var(--cb-code-bg);color:var(--cb-code-fg);font-family:var(--cb-font-sans)}:host-context([data-theme=\"dark\"]){--cb-code-bg: #0d1117;--cb-code-fg: #e6edf3;--cb-code-muted: #8b949e;--cb-code-hl: rgb(234 179 8 / .14);--cb-tok-keyword: #ff7b72;--cb-tok-builtin: #79c0ff;--cb-tok-string: #a5d6ff;--cb-tok-number: #79c0ff;--cb-tok-comment: #8b949e;--cb-tok-function: #d2a8ff;--cb-tok-operator: #ff7b72;--cb-tok-punctuation: #b1bac4;--cb-tok-tag: #7ee787;--cb-tok-attr: #79c0ff;--cb-tok-property: #79c0ff;--cb-tok-variable: #e6edf3}.cb-code-block__header{display:flex;align-items:center;justify-content:space-between;gap:.5rem;min-height:2.25rem;padding:.125rem .25rem .125rem .875rem;border-bottom:1px solid var(--cb-code-border);color:var(--cb-code-muted);font-size:var(--cb-text-xs, .75rem);font-weight:var(--cb-font-weight-medium, 500)}.cb-code-block__title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.cb-code-block__pre{margin:0;padding:.75rem 0;overflow:auto;font-family:var(--cb-font-mono);font-size:.8125rem;line-height:1.6;tab-size:2}.cb-code-block__pre:focus-visible{outline:2px solid var(--cb-color-focus-ring);outline-offset:-2px}.cb-code-block__code{display:block;min-width:fit-content;font:inherit}.cb-code-block__line{display:flex;padding:0 1rem}.cb-code-block__line--hl{background:var(--cb-code-hl);box-shadow:inset 3px 0 #eab308cc}.cb-code-block__ln{flex:none;min-width:2ch;margin-right:1rem;color:var(--cb-code-muted);text-align:right;-webkit-user-select:none;user-select:none}.cb-code-block__text{white-space:pre}.cb-code-block__text:empty:before{content:\" \"}:host(.cb-code-block--wrap) .cb-code-block__code{min-width:0}:host(.cb-code-block--wrap) .cb-code-block__text{white-space:pre-wrap;overflow-wrap:anywhere}.cb-tok-keyword{color:var(--cb-tok-keyword)}.cb-tok-builtin{color:var(--cb-tok-builtin)}.cb-tok-string{color:var(--cb-tok-string)}.cb-tok-number{color:var(--cb-tok-number)}.cb-tok-comment{color:var(--cb-tok-comment);font-style:italic}.cb-tok-function{color:var(--cb-tok-function)}.cb-tok-operator{color:var(--cb-tok-operator)}.cb-tok-punctuation{color:var(--cb-tok-punctuation)}.cb-tok-tag{color:var(--cb-tok-tag)}.cb-tok-attr{color:var(--cb-tok-attr)}.cb-tok-property{color:var(--cb-tok-property)}.cb-tok-variable{color:var(--cb-tok-variable)}\n"] }]
322
+ }], propDecorators: { code: [{ type: i0.Input, args: [{ isSignal: true, alias: "code", required: false }] }], language: [{ type: i0.Input, args: [{ isSignal: true, alias: "language", required: false }] }], filename: [{ type: i0.Input, args: [{ isSignal: true, alias: "filename", required: false }] }], lineNumbers: [{ type: i0.Input, args: [{ isSignal: true, alias: "lineNumbers", required: false }] }], startLine: [{ type: i0.Input, args: [{ isSignal: true, alias: "startLine", required: false }] }], highlightLines: [{ type: i0.Input, args: [{ isSignal: true, alias: "highlightLines", required: false }] }], wrap: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrap", required: false }] }], copyable: [{ type: i0.Input, args: [{ isSignal: true, alias: "copyable", required: false }] }], header: [{ type: i0.Input, args: [{ isSignal: true, alias: "header", required: false }] }], maxHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxHeight", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
323
+
324
+ /*
325
+ * Public API Surface de @caribeng/ui/code-block
326
+ */
327
+
328
+ /**
329
+ * Generated bundle index. Do not edit.
330
+ */
331
+
332
+ export { CbCodeBlock, cbCodeLanguageLabel, cbCodeSupports, cbHighlight, cbParseLineSet };
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { model, input, signal, viewChild, computed, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, Injector, model, input, signal, viewChild, computed, afterNextRender, forwardRef, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
4
  import * as i1 from '@angular/cdk/overlay';
5
5
  import { OverlayModule } from '@angular/cdk/overlay';
6
- import { injectCbTranslation, cbFieldState } from '@caribeng/ui';
6
+ import { injectCbTranslation, cbFormat, cbFieldState } from '@caribeng/ui';
7
7
 
8
8
  let nextUid = 0;
9
9
  const DEFAULT_PRESETS = [
@@ -25,6 +25,8 @@ class CbColorPicker {
25
25
  constructor() {
26
26
  /** Textos de interfaz en el idioma activo (`provideCaribeNG({ locale })`). */
27
27
  this.t = injectCbTranslation();
28
+ this.fmt = cbFormat;
29
+ this.injector = inject(Injector);
28
30
  /** Color seleccionado (hex `#rrggbb`). Two-way opcional fuera de Forms. */
29
31
  this.value = model('#10b981', /* @ts-ignore */
30
32
  ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
@@ -87,7 +89,13 @@ class CbColorPicker {
87
89
  toggle() {
88
90
  if (this.isDisabled())
89
91
  return;
90
- this.open() ? this.close() : this.open.set(true);
92
+ if (this.open()) {
93
+ this.close();
94
+ return;
95
+ }
96
+ this.open.set(true);
97
+ // El panel se pinta al final del documento: el foco entra en él al abrir.
98
+ afterNextRender(() => this.svRef()?.nativeElement.focus(), { injector: this.injector });
91
99
  }
92
100
  close() {
93
101
  if (!this.open())
@@ -100,7 +108,63 @@ class CbColorPicker {
100
108
  if (event.key === 'Escape') {
101
109
  event.preventDefault();
102
110
  this.close();
111
+ return;
112
+ }
113
+ // Tab fuera del panel (antes del primero o después del último) lo cierra y vuelve al botón.
114
+ if (event.key !== 'Tab' || !(event.target instanceof Element))
115
+ return;
116
+ const panel = event.target.closest('.cb-colorpicker__panel');
117
+ const focusables = panel ? Array.from(panel.querySelectorAll('[tabindex="0"], input, button')) : [];
118
+ const edge = event.shiftKey ? focusables[0] : focusables[focusables.length - 1];
119
+ if (event.target === edge) {
120
+ event.preventDefault();
121
+ this.close();
122
+ }
123
+ }
124
+ // --- Teclado en el área y el matiz (Mayús: pasos de 10) --------------------
125
+ onSvKeydown(event) {
126
+ const step = event.shiftKey ? 10 : 1;
127
+ const clamp = (n) => Math.min(100, Math.max(0, n));
128
+ switch (event.key) {
129
+ case 'ArrowRight':
130
+ this.s.set(clamp(this.s() + step));
131
+ break;
132
+ case 'ArrowLeft':
133
+ this.s.set(clamp(this.s() - step));
134
+ break;
135
+ case 'ArrowUp':
136
+ this.v.set(clamp(this.v() + step));
137
+ break;
138
+ case 'ArrowDown':
139
+ this.v.set(clamp(this.v() - step));
140
+ break;
141
+ default: return;
103
142
  }
143
+ event.preventDefault();
144
+ this.commitFromHsv();
145
+ }
146
+ onHueKeydown(event) {
147
+ const step = event.shiftKey ? 10 : 1;
148
+ const clamp = (n) => Math.min(360, Math.max(0, n));
149
+ switch (event.key) {
150
+ case 'ArrowRight':
151
+ case 'ArrowUp':
152
+ this.h.set(clamp(this.h() + step));
153
+ break;
154
+ case 'ArrowLeft':
155
+ case 'ArrowDown':
156
+ this.h.set(clamp(this.h() - step));
157
+ break;
158
+ case 'Home':
159
+ this.h.set(0);
160
+ break;
161
+ case 'End':
162
+ this.h.set(360);
163
+ break;
164
+ default: return;
165
+ }
166
+ event.preventDefault();
167
+ this.commitFromHsv();
104
168
  }
105
169
  // --- Área saturación/valor -------------------------------------------------
106
170
  onSvPointerDown(event) {
@@ -216,8 +280,16 @@ class CbColorPicker {
216
280
  <div
217
281
  #sv
218
282
  class="cb-colorpicker__sv"
283
+ role="slider"
284
+ tabindex="0"
285
+ [attr.aria-label]="t().colorArea"
286
+ aria-valuemin="0"
287
+ aria-valuemax="100"
288
+ [attr.aria-valuenow]="s()"
289
+ [attr.aria-valuetext]="fmt(t().colorAreaValue, s(), v())"
219
290
  [style.background-color]="hueColor()"
220
291
  (pointerdown)="onSvPointerDown($event)"
292
+ (keydown)="onSvKeydown($event)"
221
293
  >
222
294
  <div class="cb-colorpicker__sv-white"></div>
223
295
  <div class="cb-colorpicker__sv-black"></div>
@@ -233,7 +305,14 @@ class CbColorPicker {
233
305
  <div
234
306
  #hue
235
307
  class="cb-colorpicker__hue"
308
+ role="slider"
309
+ tabindex="0"
310
+ [attr.aria-label]="t().hue"
311
+ aria-valuemin="0"
312
+ aria-valuemax="360"
313
+ [attr.aria-valuenow]="h()"
236
314
  (pointerdown)="onHuePointerDown($event)"
315
+ (keydown)="onHueKeydown($event)"
237
316
  >
238
317
  <div class="cb-colorpicker__hue-pointer" [style.left.%]="(h() / 360) * 100"></div>
239
318
  </div>
@@ -268,7 +347,7 @@ class CbColorPicker {
268
347
  }
269
348
  </div>
270
349
  </ng-template>
271
- `, isInline: true, styles: [":host{display:inline-block}.cb-colorpicker__trigger{display:inline-flex;align-items:center;gap:var(--cb-space-2);min-height:2.5rem;padding:0 var(--cb-space-3) 0 var(--cb-space-2);background-color:var(--cb-color-bg);border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);color:var(--cb-color-text);font-family:var(--cb-font-sans);cursor:pointer;transition:border-color var(--cb-duration-fast) var(--cb-ease),box-shadow var(--cb-duration-fast) var(--cb-ease)}.cb-colorpicker__trigger--sm{min-height:2.125rem;font-size:var(--cb-text-sm)}.cb-colorpicker__trigger--lg{min-height:2.875rem;font-size:var(--cb-text-lg)}.cb-colorpicker__trigger:focus-visible,.cb-colorpicker__trigger.cb-is-open{outline:none;border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__trigger.cb-is-invalid{border-color:var(--cb-color-danger)}.cb-colorpicker__trigger.cb-is-disabled{opacity:var(--cb-opacity-disabled, .55);cursor:default}.cb-colorpicker__swatch{width:1.5rem;height:1.5rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__value{font-variant-numeric:tabular-nums;text-transform:uppercase;letter-spacing:.02em}.cb-colorpicker__panel{width:15rem;padding:var(--cb-space-3);background-color:var(--cb-color-surface-raised);border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);box-shadow:var(--cb-shadow-md);font-family:var(--cb-font-sans)}.cb-colorpicker__sv{position:relative;height:9rem;border-radius:var(--cb-radius-sm);cursor:crosshair;touch-action:none;overflow:hidden}.cb-colorpicker__sv-white,.cb-colorpicker__sv-black{position:absolute;inset:0}.cb-colorpicker__sv-white{background:linear-gradient(to right,#fff,#fff0)}.cb-colorpicker__sv-black{background:linear-gradient(to top,#000,#0000)}.cb-colorpicker__sv-pointer{position:absolute;width:.875rem;height:.875rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);border:2px solid #fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__controls{display:flex;align-items:center;gap:var(--cb-space-3);margin-top:var(--cb-space-3)}.cb-colorpicker__hue{position:relative;flex:1 1 auto;height:.875rem;border-radius:var(--cb-radius-full);cursor:pointer;touch-action:none;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red)}.cb-colorpicker__hue-pointer{position:absolute;top:50%;width:1rem;height:1rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);background:#fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__preview{width:1.75rem;height:1.75rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__fields{margin-top:var(--cb-space-3)}.cb-colorpicker__hex{width:100%;padding:var(--cb-space-2);text-align:center;text-transform:uppercase;font-variant-numeric:tabular-nums;letter-spacing:.04em;border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-sm);background-color:var(--cb-color-bg);color:var(--cb-color-text);font-family:var(--cb-font-mono, monospace);outline:none}.cb-colorpicker__hex:focus{border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__presets{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--cb-space-2);margin-top:var(--cb-space-3)}.cb-colorpicker__preset{aspect-ratio:1;border:none;border-radius:var(--cb-radius-sm);cursor:pointer;box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__preset.cb-is-active{box-shadow:inset 0 0 0 1px #00000026,0 0 0 2px var(--cb-color-primary-500)}.cb-colorpicker__preset:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
350
+ `, isInline: true, styles: [":host{display:inline-block}.cb-colorpicker__trigger{display:inline-flex;align-items:center;gap:var(--cb-space-2);min-height:2.5rem;padding:0 var(--cb-space-3) 0 var(--cb-space-2);background-color:var(--cb-color-bg);border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);color:var(--cb-color-text);font-family:var(--cb-font-sans);cursor:pointer;transition:border-color var(--cb-duration-fast) var(--cb-ease),box-shadow var(--cb-duration-fast) var(--cb-ease)}.cb-colorpicker__trigger--sm{min-height:2.125rem;font-size:var(--cb-text-sm)}.cb-colorpicker__trigger--lg{min-height:2.875rem;font-size:var(--cb-text-lg)}.cb-colorpicker__trigger:focus-visible,.cb-colorpicker__trigger.cb-is-open{outline:none;border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__trigger.cb-is-invalid{border-color:var(--cb-color-danger)}.cb-colorpicker__trigger.cb-is-disabled{opacity:var(--cb-opacity-disabled, .55);cursor:default}.cb-colorpicker__swatch{width:1.5rem;height:1.5rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__value{font-variant-numeric:tabular-nums;text-transform:uppercase;letter-spacing:.02em}.cb-colorpicker__panel{width:15rem;padding:var(--cb-space-3);background-color:var(--cb-color-surface-raised);border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);box-shadow:var(--cb-shadow-md);font-family:var(--cb-font-sans)}.cb-colorpicker__sv{position:relative;height:9rem;border-radius:var(--cb-radius-sm);cursor:crosshair;touch-action:none;overflow:hidden}.cb-colorpicker__sv-white,.cb-colorpicker__sv-black{position:absolute;inset:0}.cb-colorpicker__sv-white{background:linear-gradient(to right,#fff,#fff0)}.cb-colorpicker__sv-black{background:linear-gradient(to top,#000,#0000)}.cb-colorpicker__sv-pointer{position:absolute;width:.875rem;height:.875rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);border:2px solid #fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__controls{display:flex;align-items:center;gap:var(--cb-space-3);margin-top:var(--cb-space-3)}.cb-colorpicker__hue{position:relative;flex:1 1 auto;height:.875rem;border-radius:var(--cb-radius-full);cursor:pointer;touch-action:none;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red)}.cb-colorpicker__hue-pointer{position:absolute;top:50%;width:1rem;height:1rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);background:#fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__preview{width:1.75rem;height:1.75rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__fields{margin-top:var(--cb-space-3)}.cb-colorpicker__hex{width:100%;padding:var(--cb-space-2);text-align:center;text-transform:uppercase;font-variant-numeric:tabular-nums;letter-spacing:.04em;border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-sm);background-color:var(--cb-color-bg);color:var(--cb-color-text);font-family:var(--cb-font-mono, monospace);outline:none}.cb-colorpicker__hex:focus{border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__presets{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--cb-space-2);margin-top:var(--cb-space-3)}.cb-colorpicker__preset{aspect-ratio:1;border:none;border-radius:var(--cb-radius-sm);cursor:pointer;box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__preset.cb-is-active{box-shadow:inset 0 0 0 1px #00000026,0 0 0 2px var(--cb-color-primary-500)}.cb-colorpicker__sv:focus-visible,.cb-colorpicker__hue:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}.cb-colorpicker__preset:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}\n"], dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation", "cdkConnectedOverlayUsePopover", "cdkConnectedOverlayMatchWidth", "cdkConnectedOverlay"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
272
351
  }
273
352
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: CbColorPicker, decorators: [{
274
353
  type: Component,
@@ -313,8 +392,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
313
392
  <div
314
393
  #sv
315
394
  class="cb-colorpicker__sv"
395
+ role="slider"
396
+ tabindex="0"
397
+ [attr.aria-label]="t().colorArea"
398
+ aria-valuemin="0"
399
+ aria-valuemax="100"
400
+ [attr.aria-valuenow]="s()"
401
+ [attr.aria-valuetext]="fmt(t().colorAreaValue, s(), v())"
316
402
  [style.background-color]="hueColor()"
317
403
  (pointerdown)="onSvPointerDown($event)"
404
+ (keydown)="onSvKeydown($event)"
318
405
  >
319
406
  <div class="cb-colorpicker__sv-white"></div>
320
407
  <div class="cb-colorpicker__sv-black"></div>
@@ -330,7 +417,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
330
417
  <div
331
418
  #hue
332
419
  class="cb-colorpicker__hue"
420
+ role="slider"
421
+ tabindex="0"
422
+ [attr.aria-label]="t().hue"
423
+ aria-valuemin="0"
424
+ aria-valuemax="360"
425
+ [attr.aria-valuenow]="h()"
333
426
  (pointerdown)="onHuePointerDown($event)"
427
+ (keydown)="onHueKeydown($event)"
334
428
  >
335
429
  <div class="cb-colorpicker__hue-pointer" [style.left.%]="(h() / 360) * 100"></div>
336
430
  </div>
@@ -365,7 +459,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
365
459
  }
366
460
  </div>
367
461
  </ng-template>
368
- `, styles: [":host{display:inline-block}.cb-colorpicker__trigger{display:inline-flex;align-items:center;gap:var(--cb-space-2);min-height:2.5rem;padding:0 var(--cb-space-3) 0 var(--cb-space-2);background-color:var(--cb-color-bg);border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);color:var(--cb-color-text);font-family:var(--cb-font-sans);cursor:pointer;transition:border-color var(--cb-duration-fast) var(--cb-ease),box-shadow var(--cb-duration-fast) var(--cb-ease)}.cb-colorpicker__trigger--sm{min-height:2.125rem;font-size:var(--cb-text-sm)}.cb-colorpicker__trigger--lg{min-height:2.875rem;font-size:var(--cb-text-lg)}.cb-colorpicker__trigger:focus-visible,.cb-colorpicker__trigger.cb-is-open{outline:none;border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__trigger.cb-is-invalid{border-color:var(--cb-color-danger)}.cb-colorpicker__trigger.cb-is-disabled{opacity:var(--cb-opacity-disabled, .55);cursor:default}.cb-colorpicker__swatch{width:1.5rem;height:1.5rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__value{font-variant-numeric:tabular-nums;text-transform:uppercase;letter-spacing:.02em}.cb-colorpicker__panel{width:15rem;padding:var(--cb-space-3);background-color:var(--cb-color-surface-raised);border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);box-shadow:var(--cb-shadow-md);font-family:var(--cb-font-sans)}.cb-colorpicker__sv{position:relative;height:9rem;border-radius:var(--cb-radius-sm);cursor:crosshair;touch-action:none;overflow:hidden}.cb-colorpicker__sv-white,.cb-colorpicker__sv-black{position:absolute;inset:0}.cb-colorpicker__sv-white{background:linear-gradient(to right,#fff,#fff0)}.cb-colorpicker__sv-black{background:linear-gradient(to top,#000,#0000)}.cb-colorpicker__sv-pointer{position:absolute;width:.875rem;height:.875rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);border:2px solid #fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__controls{display:flex;align-items:center;gap:var(--cb-space-3);margin-top:var(--cb-space-3)}.cb-colorpicker__hue{position:relative;flex:1 1 auto;height:.875rem;border-radius:var(--cb-radius-full);cursor:pointer;touch-action:none;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red)}.cb-colorpicker__hue-pointer{position:absolute;top:50%;width:1rem;height:1rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);background:#fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__preview{width:1.75rem;height:1.75rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__fields{margin-top:var(--cb-space-3)}.cb-colorpicker__hex{width:100%;padding:var(--cb-space-2);text-align:center;text-transform:uppercase;font-variant-numeric:tabular-nums;letter-spacing:.04em;border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-sm);background-color:var(--cb-color-bg);color:var(--cb-color-text);font-family:var(--cb-font-mono, monospace);outline:none}.cb-colorpicker__hex:focus{border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__presets{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--cb-space-2);margin-top:var(--cb-space-3)}.cb-colorpicker__preset{aspect-ratio:1;border:none;border-radius:var(--cb-radius-sm);cursor:pointer;box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__preset.cb-is-active{box-shadow:inset 0 0 0 1px #00000026,0 0 0 2px var(--cb-color-primary-500)}.cb-colorpicker__preset:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}\n"] }]
462
+ `, styles: [":host{display:inline-block}.cb-colorpicker__trigger{display:inline-flex;align-items:center;gap:var(--cb-space-2);min-height:2.5rem;padding:0 var(--cb-space-3) 0 var(--cb-space-2);background-color:var(--cb-color-bg);border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-md);color:var(--cb-color-text);font-family:var(--cb-font-sans);cursor:pointer;transition:border-color var(--cb-duration-fast) var(--cb-ease),box-shadow var(--cb-duration-fast) var(--cb-ease)}.cb-colorpicker__trigger--sm{min-height:2.125rem;font-size:var(--cb-text-sm)}.cb-colorpicker__trigger--lg{min-height:2.875rem;font-size:var(--cb-text-lg)}.cb-colorpicker__trigger:focus-visible,.cb-colorpicker__trigger.cb-is-open{outline:none;border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__trigger.cb-is-invalid{border-color:var(--cb-color-danger)}.cb-colorpicker__trigger.cb-is-disabled{opacity:var(--cb-opacity-disabled, .55);cursor:default}.cb-colorpicker__swatch{width:1.5rem;height:1.5rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__value{font-variant-numeric:tabular-nums;text-transform:uppercase;letter-spacing:.02em}.cb-colorpicker__panel{width:15rem;padding:var(--cb-space-3);background-color:var(--cb-color-surface-raised);border:1px solid var(--cb-color-border);border-radius:var(--cb-radius-md);box-shadow:var(--cb-shadow-md);font-family:var(--cb-font-sans)}.cb-colorpicker__sv{position:relative;height:9rem;border-radius:var(--cb-radius-sm);cursor:crosshair;touch-action:none;overflow:hidden}.cb-colorpicker__sv-white,.cb-colorpicker__sv-black{position:absolute;inset:0}.cb-colorpicker__sv-white{background:linear-gradient(to right,#fff,#fff0)}.cb-colorpicker__sv-black{background:linear-gradient(to top,#000,#0000)}.cb-colorpicker__sv-pointer{position:absolute;width:.875rem;height:.875rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);border:2px solid #fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__controls{display:flex;align-items:center;gap:var(--cb-space-3);margin-top:var(--cb-space-3)}.cb-colorpicker__hue{position:relative;flex:1 1 auto;height:.875rem;border-radius:var(--cb-radius-full);cursor:pointer;touch-action:none;background:linear-gradient(to right,red,#ff0 17%,#0f0 33%,#0ff,#00f 67%,#f0f 83%,red)}.cb-colorpicker__hue-pointer{position:absolute;top:50%;width:1rem;height:1rem;transform:translate(-50%,-50%);border-radius:var(--cb-radius-full);background:#fff;box-shadow:0 0 0 1px #0000004d;pointer-events:none}.cb-colorpicker__preview{width:1.75rem;height:1.75rem;flex:none;border-radius:var(--cb-radius-sm);box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__fields{margin-top:var(--cb-space-3)}.cb-colorpicker__hex{width:100%;padding:var(--cb-space-2);text-align:center;text-transform:uppercase;font-variant-numeric:tabular-nums;letter-spacing:.04em;border:var(--cb-border-width) solid var(--cb-color-border-strong);border-radius:var(--cb-radius-sm);background-color:var(--cb-color-bg);color:var(--cb-color-text);font-family:var(--cb-font-mono, monospace);outline:none}.cb-colorpicker__hex:focus{border-color:var(--cb-color-primary-500);box-shadow:0 0 0 3px var(--cb-color-focus-ring)}.cb-colorpicker__presets{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--cb-space-2);margin-top:var(--cb-space-3)}.cb-colorpicker__preset{aspect-ratio:1;border:none;border-radius:var(--cb-radius-sm);cursor:pointer;box-shadow:inset 0 0 0 1px #00000026}.cb-colorpicker__preset.cb-is-active{box-shadow:inset 0 0 0 1px #00000026,0 0 0 2px var(--cb-color-primary-500)}.cb-colorpicker__sv:focus-visible,.cb-colorpicker__hue:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}.cb-colorpicker__preset:focus-visible{outline:2px solid var(--cb-color-primary-500);outline-offset:2px}\n"] }]
369
463
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], presets: [{ type: i0.Input, args: [{ isSignal: true, alias: "presets", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], svRef: [{ type: i0.ViewChild, args: ['sv', { isSignal: true }] }], hueRef: [{ type: i0.ViewChild, args: ['hue', { isSignal: true }] }], triggerRef: [{ type: i0.ViewChild, args: ['trigger', { isSignal: true }] }] } });
370
464
  function toBoolean(value) {
371
465
  return value !== false && value != null && `${value}` !== 'false';