@bundle-stats/ui 3.2.5 → 3.2.6-beta.3

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 (112) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/lib/components/bundle-assets/bundle-assets.js +23 -13
  3. package/lib/components/bundle-assets/bundle-assets.module.css +18 -26
  4. package/lib/components/bundle-modules/bundle-modules.js +4 -5
  5. package/lib/components/bundle-packages/bundle-packages.js +14 -8
  6. package/lib/components/bundle-packages/bundle-packages.module.css +8 -12
  7. package/lib/components/delta/delta.module.css +1 -0
  8. package/lib/components/metrics-table-search/metrics-table-search.module.css +5 -4
  9. package/lib/components/metrics-table-title/metrics-table-title.js +9 -7
  10. package/lib/components/metrics-table-title/metrics-table-title.module.css +2 -0
  11. package/lib/components/module-info/module-info.module.css +1 -0
  12. package/lib/components/summary-item/summary-item.js +14 -17
  13. package/lib/components/summary-item/summary-item.module.css +1 -19
  14. package/lib/components/total-size-type-title/total-size-type-title.js +7 -3
  15. package/lib/css/variables.css +3 -3
  16. package/lib/hooks/search-params.js +6 -6
  17. package/lib/layout/box/box.module.css +9 -0
  18. package/lib/ui/dropdown/dropdown.js +16 -26
  19. package/lib/ui/dropdown/dropdown.module.css +11 -12
  20. package/lib/ui/dropdown/dropdown.stories.js +2 -9
  21. package/lib/ui/filters/filters.js +10 -5
  22. package/lib/ui/filters/filters.module.css +10 -0
  23. package/lib/ui/hover-card/hover-card.js +100 -0
  24. package/lib/ui/hover-card/hover-card.module.css +52 -0
  25. package/lib/ui/hover-card/hover-card.stories.js +56 -0
  26. package/lib/ui/hover-card/index.js +18 -0
  27. package/lib/ui/icon/icon.js +6 -6
  28. package/lib/ui/index.js +8 -8
  29. package/lib/ui/table/table.module.css +0 -4
  30. package/lib/ui/{popover → tag}/index.js +4 -4
  31. package/lib/ui/tag/tag.js +72 -0
  32. package/lib/ui/tag/tag.module.css +55 -0
  33. package/lib/ui/tag/tag.stories.js +38 -0
  34. package/lib/ui/tooltip/tooltip.js +10 -9
  35. package/lib/ui/tooltip/tooltip.module.css +1 -1
  36. package/lib-esm/components/bundle-assets/bundle-assets.js +22 -13
  37. package/lib-esm/components/bundle-assets/bundle-assets.module.css +18 -26
  38. package/lib-esm/components/bundle-modules/bundle-modules.js +4 -5
  39. package/lib-esm/components/bundle-packages/bundle-packages.js +13 -8
  40. package/lib-esm/components/bundle-packages/bundle-packages.module.css +8 -12
  41. package/lib-esm/components/delta/delta.module.css +1 -0
  42. package/lib-esm/components/metrics-table-search/metrics-table-search.module.css +5 -4
  43. package/lib-esm/components/metrics-table-title/metrics-table-title.js +8 -7
  44. package/lib-esm/components/metrics-table-title/metrics-table-title.module.css +2 -0
  45. package/lib-esm/components/module-info/module-info.module.css +1 -0
  46. package/lib-esm/components/summary-item/summary-item.js +13 -17
  47. package/lib-esm/components/summary-item/summary-item.module.css +1 -19
  48. package/lib-esm/components/total-size-type-title/total-size-type-title.js +6 -3
  49. package/lib-esm/css/variables.css +3 -3
  50. package/lib-esm/hooks/search-params.js +6 -6
  51. package/lib-esm/layout/box/box.module.css +9 -0
  52. package/lib-esm/ui/dropdown/dropdown.js +15 -25
  53. package/lib-esm/ui/dropdown/dropdown.module.css +11 -12
  54. package/lib-esm/ui/dropdown/dropdown.stories.js +2 -7
  55. package/lib-esm/ui/filters/filters.js +9 -4
  56. package/lib-esm/ui/filters/filters.module.css +10 -0
  57. package/lib-esm/ui/hover-card/hover-card.js +86 -0
  58. package/lib-esm/ui/hover-card/hover-card.module.css +52 -0
  59. package/lib-esm/ui/hover-card/hover-card.stories.js +35 -0
  60. package/lib-esm/ui/hover-card/index.js +1 -0
  61. package/lib-esm/ui/icon/icon.js +3 -3
  62. package/lib-esm/ui/index.js +1 -1
  63. package/lib-esm/ui/table/table.module.css +0 -4
  64. package/lib-esm/ui/tag/index.js +1 -0
  65. package/lib-esm/ui/tag/tag.js +45 -0
  66. package/lib-esm/ui/tag/tag.module.css +55 -0
  67. package/lib-esm/ui/tag/tag.stories.js +23 -0
  68. package/lib-esm/ui/tooltip/tooltip.js +10 -9
  69. package/lib-esm/ui/tooltip/tooltip.module.css +1 -1
  70. package/package.json +9 -9
  71. package/src/components/bundle-assets/bundle-assets.jsx +61 -42
  72. package/src/components/bundle-assets/bundle-assets.module.css +18 -26
  73. package/src/components/bundle-modules/bundle-modules.jsx +24 -14
  74. package/src/components/bundle-packages/bundle-packages.jsx +21 -8
  75. package/src/components/bundle-packages/bundle-packages.module.css +8 -12
  76. package/src/components/delta/delta.module.css +1 -0
  77. package/src/components/metrics-table-search/metrics-table-search.module.css +5 -4
  78. package/src/components/metrics-table-title/metrics-table-title.jsx +20 -21
  79. package/src/components/metrics-table-title/metrics-table-title.module.css +2 -0
  80. package/src/components/module-info/module-info.jsx +1 -5
  81. package/src/components/module-info/module-info.module.css +1 -0
  82. package/src/components/summary-item/summary-item.jsx +20 -26
  83. package/src/components/summary-item/summary-item.module.css +1 -19
  84. package/src/components/total-size-type-title/total-size-type-title.jsx +6 -9
  85. package/src/css/variables.css +3 -3
  86. package/src/hooks/search-params.js +18 -11
  87. package/src/layout/box/box.module.css +9 -0
  88. package/src/ui/dropdown/dropdown.jsx +12 -22
  89. package/src/ui/dropdown/dropdown.module.css +11 -12
  90. package/src/ui/filters/filters.jsx +53 -50
  91. package/src/ui/filters/filters.module.css +10 -0
  92. package/src/ui/hover-card/hover-card.jsx +79 -0
  93. package/src/ui/hover-card/hover-card.module.css +52 -0
  94. package/src/ui/hover-card/index.js +1 -0
  95. package/src/ui/icon/icon.jsx +11 -7
  96. package/src/ui/index.js +1 -1
  97. package/src/ui/table/table.module.css +0 -4
  98. package/src/ui/tag/index.js +1 -0
  99. package/src/ui/tag/tag.jsx +49 -0
  100. package/src/ui/tag/tag.module.css +55 -0
  101. package/src/ui/tooltip/tooltip.jsx +10 -14
  102. package/src/ui/tooltip/tooltip.module.css +1 -1
  103. package/lib/ui/popover/popover.js +0 -92
  104. package/lib/ui/popover/popover.module.css +0 -66
  105. package/lib/ui/popover/popover.stories.js +0 -26
  106. package/lib-esm/ui/popover/index.js +0 -1
  107. package/lib-esm/ui/popover/popover.js +0 -71
  108. package/lib-esm/ui/popover/popover.module.css +0 -66
  109. package/lib-esm/ui/popover/popover.stories.js +0 -14
  110. package/src/ui/popover/index.js +0 -1
  111. package/src/ui/popover/popover.jsx +0 -79
  112. package/src/ui/popover/popover.module.css +0 -66
