@xplortech/apollo-icons 0.2.2 → 0.3.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.
package/index.js CHANGED
@@ -1,13 +1,34 @@
1
- const data = require('./build/data.json')
2
- const objectAssign = require('object-assign')
1
+ const data = require('./build/data.json');
2
+ const objectAssign = require('object-assign');
3
+ const nameAliases = require('./build/name-aliases.json');
3
4
 
4
- const DEFAULT_HEIGHT = 16
5
+ const DEFAULT_HEIGHT = 16;
6
+
7
+ // Track which apollo names have already warned (warn once per name)
8
+ const warnedNames = new Set();
9
+
10
+ /**
11
+ * Log a deprecation warning for apollo name usage (once per name)
12
+ * @param {string} apolloName - The deprecated apollo name that was used
13
+ * @param {string} nucleoName - The nucleo name that should be used instead
14
+ */
15
+ function warnDeprecation(apolloName, nucleoName) {
16
+ if (warnedNames.has(apolloName)) return;
17
+ warnedNames.add(apolloName);
18
+
19
+ // eslint-disable-next-line no-console
20
+ console.warn(
21
+ `[octicons] Deprecation warning: Icon name "${apolloName}" is deprecated ` +
22
+ `and will be removed in the next major release. ` +
23
+ `Please use "${nucleoName}" instead.`
24
+ );
25
+ }
5
26
 
6
27
  for (const key of Object.keys(data)) {
7
28
  // Returns a string representation of html attributes
8
29
  const htmlAttributes = (icon, defaultOptions, options) => {
9
- const attributes = []
10
- const attrObj = objectAssign({}, defaultOptions, options)
30
+ const attributes = [];
31
+ const attrObj = objectAssign({}, defaultOptions, options);
11
32
 
12
33
  // If the user passed in options
13
34
  if (options) {
@@ -15,37 +36,39 @@ for (const key of Object.keys(data)) {
15
36
  if (options['width'] || options['height']) {
16
37
  attrObj['width'] = options['width']
17
38
  ? options['width']
18
- : (parseInt(options['height']) * defaultOptions['width']) / defaultOptions['height']
39
+ : (parseInt(options['height']) * defaultOptions['width']) /
40
+ defaultOptions['height'];
19
41
  attrObj['height'] = options['height']
20
42
  ? options['height']
21
- : (parseInt(options['width']) * defaultOptions['height']) / defaultOptions['width']
43
+ : (parseInt(options['width']) * defaultOptions['height']) /
44
+ defaultOptions['width'];
22
45
  }
23
46
 
24
47
  // If the user passed in class
25
48
  if (options['class']) {
26
- attrObj['class'] = `octicon octicon-${key} ${options['class']}`
27
- attrObj['class'].trim()
49
+ attrObj['class'] = `octicon octicon-${key} ${options['class']}`;
50
+ attrObj['class'].trim();
28
51
  }
29
52
 
30
53
  // If the user passed in aria-label
31
54
  if (options['aria-label']) {
32
- attrObj['aria-label'] = options['aria-label']
33
- attrObj['role'] = 'img'
55
+ attrObj['aria-label'] = options['aria-label'];
56
+ attrObj['role'] = 'img';
34
57
 
35
58
  // Un-hide the icon
36
- delete attrObj['aria-hidden']
59
+ delete attrObj['aria-hidden'];
37
60
  }
38
61
  }
39
62
 
40
63
  for (const option of Object.keys(attrObj)) {
41
- attributes.push(`${option}="${attrObj[option]}"`)
64
+ attributes.push(`${option}="${attrObj[option]}"`);
42
65
  }
43
66
 
44
- return attributes.join(' ').trim()
45
- }
67
+ return attributes.join(' ').trim();
68
+ };
46
69
 
47
70
  // Set the symbol for easy access
48
- data[key].symbol = key
71
+ data[key].symbol = key;
49
72
 
50
73
  // Set options for each icon height
51
74
  for (const height of Object.keys(data[key].heights)) {
@@ -56,24 +79,117 @@ for (const key of Object.keys(data)) {
56
79
  viewBox: `0 0 ${data[key].heights[height].width} ${height}`,
57
80
  class: `octicon octicon-${key}`,
58
81
  'aria-hidden': 'true',
59
- }
82
+ };
60
83
  }
61
84
 
62
85
  // Function to return an SVG object
63
86
  data[key].toSVG = function (options = {}) {
64
- const {height, width} = options
65
- const naturalHeight = closestNaturalHeight(Object.keys(data[key].heights), height || width || DEFAULT_HEIGHT)
66
- return `<svg ${htmlAttributes(data[key], data[key].heights[naturalHeight].options, options)}>${
67
- data[key].heights[naturalHeight].path
68
- }</svg>`
87
+ const { height, width } = options;
88
+ const naturalHeight = closestNaturalHeight(
89
+ Object.keys(data[key].heights),
90
+ height || width || DEFAULT_HEIGHT
91
+ );
92
+ return `<svg ${htmlAttributes(
93
+ data[key],
94
+ data[key].heights[naturalHeight].options,
95
+ options
96
+ )}>${data[key].heights[naturalHeight].path}</svg>`;
97
+ };
98
+ }
99
+
100
+ // Returns all icons that have the specified tag/keyword
101
+ function getIconsByTag(tag) {
102
+ return Object.values(data).filter(
103
+ (icon) => icon.keywords && icon.keywords.includes(tag)
104
+ );
105
+ }
106
+
107
+ /**
108
+ * Get an icon by name, with fallback to aliased names.
109
+ * Logs deprecation warning when apollo names are used.
110
+ * @param {string} name - Icon name (nucleo or apollo)
111
+ * @returns {object|undefined} The icon object or undefined if not found
112
+ */
113
+ function getIcon(name) {
114
+ // Direct lookup first (no warning)
115
+ if (data[name]) return data[name];
116
+
117
+ // Try apollo -> nucleo fallback (with warning)
118
+ const nucleoName = nameAliases.apolloToNucleo[name];
119
+ if (nucleoName && data[nucleoName]) {
120
+ warnDeprecation(name, nucleoName);
121
+ return data[nucleoName];
69
122
  }
123
+
124
+ return undefined;
70
125
  }
