Line data Source code
1 : import * as React from 'react';
2 : import icons from '@ankoh/dashql-svg-symbols';
3 :
4 : export type IconSize = number | 'small' | 'medium' | 'large';
5 :
6 : export interface IconProps extends Omit<React.SVGProps<SVGSVGElement>, 'size' | 'title'> {
7 : size?: IconSize;
8 : title?: string;
9 : verticalAlign?: React.CSSProperties['verticalAlign'];
10 : }
11 :
12 : export type Icon = React.FC<IconProps>;
13 :
14 : type SymbolVariants = Readonly<Record<number, string>>;
15 :
16 1 : const ICON_SIZE: Record<Exclude<IconSize, number>, number> = {
17 1 : small: 16,
18 1 : medium: 32,
19 1 : large: 64,
20 1 : };
21 :
22 1 : function resolveSize(size: IconSize | undefined): number {
23 1 : if (typeof size === 'number') {
24 1 : return size;
25 : }
26 1 : return size == null ? 16 : ICON_SIZE[size];
27 1 : }
28 :
29 1 : function resolveSymbol(variants: SymbolVariants, size: number): string {
30 1 : const naturalSizes = Object.keys(variants).map(Number).sort((a, b) => a - b);
31 1 : let naturalSize = naturalSizes[0];
32 1 : for (const candidate of naturalSizes) {
33 1 : if (candidate > size) {
34 1 : break;
35 : }
36 1 : naturalSize = candidate;
37 1 : }
38 1 : return variants[naturalSize];
39 1 : }
40 :
41 1 : function createIcon(variants: SymbolVariants): Icon {
42 1 : return React.forwardRef<SVGSVGElement, IconProps>((props, ref) => {
43 1 : const {
44 1 : 'aria-label': ariaLabel,
45 1 : 'aria-labelledby': ariaLabelledBy,
46 1 : className,
47 1 : fill = 'currentColor',
48 1 : size,
49 1 : style,
50 1 : tabIndex,
51 1 : title,
52 1 : verticalAlign = 'text-bottom',
53 1 : ...svgProps
54 1 : } = props;
55 1 : const pixels = resolveSize(size);
56 1 : const labelled = Boolean(ariaLabel || ariaLabelledBy);
57 1 : const symbol = resolveSymbol(variants, pixels);
58 :
59 1 : return (
60 1 : <svg
61 1 : ref={ref}
62 1 : {...svgProps}
63 1 : aria-hidden={labelled ? undefined : 'true'}
64 1 : aria-label={ariaLabel}
65 1 : aria-labelledby={ariaLabelledBy}
66 1 : className={className}
67 1 : color={fill}
68 1 : display="inline-block"
69 1 : fill="currentColor"
70 1 : focusable={tabIndex != null && tabIndex >= 0 ? 'true' : 'false'}
71 1 : height={pixels}
72 1 : overflow="visible"
73 1 : role={labelled ? 'img' : undefined}
74 1 : style={{ verticalAlign, ...style }}
75 1 : tabIndex={tabIndex}
76 1 : width={pixels}
77 : >
78 1 : {title != null && <title>{title}</title>}
79 1 : <use xlinkHref={`${icons}#${symbol}`} />
80 1 : </svg>
81 : );
82 1 : });
83 1 : }
84 :
85 1 : const SYMBOL_ICONS = new Map<string, Icon>();
86 :
87 1 : export function SymbolIcon(symbol: string): Icon {
88 1 : const cached = SYMBOL_ICONS.get(symbol);
89 1 : if (cached != null) {
90 1 : return cached;
91 : }
92 1 : const icon = createIcon({ 16: symbol });
93 1 : SYMBOL_ICONS.set(symbol, icon);
94 1 : return icon;
95 1 : }
96 :
97 1 : export const AlertIcon = createIcon({ 16: 'alert_16' });
98 1 : export const BracesIcon = createIcon({ 16: 'braces_16' });
99 1 : export const BookIcon = createIcon({ 16: 'book_16', 24: 'book_24' });
100 1 : export const BroomIcon = createIcon({ 16: 'broom_16', 24: 'broom_24' });
101 1 : export const CheckIcon = createIcon({ 16: 'check_16', 24: 'check_24' });
102 1 : export const ChecklistIcon = createIcon({ 16: 'checklist_16' });
103 1 : export const ChevronDownIcon = createIcon({ 12: 'chevron_down_12', 16: 'chevron_down_16', 24: 'chevron_down_24' });
104 1 : export const ChevronLeftIcon = createIcon({ 12: 'chevron_left_12', 16: 'chevron_left_16', 24: 'chevron_left_24' });
105 1 : export const ChevronRightIcon = createIcon({ 12: 'chevron_right_12', 16: 'chevron_right_16', 24: 'chevron_right_24' });
106 1 : export const ChevronUpIcon = createIcon({ 12: 'chevron_up_12', 16: 'chevron_up_16', 24: 'chevron_up_24' });
107 1 : export const CircleSlashIcon = createIcon({ 16: 'circle_slash_16', 24: 'circle_slash' });
108 1 : export const CodeIcon = createIcon({ 16: 'code_16' });
109 1 : export const ComposeIcon = createIcon({ 16: 'compose_16', 24: 'compose_24' });
110 1 : export const CopyIcon = createIcon({ 16: 'copy_16' });
111 1 : export const CpuIcon = createIcon({ 16: 'cpu_16', 24: 'cpu_24' });
112 1 : export const DashIcon = createIcon({ 16: 'dash_16' });
113 1 : export const DashboardIcon = createIcon({ 16: 'dashboard_16', 24: 'dashboard_24' });
114 1 : export const DatabaseIcon = createIcon({ 16: 'database_16', 24: 'database' });
115 1 : export const DownloadIcon = createIcon({ 16: 'download_16', 24: 'download' });
116 1 : export const EyeIcon = createIcon({ 16: 'eye_16', 24: 'eye_24' });
117 1 : export const EyeClosedIcon = createIcon({ 16: 'eye_closed_16', 24: 'eye_closed_24' });
118 1 : export const FileBadgeIcon = createIcon({ 16: 'file_badge_16' });
119 1 : export const FileDirectoryFillIcon = createIcon({ 16: 'file_directory_fill_16', 24: 'folder_fill' });
120 1 : export const FileDirectoryIcon = createIcon({ 16: 'file_directory_16', 24: 'folder' });
121 1 : export const FileDirectoryOpenFillIcon = createIcon({ 16: 'file_directory_open_fill_16' });
122 1 : export const FileDirectoryPlusIcon = createIcon({ 16: 'file_directory_plus_16', 24: 'file_directory_plus_24' });
123 1 : export const FileIcon = createIcon({ 16: 'file_16', 24: 'file' });
124 1 : export const GraphIcon = createIcon({ 16: 'graph_16', 24: 'graph_24' });
125 1 : export const HeartIcon = createIcon({ 16: 'heart_16' });
126 1 : export const HistoryIcon = createIcon({ 16: 'history_16' });
127 1 : export const KeyIcon = createIcon({ 16: 'key_16' });
128 1 : export const LibraryIcon = createIcon({ 16: 'library_16', 24: 'library_24' });
129 1 : export const LinkIcon = createIcon({ 16: 'link_16' });
130 1 : export const ListUnorderedIcon = createIcon({ 16: 'list_unordered_16' });
131 1 : export const LockIcon = createIcon({ 16: 'lock_16' });
132 1 : export const PaperAirplaneIcon = createIcon({ 16: 'paper_airplane_16' });
133 1 : export const PaperclipIcon = createIcon({ 16: 'paperclip_16' });
134 1 : export const PencilIcon = createIcon({ 16: 'pencil_16', 24: 'pencil_24' });
135 1 : export const PersonIcon = createIcon({ 16: 'person_16', 24: 'person_24' });
136 1 : export const PlugIcon = createIcon({ 16: 'plug_16', 24: 'plug_24' });
137 1 : export const PlusIcon = createIcon({ 16: 'plus_16', 24: 'plus_24' });
138 1 : export const ProjectIcon = createIcon({ 16: 'project_16' });
139 1 : export const RowsIcon = createIcon({ 16: 'rows_16', 24: 'rows' });
140 1 : export const SaveIcon = createIcon({ 16: 'save_16' });
141 1 : export const SearchIcon = createIcon({ 16: 'search_16' });
142 1 : export const ScreenFullIcon = createIcon({ 16: 'screen_full_16', 24: 'screen_full_24' });
143 1 : export const ScreenNormalIcon = createIcon({ 16: 'screen_normal_16', 24: 'screen_normal_24' });
144 1 : export const StackIcon = createIcon({ 16: 'stack_16', 24: 'stack_24' });
145 1 : export const StackPlusIcon = createIcon({ 16: 'stack_plus_16', 24: 'stack_plus_24' });
146 1 : export const SquareFillIcon = createIcon({ 16: 'square_fill_16' });
147 1 : export const SyncIcon = createIcon({ 16: 'sync_16' });
148 1 : export const TableIcon = createIcon({ 16: 'table_16' });
149 1 : export const ThreeBarsIcon = createIcon({ 16: 'three_bars_16' });
150 1 : export const ToolsIcon = createIcon({ 16: 'tools_16', 24: 'tools_24' });
151 1 : export const TrashIcon = createIcon({ 16: 'trash_16', 24: 'trash_24' });
152 1 : export const TriangleDownIcon = createIcon({ 16: 'triangle_down_16', 24: 'triangle_down_24' });
153 1 : export const UnlinkIcon = createIcon({ 16: 'unlink_16' });
154 1 : export const UploadIcon = createIcon({ 16: 'upload_16', 24: 'upload_24' });
155 1 : export const XCircleFillIcon = createIcon({ 16: 'x_circle_16' });
156 1 : export const XIcon = createIcon({ 12: 'x_12', 16: 'x_16', 24: 'x_24' });
157 1 : export const ZoomInIcon = createIcon({ 16: 'zoom_in_16' });
158 1 : export const ZoomOutIcon = createIcon({ 16: 'zoom_out_16' });
|