diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx b/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx index 7e3f13b1a0..cb5d53c031 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx +++ b/playbook/app/pb_kits/playbook/pb_dropdown/_dropdown.tsx @@ -112,8 +112,6 @@ type DropdownProps = { isClosed?: boolean; label?: string; multiSelect?: boolean; - name?: string; - onChange?: (event: { target: { name?: string; value: any } }) => void; onSelect?: (arg: GenericObject) => null; options?: GenericObject; placeholder?: string; @@ -158,8 +156,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { label, multiSelect = false, formPillProps, - name, - onChange, onSelect, options, placeholder, @@ -418,10 +414,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { setIsDropDownClosed(false); }; - const handleSelectionChange = (value: any) => { - onSelect && onSelect(value); - onChange && onChange({ target: { name, value } }); - }; const handleOptionClick = (clickedItem: GenericObject) => { if (disabled) return; @@ -434,7 +426,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { const next = exists ? list.filter((option) => option.value !== clickedItem.value) : [...list, clickedItem]; - handleSelectionChange(next); + onSelect && onSelect(next); return next; }); setFilterItem(""); @@ -447,7 +439,7 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { if (shouldCloseOnClick) { setIsDropDownClosed(true); } - handleSelectionChange(clickedItem); + onSelect && onSelect(clickedItem); // Sync with DatePickers if this is a quickpick variant if (variant === "quickpick" && Array.isArray(clickedItem.value)) { @@ -476,10 +468,10 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { if (disabled) return; if (multiSelect) { setSelected([]); - handleSelectionChange([]); + onSelect && onSelect([]); } else { setSelected({}); - handleSelectionChange(null); + onSelect && onSelect(null); setFocusedOptionIndex(-1); setFilterItem(""); @@ -513,10 +505,10 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { clearSelected: () => { if (multiSelect) { setSelected([]); - handleSelectionChange([]); + onSelect && onSelect([]); } else { setSelected({}); - handleSelectionChange(null); + onSelect && onSelect(null); } setFilterItem(""); setIsDropDownClosed(true); @@ -530,16 +522,16 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { clearSelected: () => { if (multiSelect) { setSelected([]); - handleSelectionChange([]); + onSelect && onSelect([]); } else { setSelected({}); - handleSelectionChange(null); + onSelect && onSelect(null); } setFilterItem(""); setIsDropDownClosed(true); }, }; - }, [multiSelect, handleSelectionChange, setSelected, setFilterItem, setIsDropDownClosed]); + }, [multiSelect, onSelect, setSelected, setFilterItem, setIsDropDownClosed]); useImperativeHandle(ref, () => imperativeRef.current); @@ -602,7 +594,6 @@ let Dropdown = (props: DropdownProps, ref: any): React.ReactElement | null => { handleBackspace, handleChange, handleOptionClick, - handleSelectionChange, handleWrapperClick, inputRef, inputWrapperRef, diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.html.erb b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.html.erb deleted file mode 100644 index 0768ad9d49..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.html.erb +++ /dev/null @@ -1,34 +0,0 @@ -<%= pb_rails("select", props: { - id: "color_context_dropdown", - label: "Choose a Color", - name: "color_name", - options: [ - { value: "red", value_text: "Red" }, - { value: "blue", value_text: "Blue" }, - { value: "green", value_text: "Green" }, - ], -}) %> - -<%= pb_rails("dropdown", props: { - id: "dropdown-dynamic-options", - label: "Pick a Shade", - name: "shade_name", - context_selector: "color_context_dropdown", - options_by_context: { - "red" => [ - { id: "scarlet", label: "Scarlet", value: "scarlet" }, - { id: "mahogany", label: "Mahogany", value: "mahogany" }, - { id: "crimson", label: "Crimson", value: "crimson" }, - ], - "blue" => [ - { id: "sky", label: "Sky Blue", value: "sky" }, - { id: "cerulean", label: "Cerulean", value: "cerulean" }, - { id: "navy", label: "Navy", value: "navy" }, - ], - "green" => [ - { id: "emerald", label: "Emerald", value: "emerald" }, - { id: "mint", label: "Mint", value: "mint" }, - { id: "olive", label: "Olive", value: "olive" }, - ], - }, -}) %> diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.md b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.md deleted file mode 100644 index 447d4a1ac7..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options.md +++ /dev/null @@ -1,4 +0,0 @@ -You can set up a dropdown to update its options dynamically based on another input. To achieve this: -- Give the dropdown a unique `id` so it can be targeted by events and linked to a controlling input. -- Use `context_selector` to point at the controlling select’s `id`. On connect, and whenever that select’s value changes, the Dropdown reads the current value as its context. -- Use `options_by_context` to pass a hash of option lists. Keys must match the possible values of the controlling select; each key maps to an array of `{ id, label, value }` options that replace the Dropdown’s options for that context. diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.html.erb b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.html.erb deleted file mode 100644 index d0cd2cbcb5..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.html.erb +++ /dev/null @@ -1,35 +0,0 @@ -<%= pb_rails("select", props: { - id: "color_context_dropdown_autocomplete", - label: "Choose a Color", - name: "color_name_autocomplete", - options: [ - { value: "red", value_text: "Red" }, - { value: "blue", value_text: "Blue" }, - { value: "green", value_text: "Green" }, - ], -}) %> - -<%= pb_rails("dropdown", props: { - id: "dropdown-dynamic-options-autocomplete", - label: "Pick a Shade", - name: "shade_name_autocomplete", - autocomplete: true, - context_selector: "color_context_dropdown_autocomplete", - options_by_context: { - "red" => [ - { id: "scarlet", label: "Scarlet", value: "scarlet" }, - { id: "mahogany", label: "Mahogany", value: "mahogany" }, - { id: "crimson", label: "Crimson", value: "crimson" }, - ], - "blue" => [ - { id: "sky", label: "Sky Blue", value: "sky" }, - { id: "cerulean", label: "Cerulean", value: "cerulean" }, - { id: "navy", label: "Navy", value: "navy" }, - ], - "green" => [ - { id: "emerald", label: "Emerald", value: "emerald" }, - { id: "mint", label: "Mint", value: "mint" }, - { id: "olive", label: "Olive", value: "olive" }, - ], - }, -}) %> diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.md b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.md deleted file mode 100644 index dc564404ad..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_autocomplete.md +++ /dev/null @@ -1 +0,0 @@ -Dynamic options also work with `autocomplete`. Use the same `context_selector` and `options_by_context` setup as Dynamic Options, and set `autocomplete: true` so the Dropdown can be filtered by typing. \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.html.erb b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.html.erb deleted file mode 100644 index e761ace4ff..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.html.erb +++ /dev/null @@ -1,35 +0,0 @@ -<%= pb_rails("select", props: { - id: "color_context_dropdown_multi", - label: "Choose a Color", - name: "color_name_multi", - options: [ - { value: "red", value_text: "Red" }, - { value: "blue", value_text: "Blue" }, - { value: "green", value_text: "Green" }, - ], -}) %> - -<%= pb_rails("dropdown", props: { - id: "dropdown-dynamic-options-multi", - label: "Pick Shades", - name: "shade_names", - multi_select: true, - context_selector: "color_context_dropdown_multi", - options_by_context: { - "red" => [ - { id: "scarlet", label: "Scarlet", value: "scarlet" }, - { id: "mahogany", label: "Mahogany", value: "mahogany" }, - { id: "crimson", label: "Crimson", value: "crimson" }, - ], - "blue" => [ - { id: "sky", label: "Sky Blue", value: "sky" }, - { id: "cerulean", label: "Cerulean", value: "cerulean" }, - { id: "navy", label: "Navy", value: "navy" }, - ], - "green" => [ - { id: "emerald", label: "Emerald", value: "emerald" }, - { id: "mint", label: "Mint", value: "mint" }, - { id: "olive", label: "Olive", value: "olive" }, - ], - }, -}) %> diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.md b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.md deleted file mode 100644 index 36260441ee..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_dynamic_options_with_multi_select.md +++ /dev/null @@ -1 +0,0 @@ -Dynamic options also work with `multi_select`. Use the same `context_selector` and `options_by_context` setup as Dynamic Options, and set `multi_select: true` to allow selecting multiple options. diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.jsx b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.jsx deleted file mode 100644 index 55a2485f99..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react' - -import Dropdown from '../_dropdown' -import Title from '../../pb_title/_title' -import { useForm } from 'react-hook-form' - -const options = [ - { label: 'United States', value: 'unitedStates', id: 'us' }, - { label: 'United Kingdom', value: 'unitedKingdom', id: 'gb' }, - { label: 'Canada', value: 'canada', id: 'ca' }, - { label: 'Pakistan', value: 'pakistan', id: 'pk' }, - { label: 'India', value: 'india', id: 'in' }, - { label: 'Australia', value: 'australia', id: 'au' }, - { label: 'New Zealand', value: 'new Zealand', id: 'nz' }, - { label: 'Italy', value: 'italy', id: 'it' }, - { label: 'Spain', value: 'spain', id: 'es' }, -] - -const DropdownMultiSelectReactHook = (props) => { - const { register, watch } = useForm() - - const selectedCountries = watch('countries') - - return ( - <> - - - {selectedCountries && selectedCountries.map(country => ( - <p key={country.id}>{`${country.label} - ${country.value}`}</p> - ))} - </> - ) -} - -export default DropdownMultiSelectReactHook diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.md b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.md deleted file mode 100644 index 41f34c1df5..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_multi_select_react_hook.md +++ /dev/null @@ -1 +0,0 @@ -You can pass `react-hook-form` props to a multi-select Dropdown. Spread `register` onto Dropdown with `multiSelect` to keep the selected options array in form state. diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.jsx b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.jsx deleted file mode 100644 index b3bd5f8e6a..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import React from 'react' - -import Dropdown from '../_dropdown' -import Title from '../../pb_title/_title' -import { useForm } from 'react-hook-form' - -const options = [ - { label: 'United States', value: 'unitedStates', id: 'us' }, - { label: 'Canada', value: 'canada', id: 'ca' }, - { label: 'Pakistan', value: 'pakistan', id: 'pk' }, -] - -const DropdownReactHook = (props) => { - const { register, watch } = useForm() - - const selectedCountry = watch('country') - - return ( - <> - <Dropdown - label="Countries" - options={options} - {...props} - {...register('country')} - /> - <Title - marginTop="sm" - size={4} - text="Selected Country" - /> - <p>{selectedCountry && `${selectedCountry.label} - ${selectedCountry.value}`}</p> - </> - ) -} - -export default DropdownReactHook diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.md b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.md deleted file mode 100644 index 4d34d51c78..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_dropdown_react_hook.md +++ /dev/null @@ -1 +0,0 @@ -You can pass `react-hook-form` props to the Dropdown kit. Spread `register` onto a single-select Dropdown to keep the selected option in form state. diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.json b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.json index 42a9569feb..fdd2745a46 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.json +++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.json @@ -88,7 +88,6 @@ "name": "Content", "props": [ "label", - "name", "placeholder", "options", "defaultValue", @@ -131,7 +130,6 @@ { "name": "Events", "props": [ - "onChange", "onSelect" ] } diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json index b02dcb5c4d..cc84af3363 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json +++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/_playground.overrides.json @@ -70,7 +70,6 @@ "name": "Content", "props": [ "label", - "name", "placeholder", "options", "defaultValue", @@ -112,7 +111,7 @@ }, { "name": "Events", - "props": ["onChange", "onSelect"] + "props": ["onSelect"] } ], "presets": [ diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml b/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml index 4ae89b9d1e..42b288f5d4 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml +++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/example.yml @@ -39,9 +39,6 @@ examples: - dropdown_disabled: Disabled Input - dropdown_grouped_options: Grouped Options - dropdown_custom_event_type: Custom Event Type - - dropdown_dynamic_options: Dynamic Options - - dropdown_dynamic_options_with_autocomplete: Dynamic Options with Autocomplete - - dropdown_dynamic_options_with_multi_select: Dynamic Options with Multi Select react: - dropdown_default: Default @@ -84,6 +81,3 @@ examples: - dropdown_required_indicator: Required Indicator - dropdown_disabled: Disabled Input - dropdown_grouped_options: Grouped Options - - dropdown_react_hook: React Hook - - dropdown_multi_select_react_hook: React Hook Multi Select - diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js b/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js index 57eea9f555..c1e4b9e75a 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js +++ b/playbook/app/pb_kits/playbook/pb_dropdown/docs/index.js @@ -1,6 +1,4 @@ export { default as DropdownDefault } from './_dropdown_default.jsx' -export { default as DropdownReactHook } from './_dropdown_react_hook.jsx' -export { default as DropdownMultiSelectReactHook } from './_dropdown_multi_select_react_hook.jsx' export { default as DropdownWithCustomDisplay } from './_dropdown_with_custom_display.jsx' export { default as DropdownWithCustomOptions } from './_dropdown_with_custom_options.jsx' export { default as DropdownWithCustomTrigger } from './_dropdown_with_custom_trigger.jsx' diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb index 3106224e28..ad58c66c94 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb +++ b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.rb @@ -59,14 +59,6 @@ class Dropdown < Playbook::KitBase default: false prop :custom_event_type, type: Playbook::Props::String, default: "" - prop :options_by_context, type: Playbook::Props::HashProp, - default: {} - prop :context_selector, type: Playbook::Props::String, - default: "" - prop :clear_on_context_change, type: Playbook::Props::Boolean, - default: true - prop :options_event_type, type: Playbook::Props::String, - default: "" def data Hash(prop(:data)).merge( @@ -81,11 +73,7 @@ def data end_date_id: variant == "quickpick" ? end_date_id : nil, controls_start_id: variant == "quickpick" && controls_start_id.present? ? controls_start_id : nil, controls_end_id: variant == "quickpick" && controls_end_id.present? ? controls_end_id : nil, - custom_event_type: custom_event_type.presence, - pb_dropdown_options_by_context: options_by_context.present? ? options_by_context.to_json : nil, - pb_dropdown_context_selector: context_selector.presence, - pb_dropdown_clear_on_context_change: clear_on_context_change, - options_event_type: options_event_type.presence + custom_event_type: custom_event_type.presence ).compact end diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx index e76ac511d7..214e601c3f 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx +++ b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx @@ -1,5 +1,5 @@ import React, { useState } from "react" -import { render, screen, fireEvent, waitFor, act } from "../utilities/test-utils" +import { render, screen, fireEvent, waitFor } from "../utilities/test-utils" import { Dropdown, Icon, IconCircle } from 'playbook-ui' import DateTime from "../pb_kit/dateTime.ts" @@ -995,207 +995,4 @@ test('disabled prop disables autocomplete input', () => { const input = kit.querySelector('.dropdown_input') expect(input).toBeDisabled() -}) - -test('onChange uses react-hook-form event shape', () => { - const onChange = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - name="color" - onChange={onChange} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - - expect(onChange).toHaveBeenCalledWith({ - target: { name: 'color', value: options[0] }, - }) -}) - -test('react-hook-form onChange receives selected options for multiSelect', () => { - const onChange = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - multiSelect - name="languages" - onChange={onChange} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - - expect(onChange.mock.calls[0][0]).toEqual({ - target: { name: 'languages', value: [options[0]] }, - }) - expect(onChange.mock.calls[1][0]).toEqual({ - target: { name: 'languages', value: [options[0], options[1]] }, - }) -}) - -test('onSelect still fires when onChange is provided', () => { - const onSelect = jest.fn() - const onChange = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - name="country" - onChange={onChange} - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - - expect(onSelect).toHaveBeenCalledWith(options[0]) - expect(onChange).toHaveBeenCalledWith({ - target: { name: 'country', value: options[0] }, - }) -}) - -test('onSelect-only single select still receives the option object', () => { - const onSelect = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - - expect(onSelect).toHaveBeenCalledTimes(1) - expect(onSelect).toHaveBeenCalledWith(options[0]) -}) - -test('onSelect-only multiSelect still receives the selected options array', () => { - const onSelect = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - multiSelect - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[0]) - - expect(onSelect.mock.calls[0][0]).toEqual([options[0]]) - expect(onSelect.mock.calls[1][0]).toEqual([options[0], options[1]]) -}) - -test('onSelect-only clearSelected still receives null', () => { - const onSelect = jest.fn() - const dropdownRef = React.createRef() - - render( - <Dropdown - data={{ testid: testId }} - defaultValue={options[0]} - onSelect={onSelect} - options={options} - ref={dropdownRef} - /> - ) - - act(() => { - dropdownRef.current.clearSelected() - }) - - expect(onSelect).toHaveBeenCalledWith(null) -}) - -test('onSelect-only clear icon still receives null', () => { - const onSelect = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - defaultValue={options[0]} - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelector('[aria-label="times icon"]').closest('div')) - - expect(onSelect).toHaveBeenCalledWith(null) -}) - -test('onSelect-only removing a multiSelect pill still receives remaining options', () => { - const onSelect = jest.fn() - - render( - <Dropdown - data={{ testid: testId }} - defaultValue={[options[0], options[1]]} - multiSelect - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelector('.pb_form_pill_close')) - - expect(onSelect).toHaveBeenCalledWith([options[1]]) -}) - -test('autocomplete typing does not fire onSelect or onChange', () => { - const onSelect = jest.fn() - const onChange = jest.fn() - - render( - <Dropdown - autocomplete - data={{ testid: testId }} - onChange={onChange} - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.change(kit.querySelector('.dropdown_input'), { target: { value: 'Can' } }) - - expect(onSelect).not.toHaveBeenCalled() - expect(onChange).not.toHaveBeenCalled() -}) - -test('autocomplete selection still fires onSelect', () => { - const onSelect = jest.fn() - - render( - <Dropdown - autocomplete - data={{ testid: testId }} - onSelect={onSelect} - options={options} - /> - ) - - const kit = screen.getByTestId(testId) - fireEvent.click(kit.querySelectorAll('.pb_dropdown_option_list')[1]) - - expect(onSelect).toHaveBeenCalledWith(options[1]) -}) +}) \ No newline at end of file diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js b/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js deleted file mode 100644 index 1931dfa29a..0000000000 --- a/playbook/app/pb_kits/playbook/pb_dropdown/dropdown_index.test.js +++ /dev/null @@ -1,372 +0,0 @@ -import PbDropdown from "./index"; - -const OPTION_SELECTOR = "[data-dropdown-option-label]"; - -function buildDropdownElement({ - id = "test-dropdown", - options = [ - { id: "us", label: "United States", value: "us" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - optionsByContext = null, - contextSelector = null, - optionsEventType = null, -} = {}) { - const root = document.createElement("div"); - root.setAttribute("data-pb-dropdown", "true"); - root.id = id; - root.dataset.pbDropdownDisabled = "false"; - root.dataset.pbDropdownMultiSelect = "false"; - root.dataset.pbDropdownClearable = "true"; - - if (optionsByContext) { - root.dataset.pbDropdownOptionsByContext = JSON.stringify(optionsByContext); - } - if (contextSelector) { - root.dataset.pbDropdownContextSelector = contextSelector; - } - if (optionsEventType) { - root.dataset.optionsEventType = optionsEventType; - } - - root.innerHTML = ` - <div class="dropdown_wrapper"> - <input data-dropdown-selected-option name="country" style="display: none" /> - <div class="pb_dropdown_trigger"> - <span data-dropdown-trigger-display data-dropdown-placeholder="Choose one">Choose one</span> - </div> - <div class="pb_dropdown_container close" data-dropdown-container="true"> - <div class="pb_list_kit"></div> - </div> - </div> - `; - - const list = root.querySelector(".pb_list_kit"); - options.forEach((option) => { - const dropdown = new PbDropdown(root); - list.appendChild(dropdown.buildOptionElement(option)); - }); - - document.body.appendChild(root); - return root; -} - -describe("PbDropdown dynamic options", () => { - let dropdownEl; - let instance; - - beforeEach(() => { - document.body.innerHTML = ""; - dropdownEl = buildDropdownElement(); - instance = new PbDropdown(dropdownEl); - instance.connect(); - }); - - afterEach(() => { - instance.disconnect(); - document.body.innerHTML = ""; - }); - - test("replaceOptions updates rendered option count", () => { - expect(dropdownEl.querySelectorAll(OPTION_SELECTOR).length).toBe(2); - - instance.replaceOptions([ - { id: "mx", label: "Mexico", value: "mx" }, - { id: "pk", label: "Pakistan", value: "pk" }, - { id: "in", label: "India", value: "in" }, - ]); - - expect(dropdownEl.querySelectorAll(OPTION_SELECTOR).length).toBe(3); - }); - - test("pb:dropdown:updateOptions replaces options for matching dropdownId", () => { - document.dispatchEvent( - new CustomEvent("pb:dropdown:updateOptions", { - detail: { - dropdownId: "test-dropdown", - options: [{ id: "uk", label: "United Kingdom", value: "uk" }], - }, - }), - ); - - const options = dropdownEl.querySelectorAll(OPTION_SELECTOR); - expect(options.length).toBe(1); - expect(JSON.parse(options[0].dataset.dropdownOptionLabel).label).toBe( - "United Kingdom", - ); - }); - - test("pb:dropdown:updateOptions ignores events for other dropdown ids", () => { - document.dispatchEvent( - new CustomEvent("pb:dropdown:updateOptions", { - detail: { - dropdownId: "other-dropdown", - options: [{ id: "uk", label: "United Kingdom", value: "uk" }], - }, - }), - ); - - expect(dropdownEl.querySelectorAll(OPTION_SELECTOR).length).toBe(2); - }); - - test("options_event_type listener replaces options from custom events", () => { - instance.disconnect(); - dropdownEl = buildDropdownElement({ optionsEventType: "cities:loaded" }); - instance = new PbDropdown(dropdownEl); - instance.connect(); - - document.dispatchEvent( - new CustomEvent("cities:loaded", { - detail: { - dropdownId: "test-dropdown", - options: [{ id: "chi", label: "Chicago", value: "chi" }], - }, - }), - ); - - expect(dropdownEl.querySelectorAll(OPTION_SELECTOR).length).toBe(1); - }); - - test("options_by_context updates options when context select changes", () => { - instance.disconnect(); - document.body.innerHTML = ""; - - const contextSelect = document.createElement("select"); - contextSelect.id = "color_context"; - contextSelect.innerHTML = ` - <option value="red">Red</option> - <option value="blue">Blue</option> - `; - document.body.appendChild(contextSelect); - - dropdownEl = buildDropdownElement({ - optionsByContext: { - red: [{ id: "scarlet", label: "Scarlet", value: "scarlet" }], - blue: [{ id: "navy", label: "Navy", value: "navy" }], - }, - contextSelector: "color_context", - options: [{ id: "scarlet", label: "Scarlet", value: "scarlet" }], - }); - instance = new PbDropdown(dropdownEl); - instance.connect(); - - contextSelect.value = "blue"; - contextSelect.dispatchEvent(new Event("change")); - - const options = dropdownEl.querySelectorAll(OPTION_SELECTOR); - expect(options.length).toBe(1); - expect(JSON.parse(options[0].dataset.dropdownOptionLabel).label).toBe( - "Navy", - ); - }); - - test("options_by_context applies current context value on connect", () => { - instance.disconnect(); - document.body.innerHTML = ""; - - const contextSelect = document.createElement("select"); - contextSelect.id = "color_context_initial"; - contextSelect.innerHTML = ` - <option value="red">Red</option> - <option value="blue" selected>Blue</option> - `; - document.body.appendChild(contextSelect); - - dropdownEl = buildDropdownElement({ - optionsByContext: { - red: [{ id: "scarlet", label: "Scarlet", value: "scarlet" }], - blue: [{ id: "navy", label: "Navy", value: "navy" }], - }, - contextSelector: "color_context_initial", - // Intentionally mismatched SSR options (red shades) while select is blue - options: [{ id: "scarlet", label: "Scarlet", value: "scarlet" }], - }); - instance = new PbDropdown(dropdownEl); - instance.connect(); - - const options = dropdownEl.querySelectorAll(OPTION_SELECTOR); - expect(options.length).toBe(1); - expect(JSON.parse(options[0].dataset.dropdownOptionLabel).label).toBe( - "Navy", - ); - }); - - test("pb:dropdown:clear and pb:dropdown:select still work after option update", () => { - document.dispatchEvent( - new CustomEvent("pb:dropdown:updateOptions", { - detail: { - dropdownId: "test-dropdown", - options: [ - { id: "us", label: "United States", value: "us" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - }, - }), - ); - - document.dispatchEvent( - new CustomEvent("pb:dropdown:select", { - detail: { dropdownId: "test-dropdown", optionId: "ca" }, - }), - ); - - expect(dropdownEl.querySelector("input[data-dropdown-selected-option]").value).toBe( - "ca", - ); - - document.dispatchEvent( - new CustomEvent("pb:dropdown:clear", { - detail: { dropdownId: "test-dropdown" }, - }), - ); - - expect(dropdownEl.querySelector("input[data-dropdown-selected-option]").value).toBe( - "", - ); - }); - - test("replaceOptions with clearSelection false refreshes single-select from new payload", () => { - instance.setSelectionByOptionId("us"); - expect( - dropdownEl.querySelector("[data-dropdown-trigger-display]").textContent, - ).toBe("United States"); - - instance.replaceOptions( - [ - { id: "us", label: "USA", value: "united-states" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - { clearSelection: false }, - ); - - expect(dropdownEl.querySelector("input[data-dropdown-selected-option]").value).toBe( - "us", - ); - expect( - dropdownEl.querySelector("[data-dropdown-trigger-display]").textContent, - ).toBe("USA"); - }); - - test("replaceOptions with clearSelection false refreshes multi-select payloads", () => { - instance.disconnect(); - dropdownEl = buildDropdownElement({ - options: [ - { id: "us", label: "United States", value: "us" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - }); - dropdownEl.dataset.pbDropdownMultiSelect = "true"; - dropdownEl.innerHTML = ` - <div class="dropdown_wrapper"> - <input data-dropdown-selected-option name="country[]" style="display: none" /> - <div class="pb_dropdown_trigger"> - <div data-dropdown-pills-wrapper></div> - <span data-dropdown-trigger-display-multi-select>Choose one</span> - </div> - <div class="pb_dropdown_container close" data-dropdown-container="true"> - <div class="pb_list_kit"></div> - </div> - </div> - `; - const list = dropdownEl.querySelector(".pb_list_kit"); - [ - { id: "us", label: "United States", value: "us" }, - { id: "ca", label: "Canada", value: "ca" }, - ].forEach((option) => { - list.appendChild(new PbDropdown(dropdownEl).buildOptionElement(option)); - }); - instance = new PbDropdown(dropdownEl); - instance.connect(); - instance.setSelectionByOptionIds(["us"]); - - instance.replaceOptions( - [ - { id: "us", label: "USA", value: "united-states" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - { clearSelection: false }, - ); - - const selectedPayload = Array.from(instance.selectedOptions).map(JSON.parse); - expect(selectedPayload).toEqual([ - { id: "us", label: "USA", value: "united-states" }, - ]); - expect( - dropdownEl.querySelector("[data-pill-id='us'] .pb_form_pill_text").textContent, - ).toBe("USA"); - }); - - test("replaceOptions clears autocomplete filter and keyboard focus", () => { - instance.disconnect(); - dropdownEl = buildDropdownElement(); - const trigger = dropdownEl.querySelector(".pb_dropdown_trigger"); - trigger.innerHTML = ` - <input data-dropdown-autocomplete type="text" /> - <span data-dropdown-trigger-display data-dropdown-placeholder="Choose one">Choose one</span> - `; - instance = new PbDropdown(dropdownEl); - instance.connect(); - - instance.searchInput.value = "can"; - instance.handleSearch("can"); - instance.keyboardHandler.focusedOptionIndex = 1; - - instance.replaceOptions([ - { id: "mx", label: "Mexico", value: "mx" }, - { id: "pk", label: "Pakistan", value: "pk" }, - ]); - - expect(instance.searchInput.value).toBe(""); - expect(instance.keyboardHandler.focusedOptionIndex).toBe(-1); - const options = dropdownEl.querySelectorAll(OPTION_SELECTOR); - expect(options.length).toBe(2); - options.forEach((opt) => { - expect(opt.style.display).toBe(""); - }); - }); - - test("replaceOptions with clearSelection false restores autocomplete from new label", () => { - instance.disconnect(); - dropdownEl = buildDropdownElement(); - const trigger = dropdownEl.querySelector(".pb_dropdown_trigger"); - trigger.innerHTML = ` - <input data-dropdown-autocomplete type="text" /> - <span data-dropdown-trigger-display data-dropdown-placeholder="Choose one">Choose one</span> - `; - instance = new PbDropdown(dropdownEl); - instance.connect(); - instance.setSelectionByOptionId("us"); - instance.searchInput.value = "united"; - - instance.replaceOptions( - [ - { id: "us", label: "USA", value: "united-states" }, - { id: "ca", label: "Canada", value: "ca" }, - ], - { clearSelection: false }, - ); - - expect(instance.searchInput.value).toBe("USA"); - expect(instance.keyboardHandler.focusedOptionIndex).toBe(-1); - }); - - test("replaceOptions removes SSR empty-state No option placeholder", () => { - instance.disconnect(); - dropdownEl = buildDropdownElement({ options: [] }); - const list = dropdownEl.querySelector(".pb_list_kit"); - list.innerHTML = ` - <div class="pb_list_item_kit display_flex justify_content_center p_xs"> - <div class="pb_body_kit">No option</div> - </div> - `; - instance = new PbDropdown(dropdownEl); - instance.connect(); - - instance.replaceOptions([ - { id: "scarlet", label: "Scarlet", value: "scarlet" }, - ]); - - expect(list.textContent).not.toContain("No option"); - expect(dropdownEl.querySelectorAll(OPTION_SELECTOR).length).toBe(1); - }); -}); diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/index.js b/playbook/app/pb_kits/playbook/pb_dropdown/index.js index e2f50b99cd..b81b779dda 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/index.js +++ b/playbook/app/pb_kits/playbook/pb_dropdown/index.js @@ -162,8 +162,6 @@ export default class PbDropdown extends PbEnhancedElement { const baseInput = this.baseInput; this.wasOriginallyRequired = baseInput && baseInput.hasAttribute("required"); - // Apply context options before default value so SSR/default selection matches current context - this.bindContextSelector(); this.setDefaultValue(); this.bindEventListeners(); this.bindSearchInput(); @@ -186,13 +184,11 @@ export default class PbDropdown extends PbEnhancedElement { this.updateClearButton(); this.applyDisabledState(); - // Listen for clear, select, and updateOptions events from external source + // Listen for clear and select events from external source this.handleClearEventBound = this.handleClearEvent.bind(this); document.addEventListener("pb:dropdown:clear", this.handleClearEventBound); this.handleSelectEventBound = this.handleSelectEvent.bind(this); document.addEventListener("pb:dropdown:select", this.handleSelectEventBound); - this.handleUpdateOptionsEventBound = this.handleUpdateOptionsEvent.bind(this); - document.addEventListener("pb:dropdown:updateOptions", this.handleUpdateOptionsEventBound); // Listen for custom_event_type to clear on custom events const customEventTypeString = this.element.dataset.customEventType; @@ -206,19 +202,6 @@ export default class PbDropdown extends PbEnhancedElement { document.addEventListener(eventType, this.handleCustomClearBound); }); } - - // Listen for options_event_type to replace options on custom/Turbo events - const optionsEventTypeString = this.element.dataset.optionsEventType; - if (optionsEventTypeString) { - this.optionsEventTypes = optionsEventTypeString - .split(",") - .map((e) => e.trim()) - .filter(Boolean); - this.handleOptionsEventTypeBound = this.handleOptionsEventType.bind(this); - this.optionsEventTypes.forEach((eventType) => { - document.addEventListener(eventType, this.handleOptionsEventTypeBound); - }); - } } disconnect() { @@ -280,22 +263,11 @@ export default class PbDropdown extends PbEnhancedElement { if (this.handleSelectEventBound) { document.removeEventListener("pb:dropdown:select", this.handleSelectEventBound) } - if (this.handleUpdateOptionsEventBound) { - document.removeEventListener("pb:dropdown:updateOptions", this.handleUpdateOptionsEventBound) - } if (this.customClearEventTypes && this.handleCustomClearBound) { this.customClearEventTypes.forEach((eventType) => { document.removeEventListener(eventType, this.handleCustomClearBound) }) } - if (this.optionsEventTypes && this.handleOptionsEventTypeBound) { - this.optionsEventTypes.forEach((eventType) => { - document.removeEventListener(eventType, this.handleOptionsEventTypeBound) - }) - } - if (this.contextElement && this.handleContextChangeBound) { - this.contextElement.removeEventListener("change", this.handleContextChangeBound) - } } updateClearButton() { @@ -658,217 +630,6 @@ export default class PbDropdown extends PbEnhancedElement { } // ----- External events handling section ----- - - get optionsByContext() { - return this.element.dataset.pbDropdownOptionsByContext - ? JSON.parse(this.element.dataset.pbDropdownOptionsByContext) - : null; - } - - get contextElement() { - const selector = this.element.dataset.pbDropdownContextSelector; - if (!selector) return null; - - return ( - this.element.parentNode?.querySelector(`#${CSS.escape(selector)}`) || - this.element.closest(`#${CSS.escape(selector)}`) || - document.getElementById(selector) - ); - } - - get clearOnContextChange() { - return this.element.dataset.pbDropdownClearOnContextChange !== "false"; - } - - bindContextSelector() { - const contextEl = this.contextElement; - if (!contextEl || !this.optionsByContext) return; - - this.handleContextChangeBound = this.handleContextChange.bind(this); - contextEl.addEventListener("change", this.handleContextChangeBound); - - // Sync to the current context value on connect (default/restored select), without clearing - this.applyOptionsForCurrentContext({ clearSelection: false }); - } - - applyOptionsForCurrentContext({ clearSelection } = {}) { - if (this.isDisabled || !this.optionsByContext) return; - - const options = this.optionsByContext[this.contextElement?.value] || []; - this.replaceOptions(options, { - clearSelection: - clearSelection != null ? clearSelection : this.clearOnContextChange, - }); - } - - handleContextChange() { - this.applyOptionsForCurrentContext(); - } - - normalizeOption(option) { - const normalized = { ...option }; - if (normalized.id == null && normalized.value != null) { - normalized.id = normalized.value; - } - if (normalized.value == null && normalized.id != null) { - normalized.value = normalized.id; - } - return normalized; - } - - getOptionsParent() { - const container = this.target; - if (!container) return null; - - return container.querySelector(".pb_list_kit") || container; - } - - buildOptionElement(option) { - const normalized = this.normalizeOption(option); - const disabled = normalized.disabled === true; - const optionEl = document.createElement("div"); - optionEl.className = `pb_dropdown_option_list${disabled ? " disabled" : ""}`; - if (normalized.id != null && normalized.id !== "") { - optionEl.id = String(normalized.id); - } - optionEl.setAttribute("aria-disabled", disabled ? "true" : "false"); - optionEl.dataset.dropdownOptionLabel = JSON.stringify(normalized); - optionEl.dataset.dropdownOptionDisabled = disabled ? "true" : "false"; - - const listItem = document.createElement("div"); - listItem.className = - "pb_list_item_kit display_flex justify_content_center p_none cursor_pointer"; - - const wrapper = document.createElement("div"); - wrapper.className = disabled - ? "dropdown_option_wrapper disabled" - : "dropdown_option_wrapper"; - - const body = document.createElement("div"); - body.className = "pb_body_kit_light"; - body.textContent = - normalized.label != null ? String(normalized.label) : ""; - - wrapper.appendChild(body); - listItem.appendChild(wrapper); - optionEl.appendChild(listItem); - - return optionEl; - } - - replaceOptions(options, { clearSelection = true } = {}) { - if (this.isDisabled || !Array.isArray(options)) return; - - const parent = this.getOptionsParent(); - if (!parent) return; - - // Clear option nodes and any SSR empty-state ("No option") placeholder - parent.replaceChildren(); - this.removeNoOptionsMessage(); - - options.forEach((option) => { - parent.appendChild(this.buildOptionElement(option)); - }); - - // Clear typed filters and keyboard focus so new options aren't left unfiltered / - // focused against stale indexes from the previous list - this.resetInteractiveOptionState(); - - if (clearSelection) { - this.clearSelection(); - } else { - this.reconcileSelectionWithOptions(); - } - - if (this.target?.classList.contains("open")) { - this.adjustDropdownHeight(); - } - } - - resetInteractiveOptionState() { - this.resetFocus(); - - if (this.searchBar) { - this.searchBar.value = ""; - } - - if (this.searchInput) { - this.searchInput.value = ""; - } - } - - reconcileSelectionWithOptions() { - const optionEls = Array.from(this.queryAllOptions()); - const optionsById = new Map(); - optionEls.forEach((opt) => { - try { - const optionData = JSON.parse(opt.dataset.dropdownOptionLabel); - if (optionData?.id != null) { - optionsById.set(optionData.id, opt); - } - } catch { - // ignore invalid option payloads - } - }); - - if (this.isMultiSelect) { - const keptIds = Array.from(this.selectedOptions) - .map((raw) => { - try { - return JSON.parse(raw).id; - } catch { - return null; - } - }) - .filter((id) => id != null && optionsById.has(id)); - - if (keptIds.length === 0) { - this.clearSelection(); - return; - } - - // Rebuild from current option payloads so labels/values stay in sync - this.setSelectionByOptionIds(keptIds); - return; - } - - const currentId = this.baseInput?.value; - if (!currentId || !optionsById.has(currentId)) { - this.clearSelection(); - return; - } - - // Re-apply selection so trigger/autocomplete use the updated option payload - this.setSelectionByOptionId(currentId); - } - - // Handles pb:dropdown:updateOptions - replace options when event.detail.dropdownId matches. - // detail: { dropdownId, options: [{ id, label, value }], clearSelection?: boolean } - handleUpdateOptionsEvent(event) { - if (this.isDisabled) return; - const targetId = event.detail?.dropdownId; - if (!targetId || this.element.id !== targetId) return; - - const options = event.detail?.options; - if (!Array.isArray(options)) return; - - const clearSelection = event.detail?.clearSelection !== false; - this.replaceOptions(options, { clearSelection }); - } - - // Handles options_event_type events - replace options when detail.options is present. - handleOptionsEventType(event) { - if (this.isDisabled) return; - const targetId = event.detail?.dropdownId; - if (targetId != null && this.element.id !== targetId) return; - - const options = event.detail?.options; - if (!Array.isArray(options)) return; - - const clearSelection = event.detail?.clearSelection !== false; - this.replaceOptions(options, { clearSelection }); - } - // Handles pb:dropdown:clear - clear this dropdown when event.detail.dropdownId matches. handleClearEvent(event) { if (this.isDisabled) return; diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/kit.schema.json b/playbook/app/pb_kits/playbook/pb_dropdown/kit.schema.json index 059e2f0f81..04f25ad78f 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/kit.schema.json +++ b/playbook/app/pb_kits/playbook/pb_dropdown/kit.schema.json @@ -115,19 +115,6 @@ ], "default": false }, - "name": { - "type": "string", - "platforms": [ - "react", - "rails" - ] - }, - "onChange": { - "type": "function", - "platforms": [ - "react" - ] - }, "onSelect": { "type": "function", "platforms": [ @@ -207,6 +194,12 @@ ], "default": false }, + "name": { + "platforms": [ + "rails" + ], + "type": "string" + }, "required": { "platforms": [ "rails" @@ -255,33 +248,6 @@ ], "type": "string", "default": "" - }, - "optionsByContext": { - "platforms": [ - "rails" - ], - "type": "GenericObject" - }, - "contextSelector": { - "platforms": [ - "rails" - ], - "type": "string", - "default": "" - }, - "clearOnContextChange": { - "platforms": [ - "rails" - ], - "type": "boolean", - "default": true - }, - "optionsEventType": { - "platforms": [ - "rails" - ], - "type": "string", - "default": "" } }, "globalProps": true, diff --git a/playbook/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx b/playbook/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx index e3fd33a322..12e58eb560 100644 --- a/playbook/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx +++ b/playbook/app/pb_kits/playbook/pb_dropdown/subcomponents/MultiSelectTriggerDisplay.tsx @@ -19,7 +19,7 @@ const MultiSelectTriggerDisplay = ({ dark = false, }: MultiSelectTriggerDisplayProps) => { - const { setSelected, handleSelectionChange, formPillProps } = useContext(DropdownContext); + const { setSelected, onSelect, formPillProps } = useContext(DropdownContext); if (selected.length === 0) { if (autocomplete) return null; @@ -35,7 +35,7 @@ const MultiSelectTriggerDisplay = ({ const handleRemoveIconClick = (option: GenericObject) => { setSelected((prev: GenericObject[]) => { const next = prev.filter((item) => item.label !== option.label); - handleSelectionChange && handleSelectionChange(next); + onSelect && onSelect(next); return next; }); } diff --git a/playbook/spec/pb_kits/playbook/kits/dropdown_spec.rb b/playbook/spec/pb_kits/playbook/kits/dropdown_spec.rb index cfb9fec3df..23518b9f9d 100644 --- a/playbook/spec/pb_kits/playbook/kits/dropdown_spec.rb +++ b/playbook/spec/pb_kits/playbook/kits/dropdown_spec.rb @@ -32,10 +32,6 @@ it { is_expected.to define_boolean_prop(:constrain_height).with_default(false) } it { is_expected.to define_boolean_prop(:required_indicator).with_default(false) } it { is_expected.to define_string_prop(:custom_event_type).with_default("") } - it { is_expected.to define_hash_prop(:options_by_context).with_default({}) } - it { is_expected.to define_string_prop(:context_selector).with_default("") } - it { is_expected.to define_boolean_prop(:clear_on_context_change).with_default(true) } - it { is_expected.to define_string_prop(:options_event_type).with_default("") } describe "#classname" do it "returns namespaced class name", :aggregate_failures do @@ -472,47 +468,6 @@ end end - describe "dynamic options props" do - let(:options_by_context) do - { - "red" => [{ id: "scarlet", label: "Scarlet", value: "scarlet" }], - "blue" => [{ id: "navy", label: "Navy", value: "navy" }], - } - end - - it "includes options_by_context in data when present" do - dropdown = subject.new(options_by_context: options_by_context) - expect(dropdown.data).to include( - pb_dropdown_options_by_context: options_by_context.to_json - ) - end - - it "omits options_by_context from data when empty" do - dropdown = subject.new(options_by_context: {}) - expect(dropdown.data).not_to have_key(:pb_dropdown_options_by_context) - end - - it "includes context_selector in data when present" do - dropdown = subject.new(context_selector: "color_context") - expect(dropdown.data).to include(pb_dropdown_context_selector: "color_context") - end - - it "includes clear_on_context_change in data" do - dropdown = subject.new(clear_on_context_change: false) - expect(dropdown.data).to include(pb_dropdown_clear_on_context_change: false) - end - - it "includes options_event_type in data when present" do - dropdown = subject.new(options_event_type: "turbo:frame-load,cities:loaded") - expect(dropdown.data).to include(options_event_type: "turbo:frame-load,cities:loaded") - end - - it "omits options_event_type from data when blank" do - dropdown = subject.new(options_event_type: "") - expect(dropdown.data).not_to have_key(:options_event_type) - end - end - describe "#disabled" do it "includes disabled state in data when true" do dropdown = subject.new(disabled: true)