@teleporthq/teleport-plugin-css-modules 0.43.0-alpha.0 → 0.43.3

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/src/index.ts CHANGED
@@ -27,9 +27,12 @@ import {
27
27
  UIDLStyleMediaQueryScreenSizeCondition,
28
28
  PluginCssModules,
29
29
  HastNode,
30
+ UIDLElement,
31
+ UIDLElementNode,
30
32
  } from '@teleporthq/teleport-types'
31
33
  import { createStyleSheetPlugin } from './style-sheet'
32
34
  import { generateStyledFromStyleContent } from './utils'
35
+ import { isJSXElement } from '@teleporthq/teleport-plugin-common/dist/cjs/utils/ast-utils'
33
36
 
34
37
  interface CSSModulesConfig {
35
38
  componentChunkName?: string
@@ -104,26 +107,44 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
104
107
  (componentChunk.meta.nodesLookup as Record<string, HastNode | types.JSXElement>) || {}
105
108
  const propsPrefix = componentChunk.meta.dynamicRefPrefix.prop as string
106
109
 
107
- UIDLUtils.traverseElements(node, (element) => {
108
- const { style, key, referencedStyles, dependency, attrs = {} } = element
109
- const jsxTag = astNodesLookup[key] as types.JSXElement
110
- const classNamesToAppend: Set<types.MemberExpression | types.Identifier> = new Set()
110
+ const generateStylesForElementNode = (element: UIDLElement) => {
111
+ const {
112
+ style,
113
+ key,
114
+ referencedStyles,
115
+ dependency,
116
+ attrs = {},
117
+ elementType,
118
+ dynamicStyleBindings,
119
+ } = element
120
+ const jsxTag = astNodesLookup[key]
121
+ const classNamesToAppend: Set<
122
+ types.MemberExpression | types.Identifier | types.StringLiteral
123
+ > = new Set()
124
+ const hasDynamicBindings =
125
+ dynamicStyleBindings && Object.keys(dynamicStyleBindings).length > 0
126
+
127
+ if (!jsxTag || !isJSXElement(jsxTag)) {
128
+ return
129
+ }
111
130
 
112
131
  if (dependency?.type === 'local') {
113
132
  StyleBuilders.setPropValueForCompStyle({
114
133
  attrs,
115
- key,
116
- jsxNodesLookup: astNodesLookup,
117
- getClassName: (styleName: string) => StringUtils.camelCaseToDashCase(styleName),
134
+ root: jsxTag,
135
+ getClassName: (styleName: string) =>
136
+ StringUtils.camelCaseToDashCase(elementType + styleName),
118
137
  })
119
138
  }
120
139
 
121
- if (!jsxTag) {
140
+ if (!style && !referencedStyles && !hasDynamicBindings) {
122
141
  return
123
142
  }
124
143
 
125
- if (!style && !referencedStyles) {
126
- return
144
+ if (!key) {
145
+ throw new PluginCssModules(
146
+ 'Element node does not have a key \n' + JSON.stringify(element, null, 2)
147
+ )
127
148
  }
128
149
 
129
150
  const className = StringUtils.camelCaseToDashCase(key)
@@ -133,6 +154,8 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
133
154
  true
134
155
  )
135
156
 
157
+ let jsxInlineStyles: Record<string, unknown> | null = null
158
+
136
159
  /* Generating styles from UIDLElementNode to component style sheet */
137
160
  if (Object.keys(style || {}).length > 0) {
138
161
  const { staticStyles, dynamicStyles, tokenStyles } =
@@ -146,18 +169,28 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
146
169
  }
147
170
 
148
171
  if (Object.keys(dynamicStyles).length) {
149
- const inlineStyles = UIDLUtils.transformDynamicStyles(dynamicStyles, (styleValue) =>
172
+ jsxInlineStyles = UIDLUtils.transformDynamicStyles(dynamicStyles, (styleValue) =>
150
173
  StyleBuilders.createDynamicStyleExpression(styleValue, propsPrefix)
151
174
  )
175
+ }
176
+ }
152
177
 
153
- /* If dynamic styles are on nested-styles they are unfortunately lost,
154
- since inline style does not support that */
155
- if (Object.keys(inlineStyles).length > 0) {
156
- ASTUtils.addAttributeToJSXTag(jsxTag, 'style', inlineStyles)
157
- }
178
+ if (hasDynamicBindings) {
179
+ if (!jsxInlineStyles) {
180
+ jsxInlineStyles = {}
181
+ }
182
+ for (const [cssProperty, binding] of Object.entries(dynamicStyleBindings)) {
183
+ const camelCaseProperty = cssProperty.replace(/-([a-z])/g, (_, letter: string) =>
184
+ letter.toUpperCase()
185
+ )
186
+ jsxInlineStyles[camelCaseProperty] = StyleBuilders.createDynamicBindingExpression(binding)
158
187
  }
159
188
  }
160
189
 
190
+ if (jsxInlineStyles && Object.keys(jsxInlineStyles).length > 0) {
191
+ ASTUtils.addAttributeToJSXTag(jsxTag, 'style', jsxInlineStyles)
192
+ }
193
+
161
194
  /* Any media-styles, component-scoped styles, global style sheet styles are handled here */
162
195
  if (Object.keys(referencedStyles || {}).length > 0) {
163
196
  Object.values(referencedStyles).forEach((styleRef: UIDLElementNodeReferenceStyles) => {
@@ -194,13 +227,7 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
194
227
  case 'component-referenced': {
195
228
  const classContent = styleRef.content.content
196
229
  if (classContent.type === 'static') {
197
- classNamesToAppend.add(
198
- types.memberExpression(
199
- types.identifier(styleObjectImportName),
200
- types.identifier(`'${getClassName(String(classContent.content))}'`),
201
- true
202
- )
203
- )
230
+ classNamesToAppend.add(types.stringLiteral(String(classContent.content)))
204
231
  return
205
232
  }
206
233
 
@@ -223,8 +250,8 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
223
250
  if (!defaultPropValue) {
224
251
  return
225
252
  }
226
- /*
227
- Changing the default value of the prop.
253
+ /*
254
+ Changing the default value of the prop.
228
255
  When forceScoping is enabled the classnames change. So, we need to change the default prop too. */
229
256
  propDefinitions[classContent.content.id].defaultValue = getClassName(
230
257
  String(defaultPropValue)
@@ -253,9 +280,7 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
253
280
  isProjectStyleReferred = true
254
281
  const referedStyle = globalStyleSheet[content.referenceId]
255
282
  if (!referedStyle) {
256
- throw new PluginCssModules(
257
- `Style used from global stylesheet is missing - ${content.referenceId}`
258
- )
283
+ return
259
284
  }
260
285
  classNamesToAppend.add(
261
286
  types.memberExpression(
@@ -279,7 +304,17 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
279
304
  classAttributeName,
280
305
  Array.from(classNamesToAppend)
281
306
  )
282
- })
307
+ }
308
+
309
+ UIDLUtils.traverseElements(node, generateStylesForElementNode)
310
+ for (const prop of Object.values(propDefinitions)) {
311
+ if (prop.type === 'element' && prop.defaultValue) {
312
+ UIDLUtils.traverseElements(
313
+ prop.defaultValue as UIDLElementNode,
314
+ generateStylesForElementNode
315
+ )
316
+ }
317
+ }
283
318
 
284
319
  /* Generating component scoped styles */
285
320
  if (Object.keys(componentStyleSheet).length > 0) {
@@ -287,7 +322,7 @@ export const createCSSModulesPlugin: ComponentPluginFactory<CSSModulesConfig> =
287
322
  componentStyleSheet,
288
323
  cssClasses,
289
324
  mediaStylesMap,
290
- (styleId: string) => StringUtils.camelCaseToDashCase(styleId)
325
+ (styleName: string) => StringUtils.camelCaseToDashCase(uidl.name + styleName)
291
326
  )
292
327
  }
293
328
 
@@ -6,39 +6,83 @@ import {
6
6
  FileType,
7
7
  } from '@teleporthq/teleport-types'
8
8
  import { StringUtils } from '@teleporthq/teleport-shared'
9
+ import { relative, join } from 'path'
10
+
9
11
  interface StyleSheetPlugin {
10
12
  fileName?: string
11
13
  moduleExtension?: boolean
14
+ relativeFontPath?: boolean
12
15
  }
13
16
 
14
17
  const defaultConfig = {
15
18
  fileName: 'style',
16
19
  moduleExtension: false,
20
+ relativeFontPath: false,
17
21
  }
18
22
 
19
23
  export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> = (config) => {
20
- const { fileName, moduleExtension } = {
24
+ const { fileName, moduleExtension, relativeFontPath } = {
21
25
  ...defaultConfig,
22
26
  ...config,
23
27
  }
24
28
 
25
29
  const styleSheetPlugin: ComponentPlugin = async (structure) => {
26
- const { uidl, chunks } = structure
30
+ const {
31
+ uidl,
32
+ chunks,
33
+ options: { assets },
34
+ } = structure
27
35
  const { styleSetDefinitions = {}, designLanguage: { tokens = {} } = {} } = uidl
36
+ const {
37
+ localFonts = [],
38
+ fontsFolder,
39
+ identifier: assetIdentifier,
40
+ } = assets || { localFonts: [] }
41
+
42
+ const canSkipThePlugin =
43
+ localFonts?.length === 0 &&
44
+ Object.keys(styleSetDefinitions).length === 0 &&
45
+ Object.keys(tokens).length === 0
28
46
 
29
- if (
30
- (!styleSetDefinitions && !tokens) ||
31
- (Object.keys(styleSetDefinitions).length === 0 && Object.keys(tokens).length === 0)
32
- ) {
33
- return
47
+ if (canSkipThePlugin) {
48
+ return structure
34
49
  }
35
50
 
51
+ uidl.outputOptions = uidl.outputOptions || {}
52
+ uidl.outputOptions.styleFileName = moduleExtension ? `${fileName}.module` : fileName
53
+
36
54
  const cssMap: string[] = []
37
55
  const mediaStylesMap: Record<
38
56
  string,
39
57
  Array<{ [x: string]: Record<string, string | number> }>
40
58
  > = {}
41
59
 
60
+ if (localFonts.length > 0) {
61
+ localFonts.forEach((font) => {
62
+ const properties = StyleUtils.getContentOfStyleObject(font.properties) as Record<
63
+ string,
64
+ string | number
65
+ >
66
+ const format = properties?.format ? `format('${properties.format}')` : ''
67
+ /* tslint:disable:no-string-literal */
68
+ delete properties['format']
69
+
70
+ const fontPath = relativeFontPath
71
+ ? join(
72
+ relative(join(...(uidl.outputOptions?.folderPath || [])), './'),
73
+ join(fontsFolder || '', font.path)
74
+ )
75
+ : join('/', assetIdentifier || '', 'fonts', font.path)
76
+
77
+ cssMap.push(
78
+ StyleBuilders.createFontDecleration({
79
+ ...properties,
80
+ src: `url("${fontPath}") ${format}`,
81
+ })
82
+ )
83
+ })
84
+ }
85
+
42
86
  if (Object.keys(tokens).length > 0) {
43
87
  cssMap.push(
44
88
  StyleBuilders.createCSSClassWithSelector(
@@ -65,9 +109,6 @@ export const createStyleSheetPlugin: ComponentPluginFactory<StyleSheetPlugin> =
65
109
  return structure
66
110
  }
67
111
 
68
- uidl.outputOptions = uidl.outputOptions || {}
69
- uidl.outputOptions.styleFileName = moduleExtension ? `${fileName}.module` : fileName
70
-
71
112
  chunks.push({
72
113
  name: fileName,
73
114
  type: ChunkType.STRING,