@kaizen/components 0.0.0-canary-button-codemod-canary-20250212054517 → 0.0.0-canary-stacking-context-fix-20250225001220

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/bin/codemod.sh +0 -2
  2. package/codemods/README.md +0 -45
  3. package/codemods/utils/createProp.spec.ts +19 -75
  4. package/codemods/utils/createProp.ts +1 -8
  5. package/codemods/utils/getKaioTagName.ts +5 -13
  6. package/codemods/utils/index.ts +0 -1
  7. package/dist/cjs/Filter/FilterBar/subcomponents/FilterBarButton/FilterBarButton.cjs +1 -0
  8. package/dist/cjs/Filter/FilterMultiSelect/subcomponents/Trigger/FilterTriggerButton/FilterTriggerButton.cjs +1 -0
  9. package/dist/cjs/Filter/FilterMultiSelect/subcomponents/Trigger/RemovableFilterTrigger/RemovableFilterTrigger.cjs +1 -0
  10. package/dist/cjs/index.cjs +2 -0
  11. package/dist/esm/Filter/FilterBar/subcomponents/FilterBarButton/FilterBarButton.mjs +1 -0
  12. package/dist/esm/Filter/FilterMultiSelect/subcomponents/Trigger/FilterTriggerButton/FilterTriggerButton.mjs +1 -0
  13. package/dist/esm/Filter/FilterMultiSelect/subcomponents/Trigger/RemovableFilterTrigger/RemovableFilterTrigger.mjs +1 -0
  14. package/dist/esm/index.mjs +1 -0
  15. package/dist/styles.css +8647 -8640
  16. package/dist/types/Filter/FilterBar/subcomponents/FilterBarButton/FilterBarButton.d.ts +1 -1
  17. package/dist/types/Filter/FilterButton/index.d.ts +1 -0
  18. package/dist/types/Filter/FilterMultiSelect/types.d.ts +2 -1
  19. package/dist/types/RichTextEditor/utils/commands/fixtures/helpers.d.ts +0 -1
  20. package/dist/types/RichTextEditor/utils/commands/fixtures/index.d.ts +2 -0
  21. package/dist/types/RichTextEditor/utils/commands/fixtures/mockRangeForBoundingRect.d.ts +1 -0
  22. package/dist/types/__rc__/Icon/constants.d.ts +1 -1
  23. package/package.json +6 -1
  24. package/src/Filter/FilterButton/index.ts +1 -0
  25. package/src/Filter/FilterMultiSelect/types.ts +3 -1
  26. package/src/RichTextEditor/utils/commands/addMark.spec.ts +1 -5
  27. package/src/RichTextEditor/utils/commands/fixtures/helpers.ts +0 -31
  28. package/src/RichTextEditor/utils/commands/fixtures/index.ts +2 -0
  29. package/src/RichTextEditor/utils/commands/fixtures/mockRangeForBoundingRect.ts +32 -0
  30. package/src/TitleBlockZen/TitleBlockZen.module.scss +1 -6
  31. package/src/__rc__/Button/_docs/Button--usage-guidelines.mdx +170 -1
  32. package/src/__rc__/Button/_docs/Button.docs.stories.tsx +264 -9
  33. package/src/__rc__/Button/_docs/assets/button_anatomy.png +0 -0
  34. package/src/__rc__/Button/_docs/assets/button_icon_only_spec.png +0 -0
  35. package/src/__rc__/Button/_docs/assets/button_icon_spec.png +0 -0
  36. package/src/__rc__/Button/_docs/assets/button_spec.png +0 -0
  37. package/src/__rc__/Icon/constants.ts +1 -0
  38. package/src/__rc__/Tabs/subcomponents/Tab/Tab.module.css +5 -2
  39. package/src/__rc__/Tabs/subcomponents/TabList/TabList.module.css +11 -4
  40. package/codemods/upgradeV1Buttons/index.ts +0 -19
  41. package/codemods/upgradeV1Buttons/transformV1ButtonAttributes.spec.ts +0 -202
  42. package/codemods/upgradeV1Buttons/transformV1ButtonAttributes.ts +0 -132
  43. package/codemods/upgradeV1Buttons/upgradeV1Buttons.spec.ts +0 -658
  44. package/codemods/upgradeV1Buttons/upgradeV1Buttons.ts +0 -93
  45. package/codemods/utils/createJsxElementWithChildren.spec.ts +0 -119
  46. package/codemods/utils/createJsxElementWithChildren.ts +0 -55
  47. package/src/__rc__/Button/_docs/Button--migration-guide.mdx +0 -58
