@teleporthq/teleport-project-generator-html 0.44.11 → 0.44.15

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.
@@ -0,0 +1,167 @@
1
+ import {
2
+ FileType,
3
+ ProjectUIDL,
4
+ UIDLConditionalNode,
5
+ UIDLElementNode,
6
+ UIDLElementNodeProjectReferencedStyle,
7
+ } from '@teleporthq/teleport-types'
8
+ import uidlSample from '../../../../examples/uidl-samples/component-variants.json'
9
+ import { createHTMLProjectGenerator, pluginCloneGlobals, pluginHomeReplace } from '../../src'
10
+ import HTMLTemplate from '../../src/project-template'
11
+
12
+ /**
13
+ * A button component with four looks: `btn` always, plus `btn-<look>` while
14
+ * the `buttonType` prop (default "primary") names it, and `btn-full` while the
15
+ * boolean `fullWidth` prop is true. The HTML export has no runtime props, so
16
+ * every placed instance must leave the build with its own static class list.
17
+ */
18
+ const homePage = async (uidl: ProjectUIDL): Promise<string> => {
19
+ const generator = createHTMLProjectGenerator()
20
+ generator.addPlugin(pluginHomeReplace)
21
+ generator.addPlugin(pluginCloneGlobals)
22
+ const { files } = await generator.generateProject(uidl, HTMLTemplate)
23
+ return (
24
+ files.find((file) => file.name === 'index' && file.fileType === FileType.HTML)?.content ?? ''
25
+ )
26
+ }
27
+
28
+ const buttonsByLabel = async (uidl: ProjectUIDL): Promise<Record<string, string>> => {
29
+ const page = await homePage(uidl)
30
+ const button = /<button\b[^>]*>\s*<span>([^<]*)<\/span>([\s\S]*?)<\/button>/g
31
+ const contents: Record<string, string> = {}
32
+ for (let match = button.exec(page); match; match = button.exec(page)) {
33
+ contents[match[1]] = match[2]
34
+ }
35
+ return contents
36
+ }
37
+
38
+ const classesByLabel = async (uidl: ProjectUIDL): Promise<Record<string, string>> => {
39
+ const page = await homePage(uidl)
40
+ const button = /<button\s+class="([^"]*)"[^>]*>\s*<span>([^<]*)<\/span>/g
41
+ const classes: Record<string, string> = {}
42
+ for (let match = button.exec(page); match; match = button.exec(page)) {
43
+ classes[match[2]] = match[1].replace(/\s+/g, ' ')
44
+ }
45
+ return classes
46
+ }
47
+
48
+ const fixture = () => JSON.parse(JSON.stringify(uidlSample)) as ProjectUIDL
49
+
50
+ const homeOf = (uidl: ProjectUIDL) => {
51
+ const home = (uidl.root.node.content.children[0] as UIDLConditionalNode).content.node
52
+ if (home.type !== 'element') {
53
+ throw new Error('fixture drifted: Home is not an element')
54
+ }
55
+ return home
56
+ }
57
+
58
+ const placeButton = (uidl: ProjectUIDL, key: string, attrs: Record<string, unknown>) =>
59
+ homeOf(uidl).content.children.push({
60
+ type: 'element',
61
+ content: {
62
+ elementType: 'ActionButton',
63
+ semanticType: 'ActionButton',
64
+ key,
65
+ name: key,
66
+ dependency: { type: 'local' },
67
+ attrs: Object.fromEntries(
68
+ Object.entries(attrs).map(([name, content]) => [name, { type: 'static', content }])
69
+ ),
70
+ children: [],
71
+ },
72
+ } as UIDLElementNode)
73
+
74
+ const classWhen = (
75
+ referenceId: string,
76
+ propId: string,
77
+ operands: string[]
78
+ ): UIDLElementNodeProjectReferencedStyle => ({
79
+ type: 'style-map',
80
+ content: {
81
+ mapType: 'project-referenced',
82
+ referenceId,
83
+ condition: {
84
+ reference: { type: 'dynamic', content: { referenceType: 'prop', id: propId } },
85
+ expression: { conditions: operands.map((operand) => ({ operation: '===', operand })) },
86
+ },
87
+ },
88
+ })
89
+
90
+ describe('Component variants in the HTML export', () => {
91
+ it('resolves every instance to the base class and exactly its own look', async () => {
92
+ expect(await classesByLabel(fixture())).toEqual({
93
+ Primary: 'btn btn-primary',
94
+ Secondary: 'btn btn-secondary',
95
+ Outline: 'btn btn-outline',
96
+ Link: 'btn btn-link',
97
+ Unset: 'btn btn-primary',
98
+ 'Full width': 'btn btn-outline btn-full',
99
+ 'Not full width': 'btn btn-primary',
100
+ })
101
+ })
102
+
103
+ it('builds a look without a default, a look holding quotes, and dangling conditions', async () => {
104
+ const uidl = fixture()
105
+ const actionButton = uidl.components.ActionButton
106
+ delete actionButton.propDefinitions.buttonType.defaultValue
107
+ const { referencedStyles } = actionButton.node.content
108
+ referencedStyles.quoted = classWhen('btn-full', 'buttonType', ['say "hi"'])
109
+ referencedStyles.deletedProp = classWhen('btn-link', 'removedProp', ['x'])
110
+ referencedStyles.noRule = classWhen('btn-secondary', 'buttonType', [])
111
+ placeButton(uidl, 'quotedButton', { buttonType: 'say "hi"', label: 'Quoted' })
112
+
113
+ expect(await classesByLabel(uidl)).toEqual({
114
+ Primary: 'btn btn-primary',
115
+ Secondary: 'btn btn-secondary',
116
+ Outline: 'btn btn-outline',
117
+ Link: 'btn btn-link',
118
+ Unset: 'btn',
119
+ 'Full width': 'btn btn-outline btn-full',
120
+ 'Not full width': 'btn',
121
+ Quoted: 'btn btn-full',
122
+ })
123
+ })
124
+
125
+ it('shows an element bound to a number prop whose rule stores the number as text', async () => {
126
+ const uidl = fixture()
127
+ const actionButton = uidl.components.ActionButton
128
+ actionButton.propDefinitions.count = { type: 'number', defaultValue: 0 }
129
+ actionButton.node.content.children.push({
130
+ type: 'conditional',
131
+ content: {
132
+ reference: { type: 'dynamic', content: { referenceType: 'prop', id: 'count' } },
133
+ condition: { conditions: [{ operation: '===', operand: '2' }] },
134
+ node: {
135
+ type: 'element',
136
+ content: {
137
+ elementType: 'text',
138
+ key: 'two-badge',
139
+ children: [{ type: 'static', content: 'Two' }],
140
+ },
141
+ },
142
+ },
143
+ } as UIDLConditionalNode)
144
+ placeButton(uidl, 'countTwoButton', { count: 2, label: 'Count two' })
145
+ placeButton(uidl, 'countThreeButton', { count: 3, label: 'Count three' })
146
+
147
+ const buttons = await buttonsByLabel(uidl)
148
+ expect(buttons['Count two']).toContain('Two')
149
+ expect(buttons['Count three']).not.toContain('Two')
150
+ expect(buttons.Primary).not.toContain('Two')
151
+ })
152
+
153
+ it('applies a class on a number prop whose default and rule both store the number as text', async () => {
154
+ const uidl = fixture()
155
+ uidl.root.styleSetDefinitions['btn-size-two'] = uidl.root.styleSetDefinitions['btn-full']
156
+ const actionButton = uidl.components.ActionButton
157
+ actionButton.propDefinitions.size = { type: 'number', defaultValue: '2' }
158
+ actionButton.node.content.referencedStyles.sizeTwo = classWhen('btn-size-two', 'size', ['2'])
159
+ placeButton(uidl, 'sizeThreeButton', { size: 3, label: 'Size three' })
160
+ placeButton(uidl, 'sizeTwoTextButton', { size: '2', label: 'Size two as text' })
161
+
162
+ const classes = await classesByLabel(uidl)
163
+ expect(classes.Primary).toBe('btn btn-primary btn-size-two')
164
+ expect(classes['Size two as text']).toBe('btn btn-primary btn-size-two')
165
+ expect(classes['Size three']).toBe('btn btn-primary')
166
+ })
167
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teleporthq/teleport-project-generator-html",
3
- "version": "0.44.11",
3
+ "version": "0.44.15",
4
4
  "description": "Project generator for generate plain html files",
5
5
  "author": "teleportHQ",
6
6
  "license": "MIT",
@@ -24,15 +24,15 @@
24
24
  "build": "tsc -p tsconfig.json && tsc -p tsconfig.json --module commonjs --outDir dist/cjs"
25
25
  },
26
26
  "dependencies": {
27
- "@teleporthq/teleport-component-generator": "^0.44.11",
28
- "@teleporthq/teleport-component-generator-html": "^0.44.11",
29
- "@teleporthq/teleport-plugin-css": "^0.44.11",
27
+ "@teleporthq/teleport-component-generator": "^0.44.15",
28
+ "@teleporthq/teleport-component-generator-html": "^0.44.15",
29
+ "@teleporthq/teleport-plugin-css": "^0.44.15",
30
30
  "@teleporthq/teleport-postprocessor-prettier-html": "^0.44.11",
31
- "@teleporthq/teleport-project-generator": "^0.44.11",
31
+ "@teleporthq/teleport-project-generator": "^0.44.15",
32
32
  "@teleporthq/teleport-shared": "^0.44.11",
33
33
  "@teleporthq/teleport-types": "^0.44.11",
34
34
  "cheerio": "^1.0.0-rc.12",
35
35
  "path-browserify": "^1.0.1"
36
36
  },
37
- "gitHead": "1947ff6b13b1b35ece621e04d28507185a3220ff"
37
+ "gitHead": "dbf1f4bff95181c3e2394634cf659af73d3ed279"
38
38
  }