diff --git a/.changeset/rotten-numbers-explain.md b/.changeset/rotten-numbers-explain.md
new file mode 100644
index 000000000..824e4078b
--- /dev/null
+++ b/.changeset/rotten-numbers-explain.md
@@ -0,0 +1,5 @@
+---
+'@channel.io/bezier-tokens': minor
+---
+
+Add SCSS support to access design tokens directly through SCSS variables.
diff --git a/packages/bezier-react/src/styles/components/elevation.module.scss b/packages/bezier-react/src/styles/components/elevation.module.scss
index c28b6ef28..2ae0f3524 100644
--- a/packages/bezier-react/src/styles/components/elevation.module.scss
+++ b/packages/bezier-react/src/styles/components/elevation.module.scss
@@ -1,6 +1,7 @@
-$elevations: 1, 2, 3, 4, 5, 6;
+@use 'sass:map';
+@use '../../../../../node_modules/@channel.io/bezier-tokens/dist/scss' as *;
-@each $ev in $elevations {
+@each $ev in map.keys(map.get($tokens, 'light-theme', 'ev')) {
:where(.elevation-#{$ev}) {
/* stylelint-disable-next-line bezier/validate-token */
box-shadow: var(--ev-#{$ev});
diff --git a/packages/bezier-react/src/styles/components/radius.module.scss b/packages/bezier-react/src/styles/components/radius.module.scss
index 513950519..1d5e3b0fe 100644
--- a/packages/bezier-react/src/styles/components/radius.module.scss
+++ b/packages/bezier-react/src/styles/components/radius.module.scss
@@ -1,17 +1,7 @@
-$radiuses:
- 2,
- 3,
- 4,
- 6,
- 8,
- 12,
- 16,
- 20,
- 32,
- 44,
- 42-p;
+@use 'sass:map';
+@use '../../../../../node_modules/@channel.io/bezier-tokens/dist/scss' as *;
-@each $radius in $radiuses {
+@each $radius in map.keys(map.get($tokens, 'global', 'radius')) {
:where(.radius-#{$radius}) {
/* stylelint-disable-next-line bezier/validate-token */
border-radius: var(--radius-#{$radius});
diff --git a/packages/bezier-react/src/styles/components/z-index.module.scss b/packages/bezier-react/src/styles/components/z-index.module.scss
index 7d91189df..4e6702568 100644
--- a/packages/bezier-react/src/styles/components/z-index.module.scss
+++ b/packages/bezier-react/src/styles/components/z-index.module.scss
@@ -1,6 +1,7 @@
-$z-indices: hidden, base, floating, overlay, modal, toast, tooltip, important;
+@use 'sass:map';
+@use '../../../../../node_modules/@channel.io/bezier-tokens/dist/scss' as *;
-@each $z-index in $z-indices {
+@each $z-index in map.keys(map.get($tokens, 'global', 'z-index')) {
:where(.z-index-#{$z-index}) {
/* stylelint-disable-next-line bezier/validate-token */
z-index: var(--z-index-#{$z-index});
diff --git a/packages/bezier-tokens/README.md b/packages/bezier-tokens/README.md
index 4b8e6ee4e..306411788 100644
--- a/packages/bezier-tokens/README.md
+++ b/packages/bezier-tokens/README.md
@@ -10,29 +10,54 @@ npm i -D @channel.io/bezier-tokens
## Usage
-### JavaScript
+### CSS
-You can access and use values by token group.
+Provide all design tokens as CSS variables. If you want to apply dark theme tokens, add the `data-bezier-theme="dark"` attribute to the parent element. The default is light theme tokens, which can also be applied by adding the `data-bezier-theme="light"` attribute to the parent element.
```ts
-import { tokens } from '@channel.io/bezier-tokens'
+import '@channel.io/bezier-tokens/css/styles.css'
+```
-console.log(tokens.global.color['blue-300']) // "#..."
-console.log(tokens.lightTheme.color['bg-black-dark']) // "#..."
+```html
+
```
-### CSS
+```css
+.foo {
+ background-color: var(--bg-black-dark);
+}
+```
-Provide all design tokens as CSS variables. If you want to apply dark theme tokens, add the `data-bezier-theme="dark"` attribute to the parent element. The default is light theme tokens, which can also be applied by adding the `data-bezier-theme="light"` attribute to the parent element.
+### SCSS
-```ts
-import '@channel.io/bezier-tokens/css/styles.css'
+While CSS variables are recommended, you can also use SCSS variables directly if you need to.
+
+```scss
+@use "sass:map";
+@use "pkg:@channel.io/bezier-tokens" as *;
div {
- background: var(--bg-black-dark);
+ border-radius: map.get($tokens, "global", "radius", "4"); // ...px
+ background-color: map.get($tokens, "light-theme", "bg", "black", "dark"); // #...
}
```
+### JavaScript
+
+You can access and use values by token group.
+
+```ts
+import { tokens } from '@channel.io/bezier-tokens'
+
+console.log(tokens.global.color['blue-300']) // "#..."
+console.log(tokens.lightTheme.color['bg-black-dark']) // "#..."
+```
+
## Contributing
See [contribution guide](https://github.com/channel-io/bezier-react/wiki/Contribute).
diff --git a/packages/bezier-tokens/package.json b/packages/bezier-tokens/package.json
index 236b63396..7c8428f3f 100644
--- a/packages/bezier-tokens/package.json
+++ b/packages/bezier-tokens/package.json
@@ -19,7 +19,8 @@
"import": {
"types": "./dist/types/esm/index.d.mts",
"default": "./dist/esm/index.mjs"
- }
+ },
+ "sass": "./dist/scss/index.scss"
},
"./alpha": {
"require": {
@@ -29,10 +30,13 @@
"import": {
"types": "./dist/types/alpha/esm/index.d.mts",
"default": "./dist/alpha/esm/index.mjs"
- }
+ },
+ "sass": "./dist/alpha/scss/index.scss"
},
"./css/*": "./dist/css/*",
- "./alpha/css/*": "./dist/alpha/css/*"
+ "./scss/*": "./dist/scss/*",
+ "./alpha/css/*": "./dist/alpha/css/*",
+ "./alpha/scss/*": "./dist/alpha/scss/*"
},
"typesVersions": {
"*": {
@@ -42,7 +46,8 @@
}
},
"sideEffects": [
- "**/*.css"
+ "**/*.css",
+ "**/*.scss"
],
"files": [
"dist"
diff --git a/packages/bezier-tokens/scripts/build-scss-index.ts b/packages/bezier-tokens/scripts/build-scss-index.ts
new file mode 100644
index 000000000..d1a823550
--- /dev/null
+++ b/packages/bezier-tokens/scripts/build-scss-index.ts
@@ -0,0 +1,35 @@
+import fs from 'fs/promises'
+import path from 'path'
+
+interface BuildScssIndexOptions {
+ buildPath: string
+}
+
+export async function buildScssIndex({ buildPath }: BuildScssIndexOptions) {
+ const destination = path.join(buildPath, 'index.scss')
+
+ try {
+ const files = await fs.readdir(buildPath)
+ let useStatements = ''
+ let mapStatements = '$tokens: (\n'
+
+ for (const file of files.filter(
+ (file) => file.endsWith('.scss') && file !== path.basename(destination)
+ )) {
+ const moduleName = path.basename(file, '.scss')
+
+ useStatements += `@use './${moduleName}' as ${moduleName};\n`
+ mapStatements += ` "${moduleName}": ${moduleName}.$tokens,\n`
+ }
+
+ mapStatements += ');\n'
+
+ const result = `${useStatements}\n${mapStatements}`
+
+ await fs.writeFile(destination, result)
+
+ console.log(`\n✔︎ Created ${destination}`)
+ } catch (error) {
+ throw error
+ }
+}
diff --git a/packages/bezier-tokens/scripts/build-tokens.ts b/packages/bezier-tokens/scripts/build-tokens.ts
index 74758c1c3..26c99f5ed 100644
--- a/packages/bezier-tokens/scripts/build-tokens.ts
+++ b/packages/bezier-tokens/scripts/build-tokens.ts
@@ -6,6 +6,7 @@ import StyleDictionary, {
} from 'style-dictionary'
import { buildJsIndex } from './build-js-index'
+import { buildScssIndex } from './build-scss-index'
import {
alphaCustomCss,
alphaCustomJsCjs,
@@ -14,6 +15,7 @@ import {
customJsEsm,
} from './lib/format'
import { CSSTransforms } from './lib/transform'
+import { toKebabCase } from './lib/utils'
import { mergeCss } from './merge-css'
const CustomTransforms = [...Object.values(CSSTransforms)]
@@ -24,6 +26,7 @@ const BUILD_PATH = {
CJS: 'cjs',
ESM: 'esm',
CSS: 'css',
+ SCSS: 'scss',
}
const TokenBuilder = CustomTransforms.reduce(
@@ -125,6 +128,21 @@ function defineConfig({
],
transforms,
}),
+ 'web/scss': defineWebPlatform({
+ buildPath: `${basePath}/${BUILD_PATH.SCSS}/`,
+ files: [
+ {
+ destination: `${toKebabCase(destination)}.scss`,
+ format: 'scss/map-deep',
+ filter: ({ filePath }) =>
+ source.some((src) => minimatch(filePath, src)),
+ options: {
+ outputReferences: false,
+ },
+ },
+ ],
+ transforms,
+ }),
},
}
}
@@ -209,6 +227,13 @@ async function main() {
await mergeCss(buildPath)
}
+ for (const buildPath of [
+ `${BUILD_PATH.BASE}/${BUILD_PATH.SCSS}`,
+ `${BUILD_PATH.BASE_ALPHA}/${BUILD_PATH.SCSS}`,
+ ]) {
+ await buildScssIndex({ buildPath })
+ }
+
for (const options of [
{ buildPath: `${BUILD_PATH.BASE}/${BUILD_PATH.CJS}`, isCjs: true },
{ buildPath: `${BUILD_PATH.BASE_ALPHA}/${BUILD_PATH.CJS}`, isCjs: true },
diff --git a/packages/bezier-tokens/scripts/lib/utils.ts b/packages/bezier-tokens/scripts/lib/utils.ts
index c2ae222ed..6bc793d20 100644
--- a/packages/bezier-tokens/scripts/lib/utils.ts
+++ b/packages/bezier-tokens/scripts/lib/utils.ts
@@ -6,6 +6,9 @@ export const toCamelCase = (str: string) =>
.toLowerCase()
.replace(/[^a-zA-Z0-9]+(.)/g, (_, char) => char.toUpperCase())
+export const toKebabCase = (str: string) =>
+ str.replace(/([A-Z])/g, '-$1').toLowerCase()
+
export const extractNumber = (str: string) =>
str.match(/-?\d+(\.\d+)?/g)?.join('')