@@ -25,7 +25,8 @@ const getSearchPattern = (search) => {
25
25
  };
26
26
 
27
27
  const getSearchReducer =
28
- ({ defaultFilters, allEntriesFilters, setParentState }) => (state, action) => {
28
+ ({ defaultFilters, allEntriesFilters, setParentState }) =>
29
+ (state, action) => {
29
30
  const { type, payload } = action;
30
31
 
31
32
  switch (type) {
@@ -116,29 +117,35 @@ export const useSearchParams = ({
116
117
  // Update state when the custom filters/search are changing - initial load or route updates
117
118
  useLayoutEffect(() => {
118
119
  // Run a deep comparison to prevent circular setState triggering
119
- if (parentSearch === search || isEqual(parentFilters, filters)) {
120
+ if (parentSearch === search && isEqual(initialFilters, filters)) {
120
121
  return;
121
122
  }
122
123
 
123
124
  dispatch({ type: ACTION_SET, payload: generateState(initialFilters, parentSearch) });
124
- }, [search, filters, parentFilters, parentSearch]);
125
+ }, [dispatch, search, filters, parentSearch, initialFilters]);
125
126
 
126
127
  /** Callbacks */
127
- const handleUpdateSearch = useCallback((newValue) => {
128
- dispatch({ type: ACTION_SET_SEARCH, payload: newValue });
129
- }, []);
128
+ const handleUpdateSearch = useCallback(
129
+ (newValue) => {
130
+ dispatch({ type: ACTION_SET_SEARCH, payload: newValue });
131
+ },
132
+ [dispatch],
133
+ );
130
134
 
131
- const handleUpdateFilters = useCallback((newFilters) => {
132
- dispatch({ type: ACTION_SET_FILTERS, payload: newFilters });
133
- }, []);
135
+ const handleUpdateFilters = useCallback(
136
+ (newFilters) => {
137
+ dispatch({ type: ACTION_SET_FILTERS, payload: newFilters });
138
+ },
139
+ [dispatch],
140
+ );
134
141
 
135
142
  const handleResetFilters = useCallback(() => {
136
143
  dispatch({ type: ACTION_RESET_DEFAULT });
137
- }, []);
144
+ }, [dispatch]);
138
145
 
139
146
  const handleResetAllFilters = useCallback(() => {
140
147
  dispatch({ type: ACTION_RESET_ALL });
141
- }, []);
148
+ }, [dispatch]);
142
149
 
