Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add theme ai #114

Merged
merged 3 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion packages/less-plugin-dls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ With [less-loader](https://github.com/webpack-contrib/less-loader):
```less
@import "~less-plugin-dls/tokens/index.less";

a { color: @dls-link-font-color-normal; }
a {
color: @dls-link-font-color-normal;
}
```

### Use CLI argument
Expand All @@ -41,6 +43,29 @@ a { color: @dls-link-font-color-normal; }
lessc style.less --dls
```

## Using metadata

Variable values/metadata are provided in three formats for each theme.

| File | Description |
| -- | -- |
| `variables.js` | The raw variable values in JavaScript ESM format. Token names are transformed from `@dls-color-brand-7` to `dlsColorBrand7` as named exports. |
| `variables.json` | The raw variable values in JSON format. |
| `variables.less` | The variable values in Less format. |

```ts
// types for the JSON format:
interface Variables {
[tokenName: string]: {
value: string
type: 'color' | 'font' | 'numeric' | 'length' | 'complex'
global: boolean
}
}
```

There are also themed versions of the above files, which are named with the theme name as the suffix, namely `variables.<theme>.js`, `variables.<theme>.json` and `variables.<theme>.less`. Currently the only supported theme is `ai`.

## Custom functions

### `dls-contextual(@color, @type)`
Expand Down Expand Up @@ -138,6 +163,10 @@ The absolute length of the line-height.

## Options

### `theme: 'ai' | undefined`

The theme of the DLS. If not specified, the default theme will be used.

### `reduceCalc: boolean`

Indicates whether to reduce `calc` expression to the simplest form or not.
Expand Down
15 changes: 12 additions & 3 deletions packages/less-plugin-dls/lib/utils/evaluate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@ import { VariablesOutputVisitor } from './visitors'
const SELECTOR = 'DLS_VARS'

export async function getVariables(path) {
if (!fs.existsSync(path)) {
return []
}

const visitor = new VariablesOutputVisitor()

await less.render(fs.readFileSync(path, 'utf-8'), {
filename: path,
plugins: [
dls({
inject: false
Expand All @@ -25,15 +30,15 @@ export async function getVariables(path) {
return visitor.variables.map((v) => v.slice(1))
}

export async function getTuples(variables) {
export async function getTuples(variables, { theme }) {
const src = [
`${SELECTOR}{`,
variables.map((v) => `${v}: @${v}`).join(';'),
dedupe(variables).map((v) => `${v}: @${v}`).join(';'),
'}'
].join('')

const { css } = await less.render(src, {
plugins: [dls()]
plugins: [dls({ theme })]
})

return css
Expand All @@ -43,3 +48,7 @@ export async function getTuples(variables) {
.filter((v) => v)
.map((decl) => decl.split(/:\s*/))
}

function dedupe (arr) {
return Array.from(new Set(arr))
}
24 changes: 17 additions & 7 deletions packages/less-plugin-dls/scripts/vars.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,27 @@ import camelCase from 'lodash.camelcase'
import { parse } from 'postcss-values-parser'
import { getVariables, getTuples } from '../lib/utils/evaluate'

async function generate() {
async function generate({ theme } = {}) {
try {
const allVariables = await getVariables('./tokens/index.less')
const globalVariables = await getVariables('./tokens/global.less')
const themeVariables = await getVariables(`./tokens/themes/${theme}.less`)

const tuples = await getTuples(allVariables)
const tuples = await getTuples(allVariables.concat(themeVariables), {
theme
})

const themeTail = theme ? `.${theme}` : ''

// generate variables.less
fs.writeFileSync(
path.resolve(__dirname, '..', 'variables.less'),
path.resolve(__dirname, '..', `variables${themeTail}.less`),
tuples.map(([key, value]) => `@${key}: ${value};`).join('\n') + '\n',
'utf8'
)

fs.writeFileSync(
path.resolve(__dirname, '..', 'variables.js'),
path.resolve(__dirname, '..', `variables${themeTail}.js`),
tuples
.map(([key, value]) => `export const ${camelCase(key)} = '${value}'`)
.join('\n') + '\n',
Expand All @@ -28,7 +33,7 @@ async function generate() {

// generate variables.json
fs.writeFileSync(
path.resolve(__dirname, '..', 'variables.json'),
path.resolve(__dirname, '..', `variables${themeTail}.json`),
JSON.stringify(
tuples
.map(([key, value]) => ({
Expand All @@ -48,7 +53,7 @@ async function generate() {
'utf8'
)

console.log(`${tuples.length} variables generated.`)
console.log(`${tuples.length} variables generated for theme [${theme || 'default'}].`)
} catch (e) {
console.error(e)
}
Expand Down Expand Up @@ -129,4 +134,9 @@ function getTypeByValue(value) {
return 'unknown'
}

generate()
async function run() {
await generate()
await generate({ theme: 'ai' })
}

run()
25 changes: 22 additions & 3 deletions packages/less-plugin-dls/src/inject.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import path from 'path'
import fs from 'fs'

const SELF_MODULE_PATH = path.resolve(__dirname, '..')
const ENTRY_LESS = path.resolve(__dirname, '../tokens/index.less')
const THEME_DIR = path.resolve(__dirname, '../tokens/themes')

class Injector {
constructor ({ theme }) {
this.theme = theme
}

process(src, extra) {
// Don't inject self
if (
Expand All @@ -19,11 +25,24 @@ class Injector {
path.dirname(extra.fileInfo.filename),
ENTRY_LESS
)

const themeLess = path.resolve(THEME_DIR, `${this.theme}.less`)
let themeRelative = fs.existsSync(themeLess) ? path.relative(
path.dirname(extra.fileInfo.filename),
themeLess
) : null

// less requires relative path to starts with ./
if (relative.charAt(0) !== '.') {
relative = `./${relative}`
}
const injected = `@import "${relative}";\n`
if (themeRelative && themeRelative.charAt(0) !== '.') {
themeRelative = `./${themeRelative}`
}

let injected = `@import "${relative}";\n`
injected += themeRelative ? `@import "${themeRelative}";\n` : ''

const ignored = extra.imports.contentsIgnoredChars
const fileInfo = extra.fileInfo
ignored[fileInfo.filename] = ignored[fileInfo.filename] || 0
Expand All @@ -33,9 +52,9 @@ class Injector {
}

export default function inject(_, pluginManager) {
const { inject = true } = this.options || {}
const { inject = true, theme } = this.options || {}

if (inject) {
pluginManager.addPreProcessor(new Injector())
pluginManager.addPreProcessor(new Injector({ theme }))
}
}
18 changes: 12 additions & 6 deletions packages/less-plugin-dls/test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const INCLUDE_PATH = path.resolve(__dirname, '../src')
const SPEC_DIR = path.resolve(__dirname, 'specs')
const SRC_DIR = path.resolve(__dirname, '../tokens')
const SRC_COMPONENTS_DIR = path.resolve(SRC_DIR, 'components')
const MANUAL_SPEC_MODULES = ['functions', 'global']
const MANUAL_SPEC_MODULES = ['functions', 'global', 'ai']
const VAR_DEF_RE = /@([a-z]+(?:-[a-z0-9]+)*)\s*:/g

function extractVarDefs (file) {
Expand Down Expand Up @@ -114,11 +114,16 @@ function getTests () {
}

const specFile = path.resolve(moduleDir, partFile)
if (args['--update-snapshots']) {
const srcFile = !MANUAL_SPEC_MODULES.includes(module)
? path.resolve(SRC_COMPONENTS_DIR, module + '.less')
: module === 'global' ? path.resolve(SRC_DIR, 'global.less') : null

const srcFile = !MANUAL_SPEC_MODULES.includes(module)
? path.resolve(SRC_COMPONENTS_DIR, module + '.less')
: module === 'global'
? path.resolve(SRC_DIR, 'global.less')
: module === 'ai'
? path.resolve(SRC_DIR, 'themes/ai.less')
: null

if (args['--update-snapshots']) {
if (srcFile) {
const vars = extractVarDefs(srcFile)
if (vars.length) {
Expand All @@ -138,6 +143,7 @@ function getTests () {
module,
part,
src,
theme: module === 'ai' ? 'ai' : null,
expected
})
}
Expand Down Expand Up @@ -165,7 +171,7 @@ function getSuite (name, tests, { less }) {
.render(test.src, {
paths: [INCLUDE_PATH],
javascriptEnabled: true,
plugins: [dls()]
plugins: [dls({ theme: test.theme })]
})
.then(
result => {
Expand Down
46 changes: 46 additions & 0 deletions packages/less-plugin-dls/test/specs/ai/ai.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
div {
-dls-color-brand: #4d79ff;
-dls-color-brand-0: #fff;
-dls-color-brand-1: #f2f7ff;
-dls-color-brand-2: #e3edff;
-dls-color-brand-3: #c4daff;
-dls-color-brand-4: #99beff;
-dls-color-brand-5: #729cfe;
-dls-color-brand-6: #4d79ff;
-dls-color-brand-7: #3a5bfd;
-dls-color-brand-8: #333fe6;
-dls-color-brand-9: #0f2dbd;
-dls-color-brand-10: #1c244a;
-dls-color-brand-11: #000;
-dls-color-info: #4d79ff;
-dls-color-info-0: #fff;
-dls-color-info-1: #f2f7ff;
-dls-color-info-2: #e3edff;
-dls-color-info-3: #c4daff;
-dls-color-info-4: #99beff;
-dls-color-info-5: #729cfe;
-dls-color-info-6: #4d79ff;
-dls-color-info-7: #3a5bfd;
-dls-color-info-8: #333fe6;
-dls-color-info-9: #0f2dbd;
-dls-color-info-10: #1c244a;
-dls-color-info-11: #000;
-dls-color-success: #3ac222;
-dls-color-warning: #fea800;
-dls-color-error: #f53f3f;
-dls-height-xs: 28px;
-dls-height-s: 32px;
-dls-height-m: 36px;
-dls-height-l: 40px;
-dls-height-xl: 48px;
-dls-border-radius-0: 4px;
-dls-border-radius-1: 6px;
-dls-border-radius-2: 10px;
-dls-border-radius-3: 16px;
-dls-border-radius-4: 26px;
-dls-shadow-color: #0047c2;
-dls-checkbox-border-radius: 4px;
-dls-tag-color-turquoise: #00bbd1;
-dls-tag-color-violet: #824fe7;
-dls-tag-color-green: #3ac222;
}
46 changes: 46 additions & 0 deletions packages/less-plugin-dls/test/specs/ai/ai.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
div {
-dls-color-brand: @dls-color-brand;
-dls-color-brand-0: @dls-color-brand-0;
-dls-color-brand-1: @dls-color-brand-1;
-dls-color-brand-2: @dls-color-brand-2;
-dls-color-brand-3: @dls-color-brand-3;
-dls-color-brand-4: @dls-color-brand-4;
-dls-color-brand-5: @dls-color-brand-5;
-dls-color-brand-6: @dls-color-brand-6;
-dls-color-brand-7: @dls-color-brand-7;
-dls-color-brand-8: @dls-color-brand-8;
-dls-color-brand-9: @dls-color-brand-9;
-dls-color-brand-10: @dls-color-brand-10;
-dls-color-brand-11: @dls-color-brand-11;
-dls-color-info: @dls-color-info;
-dls-color-info-0: @dls-color-info-0;
-dls-color-info-1: @dls-color-info-1;
-dls-color-info-2: @dls-color-info-2;
-dls-color-info-3: @dls-color-info-3;
-dls-color-info-4: @dls-color-info-4;
-dls-color-info-5: @dls-color-info-5;
-dls-color-info-6: @dls-color-info-6;
-dls-color-info-7: @dls-color-info-7;
-dls-color-info-8: @dls-color-info-8;
-dls-color-info-9: @dls-color-info-9;
-dls-color-info-10: @dls-color-info-10;
-dls-color-info-11: @dls-color-info-11;
-dls-color-success: @dls-color-success;
-dls-color-warning: @dls-color-warning;
-dls-color-error: @dls-color-error;
-dls-height-xs: @dls-height-xs;
-dls-height-s: @dls-height-s;
-dls-height-m: @dls-height-m;
-dls-height-l: @dls-height-l;
-dls-height-xl: @dls-height-xl;
-dls-border-radius-0: @dls-border-radius-0;
-dls-border-radius-1: @dls-border-radius-1;
-dls-border-radius-2: @dls-border-radius-2;
-dls-border-radius-3: @dls-border-radius-3;
-dls-border-radius-4: @dls-border-radius-4;
-dls-shadow-color: @dls-shadow-color;
-dls-checkbox-border-radius: @dls-checkbox-border-radius;
-dls-tag-color-turquoise: @dls-tag-color-turquoise;
-dls-tag-color-violet: @dls-tag-color-violet;
-dls-tag-color-green: @dls-tag-color-green;
}
Loading