playbook_ui 16.12.0.pre.alpha.ATtest18202 → 16.12.0.pre.alpha.PLAY3072railstextinputrequiredaddonmaskingbugs18157
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.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +1 -2
- data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.json +0 -8
- data/app/pb_kits/playbook/pb_advanced_table/docs/_playground.overrides.json +0 -8
- data/app/pb_kits/playbook/pb_advanced_table/kit.schema.json +1 -1
- data/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +3 -18
- data/app/pb_kits/playbook/pb_dropdown/docs/example.yml +0 -2
- data/app/pb_kits/playbook/pb_dropdown/docs/index.js +0 -1
- data/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +0 -35
- data/app/pb_kits/playbook/pb_dropdown/hooks/useHandleOnKeydown.tsx +1 -18
- data/app/pb_kits/playbook/pb_dropdown/index.js +0 -34
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownOption.tsx +1 -8
- data/app/pb_kits/playbook/pb_dropdown/subcomponents/DropdownTrigger.tsx +6 -7
- data/app/pb_kits/playbook/pb_form/docs/_form_form_with_validate_addon_currency.html.erb +123 -0
- data/app/pb_kits/playbook/pb_form/docs/example.yml +1 -0
- data/app/pb_kits/playbook/pb_icon_button/_icon_button.scss +78 -0
- data/app/pb_kits/playbook/pb_icon_button/_icon_button.tsx +75 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_click.jsx +13 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_default.html.erb +2 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_default.jsx +17 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_sizes.html.erb +27 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_icon_button_sizes.jsx +63 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_playground.json +135 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/_playground.overrides.json +131 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/example.yml +10 -0
- data/app/pb_kits/playbook/pb_icon_button/docs/index.js +3 -0
- data/app/pb_kits/playbook/pb_icon_button/icon_button.html.erb +17 -0
- data/app/pb_kits/playbook/pb_icon_button/icon_button.rb +25 -0
- data/app/pb_kits/playbook/pb_icon_button/icon_button.test.jsx +39 -0
- data/app/pb_kits/playbook/pb_icon_button/kit.schema.json +116 -0
- data/app/pb_kits/playbook/pb_timestamp/_timestamp.tsx +2 -2
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_updated.html.erb +0 -19
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_updated.jsx +0 -21
- data/app/pb_kits/playbook/pb_timestamp/docs/_timestamp_updated.md +1 -3
- data/app/pb_kits/playbook/pb_timestamp/timestamp.test.js +0 -42
- data/dist/chunks/{_pb_line_graph-CVbptQfB.js → _pb_line_graph-BL9pXDkX.js} +1 -1
- data/dist/chunks/_typeahead-BrQbahtd.js +5 -0
- data/dist/chunks/{globalProps-CTGiwXyh.js → globalProps-BQqb1ZGy.js} +1 -1
- data/dist/chunks/lib-CYrXqTdQ.js +29 -0
- data/dist/chunks/time_picker_helper-CVMV9ync.js +1 -0
- data/dist/chunks/vendor.js +23 -3
- data/dist/menu.yml +6 -0
- data/dist/playbook-rails-react-bindings.js +1 -1
- data/dist/playbook-rails.js +1 -1
- data/dist/playbook.css +1 -1
- data/lib/playbook/version.rb +1 -1
- metadata +23 -13
- data/app/pb_kits/playbook/pb_advanced_table/docs/_description_react.md +0 -6
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value_with_autocomplete.html.erb +0 -10
- data/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_default_value_with_autocomplete.jsx +0 -35
- data/dist/chunks/StickyLayoutHelper-DCzCcWUN.js +0 -1
- data/dist/chunks/_detail-ChXSAxU0.js +0 -5
- data/dist/chunks/_table-CUOE7A8S.js +0 -1
- data/dist/chunks/_typeahead-D1_wsX6x.js +0 -1
- data/dist/chunks/lib-qubCkjWq.js +0 -29
- data/dist/chunks/time_picker_helper-Bx8nzyM8.js +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 808c3d5ab3e82537f24aeac0f1cb2e402a30d4afae94e25825bfcc0cbe8feda0
|
|
4
|
+
data.tar.gz: '084bedeca9f2498f50b6cac05965995b7cc91021f4eebd6e5e149caf79583a25'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bca00447e61c8e7ed070c1ea0fe1fa3ade2c78d3ac3a2ecc2a294d9fb25464575f299aa231f8c4808344197e741daed75e5cd7d6b408c10fe16a39327953af13
|
|
7
|
+
data.tar.gz: 52fced873ada1be081e91b4b01dbf166ed0f41e17545e86d467a1168c0d0526660e0712c04921718db3201c540c19341403873f20fe816f0205f90ae445c1cbc
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
@import 'pb_highlight/highlight';
|
|
42
42
|
@import 'pb_home_address_street/home_address_street';
|
|
43
43
|
@import 'pb_icon/icon';
|
|
44
|
+
@import 'pb_icon_button/icon_button';
|
|
44
45
|
@import 'pb_icon_circle/icon_circle';
|
|
45
46
|
@import 'pb_icon_stat_value/icon_stat_value';
|
|
46
47
|
@import 'pb_icon_value/icon_value';
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import React, {useState} from "react"
|
|
2
2
|
import { render, screen, waitFor } from "../utilities/test-utils"
|
|
3
3
|
|
|
4
|
-
import { AdvancedTable } from "playbook-ui
|
|
5
|
-
import { Pill, colors } from "playbook-ui"
|
|
4
|
+
import { AdvancedTable, Pill, colors } from "playbook-ui"
|
|
6
5
|
|
|
7
6
|
global.ResizeObserver = class {
|
|
8
7
|
observe() {}
|
|
@@ -259,11 +259,6 @@
|
|
|
259
259
|
}
|
|
260
260
|
},
|
|
261
261
|
"hints": {
|
|
262
|
-
"advanced_table_import": {
|
|
263
|
-
"when": {},
|
|
264
|
-
"message": "AdvancedTable is imported from playbook-ui/advanced-table so apps can keep TanStack out of the main playbook-ui bundle until this kit is used.",
|
|
265
|
-
"type": "info"
|
|
266
|
-
},
|
|
267
262
|
"sorting_info": {
|
|
268
263
|
"when": {
|
|
269
264
|
"enableSortingRemoval": true
|
|
@@ -321,9 +316,6 @@
|
|
|
321
316
|
"type": "info"
|
|
322
317
|
}
|
|
323
318
|
},
|
|
324
|
-
"externalImports": [
|
|
325
|
-
"import { AdvancedTable } from 'playbook-ui/advanced-table'"
|
|
326
|
-
],
|
|
327
319
|
"structureModes": {
|
|
328
320
|
"default": "implicit",
|
|
329
321
|
"modes": {
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"externalImports": [
|
|
3
|
-
"import { AdvancedTable } from 'playbook-ui/advanced-table'"
|
|
4
|
-
],
|
|
5
2
|
"structureModes": {
|
|
6
3
|
"default": "implicit",
|
|
7
4
|
"modes": {
|
|
@@ -314,11 +311,6 @@
|
|
|
314
311
|
}
|
|
315
312
|
},
|
|
316
313
|
"hints": {
|
|
317
|
-
"advanced_table_import": {
|
|
318
|
-
"when": {},
|
|
319
|
-
"message": "AdvancedTable is imported from playbook-ui/advanced-table so apps can keep TanStack out of the main playbook-ui bundle until this kit is used.",
|
|
320
|
-
"type": "info"
|
|
321
|
-
},
|
|
322
314
|
"sorting_info": {
|
|
323
315
|
"when": {
|
|
324
316
|
"enableSortingRemoval": true
|
|
@@ -312,7 +312,7 @@
|
|
|
312
312
|
"globalProps": true,
|
|
313
313
|
"usage": {
|
|
314
314
|
"react": {
|
|
315
|
-
"import": "import { AdvancedTable } from 'playbook-ui
|
|
315
|
+
"import": "import { AdvancedTable } from 'playbook-ui'",
|
|
316
316
|
"example": "<AdvancedTable columnGroupBorderColor=\"text_lt_default\" enableToggleExpansion=\"all\"></AdvancedTable>"
|
|
317
317
|
},
|
|
318
318
|
"rails": {
|
|
@@ -203,6 +203,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
203
203
|
: undefined;
|
|
204
204
|
const errorId = error ? `${selectId}-error` : undefined;
|
|
205
205
|
|
|
206
|
+
const [filterItem, setFilterItem] = useState("");
|
|
206
207
|
const initialSelected = useMemo(() => {
|
|
207
208
|
// Handle quickpick variant with string defaultValue (e.g., "This Month")
|
|
208
209
|
if (variant === "quickpick" && typeof defaultValue === "string" && defaultValue) {
|
|
@@ -225,13 +226,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
225
226
|
initialSelected
|
|
226
227
|
);
|
|
227
228
|
|
|
228
|
-
// Autocomplete displays the selection in the input; seed from defaultValue
|
|
229
|
-
const [filterItem, setFilterItem] = useState(() => {
|
|
230
|
-
if (!autocomplete || multiSelect) return "";
|
|
231
|
-
if (Array.isArray(initialSelected)) return "";
|
|
232
|
-
return (initialSelected as GenericObject)?.label || "";
|
|
233
|
-
});
|
|
234
|
-
|
|
235
229
|
const filterResetDefaultSerialized = useMemo(
|
|
236
230
|
() => serializeDropdownFilterResetDefault(variant, multiSelect, defaultValue, dropdownOptions),
|
|
237
231
|
[variant, multiSelect, defaultValue, dropdownOptions]
|
|
@@ -326,17 +320,10 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
326
320
|
}, [optionsWithBlankSelection, selectedArray, multiSelect]);
|
|
327
321
|
|
|
328
322
|
const filteredOptions = useMemo(() => {
|
|
329
|
-
// When the input shows the selected label, do not filter the list down to that one option
|
|
330
|
-
const selectedLabel =
|
|
331
|
-
!multiSelect &&
|
|
332
|
-
!Array.isArray(selected) &&
|
|
333
|
-
(selected as GenericObject)?.label;
|
|
334
|
-
const filterText =
|
|
335
|
-
selectedLabel && filterItem === selectedLabel ? "" : filterItem;
|
|
336
323
|
return availableOptions.filter((opt: GenericObject) =>
|
|
337
|
-
String(opt.label).toLowerCase().includes(
|
|
324
|
+
String(opt.label).toLowerCase().includes(filterItem.toLowerCase())
|
|
338
325
|
);
|
|
339
|
-
}, [availableOptions, filterItem
|
|
326
|
+
}, [availableOptions, filterItem]);
|
|
340
327
|
|
|
341
328
|
// For keyboard accessibility: Set focus within dropdown to selected item if it exists
|
|
342
329
|
useEffect(() => {
|
|
@@ -473,7 +460,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
473
460
|
setSelected({});
|
|
474
461
|
onSelect && onSelect(null);
|
|
475
462
|
setFocusedOptionIndex(-1);
|
|
476
|
-
setFilterItem("");
|
|
477
463
|
|
|
478
464
|
// Clear linked DatePickers as well if this is a quickpick variant with controls
|
|
479
465
|
if (variant === "quickpick") {
|
|
@@ -607,7 +593,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => {
|
|
|
607
593
|
onSelect,
|
|
608
594
|
optionsWithBlankSelection,
|
|
609
595
|
selected,
|
|
610
|
-
setFilterItem,
|
|
611
596
|
setFocusedOptionIndex,
|
|
612
597
|
setIsDropDownClosed,
|
|
613
598
|
setIsInputFocused,
|
|
@@ -22,7 +22,6 @@ examples:
|
|
|
22
22
|
- dropdown_error: Dropdown with Error
|
|
23
23
|
- dropdown_default_value: Default Value
|
|
24
24
|
- dropdown_multi_select_with_default: Multi Select Default Value
|
|
25
|
-
- dropdown_default_value_with_autocomplete: Default Value with Autocomplete
|
|
26
25
|
- dropdown_blank_selection: Blank Selection
|
|
27
26
|
- dropdown_with_placeholder: Placeholder
|
|
28
27
|
- dropdown_separators_hidden: Separators Hidden
|
|
@@ -64,7 +63,6 @@ examples:
|
|
|
64
63
|
- dropdown_error: Dropdown with Error
|
|
65
64
|
- dropdown_default_value: Default Value
|
|
66
65
|
- dropdown_multi_select_with_default: Multi Select Default Value
|
|
67
|
-
- dropdown_default_value_with_autocomplete: Default Value with Autocomplete
|
|
68
66
|
- dropdown_blank_selection: Blank Selection
|
|
69
67
|
- dropdown_with_placeholder: Placeholder
|
|
70
68
|
- dropdown_clear_selection: Clear Selection
|
|
@@ -37,4 +37,3 @@ export { default as DropdownDisabledOption } from "./_dropdown_disabled_option.j
|
|
|
37
37
|
export { default as DropdownCustomDisplayDisabledOption } from "./_dropdown_custom_display_disabled_option.jsx";
|
|
38
38
|
export { default as DropdownDisabled } from "./_dropdown_disabled.jsx";
|
|
39
39
|
export { default as DropdownGroupedOptions } from "./_dropdown_grouped_options.jsx";
|
|
40
|
-
export { default as DropdownDefaultValueWithAutocomplete } from './_dropdown_default_value_with_autocomplete.jsx'
|
|
@@ -350,41 +350,6 @@ test("autocomplete prop to render input", () => {
|
|
|
350
350
|
expect(input).toBeInTheDocument()
|
|
351
351
|
})
|
|
352
352
|
|
|
353
|
-
test("defaultValue renders in autocomplete input", () => {
|
|
354
|
-
render(
|
|
355
|
-
<Dropdown
|
|
356
|
-
autocomplete
|
|
357
|
-
data={{ testid: testId }}
|
|
358
|
-
defaultValue={options[2]}
|
|
359
|
-
options={options}
|
|
360
|
-
/>
|
|
361
|
-
)
|
|
362
|
-
|
|
363
|
-
const kit = screen.getByTestId(testId)
|
|
364
|
-
const input = kit.querySelector('.dropdown_input')
|
|
365
|
-
expect(input).toBeInTheDocument()
|
|
366
|
-
expect(input).toHaveValue(options[2].label)
|
|
367
|
-
expect(input).toHaveAttribute("placeholder", "")
|
|
368
|
-
})
|
|
369
|
-
|
|
370
|
-
test("autocomplete defaultValue still shows all options when opened", () => {
|
|
371
|
-
render(
|
|
372
|
-
<Dropdown
|
|
373
|
-
autocomplete
|
|
374
|
-
data={{ testid: testId }}
|
|
375
|
-
defaultValue={options[2]}
|
|
376
|
-
options={options}
|
|
377
|
-
/>
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
const kit = screen.getByTestId(testId)
|
|
381
|
-
const optionEls = kit.querySelectorAll('.pb_dropdown_option_list, .pb_dropdown_option_selected')
|
|
382
|
-
expect(optionEls).toHaveLength(options.length)
|
|
383
|
-
expect(kit).toHaveTextContent(options[0].label)
|
|
384
|
-
expect(kit).toHaveTextContent(options[1].label)
|
|
385
|
-
expect(kit).toHaveTextContent(options[2].label)
|
|
386
|
-
})
|
|
387
|
-
|
|
388
353
|
test("searchbar prop to render TextInput in container", () => {
|
|
389
354
|
render (
|
|
390
355
|
<Dropdown
|
|
@@ -6,13 +6,11 @@ export const useHandleOnKeyDown = () => {
|
|
|
6
6
|
|
|
7
7
|
const {
|
|
8
8
|
autocomplete,
|
|
9
|
-
filterItem,
|
|
10
9
|
filteredOptions,
|
|
11
10
|
focusedOptionIndex,
|
|
12
11
|
handleBackspace,
|
|
13
12
|
handleOptionClick,
|
|
14
13
|
selected,
|
|
15
|
-
setFilterItem,
|
|
16
14
|
setFocusedOptionIndex,
|
|
17
15
|
setIsDropDownClosed,
|
|
18
16
|
}= useContext(DropdownContext)
|
|
@@ -42,22 +40,7 @@ const {
|
|
|
42
40
|
return (e: React.KeyboardEvent) => {
|
|
43
41
|
|
|
44
42
|
if (e.key !== "Tab" && autocomplete && selected && selected.label) {
|
|
45
|
-
// Only when the input is showing the selected label (e.g. seeded defaultValue)
|
|
46
|
-
const replacingSelectedLabel = filterItem === selected.label;
|
|
47
43
|
handleBackspace();
|
|
48
|
-
|
|
49
|
-
if (replacingSelectedLabel && e.key.length === 1 && !e.ctrlKey && !e.metaKey && !e.altKey) {
|
|
50
|
-
e.preventDefault();
|
|
51
|
-
setFilterItem?.(e.key);
|
|
52
|
-
setIsDropDownClosed(false);
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (replacingSelectedLabel && (e.key === "Backspace" || e.key === "Delete")) {
|
|
57
|
-
e.preventDefault();
|
|
58
|
-
setFilterItem?.("");
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
44
|
}
|
|
62
45
|
|
|
63
46
|
switch (e.key) {
|
|
@@ -89,4 +72,4 @@ const {
|
|
|
89
72
|
break;
|
|
90
73
|
}
|
|
91
74
|
}
|
|
92
|
-
};
|
|
75
|
+
};
|
|
@@ -541,30 +541,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
541
541
|
}
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
-
// Keep the selected label in the autocomplete input, but do not treat it as a search filter
|
|
545
|
-
resetOptionFilterForSelectedLabel() {
|
|
546
|
-
if (this.isMultiSelect || !this.searchInput) return;
|
|
547
|
-
|
|
548
|
-
const selectedOption = Array.from(this.queryAllOptions()).find((opt) =>
|
|
549
|
-
opt.classList.contains("pb_dropdown_option_selected"),
|
|
550
|
-
);
|
|
551
|
-
if (!selectedOption) return;
|
|
552
|
-
|
|
553
|
-
try {
|
|
554
|
-
const selectedLabel = JSON.parse(
|
|
555
|
-
selectedOption.dataset.dropdownOptionLabel,
|
|
556
|
-
).label;
|
|
557
|
-
if (this.searchInput.value !== selectedLabel) return;
|
|
558
|
-
|
|
559
|
-
this.queryAllOptions().forEach((opt) => {
|
|
560
|
-
opt.style.display = "";
|
|
561
|
-
});
|
|
562
|
-
this.removeNoOptionsMessage();
|
|
563
|
-
} catch {
|
|
564
|
-
// ignore invalid option payloads
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
|
|
568
544
|
showNoOptionsMessage() {
|
|
569
545
|
if (this.target?.querySelector(".dropdown_no_options")) return;
|
|
570
546
|
|
|
@@ -947,9 +923,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
947
923
|
|
|
948
924
|
showElement(elem) {
|
|
949
925
|
if (this.isDisabled) return;
|
|
950
|
-
|
|
951
|
-
// When autocomplete is showing the selected label (not an active search), show all options
|
|
952
|
-
this.resetOptionFilterForSelectedLabel();
|
|
953
926
|
|
|
954
927
|
this.ensureFloatingPortalConfig();
|
|
955
928
|
if (this.useMenuPortal) {
|
|
@@ -1123,13 +1096,6 @@ export default class PbDropdown extends PbEnhancedElement {
|
|
|
1123
1096
|
const optionData = JSON.parse(selectedOption.dataset.dropdownOptionLabel);
|
|
1124
1097
|
this.setTriggerElementText(optionData.label);
|
|
1125
1098
|
|
|
1126
|
-
// Autocomplete trigger has no [data-dropdown-trigger-display]; set the input value instead
|
|
1127
|
-
const autocompleteInput =
|
|
1128
|
-
this.searchInput || this.element.querySelector(SEARCH_INPUT_SELECTOR);
|
|
1129
|
-
if (autocompleteInput) {
|
|
1130
|
-
autocompleteInput.value = optionData.label;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
1099
|
// Handle quickpick variant: populate start/end date hidden inputs and sync DatePickers
|
|
1134
1100
|
if (optionData.formatted_start_date && optionData.formatted_end_date) {
|
|
1135
1101
|
const startDateId = this.element.dataset.startDateId;
|
|
@@ -52,15 +52,8 @@ const DropdownOption = (props: DropdownOptionProps) => {
|
|
|
52
52
|
} = useContext(DropdownContext);
|
|
53
53
|
|
|
54
54
|
const isItemMatchingFilter = (option: GenericObject | undefined) => {
|
|
55
|
-
// When the input is only showing the selected label (e.g. seeded defaultValue), do not filter
|
|
56
|
-
const selectedLabel =
|
|
57
|
-
!multiSelect &&
|
|
58
|
-
!Array.isArray(selected) &&
|
|
59
|
-
(selected as GenericObject)?.label;
|
|
60
|
-
const filterText =
|
|
61
|
-
selectedLabel && filterItem === selectedLabel ? "" : filterItem;
|
|
62
55
|
const label = typeof option?.label === 'string' ? option.label.toLowerCase() : option?.label;
|
|
63
|
-
return String(label).toLowerCase().includes(
|
|
56
|
+
return String(label).toLowerCase().includes(filterItem.toLowerCase());
|
|
64
57
|
}
|
|
65
58
|
|
|
66
59
|
// When multiSelect, then if an option is selected, remove from dropdown
|
|
@@ -103,9 +103,8 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
103
103
|
"Select..."
|
|
104
104
|
);
|
|
105
105
|
|
|
106
|
-
const hideJoinedLabelInBody = Boolean(autocomplete && filterItem === joinedLabels);
|
|
107
106
|
const defaultDisplayPlaceholder = joinedLabels
|
|
108
|
-
?
|
|
107
|
+
? joinedLabels
|
|
109
108
|
: autocomplete
|
|
110
109
|
? ""
|
|
111
110
|
: placeholder
|
|
@@ -253,9 +252,9 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
253
252
|
}}
|
|
254
253
|
key={`${isDropDownClosed ? "chevron-down" : "chevron-up"}`}
|
|
255
254
|
>
|
|
256
|
-
{(!blankSelection || selected?.value !== optionsWithBlankSelection?.[0]?.value) &&
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
{(!blankSelection || selected?.value !== optionsWithBlankSelection?.[0]?.value) && (
|
|
256
|
+
<>
|
|
257
|
+
{clearable !== false && selectedArray.length > 0 && (
|
|
259
258
|
<div onClick={(e)=>{e.stopPropagation(); !disabled && handleBackspace()}}>
|
|
260
259
|
<Icon
|
|
261
260
|
cursor={disabled ? "default" : "pointer"}
|
|
@@ -265,8 +264,8 @@ const DropdownTrigger = (props: DropdownTriggerProps) => {
|
|
|
265
264
|
size="sm"
|
|
266
265
|
/>
|
|
267
266
|
</div>
|
|
268
|
-
|
|
269
|
-
|
|
267
|
+
)}
|
|
268
|
+
</>
|
|
270
269
|
)}
|
|
271
270
|
<Icon
|
|
272
271
|
cursor={disabled ? "default" : "pointer"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<%= pb_rails("title", props: { text: "Demo 1: Mask + Add On Hidden Input/Submission"})%>
|
|
2
|
+
<%= pb_form_with(scope: :transaction, method: :get, url: "", validate: true, data: { addon_currency_example: true }) do |form| %>
|
|
3
|
+
<%= pb_rails("text_input", props: {
|
|
4
|
+
label: "pb_rails Text Input Currency Mask + Add On",
|
|
5
|
+
name: "transaction[amount]",
|
|
6
|
+
id: "transaction_amount",
|
|
7
|
+
mask: "currency",
|
|
8
|
+
add_on: { icon: "dollar-sign", alignment: "left", border: false },
|
|
9
|
+
placeholder: "$0.00",
|
|
10
|
+
required: true,
|
|
11
|
+
}) %>
|
|
12
|
+
<%= form.text_field :fee, props: { label: "Form Builder Text Input Currency Mask + Add On", placeholder: "$0.00", mask: "currency", add_on: { icon: "percent", alignment: "right", border: true }, required: true } %>
|
|
13
|
+
|
|
14
|
+
<%= pb_rails("text_input", props: {
|
|
15
|
+
label: "pb_rails Text Input ZIP Code Mask + Add On",
|
|
16
|
+
name: "transaction[zip_code]",
|
|
17
|
+
id: "transaction_zip_code",
|
|
18
|
+
mask: "zip_code",
|
|
19
|
+
add_on: { icon: "map-marker-alt", alignment: "left", border: false },
|
|
20
|
+
placeholder: "12345",
|
|
21
|
+
required: true,
|
|
22
|
+
}) %>
|
|
23
|
+
<%= form.text_field :zip_code_builder, props: { label: "Form Builder Text Input ZIP Code Mask + Add On", mask: "zip_code", add_on: { icon: "map-marker-alt", alignment: "right", border: true }, placeholder: "12345", required: true } %>
|
|
24
|
+
|
|
25
|
+
<%= pb_rails("text_input", props: {
|
|
26
|
+
label: "pb_rails Text Input Postal Code Mask + Add On",
|
|
27
|
+
name: "transaction[postal_code]",
|
|
28
|
+
id: "transaction_postal_code",
|
|
29
|
+
mask: "postal_code",
|
|
30
|
+
add_on: { icon: "mail-bulk", alignment: "left", border: false },
|
|
31
|
+
placeholder: "12345-6789",
|
|
32
|
+
required: true,
|
|
33
|
+
}) %>
|
|
34
|
+
<%= form.text_field :postal_code_builder, props: { label: "Form Builder Text Input Postal Code Mask + Add On", mask: "postal_code", add_on: { icon: "mail-bulk", alignment: "right", border: true }, placeholder: "12345-6789", required: true } %>
|
|
35
|
+
|
|
36
|
+
<%= pb_rails("text_input", props: {
|
|
37
|
+
label: "pb_rails Text Input SSN Mask + Add On",
|
|
38
|
+
name: "transaction[ssn]",
|
|
39
|
+
id: "transaction_ssn",
|
|
40
|
+
mask: "ssn",
|
|
41
|
+
add_on: { icon: "id-badge", alignment: "left", border: false },
|
|
42
|
+
placeholder: "123-45-6789",
|
|
43
|
+
required: true,
|
|
44
|
+
}) %>
|
|
45
|
+
<%= form.text_field :ssn_builder, props: { label: "Form Builder Text Input SSN Mask + Add On", mask: "ssn", add_on: { icon: "id-badge", alignment: "right", border: true }, placeholder: "123-45-6789", required: true } %>
|
|
46
|
+
|
|
47
|
+
<%= pb_rails("text_input", props: {
|
|
48
|
+
label: "pb_rails Text Input Credit Card Mask + Add On",
|
|
49
|
+
name: "transaction[credit_card]",
|
|
50
|
+
id: "transaction_credit_card",
|
|
51
|
+
mask: "credit_card",
|
|
52
|
+
add_on: { icon: "credit-card", alignment: "left", border: false },
|
|
53
|
+
placeholder: "1234 5678 9012 3456",
|
|
54
|
+
required: true,
|
|
55
|
+
}) %>
|
|
56
|
+
<%= form.text_field :credit_card_builder, props: { label: "Form Builder Text Input Credit Card Mask + Add On", mask: "credit_card", add_on: { icon: "credit-card", alignment: "right", border: true }, placeholder: "1234 5678 9012 3456", required: true } %>
|
|
57
|
+
|
|
58
|
+
<%= pb_rails("text_input", props: {
|
|
59
|
+
label: "pb_rails Text Input CVV Mask + Add On",
|
|
60
|
+
name: "transaction[cvv]",
|
|
61
|
+
id: "transaction_cvv",
|
|
62
|
+
mask: "cvv",
|
|
63
|
+
add_on: { icon: "lock", alignment: "left", border: false },
|
|
64
|
+
placeholder: "123",
|
|
65
|
+
required: true,
|
|
66
|
+
}) %>
|
|
67
|
+
<%= form.text_field :cvv_builder, props: { label: "Form Builder Text Input CVV Mask + Add On", mask: "cvv", add_on: { icon: "lock", alignment: "right", border: true }, placeholder: "123", required: true } %>
|
|
68
|
+
|
|
69
|
+
<%= form.text_field :reference, props: { label: "Form Builder Text Input Add On NO MASK", add_on: { icon: "frog", alignment: "left", border: true }, required: true } %>
|
|
70
|
+
|
|
71
|
+
<%= form.actions do |action| %>
|
|
72
|
+
<%= action.submit %>
|
|
73
|
+
<%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
|
|
74
|
+
<% end %>
|
|
75
|
+
<% end %>
|
|
76
|
+
<%= pb_rails("card", props: { margin_top: "sm" }) do %>
|
|
77
|
+
<%= pb_rails("caption", props: { text: "Submitted form data", margin_bottom: "xs" }) %>
|
|
78
|
+
<%= pb_rails("body", props: { text: "Submit the form to list every param the browser sends below. The same data is logged to the console. All fields are required." }) %>
|
|
79
|
+
<pre data-addon-currency-example-output></pre>
|
|
80
|
+
<% end %>
|
|
81
|
+
|
|
82
|
+
<%= javascript_tag defer: "defer" do %>
|
|
83
|
+
document.addEventListener("submit", function(event) {
|
|
84
|
+
const form = event.target
|
|
85
|
+
if (!form.dataset || !form.dataset.addonCurrencyExample) return
|
|
86
|
+
|
|
87
|
+
// Keep the example on the page so the params stay visible.
|
|
88
|
+
event.preventDefault()
|
|
89
|
+
|
|
90
|
+
const submitted = Array.from(new FormData(form).entries())
|
|
91
|
+
.filter(([name]) => name && !["utf8", "_method", "authenticity_token"].includes(name))
|
|
92
|
+
|
|
93
|
+
const output = document.querySelector("[data-addon-currency-example-output]")
|
|
94
|
+
output.textContent = submitted.length ?
|
|
95
|
+
submitted.map(([name, value]) => `${name}: ${JSON.stringify(value)}`).join("\n") :
|
|
96
|
+
"Nothing was submitted."
|
|
97
|
+
|
|
98
|
+
console.log("Submitted form data:", Object.fromEntries(submitted))
|
|
99
|
+
})
|
|
100
|
+
<% end %>
|
|
101
|
+
|
|
102
|
+
<%= pb_rails("title", props: { text: "Demo 2: Location of Validation Message"})%>
|
|
103
|
+
<%= pb_form_with(scope: :example, method: :get, url: "", validate: true) do |form| %>
|
|
104
|
+
<%= form.text_field :example_text_field_validation, props: { label: "Form Builder Text Input Add On", add_on: { icon: "frog", alignment: 'right', border: true }, required: true } %>
|
|
105
|
+
<%= form.text_field :example_text_field_validation_2, props: { label: "Form Builder Text Input Currency Mask + Add On", mask: "currency", placeholder:"$0.00", add_on: { icon: "frog", alignment: 'left', border: false }, required: true } %>
|
|
106
|
+
<%= pb_rails("text_input", props: {
|
|
107
|
+
label: "pb_rails Text Input Add On",
|
|
108
|
+
add_on: { icon: "frog", alignment: 'left', border: false },
|
|
109
|
+
required: true,
|
|
110
|
+
}) %>
|
|
111
|
+
<%= pb_rails("text_input", props: {
|
|
112
|
+
label: "pb_rails Text Input Currency + Add On",
|
|
113
|
+
mask: "currency",
|
|
114
|
+
add_on: { icon: "frog", alignment: 'right', border: true },
|
|
115
|
+
placeholder:"$0.00",
|
|
116
|
+
required: true,
|
|
117
|
+
}) %>
|
|
118
|
+
|
|
119
|
+
<%= form.actions do |action| %>
|
|
120
|
+
<%= action.submit %>
|
|
121
|
+
<%= action.button props: { type: "reset", text: "Cancel", variant: "secondary" } %>
|
|
122
|
+
<% end %>
|
|
123
|
+
<% end %>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
$icon_colors: (
|
|
2
|
+
default: $text_lt_default,
|
|
3
|
+
link: $primary_action
|
|
4
|
+
);
|
|
5
|
+
|
|
6
|
+
@mixin icon_button_variant($variant) {
|
|
7
|
+
.icon_button_icon {
|
|
8
|
+
color: map-get($icon_colors, $variant);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.pb_icon_button_kit_default,
|
|
13
|
+
.pb_icon_button_kit_link {
|
|
14
|
+
width: fit-content;
|
|
15
|
+
height: fit-content;
|
|
16
|
+
|
|
17
|
+
&:hover {
|
|
18
|
+
.pb_button_kit {
|
|
19
|
+
background-color: $bg_light;
|
|
20
|
+
}
|
|
21
|
+
.icon_button_icon {
|
|
22
|
+
color: $primary_action;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:active {
|
|
27
|
+
.pb_button_kit {
|
|
28
|
+
background-color: $bg_light;
|
|
29
|
+
}
|
|
30
|
+
.icon_button_icon {
|
|
31
|
+
color: $primary_action;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&:hover:active {
|
|
36
|
+
.pb_button_kit {
|
|
37
|
+
background-color: $bg_light;
|
|
38
|
+
}
|
|
39
|
+
.icon_button_icon {
|
|
40
|
+
color: $text_lt_default;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
&:focus {
|
|
45
|
+
outline: 2px solid $primary_action;
|
|
46
|
+
border-radius: 8px;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.pb_button_kit {
|
|
50
|
+
min-height: 0;
|
|
51
|
+
background: none;
|
|
52
|
+
position: relative;
|
|
53
|
+
display: flex;
|
|
54
|
+
justify-content: center;
|
|
55
|
+
align-items: center;
|
|
56
|
+
flex-shrink: 0;
|
|
57
|
+
flex-grow: 0;
|
|
58
|
+
width: fit-content;
|
|
59
|
+
height: fit-content;
|
|
60
|
+
line-height: normal;
|
|
61
|
+
flex-basis: auto;
|
|
62
|
+
min-width: 0;
|
|
63
|
+
padding: 0;
|
|
64
|
+
|
|
65
|
+
.icon_button_icon {
|
|
66
|
+
display: block;
|
|
67
|
+
vertical-align: middle;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.pb_icon_button_kit_default {
|
|
73
|
+
@include icon_button_variant(default);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.pb_icon_button_kit_link {
|
|
77
|
+
@include icon_button_variant(link);
|
|
78
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
|
|
2
|
+
import React from 'react'
|
|
3
|
+
import classnames from 'classnames'
|
|
4
|
+
import { buildAriaProps, buildCss, buildDataProps, noop } from '../utilities/props'
|
|
5
|
+
import { globalProps } from '../utilities/globalProps'
|
|
6
|
+
|
|
7
|
+
import Button from '../pb_button/_button'
|
|
8
|
+
import Icon from '../pb_icon/_icon'
|
|
9
|
+
import { IconSizes } from "../pb_icon/_icon"
|
|
10
|
+
|
|
11
|
+
type IconButtonProps = {
|
|
12
|
+
aria?: { [key: string]: string },
|
|
13
|
+
className?: string,
|
|
14
|
+
data?: { [key: string]: string },
|
|
15
|
+
htmlType?: 'submit' | 'reset' | 'button' | undefined,
|
|
16
|
+
icon?: string,
|
|
17
|
+
id?: string,
|
|
18
|
+
link?: string,
|
|
19
|
+
newWindow?: boolean,
|
|
20
|
+
onClick?: React.MouseEventHandler<HTMLElement>,
|
|
21
|
+
size?: IconSizes,
|
|
22
|
+
target?: string,
|
|
23
|
+
variant?: 'default' | 'link',
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const IconButton = (props: IconButtonProps) => {
|
|
27
|
+
const {
|
|
28
|
+
aria = {},
|
|
29
|
+
className,
|
|
30
|
+
data = {},
|
|
31
|
+
htmlType = 'button',
|
|
32
|
+
icon = 'bars',
|
|
33
|
+
id,
|
|
34
|
+
link,
|
|
35
|
+
newWindow = false,
|
|
36
|
+
onClick = noop,
|
|
37
|
+
size = "2x",
|
|
38
|
+
target,
|
|
39
|
+
variant = "default",
|
|
40
|
+
} = props
|
|
41
|
+
|
|
42
|
+
const ariaProps = buildAriaProps(aria)
|
|
43
|
+
const dataProps = buildDataProps(data)
|
|
44
|
+
const classes = classnames(buildCss('pb_icon_button_kit', variant), globalProps(props), className)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<div
|
|
48
|
+
{...ariaProps}
|
|
49
|
+
{...dataProps}
|
|
50
|
+
className={classes}
|
|
51
|
+
id={id}
|
|
52
|
+
>
|
|
53
|
+
<Button
|
|
54
|
+
aria={aria}
|
|
55
|
+
borderRadius="xs"
|
|
56
|
+
htmlType={htmlType}
|
|
57
|
+
link={link}
|
|
58
|
+
newWindow={newWindow}
|
|
59
|
+
onClick={onClick}
|
|
60
|
+
target={target}
|
|
61
|
+
>
|
|
62
|
+
<Icon
|
|
63
|
+
className="icon_button_icon"
|
|
64
|
+
fixedWidth
|
|
65
|
+
icon={icon}
|
|
66
|
+
paddingX="xxs"
|
|
67
|
+
paddingY="xs"
|
|
68
|
+
size={size}
|
|
69
|
+
/>
|
|
70
|
+
</Button>
|
|
71
|
+
</div>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default IconButton
|