@dt-dds/react-icon-button 1.0.0-beta.18 → 1.0.0-beta.20

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @dt-ui/react-icon-button
2
2
 
3
+ ## 1.0.0-beta.20
4
+
5
+ ### Minor Changes
6
+
7
+ - feat: avatar interactivity via icon-button
8
+
9
+ ## 1.0.0-beta.19
10
+
11
+ ### Minor Changes
12
+
13
+ - feat: implement new Dropdown
14
+ - feat: implement new Select field
15
+
16
+ ### Patch Changes
17
+
18
+ - Updated dependencies
19
+ - Updated dependencies
20
+ - @dt-dds/react-core@1.0.0-beta.51
21
+
3
22
  ## 1.0.0-beta.18
4
23
 
5
24
  ### Patch Changes
package/README.md CHANGED
@@ -1,18 +1,72 @@
1
1
  # IconButton
2
2
 
3
- This component allows the user to take action by clicking on an Icon.
3
+ This component allows the user to take action by clicking on an Icon. It is a flexible button component that renders an icon and can be composed with any child element through CSS overrides for advanced styling customization.
4
4
 
5
5
  ## Usage
6
6
 
7
+ ### With Icon
8
+
7
9
  ```jsx
8
- import { IconButton, EditIcon } from '@dt-dds/react';
10
+ import { IconButton } from '@dt-dds/react';
11
+ import { Icon } from '@dt-dds/react-icon';
9
12
 
10
13
  export const App = () => {
11
- const handleClick = () => null;
14
+ const handleClick = () => console.log('Edit clicked');
15
+
16
+ return (
17
+ <IconButton
18
+ onClick={handleClick}
19
+ ariaLabel="Edit profile"
20
+ >
21
+ <Icon code='edit' />
22
+ </IconButton>
23
+ );
24
+ };
25
+ ```
26
+
27
+ ### With Avatar
28
+
29
+ ```jsx
30
+ import { IconButton } from '@dt-dds/react-icon-button';
31
+ import { Avatar } from '@dt-dds/react-avatar';
12
32
 
33
+ export const AvatarButton = () => {
13
34
  return (
14
- <IconButton onClick={handleClick}>
15
- <EditIcon />
35
+ <IconButton
36
+ ariaLabel="User profile"
37
+ onClick={() => console.log('Avatar clicked')}
38
+ >
39
+ <Avatar
40
+ title="John Doe"
41
+ type="letter"
42
+ size="medium"
43
+ />
44
+ </IconButton>
45
+ );
46
+ };
47
+ ```
48
+
49
+ ### CSS Overrides
50
+
51
+ The cssOverrides prop allows you to apply custom CSS styles to the IconButton and its children. This enables full styling flexibility while keeping IconButton agnostic of its child components.
52
+
53
+ #### Example: Custom Icon Button Styling
54
+
55
+ ```jsx
56
+ import { IconButton } from '@dt-dds/react-icon-button';
57
+ import { Icon } from '@dt-dds/react-icon';
58
+ import { css } from '@emotion/react';
59
+
60
+ export const CustomButton = () => {
61
+ const customStyles = css`
62
+ &:hover:not(:disabled) {
63
+ background-color: #ff5733;
64
+ }
65
+ `;
66
+
67
+ return (
68
+ <IconButton cssOverrides={customStyles}>
69
+ <Icon code='star' />
16
70
  </IconButton>
17
71
  );
18
72
  };
@@ -30,6 +84,55 @@ export const App = () => {
30
84
  | `isDisabled` | `boolean` | false | Determines the disabled state of the button |
31
85
  | `variant` | `IconButtonVariant` | `default` | Determines the variant of the icon |
32
86
  | `size` | `ComponentSize` | `large` | Determines the size of the icon |
87
+ | `cssOverrides`| `ReturnType<typeof css>`| - | Emotion CSS to apply custom styles to the button and its children |
88
+
89
+ ### Accessibility
90
+
91
+ - Always provide ariaLabel when the button doesn't contain readable text (e.g., icon-only buttons)
92
+ - Focus outline is automatically visible with keyboard navigation
93
+ - Disabled buttons are properly marked and keyboard-inaccessible
94
+ - Supports screen readers through semantic button element
95
+
96
+ ## Stack
97
+
98
+ - [TypeScript](https://www.typescriptlang.org/) for static type checking
99
+ - [React](https://reactjs.org/) — JavaScript library for user interfaces
100
+ - [Emotion](https://emotion.sh/docs/introduction) — for writing css styles with JavaScript
101
+ - [Storybook](https://storybook.js.org/) — UI component environment powered by Vite
102
+ - [Jest](https://jestjs.io/) - JavaScript Testing Framework
103
+ - [React Testing Library](https://testing-library.com/) - to test UI components in a user-centric way
104
+ - [ESLint](https://eslint.org/) for code linting
105
+ - [Prettier](https://prettier.io) for code formatting
106
+ - [Tsup](https://github.com/egoist/tsup) — TypeScript bundler powered by esbuild
107
+ - [Yarn](https://yarnpkg.com/) from managing packages
108
+
109
+ ## Commands
110
+
111
+ - `yarn build` - Build the package
112
+ - `yarn dev` - Run the package locally
113
+ - `yarn lint` - Lint all files within this package
114
+ - `yarn test` - Run all unit tests
115
+ - `yarn test:report` - Open the test coverage report
116
+ - `yarn test:update:snapshot` - Run all unit tests and update the snapshot
117
+
118
+ ## Compilation
119
+
120
+ Running `yarn build` from the root of the package will use [tsup](https://tsup.egoist.dev/) to compile the raw TypeScript and React code to plain JavaScript.
121
+
122
+ The `/dist` folder contains the compiled output.
123
+
124
+ ```bash
125
+ iconButton
126
+ └── dist
127
+ ├── index.d.ts <-- Types
128
+ ├── index.js <-- CommonJS version
129
+ └── index.mjs <-- ES Modules version
130
+ ...
131
+ ```
132
+
133
+ ## Versioning
134
+
135
+ Follows [semantic versioning](https://semver.org/)
33
136
 
34
137
  ## &copy; License
35
138
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CustomTheme } from '@dt-dds/themes';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { BaseProps, ComponentSize } from '@dt-dds/react-core';
4
+ import { css } from '@emotion/react';
4
5
  import { ComponentPropsWithoutRef } from 'react';
5
6
 
6
7
  type IconButtonVariant = 'contrast' | 'default';
@@ -11,8 +12,9 @@ interface IconButtonProps extends ComponentPropsWithoutRef<'button'>, BaseProps
11
12
  ariaLabel?: string;
12
13
  variant?: IconButtonVariant;
13
14
  size?: ComponentSize;
15
+ cssOverrides?: ReturnType<typeof css>;
14
16
  }
15
- declare const IconButton: ({ children, dataTestId, isDisabled, ariaLabel, variant, size, onClick, ...props }: IconButtonProps) => react_jsx_runtime.JSX.Element;
17
+ declare const IconButton: ({ children, dataTestId, isDisabled, ariaLabel, variant, size, onClick, cssOverrides, ...props }: IconButtonProps) => react_jsx_runtime.JSX.Element;
16
18
 
17
19
  declare module '@emotion/react' {
18
20
  interface Theme extends CustomTheme {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { CustomTheme } from '@dt-dds/themes';
2
2
  import * as react_jsx_runtime from 'react/jsx-runtime';
3
3
  import { BaseProps, ComponentSize } from '@dt-dds/react-core';
4
+ import { css } from '@emotion/react';
4
5
  import { ComponentPropsWithoutRef } from 'react';
5
6
 
6
7
  type IconButtonVariant = 'contrast' | 'default';
@@ -11,8 +12,9 @@ interface IconButtonProps extends ComponentPropsWithoutRef<'button'>, BaseProps
11
12
  ariaLabel?: string;
12
13
  variant?: IconButtonVariant;
13
14
  size?: ComponentSize;
15
+ cssOverrides?: ReturnType<typeof css>;
14
16
  }
15
- declare const IconButton: ({ children, dataTestId, isDisabled, ariaLabel, variant, size, onClick, ...props }: IconButtonProps) => react_jsx_runtime.JSX.Element;
17
+ declare const IconButton: ({ children, dataTestId, isDisabled, ariaLabel, variant, size, onClick, cssOverrides, ...props }: IconButtonProps) => react_jsx_runtime.JSX.Element;
16
18
 
17
19
  declare module '@emotion/react' {
18
20
  interface Theme extends CustomTheme {
package/dist/index.js CHANGED
@@ -83,7 +83,7 @@ var iconButtonSizeStyles = {
83
83
  `