@@ -9,7 +9,7 @@ export declare const FilterBarButton: React.ForwardRefExoticComponent<{
9
9
  label: string;
10
10
  selectedValue?: string | JSX.Element;
11
11
  isOpen?: boolean;
12
- } & Omit<import("../../../FilterButton/subcomponents/FilterButtonBase").FilterButtonBaseProps, "children"> & {
12
+ } & Omit<import("../../../FilterButton").FilterButtonBaseProps, "children"> & {
13
13
  filterId: string;
14
14
  isRemovable: boolean | undefined;
15
15
  } & React.RefAttributes<FilterTriggerRef>>;
@@ -1,2 +1,3 @@
1
+ export * from './subcomponents/FilterButtonBase';
1
2
  export * from './FilterButton';
2
3
  export * from './FilterButtonRemovable';
@@ -1,4 +1,4 @@
1
- import { type Key, type Node } from '@react-types/shared';
1
+ import { type Key, type Node, type Selection as ReactAriaSelection } from '@react-types/shared';
2
2
  export type ItemType = {
3
3
  label: string;
4
4
  value: Key;
@@ -6,3 +6,4 @@ export type ItemType = {
6
6
  isDisabled?: boolean;
7
7
  };
8
8
  export type MultiSelectItem = Node<ItemType>;
9
+ export type Selection = ReactAriaSelection;
@@ -1,6 +1,5 @@
1
1
  import { type EditorState, type Transaction } from 'prosemirror-state';
2
2
  import { type ProseMirrorModel } from '../../prosemirror';
3
- export declare const mockRangeForBoundingRect: () => void;
4
3
  export declare const simulateRangeSelection: (anchorPositionStart?: number, anchorPositionEnd?: number) => (state: EditorState, dispatch?: (tx: Transaction) => void) => boolean;
5
4
  export declare const getStartNode: (state: EditorState) => ReturnType<ProseMirrorModel.Node["childAfter"]>;
6
5
  export declare const simulateSelectionOfCurrentElement: (selectEntireElement?: boolean) => (state: EditorState, dispatch: (tx: Transaction) => void) => boolean;
@@ -0,0 +1,2 @@
1
+ export * from './mockRangeForBoundingRect';
2
+ export * from './helpers';
@@ -0,0 +1 @@
1
+ export declare const mockRangeForBoundingRect: () => void;
@@ -2,4 +2,4 @@ export declare const handledRtlIcons: {
2
2
  checklist: "checklist_rtl";
3
3
  format_list_numbered: "format_list_numbered_rtl";
4
4
  };
5
- export declare const iconDefaultSet: ("add" | "add_a_photo" | "add_comment" | "add_link" | "arrow_back" | "arrow_downward" | "arrow_drop_down" | "arrow_drop_up" | "arrow_forward" | "arrow_upward" | "assignment" | "assignment_add" | "assignment_ind" | "assignment_returned" | "assignment_turned_in" | "backup" | "bar_chart" | "bookmark" | "brush" | "build" | "cached" | "cancel" | "chat_apps_script" | "chat_error" | "chat_paste_go" | "check" | "check_circle" | "chevron_left" | "chevron_right" | "close" | "close_fullscreen" | "cloud_download" | "comment_bank" | "content_copy" | "dashboard" | "date_range" | "delete" | "domain" | "draft" | "drag_indicator" | "edit" | "error" | "event" | "favorite" | "find_in_page" | "flag" | "flash_on" | "format_bold" | "format_indent_decrease" | "format_indent_increase" | "format_italic" | "format_list_bulleted" | "format_list_numbered" | "format_underlined" | "forum" | "forward" | "front_hand" | "grade" | "group" | "groups" | "help" | "history" | "home" | "horizontal_rule" | "info" | "key" | "keyboard_arrow_down" | "keyboard_arrow_up" | "keyboard_tab" | "keyboard_tab_rtl" | "label" | "lan" | "lightbulb" | "link_off" | "list" | "local_fire_department" | "lock" | "logout" | "mail" | "manage_accounts" | "menu" | "mms" | "more_horiz" | "more_vert" | "north_east" | "note_alt" | "notifications_active" | "open_in_full" | "open_in_new" | "pause" | "percent" | "person" | "person_add" | "person_cancel" | "person_check" | "play_circle" | "playlist_add_check" | "potted_plant" | "power" | "power_settings_new" | "print" | "privacy_tip" | "psychology_alt" | "radio_button_checked" | "radio_button_unchecked" | "rate_review" | "redo" | "reduce_capacity" | "refresh" | "remove" | "reviews" | "schedule" | "school" | "search" | "send" | "sensors" | "sentiment_dissatisfied" | "sentiment_neutral" | "sentiment_satisfied" | "sentiment_very_satisfied" | "settings" | "sms" | "south_east" | "star" | "support" | "thumb_down" | "thumb_up" | "today" | "translate" | "tune" | "undo" | "user_attributes" | "visibility" | "visibility_off" | "warning" | "zoom_in" | "zoom_out" | "auto_awesome")[];
5
+ export declare const iconDefaultSet: ("add" | "add_a_photo" | "add_comment" | "add_link" | "arrow_back" | "arrow_downward" | "arrow_drop_down" | "arrow_drop_up" | "arrow_forward" | "arrow_upward" | "assignment" | "assignment_add" | "assignment_ind" | "assignment_returned" | "assignment_turned_in" | "backup" | "bar_chart" | "bookmark" | "brush" | "build" | "cached" | "cancel" | "chat_apps_script" | "chat_error" | "chat_paste_go" | "check" | "check_circle" | "chevron_left" | "chevron_right" | "close" | "close_fullscreen" | "cloud_download" | "comment_bank" | "content_copy" | "dashboard" | "date_range" | "delete" | "domain" | "draft" | "drag_indicator" | "edit" | "error" | "event" | "favorite" | "find_in_page" | "flag" | "flash_on" | "format_bold" | "format_indent_decrease" | "format_indent_increase" | "format_italic" | "format_list_bulleted" | "format_list_numbered" | "format_underlined" | "forum" | "forward" | "front_hand" | "grade" | "group" | "groups" | "help" | "history" | "home" | "horizontal_rule" | "info" | "key" | "keyboard_arrow_down" | "keyboard_arrow_up" | "keyboard_tab" | "keyboard_tab_rtl" | "label" | "lan" | "lightbulb" | "link_off" | "list" | "local_fire_department" | "lock" | "logout" | "mail" | "manage_accounts" | "menu" | "mms" | "more_horiz" | "more_vert" | "north_east" | "note_alt" | "notifications_active" | "open_in_full" | "open_in_new" | "pause" | "percent" | "person" | "person_add" | "person_cancel" | "person_check" | "play_circle" | "playlist_add_check" | "potted_plant" | "power" | "power_settings_new" | "print" | "privacy_tip" | "psychology_alt" | "radio_button_checked" | "radio_button_unchecked" | "rate_review" | "redo" | "reduce_capacity" | "refresh" | "remove" | "reviews" | "schedule" | "school" | "search" | "send" | "sensors" | "sentiment_dissatisfied" | "sentiment_neutral" | "sentiment_satisfied" | "sentiment_very_satisfied" | "settings" | "share" | "sms" | "south_east" | "star" | "support" | "thumb_down" | "thumb_up" | "today" | "translate" | "tune" | "undo" | "user_attributes" | "visibility" | "visibility_off" | "warning" | "zoom_in" | "zoom_out" | "auto_awesome")[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaizen/components",
3
- "version": "0.0.0-canary-button-codemod-canary-20250212054517",
3
+ "version": "0.0.0-canary-stacking-context-fix-20250225001220",
4
4
  "description": "Kaizen component library",
5
5
  "author": "Geoffrey Chong <geoff.chong@cultureamp.com>",
6
6
  "homepage": "https://cultureamp.design",
@@ -81,6 +81,11 @@
81
81
  "require": "./dist/cjs/reactAriaComponentsV3.cjs",
82
82
  "types": "./dist/types/__react-aria-components__/index.d.ts"
83
83
  },
84
+ "./v3/utilities": {
85
+ "import": "./dist/esm/utilitiesV3.mjs",
86
+ "require": "./dist/cjs/utilitiesV3.cjs",
87
+ "types": "./dist/types/__utilities__/v3.d.ts"
88
+ },
84
89
  "./dist/styles.css": {
85
90
  "import": "./dist/styles.css",
86
91
  "require": "./dist/styles.css",
@@ -1,2 +1,3 @@
1
+ export * from './subcomponents/FilterButtonBase'
1
2
  export * from './FilterButton'
2
3
  export * from './FilterButtonRemovable'
@@ -1,4 +1,4 @@
1
- import { type Key, type Node } from '@react-types/shared'
1
+ import { type Key, type Node, type Selection as ReactAriaSelection } from '@react-types/shared'
2
2
 
3
3
  export type ItemType = {
4
4
  label: string
@@ -8,3 +8,5 @@ export type ItemType = {
8
8
  }
9
9
 
10
10
  export type MultiSelectItem = Node<ItemType>
11
+
12
+ export type Selection = ReactAriaSelection
@@ -2,11 +2,7 @@ import { findByText, waitFor } from '@testing-library/dom'
2
2
  import { vi } from 'vitest'
3
3
  import { createRichTextEditor } from '../core'
4
4
  import { addMark } from './addMark'
5
- import {
6
- mockRangeForBoundingRect,
7
- simulateSelectionByText,
8
- simulateTextInsert,
9
- } from './fixtures/helpers'
5
+ import { mockRangeForBoundingRect, simulateSelectionByText, simulateTextInsert } from './fixtures/'
10
6
  import { testEditorState, testSchema } from './fixtures/test-state'
11
7
  describe('addMark()', () => {
12
8
  const onChange = vi.fn()
@@ -5,38 +5,7 @@ import {
5
5
  type Transaction,
6
6
  } from 'prosemirror-state'
7
7
  import { findChildrenByType } from 'prosemirror-utils'
8
- // eslint-disable-next-line import/no-extraneous-dependencies
9
- import { vi } from 'vitest'
10
8
  import { type ProseMirrorModel } from '../../prosemirror'
11
- /*
12
- ** This is used handle the JSDom type error issue you may encounter in testing
13
- ** See https://github.com/jsdom/jsdom/issues/3002
14
- */
15
- export const mockRangeForBoundingRect = (): void => {
16
- vi.spyOn(document, 'createRange').mockImplementation(() => {
17
- const range = new Range()
18
-
19
- range.getBoundingClientRect = () => ({
20
- x: 0,
21
- y: 0,
22
- bottom: 0,
23
- height: 0,
24
- left: 0,
25
- right: 0,
26
- top: 0,
27
- width: 0,
28
- toJSON: () => undefined,
29
- })
30
-
31
- range.getClientRects = () => ({
32
- item: () => null,
33
- length: 0,
34
- [Symbol.iterator]: vi.fn(),
35
- })
36
-
37
- return range
38
- })
39
- }
40
9
 
41
10
  /*
42
11
  ** Prosemirror cannot intuit a real `Selection` of content injected into the base test.
@@ -0,0 +1,2 @@
1
+ export * from './mockRangeForBoundingRect'
2
+ export * from './helpers'
@@ -0,0 +1,32 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { vi } from 'vitest'
3
+
4
+ /*
5
+ ** This is used handle the JSDom type error issue you may encounter in testing
6
+ ** See https://github.com/jsdom/jsdom/issues/3002
7
+ */
8
+ export const mockRangeForBoundingRect = (): void => {
9
+ vi.spyOn(document, 'createRange').mockImplementation(() => {
10
+ const range = new Range()
11
+
12
+ range.getBoundingClientRect = () => ({
13
+ x: 0,
14
+ y: 0,
15
+ bottom: 0,
16
+ height: 0,
17
+ left: 0,
18
+ right: 0,
19
+ top: 0,
20
+ width: 0,
21
+ toJSON: () => undefined,
22
+ })
23
+
24
+ range.getClientRects = () => ({
25
+ item: () => null,
26
+ length: 0,
27
+ [Symbol.iterator]: vi.fn(),
28
+ })
29
+
30
+ return range
31
+ })
32
+ }
@@ -114,7 +114,6 @@ $tab-container-height-medium-and-small-collapsed: 0;
114
114
  display: flex;
115
115
  align-items: center;
116
116
  min-width: 0; // this is an important trick to prevent flexbox items from overflowing
117
- z-index: $ca-z-index-dropdown; // this ensures the page switcher dropdown sits over nav tabs
118
117
  transform: translateY(-0.0833em);
119
118
 
120
119
  .hasSubtitle & {
@@ -434,7 +433,7 @@ $tab-container-height-medium-and-small-collapsed: 0;
434
433
  width: $tab-container-height-small;
435
434
  height: $tab-container-height-small;
436
435
  background: linear-gradient(0deg, $color-purple-600, rgba($color-purple-600-rgb, 0));
437
- z-index: $ca-z-index-sticky;
436
+ z-index: 1;
438
437
  }
439
438
 
440
439
  .adminVariant & {
@@ -503,7 +502,6 @@ $tab-container-height-medium-and-small-collapsed: 0;
503
502
  cursor: pointer;
504
503
  display: flex;
505
504
  position: absolute;
506
- z-index: $ca-z-index-sticky;
507
505
  align-items: center;
508
506
  top: 50%;
509
507
  transform: translateY(-50%);
@@ -573,9 +571,6 @@ $tab-container-height-medium-and-small-collapsed: 0;
573
571
  // We are using visually hidden here instead of display:none so that a screen reader
574
572
  // navigating via 'read mode' (which doesn't trigger hover/focus) will still hear this link name
575
573
  @include visually-hidden;
576
-
577
- z-index: $ca-z-index-sticky - 1;
578
-
579
574
  @include ca-position($start: -2 * $ca-grid);
580
575
 
581
576
  position: absolute;
@@ -1,6 +1,10 @@
1
1
  import { Canvas, Meta, Controls } from '@storybook/blocks'
2
- import { ResourceLinks, KAIOInstallation } from '~storybook/components'
2
+ import { ResourceLinks, KAIOInstallation, DosAndDonts, DoOrDont } from '~storybook/components'
3
3
  import * as Button from './Button.docs.stories'
4
+ import ButtonIconOnlySpec from './assets/button_icon_only_spec.png'
5
+ import ButtonIconSpec from './assets/button_icon_spec.png'
6
+ import ButtonSpec from './assets/button_spec.png'
7
+ import ButtonAnatomy from './assets/button_anatomy.png'
4
8
 
5
9
  <Meta title="Components/Button/Button (v3)/Usage Guidelines" />
6
10
 
@@ -27,3 +31,168 @@ Buttons allow users to perform an action. They have multiple styles for various
27
31
  include={['children', 'variant', 'size', 'isDisabled', 'icon', 'iconPosition']}
28
32
  className="mb-64"
29
33
  />
34
+
35
+ ## Anatomy
36
+
37
+ <img
38
+ src={ButtonAnatomy}
39
+ alt="Indicates the anatomy of an Button component with text"
40
+ className="my-auto"
41
+ />
42
+
43
+ ### When to use
44
+
45
+ Use buttons to communicate actions users can take. Each page should have only one primary button, and any remaining calls to action should use lower emphasis buttons.
46
+
47
+ ### When not to use
48
+
49
+ Do not use buttons as navigational elements. Instead, use links when the desired action is to take the user to a new page.
50
+
51
+ ## Specs
52
+
53
+ <img
54
+ src={ButtonSpec}
55
+ alt="Indicates the spacing specifications of a Button component with text"
56
+ className="my-auto"
57
+ />
58
+
59
+ <img
60
+ src={ButtonIconSpec}
61
+ alt="Indicates the spacing specifications of a Button component with text and an icon"
62
+ className="my-auto"
63
+ />
64
+
65
+ <img
66
+ src={ButtonIconOnlySpec}
67
+ alt="Indicates the spacing specifications of an icon-only Button"
68
+ className="my-auto"
69
+ />
70
+
71
+ ### Dos and don'ts
72
+
73
+ #### Use primary buttons to highlight a single, important action
74
+
75
+ Reserve the primary button for actions that are essential to an experience. Usually, use only one primary button on a page or section. These buttons give extra prominence and help establish a clear hierarchy.
76
+
77
+ <DosAndDonts>
78
+ <DoOrDont story={Button.DoExamplePrimaryAndSecondary} />
79
+ <DoOrDont story={Button.DontExamplePrimaryAndSecondary} isDont />
80
+ </DosAndDonts>
81
+
82
+ #### Use secondary buttons for medium emphasis actions
83
+
84
+ Use secondary buttons when the action requires less prominence, or if there are multiple actions with the same importance on a page or section.
85
+
86
+ #### Use tertiary buttons to communicate action hierarchy
87
+
88
+ Use tertiary buttons for less important actions within a group or section to help establish a clear hierarchy. Don't use tertiary buttons in isolation.
89
+
90
+ #### Use large buttons for high emphasis
91
+
92
+ Use large buttons sparingly within pages or sections where you need a high emphasis and prominent button to provide balance with other large elements. This might be on a landing page or a CTA in proximity to large headings.
93
+
94
+ <DosAndDonts>
95
+ <DoOrDont story={Button.DoExampleCta} />
96
+ </DosAndDonts>
97
+
98
+ #### Use medium buttons most of the time
99
+
100
+ Medium buttons are appropriate in most common contexts such as pairing with input fields.
101
+
102
+ <DosAndDonts>
103
+ <DoOrDont story={Button.DoExampleDefaultToMediumSize} />
104
+ <DoOrDont story={Button.DontExampleDefaultToMediumSize} isDont />
105
+ </DosAndDonts>
106
+
107
+ #### Use small buttons in information rich contexts
108
+
109
+ Use small buttons when space is limited, such as inside or adjacent to lists, tables, or data visualizations.
110
+
111
+ Ensure clarity by prioritizing the most important actions. Think about how many buttons you use and where you put them. Don't overload your interface with too many buttons, as clustering buttons can confuse people.
112
+
113
+ #### Use icons in Primary and Secondary buttons sparingly and consistently
114
+
115
+ Overusing icons can create visual clutter and overwhelm users. Use them sparingly to highlight common and recognizable actions.
116
+
117
+ <DosAndDonts>
118
+ <DoOrDont story={Button.DoExampleUseIconsSparingly} />
119
+ <DoOrDont story={Button.DontExampleUseIconsSparingly} isDont />
120
+ </DosAndDonts>
121
+
122
+ #### Always use icons in Tertiary buttons
123
+
124
+ Without icons, tertiary buttons can look like plain text. Tertiary buttons must always use icons to support a button affordance and meet accessibility standards.
125
+
126
+ <DosAndDonts>
127
+ <DoOrDont story={Button.DoExampleTertiaryButtonWithIcons} />
128
+ <DoOrDont story={Button.DontExampleTertiaryButtonWithIcons} isDont />
129
+ </DosAndDonts>
130
+
131
+ #### Use tooltips when the label is hidden
132
+
133
+ When a button label is hidden and only an icon is used, show a tooltip on hover that displays the label text.
134
+
135
+ <DosAndDonts>
136
+ <DoOrDont story={Button.DoExampleUseTooltips} />
137
+ <DoOrDont story={Button.DontExampleUseTooltips} isDont />
138
+ </DosAndDonts>
139
+
140
+ #### Use a menu button when all actions are equally important
141
+
142
+ Group related actions in a menu. The action options should be closely related and make sense as a group. You can use any type or size of button based on the context.
143
+
144
+ <DosAndDonts>
145
+ <DoOrDont story={Button.DoExampleMenuButton} />
146
+ </DosAndDonts>
147
+
148
+ #### Use a button and an overflow button when there is a most common or distinct action
149
+
150
+ Highlight the most important, common, or a distinct action by using a button with text. Group related, less important actions in an overflow button. The action options should be closely related and make sense as a group. You can use any type or size of button based on the context. This pattern replaces Split Buttons.
151
+
152
+ <DosAndDonts>
153
+ <DoOrDont story={Button.DoExampleKebabMenuButton} />
154
+ </DosAndDonts>
155
+
156
+ #### Write clear, action-oriented button labels
157
+
158
+ Write button labels as concise verbs that clearly state the action and its outcome. Always align the button label with the language used elsewhere in the Platform to maintain consistency and clarity.
159
+ Make sure that all your buttons begin with a strong verb (something that elicits an action from the user). Verbs indicate to a user what they’re about to see or do next.
160
+
161
+ <DosAndDonts>
162
+ <DoOrDont story={Button.DoExampleClearAndConciseLabels} />
163
+ <DoOrDont story={Button.DontExampleClearAndConciseLabels} isDont />
164
+ </DosAndDonts>
165
+
166
+ A verb and noun combination gives users more context and can help guide them when the action they’re about to perform isn’t commonplace.
167
+
168
+ <DosAndDonts>
169
+ <DoOrDont story={Button.DoExampleDeclareContext} />
170
+ <DoOrDont story={Button.DontExampleDeclareContext} isDont />
171
+ </DosAndDonts>
172
+
173
+ #### Write in sentence case with minimal punctuation
174
+
175
+ All buttons should be in sentence case i.e. the first letter of the first word is capitalized and everything else is in lower case unless it’s a proper noun or feature name. Always err on the side of minimal punctuation, so leave out full stops and commas where possible.
176
+
177
+ <DosAndDonts>
178
+ <DoOrDont story={Button.DoExampleMinimalPunctuation} />
179
+ <DoOrDont story={Button.DontExampleMinimalPunctuation} isDont />
180
+ </DosAndDonts>
181
+
182
+ #### Use second person
183
+
184
+ Any buttons that include a personal pronoun should be written in the second person. Keep in mind that you shouldn’t use personal pronouns unless you’re asking the user to filter something. For example, “View your reports” vs “View all reports.”
185
+
186
+ <DosAndDonts>
187
+ <DoOrDont story={Button.DoExampleSecondPerson} />
188
+ <DoOrDont story={Button.DontExampleSecondPerson} isDont />
189
+ </DosAndDonts>
190
+
191
+ #### Button labels should make sense in isolation
192
+
193
+ If buttons on a page have the same label repeated multiple times, they should have distinct, accessible names that add context for users. This ensures better accessibility for screen reader users, who rely on descriptive labels to distinguish between actions.
194
+
195
+ <DosAndDonts>
196
+ <DoOrDont story={Button.DoExampleFunctionalLabels} />
197
+ <DoOrDont story={Button.DontExampleFunctionalLabels} isDont />
198
+ </DosAndDonts>