create-html-element 4.0.1 → 5.1.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.
Files changed (4) hide show
  1. package/index.d.ts +63 -9
  2. package/index.js +34 -6
  3. package/package.json +13 -9
  4. package/readme.md +34 -2
package/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import {MergeExclusive} from 'type-fest';
2
- import stringifyAttributes, {HTMLAttributes} from 'stringify-attributes';
1
+ import {type MergeExclusive} from 'type-fest';
2
+ import stringifyAttributes, {type HTMLAttributes} from 'stringify-attributes';
3
3
 
4
- export interface BaseOptions {
4
+ export type BaseOptions = {
5
5
  /**
6
6
  HTML tag attributes.
7
7
  */
@@ -13,23 +13,59 @@ export interface BaseOptions {
13
13
  @default 'div'
14
14
  */
15
15
  readonly name?: string;
16
- }
16
+ };
17
17
 
18
- export interface HtmlOptions {
18
+ export type HtmlOptions = {
19
19
  /**
20
20
  HTML tag value in unescaped HTML.
21
21
  */
22
22
  readonly html?: string;
23
- }
23
+ };
24
24
 
25
- export interface TextOptions {
25
+ export type TextOptions = {
26
26
  /**
27
27
  HTML tag value in escaped HTML.
28
28
  */
29
29
  readonly text?: string;
30
- }
30
+ };
31
31
 
32
- export type Options = BaseOptions & MergeExclusive<HtmlOptions, TextOptions>;
32
+ export type ChildrenOptions = {
33
+ /**
34
+ HTML tag children.
35
+
36
+ Strings are escaped, objects are passed to `createHtmlElement`.
37
+
38
+ This option is mutually exclusive with the `html` and `text` options.
39
+
40
+ @example
41
+ ```
42
+ import createHtmlElement from 'create-html-element';
43
+
44
+ createHtmlElement({
45
+ name: 'div',
46
+ children: [
47
+ '<unsafe>',
48
+ {
49
+ name: 'iframe',
50
+ attributes: {
51
+ src: 'https://example.com'
52
+ }
53
+ },
54
+ {
55
+ name: 'span',
56
+ text: 'Label here <em>plz</em>'
57
+ }
58
+ ]
59
+ });
60
+ //=> '<div>&lt;unsafe&gt;<iframe src="https://example.com"></iframe><span>Label here &lt;em&gt;plz&lt;/em&gt;</span></div>'
61
+ ```
62
+ */
63
+ readonly children?: readonly Child[];
64
+ };
65
+
66
+ export type Child = string | (Options & {readonly length?: never});
67
+
68
+ export type Options = BaseOptions & MergeExclusive<HtmlOptions, MergeExclusive<TextOptions, ChildrenOptions>>;
33
69
 
34
70
  /**
35
71
  Create a HTML element string.
@@ -56,6 +92,24 @@ createHtmlElement({
56
92
 
57
93
  createHtmlElement({text: 'Hello <em>World</em>'});
58
94
  //=> '<div>Hello &lt;em&gt;World&lt;/em&gt;</div>'
95
+
96
+ createHtmlElement({
97
+ name: 'div',
98
+ children: [
99
+ '<unsafe>',
100
+ {
101
+ name: 'iframe',
102
+ attributes: {
103
+ src: 'https://example.com'
104
+ }
105
+ },
106
+ {
107
+ name: 'span',
108
+ text: 'Label here <em>plz</em>'
109
+ }
110
+ ]
111
+ });
112
+ //=> '<div>&lt;unsafe&gt;<iframe src="https://example.com"></iframe><span>Label here &lt;em&gt;plz&lt;/em&gt;</span></div>'
59
113
  ```
60
114
  */
61
115
  export default function createHtmlElement(options?: Options): string;
package/index.js CHANGED
@@ -1,22 +1,50 @@
1
1
  import stringifyAttributes from 'stringify-attributes';
2
- import htmlTags from 'html-tags/void.js';
2
+ import {voidHtmlTags as voidHtmlTagsArray} from 'html-tags';
3
3
  import {htmlEscape} from 'escape-goat';
4
4
 
5
- const voidHtmlTags = new Set(htmlTags);
5
+ const voidHtmlTags = new Set(voidHtmlTagsArray);
6
6
 
7
7
  export default function createHtmlElement(
8
8
  {
9
9
  name = 'div',
10
10
  attributes = {},
11
- html = '',
11
+ html,
12
12
  text,
13
+ children,
13
14
  } = {},
14
15
  ) {
15
- if (html && text) {
16
- throw new Error('The `html` and `text` options are mutually exclusive');
16
+ const hasHtml = html !== undefined;
17
+ const hasText = text !== undefined;
18
+ const hasChildren = children !== undefined;
19
+
20
+ if ([hasHtml, hasText, hasChildren].filter(Boolean).length > 1) {
21
+ throw new Error('The `html`, `text`, and `children` options are mutually exclusive');
22
+ }
23
+
24
+ if (hasChildren && !Array.isArray(children)) {
25
+ throw new TypeError('The `children` option must be an array');
26
+ }
27
+
28
+ let content = '';
29
+
30
+ if (hasChildren) {
31
+ content = children.map(child => {
32
+ if (typeof child === 'string') {
33
+ return htmlEscape(child);
34
+ }
35
+
36
+ if (typeof child === 'object' && child !== null && !Array.isArray(child)) {
37
+ return createHtmlElement(child);
38
+ }
39
+
40
+ throw new TypeError('Children must be strings or objects');
41
+ }).join('');
42
+ } else if (hasText) {
43
+ content = htmlEscape(text);
44
+ } else if (hasHtml) {
45
+ content = html;
17
46
  }
18
47
 
19
- const content = text ? htmlEscape(text) : html;
20
48
  let result = `<${name}${stringifyAttributes(attributes)}>`;
21
49
 
22
50
  if (!voidHtmlTags.has(name)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-html-element",
3
- "version": "4.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "Create a HTML element string",
5
5
  "license": "MIT",
6
6
  "repository": "sindresorhus/create-html-element",
@@ -11,9 +11,13 @@
11
11
  "url": "https://sindresorhus.com"
12
12
  },
13
13
  "type": "module",
14
- "exports": "./index.js",
14
+ "exports": {
15
+ "types": "./index.d.ts",
16
+ "default": "./index.js"
17
+ },
18
+ "sideEffects": false,
15
19
  "engines": {
16
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
20
+ "node": "^18.20.0 || >=20.10.0"
17
21
  },
18
22
  "scripts": {
19
23
  "test": "xo && ava && tsd"
@@ -33,13 +37,13 @@
33
37
  ],
34
38
  "dependencies": {
35
39
  "escape-goat": "^4.0.0",
36
- "html-tags": "^3.1.0",
37
- "stringify-attributes": "^3.0.0",
38
- "type-fest": "^2.5.0"
40
+ "html-tags": "^4.0.0",
41
+ "stringify-attributes": "^4.0.0",
42
+ "type-fest": "^4.27.0"
39
43
  },
40
44
  "devDependencies": {
41
- "ava": "^3.15.0",
42
- "tsd": "^0.18.0",
43
- "xo": "^0.45.0"
45
+ "ava": "^6.2.0",
46
+ "tsd": "^0.31.2",
47
+ "xo": "^0.59.3"
44
48
  }
45
49
  }
package/readme.md CHANGED
@@ -58,13 +58,45 @@ HTML tag attributes.
58
58
 
59
59
  HTML tag value in unescaped HTML.
60
60
 
61
- This option is mutually exclusive with the `text` option.
61
+ This option is mutually exclusive with the `text` and `children` options.
62
62
 
63
63
  ##### text
64
64
 
65
65
  HTML tag value in escaped HTML.
66
66
 
67
- This option is mutually exclusive with the `html` option.
67
+ This option is mutually exclusive with the `html` and `children` options.
68
+
69
+ ##### children
70
+
71
+ Type: `Array<string|object>`
72
+
73
+ HTML tag children.
74
+
75
+ Strings are escaped, objects are passed to `createHtmlElement`.
76
+
77
+ This option is mutually exclusive with the `html` and `text` options.
78
+
79
+ ```js
80
+ import createHtmlElement from 'create-html-element';
81
+
82
+ createHtmlElement({
83
+ name: 'div',
84
+ children: [
85
+ '<unsafe>',
86
+ {
87
+ name: 'iframe',
88
+ attributes: {
89
+ src: 'https://example.com'
90
+ }
91
+ },
92
+ {
93
+ name: 'span',
94
+ text: 'Label here <em>plz</em>'
95
+ }
96
+ ]
97
+ });
98
+ //=> '<div>&lt;unsafe&gt;<iframe src="https://example.com"></iframe><span>Label here &lt;em&gt;plz&lt;/em&gt;</span></div>'
99
+ ```
68
100
 
69
101
  ## Related
70
102