• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

IgniteUI / igniteui-webcomponents / 18941531802

30 Oct 2025 01:03PM UTC coverage: 98.129% (-0.008%) from 98.137%
18941531802

push

github

web-flow
fix(chat): adoptRootStyles @import rules interaction (#1931)

Since `@import` was officially dropped from the specfication for
constructed style sheets, skip trying to insert any such CSS rules
and error out, preventing adopting the rest of the rules inside the
chat message.

Co-authored-by: Galina Edinakova <gedinakova@infragistics.com>

5307 of 5588 branches covered (94.97%)

Branch coverage included in aggregate %.

2 of 4 new or added lines in 1 file covered. (50.0%)

35298 of 35791 relevant lines covered (98.62%)

1641.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.12
/src/components/chat/utils.ts
1
import { adoptStyles, type LitElement } from 'lit';
10✔
2
import { last } from '../common/util.js';
10✔
3
import type IgcChatMessageComponent from './chat-message.js';
10✔
4
import type { IgcChatMessageAttachment } from './types.js';
10✔
5

10✔
6
export type ChatAcceptedFileTypes = {
10✔
7
  extensions: Set<string>;
10✔
8
  mimeTypes: Set<string>;
10✔
9
  wildcardTypes: Set<string>;
10✔
10
};
10✔
11

10✔
12
export const ChatFileTypeIcons = new Map(
10✔
13
  Object.entries({
10✔
14
    css: 'file_css',
10✔
15
    csv: 'file_csv',
10✔
16
    doc: 'file_doc',
10✔
17
    docx: 'file_doc',
10✔
18
    htm: 'file_htm',
10✔
19
    html: 'file_html',
10✔
20
    js: 'file_js',
10✔
21
    json: 'file_json',
10✔
22
    pdf: 'file_pdf',
10✔
23
    rtf: 'file_rtf',
10✔
24
    svg: 'file_svg',
10✔
25
    txt: 'file_txt',
10✔
26
    url: 'file_link',
10✔
27
    xls: 'file_xls',
10✔
28
    xlsx: 'file_xls',
10✔
29
    xml: 'file_xml',
10✔
30
    zip: 'file_zip',
10✔
31
    default: 'file_generic',
10✔
32
  })
10✔
33
);
10✔
34

10✔
35
export function parseAcceptedFileTypes(
10✔
36
  fileTypes: string
2✔
37
): ChatAcceptedFileTypes {
2✔
38
  const types = fileTypes.split(',').map((each) => each.trim().toLowerCase());
2✔
39
  return {
2✔
40
    extensions: new Set(types.filter((t) => t.startsWith('.'))),
2✔
41
    mimeTypes: new Set(
2✔
42
      types.filter((t) => !t.startsWith('.') && !t.endsWith('/*'))
2✔
43
    ),
2✔
44
    wildcardTypes: new Set(
2✔
45
      types.filter((t) => t.endsWith('/*')).map((t) => t.slice(0, -2))
2✔
46
    ),
2✔
47
  };
2✔
48
}
2✔
49

10✔
50
export function isAcceptedFileType(
10✔
51
  file: File,
4✔
52
  accepted: ChatAcceptedFileTypes | null
4✔
53
): boolean {
4✔
54
  if (!(accepted && file)) {
4!
55
    return true;
×
56
  }
×
57

4✔
58
  const { extensions, mimeTypes, wildcardTypes } = accepted;
4✔
59
  const fileType = file.type.toLowerCase();
4✔
60
  const fileExtension = `.${last(file.name.split('.'))?.toLowerCase()}`;
4✔
61
  const [fileBaseType] = fileType.split('/');
4✔
62

4✔
63
  return (
4✔
64
    extensions.has(fileExtension) ||
4✔
65
    mimeTypes.has(fileType) ||
2✔
66
    wildcardTypes.has(fileBaseType)
2✔
67
  );
4✔
68
}
4✔
69

10✔
70
export function getChatAcceptedFiles(
10✔
71
  event: DragEvent,
2✔
72
  accepted: ChatAcceptedFileTypes | null
2✔
73
): File[] {
2✔
74
  return Array.from(event.dataTransfer?.items ?? [])
2!
75
    .filter(
2✔
76
      (item) =>
2✔
77
        item.kind === 'file' && isAcceptedFileType(item.getAsFile()!, accepted)
4✔
78
    )
2✔
79
    .map((item) => item.getAsFile()!);
2✔
80
}
2✔
81

10✔
82
export function getIconName(fileType?: string) {
10✔
83
  return fileType?.startsWith('image') ? 'attach_image' : 'attach_document';
11✔
84
}
11✔
85

10✔
86
export function createAttachmentURL(
10✔
87
  attachment: IgcChatMessageAttachment
7✔
88
): string {
7✔
89
  if (attachment.file) {
7!
90
    return URL.createObjectURL(attachment.file);
×
91
  }
×
92

7✔
93
  return attachment.url || '';
7!
94
}
7✔
95

10✔
96
export function getFileExtension(name: string): string {
10✔
97
  const parts = name.split('.');
13✔
98
  return parts.length > 1 ? last(parts) : '';
13!
99
}
13✔
100

10✔
101
export function isImageAttachment(
10✔
102
  attachment: IgcChatMessageAttachment | File
37✔
103
): boolean {
37✔
104
  if (attachment instanceof File) {
37✔
105
    return attachment.type.startsWith('image/');
11✔
106
  }
11✔
107

26✔
108
  return Boolean(
26✔
109
    attachment.type === 'image' || attachment.file?.type.startsWith('image/')
37✔
110
  );
37✔
111
}
37✔
112

10✔
113
export function chatMessageAdoptPageStyles(
10✔
114
  message: IgcChatMessageComponent
1✔
115
): void {
1✔
116
  const sheets: CSSStyleSheet[] = [];
1✔
117

1✔
118
  for (const sheet of document.styleSheets) {
1✔
119
    try {
1✔
120
      const constructed = new CSSStyleSheet();
1✔
121
      for (const rule of sheet.cssRules) {
1✔
122
        // https://drafts.csswg.org/cssom/#dom-cssstylesheet-insertrule:~:text=If%20parsed%20rule%20is%20an%20%40import%20rule
1✔
123
        if (rule.cssText.startsWith('@import')) {
1!
NEW
124
          continue;
×
NEW
125
        }
×
126
        constructed.insertRule(rule.cssText);
1✔
127
      }
1✔
128
      sheets.push(constructed);
1✔
129
    } catch {}
1!
130
  }
1✔
131

1✔
132
  const ctor = message.constructor as typeof LitElement;
1✔
133
  adoptStyles(message.shadowRoot!, [...ctor.elementStyles, ...sheets]);
1✔
134
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc