playbook_ui 13.31.0 → 13.32.0.pre.alpha.play1416movealiaslogic3239

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/app/pb_kits/playbook/pb_button/_button.scss +3 -3
  3. data/app/pb_kits/playbook/pb_button/_button_mixins.scss +3 -2
  4. data/app/pb_kits/playbook/pb_caption/_caption_mixin.scss +1 -1
  5. data/app/pb_kits/playbook/pb_dashboard/commonSettings.js +1 -1
  6. data/app/pb_kits/playbook/pb_dashboard/pbChartsDarkTheme.ts +1 -1
  7. data/app/pb_kits/playbook/pb_dashboard/pbChartsLightTheme.ts +1 -1
  8. data/app/pb_kits/playbook/pb_date_year_stacked/docs/_date_year_stacked_default.jsx +4 -1
  9. data/app/pb_kits/playbook/pb_draggable/context/index.tsx +15 -1
  10. data/app/pb_kits/playbook/pb_draggable/context/types.ts +5 -0
  11. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.jsx +14 -19
  12. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_default.md +5 -3
  13. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_cards.md +7 -3
  14. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_list.md +3 -5
  15. data/app/pb_kits/playbook/pb_draggable/docs/_draggable_with_selectable_list.md +3 -5
  16. data/app/pb_kits/playbook/pb_dropdown/dropdown.html.erb +3 -1
  17. data/app/pb_kits/playbook/pb_dropdown/dropdown.rb +2 -0
  18. data/app/pb_kits/playbook/pb_dropdown/index.js +33 -4
  19. data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate.html.erb +9 -0
  20. data/app/pb_kits/playbook/pb_form_pill/_form_pill.scss +1 -1
  21. data/app/pb_kits/playbook/pb_icon/_icon.tsx +6 -37
  22. data/app/pb_kits/playbook/pb_icon/icon.rb +9 -3
  23. data/app/pb_kits/playbook/pb_rich_text_editor/_rich_text_editor.tsx +8 -23
  24. data/app/pb_kits/playbook/tokens/_titles.scss +4 -4
  25. data/app/pb_kits/playbook/tokens/_typography.scss +10 -10
  26. data/dist/menu.yml +566 -472
  27. data/dist/playbook-rails.js +7 -7
  28. data/dist/reset.css +1 -1
  29. data/lib/playbook/version.rb +2 -2
  30. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c02852f26be30f0f9abff5ba3089c03c4d9f6878880b2e3f59827e7b556f8c3d
4
- data.tar.gz: a5c30e259ea3d6a77135c2f6172d607ddb105732e20caf60f68d1d1f014bf468
3
+ metadata.gz: 38d2ad5fae80d023caae7a74a96bf549e74693d82376000d2d056ecdd94e5948
4
+ data.tar.gz: c3de45c50a99868c1a157179eb8912acfd173337bd94af3eb166c42d01c051ac
5
5
  SHA512:
6
- metadata.gz: d14c183e1ef95272881479defd28dec0aa49a6ee8539af55aa630cdd493aa48918830906465d6a46c0caf405a1c2a8b2b7dd5fc894f0031feb62bbd21341ae22
7
- data.tar.gz: 26cd7b2d68304e1c80c4bf3e1bc9ce5cc07cf5c378c82e52bac4541abd61ca0a5a817ded5c6abde4282cb7c785b484778902afa96c3e83e0e7f3fcd84e68872b
6
+ metadata.gz: e83a30785c99181d6f62a6632ad1d52c6c7970f8a53dd42e01041814fe5c9f09ee969aa0c2a39b180b20f565492c096e94744ce3149cf407c8c2ed09c99636ec
7
+ data.tar.gz: 37992e6abfc459bdb39b5a62292a43c3d49a79e17261136c955929836de307c9677653338fe9635c619dc0314ca69b498348cbacea044279d1dd924e5edac86f
@@ -6,9 +6,9 @@
6
6
  @import "../tokens/typography";
