@buildcanada/charts 0.2.2 → 0.3.2

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.
@@ -17,12 +17,9 @@ import {
17
17
  shareUsingShareApi,
18
18
  shouldShareUsingShareApi,
19
19
  } from "./ShareMenu.js"
20
- import { Bounds, Tippy } from "../../utils/index.js"
20
+ import { Tippy } from "../../utils/index.js"
21
21
  import classNames from "classnames"
22
- import {
23
- DEFAULT_GRAPHER_BOUNDS,
24
- GrapherModal,
25
- } from "../core/GrapherConstants.js"
22
+ import { GrapherModal } from "../core/GrapherConstants.js"
26
23
  import { DownloadModalTabName } from "../modal/DownloadModal.js"
27
24
 
28
25
  export interface ActionButtonsManager extends ShareMenuManager {
@@ -41,15 +38,9 @@ export interface ActionButtonsManager extends ShareMenuManager {
41
38
 
42
39
  // keep in sync with sass variables in ActionButtons.scss
43
40
  const BUTTON_HEIGHT = 32
44
- const PADDING_BETWEEN_BUTTONS = 8
45
- const PADDING_BETWEEN_ICON_AND_LABEL = 8
46
- const PADDING_X = 12
47
-
48
- const BUTTON_WIDTH_ICON_ONLY = BUTTON_HEIGHT
49
41
 
50
42
  interface ActionButtonsProps {
51
43
  manager: ActionButtonsManager
52
- maxWidth?: number
53
44
  }
54
45
 
55
46
  @observer
@@ -63,165 +54,15 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
63
54
  return this.props.manager
64
55
  }
65
56
 
66
- @computed protected get maxWidth(): number {
67
- return this.props.maxWidth ?? DEFAULT_GRAPHER_BOUNDS.width
68
- }
69
-
70
57
  @computed get height(): number {
71
58
  return BUTTON_HEIGHT
72
59
  }
73
60
 
74
- @computed private get widthWithButtonLabels(): number {
75
- const {
76
- buttonCount,
77
- hasDownloadButton,
78
- hasDonateButton,
79
- hasShareButton,
80
- hasFullScreenButton,
81
- hasExploreTheDataButton,
82
- downloadButtonWithLabelWidth,
83
- donateButtonWithLabelWidth,
84
- shareButtonWithLabelWidth,
85
- fullScreenButtonWithLabelWidth,
86
- exploreTheDataButtonWithLabelWidth,
87
- } = this
88
-
89
- let width = 0
90
- if (hasDownloadButton) {
91
- width += downloadButtonWithLabelWidth
92
- }
93
- if (hasShareButton) {
94
- width += shareButtonWithLabelWidth
95
- }
96
- if (hasFullScreenButton) {
97
- width += fullScreenButtonWithLabelWidth
98
- }
99
- if (hasDonateButton) {
100
- width += donateButtonWithLabelWidth
101
- }
102
- if (hasExploreTheDataButton) {
103
- width += exploreTheDataButtonWithLabelWidth
104
- }
105
-
106
- return width + (buttonCount - 1) * PADDING_BETWEEN_BUTTONS
107
- }
108
-
109
- @computed get widthWithIconsOnly(): number {
110
- const {
111
- buttonCount,
112
- hasExploreTheDataButton,
113
- exploreTheDataButtonWidth,
114
- } = this
115
-
116
- let width = 0
117
- let remainingButtonCount = buttonCount
118
-
119
- // When shown, the explore the data button always has a label
120
- if (hasExploreTheDataButton) {
121
- width += exploreTheDataButtonWidth
122
- remainingButtonCount--
123
- }
124
- width += remainingButtonCount * BUTTON_WIDTH_ICON_ONLY
125
- width += (buttonCount - 1) * PADDING_BETWEEN_BUTTONS
126
-
127
- return width
128
- }
129
-
130
- @computed get showButtonLabels(): boolean {
131
- const { maxWidth, widthWithButtonLabels } = this
132
- return widthWithButtonLabels <= maxWidth
133
- }
134
-
135
- @computed get width(): number {
136
- const { showButtonLabels, widthWithButtonLabels, widthWithIconsOnly } =
137
- this
138
- return showButtonLabels ? widthWithButtonLabels : widthWithIconsOnly
139
- }
140
-
141
- private static computeButtonWidth(label: string): number {
142
- const labelWidth = Bounds.forText(label, { fontSize: 13 }).width
143
- return (
144
- 2 * PADDING_X +
145
- 12 + // icon width
146
- PADDING_BETWEEN_ICON_AND_LABEL +
147
- labelWidth
148
- )
149
- }
150
-
151
- @computed private get downloadButtonWithLabelWidth(): number {
152
- return ActionButtons.computeButtonWidth("Download")
153
- }
154
-
155
- @computed private get shareButtonWithLabelWidth(): number {
156
- return ActionButtons.computeButtonWidth("Share")
157
- }
158
-
159
61
  @computed private get fullScreenButtonLabel(): string {
160
62
  const { isInFullScreenMode } = this.manager
161
63
  return isInFullScreenMode ? "Exit full-screen" : "Enter full-screen"
162
64
  }
163
65
 
164
- @computed private get fullScreenButtonWithLabelWidth(): number {
165
- return ActionButtons.computeButtonWidth(this.fullScreenButtonLabel)
166
- }
167
-
168
- @computed private get donateButtonWithLabelWidth(): number {
169
- return ActionButtons.computeButtonWidth("Donate")
170
- }
171
-
172
- @computed private get exploreTheDataButtonWithLabelWidth(): number {
173
- return ActionButtons.computeButtonWidth("Explore the data")
174
- }
175
-
176
- @computed private get downloadButtonWidth(): number {
177
- const {
178
- hasDownloadButton,
179
- showButtonLabels,
180
- downloadButtonWithLabelWidth,
181
- } = this
182
- if (!hasDownloadButton) return 0
183
- if (!showButtonLabels) return BUTTON_WIDTH_ICON_ONLY
184
- return downloadButtonWithLabelWidth
185
- }
186
-
187
- @computed private get shareButtonWidth(): number {
188
- const { hasShareButton, showButtonLabels, shareButtonWithLabelWidth } =
189
- this
190
- if (!hasShareButton) return 0
191
- if (!showButtonLabels) return BUTTON_WIDTH_ICON_ONLY
192
- return shareButtonWithLabelWidth
193
- }
194
-
195
- @computed private get fullScreenButtonWidth(): number {
196
- const {
197
- hasFullScreenButton,
198
- showButtonLabels,
199
- fullScreenButtonWithLabelWidth,
200
- } = this
201
- if (!hasFullScreenButton) return 0
202
- if (!showButtonLabels) return BUTTON_WIDTH_ICON_ONLY
203
- return fullScreenButtonWithLabelWidth
204
- }
205
-
206
- @computed private get donateButtonWidth(): number {
207
- const {
208
- hasDonateButton,
209
- showButtonLabels,
210
- donateButtonWithLabelWidth,
211
- } = this
212
- if (!hasDonateButton) return 0
213
- if (!showButtonLabels) return BUTTON_WIDTH_ICON_ONLY
214
- return donateButtonWithLabelWidth
215
- }
216
-
217
- // the "Explore the data" button is never shown without a label
218
- @computed private get exploreTheDataButtonWidth(): number {
219
- const { hasExploreTheDataButton, exploreTheDataButtonWithLabelWidth } =
220
- this
221
- if (!hasExploreTheDataButton) return 0
222
- return exploreTheDataButtonWithLabelWidth
223
- }
224
-
225
66
  @action.bound toggleShareMenu(): void {
226
67
  if (shouldShareUsingShareApi(this.manager)) {
227
68
  void shareUsingShareApi(this.manager)
@@ -268,29 +109,12 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
268
109
  return !manager.hideExploreTheDataButton || !!manager.isInIFrame
269
110
  }
270
111
 
271
- @computed private get buttonCount(): number {
272
- let count = 0
273
- if (this.hasDownloadButton) count += 1
274
- if (this.hasShareButton) count += 1
275
- if (this.hasFullScreenButton) count += 1
276
- if (this.hasDonateButton) count += 1
277
- if (this.hasExploreTheDataButton) count += 1
278
- return count
279
- }
280
-
281
112
  private renderShareMenu(): React.ReactElement {
282
- // distance between the right edge of the share button and the inner border of the frame
283
- let right = 0
284
- if (this.hasFullScreenButton)
285
- right += PADDING_BETWEEN_BUTTONS + this.fullScreenButtonWidth
286
- if (this.hasExploreTheDataButton)
287
- right += PADDING_BETWEEN_BUTTONS + this.exploreTheDataButtonWidth
288
-
289
113
  return (
290
114
  <ShareMenu
291
115
  manager={this.manager}
292
116
  onDismiss={this.toggleShareMenu}
293
- right={right}
117
+ right={0}
294
118
  />
295
119
  )
296
120
  }
@@ -300,17 +124,14 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
300
124
  const { isShareMenuActive } = manager
301
125
 
302
126
  return (
303
- <div
304
- className="ActionButtons"
305
- style={{ height: this.height, width: this.width }}
306
- >
127
+ <div className="ActionButtons">
307
128
  <ul>
308
129
  {this.hasDownloadButton && (
309
- <li style={{ width: this.downloadButtonWidth }}>
130
+ <li>
310
131
  <ActionButton
311
132
  label="Download"
312
133
  dataTrackNote="chart_click_download"
313
- showLabel={this.showButtonLabels}
134
+ showLabel={true}
314
135
  icon={faDownload}
315
136
  onClick={action((e): void => {
316
137
  this.openDownloadModal()
@@ -320,11 +141,11 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
320
141
  </li>
321
142
  )}
322
143
  {this.hasShareButton && (
323
- <li style={{ width: this.shareButtonWidth }}>
144
+ <li>
324
145
  <ActionButton
325
146
  label="Share"
326
147
  dataTrackNote="chart_click_share"
327
- showLabel={this.showButtonLabels}
148
+ showLabel={true}
328
149
  icon={faShareNodes}
329
150
  onClick={action((e): void => {
330
151
  this.toggleShareMenu()
@@ -336,11 +157,11 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
336
157
  </li>
337
158
  )}
338
159
  {this.hasFullScreenButton && (
339
- <li style={{ width: this.fullScreenButtonWidth }}>
160
+ <li>
340
161
  <ActionButton
341
162
  label={this.fullScreenButtonLabel}
342
163
  dataTrackNote="chart_click_fullscreen"
343
- showLabel={this.showButtonLabels}
164
+ showLabel={true}
344
165
  icon={
345
166
  manager.isInFullScreenMode
346
167
  ? faCompress
@@ -351,19 +172,19 @@ export class ActionButtons extends React.Component<ActionButtonsProps> {
351
172
  </li>
352
173
  )}
353
174
  {this.hasDonateButton && (
354
- <li style={{ width: this.donateButtonWidth }}>
175
+ <li>
355
176
  <ActionButton
356
177
  className="ActionButton--donate"
357
178
  label="Donate"
358
179
  dataTrackNote="chart_click_donate"
359
- showLabel={this.showButtonLabels}
180
+ showLabel={true}
360
181
  icon={faHeart}
361
182
  href="https://ourworldindata.org/donate"
362
183
  />
363
184
  </li>
364
185
  )}
365
186
  {this.hasExploreTheDataButton && (
366
- <li style={{ width: this.exploreTheDataButtonWidth }}>
187
+ <li>
367
188
  <ActionButton
368
189
  label="Explore the data"
369
190
  dataTrackNote="chart_click_exploredata"
@@ -1,32 +1,41 @@
1
- $active-icon: $blue-50;
1
+ /*******************************************************************************
2
+ * Content Switchers
3
+ *
4
+ * Chart type switcher tabs (Line, Bar, Map, etc.)
5
+ * Uses Build Canada design system colors.
6
+ ******************************************************************************/
7
+
8
+ $active-icon: $white;
2
9
 
3
10
  @at-root {
4
11
  .ContentSwitchers__OverflowMenu {
5
- border-radius: 4px;
6
- background-color: #fff;
7
- box-shadow: 0px 4px 40px 0px rgba(0, 0, 0, 0.06);
12
+ border-radius: 0;
13
+ background-color: $white;
14
+ box-shadow: 0px 4px 20px 0px rgba(39, 39, 39, 0.15);
15
+ border: 1px solid $gray-20;
8
16
  }
9
17
 
10
18
  .ContentSwitchers__OverflowMenuItem {
11
19
  @include grapher_label-2-medium;
12
20
 
13
- margin: 4px 0;
21
+ margin: 0;
14
22
  padding: 0 16px;
15
23
  height: $controlRowHeight;
16
24
  display: flex;
17
25
  align-items: center;
18
- color: $light-text;
26
+ color: $charcoal;
19
27
  cursor: pointer;
20
28
  width: 100%;
21
- background-color: #fff;
29
+ background-color: $white;
30
+ transition: all 150ms ease;
22
31
 
23
32
  &:hover {
24
33
  background-color: $gray-10;
25
34
  }
26
35
 
27
36
  &:focus-visible {
28
- color: $active-text;
29
- background-color: $active-fill;
37
+ color: $white;
38
+ background-color: $auburn-500;
30
39
 
31
40
  svg {
32
41
  color: $active-icon;
@@ -44,7 +53,7 @@ $active-icon: $blue-50;
44
53
  }
45
54
 
46
55
  svg {
47
- color: $gray-60;
56
+ color: $gray-50;
48
57
 
49
58
  &.custom-icon {
50
59
  --size: $icon-width;
@@ -77,14 +86,14 @@ $active-icon: $blue-50;
77
86
 
78
87
  // Don't show as 'active' when clicked
79
88
  &[data-selected] {
80
- background: #fff;
81
- color: $light-text;
89
+ background: $white;
90
+ color: $charcoal;
82
91
  }
83
92
  }
84
93
 
85
94
  .Tabs__Tab.active {
86
- color: $active-text;
87
- background-color: $active-fill;
95
+ color: $white;
96
+ background-color: $auburn-500;
88
97
 
89
98
  svg {
90
99
  color: $active-icon;
@@ -1,13 +1,20 @@
1
+ /*******************************************************************************
2
+ * Controls
3
+ *
4
+ * Menu toggle buttons and control row styling.
5
+ * Uses Build Canada design system colors.
6
+ ******************************************************************************/
7
+
1
8
  $light-stroke: $gray-20;
2
- $dark-stroke: #2d2d2d;
3
- $active-stroke: $blue-30;
9
+ $dark-stroke: $charcoal;
10
+ $active-stroke: $cerulean-500;
4
11
 
5
- $light-fill: $gray-30;
6
- $active-fill: $blue-20;
12
+ $light-fill: $white;
13
+ $active-fill: $cerulean-100;
7
14
  $hover-fill: $gray-10;
8
- $selected-fill: #c7ced7;
15
+ $selected-fill: $cerulean-200;
9
16
 
10
- $active-switch: $blue-50;
17
+ $active-switch: $cerulean-500;
11
18
 
12
19
  $medium: 400;
13
20
  $bold: 700;
@@ -24,14 +31,16 @@ nav.controlsRow .controls {
24
31
 
25
32
  button.menu-toggle {
26
33
  font: $medium 13px/16px $lato;
27
- letter-spacing: 0.01em;
34
+ letter-spacing: 0.02em;
28
35
  display: flex;
29
36
  align-items: center;
30
37
  border: 1px solid $light-stroke;
31
- border-radius: 4px;
32
- padding: 7px;
33
- color: $dark-text;
38
+ border-radius: 0;
39
+ padding: 7px 12px;
40
+ color: $charcoal;
34
41
  white-space: nowrap;
42
+ background-color: $white;
43
+ transition: all 150ms ease;
35
44
 
36
45
  &:hover {
37
46
  background: $hover-fill;
@@ -40,14 +49,19 @@ nav.controlsRow .controls {
40
49
 
41
50
  &.active,
42
51
  &:active {
43
- color: $active-text;
52
+ color: $cerulean-900;
44
53
  background: $active-fill;
45
- border: 1px solid $active-fill;
54
+ border-color: $active-stroke;
55
+ }
56
+
57
+ &:focus-visible {
58
+ outline: 2px solid $auburn;
59
+ outline-offset: 2px;
46
60
  }
47
61
 
48
62
  svg {
49
63
  height: 12px;
50
- margin-right: 5px;
64
+ margin-right: 6px;
51
65
  vertical-align: bottom;
52
66
  }
53
67
 
@@ -57,17 +71,15 @@ nav.controlsRow .controls {
57
71
  }
58
72
  }
59
73
 
60
- //
61
- // Make buttons narrower by omitting their text labels as the viewport gets narrower
62
- // use the .GrapherComponentSemiNarrow if necessary but allow container queries to
63
- // collapse labels in two steps on browsers that support them
64
- //
65
- // TODO: the measurement and label-hiding logic will have to move to js anyway once the
66
- // number of chart buttons becomes variable and the settings button can be replaced
67
- // by a single control widget ‘promoted’ from within the drawer
68
- //
74
+ /*******************************************************************************
75
+ * Responsive Label Hiding
76
+ *
77
+ * Make buttons narrower by omitting their text labels as the viewport
78
+ * gets narrower.
79
+ ******************************************************************************/
80
+
69
81
  @at-root {
70
- // collapse both the settings and entity selector labels down at the semi-narrow breakpoint
82
+ // Collapse both settings and entity selector labels at semi-narrow breakpoint
71
83
  .GrapherComponentSemiNarrow {
72
84
  nav.controlsRow .settings-menu button.menu-toggle {
73
85
  min-height: $control-row-height;
@@ -86,8 +98,8 @@ nav.controlsRow .controls {
86
98
  }
87
99
  }
88
100
 
89
- @container grapher (max-width:575px) {
90
- // collapse the Settings toggle down to just an icon on small screens
101
+ @container grapher (max-width: 575px) {
102
+ // Collapse Settings toggle to just an icon on small screens
91
103
  nav.controlsRow .settings-menu button.menu-toggle {
92
104
  min-height: $control-row-height;
93
105
  svg {
@@ -98,7 +110,7 @@ nav.controlsRow .controls {
98
110
  }
99
111
  }
100
112
 
101
- // undo the .GrapherComponentSemiNarrow hiding until next container query
113
+ // Undo the .GrapherComponentSemiNarrow hiding until next container query
102
114
  nav.controlsRow .entity-selection-menu button.menu-toggle {
103
115
  label span {
104
116
  display: inline;
@@ -106,8 +118,8 @@ nav.controlsRow .controls {
106
118
  }
107
119
  }
108
120
 
109
- @container grapher (max-width:675px) {
110
- // hide the entity name in the Edit/Select/Switch button
121
+ @container grapher (max-width: 675px) {
122
+ // Hide entity name in Edit/Select/Switch button (chart controls)
111
123
  nav.controlsRow .chart-controls .entity-selection-menu button.menu-toggle {
112
124
  label span {
113
125
  display: none;
@@ -115,8 +127,8 @@ nav.controlsRow .controls {
115
127
  }
116
128
  }
117
129
 
118
- @container grapher (max-width:725px) {
119
- // hide the entity name in the Edit/Select/Switch button
130
+ @container grapher (max-width: 725px) {
131
+ // Hide entity name in Edit/Select/Switch button (map controls)
120
132
  nav.controlsRow .map-controls .entity-selection-menu button.menu-toggle {
121
133
  label span {
122
134
  display: none;
@@ -124,28 +136,30 @@ nav.controlsRow .controls {
124
136
  }
125
137
  }
126
138
 
127
- @container grapher (max-width:500px) {
128
- // hide labels on smaller screens
139
+ @container grapher (max-width: 500px) {
140
+ // Hide labels on smaller screens
129
141
  .ContentSwitchers .Tabs__Tab .label {
130
142
  display: none;
131
143
  }
132
144
  }
133
145
 
134
- // reduce the horizontal padding of a content switcher tab based on grapher's size
135
- @container grapher (max-width:725px) {
146
+ // Reduce horizontal padding of content switcher tab based on grapher's size
147
+ @container grapher (max-width: 725px) {
136
148
  .ContentSwitchers .Tabs__Tab {
137
149
  --tab-padding: 12px;
138
150
  }
139
151
  }
140
- @container grapher (max-width:335px) {
152
+
153
+ @container grapher (max-width: 335px) {
141
154
  .ContentSwitchers .Tabs__Tab {
142
155
  --tab-padding: 8px;
143
156
  }
144
157
  }
145
158
 
146
- //
147
- // correct for style bleeds in admin
148
- //
159
+ /*******************************************************************************
160
+ * Admin Style Corrections
161
+ ******************************************************************************/
162
+
149
163
  @at-root {
150
164
  .AdminApp {
151
165
  nav.controlsRow .controls button.menu-toggle label {