Function showUI

  • Experimental

    Shows a dynamically generated UI - !!!POC version, expect changes

    Parameters

    • ctx: Context

      The context in which the UI is rendered

    • element: Element

      The JSX element representing the UI to be shown

    Returns Promise<unknown>

    An object with state property that holds the current UI values and property button that holds the value of the clicked button that resolved the showUI promise

    • Every showUI must call a container function first. Container functions are bubble, modal, shield, and splitView.
    • Container function can contain headerBar, group, and navigationBar. All are optional.
    • showUI can be resolved by using button component with resolve: true property or by using navigationBar component with buttons property. One of them must be present to resolve the showUI promise.
    • If sub element wants to be displayed, it must be wrapped by group.
    • For alignment purposes, vertical and horizontal functions can be used.
    • To display a spinner, use progressItem component. Make sure showUI is called with void and not awaited.
    • The return value of showUI contains each UI element state grouped by name. State is any type of data that UI element needs to maintain. in example: const { state } = await showUI(ctx, element); state.hobbies // ['reading', 'traveling'] - checkboxList with name 'hobbies' state.firstName // 'Mark' - input with name 'firstName' state.food // 'burger' - radioList with name 'food' state.country // 'us' - select with name 'country'

    Usage with various elements

    const result = await showUI(
    ctx,
    bubble([
    headerBar({title: 'Modular UI form'}),
    group([
    text({
    // TODO: change so that other options are optional and content is a second or only argument
    text: async (data) =>
    '**First name:** ' +
    data.firstName +
    '\n **Country:** ' +
    data.country +
    '\n **Hobby:** ' +
    data.hobbies +
    '\n **Food:** ' +
    data.food,
    }),
    input({
    name: 'firstName',
    label: 'First name',
    defaultValue: 'Mark',
    }),
    fileUpload({
    name: 'upload-file',
    fileUploadTitle: 'Upload Files',
    uploadButton: 'Upload',
    text: 'Please select file to upload.',
    error: 'You can upload up to 3 files only.',
    maxFileLimit: 3,
    minFileLimit: 1,
    loadingText: 'Uploading...',
    validate: async (file:DroppedFile) => {
    const isValid = false // Apply your validation logic here
    const message = isValid ? '' : 'File is not valid'
    return {
    isValid,
    message,
    processedFile: file
    };
    },
    allowedTypes: {
    types: ['image/*', 'application/pdf'],
    message: 'File type must be an image or a PDF',
    },
    maxFileSize: {
    size: 5 * 1024 * 1024, // 5MB
    message: 'File size must be less than 5MB',
    },
    }),
    select({
    name: 'country',
    label: 'Country',
    items: [
    {value: 'us', label: 'United States'},
    {value: 'de', label: 'Germany'},
    {value: 'fr', label: 'France'},
    ],
    }),
    checkboxList({
    name: 'hobbies',
    label: 'Hobbies',
    items: [
    {value: 'reading', label: 'Reading'},
    {value: 'traveling', label: 'Traveling'},
    {value: 'cooking', label: 'Cooking'},
    ],
    }),
    radioList({
    name: 'food',
    label: 'food',
    items: async (state) =>
    state.country === 'us'
    ? [
    {value: 'burger', label: 'Burger'},
    {value: 'fries', label: 'Fries'},
    ]
    : [
    {value: 'pasta', label: 'Pasta'},
    {value: 'pizza', label: 'Pizza'},
    {value: 'salad', label: 'Salad'},
    ],
    }),
    statuses({
    statuses: [
    { status: 'success', text: 'Data fetched successfully.' },
    { status: 'warning', text: 'Data filtered successfully.' },
    { status: 'error', text: 'Data filtered successfully.' },
    ],
    }),
    button({
    text: 'Submit',
    value: 'submit',
    resolve: true, // to resolve the showUI promise
    updateState: async (state, value) => { // buttons can also update state
    const count = state.count || 0;
    return {count: count + 1};
    },
    }),
    spinner({
    title: 'Loading...',
    description: 'Please wait while we load the data.',
    }),
    ]),
    ]),
    );

    Usage to show a spinner

    void showUI(ctx,
    bubble([
    group([
    progressItem({
    status: 'running',
    title: 'Loading...',
    description: 'Please wait while we load the data.',
    }),
    ]),
    ]),
    );

    Usage with text and navigationBar that can be used to display a message to user

    const result = await showUI(ctx,
    bubble([
    headerBar({title: 'Modular UI Message Component'}),
    group([
    text({text: 'Welcome to the Modular UI world!'}),
    ]),
    navigationBar({
    buttons: [
    {text: 'Proceed', value: 'ok'},
    ],
    }),
    ]),
    );

    @example
    Usage with button inside group
    ```tsx
    const result = await showUI(ctx,
    bubble([
    headerBar({title: 'Modular UI with button inside group'}),
    group([
    text({text: 'Please click the button below to submit the form.'}),
    button({
    text: 'Submit',
    value: 'submit',
    resolve: true, // to resolve the showUI promise
    updateState: async (state, value) => { // buttons can also update state
    const count = state.count || 0;
    return {count: count + 1};
    },
    }),
    ]),
    ]),
    );

    Usage with form elements and navigationBar

    const result = await showUI(ctx,
    bubble([
    headerBar({title: 'Modular UI Form Component'}),
    group([
    input({name: 'name', label: 'Name'}),
    input({name: 'email', label: 'Email'}),
    input({name: 'password', label: 'Password'}),
    ]),
    navigationBar({
    buttons: [
    {text: 'Proceed', value: 'ok'},
    ],
    }),
    ]),
    );
    // result returned value: {button:"ok",state:{name:"John",email:"john@example.com",password:"supersecret"}}

    @example
    Usage with file upload
    const result = await showUI(ctx,
    bubble([
    headerBar({title: 'Modular UI File Upload Component'}),
    group([
    fileUpload({
    name: 'upload-file',
    fileUploadTitle: 'Upload Files',
    uploadButton: 'Upload',
    text: 'Please select file to upload.',
    error: 'You can upload up to 3 files only.',
    maxFileLimit: 3,
    minFileLimit: 1,
    loadingText: 'Uploading...',
    validate: async (file:DroppedFile) => {
    const isValid = false // Apply your validation logic here
    const message = isValid ? '' : 'File is not valid'
    return {
    isValid,
    message,
    processedFile: file
    };
    },
    allowedTypes: {
    types: ['image/*', 'application/pdf'],
    message: 'File type must be an image or a PDF',
    },
    maxFileSize: {
    size: 5 * 1024 * 1024, // 5MB
    message: 'File size must be less than 5MB',
    },
    }),
    ]),
    navigationBar({
    buttons: [
    {text: 'Proceed', value: 'ok'},
    ],
    }),
    ]),
    );