84
84
  };
85
85
  var IconButtonStyled = import_styled.default.button(
86
- ({ theme, disabled, variant = "default", size = "large" }) => {
86
+ ({ theme, disabled, variant = "default", size = "large", cssOverrides }) => {
87
87
  const isDefaultVariant = variant === "default";
88
88
  const baseColor = () => {
89
89
  if (disabled) {
@@ -92,14 +92,14 @@ var IconButtonStyled = import_styled.default.button(
92
92
  return isDefaultVariant ? theme.palette.content.default : theme.palette.content.contrast;
93
93
  };
94
94
  const hoverColor = isDefaultVariant ? theme.palette.accent.default : theme.palette.accent.medium;
95
- return `
95
+ const baseStyles = `
96
96
  display: flex;
97
97
  align-items: center;
98
98
  border: none;
99
99
  background-color: transparent;
100
100
  cursor: ${disabled ? "not-allowed" : "pointer"};
101
101
 
102
- i {
102
+ > i {
103
103
  ${iconButtonSizeStyles[size]};
104
104
  color: ${baseColor()};
105
105
  }
@@ -113,7 +113,40 @@ var IconButtonStyled = import_styled.default.button(
113
113
  &:focus-visible {
114
114
  outline: 2px solid ${theme.palette.primary.default};
115
115
  }
116
+
117
+ &:hover:not(:disabled) {
118
+ [data-avatar-type='letter'] {
119
+ background-color: ${theme.palette.primary.dark};
120
+ }
121
+
122
+ [data-avatar-type='collapsed'] {
123
+ background-color: ${theme.palette.primary.light};
124
+ }
125
+
126
+ [data-avatar-type='thumbnail'] {
127
+ background-color: ${theme.palette.primary.dark};
128
+ }
129
+ }
130
+
131
+ ${disabled && `
132
+ [data-avatar-type='letter'] {
133
+ background-color: ${theme.palette.primary.light};
134
+ }
135
+
136
+ [data-avatar-type='collapsed'] {
137
+ background-color: ${theme.palette.surface.contrast};
138
+ }
139
+
140
+ [data-avatar-type='thumbnail'] {
141
+ background-color: ${theme.palette.primary.light};
142
+ }
143
+
144
+ [data-avatar-type='photo'] {
145
+ opacity: 0.38;
146
+ }
147
+ `}
116
148
  `;
149
+ return cssOverrides ? [baseStyles, cssOverrides] : baseStyles;
117
150
  }
118
151
  );
119
152
 
@@ -127,7 +160,8 @@ var IconButton = (_a) => {
127
160
  ariaLabel,
128
161
  variant,
129
162
  size,
130
- onClick
163
+ onClick,
164
+ cssOverrides
131
165
  } = _b, props = __objRest(_b, [
132
166
  "children",
133
167
  "dataTestId",
@@ -135,7 +169,8 @@ var IconButton = (_a) => {
135
169
  "ariaLabel",
136
170
  "variant",
137
171
  "size",
138
- "onClick"
172
+ "onClick",
173
+ "cssOverrides"
139
174
  ]);
140
175
  const handleClick = (e) => {
141
176
  if (isDisabled) {
@@ -149,6 +184,7 @@ var IconButton = (_a) => {
149
184
  IconButtonStyled,
150
185
  __spreadProps(__spreadValues({
151
186
  "aria-label": ariaLabel,
187
+ cssOverrides,
152
188
  "data-testid": dataTestId ? dataTestId : "icon-button",
153
189
  disabled: isDisabled,
154
190
  onClick: handleClick,
package/dist/index.mjs CHANGED
@@ -50,7 +50,7 @@ var iconButtonSizeStyles = {
50
50
  `
51
51
  };
52
52
  var IconButtonStyled = styled.button(
53
- ({ theme, disabled, variant = "default", size = "large" }) => {
53
+ ({ theme, disabled, variant = "default", size = "large", cssOverrides }) => {
54
54
  const isDefaultVariant = variant === "default";
55
55
  const baseColor = () => {
56
56
  if (disabled) {
@@ -59,14 +59,14 @@ var IconButtonStyled = styled.button(
59
59
  return isDefaultVariant ? theme.palette.content.default : theme.palette.content.contrast;
60
60
  };
61
61
  const hoverColor = isDefaultVariant ? theme.palette.accent.default : theme.palette.accent.medium;
62
- return `
62
+ const baseStyles = `
63
63
  display: flex;
64
64
  align-items: center;
65
65
  border: none;
66
66
  background-color: transparent;
67
67
  cursor: ${disabled ? "not-allowed" : "pointer"};
68
68
 
69
- i {
69
+ > i {
70
70
  ${iconButtonSizeStyles[size]};
71
71
  color: ${baseColor()};
72
72
  }
@@ -80,7 +80,40 @@ var IconButtonStyled = styled.button(
80
80
  &:focus-visible {
81
81
  outline: 2px solid ${theme.palette.primary.default};
82
82
  }
83
+
84
+ &:hover:not(:disabled) {
85
+ [data-avatar-type='letter'] {
86
+ background-color: ${theme.palette.primary.dark};
87
+ }
88
+
89
+ [data-avatar-type='collapsed'] {
90
+ background-color: ${theme.palette.primary.light};
91
+ }
92
+
93
+ [data-avatar-type='thumbnail'] {
94
+ background-color: ${theme.palette.primary.dark};
95
+ }
96
+ }
97
+
98
+ ${disabled && `
99
+ [data-avatar-type='letter'] {
100
+ background-color: ${theme.palette.primary.light};
101
+ }
102
+
103
+ [data-avatar-type='collapsed'] {
104
+ background-color: ${theme.palette.surface.contrast};
105
+ }
106
+
107
+ [data-avatar-type='thumbnail'] {
108
+ background-color: ${theme.palette.primary.light};
109
+ }
110
+
111
+ [data-avatar-type='photo'] {
112
+ opacity: 0.38;
113
+ }
114
+ `}
83
115
  `;
116
+ return cssOverrides ? [baseStyles, cssOverrides] : baseStyles;
84
117
  }
85
118
  );
86
119
 
@@ -94,7 +127,8 @@ var IconButton = (_a) => {
94
127
  ariaLabel,
95
128
  variant,
96
129
  size,
97
- onClick
130
+ onClick,
131
+ cssOverrides
98
132
  } = _b, props = __objRest(_b, [
99
133
  "children",
100
134
  "dataTestId",
@@ -102,7 +136,8 @@ var IconButton = (_a) => {
102
136
  "ariaLabel",
103
137
  "variant",
104
138
  "size",
105
- "onClick"
139
+ "onClick",
140
+ "cssOverrides"
106
141
  ]);
107
142
  const handleClick = (e) => {
108
143
  if (isDisabled) {
@@ -116,6 +151,7 @@ var IconButton = (_a) => {
116
151
  IconButtonStyled,
117
152
  __spreadProps(__spreadValues({
118
153
  "aria-label": ariaLabel,
154
+ cssOverrides,
119
155
  "data-testid": dataTestId ? dataTestId : "icon-button",
120
156
  disabled: isDisabled,
121
157
  onClick: handleClick,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dt-dds/react-icon-button",
3
- "version": "1.0.0-beta.18",
3
+ "version": "1.0.0-beta.20",
4
4
  "license": "MIT",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"
@@ -20,7 +20,7 @@
20
20
  "test:update:snapshot": "jest -u"
21
21
  },
22
22
  "dependencies": {
23
- "@dt-dds/react-core": "1.0.0-beta.50",
23
+ "@dt-dds/react-core": "1.0.0-beta.51",
24
24
  "@dt-dds/themes": "1.0.0-beta.9"
25
25
  },
26
26
  "devDependencies": {