From a82779ed16a628f8813c0d0be77769d967bfa9f7 Mon Sep 17 00:00:00 2001
From: jaredgibb <70493366+jaredgibb@users.noreply.github.com>
Date: Thu, 13 Nov 2025 12:47:30 -0500
Subject: [PATCH 01/24] update
---
src/wwElement_Trigger.vue | 14 ++++++++++-
ww-config.js | 51 +++++++++++++++++++++++++++++++++++++++
2 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/src/wwElement_Trigger.vue b/src/wwElement_Trigger.vue
index 53e0dae..b328638 100644
--- a/src/wwElement_Trigger.vue
+++ b/src/wwElement_Trigger.vue
@@ -17,7 +17,8 @@
-
+
+
+ {{ displayCountText }}
+
{{ data.placeholder }}
@@ -325,6 +330,12 @@ export default {
emit('remove-multiselect-value', value);
};
+ const displayCountText = computed(() => {
+ const count = selectedDetails.value?.length || 0;
+ const template = wwLib.wwLang.getText(props.content.displayText) || 'Selected: {count}';
+ return template.replace('{count}', count.toString());
+ });
+
return {
isSingleSelect,
data,
@@ -349,6 +360,7 @@ export default {
chipIconFromOption,
isOpen,
handleChipClick,
+ displayCountText,
};
},
};
diff --git a/ww-config.js b/ww-config.js
index 1312456..06020ce 100644
--- a/ww-config.js
+++ b/ww-config.js
@@ -194,6 +194,8 @@ export default {
'searchPlaceholder',
'initialState',
'selectType',
+ 'displayMode',
+ 'displayText',
'selectTypeWarning',
],
},
@@ -521,6 +523,55 @@ export default {
},
/* wwEditor:end */
},
+ displayMode: {
+ label: 'Display mode',
+ type: 'TextSelect',
+ options: {
+ options: [
+ {
+ value: 'chips',
+ label: 'Display chips',
+ },
+ {
+ value: 'count',
+ label: 'Display count',
+ },
+ ],
+ },
+ bindable: true,
+ defaultValue: 'chips',
+ section: 'settings',
+ /* wwEditor:start */
+ bindingValidation: {
+ type: 'string',
+ tooltip: 'A string value, either "chips" or "count"',
+ },
+ propertyHelp: {
+ tooltip: 'Choose how to display selected items in multi-select mode.\nPossible values: chips, count',
+ },
+ /* wwEditor:end */
+ hidden: content => content.selectType !== 'multiple',
+ },
+ displayText: {
+ label: 'Display text',
+ type: 'Text',
+ defaultValue: { en: 'Selected: {count}' },
+ section: 'settings',
+ states: true,
+ bindable: true,
+ responsive: true,
+ multiLang: true,
+ /* wwEditor:start */
+ bindingValidation: {
+ type: 'string',
+ tooltip: 'A string value with {count} placeholder: "Selected: {count}"',
+ },
+ propertyHelp: {
+ tooltip: 'The text to display when using count mode. Use {count} as a placeholder for the number of selected items.',
+ },
+ /* wwEditor:end */
+ hidden: content => content.selectType !== 'multiple' || content.displayMode !== 'count',
+ },
disabled: {
label: { en: 'Disabled' },
type: 'OnOff',
From 7231ecfe0d13d4afa6c20574b45c6f65a3a1a364 Mon Sep 17 00:00:00 2001
From: jaredgibb <70493366+jaredgibb@users.noreply.github.com>
Date: Thu, 13 Nov 2025 13:46:52 -0500
Subject: [PATCH 02/24] commit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Summary
I've successfully implemented the "Sort Selected to Top" feature for your WeWeb select component. Here's what was added:
1. Configuration (ww-config.js)
New Property: sortSelectedToTop
Type: Toggle (On/Off)
Default: false (off)
Location: Settings → Options section
Supports binding, states, and responsive settings
2. Component Logic (wwElement_OptionsList.vue)
Injected Dependencies: Added access to selectedValue and mappingValue from the parent component
Enhanced filteredOptions Computed Property:
First applies search filtering (if active)
Then applies sorting logic when sortSelectedToTop is enabled
Compares each option's value against the selected value(s)
Handles both primitive values and objects
Handles both single and multiple selection modes
Uses JSON comparison for complex object values with fallback to direct comparison
How It Works:
When disabled (default): Options display in their original order
When enabled:
Selected items automatically move to the top of the list
Maintains relative order within selected and unselected groups
Works seamlessly with search filtering
Updates dynamically as items are selected/deselected
The feature integrates perfectly with:
Single and multiple select modes
Search functionality
Virtual scrolling (both heavy and dynamic modes)
All option types (text, icon+text, image+text)
Primitive and object-based options
Users can now enable this in the WeWeb editor under Settings → Options → Sort selected to top!
---
src/wwElement_OptionsList.vue | 62 +++++++++++++++++++++++++++++++++--
ww-config.js | 19 +++++++++++
2 files changed, 79 insertions(+), 2 deletions(-)
diff --git a/src/wwElement_OptionsList.vue b/src/wwElement_OptionsList.vue
index eaf9041..4038837 100644
--- a/src/wwElement_OptionsList.vue
+++ b/src/wwElement_OptionsList.vue
@@ -99,6 +99,8 @@ export default {
const searchState = inject('_wwSelect:searchState', ref(null));
const { updateSearch } = inject('_wwSelect:useSearch', {});
const registerOptionProperties = inject('_wwSelect:registerOptionProperties', () => {});
+ const selectedValue = inject('_wwSelect:value', ref(null));
+ const mappingValue = inject('_wwSelect:mappingValue', ref(null));
const virtualScrollMinItemSize = computed(() => props.content.virtualScrollMinItemSize);
const virtualScrollBuffer = computed(() => props.content.virtualScrollBuffer);
const heavyMode = computed(() => props.content.heavyMode);
@@ -156,8 +158,64 @@ export default {
});
const filteredOptions = computed(() => {
- if (!searchState.value || !searchState.value.value) return options.value;
- let filtered = memoizedFilter(options.value, searchState.value.value);
+ let filtered = options.value;
+
+ // Apply search filter if active
+ if (searchState.value && searchState.value.value) {
+ filtered = memoizedFilter(options.value, searchState.value.value);
+ }
+
+ // Apply sorting if sortSelectedToTop is enabled
+ if (props.content.sortSelectedToTop && selectedValue.value) {
+ filtered = [...filtered].sort((a, b) => {
+ // Get the value for each option
+ const aValue = typeof a === 'object' && a !== null
+ ? wwLib.resolveObjectPropertyPath(a, mappingValue.value?.code || 'value')
+ : a;
+ const bValue = typeof b === 'object' && b !== null
+ ? wwLib.resolveObjectPropertyPath(b, mappingValue.value?.code || 'value')
+ : b;
+
+ // Check if each option is selected
+ const aIsSelected = Array.isArray(selectedValue.value)
+ ? selectedValue.value.some(v => {
+ try {
+ return JSON.stringify(v) === JSON.stringify(aValue);
+ } catch {
+ return v === aValue;
+ }
+ })
+ : (() => {
+ try {
+ return JSON.stringify(selectedValue.value) === JSON.stringify(aValue);
+ } catch {
+ return selectedValue.value === aValue;
+ }
+ })();
+
+ const bIsSelected = Array.isArray(selectedValue.value)
+ ? selectedValue.value.some(v => {
+ try {
+ return JSON.stringify(v) === JSON.stringify(bValue);
+ } catch {
+ return v === bValue;
+ }
+ })
+ : (() => {
+ try {
+ return JSON.stringify(selectedValue.value) === JSON.stringify(bValue);
+ } catch {
+ return selectedValue.value === bValue;
+ }
+ })();
+
+ // Sort selected items to top
+ if (aIsSelected && !bIsSelected) return -1;
+ if (!aIsSelected && bIsSelected) return 1;
+ return 0; // Keep original order for items with same selection status
+ });
+ }
+
return filtered;
});
diff --git a/ww-config.js b/ww-config.js
index 06020ce..f7e1374 100644
--- a/ww-config.js
+++ b/ww-config.js
@@ -212,6 +212,7 @@ export default {
'closeOnClickOutside',
'manualTrigger',
'selectOnClick',
+ 'sortSelectedToTop',
'virtualScroll',
'virtualScrollBuffer',
'virtualScrollMinItemSize',
@@ -1076,6 +1077,24 @@ export default {
},
/* wwEditor:end */
},
+ sortSelectedToTop: {
+ label: { en: 'Sort selected to top' },
+ type: 'OnOff',
+ states: true,
+ bindable: true,
+ responsive: true,
+ defaultValue: false,
+ section: 'settings',
+ /* wwEditor:start */
+ bindingValidation: {
+ type: 'boolean',
+ tooltip: 'Whether selected items should appear at the top of the options list: `true | false`',
+ },
+ propertyHelp: {
+ tooltip: 'When enabled, selected options will be sorted to the top of the list.',
+ },
+ /* wwEditor:end */
+ },
unselectOnClick: {
label: { en: 'Unselect on click' },
type: 'OnOff',
From b7bdf63903ee359f8d36a4914da9b9382098cf89 Mon Sep 17 00:00:00 2001
From: jaredgibb <70493366+jaredgibb@users.noreply.github.com>
Date: Thu, 13 Nov 2025 13:53:02 -0500
Subject: [PATCH 03/24] Update wwElement_OptionsList.vue
---
src/wwElement_OptionsList.vue | 68 +++++++++++++++--------------------
1 file changed, 29 insertions(+), 39 deletions(-)
diff --git a/src/wwElement_OptionsList.vue b/src/wwElement_OptionsList.vue
index 4038837..6046794 100644
--- a/src/wwElement_OptionsList.vue
+++ b/src/wwElement_OptionsList.vue
@@ -52,9 +52,10 @@