diff --git a/commitlint.config.cjs b/commitlint.config.cjs
index 91021367..e4a33db7 100644
--- a/commitlint.config.cjs
+++ b/commitlint.config.cjs
@@ -36,6 +36,7 @@ module.exports = {
"calendar",
"table",
"split-button",
+ "tag",
"datepicker",
],
],
diff --git a/scripts/build.js b/scripts/build.js
index bd13ba52..ca3cf8f4 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -1,34 +1,46 @@
-import { context, build } from 'esbuild';
-import parseArgs from 'minimist';
-import CleanCSS from 'clean-css';
-import del from 'del';
-import { litCssPlugin } from 'esbuild-plugin-lit-css';
+import del from "del";
+import { context, build } from "esbuild";
+import parseArgs from "minimist";
+import CleanCSS from "clean-css";
+import { litCssPlugin } from "esbuild-plugin-lit-css";
const args = parseArgs(process.argv.slice(2), {
boolean: true,
});
(async () => {
- const { globby } = await import('globby');
- const destinationPath = 'dist';
+ const { globby } = await import("globby");
+ const destinationPath = "dist";
const isRelease = process.env.RELEASE || false;
/* This is for using inside Storybook for demonstration purposes. */
- const cssHoverClassAdder = (content) => content.replace(/.*:hover[^{]*/g, matched => {
- // Replace :hover with special class. (There will be additional classes for focus, etc. Should be implemented in here.)
- const replacedWithNewClass = matched.replace(/:hover/, '.__ONLY_FOR_STORYBOOK_DEMONSTRATION_HOVER__')
- // Concat strings
- return replacedWithNewClass.concat(', ', matched);
- });
-
- const cssCleaner = (content) => {
- const { styles, errors, warnings } = new CleanCSS({ level: 0 }).minify(content);
+ const cssHoverClassAdder = content =>
+ content.replace(/.*:hover[^{]*/g, matched => {
+ // Replace :hover with special class. (There will be additional classes for focus, etc. Should be implemented in here.)
+ const replacedWithNewClass = matched.replace(
+ /:hover/,
+ ".__ONLY_FOR_STORYBOOK_DEMONSTRATION_HOVER__"
+ );
+ // Concat strings
+ return replacedWithNewClass.concat(", ", matched);
+ });
+
+ const cssCleaner = content => {
+ const { styles, errors, warnings } = new CleanCSS({ level: 2 }).minify(content);
if (errors.length) {
- console.error(errors);
+ console.error({
+ errors,
+ styles: JSON.stringify(styles),
+ });
}
+
if (warnings.length) {
- console.warn(warnings);
+ console.warn({
+ warnings,
+ styles: JSON.stringify(styles),
+ });
}
+
return styles;
};
@@ -43,57 +55,53 @@ const args = parseArgs(process.argv.slice(2), {
const cssPluginOptions = {
filter: /components\/.*\.css$/,
- transform: (content) => cssTransformers.reduce((result, transformer) => transformer(result), content)
+ transform: content =>
+ cssTransformers.reduce((result, transformer) => transformer(result), content),
};
try {
const buildOptions = {
entryPoints: [
- 'src/baklava.ts',
- 'src/baklava-react.ts',
- 'src/localization.ts',
+ "src/baklava.ts",
+ "src/baklava-react.ts",
+ "src/localization.ts",
...(await globby([
- 'src/generated/**/*.ts',
- 'src/components/**/!(*.(test|d)).ts',
- 'src/themes/*.css',
- 'src/components/**/*.svg',
+ "src/generated/**/*.ts",
+ "src/components/**/!(*.(test|d)).ts",
+ "src/themes/*.css",
+ "src/components/**/*.svg",
])),
],
loader: {
- '.woff': 'file',
- '.woff2': 'file',
- '.svg': 'file',
+ ".woff": "file",
+ ".woff2": "file",
+ ".svg": "file",
},
outdir: destinationPath,
- assetNames: 'assets/[name]',
+ assetNames: "assets/[name]",
bundle: true,
sourcemap: true,
- format: 'esm',
- target: ['es2020', 'chrome73', 'edge79', 'firefox63', 'safari12'],
+ format: "esm",
+ target: ["es2020", "chrome73", "edge79", "firefox63", "safari12"],
splitting: true,
metafile: true,
minify: true,
- external: ['react'],
- plugins: [
- litCssPlugin(cssPluginOptions),
- ],
+ external: ["react"],
+ plugins: [litCssPlugin(cssPluginOptions)],
};
-
if (args.serve) {
- const servedir = 'playground';
+ const servedir = "playground";
let ctx = await context({
...buildOptions,
- outdir: `${servedir}/dist`
+ outdir: `${servedir}/dist`,
});
- const { host, port } = await ctx.serve(
- {
- servedir,
- host: 'localhost',
- }
- );
+ const { host, port } = await ctx.serve({
+ servedir,
+ host: "localhost",
+ });
console.log(`Playground is served on http://${host}:${port}`);
@@ -104,12 +112,12 @@ const args = parseArgs(process.argv.slice(2), {
if (errors.length > 0) {
console.table(errors);
- console.error('Build Failed!');
+ console.error("Build Failed!");
return;
}
if (warnings.length > 0) {
- console.warn('Warnings:');
+ console.warn("Warnings:");
console.table(warnings);
}
@@ -122,19 +130,19 @@ const args = parseArgs(process.argv.slice(2), {
.filter(
({ fileName }) =>
!/icon\/icons\/.*\.js/.test(fileName) &&
- (fileName.endsWith('.js') || fileName.endsWith('.css'))
+ (fileName.endsWith(".js") || fileName.endsWith(".css"))
);
analyzeResult.push({
- fileName: 'TOTAL',
+ fileName: "TOTAL",
size: `${(analyzeResult.reduce((acc, { bytes }) => acc + bytes, 0) / 1024).toFixed(2)} KB`,
- })
+ });
del(`${destinationPath}/components/icon/icons`);
- console.table(analyzeResult, ['fileName', 'size']);
+ console.table(analyzeResult, ["fileName", "size"]);
- console.info('Build Done!');
+ console.info("Build Done!");
} catch (error) {
console.error(error);
process.exit(1);
diff --git a/src/baklava.ts b/src/baklava.ts
index bbaddfb5..54d137c2 100644
--- a/src/baklava.ts
+++ b/src/baklava.ts
@@ -36,5 +36,6 @@ export { default as BlTableHeaderCell } from "./components/table/table-header-ce
export { default as BlTableCell } from "./components/table/table-cell/bl-table-cell";
export { default as BlSplitButton } from "./components/split-button/bl-split-button";
export { default as BlCalendar } from "./components/calendar/bl-calendar";
+export { default as BlTag } from "./components/tag/bl-tag";
export { default as BlDatePicker } from "./components/datepicker/bl-datepicker";
export { getIconPath, setIconPath } from "./utilities/asset-paths";
diff --git a/src/components/tag/bl-tag.css b/src/components/tag/bl-tag.css
new file mode 100644
index 00000000..87f0a70c
--- /dev/null
+++ b/src/components/tag/bl-tag.css
@@ -0,0 +1,97 @@
+:host {
+ display: inline-block;
+ max-width: 100%;
+}
+
+.tag {
+ --bg-color: var(--bl-color-neutral-full);
+ --color: var(--bl-color-neutral-darker);
+ --font: var(--bl-font-title-4-medium);
+ --padding-vertical: var(--bl-size-2xs);
+ --padding-horizontal: var(--bl-size-m);
+ --margin-icon: var(--bl-size-2xs);
+ --icon-size: var(--bl-size-m);
+ --height: var(--bl-size-2xl);
+ --border-radius: var(--bl-size-m);
+ --remove-icon-size: var(--bl-size-s);
+
+ display: flex;
+ gap: var(--margin-icon);
+ justify-content: center;
+ align-items: center;
+ box-sizing: border-box;
+ width: 100%;
+ border: 1px solid var(--bl-color-neutral-lighter);
+ border-radius: var(--border-radius);
+ padding-block: var(--padding-vertical);
+ padding-inline: var(--padding-horizontal);
+ background-color: var(--bg-color);
+ color: var(--color, white);
+ font: var(--font);
+ font-kerning: none;
+ height: var(--height);
+}
+
+:host([variant="selectable"]) .tag {
+ cursor: pointer;
+ user-select: none;
+}
+
+:host([variant="selectable"]) .tag:hover {
+ background-color: var(--bl-color-neutral-lightest);
+}
+
+:host([variant="selectable"][selected]) .tag {
+ border-color: var(--bl-color-neutral-darker);
+ background-color: var(--bl-color-neutral-darker);
+
+ --color: var(--bl-color-neutral-full);
+}
+
+
+:host([variant="selectable"][disabled]) .tag {
+ background-color: var(--bl-color-neutral-lightest);
+ border-color: var(--bl-color-neutral-lightest);
+ color: var(--bl-color-neutral-light);
+ cursor: not-allowed;
+}
+
+:host([variant="removable"]) .remove-button {
+ --bl-border-radius-m: var(--bl-border-radius-circle);
+}
+
+:host([size="small"]) .tag {
+ --font: var(--bl-font-title-4-medium);
+ --height: var(--bl-size-xl);
+ --icon-size: var(--bl-size-s);
+ --border-radius: var(--bl-size-xs);
+ --padding-vertical: 0px;
+ --padding-horizontal: var(--bl-size-2xs);
+ --remove-icon-size: var(--bl-size-xs);
+}
+
+:host([size="large"]) .tag {
+ --font: var(--bl-font-title-3-medium);
+ --padding-vertical: var(--bl-size-2xs);
+ --padding-horizontal: var(--bl-size-l);
+ --height: var(--bl-size-3xl);
+ --icon-size: var(--bl-size-m);
+ --border-radius: var(--bl-size-l);
+}
+
+:host([variant="removable"][size="small"]) .tag {
+ --padding-horizontal: var(--bl-size-2xs) 0px;
+}
+
+:host([variant="removable"]) .tag {
+ --padding-horizontal: var(--bl-size-m) var(--bl-size-3xs);
+}
+
+:host([variant="removable"][size="large"]) .tag {
+ --padding-horizontal: var(--bl-size-l) var(--bl-size-2xs);
+}
+
+slot[name="icon"] bl-icon {
+ font-size: var(--icon-size);
+ color: var(--color);
+}
diff --git a/src/components/tag/bl-tag.stories.mdx b/src/components/tag/bl-tag.stories.mdx
new file mode 100644
index 00000000..4f0cdec0
--- /dev/null
+++ b/src/components/tag/bl-tag.stories.mdx
@@ -0,0 +1,122 @@
+import { ArgsTable, Canvas, Meta, Story } from '@storybook/addon-docs';
+import { html } from 'lit';
+import { ifDefined } from 'lit/directives/if-defined.js';
+
+
+
+export const Template = (args) => html`
+