import { html, type TemplateResult } from 'lit';
import type { AutoCompleteSuggestion } from '../../components/nui-auto-complete/types.js';
import {
formatUsageFromDefaults,
type PlaygroundControl,
type PlaygroundDefinition,
type PlaygroundPreviewHandlers,
type PlaygroundProps,
whenBoolean,
whenString,
} from '../types.js';
const DEFAULT_SUGGESTIONS: AutoCompleteSuggestion[] = [
{ label: 'New York', value: 'NY' },
{ label: 'Rome', value: 'RM' },
{ label: 'London', value: 'LDN' },
{ label: 'Istanbul', value: 'IST' },
{ label: 'Paris', value: 'PRS' },
];
const ATTRIBUTE_NAMES: Record = {
optionLabel: 'option-label',
optionValue: 'option-value',
optionDisabled: 'option-disabled',
dropdownMode: 'dropdown-mode',
scrollHeight: 'scroll-height',
minLength: 'min-length',
forceSelection: 'force-selection',
completeOnFocus: 'complete-on-focus',
emptyMessage: 'empty-message',
dropdownIcon: 'dropdown-icon',
inputId: 'input-id',
ariaLabel: 'aria-label',
ariaLabelledby: 'aria-labelledby',
nuiType: 'nui-type',
autoCompleteClass: 'auto-complete-class',
};
export const NUI_AUTO_COMPLETE_DEFAULTS: PlaygroundProps = {
value: '',
suggestions: JSON.stringify(DEFAULT_SUGGESTIONS, null, 2),
optionLabel: 'label',
optionValue: 'value',
optionDisabled: 'disabled',
placeholder: 'Search city',
disabled: false,
invalid: false,
readonly: false,
fluid: false,
dropdown: true,
dropdownMode: 'blank',
size: '',
variant: '',
scrollHeight: '14rem',
minLength: '1',
forceSelection: false,
completeOnFocus: false,
emptyMessage: 'No results found',
dropdownIcon: 'mdi:chevron-down',
name: '',
inputId: 'nui-auto-complete-preview',
ariaLabel: '',
ariaLabelledby: '',
unstyled: false,
nuiType: '',
autoCompleteClass: '',
};
const CONTROLS: PlaygroundControl[] = [
{
key: 'value',
label: 'value',
type: 'text',
section: 'Content',
placeholder: 'NY',
},
{
key: 'suggestions',
label: 'suggestions (JSON)',
type: 'textarea',
section: 'Content',
rows: 8,
fullWidth: true,
placeholder: '[{"label":"New York","value":"NY"}]',
},
{
key: 'placeholder',
label: 'placeholder',
type: 'text',
section: 'Content',
placeholder: 'Search city',
},
{
key: 'optionLabel',
label: 'option-label',
type: 'text',
section: 'Content',
placeholder: 'label',
},
{
key: 'optionValue',
label: 'option-value',
type: 'text',
section: 'Content',
placeholder: 'value',
},
{
key: 'optionDisabled',
label: 'option-disabled',
type: 'text',
section: 'Content',
placeholder: 'disabled',
},
{
key: 'emptyMessage',
label: 'empty-message',
type: 'text',
section: 'Content',
},
{
key: 'autoCompleteClass',
label: 'auto-complete-class',
type: 'text',
section: 'Content',
},
{
key: 'size',
label: 'size',
type: 'select',
section: 'Appearance',
options: [
{ value: '', label: '(default)' },
{ value: 'small', label: 'small' },
{ value: 'large', label: 'large' },
],
},
{
key: 'variant',
label: 'variant',
type: 'select',
section: 'Appearance',
options: [
{ value: '', label: 'outlined' },
{ value: 'filled', label: 'filled' },
],
},
{
key: 'dropdownIcon',
label: 'dropdown-icon',
type: 'text',
section: 'Appearance',
placeholder: 'mdi:chevron-down',
},
{ key: 'nuiType', label: 'nui-type', type: 'text', section: 'Appearance' },
{
key: 'unstyled',
label: 'unstyled',
type: 'boolean',
section: 'Modifiers',
},
{ key: 'fluid', label: 'fluid', type: 'boolean', section: 'Layout' },
{ key: 'dropdown', label: 'dropdown', type: 'boolean', section: 'State' },
{
key: 'dropdownMode',
label: 'dropdown-mode',
type: 'select',
section: 'State',
options: [
{ value: 'blank', label: 'blank' },
{ value: 'current', label: 'current' },
],
},
{
key: 'forceSelection',
label: 'force-selection',
type: 'boolean',
section: 'State',
},
{
key: 'completeOnFocus',
label: 'complete-on-focus',
type: 'boolean',
section: 'State',
},
{ key: 'disabled', label: 'disabled', type: 'boolean', section: 'State' },
{ key: 'invalid', label: 'invalid', type: 'boolean', section: 'State' },
{ key: 'readonly', label: 'readonly', type: 'boolean', section: 'State' },
{
key: 'minLength',
label: 'min-length',
type: 'text',
section: 'State',
placeholder: '1',
},
{
key: 'scrollHeight',
label: 'scroll-height',
type: 'text',
section: 'State',
placeholder: '14rem',
},
{
key: 'inputId',
label: 'input-id',
type: 'text',
section: 'HTML',
},
{ key: 'name', label: 'name', type: 'text', section: 'HTML' },
{
key: 'ariaLabel',
label: 'aria-label',
type: 'text',
section: 'HTML',
},
{
key: 'ariaLabelledby',
label: 'aria-labelledby',
type: 'text',
section: 'HTML',
},
];
function parseSuggestions(value: unknown): AutoCompleteSuggestion[] {
if (typeof value !== 'string' || !value.trim()) {
return [];
}
try {
const parsed = JSON.parse(value) as unknown;
return Array.isArray(parsed) ? (parsed as AutoCompleteSuggestion[]) : [];
} catch {
return [];
}
}
function handleAutoCompleteChange(
event: Event,
handlers?: PlaygroundPreviewHandlers,
): void {
if (!handlers) {
return;
}
const value = (event as CustomEvent<{ value: string }>).detail.value;
handlers.onPropChange('value', String(value ?? ''));
}
function renderPreview(
props: PlaygroundProps,
handlers?: PlaygroundPreviewHandlers,
): TemplateResult {
return html`
handleAutoCompleteChange(event, handlers)}
>
`;
}
export const nuiAutoCompletePlayground: PlaygroundDefinition = {
tag: 'nui-auto-complete',
label: 'Auto Complete',
description:
'Input with filtered suggestions overlay, optional dropdown button, and keyboard navigation.',
defaults: NUI_AUTO_COMPLETE_DEFAULTS,
controls: CONTROLS,
renderPreview,
getPreviewClass: (props) => (props.fluid ? 'is-fluid' : ''),
formatUsage: (props) => {
const { suggestions: _suggestions, value: _value, ...usageProps } = props;
return formatUsageFromDefaults(
'nui-auto-complete',
usageProps,
NUI_AUTO_COMPLETE_DEFAULTS,
ATTRIBUTE_NAMES,
);
},
};