@keenthemes/ktui 1.0.12 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ktui.js +738 -700
- package/dist/ktui.min.js +1 -1
- package/dist/ktui.min.js.map +1 -1
- package/dist/styles.css +5824 -0
- package/examples/select/avatar.html +47 -0
- package/examples/select/basic-usage.html +10 -14
- package/examples/select/{test.html → combobox-icons_.html} +13 -48
- package/examples/select/country.html +43 -0
- package/examples/select/description.html +25 -41
- package/examples/select/disable-option.html +10 -16
- package/examples/select/disable-select.html +7 -6
- package/examples/select/icon-multiple.html +23 -31
- package/examples/select/icon.html +20 -30
- package/examples/select/max-selection.html +8 -9
- package/examples/select/modal.html +16 -17
- package/examples/select/multiple.html +11 -13
- package/examples/select/placeholder.html +9 -12
- package/examples/select/search.html +30 -22
- package/examples/select/sizes.html +94 -0
- package/examples/select/template-customization.html +0 -3
- package/lib/cjs/components/component.js +1 -1
- package/lib/cjs/components/component.js.map +1 -1
- package/lib/cjs/components/datatable/datatable.js +14 -11
- package/lib/cjs/components/datatable/datatable.js.map +1 -1
- package/lib/cjs/components/select/combobox.js +96 -61
- package/lib/cjs/components/select/combobox.js.map +1 -1
- package/lib/cjs/components/select/config.js +13 -8
- package/lib/cjs/components/select/config.js.map +1 -1
- package/lib/cjs/components/select/dropdown.js +32 -96
- package/lib/cjs/components/select/dropdown.js.map +1 -1
- package/lib/cjs/components/select/option.js +53 -20
- package/lib/cjs/components/select/option.js.map +1 -1
- package/lib/cjs/components/select/search.js +146 -97
- package/lib/cjs/components/select/search.js.map +1 -1
- package/lib/cjs/components/select/select.js +219 -118
- package/lib/cjs/components/select/select.js.map +1 -1
- package/lib/cjs/components/select/tags.js +0 -26
- package/lib/cjs/components/select/tags.js.map +1 -1
- package/lib/cjs/components/select/templates.js +130 -105
- package/lib/cjs/components/select/templates.js.map +1 -1
- package/lib/cjs/components/select/utils.js +33 -132
- package/lib/cjs/components/select/utils.js.map +1 -1
- package/lib/cjs/helpers/dom.js +0 -24
- package/lib/cjs/helpers/dom.js.map +1 -1
- package/lib/esm/components/component.js +1 -1
- package/lib/esm/components/component.js.map +1 -1
- package/lib/esm/components/datatable/datatable.js +14 -11
- package/lib/esm/components/datatable/datatable.js.map +1 -1
- package/lib/esm/components/select/combobox.js +96 -61
- package/lib/esm/components/select/combobox.js.map +1 -1
- package/lib/esm/components/select/config.js +13 -8
- package/lib/esm/components/select/config.js.map +1 -1
- package/lib/esm/components/select/dropdown.js +32 -96
- package/lib/esm/components/select/dropdown.js.map +1 -1
- package/lib/esm/components/select/option.js +53 -20
- package/lib/esm/components/select/option.js.map +1 -1
- package/lib/esm/components/select/search.js +146 -97
- package/lib/esm/components/select/search.js.map +1 -1
- package/lib/esm/components/select/select.js +219 -118
- package/lib/esm/components/select/select.js.map +1 -1
- package/lib/esm/components/select/tags.js +0 -26
- package/lib/esm/components/select/tags.js.map +1 -1
- package/lib/esm/components/select/templates.js +130 -105
- package/lib/esm/components/select/templates.js.map +1 -1
- package/lib/esm/components/select/utils.js +32 -130
- package/lib/esm/components/select/utils.js.map +1 -1
- package/lib/esm/helpers/dom.js +0 -24
- package/lib/esm/helpers/dom.js.map +1 -1
- package/package.json +9 -6
- package/src/components/component.ts +0 -4
- package/src/components/datatable/datatable.ts +14 -11
- package/src/components/input/input.css +1 -1
- package/src/components/scrollable/scrollable.css +9 -5
- package/src/components/select/combobox.ts +98 -87
- package/src/components/select/config.ts +16 -13
- package/src/components/select/dropdown.ts +43 -108
- package/src/components/select/option.ts +44 -25
- package/src/components/select/search.ts +158 -117
- package/src/components/select/select.css +99 -27
- package/src/components/select/select.ts +236 -128
- package/src/components/select/tags.ts +1 -27
- package/src/components/select/templates.ts +191 -132
- package/src/components/select/utils.ts +30 -166
- package/src/components/toast/toast.css +1 -1
- package/src/helpers/dom.ts +0 -30
- package/webpack.config.js +6 -1
- package/examples/select/combobox-icons.html +0 -58
- package/examples/select/icon-description.html +0 -56
- /package/examples/select/{combobox.html → combobox_.html} +0 -0
- /package/examples/select/{remote-data.html → remote-data_.html} +0 -0
- /package/examples/select/{tags-icons.html → tags-icons_.html} +0 -0
- /package/examples/select/{tags-selected.html → tags-selected_.html} +0 -0
- /package/examples/select/{tags.html → tags_.html} +0 -0
|
@@ -11,14 +11,14 @@ import { renderTemplateString } from './utils';
|
|
|
11
11
|
* Users can override any template by providing a matching key in the config.templates object.
|
|
12
12
|
*/
|
|
13
13
|
export const coreTemplateStrings = {
|
|
14
|
-
dropdown: `<div data-kt-select-dropdown class="kt-select-dropdown hidden {{class}}" style="z-index: {{zindex}};"
|
|
15
|
-
options: `<ul role="listbox" aria-label="{{label}}" class="kt-select-options {{class}}" data-kt-select-options="true"
|
|
16
|
-
error: `<li class="kt-select-error" role="alert"
|
|
17
|
-
highlight: `<span data-kt-select-highlight class="kt-select-highlight highlighted {{class}}">{{text}}</span>`,
|
|
14
|
+
dropdown: `<div data-kt-select-dropdown class="kt-select-dropdown hidden {{class}}" style="z-index: {{zindex}};"></div>`,
|
|
15
|
+
options: `<ul role="listbox" aria-label="{{label}}" class="kt-select-options {{class}}" data-kt-select-options="true"></ul>`,
|
|
16
|
+
error: `<li class="kt-select-error" role="alert"></li>`,
|
|
18
17
|
wrapper: `<div data-kt-select-wrapper class="kt-select-wrapper {{class}}"></div>`,
|
|
19
18
|
combobox: `
|
|
20
19
|
<div data-kt-select-combobox data-kt-select-display class="kt-select-combobox {{class}}">
|
|
21
|
-
<
|
|
20
|
+
<div data-kt-select-combobox-values="true" class="kt-select-combobox-values"></div>
|
|
21
|
+
<input class="kt-input kt-select-combobox-input" data-kt-select-search="true" type="text" placeholder="{{placeholder}}" role="searchbox" aria-label="{{label}}" {{disabled}} />
|
|
22
22
|
<button type="button" data-kt-select-clear-button="true" class="kt-select-combobox-clear-btn" aria-label="Clear selection">
|
|
23
23
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
24
24
|
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
@@ -27,20 +27,22 @@ export const coreTemplateStrings = {
|
|
|
27
27
|
</button>
|
|
28
28
|
</div>
|
|
29
29
|
`,
|
|
30
|
+
placeholder: `<div data-kt-select-placeholder class="kt-select-placeholder {{class}}"></div>`,
|
|
30
31
|
display: `
|
|
31
32
|
<div data-kt-select-display class="kt-select-display {{class}}" tabindex="{{tabindex}}" role="button" data-selected="0" aria-haspopup="listbox" aria-expanded="false" aria-label="{{label}}" {{disabled}}>
|
|
32
|
-
<div
|
|
33
|
+
<div class="kt-select-option-text" data-kt-text-container="true">{{text}}</div>
|
|
33
34
|
</div>
|
|
34
35
|
`,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
option: `
|
|
37
|
+
<li data-kt-select-option data-value="{{value}}" data-text="{{text}}" class="kt-select-option {{class}}" role="option" {{selected}} {{disabled}}>
|
|
38
|
+
<div class="kt-select-option-text" data-kt-text-container="true">{{text}}</div><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-3.5 ms-auto hidden text-primary kt-select-option-selected:block"><path d="M20 6 9 17l-5-5"/></svg>
|
|
39
|
+
</li>
|
|
40
|
+
`,
|
|
41
|
+
search: `<div data-kt-select-search class="kt-select-search {{class}}"><input type="text" data-kt-select-search="true" placeholder="{{searchPlaceholder}}" class="kt-input kt-input-ghost" role="searchbox" aria-label="{{searchPlaceholder}}"/></div>`,
|
|
42
|
+
empty: `<li data-kt-select-empty class="kt-select-no-result {{class}}" role="status"></li>`,
|
|
43
|
+
loading: `<li class="kt-select-loading {{class}}" role="status" aria-live="polite"></li>`,
|
|
44
|
+
tag: `<div data-kt-select-tag="true" class="kt-select-tag {{class}}"></div>`,
|
|
45
|
+
loadMore: `<li class="kt-select-load-more {{class}}" data-kt-select-load-more="true"></li>`,
|
|
44
46
|
tagRemoveButton: `<button type="button" data-kt-select-remove-button class="kt-select-tag-remove" aria-label="Remove tag" tabindex="0"><svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="3" x2="9" y2="9"/><line x1="9" y1="3" x2="3" y2="9"/></svg></button>`,
|
|
45
47
|
};
|
|
46
48
|
|
|
@@ -68,9 +70,9 @@ export interface KTSelectTemplateInterface {
|
|
|
68
70
|
/**
|
|
69
71
|
* Renders an error message in the dropdown
|
|
70
72
|
*/
|
|
71
|
-
error: (
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
error: (
|
|
74
|
+
config: KTSelectConfigInterface & { errorMessage: string },
|
|
75
|
+
) => HTMLElement;
|
|
74
76
|
|
|
75
77
|
// Main components
|
|
76
78
|
wrapper: (config: KTSelectConfigInterface) => HTMLElement;
|
|
@@ -91,7 +93,10 @@ export interface KTSelectTemplateInterface {
|
|
|
91
93
|
) => HTMLElement;
|
|
92
94
|
|
|
93
95
|
// Multi-select
|
|
94
|
-
tag: (
|
|
96
|
+
tag: (
|
|
97
|
+
option: HTMLOptionElement,
|
|
98
|
+
config: KTSelectConfigInterface,
|
|
99
|
+
) => HTMLElement;
|
|
95
100
|
|
|
96
101
|
placeholder: (config: KTSelectConfigInterface) => HTMLElement;
|
|
97
102
|
}
|
|
@@ -143,15 +148,6 @@ export function getTemplateStrings(
|
|
|
143
148
|
* Default templates for KTSelect component
|
|
144
149
|
*/
|
|
145
150
|
export const defaultTemplates: KTSelectTemplateInterface = {
|
|
146
|
-
/**
|
|
147
|
-
* Renders a highlighted text
|
|
148
|
-
*/
|
|
149
|
-
highlight: (config: KTSelectConfigInterface, text: string) => {
|
|
150
|
-
const template = getTemplateStrings(config).highlight;
|
|
151
|
-
const html = template.replace('{{text}}', text).replace('{{class}}', config.highlightClass || '');
|
|
152
|
-
return stringToElement(html);
|
|
153
|
-
},
|
|
154
|
-
|
|
155
151
|
/**
|
|
156
152
|
* Renders the dropdown content
|
|
157
153
|
*/
|
|
@@ -159,17 +155,28 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
159
155
|
config: KTSelectConfigInterface & { zindex?: number; content?: string },
|
|
160
156
|
) => {
|
|
161
157
|
let template = getTemplateStrings(config).dropdown;
|
|
162
|
-
|
|
158
|
+
// If a custom dropdownTemplate is provided, it's responsible for its own content.
|
|
159
|
+
// Otherwise, the base template is used, and content is appended later.
|
|
163
160
|
if (config.dropdownTemplate) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
161
|
+
const renderedCustomTemplate = renderTemplateString(
|
|
162
|
+
config.dropdownTemplate,
|
|
163
|
+
{
|
|
164
|
+
zindex: config.zindex ? String(config.zindex) : '',
|
|
165
|
+
// content: config.content || '', // No longer pass content to custom template directly here
|
|
166
|
+
class: config.dropdownClass || '',
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
// The custom template IS the dropdown element
|
|
170
|
+
const customDropdownEl = stringToElement(renderedCustomTemplate);
|
|
171
|
+
if (config.zindex) customDropdownEl.style.zIndex = String(config.zindex);
|
|
172
|
+
if (config.dropdownClass)
|
|
173
|
+
customDropdownEl.classList.add(...config.dropdownClass.split(' '));
|
|
174
|
+
return customDropdownEl;
|
|
169
175
|
}
|
|
176
|
+
|
|
170
177
|
const html = template
|
|
171
178
|
.replace('{{zindex}}', config.zindex ? String(config.zindex) : '')
|
|
172
|
-
.replace('{{content}}',
|
|
179
|
+
// .replace('{{content}}', '') // Content is no longer part of the base template string
|
|
173
180
|
.replace('{{class}}', config.dropdownClass || '');
|
|
174
181
|
return stringToElement(html);
|
|
175
182
|
},
|
|
@@ -182,7 +189,7 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
182
189
|
const html = template
|
|
183
190
|
.replace('{{label}}', config.label || 'Options')
|
|
184
191
|
.replace('{{height}}', config.height ? String(config.height) : '250')
|
|
185
|
-
.replace('{{options}}',
|
|
192
|
+
// .replace('{{options}}', '') // Options are now appended dynamically
|
|
186
193
|
.replace('{{class}}', config.optionsClass || '');
|
|
187
194
|
return stringToElement(html);
|
|
188
195
|
},
|
|
@@ -191,32 +198,38 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
191
198
|
* Renders the load more button for pagination
|
|
192
199
|
*/
|
|
193
200
|
loadMore: (config: KTSelectConfigInterface): HTMLElement => {
|
|
194
|
-
let html = getTemplateStrings(config)
|
|
195
|
-
'{{loadMoreText}}',
|
|
196
|
-
config.
|
|
197
|
-
);
|
|
198
|
-
|
|
201
|
+
let html = getTemplateStrings(config)
|
|
202
|
+
.loadMore // .replace('{{loadMoreText}}', config.loadMoreText || 'Load more...') // Content is no longer in template string
|
|
203
|
+
.replace('{{class}}', config.loadMoreClass || '');
|
|
204
|
+
const element = stringToElement(html);
|
|
205
|
+
element.textContent = config.loadMoreText || 'Load more...';
|
|
206
|
+
return element;
|
|
199
207
|
},
|
|
200
208
|
/**
|
|
201
209
|
* Renders an error message in the dropdown
|
|
202
210
|
*/
|
|
203
211
|
error: (
|
|
204
212
|
config: KTSelectConfigInterface & { errorMessage: string },
|
|
205
|
-
):
|
|
213
|
+
): HTMLElement => {
|
|
214
|
+
// Changed return type to HTMLElement
|
|
206
215
|
const template = getTemplateStrings(config).error;
|
|
207
|
-
|
|
208
|
-
.replace('{{errorMessage}}', config.errorMessage || 'An error occurred')
|
|
216
|
+
const html = template
|
|
217
|
+
// .replace('{{errorMessage}}', config.errorMessage || 'An error occurred') // Content is no longer in template string
|
|
209
218
|
.replace('{{class}}', config.errorClass || '');
|
|
219
|
+
const element = stringToElement(html);
|
|
220
|
+
element.textContent = config.errorMessage || 'An error occurred';
|
|
221
|
+
return element;
|
|
210
222
|
},
|
|
223
|
+
|
|
211
224
|
/**
|
|
212
225
|
* Renders the main container for the select component
|
|
213
226
|
*/
|
|
214
227
|
wrapper: (config: KTSelectConfigInterface): HTMLElement => {
|
|
215
|
-
const html = getTemplateStrings(config).wrapper
|
|
216
|
-
|
|
228
|
+
const html = getTemplateStrings(config).wrapper.replace(
|
|
229
|
+
'{{class}}',
|
|
230
|
+
config.wrapperClass || '',
|
|
231
|
+
);
|
|
217
232
|
const element = stringToElement(html);
|
|
218
|
-
element.setAttribute('data-kt-select-combobox', config.combobox ? 'true' : 'false');
|
|
219
|
-
element.setAttribute('data-kt-select-tags', config.tags ? 'true' : 'false');
|
|
220
233
|
return element;
|
|
221
234
|
},
|
|
222
235
|
|
|
@@ -224,28 +237,21 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
224
237
|
* Renders the display element (trigger) for the select
|
|
225
238
|
*/
|
|
226
239
|
display: (config: KTSelectConfigInterface): HTMLElement => {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
.combobox.replace(/{{placeholder}}/g, config.placeholder || 'Select...')
|
|
230
|
-
.replace(
|
|
231
|
-
/{{label}}/g,
|
|
232
|
-
config.label || config.placeholder || 'Select...',
|
|
233
|
-
)
|
|
234
|
-
.replace('{{disabled}}', config.disabled ? 'disabled' : '')
|
|
235
|
-
.replace('{{class}}', config.displayClass || '');
|
|
236
|
-
return stringToElement(html);
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
let content = config.label || config.placeholder || 'Select...';
|
|
240
|
-
|
|
241
|
-
let html = getTemplateStrings(config).display
|
|
242
|
-
.replace('{{tabindex}}', config.disabled ? '-1' : '0')
|
|
240
|
+
let html = getTemplateStrings(config)
|
|
241
|
+
.display.replace('{{tabindex}}', config.disabled ? '-1' : '0')
|
|
243
242
|
.replace('{{label}}', config.label || config.placeholder || 'Select...')
|
|
244
243
|
.replace('{{disabled}}', config.disabled ? 'aria-disabled="true"' : '')
|
|
245
244
|
.replace('{{placeholder}}', config.placeholder || 'Select...')
|
|
246
|
-
.replace('{{class}}', config.displayClass || '')
|
|
247
|
-
|
|
248
|
-
|
|
245
|
+
.replace('{{class}}', config.displayClass || '');
|
|
246
|
+
|
|
247
|
+
const element = stringToElement(html);
|
|
248
|
+
|
|
249
|
+
// Add data-multiple attribute if in multiple select mode
|
|
250
|
+
if (config.multiple) {
|
|
251
|
+
element.setAttribute('data-multiple', 'true');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return element;
|
|
249
255
|
},
|
|
250
256
|
|
|
251
257
|
/**
|
|
@@ -256,37 +262,71 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
256
262
|
config: KTSelectConfigInterface,
|
|
257
263
|
): HTMLElement => {
|
|
258
264
|
const isHtmlOption = option instanceof HTMLOptionElement;
|
|
265
|
+
let optionData: Record<string, any>;
|
|
266
|
+
|
|
267
|
+
if (isHtmlOption) {
|
|
268
|
+
// If it's a plain HTMLOptionElement, construct data similarly to how KTSelectOption would
|
|
269
|
+
// This branch might be less common if KTSelectOption instances are always used for rendering.
|
|
270
|
+
const el = option as HTMLOptionElement;
|
|
271
|
+
const textContent = el.textContent || '';
|
|
272
|
+
optionData = {
|
|
273
|
+
value: el.value,
|
|
274
|
+
text: textContent,
|
|
275
|
+
selected: el.selected,
|
|
276
|
+
disabled: el.disabled, // This captures original disabled state
|
|
277
|
+
content: textContent, // Default content to text
|
|
278
|
+
// Attempt to get custom config for this specific option value if available
|
|
279
|
+
...(config.optionsConfig?.[el.value] || {}),
|
|
280
|
+
};
|
|
281
|
+
} else {
|
|
282
|
+
// If it's a KTSelectOption class instance (from './option')
|
|
283
|
+
// which should have the getOptionDataForTemplate method.
|
|
284
|
+
optionData = (
|
|
285
|
+
option as import('./option').KTSelectOption
|
|
286
|
+
).getOptionDataForTemplate();
|
|
287
|
+
}
|
|
259
288
|
|
|
260
|
-
|
|
261
|
-
const text = isHtmlOption ? option.text : (option as KTSelectOption).title;
|
|
262
|
-
const disabled = isHtmlOption
|
|
263
|
-
? option.disabled
|
|
264
|
-
: (option as any).disabled === true;
|
|
265
|
-
const selected = isHtmlOption
|
|
266
|
-
? option.selected
|
|
267
|
-
: !!(option as KTSelectOption).selected;
|
|
289
|
+
let content = optionData.text; // Default content to option's text
|
|
268
290
|
|
|
269
|
-
let content = text;
|
|
270
291
|
if (config.optionTemplate) {
|
|
271
|
-
// Use the user template
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
selected: selected ? 'aria-selected="true"' : 'aria-selected="false"',
|
|
277
|
-
disabled: disabled ? 'aria-disabled="true"' : '',
|
|
278
|
-
content: text,
|
|
279
|
-
});
|
|
292
|
+
// Use the user-provided template string, rendering with the full optionData.
|
|
293
|
+
// renderTemplateString will replace {{key}} with values from optionData.
|
|
294
|
+
content = renderTemplateString(config.optionTemplate, optionData);
|
|
295
|
+
} else {
|
|
296
|
+
content = optionData.text || optionData.content; // Prefer explicit text, fallback to content
|
|
280
297
|
}
|
|
281
298
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
.
|
|
288
|
-
|
|
289
|
-
|
|
299
|
+
// Use the core option template string as the base structure.
|
|
300
|
+
const baseTemplate = getTemplateStrings(config).option;
|
|
301
|
+
|
|
302
|
+
const optionClasses = [config.optionClass || ''];
|
|
303
|
+
if (optionData.disabled) {
|
|
304
|
+
optionClasses.push('disabled');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Populate the base template for the <li> attributes.
|
|
308
|
+
// The actual display content (text or custom HTML) will be set on the inner span later.
|
|
309
|
+
const html = renderTemplateString(baseTemplate, {
|
|
310
|
+
...optionData, // Pass all data for {{value}}, {{text}}, {{selected}}, {{disabled}}, etc.
|
|
311
|
+
class: optionClasses.join(' ').trim() || '',
|
|
312
|
+
selected: optionData.selected
|
|
313
|
+
? 'aria-selected="true"'
|
|
314
|
+
: 'aria-selected="false"',
|
|
315
|
+
disabled: optionData.disabled ? 'aria-disabled="true"' : '',
|
|
316
|
+
content: content, // This is for the {{content}} placeholder within the option template string itself
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const element = stringToElement(html);
|
|
320
|
+
|
|
321
|
+
// If a custom option template is provided, replace the element's innerHTML with the content.
|
|
322
|
+
if (config.optionTemplate) {
|
|
323
|
+
element.innerHTML = content;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Ensure data-text attribute is set to the original, clean text for searching/filtering
|
|
327
|
+
element.setAttribute('data-text', optionData?.text?.trim() || '');
|
|
328
|
+
|
|
329
|
+
return element;
|
|
290
330
|
},
|
|
291
331
|
|
|
292
332
|
/**
|
|
@@ -306,13 +346,13 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
306
346
|
* Renders the no results message
|
|
307
347
|
*/
|
|
308
348
|
empty: (config: KTSelectConfigInterface): HTMLElement => {
|
|
309
|
-
let html = getTemplateStrings(config)
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return
|
|
349
|
+
let html = getTemplateStrings(config).empty.replace(
|
|
350
|
+
'{{class}}',
|
|
351
|
+
config.emptyClass || '',
|
|
352
|
+
);
|
|
353
|
+
const element = stringToElement(html);
|
|
354
|
+
element.textContent = config.searchNotFoundText || 'No results found';
|
|
355
|
+
return element;
|
|
316
356
|
},
|
|
317
357
|
|
|
318
358
|
/**
|
|
@@ -322,13 +362,13 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
322
362
|
config: KTSelectConfigInterface,
|
|
323
363
|
loadingMessage: string,
|
|
324
364
|
): HTMLElement => {
|
|
325
|
-
let html = getTemplateStrings(config)
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return
|
|
365
|
+
let html = getTemplateStrings(config).loading.replace(
|
|
366
|
+
'{{class}}',
|
|
367
|
+
config.loadingClass || '',
|
|
368
|
+
);
|
|
369
|
+
const element = stringToElement(html);
|
|
370
|
+
element.textContent = loadingMessage || 'Loading options...';
|
|
371
|
+
return element;
|
|
332
372
|
},
|
|
333
373
|
|
|
334
374
|
/**
|
|
@@ -339,45 +379,60 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
339
379
|
config: KTSelectConfigInterface,
|
|
340
380
|
): HTMLElement => {
|
|
341
381
|
let template = getTemplateStrings(config).tag;
|
|
342
|
-
let
|
|
343
|
-
if (config.tagTemplate) {
|
|
344
|
-
let tagTemplate = config.tagTemplate;
|
|
345
|
-
|
|
346
|
-
const text = option.getAttribute('data-text');
|
|
347
|
-
const value = option.getAttribute('data-value');
|
|
382
|
+
let preparedContent = option.title; // Default content is the option's title
|
|
348
383
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
384
|
+
if (config.tagTemplate) {
|
|
385
|
+
let tagTemplateString = config.tagTemplate;
|
|
386
|
+
const optionValue = option.getAttribute('data-value') || option.value;
|
|
387
|
+
|
|
388
|
+
// Replace all {{varname}} in option.innerHTML with values from _config.optionsConfig
|
|
389
|
+
Object.entries(
|
|
390
|
+
(config.optionsConfig as any)?.[optionValue] || {},
|
|
391
|
+
).forEach(([key, val]) => {
|
|
392
|
+
if (
|
|
393
|
+
typeof val === 'string' ||
|
|
394
|
+
typeof val === 'number' ||
|
|
395
|
+
typeof val === 'boolean'
|
|
396
|
+
) {
|
|
397
|
+
tagTemplateString = tagTemplateString.replace(
|
|
398
|
+
new RegExp(`{{${key}}}`, 'g'),
|
|
399
|
+
String(val),
|
|
400
|
+
);
|
|
353
401
|
}
|
|
354
402
|
});
|
|
355
403
|
|
|
356
|
-
|
|
404
|
+
// Render the custom tag template with option data
|
|
405
|
+
preparedContent = renderTemplateString(tagTemplateString, {
|
|
357
406
|
title: option.title,
|
|
358
407
|
id: option.id,
|
|
359
|
-
class: config.tagClass || '',
|
|
360
|
-
content: option.innerHTML,
|
|
361
|
-
text: option.innerText,
|
|
408
|
+
class: config.tagClass || '', // This class is for content, not the main tag div
|
|
409
|
+
// content: option.innerHTML, // Avoid direct innerHTML from option due to potential XSS
|
|
410
|
+
text: option.innerText || option.textContent || '',
|
|
411
|
+
value: optionValue,
|
|
362
412
|
});
|
|
363
413
|
}
|
|
364
414
|
|
|
365
|
-
|
|
415
|
+
// Append the remove button HTML string to the prepared content
|
|
416
|
+
preparedContent += getTemplateStrings(config).tagRemoveButton;
|
|
366
417
|
|
|
367
418
|
const html = template
|
|
368
|
-
.replace('{{title}}', option.title)
|
|
369
|
-
.replace('{{id}}', option.id)
|
|
370
|
-
.replace('{{
|
|
371
|
-
|
|
372
|
-
|
|
419
|
+
// .replace('{{title}}', option.title) // Title is part of preparedContent if using custom template
|
|
420
|
+
// .replace('{{id}}', option.id) // ID is part of preparedContent if using custom template
|
|
421
|
+
.replace('{{class}}', config.tagClass || ''); // Class for the main tag div
|
|
422
|
+
|
|
423
|
+
const element = stringToElement(html);
|
|
424
|
+
element.innerHTML = preparedContent; // Set the fully prepared content (text/HTML + remove button)
|
|
425
|
+
return element;
|
|
373
426
|
},
|
|
374
427
|
|
|
375
428
|
/**
|
|
376
429
|
* Renders the placeholder for the select
|
|
377
430
|
*/
|
|
378
431
|
placeholder: (config: KTSelectConfigInterface): HTMLElement => {
|
|
379
|
-
let html = getTemplateStrings(config)
|
|
380
|
-
|
|
432
|
+
let html = getTemplateStrings(config).placeholder.replace(
|
|
433
|
+
'{{class}}',
|
|
434
|
+
config.placeholderClass || '',
|
|
435
|
+
);
|
|
381
436
|
|
|
382
437
|
let content = config.placeholder || 'Select...';
|
|
383
438
|
|
|
@@ -386,9 +441,13 @@ export const defaultTemplates: KTSelectTemplateInterface = {
|
|
|
386
441
|
placeholder: config.placeholder || 'Select...',
|
|
387
442
|
class: config.placeholderClass || '',
|
|
388
443
|
});
|
|
444
|
+
const element = stringToElement(html);
|
|
445
|
+
element.innerHTML = content; // For templates, content can be HTML
|
|
446
|
+
return element;
|
|
447
|
+
} else {
|
|
448
|
+
const element = stringToElement(html);
|
|
449
|
+
element.textContent = content; // For simple text, use textContent
|
|
450
|
+
return element;
|
|
389
451
|
}
|
|
390
|
-
|
|
391
|
-
html = html.replace('{{content}}', content);
|
|
392
|
-
return stringToElement(html);
|
|
393
452
|
},
|
|
394
453
|
};
|