143
150
  return {
144
151
  search,
@@ -4,6 +4,15 @@
4
4
 
5
5
  .outline {
6
6
  border: 1px solid var(--color-outline);
7
+ border-radius: var(--radius-medium);
8
+ }
9
+
10
+ .outline > :first-child {
11
+ border-radius: var(--radius-medium) var(--radius-medium) 0 0;
12
+ }
13
+
14
+ .outline > :last-child {
15
+ border-radius: 0 0 var(--radius-medium) var(--radius-medium);
7
16
  }
8
17
 
9
18
  .padding-xxxsmall {
@@ -1,39 +1,36 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import cx from 'classnames';
4
- import { Menu, MenuItem, MenuButton, useMenuState } from 'reakit/Menu';
4
+ import { Menu, MenuButton, MenuItem, useMenuState } from 'ariakit/menu';
5
5
 
6
6
  import { FlexStack } from '../../layout/flex-stack';
7
7
  import { Icon } from '../icon';
8
8
  import css from './dropdown.module.css';
9
9
 
10
10
  export const Dropdown = (props) => {
11
- const { className, label, ariaLabel, glyph, activeLabel, children } = props;
12
- const rootClassName = cx(css.root, activeLabel && css.activeLabel, className);
13
-
14
- const menu = useMenuState({baseId: process.env.NODE_ENV === 'test' && 'id-test', modal: true });
11
+ const { className, label, ariaLabel, glyph, children } = props;
12
+ const rootClassName = cx(css.root, className);
13
+ const menuState = useMenuState();
15
14
 
16
15
  return (
17
- <>
18
- <MenuButton {...menu} className={rootClassName} tabIndex={null}>
19
- <FlexStack space="xxxsmall" className={css.label}>
16
+ <div className={rootClassName}>
17
+ <MenuButton state={menuState} className={css.button} tabIndex={null}>
18
+ <FlexStack space="xxxsmall">
20
19
  {glyph && <Icon className={css.labelIcon} glyph={glyph} />}
21
20
  {label}
22
21
  </FlexStack>
23
22
  </MenuButton>
24
- <Menu {...menu} aria-label={ariaLabel || label} className={css.dropdown}>
23
+ <Menu state={menuState} aria-label={ariaLabel || label} className={css.dropdown}>
25
24
  {typeof children === 'function'
26
- ?
27
- children({
25
+ ? children({
28
26
  MenuItem,
29
- menu,
27
+ menu: menuState,
30
28
  menuItemClassName: css.menuItem,
31
29
  menuItemActiveClassName: css.menuItemActive,
32
30
  })
33
- : children
34
- }
31
+ : children}
35
32
  </Menu>
36
- </>
33
+ </div>
37
34
  );
38
35
  };
39
36
 
@@ -42,7 +39,6 @@ Dropdown.defaultProps = {
42
39
  label: null,
43
40
  ariaLabel: '',
44
41
  glyph: null,
45
- activeLabel: false,
46
42
  };
47
43
 
48
44
  Dropdown.propTypes = {
@@ -58,12 +54,6 @@ Dropdown.propTypes = {
58
54
  /** Icon glyph */
59
55
  glyph: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
60
56
 
61
- /** Dropdown open state */
62
- open: PropTypes.bool.isRequired,
63
-
64
- /** Active label flag */
65
- activeLabel: PropTypes.bool,
66
-
67
57
  /** Content */
68
58
  children: PropTypes.oneOfType([PropTypes.string, PropTypes.element, PropTypes.func]).isRequired,
69
59
  };
@@ -1,16 +1,14 @@
1
1
  .root {
2
+ display: inline-block;
3
+ }
4
+
5
+ .button {
2
6
  background: none;
3
7
  border: none;
4
8
  padding: 0;
5
- }
6
-
7
- .root:focus {
8
- outline: none;
9
- box-shadow: 0 0 var(--space-xxxsmall) var(--color-shadow);
10
- }
11
9
 
12
- .label {
13
10
  border: 1px solid var(--color-outline);
11
+ border-radius: var(--radius-small);
14
12
  padding: calc(var(--space-xxsmall) - 1px);
15
13
  display: flex;
16
14
  align-items: center;
@@ -24,7 +22,11 @@
24
22
  color: var(--color-text-light);
25
23
  }
26
24
 
27
- .label:hover {
25
+ .button:hover,
26
+ .button:focus,
27
+ .button:active {
28
+ outline: none;
29
+ box-shadow: 0 0 var(--space-xxxsmall) var(--color-shadow);
28
30
  border-color: var(--color-outline-dark);
29
31
  color: var(--color-text);
30
32
  }
@@ -33,6 +35,7 @@
33
35
  position: absolute;
34
36
  left: 0;
35
37
  top: 100%;
38
+ border-radius: var(--radius-medium);
36
39
  box-shadow: 0 2px var(--space-xxsmall) var(--color-shadow);
37
40
  background: var(--color-background);
38
41
  min-width: 180px;
@@ -45,10 +48,6 @@
45
48
  box-shadow: 0 2px var(--space-xsmall) var(--color-shadow);
46
49
  }
47
50
 
48
- .activeLabel .label {
49
- color: var(--color-text);
50
- }
51
-
52
51
  .menuItem {
53
52
  display: block;
54
53
  appearance: none;
@@ -18,25 +18,15 @@ const Filter = (props) => {
18
18
  <div className={rootClassName}>
19
19
  {/* eslint-disable */}
20
20
  <FlexStack space="xxxsmall" as="label" className={css.filterCheckbox}>
21
- {/* eslint-enabled */}
22
- <input
23
- className={css.filterInput}
24
- type="checkbox"
25
- id={id}
26
- name={name}
27
- {...inputProps}
28
- />
21
+ {/* eslint-enabled */}
22
+ <input className={css.filterInput} type="checkbox" id={id} name={name} {...inputProps} />
29
23
  <span className={css.filterLabel} title={label}>
30
24
  {label}
31
25
  </span>
32
26
  </FlexStack>
33
27
 
34
28
  {getOnOnlyClick && (
35
- <button
36
- className={css.filterOnlyButton}
37
- type="button"
38
- onClick={getOnOnlyClick(name)}
39
- >
29
+ <button className={css.filterOnlyButton} type="button" onClick={getOnOnlyClick(name)}>
40
30
  only
41
31
  </button>
42
32
  )}
@@ -57,13 +47,17 @@ Filter.defaultProps = {
57
47
  };
58
48
 
59
49
  const FilterGroup = (props) => {
60
- const { groupKey, data, values, onCheckboxChange, toggleFilters } = props;
50
+ const { className, groupKey, data, values, onCheckboxChange, toggleFilters } = props;
61
51
 
62
52
  const { label: groupLabel, ...groupData } = data;
63
53
 
64
54
  const groupItems = Object.entries(groupData);
65
- const groupCheckboxes = groupItems.filter(([itemKey, item]) => typeof item?.defaultValue !== 'undefined');
66
- const isGroupChecked = groupCheckboxes.map(([itemKey]) => get(values, `${groupKey}.${itemKey}`)).reduce((agg, val) => agg && val, true);
55
+ const groupCheckboxes = groupItems.filter(
56
+ ([itemKey, item]) => typeof item?.defaultValue !== 'undefined',
57
+ );
58
+ const isGroupChecked = groupCheckboxes
59
+ .map(([itemKey]) => get(values, `${groupKey}.${itemKey}`))
60
+ .reduce((agg, val) => agg && val, true);
67
61
 
68
62
  const filterSuffix = getGroupFiltersLabelSuffix(groupItems);
69
63
  const hasCustomFilterSuffix = !Object.values(LABELS).includes(filterSuffix);
@@ -71,26 +65,33 @@ const FilterGroup = (props) => {
71
65
  <>
72
66
  {`${groupLabel}:`}
73
67
  &nbsp;
74
- <span className={cx(hasCustomFilterSuffix && css.labelSuffixCustom)}>
75
- {filterSuffix}
76
- </span>
68
+ <span className={cx(hasCustomFilterSuffix && css.labelSuffixCustom)}>{filterSuffix}</span>
77
69
  </>
78
70
  );
79
71
 
80
- const getOnGroupCheck = (value, overrides = {}) => () => {
81
- const newFilters = groupCheckboxes.reduce((agg, [itemKey]) => ({
82
- ...agg,
83
- [`${groupKey}.${itemKey}`]: value,
84
- }), {});
85
-
86
- toggleFilters({
87
- ...newFilters,
88
- ...overrides,
89
- });
90
- };
72
+ const getOnGroupCheck =
73
+ (value, overrides = {}) =>
74
+ () => {
75
+ const newFilters = groupCheckboxes.reduce(
76
+ (agg, [itemKey]) => ({
77
+ ...agg,
78
+ [`${groupKey}.${itemKey}`]: value,
79
+ }),
80
+ {},
81
+ );
82
+
83
+ toggleFilters({
84
+ ...newFilters,
85
+ ...overrides,
86
+ });
87
+ };
91
88
 
92
89
  return (
93
- <Dropdown label={dropdownLabel} ariaLabel={`${groupLabel}: ${filterSuffix}`}>
90
+ <Dropdown
91
+ className={className}
92
+ label={dropdownLabel}
93
+ ariaLabel={`${groupLabel}: ${filterSuffix}`}
94
+ >
94
95
  {({ MenuItem, menu, menuItemClassName }) => {
95
96
  return (
96
97
  <>
@@ -100,7 +101,11 @@ const FilterGroup = (props) => {
100
101
  const getOnOnlyClick = () => getOnGroupCheck(false, { [id]: true });
101
102
 
102
103
  return (
103
- <MenuItem key={id} {...menu} className={cx(menuItemClassName, css.filterGroupItem)}>
104
+ <MenuItem
105
+ key={id}
106
+ {...menu}
107
+ className={cx(menuItemClassName, css.filterGroupItem)}
108
+ >
104
109
  <Filter
105
110
  name={id}
106
111
  label={itemData.label}
@@ -138,12 +143,13 @@ const FilterGroup = (props) => {
138
143
  </div>
139
144
  </>
140
145
  );
141
- }}
146
+ }}
142
147
  </Dropdown>
143
148
  );
144
149
  };
145
150
 
146
151
  FilterGroup.propTypes = {
152
+ className: PropTypes.string,
147
153
  groupKey: PropTypes.string.isRequired,
148
154
  data: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
149
155
  values: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
@@ -151,14 +157,12 @@ FilterGroup.propTypes = {
151
157
  toggleFilters: PropTypes.func.isRequired,
152
158
  };
153
159
 
160
+ FilterGroup.defaultProps = {
161
+ className: '',
162
+ };
163
+
154
164
  export const Filters = (props) => {
155
- const {
156
- className,
157
- values,
158
- filters,
159
- toggleFilter,
160
- toggleFilters,
161
- } = props;
165
+ const { className, values, filters, toggleFilter, toggleFilters } = props;
162
166
 
163
167
  const onCheckboxChange = ({ target }) => toggleFilter(target.name, target.checked);
164
168
  const rootClassName = cx(css.root, className);
@@ -182,16 +186,15 @@ export const Filters = (props) => {
182
186
  }
183
187
 
184
188
  return (
185
- <div className={css.item}>
186
- <FilterGroup
187
- key={name}
188
- groupKey={name}
189
- data={data}
190
- values={values}
191
- onCheckboxChange={onCheckboxChange}
192
- toggleFilters={toggleFilters}
193
- />
194
- </div>
189
+ <FilterGroup
190
+ className={css.item}
191
+ key={name}
192
+ groupKey={name}
193
+ data={data}
194
+ values={values}
195
+ onCheckboxChange={onCheckboxChange}
196
+ toggleFilters={toggleFilters}
197
+ />
195
198
  );
196
199
  })}
197
200
  </FlexStack>
@@ -11,6 +11,7 @@
11
11
  }
12
12
 
13
13
  .filterInput {
14
+ border-radius: var(--radius-small) 0 0 var(--radius-small);
14
15
  flex: 0 0 auto;
15
16
  height: 1em;
16
17
  cursor: pointer;
@@ -129,11 +130,20 @@
129
130
  }
130
131
 
131
132
  .item {
133
+ border-radius: 0;
132
134
  position: relative;
133
135
  flex: 0 0 auto;
134
136
  margin-right: -1px;
135
137
  }
136
138
 
139
+ .item:first-child {
140
+ border-radius: var(--radius-small) 0 0 var(--radius-small);
141
+ }
142
+
143
+ .item:last-child {
144
+ border-radius: 0 var(--radius-small) var(--radius-small) 0;
145
+ }
146
+
137
147
  .item:hover {
138
148
  z-index: var(--layer-low); /* show collapsed border */
139
149
  }
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import cx from 'classnames';
4
+ import {
5
+ Hovercard,
6
+ HovercardAnchor,
7
+ HovercardArrow,
8
+ useHovercard,
9
+ useHovercardState,
10
+ } from 'ariakit/hovercard';
11
+
12
+ import { Icon } from '../icon';
13
+ import css from './hover-card.module.css';
14
+
15
+ const resolveComponent = (as, href) => {
16
+ if (as) {
17
+ return as;
18
+ }
19
+
20
+ if (href) {
21
+ return 'a';
22
+ }
23
+
24
+ return 'span';
25
+ };
26
+
27
+ export const HoverCard = (props) => {
28
+ const { className, href, as, label, children } = props;
29
+ const state = useHovercardState({ gutter: 8 });
30
+ const hoverCardProps = useHovercard({ state, portal: true });
31
+
32
+ // Fallback to span if no href
33
+ const Component = resolveComponent(as, href);
34
+
35
+ return (
36
+ <div className={cx(css.root, className)}>
37
+ <HovercardAnchor state={state} href={href} className={css.anchor} as={Component}>
38
+ {label}
39
+ </HovercardAnchor>
40
+ <Hovercard
41
+ {...hoverCardProps}
42
+ state={state}
43
+ className={css.hoverCard}
44
+ style={{ zIndex: 10000 }}
45
+ >
46
+ <HovercardArrow size={24} />
47
+ {typeof children === 'function' ? children({ close: state.hide }) : children}
48
+ <Icon
49
+ glyph="close"
50
+ size="small"
51
+ as="button"
52
+ type="button"
53
+ className={css.closeBtn}
54
+ onClick={state.hide}
55
+ />
56
+ </Hovercard>
57
+ </div>
58
+ );
59
+ };
60
+
61
+ HoverCard.propTypes = {
62
+ /** Adopted child class name */
63
+ className: PropTypes.string,
64
+ /** Anchor label */
65
+ label: PropTypes.node,
66
+ /** Anchor href */
67
+ href: PropTypes.string,
68
+ /** Anchor component */
69
+ as: PropTypes.elementType,
70
+ /** Hover card component */
71
+ children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired,
72
+ };
73
+
74
+ HoverCard.defaultProps = {
75
+ className: '',
76
+ label: '',
77
+ as: '',
78
+ href: '',
79
+ };
@@ -0,0 +1,52 @@
1
+ .root {
2
+ display: inline-block;
3
+ }
4
+
5
+ .anchor {
6
+ display: inline-block;
7
+ color: inherit;
8
+ text-decoration: none;
9
+ }
10
+
11
+ a.anchor,
12
+ buton.anchor {
13
+ cursor: pointer;
14
+ }
15
+
16
+ a.anchor:hover,
17
+ button.anchor:hover {
18
+ color: var(--color-primary);
19
+ text-decoration: underline;
20
+ }
21
+
22
+ .hoverCard {
23
+ padding: var(--space-xsmall) var(--space-large) var(--space-xsmall) var(--space-small);
24
+ border-radius: var(--radius-medium);
25
+ max-width: 320px;
26
+ outline: none;
27
+ filter: drop-shadow(0 0 var(--space-xxsmall) var(--color-shadow));
28
+ will-change: filter;
29
+ background: var(--color-light);
30
+ font-size: var(--size-small);
31
+ }
32
+
33
+ .closeBtn {
34
+ position: absolute;
35
+ right: 0;
36
+ top: var(--space-xxxsmall);
37
+ width: var(--space-large);
38
+ height: var(--space-large);
39
+ padding: var(--space-xxsmall);
40
+ background: none;
41
+ border: none;
42
+ cursor: pointer;
43
+ color: var(--color-text-ultra-light);
44
+ transition: var(--transition-out);
45
+ }
46
+
47
+ .closeBtn:hover,
48
+ .closeBtn:active,
49
+ .closeBtn:focus {
50
+ color: var(--color-text-light);
51
+ transition: var(--transition-in);
52
+ }
@@ -0,0 +1 @@
1
+ export * from './hover-card';
@@ -18,13 +18,17 @@ const ICONS = {
18
18
  WARNING: 'warning',
19
19
  };
20
20
 
21
- export const Icon = ({ className, glyph, as: Component, size, ...restProps }) => (
22
- <Component className={cx(css.root, className, css[size])} {...restProps}>
23
- <svg className={css.icon}>
24
- <use xlinkHref={`#${glyph}`} />
25
- </svg>
26
- </Component>
27
- );
21
+ export const Icon = (props) => {
22
+ const { className, glyph, as: Component, size, ...restProps } = props;
23
+
24
+ return (
25
+ <Component className={cx(css.root, className, css[size])} {...restProps}>
26
+ <svg className={css.icon}>
27
+ <use xlinkHref={`#${glyph}`} />
28
+ </svg>
29
+ </Component>
30
+ );
31
+ };
28
32
 
29
33
  Icon.ICONS = ICONS;
30
34
 
package/src/ui/index.js CHANGED
@@ -10,9 +10,9 @@ export { Input } from './input';
10
10
  export { Loader } from './loader';
11
11
  export { Logo } from './logo';
12
12
  export { Panels } from './panels';
13
- export { Popover } from './popover';
14
13
  export { Skeleton } from './skeleton';
15
14
  export { SortDropdown } from './sort-dropdown';
16
15
  export { Table } from './table';
17
16
  export { Tabs } from './tabs';
17
+ export { Tag } from './tag';
18
18
  export { Tooltip } from './tooltip';
@@ -13,10 +13,6 @@
13
13
  text-align: left;
14
14
  }
15
15
 
16
- tr:last-child .cell {
17
- border-bottom-width: 1px;
18
- }
19
-
20
16
  .root thead .cell {
21
17
  border-width: 0 0 2px;
22
18
  text-transform: uppercase;
@@ -0,0 +1 @@
1
+ export * from './tag';
@@ -0,0 +1,49 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import cx from 'classnames';
4
+
5
+ import css from './tag.module.css';
6
+
7
+ export const KINDS = {
8
+ DEFAULT: 'default',
9
+ SUCCESS: 'success',
10
+ INFO: 'info',
11
+ WARNING: 'warning',
12
+ DANGER: 'danger',
13
+ };
14
+
15
+ export const SIZES = {
16
+ SMALL: 'small',
17
+ MEDIUM: 'medium',
18
+ LARGE: 'large',
19
+ };
20
+
21
+ export const Tag = (props) => {
22
+ const {
23
+ className = '',
24
+ as: Component = 'span',
25
+ kind = KINDS.DEFAULT,
26
+ size = SIZES.MEDIUM,
27
+ ...restProps
28
+ } = props;
29
+ const rootClassName = cx(css.root, className, css[kind], css[size]);
30
+
31
+ return <Component className={rootClassName} {...restProps} />;
32
+ };
33
+
34
+ Tag.propTypes = {
35
+ className: PropTypes.string,
36
+ as: PropTypes.elementType,
37
+ kind: PropTypes.oneOf(Object.values(KINDS)),
38
+ size: PropTypes.oneOf(Object.values(SIZES)),
39
+ };
40
+
41
+ Tag.defaultProps = {
42
+ className: '',
43
+ as: 'span',
44
+ kind: KINDS.DEFAULT,
45
+ size: SIZES.MEDIUM,
46
+ };
47
+
48
+ Tag.KINDS = KINDS;
49
+ Tag.SIZES = SIZES;
@@ -0,0 +1,55 @@
1
+ .root {
2
+ display: inline-block;
3
+ font-family: var(--font-family);
4
+ font-weight: bold;
5
+ background: var(--color-text-light);
6
+ color: var(--color-light);
7
+ text-align: center;
8
+ text-transform: uppercase;
9
+ }
10
+
11
+ /** Kind variation */
12
+ .success {
13
+ background: var(--color-success);
14
+ }
15
+
16
+ .info {
17
+ background: var(--color-info);
18
+ }
19
+
20
+ .warning {
21
+ background: var(--color-warning-dark);
22
+ }
23
+
24
+ .danger {
25
+ background: var(--color-danger);
26
+ }
27
+
28
+ /** Size variation */
29
+ /** default: medium */
30
+ .root {
31
+ border-radius: var(--radius-medium);
32
+ padding: var(--space-xxxsmall);
33
+ min-width: var(--space-small);
34
+ height: var(--space-small);
35
+ font-size: 9px;
36
+ line-height: 1;
37
+ }
38
+
39
+ .small {
40
+ border-radius: var(--radius-small);
41
+ padding: calc(var(--space-xxxsmall) / 2);
42
+ height: var(--space-xsmall);
43
+ min-width: var(--space-xsmall);
44
+ font-size: 8px;
45
+ line-height: 1;
46
+ }
47
+
48
+ .large {
49
+ border-radius: var(--radius-large);
50
+ padding: var(--space-xxxsmall) var(--space-xxsmall);
51
+ min-width: var(--space-medium);
52
+ height: var(--space-medium);
53
+ font-size: 12px;
54
+ line-height: var(--space-small);
55
+ }