@wix/origami-transforms 0.1.40 → 0.1.42
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/cssPlugins/svg.d.ts +1 -0
- package/dist/cssPlugins/{wixVectorUrls.d.ts → wixUrls.d.ts} +1 -1
- package/dist/wrapperSideEffects.d.ts +8 -1
- package/package.json +3 -2
- package/src/cssPlugins/index.js +4 -4
- package/src/cssPlugins/shapeDividers.js +1 -1
- package/src/cssPlugins/svg.js +11 -0
- package/src/cssPlugins/wixUrls.js +90 -0
- package/src/wrapperSideEffects.js +42 -8
- package/src/cssPlugins/wixVectorUrls.js +0 -43
package/dist/cssPlugins/svg.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** @typedef {typeof checks[number]} Check */
|
|
2
2
|
/** @type {import('../transform/types.js').CssTransformPlugin<Check>} */
|
|
3
|
-
export const
|
|
3
|
+
export const wixUrlsPlugin: import("../transform/types.js").CssTransformPlugin<Check>;
|
|
4
4
|
export type Check = (typeof checks)[number];
|
|
5
5
|
declare const checks: readonly [];
|
|
6
6
|
export {};
|
|
@@ -5,7 +5,7 @@ export const COMPANION_APP: "companionApp";
|
|
|
5
5
|
* app: each service's bundle and the module that registers it, `<package name>/bundle.js` and `<package name>/index.js`. */
|
|
6
6
|
export const VIEWER_SERVICES_FOLDER: "src/site/_generated/viewer-services";
|
|
7
7
|
export function viewerServiceImport(generatedFolder: string, packageName: string): string;
|
|
8
|
-
export function wrapperSideEffectImports(sources: Iterable<string>, catalog: WrapperCatalog, generatedFolder: string): string[];
|
|
8
|
+
export function wrapperSideEffectImports(sources: Iterable<string>, catalog: WrapperCatalog, generatedFolder: string, refElements?: RefElements): string[];
|
|
9
9
|
/**
|
|
10
10
|
* the site's component catalog (`site-component-catalog.json`), by module
|
|
11
11
|
*/
|
|
@@ -23,3 +23,10 @@ export type WrapperCatalog = {
|
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* each wrapper component's ref element types, by
|
|
28
|
+
* its type, as its wrapper package's `origami.refElements` lists them
|
|
29
|
+
*/
|
|
30
|
+
export type RefElements = {
|
|
31
|
+
readonly [type: string]: readonly string[];
|
|
32
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/origami-transforms",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "Babel and PostCSS checks and transforms for Wix origami page files.",
|
|
5
5
|
"main": "./src/index.js",
|
|
6
6
|
"files": [
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@babel/core": "^7.26.0",
|
|
20
20
|
"@babel/parser": "^7.25.0",
|
|
21
21
|
"@babel/types": "^7.25.2",
|
|
22
|
+
"@wix/sdk": "^1.21.13",
|
|
22
23
|
"@wix/origami-fonts": "1.0.4",
|
|
23
24
|
"@wix/origami-system-components": "1.10.10",
|
|
24
25
|
"postcss": "^8.5.3",
|
|
@@ -75,5 +76,5 @@
|
|
|
75
76
|
},
|
|
76
77
|
"type": "module",
|
|
77
78
|
"types": "./dist/index.d.ts",
|
|
78
|
-
"falconPackageHash": "
|
|
79
|
+
"falconPackageHash": "a93543b10c8156d2dd51f02d94e447a5aaf82374b5c26370c547c8ba"
|
|
79
80
|
}
|
package/src/cssPlugins/index.js
CHANGED
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
// and layout move declarations out of the instance's rule. fonts appends the `@font-face` rules that load the Wix fonts
|
|
13
13
|
// the stylesheet names from Wix's CDN.
|
|
14
14
|
// component-position runs after mixins, so a position a mixin body sets is kept, and before layout compiles the rules.
|
|
15
|
-
// shape-dividers and wix-
|
|
16
|
-
//
|
|
15
|
+
// shape-dividers and wix-urls run last: they load the SVGs a stylesheet names from Wix's CDN in `prepare`, and write
|
|
16
|
+
// them in as data URIs; wix-urls links a regular image a `wix:image` url names from Wix's media service, resized.
|
|
17
17
|
//
|
|
18
18
|
// `@layer` needs no plugin: cascade layers have been in every browser since March 2022.
|
|
19
19
|
|
|
@@ -28,7 +28,7 @@ import { layoutPlugin } from './layout/index.js'
|
|
|
28
28
|
import { spxPlugin } from './spx/index.js'
|
|
29
29
|
import { spxThemeVariablesPlugin } from './spxThemeVariables/index.js'
|
|
30
30
|
import { stackChildrenPlugin } from './stackChildren.js'
|
|
31
|
-
import {
|
|
31
|
+
import { wixUrlsPlugin } from './wixUrls.js'
|
|
32
32
|
|
|
33
33
|
/** @type {readonly import('../transform/types.js').CssTransformPlugin<string>[]} */
|
|
34
34
|
export const cssPlugins = Object.freeze([
|
|
@@ -43,5 +43,5 @@ export const cssPlugins = Object.freeze([
|
|
|
43
43
|
spxThemeVariablesPlugin,
|
|
44
44
|
spxPlugin,
|
|
45
45
|
shapeDividersPlugin,
|
|
46
|
-
|
|
46
|
+
wixUrlsPlugin,
|
|
47
47
|
])
|
|
@@ -108,7 +108,7 @@ const checks = /** @type {const} */ ([])
|
|
|
108
108
|
export const shapeDividersPlugin = {
|
|
109
109
|
checks,
|
|
110
110
|
name: 'shape-dividers',
|
|
111
|
-
// Last, with wix-
|
|
111
|
+
// Last, with wix-urls: it only adds rules, which no other plugin needs to see, and it reads only `--height` as
|
|
112
112
|
// `var(--height)`, so spx converts that var's `--spx()` where it is declared.
|
|
113
113
|
order: 25,
|
|
114
114
|
prepare(root) {
|
package/src/cssPlugins/svg.js
CHANGED
|
@@ -88,3 +88,14 @@ export const svgDataUrl = svg => {
|
|
|
88
88
|
.replace(URL_SYMBOLS, encodeURIComponent)
|
|
89
89
|
return `url("data:image/svg+xml,${escaped}")`
|
|
90
90
|
}
|
|
91
|
+
|
|
92
|
+
const SIZE = /\s(?:width|height)="[^"]*"/g
|
|
93
|
+
|
|
94
|
+
/** The SVG drawn at `width` × `height` pixels, its drawing box stretched to that size: what a cursor image, which a
|
|
95
|
+
* browser draws at the image's own size, needs. */
|
|
96
|
+
export const sizeSvg = (svg, width, height) => {
|
|
97
|
+
const scaled = scaleSvg(svg, svgInfo(svg), 'none')
|
|
98
|
+
const tag = scaled.match(SVG_TAG)?.[0]
|
|
99
|
+
if (tag === undefined) return scaled
|
|
100
|
+
return scaled.replace(tag, tag.replace(SIZE, '').replace(/<svg/, `<svg width="${width}" height="${height}"`))
|
|
101
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Rewrites the urls a value names with Wix's own url schemes, which no browser can load:
|
|
2
|
+
//
|
|
3
|
+
// - `url(wix:vector://v1/<id>.svg)`: vector art, Image's `--maskImage` for one. A live Wix site writes it as a data
|
|
4
|
+
// URI of the SVG stretched to its drawing's box (Thunderbolt's `replaceWixUrl` and `createSvgCssVar`); this writes
|
|
5
|
+
// the same data URI in its place.
|
|
6
|
+
// - `url("wix:image://v1/<id>/<name>#originWidth=<w>&originHeight=<h>")`: an image at the size it's displayed at, a
|
|
7
|
+
// component's `cursor` for one (css-codec/style/cursor.ts). A browser draws a cursor at the image's pixel size, so
|
|
8
|
+
// the image is requested at that size: a regular image resized by Wix's media service, through @wix/sdk's media
|
|
9
|
+
// helpers, an SVG shape inlined as a data URI with that width and height (the media service doesn't resize an SVG).
|
|
10
|
+
//
|
|
11
|
+
// Only the url is rewritten: a cursor's hotspot and `auto` fallback stay as written. So does a url that can't be
|
|
12
|
+
// rewritten, with a warning. And only the CSS this stage renders is rewritten, never the stored bundle: an https
|
|
13
|
+
// cursor in style.css would be read back as plain CSS, not as the component's cursor.
|
|
14
|
+
|
|
15
|
+
import { getImageUrl, getScaledToFillImageUrl } from '@wix/sdk/media'
|
|
16
|
+
import { loadedSvg, loadSvgs, scaleSvg, sizeSvg, svgDataUrl, svgInfo } from './svg.js'
|
|
17
|
+
|
|
18
|
+
// A quoted url runs to its closing quote: a file name encoded with encodeURIComponent keeps `(`, `)` and `'`.
|
|
19
|
+
const WIX_URL = /url\(\s*(['"]?)(wix:(vector|image):\/\/v1\/(.+?))\1\s*\)/gi
|
|
20
|
+
const HAS_WIX_URL = /wix:(?:vector|image):\/\//i
|
|
21
|
+
|
|
22
|
+
const isSvg = id => id.endsWith('.svg')
|
|
23
|
+
|
|
24
|
+
/** Every wix url in the stylesheet: its scheme, its path after `v1/`, and the url itself. */
|
|
25
|
+
const wixUrls = root => {
|
|
26
|
+
const urls = []
|
|
27
|
+
root.walkDecls(declaration => {
|
|
28
|
+
for (const [, , wixUrl, scheme, path] of declaration.value.matchAll(WIX_URL)) urls.push({ scheme: scheme.toLowerCase(), path, wixUrl })
|
|
29
|
+
})
|
|
30
|
+
return urls
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The ids of the SVGs the stylesheet's wix urls name. */
|
|
34
|
+
const svgIdsIn = root => {
|
|
35
|
+
const ids = new Set()
|
|
36
|
+
for (const { scheme, path, wixUrl } of wixUrls(root)) {
|
|
37
|
+
if (scheme === 'vector') ids.add(path)
|
|
38
|
+
else {
|
|
39
|
+
const { id, width, height } = getImageUrl(wixUrl)
|
|
40
|
+
if (isSvg(id) && width && height) ids.add(id)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return ids
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The `wix:vector` url `id` as a data URI, or `url` as written when its SVG isn't loaded. */
|
|
47
|
+
const vectorUrl = (url, id, declaration, context) => {
|
|
48
|
+
const svg = loadedSvg(id)
|
|
49
|
+
if (svg === undefined) {
|
|
50
|
+
context.warn?.(declaration, `Couldn't load the SVG ${id} from Wix's CDN, so ${url} stays as written`, 'svg_not_loaded')
|
|
51
|
+
return url
|
|
52
|
+
}
|
|
53
|
+
return svgDataUrl(scaleSvg(svg, svgInfo(svg), 'none'))
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The `wix:image` url `wixUrl` as a loadable url at its size, or `url` as written when it can't be. */
|
|
57
|
+
const imageUrl = (url, wixUrl, declaration, context) => {
|
|
58
|
+
const { id, width, height } = getImageUrl(wixUrl)
|
|
59
|
+
if (!width || !height) {
|
|
60
|
+
context.warn?.(declaration, `The image ${id} has no size: ${url} doesn't end in #originWidth=<w>&originHeight=<h>, so it stays as written`)
|
|
61
|
+
return url
|
|
62
|
+
}
|
|
63
|
+
if (!isSvg(id)) return `url("${getScaledToFillImageUrl(wixUrl, width, height, {})}")`
|
|
64
|
+
const svg = loadedSvg(id)
|
|
65
|
+
if (svg === undefined) {
|
|
66
|
+
context.warn?.(declaration, `Couldn't load the SVG ${id} from Wix's CDN, so ${url} stays as written`, 'svg_not_loaded')
|
|
67
|
+
return url
|
|
68
|
+
}
|
|
69
|
+
return svgDataUrl(sizeSvg(svg, width, height))
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const checks = /** @type {const} */ ([])
|
|
73
|
+
/** @typedef {typeof checks[number]} Check */
|
|
74
|
+
|
|
75
|
+
/** @type {import('../transform/types.js').CssTransformPlugin<Check>} */
|
|
76
|
+
export const wixUrlsPlugin = {
|
|
77
|
+
checks,
|
|
78
|
+
name: 'wix-urls',
|
|
79
|
+
// Last, so a url a mixin or preset copies elsewhere is rewritten wherever it ends up.
|
|
80
|
+
order: 25,
|
|
81
|
+
prepare: root => loadSvgs(svgIdsIn(root)),
|
|
82
|
+
transform(root, context) {
|
|
83
|
+
root.walkDecls(declaration => {
|
|
84
|
+
if (!HAS_WIX_URL.test(declaration.value)) return
|
|
85
|
+
declaration.value = declaration.value.replace(WIX_URL, (url, _quote, wixUrl, scheme, path) =>
|
|
86
|
+
scheme.toLowerCase() === 'vector' ? vectorUrl(url, path, declaration, context) : imageUrl(url, wixUrl, declaration, context)
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
},
|
|
90
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// What an item's `_generated` entry imports before its structure, for the wrappers the structure imports: each
|
|
2
|
-
// component's defaults sheet, and the registration of each viewer service a companion app
|
|
3
|
-
// writes these lines, and `yarn dev` and `yarn build` rewrite them when the structure
|
|
4
|
-
// Kept free of dependencies, like `wrapperImport.js`, so the generator's bundle
|
|
2
|
+
// component's defaults sheet and its ref element types', and the registration of each viewer service a companion app
|
|
3
|
+
// provider needs. The export writes these lines, and `yarn dev` and `yarn build` rewrite them when the structure
|
|
4
|
+
// changes, so both follow one rule. Kept free of dependencies, like `wrapperImport.js`, so the generator's bundle
|
|
5
|
+
// doesn't take the transforms with it.
|
|
5
6
|
import { posix } from 'node:path'
|
|
6
7
|
import { moduleFromWrapperEntry, wrapperImport } from './wrapperImport.js'
|
|
7
8
|
|
|
@@ -20,6 +21,11 @@ export const VIEWER_SERVICES_FOLDER = 'src/site/_generated/viewer-services'
|
|
|
20
21
|
* } } }} WrapperCatalog the site's component catalog (`site-component-catalog.json`), by module
|
|
21
22
|
*/
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* @typedef {{ readonly [type: string]: readonly string[] }} RefElements each wrapper component's ref element types, by
|
|
26
|
+
* its type, as its wrapper package's `origami.refElements` lists them
|
|
27
|
+
*/
|
|
28
|
+
|
|
23
29
|
/**
|
|
24
30
|
* The module that registers a viewer service, as an item's `_generated` folder imports it.
|
|
25
31
|
* @param {string} generatedFolder the item's `_generated` folder, relative to the site app
|
|
@@ -30,26 +36,54 @@ export const viewerServiceImport = (generatedFolder, packageName) => {
|
|
|
30
36
|
return path.startsWith('.') ? path : `./${path}`
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
/**
|
|
40
|
+
* The `/css` of a component and of its ref elements' types, which its raw component renders itself (FastGallery its
|
|
41
|
+
* ExpandedGallery) and no structure imports: each ref type's before the component's, at any depth, so a ref type's
|
|
42
|
+
* sheet never comes after the sheet of the component that styles it. A ref type the catalog doesn't have (its app isn't
|
|
43
|
+
* on the site) brings nothing.
|
|
44
|
+
* @param {WrapperCatalog} catalog
|
|
45
|
+
* @param {RefElements} refElements
|
|
46
|
+
* @param {string} module
|
|
47
|
+
* @param {string} symbol
|
|
48
|
+
* @param {Set<string>} imports where the imports go, in order
|
|
49
|
+
* @param {Set<string>} seen the types already walked, so a cycle ends
|
|
50
|
+
*/
|
|
51
|
+
const addComponentCss = (catalog, refElements, module, symbol, imports, seen) => {
|
|
52
|
+
const type = `${module}.${symbol}`
|
|
53
|
+
if (!catalog[module]?.entries.components?.[symbol] || seen.has(type)) return
|
|
54
|
+
seen.add(type)
|
|
55
|
+
for (const refType of refElements[type] ?? []) {
|
|
56
|
+
const separator = refType.indexOf('.')
|
|
57
|
+
if (separator > 0) addComponentCss(catalog, refElements, refType.slice(0, separator), refType.slice(separator + 1), imports, seen)
|
|
58
|
+
}
|
|
59
|
+
imports.add(`${wrapperImport({ module, symbol })}/css`)
|
|
60
|
+
}
|
|
61
|
+
|
|
33
62
|
/**
|
|
34
63
|
* The side-effect imports of the wrappers an item's structure imports from, once each, in the structure's order: a
|
|
35
|
-
* component folder's `<folder>/css`, and a companion app provider folder's
|
|
36
|
-
* catalog symbol whose `wrapperImport` it is; a function library's
|
|
37
|
-
* nothing.
|
|
64
|
+
* component folder's `<folder>/css`, after its ref types' (`addComponentCss`), and a companion app provider folder's
|
|
65
|
+
* viewer service registrations. A folder is the catalog symbol whose `wrapperImport` it is; a function library's
|
|
66
|
+
* folder, or one the catalog doesn't have, brings nothing.
|
|
38
67
|
* @param {Iterable<string>} sources the structure's import sources
|
|
39
68
|
* @param {WrapperCatalog} catalog
|
|
40
69
|
* @param {string} generatedFolder the item's `_generated` folder, relative to the site app
|
|
70
|
+
* @param {RefElements} [refElements] the ref element types off the installed wrapper packages; the export, which runs
|
|
71
|
+
* before they are installed, has none
|
|
41
72
|
* @returns {string[]}
|
|
42
73
|
*/
|
|
43
|
-
export const wrapperSideEffectImports = (sources, catalog, generatedFolder) => {
|
|
74
|
+
export const wrapperSideEffectImports = (sources, catalog, generatedFolder, refElements = {}) => {
|
|
44
75
|
/** @type {Set<string>} */
|
|
45
76
|
const imports = new Set()
|
|
77
|
+
/** @type {Set<string>} */
|
|
78
|
+
const seen = new Set()
|
|
46
79
|
for (const source of sources) {
|
|
47
80
|
const module = moduleFromWrapperEntry(source)
|
|
48
81
|
if (!module) continue
|
|
49
82
|
const { components = {}, contextProviders = {} } = catalog[module]?.entries ?? {}
|
|
50
83
|
/** @param {string} name */
|
|
51
84
|
const isFolder = name => wrapperImport({ module, symbol: name }) === source
|
|
52
|
-
|
|
85
|
+
const symbol = Object.keys(components).find(isFolder)
|
|
86
|
+
if (symbol) addComponentCss(catalog, refElements, module, symbol, imports, seen)
|
|
53
87
|
if (module !== COMPANION_APP) continue
|
|
54
88
|
const provider = Object.keys(contextProviders).find(isFolder)
|
|
55
89
|
for (const service of (provider && contextProviders[provider].services) ?? []) {
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Inlines the vector art a value names with Wix's own url scheme, `url(wix:vector://v1/<id>.svg)`, which no browser
|
|
2
|
-
// can load: Image's `--maskImage`, for one. A live Wix site writes it as a data URI of the SVG stretched to its
|
|
3
|
-
// drawing's box (Thunderbolt's `replaceWixUrl` and `createSvgCssVar`); this writes the same data URI in its place.
|
|
4
|
-
// An SVG that can't be loaded stays as written, with a warning.
|
|
5
|
-
|
|
6
|
-
import { loadedSvg, loadSvgs, scaleSvg, svgDataUrl, svgInfo } from './svg.js'
|
|
7
|
-
|
|
8
|
-
const WIX_VECTOR_URL = /url\(\s*(['"]?)wix:vector:\/\/v1\/([^'")\s]+)\1\s*\)/gi
|
|
9
|
-
const HAS_WIX_VECTOR_URL = /wix:vector:\/\//i
|
|
10
|
-
|
|
11
|
-
/** The ids every `wix:vector` url in the stylesheet names. */
|
|
12
|
-
const idsIn = root => {
|
|
13
|
-
const ids = new Set()
|
|
14
|
-
root.walkDecls(declaration => {
|
|
15
|
-
for (const [, , id] of declaration.value.matchAll(WIX_VECTOR_URL)) ids.add(id)
|
|
16
|
-
})
|
|
17
|
-
return ids
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const checks = /** @type {const} */ ([])
|
|
21
|
-
/** @typedef {typeof checks[number]} Check */
|
|
22
|
-
|
|
23
|
-
/** @type {import('../transform/types.js').CssTransformPlugin<Check>} */
|
|
24
|
-
export const wixVectorUrlsPlugin = {
|
|
25
|
-
checks,
|
|
26
|
-
name: 'wix-vector-urls',
|
|
27
|
-
// Last, so a url a mixin or preset copies elsewhere is inlined wherever it ends up.
|
|
28
|
-
order: 25,
|
|
29
|
-
prepare: root => loadSvgs(idsIn(root)),
|
|
30
|
-
transform(root, context) {
|
|
31
|
-
root.walkDecls(declaration => {
|
|
32
|
-
if (!HAS_WIX_VECTOR_URL.test(declaration.value)) return
|
|
33
|
-
declaration.value = declaration.value.replace(WIX_VECTOR_URL, (url, _quote, id) => {
|
|
34
|
-
const svg = loadedSvg(id)
|
|
35
|
-
if (svg === undefined) {
|
|
36
|
-
context.warn?.(declaration, `Couldn't load the SVG ${id} from Wix's CDN, so ${url} stays as written`, 'svg_not_loaded')
|
|
37
|
-
return url
|
|
38
|
-
}
|
|
39
|
-
return svgDataUrl(scaleSvg(svg, svgInfo(svg), 'none'))
|
|
40
|
-
})
|
|
41
|
-
})
|
|
42
|
-
},
|
|
43
|
-
}
|