From f206e0f817a19d12bd8db7f9a9466c7adc809498 Mon Sep 17 00:00:00 2001 From: Justin Baur <19896123+justindbaur@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:41:47 -0500 Subject: [PATCH 1/2] Move Packages to Platform & KM (#11907) --- .github/renovate.json | 50 ++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/.github/renovate.json b/.github/renovate.json index c9cfd548956..0172403f0f1 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -41,16 +41,12 @@ }, { "matchPackageNames": [ - "@ngtools/webpack", "base64-loader", "buffer", "bufferutil", - "copy-webpack-plugin", "core-js", "css-loader", "html-loader", - "html-webpack-injector", - "html-webpack-plugin", "mini-css-extract-plugin", "ngx-infinite-scroll", "postcss", @@ -60,20 +56,15 @@ "sass-loader", "style-loader", "ts-loader", - "tsconfig-paths-webpack-plugin", "url", - "util", - "webpack", - "webpack-cli", - "webpack-dev-server", - "webpack-node-externals" + "util" ], "description": "Admin Console owned dependencies", "commitMessagePrefix": "[deps] AC:", "reviewers": ["team:team-admin-console-dev"] }, { - "matchPackageNames": ["@types/node-ipc", "node-ipc", "qrious"], + "matchPackageNames": ["qrious"], "description": "Auth owned dependencies", "commitMessagePrefix": "[deps] Auth:", "reviewers": ["team:team-auth-dev"] @@ -110,27 +101,43 @@ }, { "matchPackageNames": [ + "@babel/core", + "@babel/preset-env", "@electron/notarize", "@electron/rebuild", - "@types/argon2-browser", + "@ngtools/webpack", "@types/chrome", "@types/firefox-webext-browser", + "@types/glob", "@types/jquery", + "@types/lowdb", "@types/node", "@types/node-forge", - "argon2", - "argon2-browser", - "big-integer", + "@types/node-ipc", + "@yao-pkg", + "babel-loader", + "browserslist", + "copy-webpack-plugin", + "electron", "electron-builder", "electron-log", "electron-reload", "electron-store", "electron-updater", - "electron", + "html-webpack-injector", + "html-webpack-plugin", + "lowdb", "node-forge", + "node-ipc", + "pkg", "rxjs", + "tsconfig-paths-webpack-plugin", "type-fest", - "typescript" + "typescript", + "webpack", + "webpack-cli", + "webpack-dev-server", + "webpack-node-externals" ], "description": "Platform owned dependencies", "commitMessagePrefix": "[deps] Platform:", @@ -231,7 +238,6 @@ "@types/koa__router", "@types/koa-bodyparser", "@types/koa-json", - "@types/lowdb", "@types/lunr", "@types/node-fetch", "@types/proper-lockfile", @@ -244,18 +250,22 @@ "koa", "koa-bodyparser", "koa-json", - "lowdb", "lunr", "multer", "node-fetch", "open", - "pkg", "proper-lockfile", "qrcode-parser" ], "description": "Vault owned dependencies", "commitMessagePrefix": "[deps] Vault:", "reviewers": ["team:team-vault-dev"] + }, + { + "matchPackageNames": ["@types/argon2-browser", "argon2", "argon2-browser", "big-integer"], + "description": "Key Management owned dependencies", + "commitMessagePrefix": "[deps] KM:", + "reviewers": ["team:team-key-management-dev"] } ], "ignoreDeps": ["@types/koa-bodyparser", "bootstrap", "node-ipc", "node", "npm"] From e8dac0cc122d35d6a279fd64adda10b2df97e402 Mon Sep 17 00:00:00 2001 From: Victoria League Date: Thu, 7 Nov 2024 16:54:49 -0500 Subject: [PATCH 2/2] [CL-500] Add disclosure component and directive (#11865) --- .../disclosure-trigger-for.directive.ts | 27 +++++++++ .../src/disclosure/disclosure.component.ts | 21 +++++++ libs/components/src/disclosure/disclosure.mdx | 55 +++++++++++++++++++ .../src/disclosure/disclosure.stories.ts | 29 ++++++++++ libs/components/src/disclosure/index.ts | 2 + .../src/icon-button/icon-button.component.ts | 4 ++ .../src/icon-button/icon-button.mdx | 20 +++---- .../src/icon-button/icon-button.stories.ts | 8 +-- libs/components/src/index.ts | 1 + 9 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 libs/components/src/disclosure/disclosure-trigger-for.directive.ts create mode 100644 libs/components/src/disclosure/disclosure.component.ts create mode 100644 libs/components/src/disclosure/disclosure.mdx create mode 100644 libs/components/src/disclosure/disclosure.stories.ts create mode 100644 libs/components/src/disclosure/index.ts diff --git a/libs/components/src/disclosure/disclosure-trigger-for.directive.ts b/libs/components/src/disclosure/disclosure-trigger-for.directive.ts new file mode 100644 index 00000000000..05470281729 --- /dev/null +++ b/libs/components/src/disclosure/disclosure-trigger-for.directive.ts @@ -0,0 +1,27 @@ +import { Directive, HostBinding, HostListener, Input } from "@angular/core"; + +import { DisclosureComponent } from "./disclosure.component"; + +@Directive({ + selector: "[bitDisclosureTriggerFor]", + exportAs: "disclosureTriggerFor", + standalone: true, +}) +export class DisclosureTriggerForDirective { + /** + * Accepts template reference for a bit-disclosure component instance + */ + @Input("bitDisclosureTriggerFor") disclosure: DisclosureComponent; + + @HostBinding("attr.aria-expanded") get ariaExpanded() { + return this.disclosure.open; + } + + @HostBinding("attr.aria-controls") get ariaControls() { + return this.disclosure.id; + } + + @HostListener("click") click() { + this.disclosure.open = !this.disclosure.open; + } +} diff --git a/libs/components/src/disclosure/disclosure.component.ts b/libs/components/src/disclosure/disclosure.component.ts new file mode 100644 index 00000000000..58c67ad0f0e --- /dev/null +++ b/libs/components/src/disclosure/disclosure.component.ts @@ -0,0 +1,21 @@ +import { Component, HostBinding, Input, booleanAttribute } from "@angular/core"; + +let nextId = 0; + +@Component({ + selector: "bit-disclosure", + standalone: true, + template: ``, +}) +export class DisclosureComponent { + /** + * Optionally init the disclosure in its opened state + */ + @Input({ transform: booleanAttribute }) open?: boolean = false; + + @HostBinding("class") get classList() { + return this.open ? "" : "tw-hidden"; + } + + @HostBinding("id") id = `bit-disclosure-${nextId++}`; +} diff --git a/libs/components/src/disclosure/disclosure.mdx b/libs/components/src/disclosure/disclosure.mdx new file mode 100644 index 00000000000..8df8e7025b8 --- /dev/null +++ b/libs/components/src/disclosure/disclosure.mdx @@ -0,0 +1,55 @@ +import { Meta, Story, Primary, Controls } from "@storybook/addon-docs"; + +import * as stories from "./disclosure.stories"; + + + +```ts +import { DisclosureComponent, DisclosureTriggerForDirective } from "@bitwarden/components"; +``` + +# Disclosure + +The `bit-disclosure` component is used in tandem with the `bitDisclosureTriggerFor` directive to +create an accessible content area whose visibility is controlled by a trigger button. + +To compose a disclosure and trigger: + +1. Create a trigger component (see "Supported Trigger Components" section below) +2. Create a `bit-disclosure` +3. Set a template reference on the `bit-disclosure` +4. Use the `bitDisclosureTriggerFor` directive on the trigger component, and pass it the + `bit-disclosure` template reference +5. Set the `open` property on the `bit-disclosure` to init the disclosure as either currently + expanded or currently collapsed. The disclosure will default to `false`, meaning it defaults to + being hidden. + +``` + +click button to hide this content +``` + + + +
+
+ +## Supported Trigger Components + +This is the list of currently supported trigger components: + +- Icon button `muted` variant + +## Accessibility + +The disclosure and trigger directive functionality follow the +[Disclosure (Show/Hide)](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/) pattern for +accessibility, automatically handling the `aria-controls` and `aria-expanded` properties. A `button` +element must be used as the trigger for the disclosure. The `button` element must also have an +accessible label/title -- please follow the accessibility guidelines for whatever trigger component +you choose. diff --git a/libs/components/src/disclosure/disclosure.stories.ts b/libs/components/src/disclosure/disclosure.stories.ts new file mode 100644 index 00000000000..974589a667c --- /dev/null +++ b/libs/components/src/disclosure/disclosure.stories.ts @@ -0,0 +1,29 @@ +import { Meta, moduleMetadata, StoryObj } from "@storybook/angular"; + +import { IconButtonModule } from "../icon-button"; + +import { DisclosureTriggerForDirective } from "./disclosure-trigger-for.directive"; +import { DisclosureComponent } from "./disclosure.component"; + +export default { + title: "Component Library/Disclosure", + component: DisclosureComponent, + decorators: [ + moduleMetadata({ + imports: [DisclosureTriggerForDirective, DisclosureComponent, IconButtonModule], + }), + ], +} as Meta; + +type Story = StoryObj; + +export const DisclosureWithIconButton: Story = { + render: (args) => ({ + props: args, + template: /*html*/ ` + + click button to hide this content + `, + }), +}; diff --git a/libs/components/src/disclosure/index.ts b/libs/components/src/disclosure/index.ts new file mode 100644 index 00000000000..b5bdf68725f --- /dev/null +++ b/libs/components/src/disclosure/index.ts @@ -0,0 +1,2 @@ +export * from "./disclosure-trigger-for.directive"; +export * from "./disclosure.component"; diff --git a/libs/components/src/icon-button/icon-button.component.ts b/libs/components/src/icon-button/icon-button.component.ts index 54f6dfda963..d036e1c77ca 100644 --- a/libs/components/src/icon-button/icon-button.component.ts +++ b/libs/components/src/icon-button/icon-button.component.ts @@ -52,10 +52,14 @@ const styles: Record = { "tw-bg-transparent", "!tw-text-muted", "tw-border-transparent", + "aria-expanded:tw-bg-text-muted", + "aria-expanded:!tw-text-contrast", "hover:tw-bg-transparent-hover", "hover:tw-border-primary-700", "focus-visible:before:tw-ring-primary-700", "disabled:tw-opacity-60", + "aria-expanded:hover:tw-bg-secondary-700", + "aria-expanded:hover:tw-border-secondary-700", "disabled:hover:tw-border-transparent", "disabled:hover:tw-bg-transparent", ...focusRing, diff --git a/libs/components/src/icon-button/icon-button.mdx b/libs/components/src/icon-button/icon-button.mdx index 8361d4c3997..a45160d7884 100644 --- a/libs/components/src/icon-button/icon-button.mdx +++ b/libs/components/src/icon-button/icon-button.mdx @@ -29,8 +29,6 @@ Icon buttons can be found in other components such as: the [dialog](?path=/docs/component-library-dialogs--docs), and [table](?path=/docs/component-library-table--docs). - - ## Styles There are 4 common styles for button main, muted, contrast, and danger. The other styles follow the @@ -40,48 +38,48 @@ button component styles. Used for general icon buttons appearing on the theme’s main `background` - + ### Muted Used for low emphasis icon buttons appearing on the theme’s main `background` - + ### Contrast Used on a theme’s colored or contrasting backgrounds such as in the navigation or on toasts and banners. - + ### Danger Danger is used for “trash” actions throughout the experience, most commonly in the bottom right of the dialog component. - + ### Primary Used in place of the main button component if no text is used. This allows the button to display square. - + ### Secondary Used in place of the main button component if no text is used. This allows the button to display square. - + ### Light Used on a background that is dark in both light theme and dark theme. Example: end user navigation styles. - + **Note:** Main and contrast styles appear on backgrounds where using `primary-700` as a focus indicator does not meet WCAG graphic contrast guidelines. @@ -95,11 +93,11 @@ with less padding around the icon, such as in the navigation component. ### Small - + ### Default - + ## Accessibility diff --git a/libs/components/src/icon-button/icon-button.stories.ts b/libs/components/src/icon-button/icon-button.stories.ts index 0f25d2de583..b5542f78600 100644 --- a/libs/components/src/icon-button/icon-button.stories.ts +++ b/libs/components/src/icon-button/icon-button.stories.ts @@ -23,7 +23,7 @@ type Story = StoryObj; export const Default: Story = { render: (args) => ({ props: args, - template: ` + template: /*html*/ `
@@ -56,7 +56,7 @@ export const Small: Story = { export const Primary: Story = { render: (args) => ({ props: args, - template: ` + template: /*html*/ ` `, }), @@ -96,7 +96,7 @@ export const Muted: Story = { export const Light: Story = { render: (args) => ({ props: args, - template: ` + template: /*html*/ `
@@ -110,7 +110,7 @@ export const Light: Story = { export const Contrast: Story = { render: (args) => ({ props: args, - template: ` + template: /*html*/ `
diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index 6881d801e0f..810f32bdd3c 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -13,6 +13,7 @@ export * from "./chip-select"; export * from "./color-password"; export * from "./container"; export * from "./dialog"; +export * from "./disclosure"; export * from "./form-field"; export * from "./icon-button"; export * from "./icon";