7
7
 
8
8
  $pb_button_sizes: (
9
- "sm": 0.75rem,
10
- "md": 0.875rem,
11
- "lg": 1.125rem,
9
+ "sm": $font_smaller,
10
+ "md": $font_small,
11
+ "lg": ($font_large - 2px),
12
12
  );
13
13
 
14
14
  [class*=pb_button_kit]{
@@ -9,7 +9,7 @@
9
9
 
10
10
  $pb_button_size: 40px;
11
11
  $pb_button_v_padding: 7px;
12
- $pb_button_h_padding: 34px;
12
+ $pb_button_h_padding: 28px;
13
13
  $pb_button_hover_darken: 4%;
14
14
  $pb_button_border_width: 0px;
15
15
 
@@ -27,13 +27,14 @@ $pb_button_border_width: 0px;
27
27
  text-rendering: optimizeLegibility;
28
28
  font-size: $font_small;
29
29
  font-weight: $bold;
30
+ letter-spacing: $lspace_loose;
30
31
  text-align: center;
31
32
  text-decoration: none;
32
33
  vertical-align: middle;
33
34
  text-transform: none;
34
35
  border-width: $pb_button_border_width;
35
36
  border-style: solid;
36
- border-radius: $border_rad_light;
37
+ border-radius: $border_rad_heavy;
37
38
  min-height: $pb_button_size;
38
39
  line-height: 1.5;
39
40
  padding: $pb_button_v_padding $pb_button_h_padding;
@@ -24,7 +24,7 @@ $pb_dark_caption_colors: (
24
24
  color: $text_lt_light;
25
25
  text-transform: uppercase;
26
26
  font-size: $font_size;
27
- letter-spacing: $lspace_looser;
27
+ letter-spacing: $lspace_loosest;
28
28
  }
29
29
 
30
30
  @mixin caption_color($color: $text_lt_light) {
@@ -53,7 +53,7 @@ const adjustAxisStyle = (axis) => {
53
53
  /* Change axis label styles */
54
54
  axis.labels.style.fontFamily = typography.font_family_base
55
55
  axis.labels.style.color = colors.charcoal
56
- axis.labels.style.fontWeight = typography.light
56
+ axis.labels.style.fontWeight = typography.regular
57
57
  axis.labels.style.fontSize = typography.font_small
58
58
  }
59
59
 
@@ -33,7 +33,7 @@ const highchartsDarkTheme: ThemeProps = {
33
33
  style: {
34
34
  color: colors.text_dk_default,
35
35
  fontFamily: typography.font_family_base,
36
- fontWeight: typography.regular,
36
+ fontWeight: typography.bold,
37
37
  fontSize: typography.heading_3,
38
38
  },
39
39
  },
@@ -34,7 +34,7 @@ const highchartsTheme: ThemeProps = {
34
34
  style: {
35
35
  color: colors.text_lt_default,
36
36
  fontFamily: typography.font_family_base,
37
- fontWeight: typography.regular,
37
+ fontWeight: typography.bold,
38
38
  fontSize: typography.heading_3,
39
39
  },
40
40
  },
@@ -4,7 +4,10 @@ import { DateYearStacked } from '../../'
4
4
  const DateYearStackedDefault = (props) => {
5
5
  return (
6
6
  <div>
7
- <DateYearStacked date={new Date()} />
7
+ <DateYearStacked
8
+ date={new Date()}
9
+ {...props}
10
+ />
8
11
  <DateYearStacked
9
12
  align="center"
10
13
  date={new Date()}
@@ -51,7 +51,16 @@ export const DraggableContext = () => {
51
51
  return useContext(DragContext);
52
52
  };
53
53
 
54
- export const DraggableProvider = ({ children, initialItems, onReorder }: DraggableProviderType) => {
54
+ export const DraggableProvider = ({
55
+ children,
56
+ initialItems,
57
+ onReorder,
58
+ onDragStart,
59
+ onDragEnter,
60
+ onDragEnd,
61
+ onDrop,
62
+ onDragOver
63
+ }: DraggableProviderType) => {
55
64
  const [state, dispatch] = useReducer(reducer, initialState);
56
65
 
57
66
  useEffect(() => {
@@ -65,6 +74,7 @@ export const DraggableProvider = ({ children, initialItems, onReorder }: Draggab
65
74
  const handleDragStart = (id: string, container: string) => {
66
75
  dispatch({ type: 'SET_DRAG_DATA', payload: { id: id, initialGroup: container } });
67
76
  dispatch({ type: 'SET_IS_DRAGGING', payload: id });
77
+ if (onDragStart) onDragStart(id, container);
68
78
  };
69
79
 
70
80
  const handleDragEnter = (id: string, container: string) => {
@@ -72,11 +82,13 @@ export const DraggableProvider = ({ children, initialItems, onReorder }: Draggab
72
82
  dispatch({ type: 'REORDER_ITEMS', payload: { dragId: state.dragData.id, targetId: id } });
73
83
  dispatch({ type: 'SET_DRAG_DATA', payload: { id: state.dragData.id, initialGroup: container } });
74
84
  }
85
+ if (onDragEnter) onDragEnter(id, container);
75
86
  };
76
87
 
77
88
  const handleDragEnd = () => {
78
89
  dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
79
90
  dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
91
+ if (onDragEnd) onDragEnd();
80
92
  };
81
93
 
82
94
  const changeCategory = (itemId: string, container: string) => {
@@ -87,11 +99,13 @@ export const DraggableProvider = ({ children, initialItems, onReorder }: Draggab
87
99
  dispatch({ type: 'SET_IS_DRAGGING', payload: "" });
88
100
  dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: "" });
89
101
  changeCategory(state.dragData.id, container);
102
+ if (onDrop) onDrop(container);
90
103
  };
91
104
 
92
105
  const handleDragOver = (e: Event, container: string) => {
93
106
  e.preventDefault();
94
107
  dispatch({ type: 'SET_ACTIVE_CONTAINER', payload: container });
108
+ if (onDragOver) onDragOver(e, container);
95
109
  };
96
110
 
97
111
  const contextValue = useMemo(() => ({
@@ -23,4 +23,9 @@ export interface ItemType {
23
23
  children: React.ReactNode;
24
24
  initialItems: ItemType[];
25
25
  onReorder: (items: ItemType[]) => void;
26
+ onDragStart?: (id: string, container: string) => void;
27
+ onDragEnter?: (id: string, container: string) => void;
28
+ onDragEnd?: () => void;
29
+ onDrop?: (container: string) => void;
30
+ onDragOver?: (e: Event, container: string) => void;
26
31
  }
@@ -1,23 +1,19 @@
1
1
  import React, { useState } from "react";
2
- import { SelectableList, Draggable, DraggableProvider } from "../../";
2
+ import { Flex, Image, Draggable, DraggableProvider } from "../../";
3
3
 
4
4
  // Initial items to be dragged
5
5
  const data = [
6
6
  {
7
- id: "1",
8
- text: "Task 1",
7
+ id: "21",
8
+ url: "https://unsplash.it/500/400/?image=633",
9
9
  },
10
10
  {
11
- id: "2",
12
- text: "Task 2",
11
+ id: "22",
12
+ url: "https://unsplash.it/500/400/?image=634",
13
13
  },
14
14
  {
15
- id: "3",
16
- text: "Task 3",
17
- },
18
- {
19
- id: "4",
20
- text: "Task 4",
15
+ id: "23",
16
+ url: "https://unsplash.it/500/400/?image=637",
21
17
  },
22
18
  ];
23
19
 
@@ -30,20 +26,19 @@ const DraggableDefault = (props) => {
30
26
  onReorder={(items) => setInitialState(items)}
31
27
  >
32
28
  <Draggable.Container {...props}>
33
- <SelectableList variant="checkbox">
34
- {initialState.map(({ id, text }) => (
29
+ <Flex>
30
+ {initialState.map(({ id, url }) => (
35
31
  <Draggable.Item dragId={id}
36
32
  key={id}
37
33
  >
38
- <SelectableList.Item
39
- label={text}
40
- name={id}
41
- value={id}
42
- {...props}
34
+ <Image alt={id}
35
+ margin="xs"
36
+ size="md"
37
+ url={url}
43
38
  />
44
39
  </Draggable.Item>
45
40
  ))}
46
- </SelectableList>
41
+ </Flex>
47
42
  </Draggable.Container>
48
43
  </DraggableProvider>
49
44
  </>
@@ -1,4 +1,6 @@
1
- To use the Draggable kit, you must use the DraggableProvider and pass in `initialItems`. The `onReorder` is a function that returns the data as it changes as items are reordered. Use this to manage state as shown.
1
+ The Draggable kit gives you a full subcomponent structure that allows it to be used with almost any kits.
2
2
 
3
- The `Draggable.Container` specifies the container within which items can be dropped.
4
- The `Draggable.Item` specifies the items that can be dragged and dropped. `dragId` is a REQUIRED prop for Draggable.Item.
3
+ `DraggableProvider` = This provider manages all settings that allows drag and drop to function and must be used as the outermost wrapper. It has 2 REQUIRED props: `initialItems` (initial data) and `onReorder` (function that returns mutated data as items are reordered via drag and drop). Devs must manage state as shown.
4
+
5
+ `Draggable.Container` = This specifies the container within which items can be dropped.
6
+ `Draggable.Item` = This specifies the items that can be dragged and dropped. `dragId` is a REQUIRED prop for Draggable.Item.
@@ -1,5 +1,9 @@
1
- For a simplified version of the Draggable API for the Card kit, You can use the the Card kit as the Draggable Item by using the `draggableItem` prop. The dragHandle is added by default but this can be opted out of by setting `dragHandle` to false on the Card kit.
1
+ For a simplified version of the Draggable API for the Card kit, you can do the following:
2
+
3
+ Use `DraggableProvider` and manage state as shown.
4
+
5
+ `Draggable.Container` creates the container within which the cards can be dragged and dropped.
6
+
7
+ The Card kit is optimized to work with the draggable kit. To enable drag, use the `draggableItem` and `dragId` props on the Card kit as shown. An additional optional boolean prop (set to true by default) of `dragHandle` is also available to show the drag handle icon.
2
8
 
3
- In addition to the above `dragId` is a REQUIRED prop to be passedd to the Card kit when implementing dragging.
4
9
 
5
- The dev must manage state as shown.
@@ -1,7 +1,5 @@
1
- For a simplified version of the Draggable API for the List kit, use the DraggableProvider to wrap the List kit and use the `enableDrag` prop.
1
+ For a simplified version of the Draggable API for the List kit, you can do the following:
2
2
 
3
- In addition to the above `dragId` is a REQUIRED prop to be passed to the List kit when implementing dragging.
3
+ Use `DraggableProvider` and manage state as shown.
4
4
 
5
- The dev must manage state as shown.
6
-
7
- The dragHandle is added by default but this can be opted out of by setting `dragHandle` to false on the List kit.
5
+ The List kit is optimized to work with the draggable kit. To enable drag, use the `enableDrag` prop on List kit AND `dragId` prop on ListItem. An additional optional boolean prop (set to true by default) of `dragHandle` is also available on List kit to show the drag handle icon.
@@ -1,7 +1,5 @@
1
- For a simplified version of the Draggable API for the SelectableList kit, use the DraggableProvider to wrap the SelectableList kit and use the `enableDrag` prop.
1
+ For a simplified version of the Draggable API for the SelectableList kit, you can do the following:
2
2
 
3
- In addition to the above `dragId` is a REQUIRED prop to be passed to the SelectableList kit when implementing dragging.
3
+ Use `DraggableProvider` and manage state as shown.
4
4
 
5
- The dev must manage state as shown.
6
-
7
- The dragHandle is added by default but this can be opted out of by setting `dragHandle` to false on the SelectableList kit.
5
+ The SelectableList kit is optimized to work with the draggable kit. To enable drag, use the `enableDrag` prop on SelectableList kit AND `dragId` prop on SelectableList.Item. An additional optional boolean prop (set to true by default) of `dragHandle` is also available on SelectableList kit to show the drag handle icon.
@@ -8,7 +8,9 @@
8
8
  <%= pb_rails("caption", props: {text: object.label, margin_bottom:"xs"}) %>
9
9
  <% end %>
10
10
  <div class="dropdown_wrapper<%= error_class %>" style="position: relative">
11
- <input type="hidden" name="<%= object.name %>" id="dropdown-selected-option" value=""/>
11
+ <input type="hidden" name="<%= object.name %>" id="dropdown-selected-option" value="" />
12
+ <input id="dropdown-form-validation" name="<%= object.name %>_form_validation" value="" style="display: none" <%= object.required ? "required" : ""%> />
13
+
12
14
  <% if content.present? %>
13
15
  <%= content.presence %>
14
16
  <%= pb_rails("body", props: { status: "negative", text: object.error }) %>
@@ -8,6 +8,8 @@ module Playbook
8
8
  prop :label, type: Playbook::Props::String
9
9
  prop :name, type: Playbook::Props::String
10
10
  prop :error, type: Playbook::Props::String
11
+ prop :required, type: Playbook::Props::Boolean,
12
+ default: false
11
13
 
12
14
  def data
13
15
  Hash(prop(:data)).merge(pb_dropdown: true)
@@ -8,16 +8,22 @@ const DOWN_ARROW_SELECTOR = "#dropdown_open_icon";
8
8
  const UP_ARROW_SELECTOR = "#dropdown_close_icon";
9
9
  const OPTION_SELECTOR = "[data-dropdown-option-label]";
10
10
  const CUSTOM_DISPLAY_SELECTOR = "[data-dropdown-custom-trigger]";
11
+ const INPUT_FORM_VALIDATION = "#dropdown-form-validation";
11
12
 
12
13
  export default class PbDropdown extends PbEnhancedElement {
13
14
  static get selector() {
14
15
  return DROPDOWN_SELECTOR;
15
16
  }
16
17
 
18
+ get target() {
19
+ return this.element.parentNode.querySelector(CONTAINER_SELECTOR);
20
+ }
21
+
17
22
  connect() {
18
23
  this.keyboardHandler = new PbDropdownKeyboard(this);
19
24
  this.bindEventListeners();
20
25
  this.updateArrowDisplay(false);
26
+ this.handleFormValidation();
21
27
  }
22
28
 
23
29
  bindEventListeners() {
@@ -38,9 +44,13 @@ export default class PbDropdown extends PbEnhancedElement {
38
44
  handleOptionClick(event) {
39
45
  const option = event.target.closest(OPTION_SELECTOR);
40
46
  const hiddenInput = this.element.querySelector("#dropdown-selected-option");
47
+ const inputFormValidation = this.element.querySelector(INPUT_FORM_VALIDATION);
48
+
41
49
  if (option) {
42
50
  const value = option.dataset.dropdownOptionLabel;
43
51
  hiddenInput.value = JSON.parse(value).id;
52
+ inputFormValidation.value = JSON.parse(value).id;
53
+ this.clearFormValidation(inputFormValidation);
44
54
  this.onOptionSelected(value, option);
45
55
  }
46
56
  }
@@ -103,10 +113,6 @@ export default class PbDropdown extends PbEnhancedElement {
103
113
  selectedOption.classList.add("pb_dropdown_option_selected");
104
114
  }
105
115
 
106
- get target() {
107
- return this.element.parentNode.querySelector(CONTAINER_SELECTOR);
108
- }
109
-
110
116
  showElement(elem) {
111
117
  elem.classList.remove("close");
112
118
  elem.classList.add("open");
@@ -150,4 +156,27 @@ export default class PbDropdown extends PbEnhancedElement {
150
156
  upArrow.style.display = isOpen ? "inline-block" : "none";
151
157
  }
152
158
  }
159
+
160
+ handleFormValidation() {
161
+ const inputFormValidation = this.element.querySelector(INPUT_FORM_VALIDATION);
162
+
163
+ inputFormValidation.addEventListener("invalid", function (event) {
164
+ if (inputFormValidation.hasAttribute("required") && inputFormValidation.value === "") {
165
+ event.preventDefault();
166
+ inputFormValidation.closest(".dropdown_wrapper").classList.add("error");
167
+ }
168
+ }, true);
169
+ }
170
+
171
+ clearFormValidation(input) {
172
+ if (input.checkValidity()) {
173
+ const dropdownWrapperElement = input.closest(".dropdown_wrapper");
174
+ dropdownWrapperElement.classList.remove("error");
175
+
176
+ const errorLabelElement = dropdownWrapperElement.querySelector(".pb_body_kit_negative");
177
+ if (errorLabelElement) {
178
+ errorLabelElement.remove();
179
+ }
180
+ }
181
+ }
153
182
  }
@@ -13,6 +13,14 @@
13
13
  ]
14
14
  %>
15
15
 
16
+ <%
17
+ example_dropdown_options = [
18
+ { label: 'United States', value: 'United States', id: 'us' },
19
+ { label: 'Canada', value: 'Canada', id: 'ca' },
20
+ { label: 'Pakistan', value: 'Pakistan', id: 'pk' },
21
+ ]
22
+ %>
23
+
16
24
  <%= pb_form_with(scope: :example, method: :get, url: "", validate: true) do |form| %>
17
25
  <%= form.text_field :example_text_field, props: { label: true, required: true } %>
18
26
  <%= form.phone_number_field :example_phone_number_field, props: { label: "Example phone field" } %>
@@ -22,6 +30,7 @@
22
30
  <%= form.password_field :example_password_field, props: { label: true, required: true } %>
23
31
  <%= form.url_field :example_url_field, props: { label: true, required: true } %>
24
32
  <%= form.text_area :example_text_area, props: { label: true, required: true } %>
33
+ <%= form.dropdown_field :example_dropdown, props: { label: true, options: example_dropdown_options, required: true } %>
25
34
  <%= form.select :example_select, [ ["Yes", 1], ["No", 2] ], props: { label: true, blank_selection: "Select One...", required: true } %>
26
35
  <%= form.collection_select :example_collection_select, example_collection, :value, :name, props: { label: true, blank_selection: "Select One...", required: true } %>
27
36
  <%= form.check_box :example_checkbox, props: { text: "Example Checkbox", label: true, required: true } %>
@@ -55,7 +55,7 @@ $form_pill_colors: (
55
55
  height: fit-content;
56
56
  height: -moz-fit-content;
57
57
  .pb_form_pill_text, .pb_form_pill_close, .pb_form_pill_tag {
58
- font-size: 16px;
58
+ font-size: $font_base;
59
59
  font-weight: $regular;
60
60
  }
61
61
  .pb_form_pill_text, .pb_form_pill_tag {
@@ -3,7 +3,6 @@ import classnames from 'classnames'
3
3
  import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
4
4
  import { GlobalProps, globalProps } from '../utilities/globalProps'
5
5
  import { isValidEmoji } from '../utilities/validEmojiChecker'
6
- import aliasesJson from './icon_aliases.json'
7
6
 
8
7
  export type IconSizes = "lg"
9
8
  | "xs"
@@ -41,19 +40,6 @@ type IconProps = {
41
40
  spin?: boolean,
42
41
  } & GlobalProps
43
42
 
44
- type AliasType = string | string[];
45
-
46
- interface Aliases {
47
- [key: string]: AliasType;
48
- }
49
-
50
- interface AliasesJson {
51
- aliases: Aliases;
52
- }
53
-
54
- const aliases: AliasesJson = aliasesJson;
55
-
56
-
57
43
  const flipMap = {
58
44
  horizontal: 'fa-flip-horizontal',
59
45
  vertical: 'fa-flip-vertical',
@@ -66,22 +52,6 @@ declare global {
66
52
  var PB_ICONS: {[key: string]: React.FunctionComponent<any>}
67
53
  }
68
54
 
69
- // Resolve alias function
70
- const resolveAlias = (icon: string): string => {
71
- const alias = aliases.aliases[icon];
72
-
73
- if (alias) {
74
- if (Array.isArray(alias)) {
75
- return alias[0];
76
- } else {
77
- return alias;
78
- }
79
- }
80
-
81
- return icon;
82
- };
83
-
84
-
85
55
  const Icon = (props: IconProps) => {
86
56
  const {
87
57
  aria = {},
@@ -104,8 +74,7 @@ const Icon = (props: IconProps) => {
104
74
  spin = false,
105
75
  } = props
106
76
 
107
- const resolvedIcon = resolveAlias(icon as string)
108
- let iconElement: ReactSVGElement | null = typeof(resolvedIcon) === "object" ? resolvedIcon : null
77
+ let iconElement: ReactSVGElement | null = typeof(icon) === "object" ? icon : null
109
78
 
110
79
  const faClasses = {
111
80
  'fa-border': border,
@@ -121,12 +90,12 @@ const Icon = (props: IconProps) => {
121
90
 
122
91
  if (!customIcon && !iconElement) {
123
92
  const PowerIcon: React.FunctionComponent<any> | undefined =
124
- window.PB_ICONS ? window.PB_ICONS[resolvedIcon as string] : null
93
+ window.PB_ICONS ? window.PB_ICONS[icon as string] : null
125
94
 
126
95
  if (PowerIcon) {
127
96
  iconElement = <PowerIcon /> as ReactSVGElement
128
97
  } else {
129
- faClasses[`fa-${resolvedIcon}`] = resolvedIcon as string
98
+ faClasses[`fa-${icon}`] = icon as string
130
99
  }
131
100
  }
132
101
 
@@ -146,7 +115,7 @@ const Icon = (props: IconProps) => {
146
115
  className
147
116
  )
148
117
 
149
- aria.label ? null : aria.label = `${resolvedIcon} icon`
118
+ aria.label ? null : aria.label = `${icon} icon`
150
119
  const ariaProps: {[key: string]: any} = buildAriaProps(aria)
151
120
  const dataProps: {[key: string]: any} = buildDataProps(data)
152
121
  const htmlProps = buildHtmlProps(htmlOptions)
@@ -168,7 +137,7 @@ const Icon = (props: IconProps) => {
168
137
  }
169
138
  </>
170
139
  )
171
- else if (isValidEmoji(resolvedIcon as string))
140
+ else if (isValidEmoji(icon as string))
172
141
  return (
173
142
  <>
174
143
  <span
@@ -177,7 +146,7 @@ const Icon = (props: IconProps) => {
177
146
  className={classesEmoji}
178
147
  id={id}
179
148
  >
180
- {resolvedIcon}
149
+ {icon}
181
150
  </span>
182
151
  </>
183
152
  )
@@ -39,8 +39,6 @@ module Playbook
39
39
  prop :spin, type: Playbook::Props::Boolean,
40
40
  default: false
41
41
 
42
- ALIASES = JSON.parse(File.read(Playbook::Engine.root.join("app/pb_kits/playbook/pb_icon/icon_aliases.json")))["aliases"].freeze
43
-
44
42
  def valid_emoji?
45
43
  emoji_regex = /\p{Emoji}/
46
44
  emoji_regex.match?(icon)
@@ -82,6 +80,14 @@ module Playbook
82
80
  )
83
81
  end
84
82
 
83
+ def icon_alias_map
84
+ return unless Rails.application.config.respond_to?(:icon_alias_path)
85
+
86
+ base_path = Rails.application.config.icon_alias_path
87
+ json = File.read(Rails.root.join(base_path))
88
+ JSON.parse(json)["aliases"].freeze
89
+ end
90
+
85
91
  def asset_path
86
92
  return unless Rails.application.config.respond_to?(:icon_path)
87
93
 
@@ -111,7 +117,7 @@ module Playbook
111
117
  private
112
118
 
113
119
  def resolve_alias(icon)
114
- aliases = ALIASES[icon]
120
+ aliases = icon_alias_map[icon]
115
121
  return icon unless aliases
116
122
 
117
123
  if aliases.is_a?(Array)
@@ -86,33 +86,18 @@ const RichTextEditor = (props: RichTextEditorProps): React.ReactElement => {
86
86
  const toolbarElement = element.parentElement.querySelector('trix-toolbar') as HTMLElement,
87
87
  blockCodeButton = toolbarElement.querySelector('[data-trix-attribute=code]') as HTMLElement
88
88
 
89
+ // replace default trix "block code" button with "inline code" button
89
90
  let inlineCodeButton = toolbarElement.querySelector('[data-trix-attribute=inlineCode]') as HTMLElement
90
- if (!inlineCodeButton) inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
91
-
92
- // set button attributes
93
- inlineCodeButton.dataset.trixAttribute = 'inlineCode'
94
- blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
91
+ if (!inlineCodeButton) {
92
+ inlineCodeButton = blockCodeButton.cloneNode(true) as HTMLElement
93
+ blockCodeButton.hidden = true
94
+ // set button attributes
95
+ inlineCodeButton.dataset.trixAttribute = 'inlineCode'
96
+ blockCodeButton.insertAdjacentElement('afterend', inlineCodeButton)
97
+ }
95
98
 
96
99
  if (toolbarBottom) editor.element.after(toolbarElement)
97
100
 
98
- const getCodeFormattingType = (): string => {
99
- if (editor.attributeIsActive('code')) return 'block'
100
- if (editor.attributeIsActive('inlineCode')) return 'inline'
101
-
102
- const range = editor.getSelectedRange()
103
- if (range[0] == range[1]) return 'block'
104
-
105
- const text = editor.getSelectedDocument().toString().trim()
106
- return /\n/.test(text) ? 'block' : 'inline'
107
- }
108
-
109
- // DOM event listeners
110
- element.addEventListener('trix-selection-change', () => {
111
- const type = getCodeFormattingType()
112
- blockCodeButton.hidden = type == 'inline'
113
- inlineCodeButton.hidden = type == 'block'
114
- })
115
-
116
101
  focus
117
102
  ? (document.addEventListener('trix-focus', useFocus),
118
103
  document.addEventListener('trix-blur', useFocus),
@@ -5,10 +5,11 @@
5
5
  @mixin pb_title(
6
6
  $fontSize: $heading_1,
7
7
  $fontWeight: $lighter,
8
- $lineHeight: $lh_tighter
8
+ $lineHeight: $lh_tighter,
9
+ $letterSpacing: $lspace_tight
9
10
  ){
10
11
  font-size: $fontSize;
11
- letter-spacing: $lspace_tight;
12
+ letter-spacing: $letterSpacing;
12
13
  font-weight: $fontWeight;
13
14
  color: $text_lt_default;
14
15
  margin: 0;
@@ -29,8 +30,7 @@
29
30
  }
30
31
 
31
32
  @mixin pb_title_4 {
32
- @include pb_title($heading_4, $bolder);
33
- letter-spacing: -0.03em;
33
+ @include pb_title($heading_4, $bolder, $letterSpacing: $lspace_normal);
34
34
  }
35
35
 
36
36
  @mixin pb_title_dark {