@nordcraft/core 1.0.76 → 1.0.78
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/dist/api/ToddleApiV2.d.ts +1 -1
- package/dist/api/apiTypes.d.ts +1 -1
- package/dist/component/component.types.d.ts +7 -0
- package/dist/component/component.types.js.map +1 -1
- package/dist/component/schemas/zod-schemas.js +4 -0
- package/dist/component/schemas/zod-schemas.js.map +1 -1
- package/dist/styling/customProperty.d.ts +4 -0
- package/dist/styling/customProperty.js +13 -5
- package/dist/styling/customProperty.js.map +1 -1
- package/dist/styling/style.css.d.ts +3 -1
- package/dist/styling/style.css.js +124 -128
- package/dist/styling/style.css.js.map +1 -1
- package/dist/styling/theme.const.d.ts +2 -0
- package/dist/styling/theme.const.js +2 -0
- package/dist/styling/theme.const.js.map +1 -1
- package/dist/styling/theme.d.ts +1 -1
- package/dist/styling/theme.js +3 -3
- package/dist/styling/theme.js.map +1 -1
- package/dist/styling/variantSelector.d.ts +1 -8
- package/dist/styling/variantSelector.js.map +1 -1
- package/package.json +6 -1
- package/src/api/apiTypes.ts +1 -1
- package/src/component/component.types.ts +8 -0
- package/src/component/schemas/zod-schemas.ts +4 -0
- package/src/styling/customProperty.ts +31 -7
- package/src/styling/style.css.test.ts +929 -0
- package/src/styling/style.css.ts +148 -152
- package/src/styling/theme.const.ts +3 -0
- package/src/styling/theme.test.ts +4 -4
- package/src/styling/theme.ts +4 -4
- package/src/styling/variantSelector.ts +1 -7
package/src/styling/style.css.ts
CHANGED
|
@@ -22,9 +22,9 @@ const LEGACY_BREAKPOINTS = {
|
|
|
22
22
|
export function kebabCase(string: string) {
|
|
23
23
|
return string
|
|
24
24
|
.split('')
|
|
25
|
-
.map((char) => {
|
|
25
|
+
.map((char, index) => {
|
|
26
26
|
return 'ABCDEFGHIJKLMNOPQRSTYVWXYZ'.includes(char)
|
|
27
|
-
? '-' + char.toLocaleLowerCase()
|
|
27
|
+
? (index === 0 ? '' : '-') + char.toLocaleLowerCase()
|
|
28
28
|
: char
|
|
29
29
|
})
|
|
30
30
|
.join('')
|
|
@@ -68,6 +68,150 @@ const SIZE_PROPERTIES = new Set([
|
|
|
68
68
|
'outline-width',
|
|
69
69
|
])
|
|
70
70
|
|
|
71
|
+
export const styleToCss = (style: NodeStyleModel) => {
|
|
72
|
+
return Object.entries(style)
|
|
73
|
+
.map(([property, value]) => {
|
|
74
|
+
if (!isDefined(value)) {
|
|
75
|
+
// ignore undefined/null values
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
const propertyName = kebabCase(property)
|
|
79
|
+
const propertyValue =
|
|
80
|
+
String(Number(value)) === String(value) &&
|
|
81
|
+
SIZE_PROPERTIES.has(propertyName)
|
|
82
|
+
? `${Number(value) * 4}px`
|
|
83
|
+
: value
|
|
84
|
+
return `${propertyName}:${propertyValue};`
|
|
85
|
+
})
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
.join('\n ')
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const getNodeStyles = (
|
|
91
|
+
node: ElementNodeModel | ComponentNodeModel,
|
|
92
|
+
classHash: string,
|
|
93
|
+
animationHashes: Set<string> = new Set(),
|
|
94
|
+
) => {
|
|
95
|
+
try {
|
|
96
|
+
const style = omitKeys(node.style ?? {}, [
|
|
97
|
+
'variants',
|
|
98
|
+
'breakpoints',
|
|
99
|
+
'shadows',
|
|
100
|
+
])
|
|
101
|
+
const styleVariants =
|
|
102
|
+
node.variants ??
|
|
103
|
+
// Support for old style variants stored inside style object
|
|
104
|
+
// Once we have better versioning options, this should be removed
|
|
105
|
+
(node.style?.variants as any as StyleVariant[])
|
|
106
|
+
const renderVariant = (
|
|
107
|
+
selector: string,
|
|
108
|
+
style: NodeStyleModel,
|
|
109
|
+
options?: Nullable<{ startingStyle?: Nullable<boolean> }>,
|
|
110
|
+
) => {
|
|
111
|
+
const scrollbarStyles = Object.entries(style).filter(
|
|
112
|
+
([key]) => key === 'scrollbar-width',
|
|
113
|
+
)
|
|
114
|
+
// If selectorCss is empty, we don't need to render the selector
|
|
115
|
+
let styles = styleToCss(style)
|
|
116
|
+
if (options?.startingStyle) {
|
|
117
|
+
styles = `
|
|
118
|
+
@starting-style {
|
|
119
|
+
${styles}
|
|
120
|
+
}`
|
|
121
|
+
}
|
|
122
|
+
const scrollbarCSS =
|
|
123
|
+
scrollbarStyles.length > 0
|
|
124
|
+
? `
|
|
125
|
+
|
|
126
|
+
${selector}::-webkit-scrollbar {
|
|
127
|
+
${scrollbarStyles
|
|
128
|
+
.map(([_, value]) => {
|
|
129
|
+
switch (value) {
|
|
130
|
+
case 'none':
|
|
131
|
+
return 'width: 0;'
|
|
132
|
+
case 'thinn':
|
|
133
|
+
case 'thin':
|
|
134
|
+
return 'width: 4px;'
|
|
135
|
+
default:
|
|
136
|
+
return ''
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.join('\n')}
|
|
140
|
+
}`
|
|
141
|
+
: ''
|
|
142
|
+
const stylesCSS =
|
|
143
|
+
styles.length > 0
|
|
144
|
+
? `
|
|
145
|
+
|
|
146
|
+
${selector} {
|
|
147
|
+
${styles}
|
|
148
|
+
}`
|
|
149
|
+
: ''
|
|
150
|
+
return stylesCSS + scrollbarCSS
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const variantsCSS = (styleVariants ?? [])
|
|
154
|
+
.map((variant) => {
|
|
155
|
+
const renderedVariant = renderVariant(
|
|
156
|
+
`.${classHash}${variantSelector(variant)}`,
|
|
157
|
+
variant.style,
|
|
158
|
+
{
|
|
159
|
+
startingStyle: variant.startingStyle,
|
|
160
|
+
},
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if (variant.mediaQuery) {
|
|
164
|
+
return `
|
|
165
|
+
|
|
166
|
+
@media (${Object.entries(variant.mediaQuery)
|
|
167
|
+
.filter(([_, value]) => value !== null && value !== undefined)
|
|
168
|
+
.map(([key, value]) => `${key}: ${value}`)
|
|
169
|
+
.join(') and (')}) {${renderedVariant}
|
|
170
|
+
}`
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (variant.breakpoint) {
|
|
174
|
+
return `
|
|
175
|
+
|
|
176
|
+
@media (min-width: ${LEGACY_BREAKPOINTS[variant.breakpoint]}px) {${renderedVariant}
|
|
177
|
+
}`
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return renderedVariant
|
|
181
|
+
})
|
|
182
|
+
.join('')
|
|
183
|
+
const animationsCSS = node.animations
|
|
184
|
+
? Object.entries(node.animations)
|
|
185
|
+
.map(([animationName, keyframes]) => {
|
|
186
|
+
// Animation names are stored by their hash, so no need to render them more than once.
|
|
187
|
+
if (animationHashes.has(animationName)) {
|
|
188
|
+
return ''
|
|
189
|
+
}
|
|
190
|
+
animationHashes.add(animationName)
|
|
191
|
+
return `
|
|
192
|
+
|
|
193
|
+
@keyframes ${animationName} {${Object.values(keyframes)
|
|
194
|
+
.sort((a, b) => a.position - b.position)
|
|
195
|
+
.map(({ key, position, value }) => {
|
|
196
|
+
return `
|
|
197
|
+
${position * 100}% {
|
|
198
|
+
${key}: ${value};
|
|
199
|
+
}`
|
|
200
|
+
})
|
|
201
|
+
.join('\n')}
|
|
202
|
+
}`
|
|
203
|
+
})
|
|
204
|
+
.join('\n')
|
|
205
|
+
: ''
|
|
206
|
+
|
|
207
|
+
return renderVariant('.' + classHash, style) + variantsCSS + animationsCSS
|
|
208
|
+
} catch (e) {
|
|
209
|
+
// eslint-disable-next-line no-console
|
|
210
|
+
console.error(e)
|
|
211
|
+
return ''
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
71
215
|
export const createStylesheet = (
|
|
72
216
|
root: Component,
|
|
73
217
|
components: Component[],
|
|
@@ -109,155 +253,6 @@ export const createStylesheet = (
|
|
|
109
253
|
),
|
|
110
254
|
options,
|
|
111
255
|
)
|
|
112
|
-
const styleToCss = (style: NodeStyleModel) => {
|
|
113
|
-
return Object.entries(style)
|
|
114
|
-
.map(([property, value]) => {
|
|
115
|
-
if (!isDefined(value)) {
|
|
116
|
-
// ignore undefined/null values
|
|
117
|
-
return
|
|
118
|
-
}
|
|
119
|
-
const propertyName = kebabCase(property)
|
|
120
|
-
const propertyValue =
|
|
121
|
-
String(Number(value)) === String(value) &&
|
|
122
|
-
SIZE_PROPERTIES.has(propertyName)
|
|
123
|
-
? `${Number(value) * 4}px`
|
|
124
|
-
: value
|
|
125
|
-
return `${propertyName}:${propertyValue};`
|
|
126
|
-
})
|
|
127
|
-
.filter(Boolean)
|
|
128
|
-
.join('\n ')
|
|
129
|
-
}
|
|
130
|
-
const getNodeStyles = (
|
|
131
|
-
node: ElementNodeModel | ComponentNodeModel,
|
|
132
|
-
classHash: string,
|
|
133
|
-
) => {
|
|
134
|
-
try {
|
|
135
|
-
const style = omitKeys(node.style ?? {}, [
|
|
136
|
-
'variants',
|
|
137
|
-
'breakpoints',
|
|
138
|
-
'shadows',
|
|
139
|
-
])
|
|
140
|
-
const styleVariants =
|
|
141
|
-
node.variants ??
|
|
142
|
-
// Support for old style variants stored inside style object
|
|
143
|
-
// Once we have better versioning options, this should be removed
|
|
144
|
-
(node.style?.variants as any as StyleVariant[])
|
|
145
|
-
const renderVariant = (
|
|
146
|
-
selector: string,
|
|
147
|
-
style: NodeStyleModel,
|
|
148
|
-
options?: Nullable<{ startingStyle?: Nullable<boolean> }>,
|
|
149
|
-
) => {
|
|
150
|
-
const scrollbarStyles = Object.entries(style).filter(
|
|
151
|
-
([key]) => key === 'scrollbar-width',
|
|
152
|
-
)
|
|
153
|
-
// If selectorCss is empty, we don't need to render the selector
|
|
154
|
-
let styles = styleToCss(style)
|
|
155
|
-
if (options?.startingStyle) {
|
|
156
|
-
styles = `@starting-style {
|
|
157
|
-
${styles}
|
|
158
|
-
}`
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return `
|
|
162
|
-
${
|
|
163
|
-
styles.length > 0
|
|
164
|
-
? `${selector} {
|
|
165
|
-
${styles}
|
|
166
|
-
}`
|
|
167
|
-
: ''
|
|
168
|
-
}
|
|
169
|
-
${
|
|
170
|
-
scrollbarStyles.length > 0
|
|
171
|
-
? `
|
|
172
|
-
${selector}::-webkit-scrollbar {
|
|
173
|
-
${scrollbarStyles
|
|
174
|
-
.map(([_, value]) => {
|
|
175
|
-
switch (value) {
|
|
176
|
-
case 'none':
|
|
177
|
-
return 'width: 0;'
|
|
178
|
-
case 'thinn':
|
|
179
|
-
case 'thin':
|
|
180
|
-
return 'width: 4px;'
|
|
181
|
-
default:
|
|
182
|
-
return ''
|
|
183
|
-
}
|
|
184
|
-
})
|
|
185
|
-
.join('\n')}
|
|
186
|
-
}
|
|
187
|
-
`
|
|
188
|
-
: ''
|
|
189
|
-
}
|
|
190
|
-
`
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return `
|
|
194
|
-
${renderVariant('.' + classHash, style)}
|
|
195
|
-
${(styleVariants ?? [])
|
|
196
|
-
.map((variant) => {
|
|
197
|
-
const renderedVariant = renderVariant(
|
|
198
|
-
`.${classHash}${variantSelector(variant)}`,
|
|
199
|
-
variant.style,
|
|
200
|
-
{
|
|
201
|
-
startingStyle: variant.startingStyle,
|
|
202
|
-
},
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
if (variant.mediaQuery) {
|
|
206
|
-
return `
|
|
207
|
-
@media (${Object.entries(variant.mediaQuery)
|
|
208
|
-
.map(([key, value]) => `${key}: ${value}`)
|
|
209
|
-
.filter(Boolean)
|
|
210
|
-
.join(') and (')}) {
|
|
211
|
-
${renderedVariant}
|
|
212
|
-
}
|
|
213
|
-
`
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (variant.breakpoint) {
|
|
217
|
-
return `
|
|
218
|
-
@media (min-width: ${LEGACY_BREAKPOINTS[variant.breakpoint]}px) {
|
|
219
|
-
${renderedVariant}
|
|
220
|
-
}
|
|
221
|
-
`
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
return renderedVariant
|
|
225
|
-
})
|
|
226
|
-
.join('\n')}
|
|
227
|
-
${
|
|
228
|
-
node.animations
|
|
229
|
-
? Object.entries(node.animations)
|
|
230
|
-
.map(([animationName, keyframes]) => {
|
|
231
|
-
// Animation names are stored by their hash, so no need to render them more than once.
|
|
232
|
-
if (animationHashes.has(animationName)) {
|
|
233
|
-
return ''
|
|
234
|
-
}
|
|
235
|
-
animationHashes.add(animationName)
|
|
236
|
-
return `
|
|
237
|
-
@keyframes ${animationName} {
|
|
238
|
-
${Object.values(keyframes)
|
|
239
|
-
.sort((a, b) => a.position - b.position)
|
|
240
|
-
.map(({ key, position, value }) => {
|
|
241
|
-
return `
|
|
242
|
-
${position * 100}% {
|
|
243
|
-
${key}: ${value};
|
|
244
|
-
}
|
|
245
|
-
`
|
|
246
|
-
})
|
|
247
|
-
.join('\n')}
|
|
248
|
-
}
|
|
249
|
-
`
|
|
250
|
-
})
|
|
251
|
-
.join('\n')
|
|
252
|
-
: ''
|
|
253
|
-
}
|
|
254
|
-
`
|
|
255
|
-
} catch (e) {
|
|
256
|
-
// eslint-disable-next-line no-console
|
|
257
|
-
console.error(e)
|
|
258
|
-
return ''
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
256
|
|
|
262
257
|
// Make sure that CSS for dependencies are rendered first so that instance styles can override
|
|
263
258
|
const visitedComponents = new Set<string>()
|
|
@@ -288,6 +283,7 @@ ${selector}::-webkit-scrollbar {
|
|
|
288
283
|
stylesheet += getNodeStyles(
|
|
289
284
|
node as any,
|
|
290
285
|
toValidClassName(`${component.name}:${id}`, true),
|
|
286
|
+
animationHashes,
|
|
291
287
|
)
|
|
292
288
|
|
|
293
289
|
return
|
|
@@ -301,7 +297,7 @@ ${selector}::-webkit-scrollbar {
|
|
|
301
297
|
return ''
|
|
302
298
|
}
|
|
303
299
|
hashes.add(classHash)
|
|
304
|
-
stylesheet += getNodeStyles(node as any, classHash)
|
|
300
|
+
stylesheet += getNodeStyles(node as any, classHash, animationHashes)
|
|
305
301
|
})
|
|
306
302
|
}
|
|
307
303
|
insertComponentStyles(root)
|
|
@@ -2,6 +2,9 @@ import type { OldTheme } from './theme'
|
|
|
2
2
|
|
|
3
3
|
export const CUSTOM_PROPERTIES_STYLESHEET_ID = 'nc-custom-properties'
|
|
4
4
|
|
|
5
|
+
export const THEME_DATA_ATTRIBUTE = 'data-nc-theme'
|
|
6
|
+
export const THEME_COOKIE_NAME = 'nc-theme'
|
|
7
|
+
|
|
5
8
|
export const RESET_STYLES = `
|
|
6
9
|
@layer reset {
|
|
7
10
|
html {
|
|
@@ -38,11 +38,11 @@ describe('renderThemeValues()', () => {
|
|
|
38
38
|
}
|
|
39
39
|
expect(
|
|
40
40
|
renderThemeValues(
|
|
41
|
-
'[data-theme="my-theme"]',
|
|
41
|
+
'[data-nc-theme="my-theme"]',
|
|
42
42
|
getThemeEntries(theme, 'my-theme'),
|
|
43
43
|
),
|
|
44
44
|
).toMatchInlineSnapshot(`
|
|
45
|
-
"[data-theme="my-theme"] {
|
|
45
|
+
"[data-nc-theme="my-theme"] {
|
|
46
46
|
--my-color: rebeccapurple;
|
|
47
47
|
--my-third-prop: var(--my-color);
|
|
48
48
|
}"
|
|
@@ -126,11 +126,11 @@ describe('getThemeCss()', () => {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
[data-theme~="my-theme"] {
|
|
129
|
+
[data-nc-theme~="my-theme"] {
|
|
130
130
|
--my-color: rebeccapurple;
|
|
131
131
|
--my-third-prop: var(--my-color);
|
|
132
132
|
}
|
|
133
|
-
[data-theme~="super-dark"] {
|
|
133
|
+
[data-nc-theme~="super-dark"] {
|
|
134
134
|
--my-color: black;
|
|
135
135
|
}
|
|
136
136
|
|
package/src/styling/theme.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { CustomPropertyName } from '../component/component.types'
|
|
|
2
2
|
import type { Nullable } from '../types'
|
|
3
3
|
import { isDefined } from '../utils/util'
|
|
4
4
|
import { renderSyntaxDefinition, type CssSyntaxNode } from './customProperty'
|
|
5
|
-
import { RESET_STYLES } from './theme.const'
|
|
5
|
+
import { RESET_STYLES, THEME_DATA_ATTRIBUTE } from './theme.const'
|
|
6
6
|
|
|
7
7
|
export interface ThemeOptions {
|
|
8
8
|
includeResetStyle: boolean
|
|
@@ -34,7 +34,7 @@ export type FontFamily = {
|
|
|
34
34
|
family: string
|
|
35
35
|
provider: 'google' | 'upload'
|
|
36
36
|
type: 'serif' | 'sans-serif' | 'monospace' | 'cursive'
|
|
37
|
-
variants
|
|
37
|
+
variants?: Array<{
|
|
38
38
|
name: string
|
|
39
39
|
weight:
|
|
40
40
|
| '100'
|
|
@@ -147,7 +147,7 @@ export const getThemeCss = (
|
|
|
147
147
|
${Object.entries(themeV2.themes ?? {})
|
|
148
148
|
.map(([key, _t]) =>
|
|
149
149
|
renderThemeValues(
|
|
150
|
-
`[
|
|
150
|
+
`[${THEME_DATA_ATTRIBUTE}~="${key}"]`,
|
|
151
151
|
getThemeEntries(themeV2, key),
|
|
152
152
|
),
|
|
153
153
|
)
|
|
@@ -165,7 +165,7 @@ ${options.includeResetStyle ? RESET_STYLES : ''}
|
|
|
165
165
|
.flat()
|
|
166
166
|
.map(
|
|
167
167
|
(font) => `
|
|
168
|
-
${font.variants
|
|
168
|
+
${(font.variants ?? [])
|
|
169
169
|
.map(
|
|
170
170
|
(variant) => `
|
|
171
171
|
@font-face {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CustomProperty,
|
|
3
3
|
CustomPropertyName,
|
|
4
|
+
MediaQuery,
|
|
4
5
|
NodeStyleModel,
|
|
5
6
|
} from '../component/component.types'
|
|
6
7
|
import type { Nullable } from '../types'
|
|
@@ -24,13 +25,6 @@ export type Filter =
|
|
|
24
25
|
percent: number
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
type MediaQuery = {
|
|
28
|
-
'min-width'?: Nullable<string>
|
|
29
|
-
'max-width'?: Nullable<string>
|
|
30
|
-
'min-height'?: Nullable<string>
|
|
31
|
-
'max-height'?: Nullable<string>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
28
|
export interface StyleVariant {
|
|
35
29
|
'even-child'?: Nullable<boolean>
|
|
36
30
|
'first-child'?: Nullable<boolean>
|