@semantic-components/code 0.63.0 → 0.64.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 (64) hide show
  1. package/esm2022/index.js +2 -0
  2. package/esm2022/index.js.map +1 -0
  3. package/esm2022/lib/components/code-editor/code-editor-content.js +435 -0
  4. package/esm2022/lib/components/code-editor/code-editor-content.js.map +1 -0
  5. package/esm2022/lib/components/code-editor/code-editor-copy-button.js +90 -0
  6. package/esm2022/lib/components/code-editor/code-editor-copy-button.js.map +1 -0
  7. package/esm2022/lib/components/code-editor/code-editor-footer.js +27 -0
  8. package/esm2022/lib/components/code-editor/code-editor-footer.js.map +1 -0
  9. package/esm2022/lib/components/code-editor/code-editor-header.js +27 -0
  10. package/esm2022/lib/components/code-editor/code-editor-header.js.map +1 -0
  11. package/esm2022/lib/components/code-editor/code-editor-label.js +27 -0
  12. package/esm2022/lib/components/code-editor/code-editor-label.js.map +1 -0
  13. package/esm2022/lib/components/code-editor/code-editor.js +27 -0
  14. package/esm2022/lib/components/code-editor/code-editor.js.map +1 -0
  15. package/esm2022/lib/components/code-editor/index.js +7 -0
  16. package/esm2022/lib/components/code-editor/index.js.map +1 -0
  17. package/esm2022/lib/components/code-viewer/code-viewer-content.js +70 -0
  18. package/esm2022/lib/components/code-viewer/code-viewer-content.js.map +1 -0
  19. package/esm2022/lib/components/code-viewer/code-viewer-header.js +27 -0
  20. package/esm2022/lib/components/code-viewer/code-viewer-header.js.map +1 -0
  21. package/esm2022/lib/components/code-viewer/code-viewer-label.js +27 -0
  22. package/esm2022/lib/components/code-viewer/code-viewer-label.js.map +1 -0
  23. package/esm2022/lib/components/code-viewer/code-viewer.js +27 -0
  24. package/esm2022/lib/components/code-viewer/code-viewer.js.map +1 -0
  25. package/esm2022/lib/components/code-viewer/index.js +5 -0
  26. package/esm2022/lib/components/code-viewer/index.js.map +1 -0
  27. package/esm2022/lib/components/index.js +3 -0
  28. package/esm2022/lib/components/index.js.map +1 -0
  29. package/esm2022/semantic-components-code.js +5 -0
  30. package/esm2022/semantic-components-code.js.map +1 -0
  31. package/lib/components/code-editor/code-editor-content.d.ts +57 -0
  32. package/lib/components/code-editor/code-editor-copy-button.d.ts +11 -0
  33. package/lib/components/code-editor/code-editor-footer.d.ts +7 -0
  34. package/lib/components/code-editor/code-editor-header.d.ts +7 -0
  35. package/lib/components/code-editor/code-editor-label.d.ts +7 -0
  36. package/lib/components/code-editor/code-editor.d.ts +7 -0
  37. package/lib/components/code-viewer/code-viewer-content.d.ts +17 -0
  38. package/lib/components/code-viewer/code-viewer-header.d.ts +7 -0
  39. package/lib/components/code-viewer/code-viewer-label.d.ts +7 -0
  40. package/lib/components/code-viewer/code-viewer.d.ts +7 -0
  41. package/package.json +15 -3
  42. package/semantic-components-code.d.ts +5 -0
  43. package/eslint.config.mjs +0 -48
  44. package/ng-package.json +0 -8
  45. package/project.json +0 -28
  46. package/src/lib/components/code-editor/README.md +0 -368
  47. package/src/lib/components/code-editor/code-editor-content.ts +0 -507
  48. package/src/lib/components/code-editor/code-editor-copy-button.ts +0 -77
  49. package/src/lib/components/code-editor/code-editor-footer.ts +0 -31
  50. package/src/lib/components/code-editor/code-editor-header.ts +0 -31
  51. package/src/lib/components/code-editor/code-editor-label.ts +0 -28
  52. package/src/lib/components/code-editor/code-editor.ts +0 -31
  53. package/src/lib/components/code-viewer/README.md +0 -178
  54. package/src/lib/components/code-viewer/code-viewer-content.ts +0 -96
  55. package/src/lib/components/code-viewer/code-viewer-header.ts +0 -31
  56. package/src/lib/components/code-viewer/code-viewer-label.ts +0 -28
  57. package/src/lib/components/code-viewer/code-viewer.ts +0 -28
  58. package/tsconfig.json +0 -28
  59. package/tsconfig.lib.json +0 -12
  60. package/tsconfig.lib.prod.json +0 -7
  61. /package/{src/index.ts → index.d.ts} +0 -0
  62. /package/{src/lib/components/code-editor/index.ts → lib/components/code-editor/index.d.ts} +0 -0
  63. /package/{src/lib/components/code-viewer/index.ts → lib/components/code-viewer/index.d.ts} +0 -0
  64. /package/{src/lib/components/index.ts → lib/components/index.d.ts} +0 -0
