-
Notifications
You must be signed in to change notification settings - Fork 2
/
IconHelper.tsx
113 lines (103 loc) · 3.86 KB
/
IconHelper.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Utilities
*/
import * as React from "react";
import { ConditionalStringValue } from "@itwin/appui-abstract";
import type { IconSpec } from "../icons/IconComponent";
import { Icon } from "../icons/IconComponent";
import { ConditionalIconItem } from "../icons/ConditionalIconItem";
/** Icon Helper Class used to store the data needed to generate an <Icon> for use in any control that shows an icon.
* @public
*/
export class IconHelper {
public static get reactIconKey(): string {
return "#-react-iconspec-node-#";
}
public static get conditionalIconItemKey(): string {
return "#-conditional-icon-item-node-#";
}
/** Returns an <Icon> ReactNode from the many ways an icon can be specified.
* @param icon abstract icon specification.
* @param internalData a map that may hold a React.ReactNode stored in an abstract item definition.
*/
public static getIconReactNode(
icon:
| string
| ConditionalStringValue
| React.ReactNode
| ConditionalIconItem,
internalData?: Map<string, any>
): React.ReactNode {
// istanbul ignore else
if (!icon) return null;
// istanbul ignore else
if (ConditionalIconItem.isConditionalIconItem(icon))
return <Icon iconSpec={ConditionalIconItem.getValue(icon)} />;
// istanbul ignore else
if (React.isValidElement(icon)) return <Icon iconSpec={icon} />;
// istanbul ignore if
if (!(icon instanceof ConditionalStringValue) && typeof icon !== "string")
return null;
const iconString = ConditionalStringValue.getValue(icon);
if (!iconString) return null;
// istanbul ignore else
if (iconString === IconHelper.reactIconKey) {
// istanbul ignore else
if (internalData)
return (
<Icon
iconSpec={
internalData.get(IconHelper.reactIconKey) as React.ReactNode
}
/>
);
return null;
} else if (iconString === IconHelper.conditionalIconItemKey) {
// istanbul ignore else
if (internalData) {
const iconItem = internalData.get(
IconHelper.conditionalIconItemKey
) as ConditionalIconItem;
return <Icon iconSpec={ConditionalIconItem.getValue(iconItem)} />;
}
return null;
}
return <Icon iconSpec={iconString} />;
}
/** Returns an icon definition that can be stored in an abstract item definition. If the iconSpec specifies a ReactNode
* then the react data is stored in the internalData map and the key to the react data is returned.
* @param iconSpec any supported variations of how an icon can be defined in an abstract item or IconProps.
* @param internalData a map supplied by the caller to store away react element if React.ReactNode
*/
public static getIconData(
iconSpec: IconSpec,
internalData?: Map<string, any>
): string | ConditionalStringValue {
let icon;
if (ConditionalIconItem.isConditionalIconItem(iconSpec)) {
icon = IconHelper.conditionalIconItemKey;
// istanbul ignore else
if (internalData)
internalData.set(IconHelper.conditionalIconItemKey, iconSpec);
return icon;
} else {
icon = React.isValidElement(iconSpec)
? IconHelper.reactIconKey
: iconSpec;
}
if (
internalData &&
typeof icon === "string" &&
icon === IconHelper.reactIconKey
) {
internalData.set(IconHelper.reactIconKey, iconSpec);
}
if (typeof icon === "string" || icon instanceof ConditionalStringValue)
return icon;
return "";
}
}