71
126
 
72
- // Import data into exports
73
- module.exports = data
127
+ // Proxy handler to intercept apollo name lookups with deprecation warnings
128
+ const proxyHandler = {
129
+ get(target, prop, receiver) {
130
+ // Handle non-string properties and special cases
131
+ if (typeof prop !== 'string') {
132
+ return Reflect.get(target, prop, receiver);
133
+ }
134
+
135
+ // If it's a direct property, return it
136
+ if (prop in target) {
137
+ return Reflect.get(target, prop, receiver);
138
+ }
139
+
140
+ // Check if it's an apollo name that maps to a nucleo name
141
+ const nucleoName = nameAliases.apolloToNucleo[prop];
142
+ if (nucleoName && nucleoName in target) {
143
+ warnDeprecation(prop, nucleoName);
144
+ return Reflect.get(target, nucleoName, receiver);
145
+ }
146
+
147
+ return undefined;
148
+ },
149
+
150
+ // Support 'in' operator for apollo names
151
+ has(target, prop) {
152
+ if (prop in target) return true;
153
+ const nucleoName = nameAliases.apolloToNucleo[prop];
154
+ return nucleoName && nucleoName in target;
155
+ },
156
+
157
+ // Ensure Object.keys() only returns nucleo names
158
+ ownKeys(target) {
159
+ return Reflect.ownKeys(target);
160
+ },
161
+
162
+ getOwnPropertyDescriptor(target, prop) {
163
+ return Reflect.getOwnPropertyDescriptor(target, prop);
164
+ },
165
+ };
166
+
167
+ // Create proxied export
168
+ const proxiedData = new Proxy(data, proxyHandler);
169
+
170
+ // Export the proxied data
171
+ module.exports = proxiedData;
172
+
173
+ // Add getIconsByTag as a non-enumerable property so it doesn't
174
+ // appear when iterating over icon keys with Object.keys()
175
+ Object.defineProperty(module.exports, 'getIconsByTag', {
176
+ value: getIconsByTag,
177
+ enumerable: false,
178
+ writable: false,
179
+ });
180
+
181
+ // Add getIcon as a non-enumerable property
182
+ Object.defineProperty(module.exports, 'getIcon', {
183
+ value: getIcon,
184
+ enumerable: false,
185
+ writable: false,
186
+ });
74
187
 
75
188
  function closestNaturalHeight(naturalHeights, height) {
76
189
  return naturalHeights
77
- .map(naturalHeight => parseInt(naturalHeight, 10))
78
- .reduce((acc, naturalHeight) => (naturalHeight <= height ? naturalHeight : acc), naturalHeights[0])
190
+ .map((naturalHeight) => parseInt(naturalHeight, 10))
191
+ .reduce(
192
+ (acc, naturalHeight) => (naturalHeight <= height ? naturalHeight : acc),
193
+ naturalHeights[0]
194
+ );
79
195
  }
package/index.scss CHANGED
@@ -1,6 +1,6 @@
1
1
  .octicon {
2
2
  display: inline-block;
3
3
  vertical-align: text-top;
4
- fill: currentColor;
4
+ stroke: currentColor;
5
5
  overflow: visible;
6
6
  }
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@xplortech/apollo-icons",
3
- "version": "0.2.2",
3
+ "version": "0.3.0",
4
4
  "description": "A scalable set of icons for Xplor's Apollo Design System.",
5
5
  "homepage": "https://xplor-apollo.herokuapp.com/?path=/story/icons-icons--icons",
6
6
  "author": "Xplor Technologies",
7
7
  "license": "MIT",
8
8
  "style": "index.scss",
9
9
  "main": "index.js",
10
+ "types": "index.d.ts",
10
11
  "files": [
11
12
  "index.js",
13
+ "index.d.ts",
12
14
  "index.scss",
13
15
  "build"
14
16
  ],
@@ -24,7 +26,7 @@
24
26
  "url": "https://github.com/xplor/apollo-icons/issues"
25
27
  },
26
28
  "scripts": {
27
- "build": "\\cp -r ../build/ ./build && \\cp index.scss ./build/build.css",
29
+ "build": "\\cp -r ../build/ ./build && \\cp index.scss ./build/build.css && cp ../../name-aliases.json ./build/name-aliases.json",
28
30
  "lint": "eslint index.js tests/*.js",
29
31
  "test": "ava --verbose 'tests/*.js'"
30
32
  },