@@ -1,507 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- effect,
6
- ElementRef,
7
- inject,
8
- input,
9
- model,
10
- output,
11
- signal,
12
- viewChild,
13
- ViewEncapsulation,
14
- } from '@angular/core';
15
- import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
16
- import { codeToHtml } from 'shiki';
17
- import { cn } from '@semantic-components/ui';
18
-
19
- export type ScCodeEditorLanguage =
20
- | 'angular-ts'
21
- | 'typescript'
22
- | 'javascript'
23
- | 'html'
24
- | 'css'
25
- | 'json'
26
- | 'python'
27
- | 'bash'
28
- | 'shell'
29
- | 'markdown'
30
- | 'yaml'
31
- | 'sql'
32
- | 'go'
33
- | 'rust'
34
- | 'java'
35
- | 'plaintext';
36
-
37
- const EXTENSION_MAP: Record<string, ScCodeEditorLanguage> = {
38
- js: 'javascript',
39
- mjs: 'javascript',
40
- cjs: 'javascript',
41
- jsx: 'javascript',
42
- ts: 'typescript',
43
- mts: 'typescript',
44
- cts: 'typescript',
45
- tsx: 'typescript',
46
- html: 'html',
47
- htm: 'html',
48
- css: 'css',
49
- scss: 'css',
50
- sass: 'css',
51
- less: 'css',
52
- json: 'json',
53
- py: 'python',
54
- pyw: 'python',
55
- sh: 'bash',
56
- bash: 'bash',
57
- zsh: 'shell',
58
- sql: 'sql',
59
- md: 'markdown',
60
- markdown: 'markdown',
61
- yaml: 'yaml',
62
- yml: 'yaml',
63
- go: 'go',
64
- rs: 'rust',
65
- java: 'java',
66
- txt: 'plaintext',
67
- };
68
-
69
- export function detectLanguage(
70
- code: string,
71
- filename?: string,
72
- ): ScCodeEditorLanguage {
73
- if (filename) {
74
- const ext = filename.split('.').pop()?.toLowerCase();
75
- if (ext && EXTENSION_MAP[ext]) {
76
- return EXTENSION_MAP[ext];
77
- }
78
- }
79
-
80
- // Try to detect from content
81
- if (
82
- code.includes('<!DOCTYPE') ||
83
- code.includes('<html') ||
84
- /<\w+[^>]*>/.test(code)
85
- ) {
86
- return 'html';
87
- }
88
- if (/^\s*\{[\s\S]*\}\s*$/.test(code) || /^\s*\[[\s\S]*\]\s*$/.test(code)) {
89
- try {
90
- JSON.parse(code);
91
- return 'json';
92
- } catch {
93
- // Not JSON
94
- }
95
- }
96
- if (/^(import|export|const|let|var|function|class)\s/.test(code)) {
97
- if (
98
- /:\s*(string|number|boolean|any|void|never)\b/.test(code) ||
99
- /interface\s+\w+/.test(code)
100
- ) {
101
- return 'typescript';
102
- }
103
- return 'javascript';
104
- }
105
- if (
106
- /^(def|class|import|from|if __name__)\s/.test(code) ||
107
- /:\s*$/.test(code.split('\n')[0])
108
- ) {
109
- return 'python';
110
- }
111
- if (/^(SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP)\s/i.test(code)) {
112
- return 'sql';
113
- }
114
- if (/^#\s/.test(code) || /^\*\*.*\*\*$/.test(code)) {
115
- return 'markdown';
116
- }
117
- if (/^#!/.test(code)) {
118
- return 'bash';
119
- }
120
-
121
- return 'plaintext';
122
- }
123
-
124
- @Component({
125
- selector: 'div[sc-code-editor-content]',
126
- template: `
127
- <!-- Line numbers -->
128
- @if (showLineNumbers()) {
129
- <div
130
- class="sc-code-editor-content__line-numbers flex-shrink-0 select-none border-r border-border py-3 pl-3 pr-3 text-right"
131
- [style.min-width.ch]="lineNumberWidth()"
132
- aria-hidden="true"
133
- >
134
- @for (line of lines(); track $index) {
135
- <div
136
- class="font-mono text-sm leading-relaxed"
137
- [class.sc-code-editor-content__line-numbers--active]="
138
- activeLine() === $index + 1
139
- "
140
- >
141
- {{ $index + 1 }}
142
- </div>
143
- }
144
- </div>
145
- }
146
-
147
- <!-- Code area -->
148
- <div class="relative min-w-0 flex-1">
149
- <!-- Highlighted code (display layer) -->
150
- <div
151
- class="pointer-events-none absolute inset-0 overflow-hidden"
152
- [class.word-wrap-enabled]="wordWrap()"
153
- aria-hidden="true"
154
- >
155
- @if (highlightedHtml()) {
156
- <div [innerHTML]="highlightedHtml()"></div>
157
- } @else {
158
- <pre
159
- class="m-0 p-3 font-mono text-sm leading-relaxed"
160
- ><code>{{ displayCode() }}</code></pre>
161
- }
162
- </div>
163
-
164
- <!-- Textarea (input layer) -->
165
- <textarea
166
- #textarea
167
- [value]="value()"
168
- (input)="onInput($event)"
169
- (keydown)="onKeydown($event)"
170
- (scroll)="onScroll($event)"
171
- (focus)="onFocus()"
172
- (blur)="onBlur()"
173
- (click)="updateActiveLine($event)"
174
- (keyup)="updateActiveLine($event)"
175
- [disabled]="disabled()"
176
- [readonly]="readonly()"
177
- [placeholder]="placeholder()"
178
- [attr.aria-label]="ariaLabel() || 'Code editor'"
179
- [attr.aria-describedby]="ariaDescribedby()"
180
- autocomplete="off"
181
- autocorrect="off"
182
- autocapitalize="off"
183
- spellcheck="false"
184
- [class]="textareaClass()"
185
- [style]="textareaStyle()"
186
- ></textarea>
187
- </div>
188
- `,
189
- styles: `
190
- .sc-code-editor-content__line-numbers {
191
- color: oklch(from var(--muted-foreground) l c h / 0.5);
192
- }
193
-
194
- .sc-code-editor-content__line-numbers--active {
195
- color: var(--foreground);
196
- }
197
-
198
- /* Transparent background for editor overlay effect */
199
- [sc-code-editor-content] pre.shiki,
200
- [sc-code-editor-content] pre.shiki span {
201
- background-color: transparent !important;
202
- }
203
-
204
- /* Word wrap support */
205
- [sc-code-editor-content] .word-wrap-enabled pre.shiki {
206
- white-space: pre-wrap;
207
- word-break: break-all;
208
- }
209
-
210
- /* Caret color */
211
- [sc-code-editor-content] textarea {
212
- caret-color: var(--primary);
213
- }
214
- `,
215
- host: {
216
- 'data-slot': 'code-editor-content',
217
- '[class]': 'wrapperClass()',
218
- '(click)': 'focusTextarea()',
219
- },
220
- encapsulation: ViewEncapsulation.None,
221
- changeDetection: ChangeDetectionStrategy.OnPush,
222
- })
223
- export class ScCodeEditorContent {
224
- // Two-way binding for value
225
- readonly value = model<string>('');
226
-
227
- // Inputs
228
- readonly language = input<ScCodeEditorLanguage>('plaintext');
229
- readonly filename = input<string>('');
230
- readonly placeholder = input<string>('');
231
- readonly disabled = input(false);
232
- readonly readonly = input(false);
233
- readonly showLineNumbers = input(true);
234
- readonly tabSize = input(2);
235
- readonly insertSpaces = input(true);
236
- readonly wordWrap = input(false);
237
- readonly autoDetectLanguage = input(false);
238
- readonly ariaLabel = input<string>('');
239
- readonly ariaDescribedby = input<string>('');
240
- readonly classInput = input<string>('', { alias: 'class' });
241
-
242
- // Outputs
243
- readonly valueChange = output<string>();
244
- readonly languageDetected = output<ScCodeEditorLanguage>();
245
- readonly cursorChange = output<{ line: number; column: number }>();
246
-
247
- // Internal state
248
- readonly activeLine = signal(1);
249
- readonly activeColumn = signal(1);
250
- readonly isFocused = signal(false);
251
- protected readonly highlightedHtml = signal<SafeHtml | null>(null);
252
- private scrollTop = 0;
253
- private scrollLeft = 0;
254
-
255
- private readonly sanitizer = inject(DomSanitizer);
256
- private readonly textarea =
257
- viewChild.required<ElementRef<HTMLTextAreaElement>>('textarea');
258
-
259
- protected readonly lines = computed(() => {
260
- const code = this.value() || '';
261
- return code.split('\n');
262
- });
263
-
264
- protected readonly lineNumberWidth = computed(() => {
265
- return Math.max(2, String(this.lines().length).length + 1);
266
- });
267
-
268
- protected readonly displayCode = computed(() => {
269
- const code = this.value() || '';
270
- return code.endsWith('\n') ? code : code + '\n';
271
- });
272
-
273
- protected readonly effectiveLanguage = computed(() => {
274
- if (this.autoDetectLanguage() && this.value()) {
275
- return detectLanguage(this.value(), this.filename());
276
- }
277
- return this.language();
278
- });
279
-
280
- protected readonly wrapperClass = computed(() =>
281
- cn('relative flex overflow-hidden', this.classInput()),
282
- );
283
-
284
- protected readonly textareaClass = computed(() =>
285
- cn(
286
- 'relative m-0 w-full resize-none p-3',
287
- 'border-none bg-transparent text-transparent caret-current outline-none',
288
- 'font-mono text-sm leading-relaxed',
289
- this.disabled() && 'cursor-not-allowed',
290
- ),
291
- );
292
-
293
- protected readonly textareaStyle = computed(() => ({
294
- whiteSpace: this.wordWrap() ? 'pre-wrap' : 'pre',
295
- wordBreak: this.wordWrap() ? 'break-all' : 'normal',
296
- overflowWrap: this.wordWrap() ? 'break-word' : 'normal',
297
- }));
298
-
299
- constructor() {
300
- // Effect to trigger Shiki highlighting
301
- effect(() => {
302
- const code = this.displayCode();
303
- const lang = this.effectiveLanguage();
304
-
305
- this.highlight(code, lang);
306
- });
307
-
308
- // Effect for language detection notification
309
- effect(() => {
310
- if (this.autoDetectLanguage() && this.value()) {
311
- const detected = detectLanguage(this.value(), this.filename());
312
- this.languageDetected.emit(detected);
313
- }
314
- });
315
- }
316
-
317
- private async highlight(
318
- code: string,
319
- lang: ScCodeEditorLanguage,
320
- ): Promise<void> {
321
- try {
322
- const html = await codeToHtml(code, {
323
- lang,
324
- themes: {
325
- light: 'github-light',
326
- dark: 'github-dark',
327
- },
328
- defaultColor: false,
329
- });
330
- this.highlightedHtml.set(this.sanitizer.bypassSecurityTrustHtml(html));
331
- } catch {
332
- this.highlightedHtml.set(null);
333
- }
334
- }
335
-
336
- focusTextarea(): void {
337
- if (!this.disabled() && !this.readonly()) {
338
- this.textarea().nativeElement.focus();
339
- }
340
- }
341
-
342
- protected onInput(event: Event): void {
343
- const target = event.target as HTMLTextAreaElement;
344
- this.value.set(target.value);
345
- this.valueChange.emit(target.value);
346
- this.updateCursorPosition(target);
347
- }
348
-
349
- protected onKeydown(event: KeyboardEvent): void {
350
- const target = event.target as HTMLTextAreaElement;
351
-
352
- // Handle Tab key
353
- if (event.key === 'Tab') {
354
- event.preventDefault();
355
- const start = target.selectionStart;
356
- const end = target.selectionEnd;
357
- const value = target.value;
358
-
359
- const indent = this.insertSpaces() ? ' '.repeat(this.tabSize()) : '\t';
360
-
361
- if (event.shiftKey) {
362
- // Outdent
363
- const lineStart = value.lastIndexOf('\n', start - 1) + 1;
364
- const lineContent = value.slice(lineStart, start);
365
- const indentMatch = lineContent.match(/^(\t| {1,})/);
366
-
367
- if (indentMatch) {
368
- const removeLength = Math.min(
369
- indentMatch[1].length,
370
- this.insertSpaces() ? this.tabSize() : 1,
371
- );
372
- const newValue =
373
- value.slice(0, lineStart) + value.slice(lineStart + removeLength);
374
-
375
- this.value.set(newValue);
376
- this.valueChange.emit(newValue);
377
-
378
- // Restore cursor position
379
- setTimeout(() => {
380
- target.selectionStart = target.selectionEnd = start - removeLength;
381
- });
382
- }
383
- } else {
384
- // Indent
385
- const newValue = value.slice(0, start) + indent + value.slice(end);
386
- this.value.set(newValue);
387
- this.valueChange.emit(newValue);
388
-
389
- // Move cursor after indent
390
- setTimeout(() => {
391
- target.selectionStart = target.selectionEnd = start + indent.length;
392
- });
393
- }
394
- }
395
-
396
- // Handle Enter for auto-indent
397
- if (event.key === 'Enter' && !event.shiftKey) {
398
- const start = target.selectionStart;
399
- const value = target.value;
400
-
401
- // Find the current line's indentation
402
- const lineStart = value.lastIndexOf('\n', start - 1) + 1;
403
- const lineContent = value.slice(lineStart, start);
404
- const indentMatch = lineContent.match(/^(\s*)/);
405
- const currentIndent = indentMatch ? indentMatch[1] : '';
406
-
407
- // Check if we need extra indent (after { or :)
408
- const charBefore = value[start - 1];
409
- const extraIndent =
410
- charBefore === '{' || charBefore === ':' || charBefore === '['
411
- ? this.insertSpaces()
412
- ? ' '.repeat(this.tabSize())
413
- : '\t'
414
- : '';
415
-
416
- event.preventDefault();
417
- const newValue =
418
- value.slice(0, start) +
419
- '\n' +
420
- currentIndent +
421
- extraIndent +
422
- value.slice(start);
423
-
424
- this.value.set(newValue);
425
- this.valueChange.emit(newValue);
426
-
427
- setTimeout(() => {
428
- const newPos = start + 1 + currentIndent.length + extraIndent.length;
429
- target.selectionStart = target.selectionEnd = newPos;
430
- this.updateCursorPosition(target);
431
- });
432
- }
433
-
434
- // Handle closing brackets
435
- if (event.key === '}' || event.key === ']' || event.key === ')') {
436
- const start = target.selectionStart;
437
- const value = target.value;
438
- const lineStart = value.lastIndexOf('\n', start - 1) + 1;
439
- const beforeCursor = value.slice(lineStart, start);
440
-
441
- // If line is only whitespace, reduce indent
442
- if (/^\s+$/.test(beforeCursor)) {
443
- const reduceBy = this.insertSpaces() ? this.tabSize() : 1;
444
- const newIndent = beforeCursor.slice(
445
- 0,
446
- Math.max(0, beforeCursor.length - reduceBy),
447
- );
448
-
449
- event.preventDefault();
450
- const newValue =
451
- value.slice(0, lineStart) +
452
- newIndent +
453
- event.key +
454
- value.slice(start);
455
-
456
- this.value.set(newValue);
457
- this.valueChange.emit(newValue);
458
-
459
- setTimeout(() => {
460
- target.selectionStart = target.selectionEnd =
461
- lineStart + newIndent.length + 1;
462
- });
463
- }
464
- }
465
- }
466
-
467
- protected onScroll(event: Event): void {
468
- const target = event.target as HTMLTextAreaElement;
469
- this.scrollTop = target.scrollTop;
470
- this.scrollLeft = target.scrollLeft;
471
-
472
- // Sync scroll with the display layer
473
- const displayLayer = target.previousElementSibling as HTMLElement;
474
- if (displayLayer) {
475
- displayLayer.scrollTop = this.scrollTop;
476
- displayLayer.scrollLeft = this.scrollLeft;
477
- }
478
- }
479
-
480
- protected onFocus(): void {
481
- this.isFocused.set(true);
482
- }
483
-
484
- protected onBlur(): void {
485
- this.isFocused.set(false);
486
- }
487
-
488
- protected updateActiveLine(event: Event): void {
489
- const target = event.target as HTMLTextAreaElement;
490
- this.updateCursorPosition(target);
491
- }
492
-
493
- private updateCursorPosition(textarea: HTMLTextAreaElement): void {
494
- const value = textarea.value;
495
- const pos = textarea.selectionStart;
496
-
497
- // Calculate line and column
498
- const textBeforeCursor = value.slice(0, pos);
499
- const lines = textBeforeCursor.split('\n');
500
- const line = lines.length;
501
- const column = lines[lines.length - 1].length + 1;
502
-
503
- this.activeLine.set(line);
504
- this.activeColumn.set(column);
505
- this.cursorChange.emit({ line, column });
506
- }
507
- }
@@ -1,77 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- signal,
7
- ViewEncapsulation,
8
- } from '@angular/core';
9
- import { cn } from '@semantic-components/ui';
10
-
11
- @Component({
12
- selector: 'button[sc-code-editor-copy-button]',
13
- template: `
14
- @if (copied()) {
15
- <svg
16
- xmlns="http://www.w3.org/2000/svg"
17
- viewBox="0 0 24 24"
18
- fill="none"
19
- stroke="currentColor"
20
- stroke-width="2"
21
- class="size-4"
22
- >
23
- <polyline points="20 6 9 17 4 12" />
24
- </svg>
25
- } @else {
26
- <svg
27
- xmlns="http://www.w3.org/2000/svg"
28
- viewBox="0 0 24 24"
29
- fill="none"
30
- stroke="currentColor"
31
- stroke-width="2"
32
- class="size-4"
33
- >
34
- <rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
35
- <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
36
- </svg>
37
- }
38
- `,
39
- host: {
40
- 'data-slot': 'code-editor-copy-button',
41
- '[class]': 'class()',
42
- '[attr.aria-label]': 'ariaLabel()',
43
- type: 'button',
44
- '(click)': 'copyCode($event)',
45
- },
46
- encapsulation: ViewEncapsulation.None,
47
- changeDetection: ChangeDetectionStrategy.OnPush,
48
- })
49
- export class ScCodeEditorCopyButton {
50
- readonly code = input.required<string>();
51
- readonly classInput = input<string>('', { alias: 'class' });
52
-
53
- readonly copied = signal(false);
54
-
55
- protected readonly class = computed(() =>
56
- cn(
57
- 'rounded p-1.5 text-muted-foreground transition-colors hover:bg-accent hover:text-foreground',
58
- this.classInput(),
59
- ),
60
- );
61
-
62
- protected readonly ariaLabel = computed(() =>
63
- this.copied() ? 'Copied!' : 'Copy code',
64
- );
65
-
66
- protected async copyCode(event: Event): Promise<void> {
67
- event.stopPropagation();
68
-
69
- try {
70
- await navigator.clipboard.writeText(this.code());
71
- this.copied.set(true);
72
- setTimeout(() => this.copied.set(false), 2000);
73
- } catch (err) {
74
- console.error('Failed to copy code:', err);
75
- }
76
- }
77
- }
@@ -1,31 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- ViewEncapsulation,
7
- } from '@angular/core';
8
- import { cn } from '@semantic-components/ui';
9
-
10
- @Component({
11
- selector: 'div[sc-code-editor-footer]',
12
- template: `
13
- <ng-content />
14
- `,
15
- host: {
16
- 'data-slot': 'code-editor-footer',
17
- '[class]': 'class()',
18
- },
19
- encapsulation: ViewEncapsulation.None,
20
- changeDetection: ChangeDetectionStrategy.OnPush,
21
- })
22
- export class ScCodeEditorFooter {
23
- readonly classInput = input<string>('', { alias: 'class' });
24
-
25
- protected readonly class = computed(() =>
26
- cn(
27
- 'flex items-center justify-between border-t border-border bg-background/50 px-3 py-1.5 text-xs text-muted-foreground',
28
- this.classInput(),
29
- ),
30
- );
31
- }
@@ -1,31 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- ViewEncapsulation,
7
- } from '@angular/core';
8
- import { cn } from '@semantic-components/ui';
9
-
10
- @Component({
11
- selector: 'div[sc-code-editor-header]',
12
- template: `
13
- <ng-content />
14
- `,
15
- host: {
16
- 'data-slot': 'code-editor-header',
17
- '[class]': 'class()',
18
- },
19
- encapsulation: ViewEncapsulation.None,
20
- changeDetection: ChangeDetectionStrategy.OnPush,
21
- })
22
- export class ScCodeEditorHeader {
23
- readonly classInput = input<string>('', { alias: 'class' });
24
-
25
- protected readonly class = computed(() =>
26
- cn(
27
- 'flex items-center justify-between border-b border-border bg-background/50 px-3 py-2',
28
- this.classInput(),
29
- ),
30
- );
31
- }
@@ -1,28 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- ViewEncapsulation,
7
- } from '@angular/core';
8
- import { cn } from '@semantic-components/ui';
9
-
10
- @Component({
11
- selector: 'span[sc-code-editor-label]',
12
- template: `
13
- <ng-content />
14
- `,
15
- host: {
16
- 'data-slot': 'code-editor-label',
17
- '[class]': 'class()',
18
- },
19
- encapsulation: ViewEncapsulation.None,
20
- changeDetection: ChangeDetectionStrategy.OnPush,
21
- })
22
- export class ScCodeEditorLabel {
23
- readonly classInput = input<string>('', { alias: 'class' });
24
-
25
- protected readonly class = computed(() =>
26
- cn('text-xs font-medium text-muted-foreground', this.classInput()),
27
- );
28
- }
@@ -1,31 +0,0 @@
1
- import {
2
- ChangeDetectionStrategy,
3
- Component,
4
- computed,
5
- input,
6
- ViewEncapsulation,
7
- } from '@angular/core';
8
- import { cn } from '@semantic-components/ui';
9
-
10
- @Component({
11
- selector: 'div[sc-code-editor]',
12
- template: `
13
- <ng-content />
14
- `,
15
- host: {
16
- 'data-slot': 'code-editor',
17
- '[class]': 'class()',
18
- },
19
- encapsulation: ViewEncapsulation.None,
20
- changeDetection: ChangeDetectionStrategy.OnPush,
21
- })
22
- export class ScCodeEditor {
23
- readonly classInput = input<string>('', { alias: 'class' });
24
-
25
- protected readonly class = computed(() =>
26
- cn(
27
- 'overflow-hidden rounded-lg border border-border bg-muted focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2',
28
- this.classInput(),
29
- ),
30
- );
31
- }