diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..95b961d530 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,31 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Jest All", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["--runInBand"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + }, + { + "type": "node", + "request": "launch", + "name": "Jest Current File", + "program": "${workspaceFolder}/node_modules/.bin/jest", + "args": ["${fileBasenameNoExtension}", "--config", "jest.config.js"], + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + } + } + ] +} diff --git a/jest.config.js b/jest.config.js index 493e624271..cfec042088 100644 --- a/jest.config.js +++ b/jest.config.js @@ -15,6 +15,7 @@ module.exports = { "/libs/angular/jest.config.js", "/libs/common/jest.config.js", + "/libs/components/jest.config.js", "/libs/electron/jest.config.js", "/libs/node/jest.config.js", ], diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index e5c4c5cb13..2acd60765f 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -7,6 +7,7 @@ export * from "./icon"; export * from "./menu"; export * from "./dialog"; export * from "./submit-button"; +export * from "./link"; export * from "./tabs"; export * from "./toggle-group"; export * from "./utils/i18n-mock.service"; diff --git a/libs/components/src/link/index.ts b/libs/components/src/link/index.ts new file mode 100644 index 0000000000..480f5396de --- /dev/null +++ b/libs/components/src/link/index.ts @@ -0,0 +1,2 @@ +export * from "./link.directive"; +export * from "./link.module"; diff --git a/libs/components/src/link/link.directive.ts b/libs/components/src/link/link.directive.ts new file mode 100644 index 0000000000..d4ae14058e --- /dev/null +++ b/libs/components/src/link/link.directive.ts @@ -0,0 +1,54 @@ +import { Input, HostBinding, Directive } from "@angular/core"; + +export type LinkType = "primary" | "secondary" | "contrast"; + +const linkStyles: Record = { + primary: [ + "!tw-text-primary-500", + "hover:!tw-text-primary-500", + "focus-visible:tw-ring-primary-700", + "disabled:!tw-text-primary-500/60", + ], + secondary: [ + "!tw-text-main", + "hover:!tw-text-main", + "focus-visible:tw-ring-primary-700", + "disabled:!tw-text-muted/60", + ], + contrast: [ + "!tw-text-contrast", + "hover:!tw-text-contrast", + "focus-visible:tw-ring-text-contrast", + "disabled:!tw-text-contrast/60", + ], +}; + +@Directive({ + selector: "button[bitLink], a[bitLink]", +}) +export class LinkDirective { + @HostBinding("class") get classList() { + return [ + "tw-font-semibold", + "tw-py-0.5", + "tw-px-0", + "tw-bg-transparent", + "tw-border-0", + "tw-border-none", + "tw-rounded", + "tw-transition", + "hover:tw-underline", + "hover:tw-decoration-1", + "focus-visible:tw-outline-none", + "focus-visible:tw-underline", + "focus-visible:tw-decoration-1", + "focus-visible:tw-ring-2", + "focus-visible:tw-z-10", + "disabled:tw-no-underline", + "disabled:tw-cursor-not-allowed", + ].concat(linkStyles[this.linkType] ?? []); + } + + @Input() + linkType: LinkType = "primary"; +} diff --git a/libs/components/src/link/link.module.ts b/libs/components/src/link/link.module.ts new file mode 100644 index 0000000000..73e78edf78 --- /dev/null +++ b/libs/components/src/link/link.module.ts @@ -0,0 +1,11 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; + +import { LinkDirective } from "./link.directive"; + +@NgModule({ + imports: [CommonModule], + exports: [LinkDirective], + declarations: [LinkDirective], +}) +export class LinkModule {} diff --git a/libs/components/src/link/link.stories.ts b/libs/components/src/link/link.stories.ts new file mode 100644 index 0000000000..5c7b11fe35 --- /dev/null +++ b/libs/components/src/link/link.stories.ts @@ -0,0 +1,93 @@ +import { Meta, Story } from "@storybook/angular"; + +import { LinkDirective } from "./link.directive"; + +export default { + title: "Component Library/Link", + component: LinkDirective, + argTypes: { + linkType: { + options: ["primary", "secondary", "contrast"], + control: { type: "radio" }, + }, + }, + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17419", + }, + }, +} as Meta; + +const ButtonTemplate: Story = (args: LinkDirective) => ({ + props: args, + template: ` +
+ + + + +
+ `, +}); + +const AnchorTemplate: Story = (args: LinkDirective) => ({ + props: args, + template: ` + + `, +}); + +export const Buttons = ButtonTemplate.bind({}); +Buttons.args = { + linkType: "primary", +}; + +export const Anchors = AnchorTemplate.bind({}); +Anchors.args = { + linkType: "primary", +}; + +const DisabledTemplate: Story = (args) => ({ + props: args, + template: ` + + +
+ +
+ `, +}); + +export const Disabled = DisabledTemplate.bind({}); +Disabled.parameters = { + controls: { + exclude: ["linkType"], + hideNoControlsWarning: true, + }, +}; diff --git a/libs/components/src/tabs/tab-item.component.ts b/libs/components/src/tabs/tab-item.component.ts index b8fb7a1e2b..aa339b713e 100644 --- a/libs/components/src/tabs/tab-item.component.ts +++ b/libs/components/src/tabs/tab-item.component.ts @@ -29,8 +29,8 @@ export class TabItemComponent { "focus-visible:tw-outline-none", "focus-visible:tw-ring-2", "focus-visible:tw-ring-primary-700", - "disabled:tw-bg-secondary-100", - "disabled:!tw-text-muted", + "disabled:tw-bg-transparent", + "disabled:!tw-text-muted/60", "disabled:tw-no-underline", "disabled:tw-cursor-not-allowed", ]; diff --git a/libs/components/src/tw-theme.css b/libs/components/src/tw-theme.css index d41b331d4a..3801dd2e9e 100644 --- a/libs/components/src/tw-theme.css +++ b/libs/components/src/tw-theme.css @@ -1,35 +1,35 @@ :root { - --color-background: #ffffff; - --color-background-alt: #fbfbfb; - --color-background-alt2: #175ddc; + --color-background: 255 255 255; + --color-background-alt: 251 251 251; + --color-background-alt2: 23 92 219; - --color-primary-300: #6795e8; - --color-primary-500: #175ddc; - --color-primary-700: #1252a3; + --color-primary-300: 103 149 232; + --color-primary-500: 23 93 220; + --color-primary-700: 18 82 163; - --color-secondary-100: #f0f0f0; - --color-secondary-300: #ced4dc; - --color-secondary-500: #89929f; - --color-secondary-700: #212529; + --color-secondary-100: 240 240 240; + --color-secondary-300: 206 212 220; + --color-secondary-500: 137 146 159; + --color-secondary-700: 33 37 41; - --color-success-500: #017e45; - --color-success-700: #00552e; + --color-success-500: 1 126 69; + --color-success-700: 0 85 46; - --color-danger-500: #c83522; - --color-danger-700: #98291b; + --color-danger-500: 200 53 34; + --color-danger-700: 152 41 27; - --color-warning-500: #8b6609; - --color-warning-700: #694d05; + --color-warning-500: 139 102 9; + --color-warning-700: 105 77 5; - --color-info-500: #555555; - --color-info-700: #3b3a3a; + --color-info-500: 85 85 85; + --color-info-700: 59 58 58; - --color-text-main: #212529; - --color-text-muted: #6d757e; - --color-text-contrast: #ffffff; - --color-text-alt2: #ffffff; + --color-text-main: 33 37 41; + --color-text-muted: 109 117 126; + --color-text-contrast: 255 255 255; + --color-text-alt2: 255 255 255; - --tw-ring-offset-color: #fff; + --tw-ring-offset-color: #ffffff; } .theme_light { @@ -37,35 +37,35 @@ } .theme_dark { - --color-background: #1f242e; - --color-background-alt: #161c26; - --color-background-alt2: #2f343d; + --color-background: 31 36 46; + --color-background-alt: 22 28 38; + --color-background-alt2: 47 52 61; - --color-primary-300: #175ddc; - --color-primary-500: #6a99f0; - --color-primary-700: #b4ccf9; + --color-primary-300: 23 93 220; + --color-primary-500: 106 153 240; + --color-primary-700: 180 204 249; - --color-secondary-100: #2f343d; - --color-secondary-300: #6e7689; - --color-secondary-500: #bac0ce; - --color-secondary-700: #ffffff; + --color-secondary-100: 47 52 61; + --color-secondary-300: 110 118 137; + --color-secondary-500: 186 192 206; + --color-secondary-700: 255 255 255; - --color-success-500: #52e07c; - --color-success-700: #a8efbe; + --color-success-500: 82 224 124; + --color-success-700: 168 239 190; - --color-danger-500: #ff8d85; - --color-danger-700: #ffbfbb; + --color-danger-500: 255 141 133; + --color-danger-700: 255 191 187; - --color-warning-500: #ffeb66; - --color-warning-700: #fff5b3; + --color-warning-500: 255 235 102; + --color-warning-700: 255 245 179; - --color-info-500: #a4b0c6; - --color-info-700: #d1d7e2; + --color-info-500: 164 176 198; + --color-info-700: 209 215 226; - --color-text-main: #ffffff; - --color-text-muted: #bac0ce; - --color-text-contrast: #191e26; - --color-text-alt2: #ffffff; + --color-text-main: 255 255 255; + --color-text-muted: 186 192 206; + --color-text-contrast: 25 30 38; + --color-text-alt2: 255 255 255; --tw-ring-offset-color: #1f242e; } diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index dff31e69db..0ebf0e309a 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -1,6 +1,10 @@ /* eslint-disable */ const colors = require("tailwindcss/colors"); +function rgba(color) { + return "rgb(var(" + color + ") / )"; +} + module.exports = { prefix: "tw-", content: ["./src/**/*.{html,ts}", "../../libs/components/src/**/*.{html,ts}"], @@ -12,57 +16,57 @@ module.exports = { current: colors.current, black: colors.black, primary: { - 300: "var(--color-primary-300)", - 500: "var(--color-primary-500)", - 700: "var(--color-primary-700)", + 300: rgba("--color-primary-300"), + 500: rgba("--color-primary-500"), + 700: rgba("--color-primary-700"), }, secondary: { - 100: "var(--color-secondary-100)", - 300: "var(--color-secondary-300)", - 500: "var(--color-secondary-500)", - 700: "var(--color-secondary-700)", + 100: rgba("--color-secondary-100"), + 300: rgba("--color-secondary-300"), + 500: rgba("--color-secondary-500"), + 700: rgba("--color-secondary-700"), }, success: { - 500: "var(--color-success-500)", - 700: "var(--color-success-700)", + 500: rgba("--color-success-500"), + 700: rgba("--color-success-700"), }, danger: { - 500: "var(--color-danger-500)", - 700: "var(--color-danger-700)", + 500: rgba("--color-danger-500"), + 700: rgba("--color-danger-700"), }, warning: { - 500: "var(--color-warning-500)", - 700: "var(--color-warning-700)", + 500: rgba("--color-warning-500"), + 700: rgba("--color-warning-700"), }, info: { - 500: "var(--color-info-500)", - 700: "var(--color-info-700)", + 500: rgba("--color-info-500"), + 700: rgba("--color-info-700"), }, text: { - main: "var(--color-text-main)", - muted: "var(--color-text-muted)", - contrast: "var(--color-text-contrast)", - alt2: "var(--color-text-alt2)", + main: rgba("--color-text-main"), + muted: rgba("--color-text-muted"), + contrast: rgba("--color-text-contrast"), + alt2: rgba("--color-text-alt2"), }, background: { - DEFAULT: "var(--color-background)", - alt: "var(--color-background-alt)", - alt2: "var(--color-background-alt2)", + DEFAULT: rgba("--color-background"), + alt: rgba("--color-background-alt"), + alt2: rgba("--color-background-alt2"), }, }, textColor: { - main: "var(--color-text-main)", - muted: "var(--color-text-muted)", - contrast: "var(--color-text-contrast)", - alt2: "var(--color-text-alt2)", - success: "var(--color-success-500)", - danger: "var(--color-danger-500)", - warning: "var(--color-warning-500)", - info: "var(--color-info-500)", + main: rgba("--color-text-main"), + muted: rgba("--color-text-muted"), + contrast: rgba("--color-text-contrast"), + alt2: rgba("--color-text-alt2"), + success: rgba("--color-success-500"), + danger: rgba("--color-danger-500"), + warning: rgba("--color-warning-500"), + info: rgba("--color-info-500"), primary: { - 300: "var(--color-primary-300)", - 500: "var(--color-primary-500)", - 700: "var(--color-primary-700)", + 300: rgba("--color-primary-300"), + 500: rgba("--color-primary-500"), + 700: rgba("--color-primary-700"), }, }, ringOffsetColor: ({ theme }) => ({ diff --git a/package.json b/package.json index 7a4f6e34ab..82e67080c1 100644 --- a/package.json +++ b/package.json @@ -204,5 +204,8 @@ "engines": { "node": "~16", "npm": "~8" + }, + "jest": { + "testEnvironment": "node" } }