From beee1335ca215095d650b4e14c59a46eb73ce393 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Sat, 28 Mar 2026 11:37:38 +0100 Subject: [PATCH 01/22] IBX-11507-use-ds-radio-button: include DS base styles in admin UI --- src/bundle/Resources/encore/ibexa.css.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bundle/Resources/encore/ibexa.css.config.js b/src/bundle/Resources/encore/ibexa.css.config.js index 62dfba962e..283f45eb1f 100644 --- a/src/bundle/Resources/encore/ibexa.css.config.js +++ b/src/bundle/Resources/encore/ibexa.css.config.js @@ -5,6 +5,7 @@ module.exports = (Encore) => { path.resolve(__dirname, '../public/scss/ibexa-bootstrap.scss'), path.resolve(__dirname, '../public/scss/ibexa.scss'), path.resolve(__dirname, '../public/scss/ui/ibexa-modules.scss'), + path.resolve('./vendor/ibexa/admin-ui-assets/src/bundle/Resources/public/vendors/ids-assets/dist/css/styles.css'), path.resolve('./vendor/ibexa/admin-ui-assets/src/bundle/Resources/public/vendors/flatpickr/dist/flatpickr.min.css'), path.resolve( './vendor/ibexa/admin-ui-assets/src/bundle/Resources/public/vendors/flatpickr/dist/plugins/confirmDate/confirmDate.css', From f1aeffd18aec30ae290dbb64e3c0cb9566ee1b21 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Tue, 5 May 2026 08:00:31 +0200 Subject: [PATCH 02/22] IBX-11413: add DS dropdown compatibility wrapper --- .../Resources/encore/ibexa.js.config.js | 4 + .../public/js/scripts/filters.action.btns.js | 10 +- .../js/scripts/sidebar/extra.actions.js | 2 +- .../admin/content/tab/content.html.twig | 4 +- .../admin/content_type/tab/view.html.twig | 4 +- .../component/dropdown/dropdown_ds.html.twig | 201 ++++++++++++++++++ .../dropdown/dropdown_ds_multi.html.twig | 27 +++ .../dropdown/dropdown_ds_single.html.twig | 17 ++ .../ui/form_fields/dropdown_widget.html.twig | 2 +- 9 files changed, 260 insertions(+), 11 deletions(-) create mode 100644 src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig create mode 100644 src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig create mode 100644 src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js index 30b8296fd9..b12c548364 100644 --- a/src/bundle/Resources/encore/ibexa.js.config.js +++ b/src/bundle/Resources/encore/ibexa.js.config.js @@ -7,6 +7,10 @@ const layout = [ path.resolve(__dirname, '../public/js/scripts/admin.format.date.js'), path.resolve(__dirname, '../public/js/scripts/core/draggable.js'), path.resolve(__dirname, '../public/js/scripts/core/dropdown.js'), + path.resolve( + __dirname, + '../../../../../design-system-twig/src/bundle/Resources/public/ts/init_components.ts', + ), path.resolve(__dirname, '../public/js/scripts/core/backdrop.js'), path.resolve(__dirname, '../public/js/scripts/core/custom.tooltip.js'), path.resolve(__dirname, '../public/js/scripts/core/base.chart.js'), diff --git a/src/bundle/Resources/public/js/scripts/filters.action.btns.js b/src/bundle/Resources/public/js/scripts/filters.action.btns.js index ea1569d8f3..c7f2566bc5 100644 --- a/src/bundle/Resources/public/js/scripts/filters.action.btns.js +++ b/src/bundle/Resources/public/js/scripts/filters.action.btns.js @@ -4,7 +4,7 @@ containers.forEach((container) => { const clearBtn = container.querySelector('.ibexa-adaptive-filters__clear-btn'); const applyBtn = container.querySelector('.ibexa-adaptive-filters__submit-btn'); - const dropdownNodes = [...container.querySelectorAll('.ibexa-dropdown')]; + const dropdownNodes = [...container.querySelectorAll('.ibexa-dropdown, .ids-dropdown')]; const textInputNodes = [...container.querySelectorAll('.ibexa-input--text')]; const dateInputNodes = [...container.querySelectorAll('.ibexa-input--date')]; const originalValuesMap = new Map(); @@ -40,8 +40,8 @@ return ( textInputNodes.every((textInputNode) => textInputNode.disabled || textInputNode.value === '') && dropdownNodes.every((dropdownNode) => { - const isDisabled = dropdownNode.classList.contains('ibexa-dropdown--disabled'); - const selectNode = dropdownNode.querySelector('.ibexa-input--select'); + const isDisabled = dropdownNode.classList.contains('ibexa-dropdown--disabled') || dropdownNode.classList.contains('ids-dropdown--disabled'); + const selectNode = dropdownNode.querySelector('.ibexa-input--select, .ids-dropdown__source select'); const dropdown = dropdownNode.ibexaInstance; return isDisabled || (dropdown.canSelectOnlyOne ? selectNode.selectedIndex === 0 : selectNode.selectedIndex === -1); @@ -78,7 +78,7 @@ } }); dropdownNodes.forEach((dropdownNode) => { - const isDisabled = dropdownNode.classList.contains('ibexa-dropdown--disabled'); + const isDisabled = dropdownNode.classList.contains('ibexa-dropdown--disabled') || dropdownNode.classList.contains('ids-dropdown--disabled'); if (!isDisabled) { const dropdown = dropdownNode.ibexaInstance; @@ -135,7 +135,7 @@ } dropdownNodes.forEach((dropdownNode) => { - const select = dropdownNode.querySelector('.ibexa-input--select'); + const select = dropdownNode.querySelector('.ibexa-input--select, .ids-dropdown__source select'); select.addEventListener('change', handleInputChange, false); }); diff --git a/src/bundle/Resources/public/js/scripts/sidebar/extra.actions.js b/src/bundle/Resources/public/js/scripts/sidebar/extra.actions.js index e531ccf33c..ded5d4d6c3 100644 --- a/src/bundle/Resources/public/js/scripts/sidebar/extra.actions.js +++ b/src/bundle/Resources/public/js/scripts/sidebar/extra.actions.js @@ -36,7 +36,7 @@ import { getInstance } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scri node.checked = value; } else if (node.tagName === 'SELECT') { - const dropdownContainer = node.closest('.ibexa-dropdown'); + const dropdownContainer = node.closest('.ibexa-dropdown, .ids-dropdown'); if (dropdownContainer) { const dropdownInstance = getInstance(dropdownContainer); diff --git a/src/bundle/Resources/views/themes/admin/content/tab/content.html.twig b/src/bundle/Resources/views/themes/admin/content/tab/content.html.twig index 9686cd352f..4dcbf9ff5c 100644 --- a/src/bundle/Resources/views/themes/admin/content/tab/content.html.twig +++ b/src/bundle/Resources/views/themes/admin/content/tab/content.html.twig @@ -36,12 +36,12 @@ {% endset %} - {% include '@ibexadesign/ui/component/dropdown/dropdown.html.twig' with { + {% include '@ibexadesign/ui/component/dropdown/dropdown_ds.html.twig' with { source: source, choices: choices, value: value, is_small: true, - } %} + } only %} {% endif %} {% endblock %} diff --git a/src/bundle/Resources/views/themes/admin/content_type/tab/view.html.twig b/src/bundle/Resources/views/themes/admin/content_type/tab/view.html.twig index 8e44d00a31..63d6b7e373 100644 --- a/src/bundle/Resources/views/themes/admin/content_type/tab/view.html.twig +++ b/src/bundle/Resources/views/themes/admin/content_type/tab/view.html.twig @@ -79,12 +79,12 @@ {% endset %} - {% include '@ibexadesign/ui/component/dropdown/dropdown.html.twig' with { + {% include '@ibexadesign/ui/component/dropdown/dropdown_ds.html.twig' with { source: source, choices: choices, value: value, is_small: true, - } %} + } only %} {% endif %} {% endset %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig new file mode 100644 index 0000000000..44a9e9fb92 --- /dev/null +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -0,0 +1,201 @@ +{% set preferred_choices = preferred_choices|default([]) %} +{% set translation_domain = translation_domain|default(false) %} +{% set value = value is defined ? value : null %} +{% set multiple = multiple|default(false) %} +{% set custom_init = custom_init|default(false) %} +{% set is_disabled = is_disabled|default(false) or attr.readonly|default(false) %} +{% set max_visible_items = 5 %} +{% set item_template_props = { + id: '{{ id }}', + label: '{{ label }}', +} %} +{% set preferred_choices_flat = preferred_choices + | map(choice => choice.choices is defined ? choice.choices : [choice]) + | reduce((carry, choices) => carry|merge(choices), []) +%} +{% set choices_flat = choices + | map(choice => choice.choices is defined ? choice.choices : [choice]) + | reduce((carry, choices) => carry|merge(choices), []) +%} + +{% set normalized_preferred_choices = preferred_choices + | map(choice => choice.choices is defined + ? choice.choices|map(child => { + value: child.value ~ '', + label: '[' + ~ (translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain)) + ~ ']: ' + ~ (translation_domain is same as(false) ? child.label : child.label|trans({}, translation_domain)), + }) + : [{ + value: choice.value ~ '', + label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), + }] + ) + | reduce((carry, choices) => carry|merge(choices), []) +%} +{% set normalized_choices = choices + | map(choice => choice.choices is defined + ? choice.choices|map(child => { + value: child.value ~ '', + label: '[' + ~ (translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain)) + ~ ']: ' + ~ (translation_domain is same as(false) ? child.label : child.label|trans({}, translation_domain)), + }) + : [{ + value: choice.value ~ '', + label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), + }] + ) + | reduce((carry, choices) => carry|merge(choices), []) +%} +{% set normalized_choices_data = normalized_preferred_choices + | merge(normalized_choices) + | reduce((carry, choice) => choice.value in carry.values + ? carry + : { + items: carry.items|merge([choice]), + values: carry.values|merge([choice.value]), + }, { + items: [], + values: [], + }) +%} +{% set normalized_items = normalized_choices_data.items %} +{% set has_icons = item_icon is defined + or preferred_choices_flat|filter(choice => choice.icon is defined)|length > 0 + or choices_flat|filter(choice => choice.icon is defined)|length > 0 +%} +{% set placeholder = placeholder is defined and placeholder is not none + ? (translation_domain is same as(false) ? placeholder : placeholder|trans({}, translation_domain)) + : null +%} +{% set normalized_ds_items = normalized_items|map(choice => { + id: choice.value, + label: choice.label, +}) %} +{% set ds_items = not multiple and placeholder is not same as(null) + ? [{ id: '', label: placeholder }]|merge(normalized_ds_items) + : normalized_ds_items +%} +{% set ds_value = multiple + ? (value is iterable ? value|map(item => item ~ '') : []) + : (value is not null ? value ~ '' : '') +%} +{% set has_selected_item_template_path = selected_item_template_path is defined and selected_item_template_path is not null %} +{% set has_list_item_template_path = list_item_template_path is defined and list_item_template_path is not null %} +{% set has_selected_item_label = selected_item_label is defined and selected_item_label is not empty %} +{% set has_items_class = items_class is defined and items_class is not empty %} +{% set has_items_list_header = items_list_header is defined and items_list_header is not empty %} +{% set has_min_search_items = min_search_items is defined and min_search_items is not null %} +{% set has_min_select_all_toggler_items = min_select_all_toggler_items is defined and min_select_all_toggler_items is not null %} +{% set has_min_item_width = min_item_width is defined and min_item_width is not null %} +{% set selected_items = multiple ? ds_items|filter(item => item.id in ds_value) : [] %} +{% set selected_item = not multiple + ? (ds_items|filter(item => item.id == ds_value)|first) + : null +%} +{% set default_selected_item = not multiple and (placeholder is not defined or placeholder is same as(null)) + ? ds_items|first + : null +%} +{% set effective_selected_item = selected_item ?: default_selected_item %} +{% set selected_label = effective_selected_item.label|default('') %} +{% set is_empty = multiple ? ds_value is empty : effective_selected_item is null %} +{% set can_use_ds = not ( + custom_init + or has_selected_item_template_path + or has_list_item_template_path + or has_selected_item_label + or is_dynamic|default(false) + or is_selector|default(false) + or has_items_class + or has_items_list_header + or is_small|default(false) + or is_ghost|default(false) + or has_min_search_items + or has_min_item_width +) %} + +{% if can_use_ds %} + {% include multiple + ? '@ibexadesign/ui/component/dropdown/dropdown_ds_multi.html.twig' + : '@ibexadesign/ui/component/dropdown/dropdown_ds_single.html.twig' + with { + source: source|default(''), + items: ds_items, + value: ds_value, + selected_items: selected_items, + selected_label: selected_label, + is_empty: is_empty, + is_search_visible: ds_items|length >= max_visible_items, + max_visible_items: max_visible_items, + item_template_props: item_template_props, + disabled: is_disabled, + error: false, + class: class|default(''), + name: name|default('dropdown'), + placeholder: placeholder, + } only %} +{% else %} + {% set legacy_context = { + source: source|default(null), + choices: choices, + preferred_choices: preferred_choices, + value: value, + multiple: multiple, + custom_init: custom_init, + class: class|default(''), + translation_domain: translation_domain, + custom_form: custom_form is defined ? custom_form : true, + is_disabled: is_disabled, + is_hidden: is_hidden|default(false), + is_small: is_small|default(false), + is_ghost: is_ghost|default(false), + is_selector: is_selector|default(false), + is_dynamic: is_dynamic|default(false), + has_select_all_toggler: has_select_all_toggler|default(false), + placeholder: placeholder, + item_icon_class: item_icon_class|default(''), + attr: attr|default({}), + } %} + {% set legacy_context = has_selected_item_template_path + ? legacy_context|merge({ selected_item_template_path: selected_item_template_path }) + : legacy_context + %} + {% set legacy_context = has_list_item_template_path + ? legacy_context|merge({ list_item_template_path: list_item_template_path }) + : legacy_context + %} + {% set legacy_context = has_items_class + ? legacy_context|merge({ items_class: items_class }) + : legacy_context + %} + {% set legacy_context = has_items_list_header + ? legacy_context|merge({ items_list_header: items_list_header }) + : legacy_context + %} + {% set legacy_context = item_icon is defined and item_icon is not null + ? legacy_context|merge({ item_icon: item_icon }) + : legacy_context + %} + {% set legacy_context = has_min_search_items + ? legacy_context|merge({ min_search_items: min_search_items }) + : legacy_context + %} + {% set legacy_context = has_min_select_all_toggler_items + ? legacy_context|merge({ min_select_all_toggler_items: min_select_all_toggler_items }) + : legacy_context + %} + {% set legacy_context = has_min_item_width + ? legacy_context|merge({ min_item_width: min_item_width }) + : legacy_context + %} + {% set legacy_context = has_selected_item_label + ? legacy_context|merge({ selected_item_label: selected_item_label }) + : legacy_context + %} + + {% include '@ibexadesign/ui/component/dropdown/dropdown.html.twig' with legacy_context only %} +{% endif %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig new file mode 100644 index 0000000000..7d36ccb313 --- /dev/null +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig @@ -0,0 +1,27 @@ +{% extends '@IbexaDesignSystemTwig/themes/standard/design_system/partials/base_dropdown.html.twig' %} + +{% set class = html_classes('ids-dropdown--multi', class|default('')) %} + +{% block source %} + {{ source|raw }} +{% endblock source %} + +{% block placeholder %} +
+ {{ placeholder|default('ibexa.dropdown.placeholder'|trans({}, 'ibexa_design_system_twig')) }} +
+{% endblock placeholder %} + +{% block item_content %} + + {{ item.label }} +{% endblock item_content %} + +{% block selected_items %} + {{ selected_items|map(item => item.label)|join(', ') }} +{% endblock selected_items %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig new file mode 100644 index 0000000000..5d5d6dedac --- /dev/null +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig @@ -0,0 +1,17 @@ +{% extends '@IbexaDesignSystemTwig/themes/standard/design_system/partials/base_dropdown.html.twig' %} + +{% set class = html_classes('ids-dropdown--single', class|default('')) %} + +{% block source %} + {{ source|raw }} +{% endblock source %} + +{% block placeholder %} +
+ {{ placeholder|default('ibexa.dropdown.placeholder'|trans({}, 'ibexa_design_system_twig')) }} +
+{% endblock placeholder %} + +{% block selected_items %} + {{ selected_label }} +{% endblock selected_items %} diff --git a/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig b/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig index 70dc38cf11..d4e35a50de 100644 --- a/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig @@ -9,7 +9,7 @@ {{- block('choice_widget_collapsed') -}} {% endset %} - {% include '@ibexadesign/ui/component/dropdown/dropdown.html.twig' with { + {% include '@ibexadesign/ui/component/dropdown/dropdown_ds.html.twig' with { source: source, choices: choices, preferred_choices: preferred_choices, From e678ff34311ca0222eb7f817c9a1780774bbd385 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Tue, 5 May 2026 08:45:39 +0200 Subject: [PATCH 03/22] fix: support DS dropdowns in admin UI dynamic flows --- .../js/scripts/admin.contenttype.edit.js | 45 ++++++++++++++----- .../scripts/admin.location.add.custom_url.js | 12 ++++- .../js/scripts/admin.notifications.filters.js | 7 +-- 3 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/admin.contenttype.edit.js b/src/bundle/Resources/public/js/scripts/admin.contenttype.edit.js index eb8935244d..4c9c04a2ef 100644 --- a/src/bundle/Resources/public/js/scripts/admin.contenttype.edit.js +++ b/src/bundle/Resources/public/js/scripts/admin.contenttype.edit.js @@ -1,3 +1,5 @@ +import { DropdownMultiInput, DropdownSingleInput } from '../../../../../../../design-system-twig/src/bundle/Resources/public/ts/components/dropdown'; + (function (global, doc, ibexa, Routing, Translator, bootstrap) { const SELECTOR_INPUTS_TO_VALIDATE = '.ibexa-input[required]:not([disabled]):not([hidden])'; const SELETOR_FIELD_INPUTS = @@ -102,6 +104,35 @@ return fieldNode; }; const attachFieldDefinitionNodeEvents = (fieldNode, { targetContainer }) => { + const initDropdown = (dropdownContainer) => { + const dropdownAlreadyInitialized = !!ibexa.helpers.objectInstances.getInstance(dropdownContainer); + + if (dropdownAlreadyInitialized) { + return; + } + + if (dropdownContainer.classList.contains('ids-dropdown--multi')) { + const dropdown = new DropdownMultiInput(dropdownContainer); + + dropdown.init(); + + return; + } + + if (dropdownContainer.classList.contains('ids-dropdown--single')) { + const dropdown = new DropdownSingleInput(dropdownContainer); + + dropdown.init(); + + return; + } + + const dropdown = new ibexa.core.Dropdown({ + container: dropdownContainer, + }); + + dropdown.init(); + }; const fieldGroupInput = fieldNode.querySelector('.ibexa-input--field-group'); const fieldDefinitionsInputs = fieldNode.querySelectorAll(SELETOR_FIELD_INPUTS); const removeFieldBtns = fieldNode.querySelectorAll('.ibexa-collapse__extra-action-button--remove-field-definitions'); @@ -122,20 +153,10 @@ }); } - const dropdowns = fieldNode.querySelectorAll('.ibexa-dropdown'); + const dropdowns = fieldNode.querySelectorAll('.ibexa-dropdown, .ids-dropdown'); dropdowns.forEach((dropdownContainer) => { - const dropdownAlreadyInitialized = !!ibexa.helpers.objectInstances.getInstance(dropdownContainer); - - if (dropdownAlreadyInitialized) { - return; - } - - const dropdown = new ibexa.core.Dropdown({ - container: dropdownContainer, - }); - - dropdown.init(); + initDropdown(dropdownContainer); }); draggableGroups.forEach((group) => { diff --git a/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js b/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js index 8668cff04f..3766be2f01 100644 --- a/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js +++ b/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js @@ -18,11 +18,19 @@ }; const toggleSiteAccessSelect = (event) => { const isChecked = event.target.checked; - const siteAccessSelect = modal.querySelector('.ibexa-custom-url-from__item--siteacces .ibexa-dropdown'); + const siteAccessSelect = modal.querySelector('.ibexa-custom-url-from__item--siteacces .ibexa-dropdown, .ibexa-custom-url-from__item--siteacces .ids-dropdown'); + const sourceSelect = siteAccessSelect?.querySelector('.ibexa-input--select, .ids-dropdown__source select'); - siteAccessSelect.classList.toggle('ibexa-dropdown--is-disabled', isChecked); + siteAccessSelect?.classList.toggle('ibexa-dropdown--is-disabled', isChecked); + siteAccessSelect?.classList.toggle('ibexa-dropdown--disabled', isChecked); + siteAccessSelect?.classList.toggle('ids-dropdown--disabled', isChecked); + + if (sourceSelect) { + sourceSelect.disabled = isChecked; + } }; + toggleSiteAccessSelect({ target: siteRootCheckbox }); input.addEventListener('input', toggleButtonState, false); siteRootCheckbox.addEventListener('change', toggleSiteAccessSelect, false); discardBtns.forEach((btn) => btn.addEventListener('click', clearValues, false)); diff --git a/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js b/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js index 33fb21d9d9..594de83356 100644 --- a/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js +++ b/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js @@ -1,4 +1,5 @@ (function (global, doc) { + const SELECTOR_DROPDOWN_SOURCE_SELECT = '.ibexa-dropdown__source .ibexa-input--select, .ids-dropdown__source select'; const searchForm = doc.querySelector('.ibexa-list-search-form'); const filtersContainerNode = doc.querySelector('.ibexa-list-filters'); const applyFiltersBtn = filtersContainerNode.querySelector('.ibexa-btn--apply'); @@ -12,7 +13,7 @@ return; } - const sourceSelect = filterNode.querySelector('.ibexa-list-filters__item-content .ibexa-dropdown__source .ibexa-input--select'); + const sourceSelect = filterNode.querySelector(`.ibexa-list-filters__item-content ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); const checkboxes = filterNode.querySelectorAll( '.ibexa-list-filters__item-content .ibexa-input--checkbox:not([name="dropdown-checkbox"])', ); @@ -57,7 +58,7 @@ return; } - const sourceSelect = filterNode.querySelector('.ibexa-list-filters__item-content .ibexa-dropdown__source .ibexa-input--select'); + const sourceSelect = filterNode.querySelector(`.ibexa-list-filters__item-content ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); sourceSelect?.addEventListener('change', filterChange, false); }; @@ -79,7 +80,7 @@ return; } - const select = filterNode.querySelector('.ibexa-dropdown__source .ibexa-input--select'); + const select = filterNode.querySelector(SELECTOR_DROPDOWN_SOURCE_SELECT); const checkedCheckboxes = filterNode.querySelectorAll('.ibexa-input--checkbox:checked'); if (isNodeDatePicker(filterNode)) { From 31f526f95099273d1816dd1d400e367964484575 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Wed, 6 May 2026 09:04:19 +0200 Subject: [PATCH 04/22] fix: pass hidden state to DS dropdown wrapper --- .../themes/admin/ui/component/dropdown/dropdown_ds.html.twig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 44a9e9fb92..be2d5e37e5 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -119,6 +119,7 @@ ) %} {% if can_use_ds %} + {# {{ dump() }} #} {% include multiple ? '@ibexadesign/ui/component/dropdown/dropdown_ds_multi.html.twig' : '@ibexadesign/ui/component/dropdown/dropdown_ds_single.html.twig' @@ -135,6 +136,9 @@ disabled: is_disabled, error: false, class: class|default(''), + attributes: { + hidden: is_hidden|default(false), + }, name: name|default('dropdown'), placeholder: placeholder, } only %} From 45ee4cb6b3712f2801d645432d1e9797230d6db0 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Wed, 6 May 2026 13:32:06 +0200 Subject: [PATCH 05/22] fix: keep DS dropdown placeholder behavior consistent --- .../component/dropdown/dropdown_ds.html.twig | 18 +++++++++++------- .../dropdown/dropdown_ds_multi.html.twig | 6 ------ .../dropdown/dropdown_ds_single.html.twig | 6 ------ 3 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index be2d5e37e5..975f9dd708 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -67,16 +67,21 @@ or preferred_choices_flat|filter(choice => choice.icon is defined)|length > 0 or choices_flat|filter(choice => choice.icon is defined)|length > 0 %} -{% set placeholder = placeholder is defined and placeholder is not none +{% set translated_placeholder = placeholder is defined and placeholder is not none ? (translation_domain is same as(false) ? placeholder : placeholder|trans({}, translation_domain)) : null %} +{% set empty_placeholder_fallback = 'ibexa.dropdown.placeholder.all'|trans({}, 'ibexa_design_system_twig')|desc('All') %} +{% set empty_placeholder_label = translated_placeholder is not same as(null) + ? translated_placeholder|trim|default(empty_placeholder_fallback) + : null +%} {% set normalized_ds_items = normalized_items|map(choice => { id: choice.value, label: choice.label, }) %} -{% set ds_items = not multiple and placeholder is not same as(null) - ? [{ id: '', label: placeholder }]|merge(normalized_ds_items) +{% set ds_items = not multiple and translated_placeholder is not same as(null) + ? [{ id: '', label: empty_placeholder_label }]|merge(normalized_ds_items) : normalized_ds_items %} {% set ds_value = multiple @@ -96,7 +101,7 @@ ? (ds_items|filter(item => item.id == ds_value)|first) : null %} -{% set default_selected_item = not multiple and (placeholder is not defined or placeholder is same as(null)) +{% set default_selected_item = not multiple and translated_placeholder is same as(null) ? ds_items|first : null %} @@ -119,7 +124,6 @@ ) %} {% if can_use_ds %} - {# {{ dump() }} #} {% include multiple ? '@ibexadesign/ui/component/dropdown/dropdown_ds_multi.html.twig' : '@ibexadesign/ui/component/dropdown/dropdown_ds_single.html.twig' @@ -140,7 +144,7 @@ hidden: is_hidden|default(false), }, name: name|default('dropdown'), - placeholder: placeholder, + placeholder: translated_placeholder, } only %} {% else %} {% set legacy_context = { @@ -160,7 +164,7 @@ is_selector: is_selector|default(false), is_dynamic: is_dynamic|default(false), has_select_all_toggler: has_select_all_toggler|default(false), - placeholder: placeholder, + placeholder: translated_placeholder, item_icon_class: item_icon_class|default(''), attr: attr|default({}), } %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig index 7d36ccb313..210653b8fc 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig @@ -6,12 +6,6 @@ {{ source|raw }} {% endblock source %} -{% block placeholder %} -
- {{ placeholder|default('ibexa.dropdown.placeholder'|trans({}, 'ibexa_design_system_twig')) }} -
-{% endblock placeholder %} - {% block item_content %} - {{ placeholder|default('ibexa.dropdown.placeholder'|trans({}, 'ibexa_design_system_twig')) }} - -{% endblock placeholder %} - {% block selected_items %} {{ selected_label }} {% endblock selected_items %} From 69212e66bb19d69e0db4db64a2172f81570d481b Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 7 May 2026 09:29:29 +0200 Subject: [PATCH 06/22] fix: render multi dropdown selections as chips --- .../Resources/public/scss/_dropdown.scss | 8 ++++ .../dropdown/dropdown_ds_multi.html.twig | 37 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/bundle/Resources/public/scss/_dropdown.scss b/src/bundle/Resources/public/scss/_dropdown.scss index 319de4f673..e407e47d31 100644 --- a/src/bundle/Resources/public/scss/_dropdown.scss +++ b/src/bundle/Resources/public/scss/_dropdown.scss @@ -561,6 +561,14 @@ } } +.ids-dropdown { + &__selection-info, + &__selection-info-items, + .ids-overflow-list { + min-width: 0; + } +} + .form-inline { .ibexa-dropdown { margin: calculateRem(5px) calculateRem(8px); diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig index 210653b8fc..fa218edc42 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig @@ -1,6 +1,13 @@ {% extends '@IbexaDesignSystemTwig/themes/standard/design_system/partials/base_dropdown.html.twig' %} +{% trans_default_domain 'ibexa_design_system_twig' %} + {% set class = html_classes('ids-dropdown--multi', class|default('')) %} +{% set selected_item_template_props = { + id: '{{ id }}', + label: '{{ label }}', +} %} +{% set hidden_count_template = '{{ hidden_count }}' %} {% block source %} {{ source|raw }} @@ -17,5 +24,33 @@ {% endblock item_content %} {% block selected_items %} - {{ selected_items|map(item => item.label)|join(', ') }} +
+
+ {% for item in selected_items %} + + {{ item.label }} + + {% endfor %} + + +
+ + +
{% endblock selected_items %} From f3c560319487ed80f03d2a66b0a89c52007b1ac0 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 7 May 2026 12:30:12 +0200 Subject: [PATCH 07/22] refactor: reuse shared overflow list markup --- .../dropdown/dropdown_ds_multi.html.twig | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig index fa218edc42..884de4a1c2 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig @@ -24,14 +24,18 @@ {% endblock item_content %} {% block selected_items %} -
-
- {% for item in selected_items %} - - {{ item.label }} - - {% endfor %} + {% embed '@IbexaDesignSystemTwig/themes/standard/design_system/components/overflow_list.html.twig' with { + items: selected_items, + item_template_props: selected_item_template_props, + hidden_count_template: hidden_count_template, + } only %} + {% block item %} + + {{ item.label }} + + {% endblock item %} + {% block more_item_current %} +0 -
- - -
+ {% endblock more_item_template %} + {% endembed %} {% endblock selected_items %} From 156e921c8c61d8eb7e4b9b1b3db96b0903ccbf97 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 7 May 2026 14:28:59 +0200 Subject: [PATCH 08/22] refactor: render flat dropdowns with DS inputs directly --- .../public/js/scripts/admin.search.filters.js | 26 +++++--- .../component/dropdown/dropdown_ds.html.twig | 64 ++++++++----------- .../dropdown/dropdown_ds_multi.html.twig | 54 ---------------- .../dropdown/dropdown_ds_single.html.twig | 11 ---- 4 files changed, 43 insertions(+), 112 deletions(-) delete mode 100644 src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig delete mode 100644 src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig diff --git a/src/bundle/Resources/public/js/scripts/admin.search.filters.js b/src/bundle/Resources/public/js/scripts/admin.search.filters.js index 7f6b1dcc1c..71f405a3c2 100644 --- a/src/bundle/Resources/public/js/scripts/admin.search.filters.js +++ b/src/bundle/Resources/public/js/scripts/admin.search.filters.js @@ -2,17 +2,22 @@ const { escapeHTML, escapeHTMLAttribute } = ibexa.helpers.text; const { dangerouslySetInnerHTML } = ibexa.helpers.dom; const { getInstance } = ibexa.helpers.objectInstances; + const SELECTOR_DROPDOWN = '.ibexa-dropdown, .ids-dropdown'; + const SELECTOR_DROPDOWN_SOURCE_SELECT = '.ibexa-input--select, .ids-dropdown__source select'; let getUsersTimeout; const SELECTOR_TAG = '.ibexa-tag'; const token = doc.querySelector('meta[name="CSRF-Token"]').content; const siteaccess = doc.querySelector('meta[name="SiteAccess"]').content; const filters = doc.querySelector('.ibexa-filters'); + const getDropdownContainer = (selector) => filters.querySelector(`${selector} ${SELECTOR_DROPDOWN}`); + const getDropdownSourceSelect = (selector) => filters.querySelector(`${selector} ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); const clearBtn = filters.querySelector('.ibexa-btn--clear'); const applyBtn = filters.querySelector('.ibexa-btn--apply'); const contentTypeSelect = doc.querySelector('.ibexa-filters__item--content-type .ibexa-filters__select'); - const sectionSelect = doc.querySelector('.ibexa-filters__item--section .ibexa-filters__select'); - const lastModifiedSelectNode = doc.querySelector('.ibexa-filters__item--modified .ibexa-filters__select'); - const lastModifiedSelect = getInstance(lastModifiedSelectNode); + const sectionSelect = getDropdownSourceSelect('.ibexa-filters__item--section'); + const lastModifiedDropdownNode = getDropdownContainer('.ibexa-filters__item--modified'); + const lastModifiedSelectNode = getDropdownSourceSelect('.ibexa-filters__item--modified'); + const lastModifiedSelect = getInstance(lastModifiedDropdownNode); const lastModifiedDateRangeNode = doc.querySelector('.ibexa-filters__item--modified .ibexa-date-time-range-single'); const lastModifiedDateRange = getInstance(lastModifiedDateRangeNode); const { @@ -23,8 +28,9 @@ const lastModifiedPeriod = doc.querySelector(lastModifiedPeriodSelector); const lastModifiedStartDate = doc.querySelector(lastModifiedStartSelector); const lastModifiedEndDate = doc.querySelector(lastModifiedEndSelector); - const lastCreatedSelectNode = doc.querySelector('.ibexa-filters__item--created .ibexa-filters__select'); - const lastCreatedSelect = getInstance(lastCreatedSelectNode); + const lastCreatedDropdownNode = getDropdownContainer('.ibexa-filters__item--created'); + const lastCreatedSelectNode = getDropdownSourceSelect('.ibexa-filters__item--created'); + const lastCreatedSelect = getInstance(lastCreatedDropdownNode); const lastCreatedDateRangeNode = doc.querySelector('.ibexa-filters__item--created .ibexa-date-time-range-single'); const lastCreatedDateRange = getInstance(lastCreatedDateRangeNode); const { @@ -63,9 +69,8 @@ sectionSelect[0].selected = true; } - lastModifiedSelectNode[0].selected = true; - lastCreatedSelectNode[0].selected = true; - lastModifiedSelectNode.querySelector('option').selected = true; + lastModifiedSelect.selectFirstOption(); + lastCreatedSelect.selectFirstOption(); lastModifiedPeriod.value = ''; lastModifiedEnd.value = ''; lastCreatedPeriod.value = ''; @@ -240,7 +245,10 @@ removeSearchTag(event); }; const clearSection = (event) => { - sectionSelect[0].selected = true; + if (sectionSelect) { + sectionSelect[0].selected = true; + } + removeSearchTag(event); }; const clearSubtree = (event) => { diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 975f9dd708..754c7c2538 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -5,10 +5,6 @@ {% set custom_init = custom_init|default(false) %} {% set is_disabled = is_disabled|default(false) or attr.readonly|default(false) %} {% set max_visible_items = 5 %} -{% set item_template_props = { - id: '{{ id }}', - label: '{{ label }}', -} %} {% set preferred_choices_flat = preferred_choices | map(choice => choice.choices is defined ? choice.choices : [choice]) | reduce((carry, choices) => carry|merge(choices), []) @@ -96,18 +92,8 @@ {% set has_min_search_items = min_search_items is defined and min_search_items is not null %} {% set has_min_select_all_toggler_items = min_select_all_toggler_items is defined and min_select_all_toggler_items is not null %} {% set has_min_item_width = min_item_width is defined and min_item_width is not null %} -{% set selected_items = multiple ? ds_items|filter(item => item.id in ds_value) : [] %} -{% set selected_item = not multiple - ? (ds_items|filter(item => item.id == ds_value)|first) - : null -%} -{% set default_selected_item = not multiple and translated_placeholder is same as(null) - ? ds_items|first - : null -%} -{% set effective_selected_item = selected_item ?: default_selected_item %} -{% set selected_label = effective_selected_item.label|default('') %} -{% set is_empty = multiple ? ds_value is empty : effective_selected_item is null %} +{% set has_grouped_preferred_choices = preferred_choices|filter(choice => choice.choices is defined)|length > 0 %} +{% set has_grouped_choices = choices|filter(choice => choice.choices is defined)|length > 0 %} {% set can_use_ds = not ( custom_init or has_selected_item_template_path @@ -121,31 +107,33 @@ or is_ghost|default(false) or has_min_search_items or has_min_item_width + or has_grouped_preferred_choices + or has_grouped_choices ) %} {% if can_use_ds %} - {% include multiple - ? '@ibexadesign/ui/component/dropdown/dropdown_ds_multi.html.twig' - : '@ibexadesign/ui/component/dropdown/dropdown_ds_single.html.twig' - with { - source: source|default(''), - items: ds_items, - value: ds_value, - selected_items: selected_items, - selected_label: selected_label, - is_empty: is_empty, - is_search_visible: ds_items|length >= max_visible_items, - max_visible_items: max_visible_items, - item_template_props: item_template_props, - disabled: is_disabled, - error: false, - class: class|default(''), - attributes: { - hidden: is_hidden|default(false), - }, - name: name|default('dropdown'), - placeholder: translated_placeholder, - } only %} + {% set ds_dropdown_props = { + name: name|default('dropdown'), + items: ds_items, + value: ds_value, + disabled: is_disabled, + maxVisibleItems: max_visible_items, + class: class|default(''), + } %} + {% set ds_dropdown_props = translated_placeholder is not same as(null) + ? ds_dropdown_props|merge({ placeholder: translated_placeholder }) + : ds_dropdown_props + %} + {% set ds_dropdown_props = is_hidden|default(false) + ? ds_dropdown_props|merge({ hidden: true }) + : ds_dropdown_props + %} + + {% if multiple %} + + {% else %} + + {% endif %} {% else %} {% set legacy_context = { source: source|default(null), diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig deleted file mode 100644 index 884de4a1c2..0000000000 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_multi.html.twig +++ /dev/null @@ -1,54 +0,0 @@ -{% extends '@IbexaDesignSystemTwig/themes/standard/design_system/partials/base_dropdown.html.twig' %} - -{% trans_default_domain 'ibexa_design_system_twig' %} - -{% set class = html_classes('ids-dropdown--multi', class|default('')) %} -{% set selected_item_template_props = { - id: '{{ id }}', - label: '{{ label }}', -} %} -{% set hidden_count_template = '{{ hidden_count }}' %} - -{% block source %} - {{ source|raw }} -{% endblock source %} - -{% block item_content %} - - {{ item.label }} -{% endblock item_content %} - -{% block selected_items %} - {% embed '@IbexaDesignSystemTwig/themes/standard/design_system/components/overflow_list.html.twig' with { - items: selected_items, - item_template_props: selected_item_template_props, - hidden_count_template: hidden_count_template, - } only %} - {% block item %} - - {{ item.label }} - - {% endblock item %} - - {% block more_item_current %} - - {% endblock more_item_current %} - - {% block more_item_template %} - - +{{ hidden_count_template }} - - {% endblock more_item_template %} - {% endembed %} -{% endblock selected_items %} diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig deleted file mode 100644 index 2d2c3598cf..0000000000 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds_single.html.twig +++ /dev/null @@ -1,11 +0,0 @@ -{% extends '@IbexaDesignSystemTwig/themes/standard/design_system/partials/base_dropdown.html.twig' %} - -{% set class = html_classes('ids-dropdown--single', class|default('')) %} - -{% block source %} - {{ source|raw }} -{% endblock source %} - -{% block selected_items %} - {{ selected_label }} -{% endblock selected_items %} From 59d0ddf44f9b3178e3a3f13c54f2bfc3a0aff1d4 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Fri, 8 May 2026 22:51:10 +0200 Subject: [PATCH 09/22] fix: wire DS dropdown context in UDW --- .../public/js/scripts/helpers/icon.helper.js | 4 +- .../design-system/design.system.provider.js | 30 ++ .../content.create.widget.js | 14 +- .../components/filters/filters.js | 25 +- .../universal.discovery.module.js | 261 +++++++++--------- 5 files changed, 182 insertions(+), 152 deletions(-) create mode 100644 src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js diff --git a/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js b/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js index f9d9193c28..a8b1d27fec 100644 --- a/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js +++ b/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js @@ -1,9 +1,9 @@ import { getAdminUiConfig } from './context.helper'; -const getIconPath = (aliasPath, iconSet) => { +const getIconPath = (iconName, iconSet, useLegacyNames = true) => { const adminUiConfig = getAdminUiConfig(); const { defaultIconSet, iconSets, iconAliases } = adminUiConfig.iconPaths; - const path = iconAliases[aliasPath] || aliasPath; + const path = useLegacyNames ? iconAliases[iconName] || iconName : iconName; if (!iconSet) { iconSet = defaultIconSet; diff --git a/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js b/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js new file mode 100644 index 0000000000..ef38ea08fa --- /dev/null +++ b/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js @@ -0,0 +1,30 @@ +import React, { useMemo } from 'react'; + +import { AssetsProvider, TranslatorProvider } from '@ids-components/context'; + +import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper'; +import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper'; + +const DesignSystemProvider = ({ children }) => { + const Translator = getTranslator(); + const assetsContextValue = useMemo( + () => ({ + getIconPath: (iconName, iconSet) => getIconPath(iconName, iconSet, false), + }), + [], + ); + const translatorContextValue = useMemo( + () => ({ + trans: (key, parameters = {}, domain) => Translator.trans(key, parameters, domain), + }), + [Translator], + ); + + return ( + + {children} + + ); +}; + +export default DesignSystemProvider; diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js index 0d2615d30c..26d18540d4 100644 --- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js +++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js @@ -2,10 +2,9 @@ import React, { useContext, useState, useEffect, useRef, useMemo } from 'react'; import { createCssClassNames } from '../../../common/helpers/css.class.names'; import Icon from '../../../common/icon/icon'; -import Dropdown from '../../../common/dropdown/dropdown'; +import { DropdownSingleInput } from '@ids-components/components/Dropdown'; import { - DropdownPortalRefContext, CreateContentWidgetContext, ActiveTabContext, ContentOnTheFlyDataContext, @@ -29,7 +28,6 @@ const ContentCreateWidget = () => { const Translator = getTranslator(); const adminUiConfig = getAdminUiConfig(); const refContentTree = useRef(null); - const dropdownListRef = useContext(DropdownPortalRefContext); const [markedLocationId] = useContext(MarkedLocationIdContext); const [loadedLocationsMap] = useContext(LoadedLocationsMapContext); const { allowedLanguages, preselectedLanguage, preselectedContentType } = useContext(ContentOnTheFlyConfigContext); @@ -189,13 +187,13 @@ const ContentCreateWidget = () => {
- ({ id: value, label }))} + maxVisibleItems={5} + name="" onChange={updateSelectedLanguage} - single={true} value={selectedLanguage} - options={languageOptions} - extraClasses="c-udw-dropdown" />
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js index 7a9e2a8a1c..41c9d7abe7 100644 --- a/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js +++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js @@ -13,9 +13,9 @@ import { SelectedSubtreeBreadcrumbsContext, } from '../search/search'; -import UniversalDiscoveryModule, { DropdownPortalRefContext } from '../../universal.discovery.module'; +import UniversalDiscoveryModule from '../../universal.discovery.module'; -import Dropdown from '../../../common/dropdown/dropdown'; +import { DropdownSingleInput } from '@ids-components/components/Dropdown'; import ContentTypeSelector from '../content-type-selector/content.type.selector'; import Icon from '../../../common/icon/icon'; @@ -35,7 +35,6 @@ const Filters = ({ search }) => { const [selectedLanguage, setSelectedLanguage] = useContext(SelectedLanguageContext); const [selectedSubtreeBreadcrumbs, setSelectedSubtreeBreadcrumbs] = useContext(SelectedSubtreeBreadcrumbsContext); const prevSelectedLanguage = useRef(selectedLanguage); - const dropdownListRef = useContext(DropdownPortalRefContext); const [filtersCleared, setFiltersCleared] = useState(false); const [isNestedUdwOpened, setIsNestedUdwOpened] = useState(false); const filterSubtreeUdwConfig = JSON.parse(window.document.querySelector('#react-udw').dataset.filterSubtreeUdwConfig); @@ -152,24 +151,24 @@ const Filters = ({ search }) => { {isNestedUdwOpened && ReactDOM.createPortal(, nestedUdwContainer.current)} - ({ id: value, label }))} + maxVisibleItems={5} + name="" onChange={updateSelectedLanguage} value={selectedLanguage} - options={languageOptions} - extraClasses="ibexa-dropdown--small c-udw-dropdown" /> - ({ id: value, label }))} + maxVisibleItems={5} + name="" onChange={updateSection} value={selectedSection} - options={sectionOptions} - extraClasses="ibexa-dropdown--small c-udw-dropdown" /> diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js index 062d87b193..1b891bcd5c 100644 --- a/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js +++ b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js @@ -2,6 +2,7 @@ import React, { useEffect, useCallback, useState, createContext, useRef, useMemo import PropTypes from 'prop-types'; import Icon from '../common/icon/icon'; +import DesignSystemProvider from '../common/design-system/design.system.provider'; import deepClone from '../common/helpers/deep.clone.helper'; import { createCssClassNames } from '../common/helpers/css.class.names'; import { useLoadedLocationsReducer } from './hooks/useLoadedLocationsReducer'; @@ -540,164 +541,166 @@ const UniversalDiscoveryModule = ({ }, [currentView]); return ( -
- - - - - - - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); }; From 77249032f7bd43baba3cd8b9fefe9aeb08c0fee6 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Sun, 10 May 2026 10:48:18 +0200 Subject: [PATCH 10/22] fix: preserve source select attributes in DS dropdowns --- .../component/dropdown/dropdown_ds.html.twig | 33 ++++++++++++++++++- .../ui/form_fields/dropdown_widget.html.twig | 4 +++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 754c7c2538..ea6464ad66 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -4,7 +4,36 @@ {% set multiple = multiple|default(false) %} {% set custom_init = custom_init|default(false) %} {% set is_disabled = is_disabled|default(false) or attr.readonly|default(false) %} +{% set source = source|default(null) %} +{% set source_attr = source_attr|default({}) %} +{% set source_id = source_id|default(source_attr.id|default(null)) %} +{% set source_name = source_name|default(source_attr.name|default(name|default('dropdown'))) %} {% set max_visible_items = 5 %} +{% set excluded_source_attr_keys = [ + 'dropdown_hidden', + 'dropdown_class', + 'dropdown_custom_init', + 'is_small', + 'is_ghost', + 'is_selector', + 'is_dynamic', + 'has_select_all_toggler', +] %} +{% set normalized_source_attr = {} %} +{% for key, item in source_attr %} + {% if key not in excluded_source_attr_keys %} + {% set normalized_source_attr = normalized_source_attr|merge({ (key): item }) %} + {% endif %} +{% endfor %} +{% set normalized_source_attr = normalized_source_attr|merge({ + name: source_name, + disabled: is_disabled, + required: required|default(false), +}) %} +{% set normalized_source_attr = source_id is not null + ? normalized_source_attr|merge({ id: source_id }) + : normalized_source_attr +%} {% set preferred_choices_flat = preferred_choices | map(choice => choice.choices is defined ? choice.choices : [choice]) | reduce((carry, choices) => carry|merge(choices), []) @@ -113,12 +142,14 @@ {% if can_use_ds %} {% set ds_dropdown_props = { - name: name|default('dropdown'), + name: source_name, items: ds_items, value: ds_value, disabled: is_disabled, maxVisibleItems: max_visible_items, class: class|default(''), + source: source, + sourceAttributes: normalized_source_attr, } %} {% set ds_dropdown_props = translated_placeholder is not same as(null) ? ds_dropdown_props|merge({ placeholder: translated_placeholder }) diff --git a/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig b/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig index d4e35a50de..8ba090d083 100644 --- a/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/form_fields/dropdown_widget.html.twig @@ -11,10 +11,14 @@ {% include '@ibexadesign/ui/component/dropdown/dropdown_ds.html.twig' with { source: source, + source_id: form.vars.id, + source_name: full_name, + source_attr: attr, choices: choices, preferred_choices: preferred_choices, value: form.vars.value, multiple: form.vars.multiple, + required: required, custom_init: attr.dropdown_custom_init|default(false), class: attr.dropdown_class|default(''), translation_domain: choice_translation_domain|default(false), From 5fa79abccbe72ba070fa47e3985f5179cdc2411a Mon Sep 17 00:00:00 2001 From: tischsoic Date: Fri, 27 Mar 2026 13:18:58 +0100 Subject: [PATCH 11/22] IBX-11506: Initialize DS components in admin UI --- src/bundle/Resources/encore/ibexa.js.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js index b12c548364..fa89300555 100644 --- a/src/bundle/Resources/encore/ibexa.js.config.js +++ b/src/bundle/Resources/encore/ibexa.js.config.js @@ -53,6 +53,7 @@ const layout = [ path.resolve(__dirname, '../public/js/scripts/admin.focus.mode.js'), path.resolve(__dirname, '../public/js/scripts/sidebar/main.menu.js'), path.resolve(__dirname, '../public/js/scripts/admin.input.text.js'), + path.resolve('./vendor/ibexa/design-system-twig/src/bundle/Resources/public/ts/init_components.ts'), path.resolve(__dirname, '../public/js/scripts/admin.table.js'), path.resolve(__dirname, '../public/js/scripts/core/collapse.js'), path.resolve(__dirname, '../public/js/scripts/admin.dropdown.js'), From 1c48ada95150bc8ef3bd921618b0f19eaf119619 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Sun, 10 May 2026 11:46:43 +0200 Subject: [PATCH 12/22] Revert "IBX-11506: Initialize DS components in admin UI" This reverts commit 9eaad2c23f09330ffe8e220274f0a053f1f71541. --- src/bundle/Resources/encore/ibexa.js.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js index fa89300555..b12c548364 100644 --- a/src/bundle/Resources/encore/ibexa.js.config.js +++ b/src/bundle/Resources/encore/ibexa.js.config.js @@ -53,7 +53,6 @@ const layout = [ path.resolve(__dirname, '../public/js/scripts/admin.focus.mode.js'), path.resolve(__dirname, '../public/js/scripts/sidebar/main.menu.js'), path.resolve(__dirname, '../public/js/scripts/admin.input.text.js'), - path.resolve('./vendor/ibexa/design-system-twig/src/bundle/Resources/public/ts/init_components.ts'), path.resolve(__dirname, '../public/js/scripts/admin.table.js'), path.resolve(__dirname, '../public/js/scripts/core/collapse.js'), path.resolve(__dirname, '../public/js/scripts/admin.dropdown.js'), From 5884aaaa48c172803027075fda04b2c65c6ffd94 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Sun, 10 May 2026 12:04:56 +0200 Subject: [PATCH 13/22] fix: support small DS dropdown wrappers --- .../themes/admin/ui/component/dropdown/dropdown_ds.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index ea6464ad66..062cd7ea90 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -132,7 +132,6 @@ or is_selector|default(false) or has_items_class or has_items_list_header - or is_small|default(false) or is_ghost|default(false) or has_min_search_items or has_min_item_width @@ -148,6 +147,7 @@ disabled: is_disabled, maxVisibleItems: max_visible_items, class: class|default(''), + size: is_small|default(false) ? 'small' : 'medium', source: source, sourceAttributes: normalized_source_attr, } %} From 09df0ac25671f8a1e1a36138dc4185c355a53380 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Sun, 10 May 2026 13:56:46 +0200 Subject: [PATCH 14/22] fix: keep small dropdowns on legacy renderer --- .../themes/admin/ui/component/dropdown/dropdown_ds.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 062cd7ea90..ea6464ad66 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -132,6 +132,7 @@ or is_selector|default(false) or has_items_class or has_items_list_header + or is_small|default(false) or is_ghost|default(false) or has_min_search_items or has_min_item_width @@ -147,7 +148,6 @@ disabled: is_disabled, maxVisibleItems: max_visible_items, class: class|default(''), - size: is_small|default(false) ? 'small' : 'medium', source: source, sourceAttributes: normalized_source_attr, } %} From 04ca3d25816431bcb3eb21be979579c4004d9c28 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 12:41:34 +0200 Subject: [PATCH 15/22] refactor --- .../component/dropdown/dropdown_ds.html.twig | 104 ++++++------------ 1 file changed, 34 insertions(+), 70 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index ea6464ad66..111a33612c 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -34,64 +34,6 @@ ? normalized_source_attr|merge({ id: source_id }) : normalized_source_attr %} -{% set preferred_choices_flat = preferred_choices - | map(choice => choice.choices is defined ? choice.choices : [choice]) - | reduce((carry, choices) => carry|merge(choices), []) -%} -{% set choices_flat = choices - | map(choice => choice.choices is defined ? choice.choices : [choice]) - | reduce((carry, choices) => carry|merge(choices), []) -%} - -{% set normalized_preferred_choices = preferred_choices - | map(choice => choice.choices is defined - ? choice.choices|map(child => { - value: child.value ~ '', - label: '[' - ~ (translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain)) - ~ ']: ' - ~ (translation_domain is same as(false) ? child.label : child.label|trans({}, translation_domain)), - }) - : [{ - value: choice.value ~ '', - label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), - }] - ) - | reduce((carry, choices) => carry|merge(choices), []) -%} -{% set normalized_choices = choices - | map(choice => choice.choices is defined - ? choice.choices|map(child => { - value: child.value ~ '', - label: '[' - ~ (translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain)) - ~ ']: ' - ~ (translation_domain is same as(false) ? child.label : child.label|trans({}, translation_domain)), - }) - : [{ - value: choice.value ~ '', - label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), - }] - ) - | reduce((carry, choices) => carry|merge(choices), []) -%} -{% set normalized_choices_data = normalized_preferred_choices - | merge(normalized_choices) - | reduce((carry, choice) => choice.value in carry.values - ? carry - : { - items: carry.items|merge([choice]), - values: carry.values|merge([choice.value]), - }, { - items: [], - values: [], - }) -%} -{% set normalized_items = normalized_choices_data.items %} -{% set has_icons = item_icon is defined - or preferred_choices_flat|filter(choice => choice.icon is defined)|length > 0 - or choices_flat|filter(choice => choice.icon is defined)|length > 0 -%} {% set translated_placeholder = placeholder is defined and placeholder is not none ? (translation_domain is same as(false) ? placeholder : placeholder|trans({}, translation_domain)) : null @@ -101,18 +43,7 @@ ? translated_placeholder|trim|default(empty_placeholder_fallback) : null %} -{% set normalized_ds_items = normalized_items|map(choice => { - id: choice.value, - label: choice.label, -}) %} -{% set ds_items = not multiple and translated_placeholder is not same as(null) - ? [{ id: '', label: empty_placeholder_label }]|merge(normalized_ds_items) - : normalized_ds_items -%} -{% set ds_value = multiple - ? (value is iterable ? value|map(item => item ~ '') : []) - : (value is not null ? value ~ '' : '') -%} + {% set has_selected_item_template_path = selected_item_template_path is defined and selected_item_template_path is not null %} {% set has_list_item_template_path = list_item_template_path is defined and list_item_template_path is not null %} {% set has_selected_item_label = selected_item_label is defined and selected_item_label is not empty %} @@ -123,6 +54,7 @@ {% set has_min_item_width = min_item_width is defined and min_item_width is not null %} {% set has_grouped_preferred_choices = preferred_choices|filter(choice => choice.choices is defined)|length > 0 %} {% set has_grouped_choices = choices|filter(choice => choice.choices is defined)|length > 0 %} + {% set can_use_ds = not ( custom_init or has_selected_item_template_path @@ -141,6 +73,38 @@ ) %} {% if can_use_ds %} + {% set normalized_preferred_choices = preferred_choices|map(choice => { + value: choice.value ~ '', + label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), + }) %} + {% set normalized_choices = choices|map(choice => { + value: choice.value ~ '', + label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), + }) %} + {% set normalized_items = normalized_preferred_choices + | merge(normalized_choices) + | reduce((carry, choice) => choice.value in carry.values + ? carry + : { + items: carry.items|merge([choice]), + values: carry.values|merge([choice.value]), + }, { + items: [], + values: [], + }) + %} + {% set normalized_ds_items = normalized_items.items|map(choice => { + id: choice.value, + label: choice.label, + }) %} + {% set ds_items = not multiple and translated_placeholder is not same as(null) + ? [{ id: '', label: empty_placeholder_label }]|merge(normalized_ds_items) + : normalized_ds_items + %} + {% set ds_value = multiple + ? (value is iterable ? value|map(item => item ~ '') : []) + : (value is not null ? value ~ '' : '') + %} {% set ds_dropdown_props = { name: source_name, items: ds_items, From 4f7ddc00c98c7c085c2df79e01a838b7f700bd1f Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:04:02 +0200 Subject: [PATCH 16/22] fix: toggle matching dropdown disabled class --- .../public/js/scripts/admin.location.add.custom_url.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js b/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js index 3766be2f01..b271b85ea8 100644 --- a/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js +++ b/src/bundle/Resources/public/js/scripts/admin.location.add.custom_url.js @@ -21,9 +21,11 @@ const siteAccessSelect = modal.querySelector('.ibexa-custom-url-from__item--siteacces .ibexa-dropdown, .ibexa-custom-url-from__item--siteacces .ids-dropdown'); const sourceSelect = siteAccessSelect?.querySelector('.ibexa-input--select, .ids-dropdown__source select'); - siteAccessSelect?.classList.toggle('ibexa-dropdown--is-disabled', isChecked); - siteAccessSelect?.classList.toggle('ibexa-dropdown--disabled', isChecked); - siteAccessSelect?.classList.toggle('ids-dropdown--disabled', isChecked); + if (siteAccessSelect?.classList.contains('ibexa-dropdown')) { + siteAccessSelect.classList.toggle('ibexa-dropdown--disabled', isChecked); + } else if (siteAccessSelect?.classList.contains('ids-dropdown')) { + siteAccessSelect.classList.toggle('ids-dropdown--disabled', isChecked); + } if (sourceSelect) { sourceSelect.disabled = isChecked; From 55335712634843a7685bc60bc23db55406d6bddd Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:26:08 +0200 Subject: [PATCH 17/22] refactor: simplify dropdown compatibility helpers --- .../js/scripts/admin.notifications.filters.js | 11 +++++---- .../public/js/scripts/admin.search.filters.js | 24 ++++++++++++------- .../component/dropdown/dropdown_ds.html.twig | 1 + 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js b/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js index 594de83356..70b8320398 100644 --- a/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js +++ b/src/bundle/Resources/public/js/scripts/admin.notifications.filters.js @@ -1,5 +1,4 @@ (function (global, doc) { - const SELECTOR_DROPDOWN_SOURCE_SELECT = '.ibexa-dropdown__source .ibexa-input--select, .ids-dropdown__source select'; const searchForm = doc.querySelector('.ibexa-list-search-form'); const filtersContainerNode = doc.querySelector('.ibexa-list-filters'); const applyFiltersBtn = filtersContainerNode.querySelector('.ibexa-btn--apply'); @@ -13,7 +12,9 @@ return; } - const sourceSelect = filterNode.querySelector(`.ibexa-list-filters__item-content ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); + const sourceSelect = filterNode.querySelector( + '.ibexa-list-filters__item-content .ibexa-dropdown__source .ibexa-input--select, .ibexa-list-filters__item-content .ids-dropdown__source select', + ); const checkboxes = filterNode.querySelectorAll( '.ibexa-list-filters__item-content .ibexa-input--checkbox:not([name="dropdown-checkbox"])', ); @@ -58,7 +59,9 @@ return; } - const sourceSelect = filterNode.querySelector(`.ibexa-list-filters__item-content ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); + const sourceSelect = filterNode.querySelector( + '.ibexa-list-filters__item-content .ibexa-dropdown__source .ibexa-input--select, .ibexa-list-filters__item-content .ids-dropdown__source select', + ); sourceSelect?.addEventListener('change', filterChange, false); }; @@ -80,7 +83,7 @@ return; } - const select = filterNode.querySelector(SELECTOR_DROPDOWN_SOURCE_SELECT); + const select = filterNode.querySelector('.ibexa-dropdown__source .ibexa-input--select, .ids-dropdown__source select'); const checkedCheckboxes = filterNode.querySelectorAll('.ibexa-input--checkbox:checked'); if (isNodeDatePicker(filterNode)) { diff --git a/src/bundle/Resources/public/js/scripts/admin.search.filters.js b/src/bundle/Resources/public/js/scripts/admin.search.filters.js index 71f405a3c2..6959eda4af 100644 --- a/src/bundle/Resources/public/js/scripts/admin.search.filters.js +++ b/src/bundle/Resources/public/js/scripts/admin.search.filters.js @@ -2,21 +2,23 @@ const { escapeHTML, escapeHTMLAttribute } = ibexa.helpers.text; const { dangerouslySetInnerHTML } = ibexa.helpers.dom; const { getInstance } = ibexa.helpers.objectInstances; - const SELECTOR_DROPDOWN = '.ibexa-dropdown, .ids-dropdown'; - const SELECTOR_DROPDOWN_SOURCE_SELECT = '.ibexa-input--select, .ids-dropdown__source select'; let getUsersTimeout; const SELECTOR_TAG = '.ibexa-tag'; const token = doc.querySelector('meta[name="CSRF-Token"]').content; const siteaccess = doc.querySelector('meta[name="SiteAccess"]').content; const filters = doc.querySelector('.ibexa-filters'); - const getDropdownContainer = (selector) => filters.querySelector(`${selector} ${SELECTOR_DROPDOWN}`); - const getDropdownSourceSelect = (selector) => filters.querySelector(`${selector} ${SELECTOR_DROPDOWN_SOURCE_SELECT}`); const clearBtn = filters.querySelector('.ibexa-btn--clear'); const applyBtn = filters.querySelector('.ibexa-btn--apply'); const contentTypeSelect = doc.querySelector('.ibexa-filters__item--content-type .ibexa-filters__select'); - const sectionSelect = getDropdownSourceSelect('.ibexa-filters__item--section'); - const lastModifiedDropdownNode = getDropdownContainer('.ibexa-filters__item--modified'); - const lastModifiedSelectNode = getDropdownSourceSelect('.ibexa-filters__item--modified'); + const sectionSelect = filters.querySelector( + '.ibexa-filters__item--section .ibexa-input--select, .ibexa-filters__item--section .ids-dropdown__source select', + ); + const lastModifiedDropdownNode = filters.querySelector( + '.ibexa-filters__item--modified .ibexa-dropdown, .ibexa-filters__item--modified .ids-dropdown', + ); + const lastModifiedSelectNode = filters.querySelector( + '.ibexa-filters__item--modified .ibexa-input--select, .ibexa-filters__item--modified .ids-dropdown__source select', + ); const lastModifiedSelect = getInstance(lastModifiedDropdownNode); const lastModifiedDateRangeNode = doc.querySelector('.ibexa-filters__item--modified .ibexa-date-time-range-single'); const lastModifiedDateRange = getInstance(lastModifiedDateRangeNode); @@ -28,8 +30,12 @@ const lastModifiedPeriod = doc.querySelector(lastModifiedPeriodSelector); const lastModifiedStartDate = doc.querySelector(lastModifiedStartSelector); const lastModifiedEndDate = doc.querySelector(lastModifiedEndSelector); - const lastCreatedDropdownNode = getDropdownContainer('.ibexa-filters__item--created'); - const lastCreatedSelectNode = getDropdownSourceSelect('.ibexa-filters__item--created'); + const lastCreatedDropdownNode = filters.querySelector( + '.ibexa-filters__item--created .ibexa-dropdown, .ibexa-filters__item--created .ids-dropdown', + ); + const lastCreatedSelectNode = filters.querySelector( + '.ibexa-filters__item--created .ibexa-input--select, .ibexa-filters__item--created .ids-dropdown__source select', + ); const lastCreatedSelect = getInstance(lastCreatedDropdownNode); const lastCreatedDateRangeNode = doc.querySelector('.ibexa-filters__item--created .ibexa-date-time-range-single'); const lastCreatedDateRange = getInstance(lastCreatedDateRangeNode); diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 111a33612c..bd7cc652e4 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -4,6 +4,7 @@ {% set multiple = multiple|default(false) %} {% set custom_init = custom_init|default(false) %} {% set is_disabled = is_disabled|default(false) or attr.readonly|default(false) %} + {% set source = source|default(null) %} {% set source_attr = source_attr|default({}) %} {% set source_id = source_id|default(source_attr.id|default(null)) %} From 3d742864bec6dc4d1e25fc001dbd22664791583b Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:31:27 +0200 Subject: [PATCH 18/22] refactor: drop unused source attr exclusions --- .../ui/component/dropdown/dropdown_ds.html.twig | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index bd7cc652e4..6577a2f4cb 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -10,21 +10,9 @@ {% set source_id = source_id|default(source_attr.id|default(null)) %} {% set source_name = source_name|default(source_attr.name|default(name|default('dropdown'))) %} {% set max_visible_items = 5 %} -{% set excluded_source_attr_keys = [ - 'dropdown_hidden', - 'dropdown_class', - 'dropdown_custom_init', - 'is_small', - 'is_ghost', - 'is_selector', - 'is_dynamic', - 'has_select_all_toggler', -] %} {% set normalized_source_attr = {} %} {% for key, item in source_attr %} - {% if key not in excluded_source_attr_keys %} - {% set normalized_source_attr = normalized_source_attr|merge({ (key): item }) %} - {% endif %} + {% set normalized_source_attr = normalized_source_attr|merge({ (key): item }) %} {% endfor %} {% set normalized_source_attr = normalized_source_attr|merge({ name: source_name, From cf59a77e149394b23f649c5d4fac949f872cee44 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:33:16 +0200 Subject: [PATCH 19/22] refactor: tighten DS dropdown bridge setup --- .../admin/ui/component/dropdown/dropdown_ds.html.twig | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index 6577a2f4cb..dbb334d238 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -9,12 +9,7 @@ {% set source_attr = source_attr|default({}) %} {% set source_id = source_id|default(source_attr.id|default(null)) %} {% set source_name = source_name|default(source_attr.name|default(name|default('dropdown'))) %} -{% set max_visible_items = 5 %} -{% set normalized_source_attr = {} %} -{% for key, item in source_attr %} - {% set normalized_source_attr = normalized_source_attr|merge({ (key): item }) %} -{% endfor %} -{% set normalized_source_attr = normalized_source_attr|merge({ +{% set normalized_source_attr = source_attr|merge({ name: source_name, disabled: is_disabled, required: required|default(false), @@ -62,6 +57,7 @@ ) %} {% if can_use_ds %} + {% set max_visible_items = 5 %} {% set normalized_preferred_choices = preferred_choices|map(choice => { value: choice.value ~ '', label: translation_domain is same as(false) ? choice.label : choice.label|trans({}, translation_domain), From b6dc5f1a6c42c9859eb0c5d712638bbb2163b552 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:46:12 +0200 Subject: [PATCH 20/22] refactor: simplify dropdown bridge context maps --- .../component/dropdown/dropdown_ds.html.twig | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig index dbb334d238..82fa542963 100644 --- a/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig +++ b/src/bundle/Resources/views/themes/admin/ui/component/dropdown/dropdown_ds.html.twig @@ -97,7 +97,7 @@ disabled: is_disabled, maxVisibleItems: max_visible_items, class: class|default(''), - source: source, + source, sourceAttributes: normalized_source_attr, } %} {% set ds_dropdown_props = translated_placeholder is not same as(null) @@ -116,16 +116,16 @@ {% endif %} {% else %} {% set legacy_context = { - source: source|default(null), - choices: choices, - preferred_choices: preferred_choices, - value: value, - multiple: multiple, - custom_init: custom_init, + source, + choices, + preferred_choices, + value, + multiple, + custom_init, class: class|default(''), - translation_domain: translation_domain, + translation_domain, custom_form: custom_form is defined ? custom_form : true, - is_disabled: is_disabled, + is_disabled, is_hidden: is_hidden|default(false), is_small: is_small|default(false), is_ghost: is_ghost|default(false), From 0fa2f8d0560e3b1bc85d757babf8d41bdeb40d7d Mon Sep 17 00:00:00 2001 From: tischsoic Date: Mon, 11 May 2026 14:53:46 +0200 Subject: [PATCH 21/22] fix: address design system provider lint issues --- .../modules/common/design-system/design.system.provider.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js b/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js index ef38ea08fa..aa6af3c473 100644 --- a/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js +++ b/src/bundle/ui-dev/src/modules/common/design-system/design.system.provider.js @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import PropTypes from 'prop-types'; import { AssetsProvider, TranslatorProvider } from '@ids-components/context'; @@ -15,7 +16,7 @@ const DesignSystemProvider = ({ children }) => { ); const translatorContextValue = useMemo( () => ({ - trans: (key, parameters = {}, domain) => Translator.trans(key, parameters, domain), + trans: (key, parameters, domain) => Translator.trans(key, parameters ?? {}, domain), }), [Translator], ); @@ -27,4 +28,8 @@ const DesignSystemProvider = ({ children }) => { ); }; +DesignSystemProvider.propTypes = { + children: PropTypes.node.isRequired, +}; + export default DesignSystemProvider; From c41218f8562f23e03ecf2c75fb1d1c4678961b95 Mon Sep 17 00:00:00 2001 From: tischsoic Date: Thu, 12 Mar 2026 10:30:45 +0100 Subject: [PATCH 22/22] DST in composer.json --- composer.json | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 97beea181e..e34fc9058c 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "ibexa/content-forms": "~6.0.x-dev", "ibexa/core": "~6.0.x-dev", "ibexa/design-engine": "~6.0.x-dev", + "ibexa/design-system-twig": "~6.0.x-dev", "ibexa/rest": "~6.0.x-dev", "ibexa/search": "~6.0.x-dev", "ibexa/twig-components": "~6.0.x-dev", @@ -97,5 +98,11 @@ "branch-alias": { "dev-main": "6.0.x-dev" } - } + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/ibexa/design-system-twig" + } + ] }