@wix/origami-transforms 0.1.39 → 0.1.41

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.
@@ -15,3 +15,4 @@ export function viewBoxOf({ type, viewBox, bbox }: {
15
15
  }): any;
16
16
  export function scaleSvg(svg: any, info: any, preserveAspectRatio: any): any;
17
17
  export function svgDataUrl(svg: any): string;
18
+ export function sizeSvg(svg: any, width: any, height: any): any;
@@ -1,6 +1,6 @@
1
1
  /** @typedef {typeof checks[number]} Check */
2
2
  /** @type {import('../transform/types.js').CssTransformPlugin<Check>} */
3
- export const wixVectorUrlsPlugin: import("../transform/types.js").CssTransformPlugin<Check>;
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 {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/origami-transforms",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "description": "Babel and PostCSS checks and transforms for Wix origami page files.",
5
5
  "main": "./src/index.js",
6
6
  "files": [
@@ -19,11 +19,12 @@
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",
25
26
  "postcss-custom-media": "^12.0.1",
26
- "@wix/origami-bi": "0.13.0"
27
+ "@wix/origami-bi": "0.14.0"
27
28
  },
28
29
  "devDependencies": {
29
30
  "@types/node": "^22.0.0",
@@ -75,5 +76,5 @@
75
76
  },
76
77
  "type": "module",
77
78
  "types": "./dist/index.d.ts",
78
- "falconPackageHash": "0a5a98c7ec377b67dabfecd4436705ec8bb2a54dee0915dc6fd3451e"
79
+ "falconPackageHash": "573fa6b0fb741a4bb27078f673fa0895c486a65ee23b26a1cf1127e8"
79
80
  }
@@ -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-vector-urls run last: they load the SVGs a stylesheet names from Wix's CDN in `prepare`, and
16
- // write them in as data URIs.
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 { wixVectorUrlsPlugin } from './wixVectorUrls.js'
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
- wixVectorUrlsPlugin,
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-vector-urls: it only adds rules, which no other plugin needs to see, and it reads only `--height` as
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) {
@@ -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,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
- }