@webority/canvas-kit 0.83.6 → 0.85.0
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/README.md +38 -11
- package/dist/browser.js +1 -1
- package/dist/build.js +3 -3
- package/dist/cli.js +6 -3
- package/dist/kitModule.js +1 -1
- package/dist/manifest.js +1 -1
- package/dist/phone.js +1 -1
- package/dist/release.js +1 -1
- package/dist/spec.d.ts +2 -0
- package/dist/tokens.js +1 -1
- package/package.json +2 -2
- package/dist/styleKeyTable.js +0 -1
package/README.md
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
# @webority/canvas-kit
|
|
2
2
|
|
|
3
|
-
Builds a
|
|
4
|
-
components. The build writes an immutable release folder that Canvas stores and draws screens with.
|
|
3
|
+
Builds a kit for Webority Canvas. A kit is a pinned Webority library, and a product kit adds the product's own
|
|
4
|
+
presentational components. The build writes an immutable release folder that Canvas stores and draws screens with.
|
|
5
|
+
|
|
6
|
+
There are two kinds of kit. A library-only kit has no `entry`: it draws the library's components and nothing else. The
|
|
7
|
+
Webority fleet kits (`webority-web`, `webority-phone`) are built this way by Canvas Web's `publish-fleet-kit.mjs`. A
|
|
8
|
+
product kit has an `entry` and adds its own components.
|
|
5
9
|
|
|
6
10
|
## Build a release
|
|
7
11
|
|
|
8
12
|
```sh
|
|
9
13
|
canvas-kit build --config canvas-kit.json --out canvas-kit-release
|
|
14
|
+
canvas-kit build --config fleet.json --out Webority.Canvas.Kits/webority-web/<version> --style-keys Webority.Canvas.Web/scripts/styleKeyTable.json
|
|
10
15
|
```
|
|
11
16
|
|
|
12
|
-
`--out` must not exist. A release folder is never overwritten; build into a new folder.
|
|
17
|
+
`--out` must not exist. A release folder is never overwritten; build into a new folder. A library-only kit writes to
|
|
18
|
+
`<kitKey>/<version>`, and the build refuses any other folder.
|
|
19
|
+
|
|
20
|
+
The flags are:
|
|
21
|
+
|
|
22
|
+
| Flag | Meaning |
|
|
23
|
+
| --- | --- |
|
|
24
|
+
| `--style-keys <file>` | The style key table the renderer draws from. A library-only kit needs it. |
|
|
25
|
+
| `--phone-renderer-support <file>` | The phone renderer's support file: each style key's `phoneSupported` flag and the phone kit's action lists. A Phone kit needs it. |
|
|
26
|
+
|
|
27
|
+
Flag paths are relative to the working directory.
|
|
13
28
|
|
|
14
29
|
The config is a JSON object with these keys. Paths are relative to the config file.
|
|
15
30
|
|
|
@@ -17,18 +32,28 @@ The config is a JSON object with these keys. Paths are relative to the config fi
|
|
|
17
32
|
| --- | --- |
|
|
18
33
|
| `kit` | The kit key, lowercase letters, digits and hyphens, 2 to 40 characters, for example `lumex-portal`. |
|
|
19
34
|
| `platform` | `Web` or `Phone`. A Web kit takes its tokens from the theme and its icons from the library; a Phone kit takes both from the phone library. |
|
|
20
|
-
| `entry` | The kit's entry module, which exports the components. |
|
|
21
|
-
| `libraryPackage` | The Webority library the
|
|
35
|
+
| `entry` | Optional. The kit's entry module, which exports the product's components. Leave it out for a library-only kit. |
|
|
36
|
+
| `libraryPackage` | The Webority library the kit is built on, for example `@webority/ui-react`. |
|
|
22
37
|
| `rolesFile` | Optional. A JSON object from component name to `title` or `navigation`. |
|
|
23
38
|
| `rendererProtocolVersion` | The renderer protocol number the kit is built for. |
|
|
24
|
-
|
|
39
|
+
|
|
40
|
+
A config that names any other key, such as the retired `phoneStyleSupportFile`, fails the read.
|
|
25
41
|
|
|
26
42
|
## What a release holds
|
|
27
43
|
|
|
28
|
-
|
|
44
|
+
The release folder is `<kit>/<version>`:
|
|
45
|
+
|
|
46
|
+
- `kit.js`: one ES module whose default export comes from `defineKit`, with the components, the markers, the token
|
|
47
|
+
values and the manifest. React and react-dom stay bare imports, so the renderer's own React draws the kit. A Phone kit
|
|
48
|
+
also leaves react-native and react-native-svg bare; the phone renderer's import map resolves them.
|
|
29
49
|
- `kit.css`: the styles the bundle imports, or an empty file.
|
|
30
|
-
- `manifest.json`: the components with their props, sources and roles, the library's tokens and icons, and the style
|
|
31
|
-
|
|
50
|
+
- `manifest.json`: the components with their props, sources and roles, the library's tokens and icons, and the style
|
|
51
|
+
keys each with its `phoneSupported` flag.
|
|
52
|
+
- `release.json`: the kit key as `name`, the `version`, the platform, the kit module version, the protocol version, the
|
|
53
|
+
library name and version, and the SHA-256 and byte count of each file above.
|
|
54
|
+
|
|
55
|
+
A library-only kit is stamped with the installed library's version. A product kit is stamped with the product's
|
|
56
|
+
`package.json` version.
|
|
32
57
|
|
|
33
58
|
## Product components
|
|
34
59
|
|
|
@@ -44,7 +69,9 @@ The build stops with a named fix when:
|
|
|
44
69
|
- the product's React is not major 19, the Canvas renderer's React major;
|
|
45
70
|
- the library installed differs from the exact version the product pins;
|
|
46
71
|
- a role names a component the kit does not have, or a role is not `title` or `navigation`;
|
|
47
|
-
- a product component takes a name the library already exports
|
|
72
|
+
- a product component takes a name the library already exports;
|
|
73
|
+
- a library-only kit is built without `--style-keys`, or a Phone kit without `--phone-renderer-support`;
|
|
74
|
+
- a library-only kit is written to a folder that is not `<kitKey>/<version>`.
|
|
48
75
|
|
|
49
76
|
## Reading a release back
|
|
50
77
|
|
|
@@ -55,7 +82,7 @@ Any file changed after the build fails the check.
|
|
|
55
82
|
|
|
56
83
|
- `.`: `kitModuleVersion`, `KIT_MODULE_EXTERNALS`, `defineKit`, `readManifest`, `readReleaseManifest(dir)`, `buildKitRelease`, `readConfig`. Node only.
|
|
57
84
|
- `./kitModule`: the kit module contract alone.
|
|
58
|
-
- `./browser`: for the renderers, with no Node built-ins. `
|
|
85
|
+
- `./browser`: for the renderers, with no Node built-ins. `loadKit({ kitKey, version, baseUrl })` loads the release at `<baseUrl>/<kitKey>/<version>` and returns its kit module, for a fleet kit and a product kit alike.
|
|
59
86
|
|
|
60
87
|
## Tests
|
|
61
88
|
|
package/dist/browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import"./kitModule.js";import{
|
|
1
|
+
import"./kitModule.js";import{RELEASE_CONTENT as e,RELEASE_FILE as t,changedMessage as n,checkStampFiles as r}from"./releaseStamp.js";var i=e=>new TextDecoder().decode(e);async function a(e){let t=await globalThis.crypto.subtle.digest(`SHA-256`,e);return Array.from(new Uint8Array(t),e=>e.toString(16).padStart(2,`0`)).join(``)}async function o(e,t){let n=await t(e);if(!n.ok)throw Error(`${e} could not be loaded (HTTP ${n.status}).`);return new Uint8Array(await n.arrayBuffer())}async function s(e){let t=URL.createObjectURL(new Blob([e],{type:`text/javascript`}));try{return await import(t)}finally{URL.revokeObjectURL(t)}}async function c({kitKey:c,version:l,baseUrl:u,fetch:d=globalThis.fetch,importScript:f=s}){if([c,l,u].some(e=>typeof e!=`string`||e===``))throw Error(`loadKit needs the kit key, the version and the base URL, each a non-empty string.`);let p=`${u.replace(/\/+$/,``)}/${encodeURIComponent(c)}/${encodeURIComponent(l)}`,m=`the release ${c} ${l}`,h=JSON.parse(i(await o(`${p}/${t}`,d)));if(h?.kitModuleVersion!==2)throw Error(`Release ${c} ${l} was built for kit module version ${h?.kitModuleVersion}; this renderer reads version 2. Rebuild the release with the @webority/canvas-kit that reads version 2.`);if(r(h,m),h.name!==c||h.version!==l)throw Error(`${t} in ${p} names ${h.name} ${h.version}, not ${c} ${l}.`);let g=Object.fromEntries(await Promise.all(e.map(async e=>{let t=await o(`${p}/${e}`,d),r=h.files[e];if(await a(t)!==r.sha256||t.byteLength!==r.bytes)throw Error(n(e,m));return[e,t]}))),_=JSON.parse(i(g[`manifest.json`])),v=(await f(i(g[`kit.js`])))?.default;if(typeof v!=`object`||!v)throw Error(`The kit bundle of ${m} has no default export; rebuild the release.`);if(JSON.stringify(v.manifest)!==JSON.stringify(_))throw Error(`The kit bundle of ${m} does not carry its manifest.json; rebuild the release.`);return{components:v.components,markers:v.markers,tokenValues:v.tokenValues,manifest:_,kitStyles:i(g[`kit.css`])}}export{c as loadKit};
|
package/dist/build.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{findPackageDir as e,readJson as t,toPosix as n}from"./files.js";import{KIT_MODULE_EXTERNALS as r}from"./kitModule.js";import{libraryFiles as i,readManifest as a}from"./manifest.js";import{
|
|
2
|
-
`)}function
|
|
3
|
-
`);return{script:
|
|
1
|
+
import{findPackageDir as e,readJson as t,toPosix as n}from"./files.js";import{KIT_MODULE_EXTERNALS as r}from"./kitModule.js";import{libraryFiles as i,readManifest as a}from"./manifest.js";import{checkFleetFolder as o,digest as s,writeReleaseFolder as c}from"./release.js";import{existsSync as l}from"node:fs";import{dirname as u,join as d,resolve as f}from"node:path";import{fileURLToPath as p}from"node:url";import{build as m}from"vite";var h=19,g=[`react-redux`,`react-router-dom`,`axios`],_=[`kit`,`platform`,`entry`,`libraryPackage`,`rolesFile`,`rendererProtocolVersion`],v=[`kit`,`platform`,`libraryPackage`,`rendererProtocolVersion`],y=`canvas-kit:entry`,b=`\0${y}`,x=d(u(p(import.meta.url)),`kitModule.js`);function S(e){let n=t(e);if(typeof n!=`object`||!n||Array.isArray(n))throw Error(`${e} must be a JSON object.`);for(let t of Object.keys(n))if(!_.includes(t))throw Error(`${e} has the unknown key ${t}. The keys are ${_.join(`, `)}.`);for(let t of v)if(n[t]===void 0)throw Error(`${e} needs the key ${t}.`);for(let t of[`kit`,`platform`,`libraryPackage`])if(typeof n[t]!=`string`)throw Error(`${e}: ${t} must be a string.`);for(let t of[`entry`,`rolesFile`])if(n[t]!==void 0&&typeof n[t]!=`string`)throw Error(`${e}: ${t} must be a string path.`);return n}function C(n){let r=e(n,`react`);if(!r)throw Error(`react is not installed for ${n}. Run pnpm install there.`);let{version:i}=t(d(r,`package.json`));if(Number(String(i).split(`.`)[0])!==h)throw Error(`The product uses React ${i}; the Canvas renderer runs React ${h}. Pin react to ${h}.x and rebuild.`)}function w(e){let{version:n}=t(d(e,`package.json`));if(!n)throw Error(`${d(e,`package.json`)} needs a version; the release is stamped with it.`);return n}function T({entryFile:e,libraryFile:t,manifest:r,libraryNames:i,productNames:a}){let o=[`import { defineKit } from ${JSON.stringify(n(x))};`];e!==void 0&&o.push(`import * as product from ${JSON.stringify(n(e))};`),i.length>0&&o.push(`import { ${i.join(`, `)} } from ${JSON.stringify(n(t))};`);let s=[...i,...a.map(e=>`${e}: product.${e}`)],c=Object.fromEntries(r.components.filter(({marker:e})=>e!==null).map(({name:e,marker:t})=>[e,t]));return o.push(`export default defineKit({ components: { ${s.join(`, `)} }, markers: ${JSON.stringify(c)}, tokenValues: ${JSON.stringify(r.tokenValues)}, manifest: ${JSON.stringify(r)} });`,``),o.join(`
|
|
2
|
+
`)}function E(e){return{name:`canvas-kit-entry`,resolveId(e){return e===y?b:null},load(t){return t===b?e:null}}}function D(e){let t=`${n(d(e,`src`,`services`))}/`;return{name:`canvas-kit-banned-imports`,transform(e,r){let i=n(r.split(`?`)[0]),a=g.find(e=>i.includes(`/node_modules/${e}/`));if(a)throw Error(`The kit imports ${a} (${i}). A kit draws from its props only; the container that renders it holds the state and the calls.`);if(i.startsWith(t))throw Error(`The kit imports ${i}, which is in src/services. A kit draws from its props only; move the call into the container.`);return null}}}async function O({root:e,kit:t,platform:n,entryFile:i,libraryFile:a,libraryNames:o,productNames:s,manifest:c}){let l=r[n],u=await m({configFile:!1,root:e,logLevel:`warn`,publicDir:!1,envDir:!1,plugins:[E(T({entryFile:i,libraryFile:a,manifest:c,libraryNames:o,productNames:s})),D(e)],esbuild:{jsx:`automatic`,jsxImportSource:`react`,include:/\.[cm]?[jt]sx?$/},build:{write:!1,minify:!0,target:`es2022`,cssCodeSplit:!1,lib:{entry:y,formats:[`es`],fileName:()=>`kit.js`},rollupOptions:{input:y,external:e=>l.some(t=>e===t||e.startsWith(`${t}/`))}}}),d=(Array.isArray(u)?u:[u]).flatMap(e=>e.output),f=d.find(e=>e.type===`chunk`&&e.isEntry);if(!f)throw Error(`The bundle of ${t} has no entry module.`);let p=d.filter(e=>e.type===`asset`&&e.fileName.endsWith(`.css`)).map(e=>typeof e.source==`string`?e.source:Buffer.from(e.source).toString(`utf8`)).join(`
|
|
3
|
+
`);return{script:f.code,styles:p}}async function k({configFile:e,outDir:t,styleKeysFile:n,phoneRendererSupportFile:r}){let d=f(e),p=f(t);if(l(p))throw Error(`${p} already exists. A release folder is never overwritten; choose a new folder.`);let m=S(d),h=u(d),g=m.entry===void 0,_=g?void 0:f(h,m.entry);if(_!==void 0&&!l(_))throw Error(`The kit entry ${_} does not exist.`);if(g&&n===void 0)throw Error(`A library-only kit needs --style-keys: the style key table the renderer draws from.`);if(m.platform===`Phone`&&r===void 0)throw Error(`A Phone kit needs --phone-renderer-support: the phone renderer's support file.`);if(m.platform!==`Phone`&&r!==void 0)throw Error(`Only a Phone kit reads --phone-renderer-support; a Web kit takes no phone support file.`);C(h);let v=m.rolesFile===void 0?void 0:f(h,m.rolesFile),{manifest:y,warnings:b}=a({projectRoot:h,kit:m.kit,platform:m.platform,entry:_,libraryPackage:m.libraryPackage,rolesFile:v,rendererProtocolVersion:m.rendererProtocolVersion,phoneRendererSupportFile:r===void 0?void 0:f(r),styleKeysFile:n===void 0?void 0:f(n)}),x=i(h,m.libraryPackage),T=g?x.pkg.version:w(h);g&&o(p,m.kit,T);let E=y.components.filter(({source:e})=>e===m.libraryPackage).map(({name:e})=>e),D=y.components.filter(({source:e})=>e!==m.libraryPackage).map(({name:e})=>e),{script:k,styles:A}=await O({root:h,kit:m.kit,platform:m.platform,entryFile:_,libraryFile:x.entryFile,libraryNames:E,productNames:D,manifest:y}),j={"manifest.json":`${JSON.stringify(y,null,2)}\n`,"kit.js":k,"kit.css":A},M={name:m.kit,version:T,platform:m.platform,kitModuleVersion:2,rendererProtocolVersion:m.rendererProtocolVersion,library:y.library,files:Object.fromEntries(Object.entries(j).map(([e,t])=>[e,s(t)]))};return c(p,j,M),{outDir:p,release:M,manifest:y,warnings:b}}export{k as buildKitRelease,S as readConfig};
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{buildKitRelease as e}from"./build.js";import{resolve as t}from"node:path";var n=`Usage: canvas-kit build --config <file> --out <dir>
|
|
2
|
+
import{buildKitRelease as e}from"./build.js";import{resolve as t}from"node:path";var n=`Usage: canvas-kit build --config <file> --out <dir> [--style-keys <file>] [--phone-renderer-support <file>]
|
|
3
3
|
|
|
4
|
-
Builds a
|
|
5
|
-
<dir> must not exist; a release folder is never overwritten
|
|
4
|
+
Builds a kit release into <dir>: kit.js, kit.css, manifest.json and release.json.
|
|
5
|
+
<dir> must not exist; a release folder is never overwritten.
|
|
6
|
+
--style-keys: the style key table the renderer draws from. A library-only kit (no entry) needs it.
|
|
7
|
+
--phone-renderer-support: the phone renderer's support file. A Phone kit needs it.
|
|
8
|
+
Flag paths are relative to the working directory; the paths in the config are relative to the config file.`,r=new Set([`--config`,`--out`,`--style-keys`,`--phone-renderer-support`]);function i(e){if(e.length===0||e.includes(`--help`)||e.includes(`-h`))return{help:!0};let[t,...n]=e,i={};for(let e=0;e<n.length;e+=1){let t=n[e];if(!r.has(t))throw Error(`Unknown argument ${t}.`);let a=n[e+1];if(a===void 0||a.startsWith(`--`))throw Error(`${t} needs a value.`);i[t.slice(2)]=a,e+=1}return{command:t,options:i}}async function a(r){let a=i(r);if(a.help){process.stdout.write(`${n}\n`);return}if(a.command!==`build`)throw Error(`Unknown command ${a.command}. The only command is build.`);if(!a.options.config||!a.options.out)throw Error(`build needs --config and --out.`);let o=a.options[`style-keys`],s=a.options[`phone-renderer-support`],c=await e({configFile:t(a.options.config),outDir:t(a.options.out),styleKeysFile:o===void 0?void 0:t(o),phoneRendererSupportFile:s===void 0?void 0:t(s)});for(let e of c.warnings)process.stderr.write(`warning: ${e}\n`);process.stdout.write(`Built ${c.release.name} (${c.release.platform}): ${c.manifest.components.length} components. Release written to ${c.outDir}.\n`)}a(process.argv.slice(2)).catch(e=>{process.stderr.write(`canvas-kit: ${e.message}\n`),process.exitCode=1});export{};
|
package/dist/kitModule.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=
|
|
1
|
+
var e=2,t=Object.freeze({Web:[`react`,`react-dom`,`react/jsx-runtime`],Phone:[`react`,`react-dom`,`react/jsx-runtime`,`react-native`,`react-native-svg`]});function n({components:e,markers:n,tokenValues:r,manifest:i}){if(typeof i!=`object`||!i)throw Error(`defineKit needs the manifest, the kit's manifest object.`);if(!Object.hasOwn(t,i.platform))throw Error(`defineKit: platform ${JSON.stringify(i.platform)} is not Web or Phone.`);if(typeof e!=`object`||!e)throw Error(`defineKit: components must be an object of React components.`);let a={};for(let[t,n]of Object.entries(e)){if(n===null||typeof n!=`function`&&typeof n!=`object`)throw Error(`defineKit: component ${t} is not a React component.`);a[t]=n}if(typeof n!=`object`||!n)throw Error(`defineKit: markers must be an object of marker names by component name.`);for(let[e,t]of Object.entries(n))if(!Object.hasOwn(a,e)||typeof t!=`string`||t===``)throw Error(`defineKit: the marker of ${e} must name a component with a non-empty marker.`);if(r===void 0||r!==null&&typeof r!=`object`)throw Error(`defineKit: tokenValues must be an object, or null on a release built before it existed.`);return{components:Object.freeze(a),markers:Object.freeze({...n}),tokenValues:r,manifest:i}}export{t as KIT_MODULE_EXTERNALS,n as defineKit,e as kitModuleVersion};
|
package/dist/manifest.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{findPackageDir as e,readJson as t,readText as n,toPosix as r}from"./files.js";import"./kitModule.js";import{collectComponents as i}from"./declarations.js";import{PHONE_EXCLUDED_COMPONENTS as a,applyPhoneActions as o,phoneIcons as s,phoneTokens as
|
|
1
|
+
import{findPackageDir as e,readJson as t,readText as n,toPosix as r}from"./files.js";import"./kitModule.js";import{collectComponents as i}from"./declarations.js";import{PHONE_EXCLUDED_COMPONENTS as a,applyPhoneActions as o,phoneIcons as s,phoneTokenValues as c,phoneTokens as l}from"./phone.js";import{colourMeanings as u,webIcons as d,webTokenValues as ee,webTokens as f}from"./tokens.js";import{createRequire as p}from"node:module";import{existsSync as m,mkdtempSync as h,rmSync as g}from"node:fs";import{dirname as _,join as v,relative as y,resolve as b}from"node:path";import{execFileSync as x}from"node:child_process";import{tmpdir as S}from"node:os";import C from"@babel/parser";var w=/^[a-z][a-z0-9-]{1,39}$/,T=[`Web`,`Phone`],E=[`title`,`navigation`],D=v(_(p(import.meta.url).resolve(`typescript/package.json`)),`bin`,`tsc`),O=[`.jsx`,`.js`,`.tsx`,`.ts`,`.mjs`],k=/^App[A-Z]/,A={Web:`WeborityWeb`,Phone:`WeborityPhone`};function j(n,r){let i=e(n,r);if(!i)throw Error(`${r} is not installed for ${n}. Run pnpm install there.`);let a=t(v(i,`package.json`)),o=a.exports?.[`.`],s=a.types??(o&&typeof o==`object`?o.types:void 0),c=(typeof o==`string`?o:o&&typeof o==`object`?o.import??o.default:void 0)??a.main;if(!s)throw Error(`${r} declares no types, and the manifest reads its declaration files.`);if(!c)throw Error(`${r} declares no entry file for its runtime.`);return{dir:i,pkg:a,typesFile:v(i,s),entryFile:v(i,c)}}function M(t){let n=e(t,`@webority/theme`);if(!n)throw Error(`@webority/theme is not installed for ${t}. Run pnpm install.`);return n}function N(e,n,r){let i=t(v(e,`package.json`)),a=i.dependencies?.[n]??i.devDependencies?.[n];if(/^\d+\.\d+\.\d+$/.test(a??``)&&a!==r)throw Error(`${n} is pinned to ${a} in package.json but ${r} is installed. Run pnpm install first.`)}function P(e,t){let n=h(v(S(),`canvas-kit-declarations-`));try{x(process.execPath,[D,`--allowJs`,`--declaration`,`--emitDeclarationOnly`,`--jsx`,`react-jsx`,`--module`,`esnext`,`--moduleResolution`,`bundler`,`--target`,`es2022`,`--skipLibCheck`,`--rootDir`,e,`--outDir`,n,t],{cwd:e,encoding:`utf8`,stdio:`pipe`})}catch(e){throw g(n,{recursive:!0,force:!0}),Error(`Could not read the declarations of ${t}: ${e.stdout||e.stderr||e.message}`)}return n}function F(e,t,n){let i=y(t,n).replace(/\.d\.ts$/,``);for(let t of O)if(m(v(e,`${i}${t}`)))return r(`${i}${t}`);throw Error(`No source file for the declarations in ${n}`)}function I(e,t,r){let i=/\.tsx?$/.test(t)?[`jsx`,`typescript`]:[`jsx`],a=C.parse(n(v(e,t)),{sourceType:`module`,plugins:i});for(let e of a.program.body){let t=e.type===`ExpressionStatement`?e.expression:null;if(t?.type===`AssignmentExpression`&&t.left.type===`MemberExpression`&&!t.left.computed&&t.left.object.type===`Identifier`&&t.left.object.name===r&&t.left.property.name===`displayName`&&t.right.type===`StringLiteral`)return t.right.value}return null}function L(e){return e.filter(e=>e.type===`array`&&(e.itemFields??[]).some(e=>[`href`,`to`].includes(e.name))).map(e=>e.name)}function R(e,n){if(!n)return;let r=t(n);if(typeof r!=`object`||!r||Array.isArray(r))throw Error(`${n} must be an object from component name to role.`);for(let[t,i]of Object.entries(r)){let r=e.find(e=>e.name===t);if(!r)throw Error(`${n} names ${t}, which the kit does not have.`);if(!E.includes(i))throw Error(`${n}: ${t} has role ${JSON.stringify(i)}; a role is title or navigation.`);r.role=i}}function z(e){let n=t(e);if(!Array.isArray(n)||n.some(e=>typeof e?.name!=`string`))throw Error(`${e} must be the style key table: a list of style keys, each with a name.`);return n}function B(e){let n=t(e);if(n?.schema!==1)throw Error(`${e} has schema ${n?.schema}; this reader reads schema 1.`);if(!n.itemActions)throw Error(`${e} has no itemActions; the phone kit's action lists come from it.`);return{flags:n.styleKeys??{},itemActions:n.itemActions}}function V(e,t,n){let r=e.map(({name:e})=>e),i=r.filter(e=>typeof t[e]!=`boolean`),a=Object.keys(t).filter(e=>!r.includes(e));if(i.length>0||a.length>0)throw Error(`${n} must list exactly the style keys of the style key table, each true or false. Missing or not a boolean: ${i.join(`, `)||`none`}. Not in the table: ${a.join(`, `)||`none`}.`)}function H(e,t){return e.map(({name:e,type:n,values:r,appliesTo:i,description:a})=>({name:e,type:n,values:r,appliesTo:i,...t?{phoneSupported:t[e]}:{},description:a}))}function U({projectRoot:e,kit:r,platform:p,entry:m,libraryPackage:h,rolesFile:_,rendererProtocolVersion:x,phoneRendererSupportFile:S,styleKeysFile:C}){if(!w.test(r??``))throw Error(`kit ${JSON.stringify(r)} must be 2 to 40 characters: lowercase letters, digits and hyphens, starting with a letter.`);if(!T.includes(p))throw Error(`platform must be Web or Phone, not ${JSON.stringify(p)}.`);if(!Number.isInteger(x)||x<1)throw Error(`rendererProtocolVersion must be a positive integer, not ${JSON.stringify(x)}.`);if(p===`Phone`&&!S)throw Error(`A Phone kit needs phoneRendererSupportFile, the phone renderer's support file.`);let E=b(e),D=j(E,h);N(E,h,D.pkg.version);let O=p===`Phone`?B(S):null,U=C?z(C):null;U&&O&&V(U,O.flags,S);let W=i(D.typesFile,{namedConsts:!0,kit:h}),G=p===`Phone`?W.components.filter(({name:e})=>!a.has(e)):W.components,K={components:[],warnings:[]},q=new Map;if(m!==void 0){let e=b(m);if(y(E,e).startsWith(`..`))throw Error(`The kit entry ${e} is outside the product folder ${E}.`);let t=P(E,e);try{K=i(v(t,y(E,e)).replace(/\.[^./\\]+$/,`.d.ts`),{kit:r}),q=new Map(K.components.map(e=>[e.name,F(E,t,e.file)]))}finally{g(t,{recursive:!0,force:!0})}}let J=new Set(G.map(({name:e})=>e)),Y=K.components.filter(({name:e})=>J.has(e)).map(({name:e})=>e);if(Y.length>0)throw Error(`The kit names ${Y.join(`, `)} as ${h} already has them; rename the product components.`);let X=[...G.map(e=>({...e,source:h,marker:k.test(e.name)?e.name:null})),...K.components.map(e=>{let t=q.get(e.name);return{...e,source:t,marker:I(E,t,e.name)}})].sort((e,t)=>e.name<t.name?-1:+(e.name>t.name)).map(({name:e,marker:t,acceptsChildren:n,props:r,source:i})=>({name:e,marker:t,acceptsChildren:n,props:r,itemsTakeAction:p===`Web`?L(r):[],takesAction:[],source:i}));O&&o(X,O.itemActions),R(X,_);let Z,Q,$;if(p===`Web`){let e=M(E);Z=f(n(v(e,`scss`,`_tokens.scss`))),Z.colorMeanings=u(Z.color,t(v(e,`token-meanings.json`))),Q=ee(v(e,`dist`,`published-theme.json`),Z),$=d(v(D.dir,`dist`))}else{let e=v(D.dir,`lib`,`module`,`theme`,`tokens.js`);Z=l(e),Q=c(e),$=s(v(D.dir,`lib`,`typescript`,`module`,`components`,`AppIcon`,`catalog.g.d.ts`))}return{manifest:{kind:m===void 0?A[p]:`Product`,library:{name:D.pkg.name,version:D.pkg.version},rendererProtocolVersion:x,platform:p,kitModuleVersion:2,productKit:null,components:X,tokens:Z,tokenValues:Q,icons:$,...U?{styleKeys:H(U,O?O.flags:null)}:{}},warnings:[...W.warnings,...K.warnings]}}export{j as libraryFiles,U as readManifest,B as readPhoneSupport};
|
package/dist/phone.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readText as e}from"./files.js";import t from"@babel/parser";var n=new Set([`Form`,`NetworkStatusBanner`,`SkeletonClockProvider`,`SkeletonProvider`,`SkeletonSkip`,`ThemeProvider`,`ToastProvider`,`Box`,`Text`]),r=[`sans`]
|
|
1
|
+
import{readText as e}from"./files.js";import t from"@babel/parser";var n=new Set([`Form`,`NetworkStatusBanner`,`SkeletonClockProvider`,`SkeletonProvider`,`SkeletonSkip`,`ThemeProvider`,`ToastProvider`,`Box`,`Text`]),r=[`sans`],i=`System`;function a(n){return t.parse(e(n),{sourceType:`module`,plugins:[`typescript`]})}function o(e){return[...new Set(e)].sort((e,t)=>e<t?-1:+(e>t))}function s(e){return e.type===`Identifier`?e.name:e.type===`StringLiteral`?e.value:null}function c(e){let t=new Map;for(let n of e.program.body){let e=n.type===`ExportNamedDeclaration`?n.declaration:n;if(e?.type===`VariableDeclaration`)for(let n of e.declarations)n.id.type===`Identifier`&&t.set(n.id.name,n.init)}return t}function l(e,t,n){let r=t;for(let t=0;r?.type===`Identifier`;t+=1){if(t>10||!e.has(r.name))throw Error(`${r.name} in ${n} is not a constant the reader can follow.`);r=e.get(r.name)}return r}function u(e,t,n,r){let i=n.properties.find(e=>e.type===`ObjectProperty`&&s(e.key)===r);if(!i)throw Error(`${r} is missing from the theme in ${t}`);return l(e,i.value,t)}function d(e){return e.properties.filter(e=>e.type===`ObjectProperty`).map(e=>s(e.key))}function f(e,t,n,r=``){return n.properties.flatMap(n=>{if(n.type!==`ObjectProperty`)return[];let i=`${r}${s(n.key)}`,a=l(e,n.value,t);return a.type===`StringLiteral`?[i]:a.type===`ObjectExpression`?f(e,t,a,`${i}.`):[]})}function p(e){let t=c(a(e));if(!t.has(`lightTheme`))throw Error(`lightTheme is not declared in ${e}`);let n=l(t,t.get(`lightTheme`),e),i=u(t,e,n,`typography`);return{color:o(f(t,e,u(t,e,n,`colors`))),space:o(d(u(t,e,n,`spacing`))),radius:o(d(u(t,e,n,`radius`))),shadow:o(d(u(t,e,n,`shadows`))),font:r,text:o(d(u(t,e,i,`fontSize`)))}}function m(e,t,n){let r=l(e,t,n);if(r.type===`StringLiteral`||r.type===`NumericLiteral`)return r.value;if(r.type===`UnaryExpression`&&r.operator===`-`&&r.argument.type===`NumericLiteral`)return-r.argument.value;if(r.type===`ObjectExpression`)return Object.fromEntries(r.properties.map(t=>{if(t.type!==`ObjectProperty`)throw Error(`${n} spreads an object the reader cannot follow.`);return[s(t.key),m(e,t.value,n)]}));throw Error(`${n} has a ${r.type} the reader cannot read as a value.`)}function h(e,t,n,r){let i=l(e,n,t);for(let n of r)i=u(e,t,i,n);return m(e,i,t)}function g(e,t,n){return Object.fromEntries(Object.entries(e).map(([e,r])=>{if(typeof r!=`number`)throw Error(`${t}.${e} in ${n} is not a number.`);return[e,r]}))}function _(e,t,n){if(Object.keys(e).length===0)return`none`;let{shadowColor:r,shadowOffset:i,shadowOpacity:a,shadowRadius:o}=e,s=/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(typeof r==`string`?r:``);if(!s||typeof i?.width!=`number`||typeof i?.height!=`number`||typeof a!=`number`||typeof o!=`number`)throw Error(`shadows.${t} in ${n} is not a shadow the reader can draw.`);let c=s[1].length===3?[...s[1]].map(e=>e+e).join(``):s[1],[l,u,d]=[0,2,4].map(e=>Number.parseInt(c.slice(e,e+2),16));return`${i.width}px ${i.height}px ${o}px rgba(${l}, ${u}, ${d}, ${a})`}function v(e){let t=c(a(e));for(let n of[`lightTheme`,`darkTheme`])if(!t.has(n))throw Error(`${n} is not declared in ${e}; the phone kit's token values need the light and dark themes.`);let n=t.get(`lightTheme`),r=t.get(`darkTheme`),o=u(t,e,l(t,n,e),`colors`),s=u(t,e,l(t,r,e),`colors`),d=h(t,e,n,[`fontFamily`,`sans`]);if(typeof d!=`string`)throw Error(`fontFamily.sans in ${e} is not a font family name.`);return{color:Object.fromEntries(f(t,e,o).map(n=>{let r=n.split(`.`);return[n,{light:h(t,e,o,r),dark:h(t,e,s,r)}]})),space:g(h(t,e,n,[`spacing`]),`spacing`,e),radius:g(h(t,e,n,[`radius`]),`radius`,e),shadow:Object.fromEntries(Object.entries(h(t,e,n,[`shadows`])).map(([t,n])=>[t,_(n,t,e)])),font:{sans:{family:d,fallback:i}},text:Object.fromEntries(Object.entries(g(h(t,e,n,[`typography`,`fontSize`]),`fontSize`,e)).map(([e,t])=>[e,{size:t,lineHeight:null,weight:null}]))}}function y(e){let t=a(e).program.body.map(e=>e.type===`ExportNamedDeclaration`?e.declaration:e).find(e=>e?.type===`TSTypeAliasDeclaration`&&e.id.name===`IconName`);if(t?.typeAnnotation.type!==`TSUnionType`)throw Error(`IconName union not found in ${e}`);return o(t.typeAnnotation.types.map(t=>{if(t.type!==`TSLiteralType`||t.literal.type!==`StringLiteral`)throw Error(`IconName in ${e} has a member that is not a string literal`);return t.literal.value}))}function b(e,t){for(let[n,r]of[[`itemsTakeAction`,`array`],[`takesAction`,`object`]])for(let[i,a]of Object.entries(t[n]??{})){let t=e.find(({name:e})=>e===i);if(!t)throw Error(`phoneStyleSupport.json ${n} names ${i}, which the kit does not have.`);for(let e of a)if(t.props.find(({name:t})=>t===e)?.type!==r)throw Error(`phoneStyleSupport.json ${n} names ${i}.${e}, which is not a prop of type ${r} in the kit.`);t[n]=o(a)}}export{n as PHONE_EXCLUDED_COMPONENTS,b as applyPhoneActions,y as phoneIcons,v as phoneTokenValues,p as phoneTokens};
|
package/dist/release.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readJson as e}from"./files.js";import{RELEASE_FILE as t,changedMessage as n,checkStampFiles as r}from"./releaseStamp.js";import{existsSync as i,mkdirSync as a,readFileSync as o,renameSync as s,rmSync as c,writeFileSync as l}from"node:fs";import{
|
|
1
|
+
import{readJson as e}from"./files.js";import{RELEASE_FILE as t,changedMessage as n,checkStampFiles as r}from"./releaseStamp.js";import{existsSync as i,mkdirSync as a,readFileSync as o,renameSync as s,rmSync as c,writeFileSync as l}from"node:fs";import{basename as u,dirname as d,join as f}from"node:path";import{createHash as p}from"node:crypto";function m(e){let t=Buffer.from(e);return{sha256:p(`sha256`).update(t).digest(`hex`),bytes:t.length}}function h(e,t,n){if(u(e)!==n||u(d(e))!==t)throw Error(`A library-only kit writes its release to a folder named ${t}/${n}, not ${e}.`)}function g(e,n,r){if(i(e))throw Error(`${e} already exists. A release folder is never overwritten; choose a new folder.`);a(d(e),{recursive:!0});let o=`${e}.staging-${process.pid}-${Date.now()}`;a(o);try{for(let[e,t]of Object.entries(n))l(f(o,e),t,{flag:`wx`});l(f(o,t),`${JSON.stringify(r,null,2)}\n`,{flag:`wx`}),s(o,e)}catch(e){throw c(o,{recursive:!0,force:!0}),e}}function _(a){let s=f(a,t);if(!i(s))throw Error(`${a} has no ${t}; it is not a kit release.`);let c=e(s);r(c,a);for(let[e,t]of Object.entries(c.files)){let r=f(a,e);if(!i(r))throw Error(`${e} is missing from ${a}.`);let s=m(o(r));if(s.sha256!==t.sha256||s.bytes!==t.bytes)throw Error(n(e,a))}return{release:c,manifest:e(f(a,`manifest.json`))}}export{h as checkFleetFolder,m as digest,_ as readReleaseManifest,g as writeReleaseFolder};
|
package/dist/spec.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface CanvasSpecNode {
|
|
|
19
19
|
id: string;
|
|
20
20
|
// The component the node draws: a block type (Box, Text, Image, Icon, Vector) or a library component name.
|
|
21
21
|
component: string;
|
|
22
|
+
// The component the node maps to, when the node carries a code mapping.
|
|
23
|
+
code?: string;
|
|
22
24
|
box: CanvasSpecBox;
|
|
23
25
|
// The CSS the renderer applied to the node's element, keyed by property name.
|
|
24
26
|
styles: Record<string, string>;
|
package/dist/tokens.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readText as
|
|
1
|
+
import{readJson as e,readText as t}from"./files.js";import{existsSync as n}from"node:fs";import{join as r}from"node:path";var i=[`none`,`xxs`,`xs`,`sm`,`md`,`lg`,`xl`,`2xl`,`3xl`,`4xl`],a=[`sans`,`display`],o=e=>typeof e==`object`&&!!e&&!Array.isArray(e),s=e=>typeof e==`number`&&Number.isFinite(e),c=e=>typeof e==`string`,l={color:e=>o(e)&&c(e.light)&&c(e.dark),space:s,radius:s,shadow:c,font:e=>o(e)&&c(e.family)&&c(e.fallback),text:e=>o(e)&&s(e.size)&&[e.lineHeight,e.weight].every(e=>e==null||s(e))};function u(e){return[...new Set(e)].sort((e,t)=>e<t?-1:+(e>t))}function d(e){let t=e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/(^|\s)\/\/.*$/gm,`$1`),n=new Map;for(let e of t.matchAll(/(?<![\w-])(--wui-[a-z0-9-]+)\s*:([^;]*);/g))n.has(e[1])||n.set(e[1],e[2].replace(/\s+/g,` `).trim());let r=(e,t=0)=>{let i=n.get(e);if(i===void 0)return!1;if(/^(#|rgba?\(|hsla?\()/.test(i))return!0;let a=/^var\((--wui-[a-z0-9-]+)\)$/.exec(i);return a!==null&&t<10&&r(a[1],t+1)},o=e=>u([...n.keys()].filter(t=>t.startsWith(e)).map(t=>t.slice(e.length)));return{color:u([...n.keys()].filter(e=>r(e)&&!e.startsWith(`--wui-font-`)&&!e.startsWith(`--wui-dark-`)).map(e=>e.slice(6))),space:u(i),radius:o(`--wui-radius-`),shadow:o(`--wui-shadow-`),font:u(a),text:o(`--wui-fs-`)}}function f(e,t){return Object.fromEntries(e.map(e=>{let n=t[`--wui-${e}`];if(typeof n!=`string`||n===``)throw Error(`@webority/theme token-meanings.json has no meaning for --wui-${e}; move the theme pin to a version that publishes one.`);return[e,n]}))}function p(e){let n=r(e,`components`,`iconCatalogNames.g.js`),i=t(n),a=/`([^`]+)`\.split\(`\.`\)/.exec(i);if(!a)throw Error(`No icon name list in ${n}`);return u(a[1].split(`.`).filter(Boolean))}function m(t,r){if(!n(t))throw Error(`${t} is missing; rebuild the release with canvas-kit build.`);let i=e(t),a={};for(let[e,n]of Object.entries(l)){let s=o(i)&&o(i[e])?i[e]:null;if(!s)throw Error(`${t} has no ${e} object; rebuild the release with canvas-kit build.`);for(let[r,i]of Object.entries(s))if(!n(i))throw Error(`${t}: ${e}.${r} is not a value the kit can draw; rebuild the release with canvas-kit build.`);if(e!==`space`){let n=r[e].filter(e=>!Object.hasOwn(s,e));if(n.length>0)throw Error(`${t} has no ${e} value for ${n.join(`, `)}; rebuild the release with canvas-kit build.`)}a[e]=e===`text`?g(s,h):s}return a}function h({size:e,lineHeight:t,weight:n}){return{size:e,lineHeight:t??null,weight:n??null}}function g(e,t){return Object.fromEntries(Object.entries(e).map(([e,n])=>[e,t(n)]))}export{f as colourMeanings,p as webIcons,m as webTokenValues,d as webTokens};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webority/canvas-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.85.0",
|
|
4
4
|
"description": "Builds product kits for Webority Canvas: a kit bundle, its manifest, and the spec shape the renderers answer.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"react": "^19.2.6",
|
|
26
|
-
"@webority/ui-react": "0.
|
|
26
|
+
"@webority/ui-react": "0.85.0"
|
|
27
27
|
},
|
|
28
28
|
"scripts": {
|
|
29
29
|
"build": "vite build --config vite.cli.config.js",
|
package/dist/styleKeyTable.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var e=[{name:`layout`,type:`enum`,values:[`row`,`column`,`grid`,`overlay`,`free`],appliesTo:`any`,description:`How children are placed: row, column, grid, overlay (stacked in one cell) or free (x and y).`},{name:`gap`,type:`token`,values:[`space`],appliesTo:`any`,description:`Space between children: a space token or px.`},{name:`rowGap`,type:`token`,values:[`space`],appliesTo:`any`,description:`Space between rows; overrides gap.`},{name:`columnGap`,type:`token`,values:[`space`],appliesTo:`any`,description:`Space between columns; overrides gap.`},{name:`padding`,type:`token`,values:[`space`],appliesTo:`any`,description:`Inside space: a space token, px, or four px values [top, right, bottom, left]. Counted inside width and height.`},{name:`margin`,type:`token`,values:[`space`],appliesTo:`any`,description:`Outside space: px (negative allowed), a space token, auto, or four values, each px or auto.`},{name:`align`,type:`enum`,values:[`start`,`center`,`end`,`stretch`,`baseline`],appliesTo:`any`,description:`Cross-axis alignment of the children; baseline lines text up on its baseline.`},{name:`alignSelf`,type:`enum`,values:[`start`,`center`,`end`,`stretch`,`baseline`],appliesTo:`any`,description:`The node's own cross-axis alignment.`},{name:`justify`,type:`enum`,values:[`start`,`center`,`end`,`between`,`around`],appliesTo:`any`,description:`Main-axis distribution of the children.`},{name:`wrap`,type:`boolean`,values:[],appliesTo:`any`,description:`Children wrap onto new lines.`},{name:`columns`,type:`list`,values:[],appliesTo:`any`,description:`Grid columns: a count of equal columns, or a list of px numbers and fr shares such as [120, 1fr, 30] (fr shares are strings).`},{name:`width`,type:`size`,values:[`fill`,`hug`],appliesTo:`any`,description:`px, fill (the space the parent gives), hug (the content) or a percent string such as 76%.`},{name:`height`,type:`size`,values:[`fill`,`hug`],appliesTo:`any`,description:`px, fill, hug or a percent string.`},{name:`minWidth`,type:`size`,values:[],appliesTo:`any`,description:`px or a percent string.`},{name:`maxWidth`,type:`size`,values:[],appliesTo:`any`,description:`px or a percent string.`},{name:`minHeight`,type:`size`,values:[],appliesTo:`any`,description:`px or a percent string.`},{name:`maxHeight`,type:`size`,values:[],appliesTo:`any`,description:`px or a percent string.`},{name:`grow`,type:`number`,values:[],appliesTo:`any`,description:`Share of the free space this node takes in a row or column.`},{name:`shrink`,type:`number`,values:[],appliesTo:`any`,description:`How much the node shrinks when space runs out; 0 keeps its size.`},{name:`position`,type:`enum`,values:[`absolute`],appliesTo:`any`,description:`absolute places the node at x and y over its parent box, out of the flow.`},{name:`x`,type:`number`,values:[],appliesTo:`any`,description:`Left offset in px when the parent layout is free or position is absolute.`},{name:`y`,type:`number`,values:[],appliesTo:`any`,description:`Top offset in px, by the same rule as x.`},{name:`zIndex`,type:`integer`,values:[],appliesTo:`any`,description:`Stacking order among siblings, -100 to 100.`},{name:`background`,type:`token`,values:[`color`],appliesTo:`any`,description:`A colour token, a gradient (gradient linear, radial or conic; angle; stops of color and at, a percent from 0 to 100), or a list of 2 to 4 layers, top first.`},{name:`border`,type:`object`,values:[],appliesTo:`any`,description:`width, color and style; width is px or four px values [top, right, bottom, left]; style is solid or dashed.`},{name:`radius`,type:`token`,values:[`radius`],appliesTo:`any`,description:`A radius token or px, or four values [top-left, top-right, bottom-right, bottom-left].`},{name:`shadow`,type:`token`,values:[`shadow`],appliesTo:`any`,description:`A shadow token; it is a CSS box-shadow, so spread works.`},{name:`opacity`,type:`number`,values:[],appliesTo:`any`,description:`0 to 1.`},{name:`blur`,type:`number`,values:[],appliesTo:`any`,description:`Blurs the node itself, in px.`},{name:`backdropBlur`,type:`number`,values:[],appliesTo:`any`,description:`Blurs what is behind the node (frosted glass), in px; give the node a translucent background.`},{name:`overflow`,type:`enum`,values:[`visible`,`hidden`,`scroll`],appliesTo:`any`,description:`What happens to content past the box.`},{name:`font`,type:`token`,values:[`font`],appliesTo:`any`,description:`A font token.`},{name:`text`,type:`token`,values:[`text`],appliesTo:`any`,description:`A type-scale token: size, line height, weight and letter spacing.`},{name:`color`,type:`token`,values:[`color`],appliesTo:`any`,description:`The text colour token.`},{name:`weight`,type:`number`,values:[],appliesTo:`any`,description:`Font weight; overrides the text token.`},{name:`textAlign`,type:`enum`,values:[`left`,`center`,`right`],appliesTo:`any`,description:`Text alignment.`},{name:`lineHeight`,type:`number`,values:[],appliesTo:`any`,description:`Line height; overrides the text token.`},{name:`letterSpacing`,type:`number`,values:[],appliesTo:`any`,description:`Letter spacing in px; overrides the text token.`},{name:`transform`,type:`enum`,values:[`none`,`uppercase`,`lowercase`],appliesTo:`any`,description:`Text case.`},{name:`nowrap`,type:`boolean`,values:[],appliesTo:`Text`,description:`Keeps the text on one line.`},{name:`ellipsis`,type:`boolean`,values:[],appliesTo:`Text`,description:`One line, cut with an ellipsis where it no longer fits.`},{name:`maxLines`,type:`integer`,values:[],appliesTo:`Text`,description:`Stops after this many lines, cut with an ellipsis.`}];export{e as default};
|