@sj-distributor/react-iconfont-cli 2.4.2 → 2.5.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/README.md CHANGED
@@ -155,6 +155,32 @@ export const App = () => {
155
155
  </div>
156
156
  ```
157
157
 
158
+ ## 无障碍支持(WCAG)
159
+
160
+ 无障碍属性添加在最终生成的单图标 SVG 上。重新运行生成命令后,现有调用无需修改即可获得默认的可访问名称。
161
+
162
+ 将生成类似下面的 SVG:
163
+
164
+ ```html
165
+ <svg role="img" aria-label="alipay" focusable="false">...</svg>
166
+ ```
167
+
168
+ 默认的 `aria-label` 是本包提供的兜底值:它根据去除前缀后的图标名生成,并将连字符、下划线和驼峰命名转换为空格。例如 `arrow-left` 会生成 `aria-label="arrow left"`。
169
+
170
+ 本包无法判断图标在具体页面中的含义和语言。调用方应根据实际语境覆盖默认标签:
171
+
172
+ ```tsx
173
+ <IconFont name="alipay" aria-label="支付宝" />
174
+ ```
175
+
176
+ 如果图标只是装饰,或者所在按钮、链接已经有可访问名称,可以显式隐藏图标,避免读屏软件重复朗读:
177
+
178
+ ```tsx
179
+ <button type="button" aria-label="关闭">
180
+ <IconFont name="close" aria-hidden="true" />
181
+ </button>
182
+ ```
183
+
158
184
  ## 更新图标
159
185
 
160
186
  当 iconfont 项目图标有变更时,更新 `iconfont.json` 中的 `symbol_url` 后重新生成:
@@ -39,6 +39,7 @@ var generateComponent = function (data, config) {
39
39
  cases += "".concat((0, whitespace_1.whitespace)(6), "return <").concat(componentName, " {...rest} />;\n");
40
40
  singleFile = (0, getTemplate_1.getTemplate)("SingleIcon" + jsxExtension);
41
41
  singleFile = (0, replace_1.replaceSize)(singleFile, config.default_icon_size);
42
+ singleFile = (0, replace_1.replaceAriaLabel)(singleFile, getAccessibleLabel(iconIdAfterTrim));
42
43
  if (jsxExtension === ".tsx") {
43
44
  singleFile = (0, replace_1.replaceReactName)(singleFile, config.can_import_react);
44
45
  }
@@ -74,7 +75,7 @@ var generateComponent = function (data, config) {
74
75
  exports.generateComponent = generateComponent;
75
76
  var generateCase = function (data, baseIdent) {
76
77
  var e_1, _a;
77
- var template = "\n".concat((0, whitespace_1.whitespace)(baseIdent), "<svg viewBox=\"").concat(data.$.viewBox, "\" width={size} height={size} style={style} {...rest}>\n");
78
+ var template = "\n".concat((0, whitespace_1.whitespace)(baseIdent), "<svg viewBox=\"").concat(data.$.viewBox, "\" width={size} height={size} style={style} role={role} aria-label={accessibilityLabel} focusable=\"false\" {...rest}>\n");
78
79
  // Determine the primary fill color (first path's fill)
79
80
  // to distinguish primary paths from detail paths at runtime.
80
81
  var primaryFill = getPrimaryFill(data);
@@ -115,6 +116,14 @@ var generateCase = function (data, baseIdent) {
115
116
  template += "".concat((0, whitespace_1.whitespace)(baseIdent), "</svg>\n");
116
117
  return template;
117
118
  };
119
+ var getAccessibleLabel = function (iconName) {
120
+ var label = iconName
121
+ .replace(/([a-z\d])([A-Z])/g, "$1 $2")
122
+ .replace(/[-_.=+#@!~*]+/g, " ")
123
+ .replace(/\s+/g, " ")
124
+ .trim();
125
+ return label || iconName;
126
+ };
118
127
  var getPrimaryFill = function (data) {
119
128
  var e_2, _a;
120
129
  var _b;
package/libs/replace.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export declare const replaceSize: (content: string, size: number) => string;
2
+ export declare const replaceAriaLabel: (content: string, label: string) => string;
2
3
  export declare const replaceCases: (content: string, cases: string) => string;
3
4
  export declare const replaceNames: (content: string, names: string[]) => string;
4
5
  export declare const replaceNamesArray: (content: string, names: string[]) => string;
package/libs/replace.js CHANGED
@@ -1,10 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.replaceExports = exports.replaceSizeUnit = exports.replaceImports = exports.replaceSingleIconContent = exports.replaceReactName = exports.replaceComponentName = exports.replaceNamesArray = exports.replaceNames = exports.replaceCases = exports.replaceSize = void 0;
3
+ exports.replaceExports = exports.replaceSizeUnit = exports.replaceImports = exports.replaceSingleIconContent = exports.replaceReactName = exports.replaceComponentName = exports.replaceNamesArray = exports.replaceNames = exports.replaceCases = exports.replaceAriaLabel = exports.replaceSize = void 0;
4
4
  var replaceSize = function (content, size) {
5
5
  return content.replace(/#size#/g, String(size));
6
6
  };
7
7
  exports.replaceSize = replaceSize;
8
+ var replaceAriaLabel = function (content, label) {
9
+ return content.replace(/#ariaLabel#/g, JSON.stringify(label));
10
+ };
11
+ exports.replaceAriaLabel = replaceAriaLabel;
8
12
  var replaceCases = function (content, cases) {
9
13
  return content.replace(/#cases#/g, cases);
10
14
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sj-distributor/react-iconfont-cli",
3
- "version": "2.4.2",
3
+ "version": "2.5.0",
4
4
  "main": "index.js",
5
5
  "keywords": [
6
6
  "iconfont",
@@ -7,8 +7,16 @@ const DEFAULT_STYLE = {
7
7
  display: 'block',
8
8
  };
9
9
 
10
- const #componentName# = ({ size = #size#, color, style: _style, ...rest }) => {
10
+ const #componentName# = ({
11
+ size = #size#,
12
+ color,
13
+ style: _style,
14
+ role = 'img',
15
+ 'aria-label': ariaLabel,
16
+ ...rest
17
+ }) => {
11
18
  const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE;
19
+ const accessibilityLabel = typeof ariaLabel === 'string' && ariaLabel.trim() ? ariaLabel.trim() : #ariaLabel#;
12
20
 
13
21
  return (#iconContent# );
14
22
  };
@@ -13,8 +13,16 @@ const DEFAULT_STYLE: CSSProperties = {
13
13
  display: 'block',
14
14
  };
15
15
 
16
- const #componentName#: FunctionComponent<Props> = ({ size = #size#, color, style: _style, ...rest }) => {
16
+ const #componentName#: FunctionComponent<Props> = ({
17
+ size = #size#,
18
+ color,
19
+ style: _style,
20
+ role = 'img',
21
+ 'aria-label': ariaLabel,
22
+ ...rest
23
+ }) => {
17
24
  const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE;
25
+ const accessibilityLabel = ariaLabel && ariaLabel.trim() ? ariaLabel.trim() : #ariaLabel#;
18
26
 
19
27
  return (#iconContent# );
20
28
  };