lekoala / bootstrap5-autocomplete

Autocomplete for Bootstrap 5 (and 4!)
MIT License
87 stars 16 forks source link

Missing TypeScript types #26

Closed williamdes closed 1 year ago

williamdes commented 1 year ago

Hi 👋🏻 I found this library and it really seems interesting ! That said I use TypeScript with VueJS and it complains about the lack of .d.ts files. Could you add a types file or would you be open to migrating to TypeScript (but still generating .js files) ?

williamdes commented 1 year ago

I did some transformation of your annotations with vscode

 \* @property \{(.*)\} ([a-z]+) (.*)

to

$2: $1; // $3

Will continue posting as I advance on this

lekoala commented 1 year ago

i'm absolutely against typescript :-)

i haven't checked if there is a way to generate .d.ts because i have no need for them

williamdes commented 1 year ago

Yay 😄 ..

type ItemCallback = (item: Object, inst: Autocomplete) => void;
type RenderCallback = (item: Object, label: string, inst: Autocomplete) => string;
type ServerCallback = (response: Response, inst: Autocomplete) => Promise

interface Config {
    showAllSuggestions?: Boolean; // Show all suggestions even if they don't match
    suggestionsThreshold?: Number; // Number of chars required to show suggestions
    maximumItems?: Number; // Maximum number of items to display
    autoselectFirst?: Boolean; // Always select the first item
    ignoreEnter?: Boolean; // Ignore enter if no items are selected (play nicely with autoselectFirst=0)
    updateOnSelect?: Boolean; // Update input value on selection (doesn't play nice with autoselectFirst)
    highlightTyped?: Boolean; // Highlight matched part of the label
    highlightClass?: String; // Class added to the mark label
    fullWidth?: Boolean; // Match the width on the input field
    fixed?: Boolean; // Use fixed positioning (solve overflow issues)
    fuzzy?: Boolean; // Fuzzy search
    startsWith?: Boolean; // Must start with the string. Defaults to false (it matches any position).
    preventBrowserAutocomplete?: Boolean; // Additional measures to prevent browser autocomplete
    itemClass?: String; // Applied to the 'li'. Accepts space separated classes.
    activeClasses?: Array; // By default: ["bg-primary", "text-white"]
    labelField?: String; // Key for the label
    valueField?: String; // Key for the value
    searchFields?: Array; // Key for the search
    queryParam?: String; // Key for the query parameter for server
    items?: Array | Object; // An array of label/value objects or an object with key/values
    source?: Function; // A function that provides the list of items
    hiddenInput?: Boolean; // Create an hidden input which stores the valueField
    hiddenValue?: String; // Populate the initial hidden value. Mostly useful with liveServer.
    datalist?: String; // The id of the source datalist
    server?: String; // Endpoint for data provider
    serverMethod?: String; // HTTP request method for data provider, default is GET
    serverParams?: String | Object; // Parameters to pass along to the server. You can specify a "related" key with the id of a related field.
    serverDataKey?: String; // By default: data
    fetchOptions?: Object; // Any other fetch options (https://developer.mozilla.org/en-US/docs/Web/API/fetch#syntax)
    liveServer?: Boolean; // Should the endpoint be called each time on input
    noCache?: Boolean; // Prevent caching by appending a timestamp
    debounceTime?: Number; // Debounce time for live server
    notFoundMessage?: String; // Display a no suggestions found message. Leave empty to disable
    onRenderItem?: RenderCallback; // Callback function that returns the label
    onSelectItem?: ItemCallback; // Callback function to call on selection
    onServerResponse?: ServerCallback; // Callback function to process server response. Must return a Promise
    onChange?: ItemCallback; // Callback function to call on change-event. Returns currently selected item if any
}

declare module 'bootstrap5-autocomplete' {
    export default class Autocomplete {
        /**
         * Attach to all elements matched by the selector
         */
        public static init(selector: string, config: Config);
    }
}

Okay, then you can include a file with the types. Here is what I managed to do. And it works !

lekoala commented 1 year ago

it seems the proper way would be to generate that during the build process

https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html https://github.com/evanw/esbuild/issues/95

williamdes commented 1 year ago

Awesome 💯 , I can test the result for you if needed

lekoala commented 1 year ago

@williamdes have a look https://github.com/lekoala/bootstrap5-autocomplete/commit/a2a7d87c73bab9b0eb00058dfa118bd3c7ee56e7

williamdes commented 1 year ago

Very cool, could you change all occurrences of config to Config and not Object ? Also, the current Config object forces to define all the config keys. See my example where I changed them all to <name>?: so they all can be missing since they all have default values

williamdes commented 1 year ago

Also, you should probably apply: https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#including-declarations-in-your-npm-package

Example: https://github.com/mynamesleon/aria-autocomplete/blob/2d41bb059b2f2716b9471d4beee08247b623763b/package.json#L7

williamdes commented 1 year ago

PS: the README should probably say import Autocomplete from "bootstrap5-autocomplete"; Maybe it does not apply to JS installations 🤔

lekoala commented 1 year ago

yes, the optional keys are kinda of annoying. the way i designed it, is that the full config object must have all the keys, but obviously you can also pass partial configs since they are going to be merged anyway. And i don't really want to declare two config interface (one partial, one with mandatory fields) for the sake of it. That's why i also allow regular objects

williamdes commented 1 year ago

yes, the optional keys are kinda of annoying. the way i designed it, is that the full config object must have all the keys, but obviously you can also pass partial configs since they are going to be merged anyway. And i don't really want to declare two config interface (one partial, one with mandatory fields) for the sake of it. That's why i also allow regular objects

Only one could be enough I think, not sure if default values can be embed into an interface. Why do you not want to make them all not required since it's the actual truth?

lekoala commented 1 year ago

@williamdes internally, they are all required by the class (values are expected to be set), but as an argument, you can pass anything

lekoala commented 1 year ago

closing this, if anyone has a good proposal to deal with partial config, i'm open to hear it, otherwise, as far as i'm concerned, i can live with how it's done :-)