Manifest Debugger

Tip: You are using react-docgen (the default). Generation took 0.4s. For higher quality prop types, consider switching to react-docgen-typescript in your main.ts:
typescript: {
  reactDocgen: 'react-docgen-typescript',
}
Note: react-docgen-typescript can be slower. If performance is acceptable for your project, it generally produces better results. Learn more

Components

CSSValueInput

uikit-controls-cssvalueinput · ./stories/CSSValueInput.stories.tsx
Prop type error
No component file found for the "CSSValueInput" component.
   6 | import type { Meta, StoryObj } from '@storybook/react-vite';
   7 |
>  8 | const meta: Meta<typeof CSSValueInput> = {
     | ^
   9 |     component: CSSValueInput,
  10 |     parameters: {
  11 |         docs: {

./stories/CSSValueInput.stories.tsx:
import CSSValueInput from '../../css-value-input/src/CSSValueInput.js';

import './CSSValueInput.css';
import './InputText.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const meta: Meta<typeof CSSValueInput> = {
    component: CSSValueInput,
    parameters: {
        docs: {
            description: {
                component:
                    '`CSSValueInput` is a React component that renders a text input that can take and update a CSS value of a particular type with a default unit. The input’s behavior is similar to those in design applications such as Adobe Illustrator or XD.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/CSSValueInput',
};

export default meta;

type Story = StoryObj<typeof CSSValueInput>;

export const Length: Story = {
    args: {
        className: 'my-special-input',
        cssValueType: 'length',
        label: 'Font size',
        name: 'fontsize',
        placeholder: '1rem',
        tabIndex: 1,
        unit: 'rem',
        validator:
            /^(xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|inherit)$/,
        value: '24px',
    },
};

export const Time: Story = {
    args: {
        className: 'my-panel-input',
        cssValueType: 'time',
        label: 'Duration',
        max: 20,
        min: 0,
        name: 'duration',
        placeholder: '0.25s',
        step: 0.1,
        unit: 's',
    },
};

export const Angle: Story = {
    args: {
        className: 'flex-item-example',
        cssValueType: 'angle',
        icon: (
            <svg
                width="100px"
                height="100px"
                viewBox="0 0 100 100"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
            >
                <g stroke="none" strokeWidth="1" fill="none">
                    <g transform="translate(2, 2)" stroke="#222F3E" strokeWidth="4">
                        <path
                            d="M56.5106952,10.5464071 C60.8135865,11.5200327 64.8423906,13.2161538 68.4628809,15.5005439 L76.8618891,8.97963811 L87.0203619,19.1381109 L80.4994561,27.5371191 C82.7838462,31.1576094 84.4799673,35.1864135 85.4535929,39.4893048 L96,40.816875 L96,55.183125 L85.4535929,56.5106952 C84.4799673,60.8135865 82.7838462,64.8423906 80.4994561,68.4628809 L87.0203619,76.8618891 L76.8618891,87.0203619 L68.4628809,80.4994561 C64.8423906,82.7838462 60.8135865,84.4799673 56.5106952,85.4535929 L55.183125,96 L40.816875,96 L39.4893048,85.4535929 C35.1864135,84.4799673 31.1576094,82.7838462 27.5371191,80.4994561 L19.1381109,87.0203619 L8.97963811,76.8618891 L15.5005439,68.4628809 C13.2161538,64.8423906 11.5200327,60.8135865 10.5464071,56.5106952 L0,55.183125 L0,40.816875 L10.5464071,39.4893048 C11.5200327,35.1864135 13.2161538,31.1576094 15.5005439,27.5371191 L8.97963811,19.1381109 L19.1381109,8.97963811 L27.5371191,15.5005439 C31.1576094,13.2161538 35.1864135,11.5200327 39.4893048,10.5464071 L40.816875,0 L55.183125,0 L56.5106952,10.5464071 Z"
                            id="Layer-1"
                        ></path>
                        <circle cx="48" cy="48" r="14.4"></circle>
                    </g>
                </g>
            </svg>
        ),
        label: 'Rotate Z',
        name: 'rotatez',
        placeholder: '0deg',
        step: 45,
        unit: 'deg',
        value: '90deg',
    },
};

export const Percent: Story = {
    args: {
        cssValueType: 'percent',
        label: 'Width',
        min: 0,
        name: 'width',
        placeholder: '100%',
        step: 10,
        unit: '%',
        value: '30%',
    },
};

export const LabelLess: Story = {
    args: {
        className: 'my-special-input',
        cssValueType: 'length',
        name: 'labelless',
        placeholder: '1rem',
        title: 'No label',
        unit: 'rem',
        value: '24px',
    },
};

export const CustomGetValueAsNumber: Story = {
    args: {
        className: 'letter-spacing',
        getValueAsNumber: (value: number | string) => {
            if (typeof value === 'number') return value;
            // “normal” for letter-spacing is effectively equivalent to 0
            if (typeof value === 'string' && value.toLowerCase() === 'normal') {
                return 0;
            }
            return parseFloat(value);
        },
        label: 'Letter spacing',
        name: 'letterspacing',
        placeholder: 'normal',
        tabIndex: 2,
    },
};

export const BackgroundSize: Story = {
    args: {
        className: 'background-size',
        label: 'Background Size',
        name: 'backgroundsize',
        unit: '%',
        validator: /^(auto|contain|cover)$/,
        value: 'cover',
    },
};

export const ZIndex: Story = {
    args: {
        cssValueType: 'integer',
        label: 'z-index',
        name: 'zindex',
        value: '0',
    },
};

export const NumberValue: Story = {
    args: {
        cssValueType: 'integer',
        label: 'opacity',
        name: 'opacity',
        value: '0',
    },
};

export const LineHeight: Story = {
    args: {
        cssValueType: 'length',
        label: 'line height',
        name: 'line-height',
        step: 0.1,
        unit: '',
        value: '1.4',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { CSSValueInput } from "@acusti/uikit-docs";
Length story ok
const Length = () => <CSSValueInput
    className="my-special-input"
    cssValueType="length"
    label="Font size"
    name="fontsize"
    placeholder="1rem"
    tabIndex={1}
    unit="rem"
    validator={/^(xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|inherit)$/}
    value="24px" />;
Time story ok
const Time = () => <CSSValueInput
    className="my-panel-input"
    cssValueType="time"
    label="Duration"
    max={20}
    min={0}
    name="duration"
    placeholder="0.25s"
    step={0.1}
    unit="s" />;
Angle story ok
const Angle = () => <CSSValueInput
    className="flex-item-example"
    cssValueType="angle"
    icon={(<svg
        width="100px"
        height="100px"
        viewBox="0 0 100 100"
        version="1.1"
        xmlns="http://www.w3.org/2000/svg"
    >
        <g stroke="none" strokeWidth="1" fill="none">
            <g transform="translate(2, 2)" stroke="#222F3E" strokeWidth="4">
                <path
                    d="M56.5106952,10.5464071 C60.8135865,11.5200327 64.8423906,13.2161538 68.4628809,15.5005439 L76.8618891,8.97963811 L87.0203619,19.1381109 L80.4994561,27.5371191 C82.7838462,31.1576094 84.4799673,35.1864135 85.4535929,39.4893048 L96,40.816875 L96,55.183125 L85.4535929,56.5106952 C84.4799673,60.8135865 82.7838462,64.8423906 80.4994561,68.4628809 L87.0203619,76.8618891 L76.8618891,87.0203619 L68.4628809,80.4994561 C64.8423906,82.7838462 60.8135865,84.4799673 56.5106952,85.4535929 L55.183125,96 L40.816875,96 L39.4893048,85.4535929 C35.1864135,84.4799673 31.1576094,82.7838462 27.5371191,80.4994561 L19.1381109,87.0203619 L8.97963811,76.8618891 L15.5005439,68.4628809 C13.2161538,64.8423906 11.5200327,60.8135865 10.5464071,56.5106952 L0,55.183125 L0,40.816875 L10.5464071,39.4893048 C11.5200327,35.1864135 13.2161538,31.1576094 15.5005439,27.5371191 L8.97963811,19.1381109 L19.1381109,8.97963811 L27.5371191,15.5005439 C31.1576094,13.2161538 35.1864135,11.5200327 39.4893048,10.5464071 L40.816875,0 L55.183125,0 L56.5106952,10.5464071 Z"
                    id="Layer-1"
                ></path>
                <circle cx="48" cy="48" r="14.4"></circle>
            </g>
        </g>
    </svg>)}
    label="Rotate Z"
    name="rotatez"
    placeholder="0deg"
    step={45}
    unit="deg"
    value="90deg" />;
Percent story ok
const Percent = () => <CSSValueInput
    cssValueType="percent"
    label="Width"
    min={0}
    name="width"
    placeholder="100%"
    step={10}
    unit="%"
    value="30%" />;
Label Less story ok
const LabelLess = () => <CSSValueInput
    className="my-special-input"
    cssValueType="length"
    name="labelless"
    placeholder="1rem"
    title="No label"
    unit="rem"
    value="24px" />;
Custom Get Value As Number story ok
const CustomGetValueAsNumber = () => <CSSValueInput
    className="letter-spacing"
    getValueAsNumber={(value: number | string) => {
        if (typeof value === 'number') return value;
        // “normal” for letter-spacing is effectively equivalent to 0
        if (typeof value === 'string' && value.toLowerCase() === 'normal') {
            return 0;
        }
        return parseFloat(value);
    }}
    label="Letter spacing"
    name="letterspacing"
    placeholder="normal"
    tabIndex={2} />;
Background Size story ok
const BackgroundSize = () => <CSSValueInput
    className="background-size"
    label="Background Size"
    name="backgroundsize"
    unit="%"
    validator={/^(auto|contain|cover)$/}
    value="cover" />;
Z Index story ok
const ZIndex = () => <CSSValueInput cssValueType="integer" label="z-index" name="zindex" value="0" />;
Number Value story ok
const NumberValue = () => <CSSValueInput cssValueType="integer" label="opacity" name="opacity" value="0" />;
Line Height story ok
const LineHeight = () => <CSSValueInput
    cssValueType="length"
    label="line height"
    name="line-height"
    step={0.1}
    unit=""
    value="1.4" />;

DatePicker

uikit-controls-datepicker-datepicker · ./stories/DatePicker.stories.tsx
Prop type error
File: /Users/andrew/Projects/uikit/packages/date-picker/src/index.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
export { default as DatePicker } from './DatePicker.js';
export { default as MonthCalendar } from './MonthCalendar.js';
export * from './utils.js';


File: /Users/andrew/Projects/uikit/packages/date-picker/src/utils.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
// The following utils work on a “month” as a unique numerical value
// representing the number of months since the unix epoch (jan 1970)
const START_YEAR = 1970;
const MONTH_NAMES = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
];

const getYearFromDate = (date: Date, asUTC?: boolean) =>
    (asUTC ? date.getUTCFullYear() : date.getFullYear()) - START_YEAR;

export const getMonthFromDate = (date: Date, asUTC?: boolean) => {
    const yearAsMonths = getYearFromDate(date, asUTC) * 12;
    return yearAsMonths + (asUTC ? date.getUTCMonth() : date.getMonth());
};

export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;

export const getMonthNameFromMonth = (month: number): string => {
    let index = month % 12;
    if (Number.isNaN(index)) return '';
    if (index < 0) index = 12 + index;
    return MONTH_NAMES[index];
};

export const getMonthAbbreviationFromMonth = (month: number) => {
    const monthName = getMonthNameFromMonth(month);
    if (monthName === 'September') return 'Sept';
    return monthName.substring(0, 3);
};

export const getDateFromMonthAndDay = (month: number, day: number, asUTC?: boolean) => {
    const monthIn12 = month < 0 ? (12 - Math.abs(month % 12)) % 12 : month % 12;
    const year = getYearFromMonth(month);
    return asUTC
        ? new Date(Date.UTC(year, monthIn12, day))
        : new Date(year, monthIn12, day);
};

export const getLastDateFromMonth = (month: number, asUTC?: boolean) => {
    // day 0 of the next month is the last day of the current month
    return getDateFromMonthAndDay(month + 1, 0, asUTC);
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { DatePicker } from "@acusti/date-picker";
Default Date Picker story ok
const DefaultDatePicker = () => <DatePicker className="default-date-picker-story" />;
Two Up Date Picker story ok
const TwoUpDatePicker = () => <DatePicker className="two-up-date-picker-story" isTwoUp />;
Date Range Navidad Dia De Los Reyes Date Picker story ok
const DateRangeNavidadDiaDeLosReyesDatePicker = () => <DatePicker />;
No Future Two Up Date Picker story ok
const NoFutureTwoUpDatePicker = () => <DatePicker
    className="no-future-two-up-date-picker-story"
    isTwoUp
    monthLimitLast={getMonthFromDate(new Date())} />;
Show End Initially Date Picker story ok
const ShowEndInitiallyDatePicker = () => <DatePicker
    className="no-future-two-up-date-picker-story"
    defaultDateEnd={new Date(1234, 0, 1).toISOString()}
    defaultDateStart={new Date(1233, 0, 1).toISOString()}
    isTwoUp
    showEndInitially />;
Booking System Date Range story ok
const BookingSystemDateRange = () => <DatePicker />;
Event Scheduler story ok
const EventScheduler = () => <DatePicker />;
Birthday Picker story ok
const BirthdayPicker = () => <DatePicker />;
Flexible Date Picker story ok
const FlexibleDatePicker = () => <DatePicker />;

Demo

uikit-hooks-usekeyboardevents · ./stories/useKeyboardEvents.stories.tsx
Prop type error
No component file found for the "Demo" component.
  39 | }
  40 |
> 41 | const meta: Meta<typeof Demo> = {
     | ^
  42 |     argTypes: {
  43 |         ignoreUsedKeyboardEvents: {
  44 |             control: 'boolean',

./stories/useKeyboardEvents.stories.tsx:
import * as React from 'react';

import useKeyboardEvents from '../../use-keyboard-events/src/useKeyboardEvents.js';

import './useKeyboardEvents.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const { Fragment, useState } = React;

function Demo() {
    const [event, setEvent] = useState<KeyboardEvent | null>(null);

    useKeyboardEvents({ onKeyDown: setEvent, onKeyUp: setEvent });

    const modifiers = [
        event?.shiftKey ? '⇧ ' : '',
        event?.ctrlKey ? '⌃ ' : '',
        event?.altKey ? '⌥ ' : '',
        event?.metaKey ? '⌘ ' : '',
    ].join('');

    return (
        <Fragment>
            <p className="keyboard-event-row">
                <span className="label">Event:</span>
                <input className="code" disabled value={event?.type} />
            </p>
            <p className="keyboard-event-row">
                <span className="label">Key:</span>
                <input className="code" disabled value={event?.key} />
            </p>
            <p className="keyboard-event-row">
                <span className="label">Modifiers:</span>
                <input disabled value={modifiers} />
            </p>
        </Fragment>
    );
}

const meta: Meta<typeof Demo> = {
    argTypes: {
        ignoreUsedKeyboardEvents: {
            control: 'boolean',
            description:
                'If the prop is true, the keyboard event target is an input, textarea, or contenteditable element, and the keyboard event is usable by the element, your keyboard event listeners will not be triggered',
            table: {
                defaultValue: { summary: true },
                type: { summary: 'boolean' },
            },
        },
        priority: {
            control: 'number',
            description:
                'Priority defines what order handlers should be invoked and defaults to 0. It can be any number between -50 (lowest priority) and 50 (highest priority).',
            table: {
                defaultValue: { summary: 0 },
                type: { summary: 'number' },
            },
        },
        onKeyDown: {
            action: 'onKeyDown',
            description: 'A function that will be called when a key is pressed down',
            table: {
                type: { summary: 'function' },
            },
        },
        onKeyPress: {
            action: 'onKeyPress',
            description:
                'A function that will be called when a key that produces a character value is pressed down',
            table: {
                type: { summary: 'function' },
            },
        },
        onKeyUp: {
            action: 'onKeyUp',
            description: 'A function that will be called when a key is released',
            table: {
                type: { summary: 'function' },
            },
        },
    },
    component: Demo,
    parameters: {
        docs: {
            description: {
                component:
                    '`useKeyboardEvents` is a React hook that uses keyboard event listeners on the document to trigger the onKey(Down|Press|Up) functions in order to ensure that all key events are captured regardless of whether there is currently a focused element in the DOM (i.e. `document.activeElement` is set). This solves the problem where keyboard event handlers attached via React’s `onKey(Down|Press|Up)` props miss any keyboard events that occur when the target element and its descendants aren’t focused.',
            },
        },
    },
    // https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Hooks/useKeyboardEvents',
};

export default meta;

type Story = StoryObj<typeof Demo>;

export const UseKeyboardEvents: Story = {
    args: {},
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Use Keyboard Events story error
Could not generate snippet without component name.
Imports
import { Demo } from "@acusti/uikit-docs";

Dropdown

uikit-controls-dropdown · ./stories/Dropdown.stories.tsx
Prop type error
No component file found for the "Dropdown" component.
  35 | }
  36 |
> 37 | const meta: Meta<typeof Dropdown> = {
     | ^
  38 |     args: {
  39 |         onClick: fn(),
  40 |         onClose: fn(),

./stories/Dropdown.stories.tsx:
import { fn } from 'storybook/test';
import * as React from 'react';

import CSSValueInput from '../../css-value-input/src/CSSValueInput.js';
import Dropdown from '../../dropdown/src/Dropdown.js';

import './CSSValueInput.css';
import './Dropdown.css';
import './InputText.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const { Fragment } = React;

function ChevronDownIcon(props: React.SVGProps<SVGSVGElement>) {
    return (
        <svg
            aria-hidden="true"
            fill="none"
            focusable="false"
            height="12"
            viewBox="0 0 12 12"
            width="12"
            {...props}
        >
            <path
                d="M2.5 4.5 6 8l3.5-3.5"
                stroke="currentColor"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="1.5"
            />
        </svg>
    );
}

const meta: Meta<typeof Dropdown> = {
    args: {
        onClick: fn(),
        onClose: fn(),
        onMouseDown: fn(),
        onMouseUp: fn(),
        onOpen: fn(),
        onSubmitItem: fn(),
    },
    component: Dropdown,
    parameters: {
        docs: {
            description: {
                component:
                    '`Dropdown` is a React component that renders a menu-like UI with a trigger that the user clicks to disclose a dropdown positioned below the trigger. The body of the dropdown can include any DOM, and many dropdowns can be combined to form a multi-item menu, like the system menu in the top toolbar of macOS.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/Dropdown',
};

export default meta;

type Story = StoryObj<typeof Dropdown>;

export const CSSLengthsDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'css-lengths no-trigger-text',
    },
};

export const StatesDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>Alabama</li>
                <li>Alaska</li>
                <li>Arizona</li>
                <li>Arkansas</li>
                <li>California</li>
                <li>Colorado</li>
                <li>Connecticut</li>
                <li>Delaware</li>
                <li>Florida</li>
                <li>Georgia</li>
                <li>Hawaii</li>
                <li>Idaho</li>
                <li>Illinois</li>
                <li>Indiana</li>
                <li>Iowa</li>
                <li>Kansas</li>
                <li>Kentucky</li>
                <li>Louisiana</li>
                <li>Maine</li>
                <li>Maryland</li>
                <li>Massachusetts</li>
                <li>Michigan</li>
                <li>Minnesota</li>
                <li>Mississippi</li>
                <li>Missouri</li>
                <li>Montana</li>
                <li>Nebraska</li>
                <li>Nevada</li>
                <li>New Hampshire</li>
                <li>New Jersey</li>
                <li>New Mexico</li>
                <li>New York</li>
                <li>North Carolina</li>
                <li>North Dakota</li>
                <li>Ohio</li>
                <li>Oklahoma</li>
                <li>Oregon</li>
                <li>Pennsylvania</li>
                <li>Rhode Island</li>
                <li>South Carolina</li>
                <li>South Dakota</li>
                <li>Tennessee</li>
                <li>Texas</li>
                <li>Utah</li>
                <li>Vermont</li>
                <li>Virginia</li>
                <li>Washington</li>
                <li>West Virginia</li>
                <li>Wisconsin</li>
                <li>Wyoming</li>
            </ul>
        ),
        className: 'states-dropdown',
        isSearchable: true,
        placeholder: 'Choose a state…',
    },
};

export const FontWeightDropdown: Story = {
    args: {
        children: (
            <ul>
                <li data-ukt-value="100">
                    <span className="item-title">Font Weight - </span>
                    100
                </li>
                <li data-ukt-value="200">
                    <span className="item-title">Font Weight - </span>
                    200
                </li>
                <li data-ukt-value="300">
                    <span className="item-title">Font Weight - </span>
                    300
                </li>
                <li data-ukt-value="400">
                    <span className="item-title">Font Weight - </span>
                    400
                </li>
                <li data-ukt-value="500">
                    <span className="item-title">Font Weight - </span>
                    500
                </li>
                <li data-ukt-value="600">
                    <span className="item-title">Font Weight - </span>
                    600
                </li>
                <li data-ukt-value="700">
                    <span className="item-title">Font Weight - </span>
                    700
                </li>
            </ul>
        ),
        className: 'font-weight',
        isSearchable: true,
    },
};

export const ShowContextMenuOnMount: Story = {
    args: {
        children: [
            'View menu',
            <Fragment>
                <h4 className="heading">View</h4>
                <ul>
                    <li data-ukt-item>Open</li>
                    <li data-ukt-item>Preview</li>
                </ul>
                <h4 className="heading">Edit</h4>
                <ul>
                    <li data-ukt-value="save-item">Save</li>
                    <li data-ukt-value="edit-item">Edit</li>
                    <li data-ukt-value="delete-item">Delete</li>
                </ul>
            </Fragment>,
        ],
        className: 'open-on-mount-context-menu',
        isOpenOnMount: true,
    },
};

export const DropdownWithInteractiveContents: Story = {
    args: {
        children: [
            'Open',
            <div>
                <p>
                    Try interacting with the controls here. The dropdown should only close
                    when you click outside of the entire dropdown or if you hit the escape
                    key when focus isn’t in the input controls.
                </p>
                <CSSValueInput
                    cssValueType="length"
                    label="Width"
                    onSubmitValue={() => {}}
                    placeholder="100vw"
                    unit="vw"
                />
                <CSSValueInput
                    cssValueType="length"
                    label="Rotation"
                    onSubmitValue={() => {}}
                    placeholder="0deg"
                    step={5}
                    unit="deg"
                />
            </div>,
        ],
        className: 'dropdown-without-items',
        hasItems: false,
    },
};

export const SearchableWithLabel: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'searchable-with-label',
        isSearchable: true,
        label: (
            <span
                style={{
                    alignItems: 'center',
                    display: 'inline-flex',
                    gap: '0.25rem',
                }}
            >
                Font size
                <ChevronDownIcon />
            </span>
        ),
    },
};

export const SearchableAndAllowCreate: Story = {
    args: {
        allowCreate: true,
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'searchable-and-allow-create',
        isSearchable: true,
        label: 'Font size',
    },
};

export const CSSValueInputTrigger: Story = {
    args: {
        allowCreate: true,
        children: [
            <CSSValueInput
                name="cssinputbackgroundsize"
                onSubmitValue={() => {}}
                placeholder="cover"
                validator={/^(auto|contain|cover)$/}
            />,
            <ul>
                <li>cover</li>
                <li>contain</li>
                <li>auto</li>
                <li>50px</li>
                <li>100px</li>
                <li>200px</li>
                <li>50%</li>
            </ul>,
        ],
        className: 'css-value-input-trigger',
        hasItems: true,
        label: 'Background size',
    },
};

export const TextareaTrigger: Story = {
    args: {
        children: [
            <textarea></textarea>,
            <ul>
                <li>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
                    ullamcorper fringilla quam, vel tincidunt nisl mattis vel.
                </li>
                <li>
                    Aenean posuere erat sed enim luctus, et accumsan nisl elementum. Nulla
                    vel blandit urna, vel accumsan nulla. Nulla varius luctus ex, gravida
                    ultrices orci sagittis eu.
                </li>
                <li>
                    Quisque vitae magna euismod ligula molestie maximus id et nunc. Nam et
                    lacus euismod, porttitor massa vel, sollicitudin ex. Sed ut tellus
                    suscipit, faucibus tortor nec, fermentum mi.
                </li>
                <li>
                    Nulla sagittis justo non accumsan sagittis. Cras a eros et dolor
                    dapibus bibendum lobortis quis ante. Ut eget scelerisque massa.
                </li>
                <li>
                    Vestibulum quis dignissim nunc. Mauris fringilla at nulla non lacinia.
                    Etiam tristique elit non nisl finibus, fringilla hendrerit ligula
                    hendrerit. Fusce eget leo lacinia, eleifend diam non, suscipit purus.
                </li>
            </ul>,
        ],
        className: 'textarea-trigger',
        hasItems: true,
    },
};

export const CheckboxesDropdown: Story = {
    args: {
        children: [
            'Colors',
            <ul>
                <li>
                    <label>
                        <input type="checkbox" /> Red
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Blue
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Yellow
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Cyan
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Orchid
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Slate
                    </label>
                </li>
            </ul>,
        ],
        className: 'checkboxes',
        keepOpenOnSubmit: true,
    },
};

const FIXED_HEADER_PROPS = {
    children: [
        <button
            aria-label="Open user menu"
            className="avatar-profile has-avatar"
            popoverTarget="avatar-menu-popover"
            style={{ backgroundImage: `url("https://picsum.photos/id/40/100/100")` }}
        >
            AP
        </button>,
        <ul className="menu-list avatar-dropdown">
            <div
                className="avatar-edit has-avatar"
                style={{
                    backgroundImage: `url("https://picsum.photos/id/40/100/100")`,
                }}
            >
                <div className="avatar-initials">AP</div>
            </div>
            <div className="profile-email-wrap">
                <p className="profile-email">andrew@example.com</p>
            </div>
            <form method="post" action="/logout" className="sign-out-wrap">
                <button className="btn-ghost" type="submit">
                    Sign Out
                </button>
            </form>
        </ul>,
    ] as const,
    className: 'avatar-menu',
};

export const FixedHeader: Story = {
    args: FIXED_HEADER_PROPS,
    render() {
        // const [dateStart, setDateStart] = useState(
        //     FIXED_HEADER_PROPS.dateStart,
        // );
        // const [dateEnd, setDateEnd] = useState(
        //     FIXED_HEADER_PROPS.dateEnd,
        // );

        return (
            <>
                <header className="mk-header">
                    <nav className="mk-nav a1">
                        <a className="logo" href="/"></a>
                        <a className="btn-text logo-text" href="/">
                            UIKit
                        </a>
                    </nav>
                    <div className="mk-nav center">
                        <h5 className="mk subtitle">
                            Welcome! Join our{' '}
                            <a
                                className="home-link"
                                rel="noreferrer"
                                href="https://discord.gg/dTpXZpQ9Rz"
                                target="_blank"
                            >
                                Discord.
                            </a>
                        </h5>
                    </div>
                    <nav className="mk-nav a2">
                        <a className="btn-text" href="/projects">
                            Projects
                        </a>
                        <Dropdown {...FIXED_HEADER_PROPS} />
                    </nav>
                </header>
                <h1>Lorem ipsum</h1>
            </>
        );
    },
};

export const DisabledDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'disabled-dropdown',
        disabled: true,
        isSearchable: true,
        label: 'Disabled',
        name: 'disabledexample',
        value: '167px',
    },
};

export const OverlappingDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>the carbon in our apple pies</li>
                <li>sea of tranquility tesseract</li>
                <li>encyclopaedia galactica</li>
                <li>billions upon billions</li>
                <li>network of wormholes</li>
                <li>tingling of the spine</li>
                <li>corpus callosum</li>
                <li>finite but unbounded</li>
            </ul>
        ),
        className: 'overlapping-dropdown no-trigger-text',
    },
};

export const OutOfBoundsAtRight: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'out-of-bounds-example position-right',
        isSearchable: true,
        name: 'outofboundsatright',
        placeholder: 'Fill available space',
    },
};

export const OutOfBoundsWithNoDirectionChange: Story = {
    args: {
        children: (
            <ul>
                <li>Antarctica</li>
                <li>Arctic Circle</li>
                <li>North Pole</li>
            </ul>
        ),
        className: 'out-of-bounds-example no-direction-change',
        isSearchable: true,
        name: 'outofboundsatbottomnodirectionchange',
        placeholder: 'Show below even though it goes out of bounds',
    },
};

export const ConstrainHeightToAvoidClipping: Story = {
    args: {
        children: (
            <ul>
                <li>Antarctica</li>
                <li>Arctic Circle</li>
                <li>North Pole</li>
            </ul>
        ),
        className: 'out-of-bounds-example no-direction-change',
        constrainHeightToAvoidClipping: true,
        isSearchable: true,
        name: 'constrainheighttoavoidclipping',
        placeholder: 'Stay below, but scroll if clipping remains',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { CSSValueInput, Dropdown } from "@acusti/uikit-docs";
CSS Lengths Dropdown story ok
const CSSLengthsDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="css-lengths no-trigger-text">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
States Dropdown story ok
const StatesDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="states-dropdown"
    isSearchable
    placeholder="Choose a state…">(<ul>
        <li>Alabama</li>
        <li>Alaska</li>
        <li>Arizona</li>
        <li>Arkansas</li>
        <li>California</li>
        <li>Colorado</li>
        <li>Connecticut</li>
        <li>Delaware</li>
        <li>Florida</li>
        <li>Georgia</li>
        <li>Hawaii</li>
        <li>Idaho</li>
        <li>Illinois</li>
        <li>Indiana</li>
        <li>Iowa</li>
        <li>Kansas</li>
        <li>Kentucky</li>
        <li>Louisiana</li>
        <li>Maine</li>
        <li>Maryland</li>
        <li>Massachusetts</li>
        <li>Michigan</li>
        <li>Minnesota</li>
        <li>Mississippi</li>
        <li>Missouri</li>
        <li>Montana</li>
        <li>Nebraska</li>
        <li>Nevada</li>
        <li>New Hampshire</li>
        <li>New Jersey</li>
        <li>New Mexico</li>
        <li>New York</li>
        <li>North Carolina</li>
        <li>North Dakota</li>
        <li>Ohio</li>
        <li>Oklahoma</li>
        <li>Oregon</li>
        <li>Pennsylvania</li>
        <li>Rhode Island</li>
        <li>South Carolina</li>
        <li>South Dakota</li>
        <li>Tennessee</li>
        <li>Texas</li>
        <li>Utah</li>
        <li>Vermont</li>
        <li>Virginia</li>
        <li>Washington</li>
        <li>West Virginia</li>
        <li>Wisconsin</li>
        <li>Wyoming</li>
    </ul>)</Dropdown>;
Font Weight Dropdown story ok
const FontWeightDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="font-weight"
    isSearchable>(<ul>
        <li data-ukt-value="100">
            <span className="item-title">Font Weight - </span>
            100
        </li>
        <li data-ukt-value="200">
            <span className="item-title">Font Weight - </span>
            200
        </li>
        <li data-ukt-value="300">
            <span className="item-title">Font Weight - </span>
            300
        </li>
        <li data-ukt-value="400">
            <span className="item-title">Font Weight - </span>
            400
        </li>
        <li data-ukt-value="500">
            <span className="item-title">Font Weight - </span>
            500
        </li>
        <li data-ukt-value="600">
            <span className="item-title">Font Weight - </span>
            600
        </li>
        <li data-ukt-value="700">
            <span className="item-title">Font Weight - </span>
            700
        </li>
    </ul>)</Dropdown>;
Show Context Menu On Mount story ok
const ShowContextMenuOnMount = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="open-on-mount-context-menu"
    isOpenOnMount>{[
        'View menu',
        <Fragment>
            <h4 className="heading">View</h4>
            <ul>
                <li data-ukt-item>Open</li>
                <li data-ukt-item>Preview</li>
            </ul>
            <h4 className="heading">Edit</h4>
            <ul>
                <li data-ukt-value="save-item">Save</li>
                <li data-ukt-value="edit-item">Edit</li>
                <li data-ukt-value="delete-item">Delete</li>
            </ul>
        </Fragment>,
    ]}</Dropdown>;
Dropdown With Interactive Contents story ok
const DropdownWithInteractiveContents = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="dropdown-without-items"
    hasItems={false}>{[
        'Open',
        <div>
            <p>
                Try interacting with the controls here. The dropdown should only close
                when you click outside of the entire dropdown or if you hit the escape
                key when focus isn’t in the input controls.
            </p>
            <CSSValueInput
                cssValueType="length"
                label="Width"
                onSubmitValue={() => {}}
                placeholder="100vw"
                unit="vw"
            />
            <CSSValueInput
                cssValueType="length"
                label="Rotation"
                onSubmitValue={() => {}}
                placeholder="0deg"
                step={5}
                unit="deg"
            />
        </div>,
    ]}</Dropdown>;
Searchable With Label story ok
const SearchableWithLabel = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="searchable-with-label"
    isSearchable
    label={(<span
        style={{
            alignItems: 'center',
            display: 'inline-flex',
            gap: '0.25rem',
        }}
    >Font size
                        <ChevronDownIcon />
    </span>)}>(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Searchable And Allow Create story ok
const SearchableAndAllowCreate = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    allowCreate
    className="searchable-and-allow-create"
    isSearchable
    label="Font size">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
CSS Value Input Trigger story ok
const CSSValueInputTrigger = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    allowCreate
    className="css-value-input-trigger"
    hasItems
    label="Background size">{[
        <CSSValueInput
            name="cssinputbackgroundsize"
            onSubmitValue={() => {}}
            placeholder="cover"
            validator={/^(auto|contain|cover)$/}
        />,
        <ul>
            <li>cover</li>
            <li>contain</li>
            <li>auto</li>
            <li>50px</li>
            <li>100px</li>
            <li>200px</li>
            <li>50%</li>
        </ul>,
    ]}</Dropdown>;
Textarea Trigger story ok
const TextareaTrigger = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="textarea-trigger"
    hasItems>{[
        <textarea></textarea>,
        <ul>
            <li>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
                ullamcorper fringilla quam, vel tincidunt nisl mattis vel.
            </li>
            <li>
                Aenean posuere erat sed enim luctus, et accumsan nisl elementum. Nulla
                vel blandit urna, vel accumsan nulla. Nulla varius luctus ex, gravida
                ultrices orci sagittis eu.
            </li>
            <li>
                Quisque vitae magna euismod ligula molestie maximus id et nunc. Nam et
                lacus euismod, porttitor massa vel, sollicitudin ex. Sed ut tellus
                suscipit, faucibus tortor nec, fermentum mi.
            </li>
            <li>
                Nulla sagittis justo non accumsan sagittis. Cras a eros et dolor
                dapibus bibendum lobortis quis ante. Ut eget scelerisque massa.
            </li>
            <li>
                Vestibulum quis dignissim nunc. Mauris fringilla at nulla non lacinia.
                Etiam tristique elit non nisl finibus, fringilla hendrerit ligula
                hendrerit. Fusce eget leo lacinia, eleifend diam non, suscipit purus.
            </li>
        </ul>,
    ]}</Dropdown>;
Checkboxes Dropdown story ok
const CheckboxesDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="checkboxes"
    keepOpenOnSubmit>{[
        'Colors',
        <ul>
            <li>
                <label>
                    <input type="checkbox" /> Red
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Blue
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Yellow
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Cyan
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Orchid
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Slate
                </label>
            </li>
        </ul>,
    ]}</Dropdown>;
Fixed Header story ok
const FixedHeader = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()} />;
Disabled Dropdown story ok
const DisabledDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="disabled-dropdown"
    disabled
    isSearchable
    label="Disabled"
    name="disabledexample"
    value="167px">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Overlapping Dropdown story ok
const OverlappingDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="overlapping-dropdown no-trigger-text">(<ul>
        <li>the carbon in our apple pies</li>
        <li>sea of tranquility tesseract</li>
        <li>encyclopaedia galactica</li>
        <li>billions upon billions</li>
        <li>network of wormholes</li>
        <li>tingling of the spine</li>
        <li>corpus callosum</li>
        <li>finite but unbounded</li>
    </ul>)</Dropdown>;
Out Of Bounds At Right story ok
const OutOfBoundsAtRight = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example position-right"
    isSearchable
    name="outofboundsatright"
    placeholder="Fill available space">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Out Of Bounds With No Direction Change story ok
const OutOfBoundsWithNoDirectionChange = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example no-direction-change"
    isSearchable
    name="outofboundsatbottomnodirectionchange"
    placeholder="Show below even though it goes out of bounds">(<ul>
        <li>Antarctica</li>
        <li>Arctic Circle</li>
        <li>North Pole</li>
    </ul>)</Dropdown>;
Constrain Height To Avoid Clipping story ok
const ConstrainHeightToAvoidClipping = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example no-direction-change"
    constrainHeightToAvoidClipping
    isSearchable
    name="constrainheighttoavoidclipping"
    placeholder="Stay below, but scroll if clipping remains">(<ul>
        <li>Antarctica</li>
        <li>Arctic Circle</li>
        <li>North Pole</li>
    </ul>)</Dropdown>;

Dropdown

uikit-hooks-useisoutofbounds · ./stories/useIsOutOfBounds.stories.tsx
Prop type error
No component file found for the "Dropdown" component.
   7 | import type { Meta, StoryObj } from '@storybook/react-vite';
   8 |
>  9 | const meta: Meta<typeof useIsOutOfBounds> = {
     | ^
  10 |     argTypes: {
  11 |         element: {
  12 |             description:

./stories/useIsOutOfBounds.stories.tsx:
import Dropdown from '../../dropdown/src/Dropdown.js';
import useIsOutOfBounds from '../../use-is-out-of-bounds/src/useIsOutOfBounds.js';

import './Dropdown.css';
import './useIsOutOfBounds.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const meta: Meta<typeof useIsOutOfBounds> = {
    argTypes: {
        element: {
            description:
                'The HTMLElement that will be checked to see if it is out of bounds and in what direction. Can be null or undefined.',
            table: {
                type: { summary: 'object' },
            },
        },
    },
    component: Dropdown,
    parameters: {
        controls: { exclude: /.*/g },
        docs: {
            description: {
                component: `\`useIsOutOfBounds\` is a React hook that returns an object indicating if the
current component is out of the bounds of its nearest ancestor that doesn’t have overflow: visible. In other words,
it provides collision detection between an element and its bounds. The return value is

\`\`\`
type OutOfBounds = {
    bottom: boolean;
    hasLayout: boolean;
    left: boolean;
    maxHeight: null | number;
    maxWidth: null | number;
    right: boolean;
    top: boolean;
};
\`\`\`

It is used in @acusti/dropdown to automatically position the dropdown in the direction
where there is room for it to render, so this story uses \`<Dropdown>\` to illustrate that behavior.`,
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Hooks/useIsOutOfBounds',
};

export default meta;

type Story = StoryObj<typeof Dropdown>;

const list = (
    <ul>
        <li>Brunei Darussalam</li>
        <li>Cambodia</li>
        <li>Indonesia</li>
        <li>Laos</li>
        <li>Malaysia</li>
        <li>Myanmar (Burma)</li>
        <li>Philippines</li>
        <li>Singapore</li>
        <li>Thailand</li>
        <li>Timor-Leste (East Timor)</li>
        <li>Vietnam</li>
    </ul>
);

export const NotOutOfBounds: Story = {
    args: {
        children: list,
        className: 'not-out-of-bounds-example',
        isSearchable: true,
        name: 'notoutofbounds',
        placeholder: 'Default behavior',
    },
};

export const OutOfBoundsAtBottom: Story = {
    args: {
        children: list,
        className: 'out-of-bounds-example',
        isSearchable: true,
        name: 'outofboundsatbottom',
        placeholder: 'Show above',
    },
};

export const OutOfBoundsAtRight: Story = {
    args: {
        children: list,
        className: 'out-of-bounds-example position-right',
        isSearchable: true,
        name: 'outofboundsatright',
        placeholder: 'Show above & to the left',
    },
};

export const OutOfBoundsTopAndBottom: Story = {
    args: {
        children: (
            <ul>
                <li>Algeria</li>
                <li>Angola</li>
                <li>Benin</li>
                <li>Botswana</li>
                <li>Burkina Faso</li>
                <li>Burundi</li>
                <li>Cabo Verde</li>
                <li>Cameroon</li>
                <li>Central African Republic</li>
                <li>Chad</li>
                <li>Comoros</li>
                <li>Congo, Democratic Republic of the</li>
                <li>Congo, Republic of the</li>
                <li>Cote d’Ivoire</li>
                <li>Djibouti</li>
                <li>Egypt</li>
                <li>Equatorial Guinea</li>
                <li>Eritrea</li>
                <li>Eswatini</li>
                <li>Ethiopia</li>
                <li>Gabon</li>
                <li>Gambia</li>
                <li>Ghana</li>
                <li>Guinea</li>
                <li>Guinea-Bissau</li>
                <li>Kenya</li>
                <li>Lesotho</li>
                <li>Liberia</li>
                <li>Libya</li>
                <li>Madagascar</li>
                <li>Malawi</li>
                <li>Mali</li>
                <li>Mauritania</li>
                <li>Mauritius</li>
                <li>Morocco</li>
                <li>Mozambique</li>
                <li>Namibia</li>
                <li>Niger</li>
                <li>Nigeria</li>
                <li>Rwanda</li>
                <li>Sao Tome and Principe</li>
                <li>Senegal</li>
                <li>Seychelles</li>
                <li>Sierra Leone</li>
                <li>Somalia</li>
                <li>South Africa</li>
                <li>South Sudan</li>
                <li>Sudan</li>
                <li>Tanzania</li>
                <li>Togo</li>
                <li>Tunisia</li>
                <li>Uganda</li>
                <li>Zambia</li>
                <li>Zimbabwe</li>
            </ul>
        ),
        className: 'out-of-bounds-top-and-bottom-example',
        isSearchable: true,
        name: 'outofboundstopandbottom',
        placeholder: 'long list',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { Dropdown } from "@acusti/uikit-docs";
Not Out Of Bounds story ok
const NotOutOfBounds = () => <Dropdown
    className="not-out-of-bounds-example"
    isSearchable
    name="notoutofbounds"
    placeholder="Default behavior">{list}</Dropdown>;
Out Of Bounds At Bottom story ok
const OutOfBoundsAtBottom = () => <Dropdown
    className="out-of-bounds-example"
    isSearchable
    name="outofboundsatbottom"
    placeholder="Show above">{list}</Dropdown>;
Out Of Bounds At Right story ok
const OutOfBoundsAtRight = () => <Dropdown
    className="out-of-bounds-example position-right"
    isSearchable
    name="outofboundsatright"
    placeholder="Show above & to the left">{list}</Dropdown>;
Out Of Bounds Top And Bottom story ok
const OutOfBoundsTopAndBottom = () => <Dropdown
    className="out-of-bounds-top-and-bottom-example"
    isSearchable
    name="outofboundstopandbottom"
    placeholder="long list">(<ul>
        <li>Algeria</li>
        <li>Angola</li>
        <li>Benin</li>
        <li>Botswana</li>
        <li>Burkina Faso</li>
        <li>Burundi</li>
        <li>Cabo Verde</li>
        <li>Cameroon</li>
        <li>Central African Republic</li>
        <li>Chad</li>
        <li>Comoros</li>
        <li>Congo, Democratic Republic of the</li>
        <li>Congo, Republic of the</li>
        <li>Cote d’Ivoire</li>
        <li>Djibouti</li>
        <li>Egypt</li>
        <li>Equatorial Guinea</li>
        <li>Eritrea</li>
        <li>Eswatini</li>
        <li>Ethiopia</li>
        <li>Gabon</li>
        <li>Gambia</li>
        <li>Ghana</li>
        <li>Guinea</li>
        <li>Guinea-Bissau</li>
        <li>Kenya</li>
        <li>Lesotho</li>
        <li>Liberia</li>
        <li>Libya</li>
        <li>Madagascar</li>
        <li>Malawi</li>
        <li>Mali</li>
        <li>Mauritania</li>
        <li>Mauritius</li>
        <li>Morocco</li>
        <li>Mozambique</li>
        <li>Namibia</li>
        <li>Niger</li>
        <li>Nigeria</li>
        <li>Rwanda</li>
        <li>Sao Tome and Principe</li>
        <li>Senegal</li>
        <li>Seychelles</li>
        <li>Sierra Leone</li>
        <li>Somalia</li>
        <li>South Africa</li>
        <li>South Sudan</li>
        <li>Sudan</li>
        <li>Tanzania</li>
        <li>Togo</li>
        <li>Tunisia</li>
        <li>Uganda</li>
        <li>Zambia</li>
        <li>Zimbabwe</li>
    </ul>)</Dropdown>;

InputText

uikit-controls-inputtext · ./stories/InputText.stories.tsx
Prop type error
No component file found for the "InputText" component.
   7 | import './InputText.css';
   8 |
>  9 | const meta: Meta<typeof InputText> = {
     | ^
  10 |     component: InputText,
  11 |     parameters: {
  12 |         docs: {

./stories/InputText.stories.tsx:
import type { Meta, StoryObj } from '@storybook/react-vite';
import { type FormEvent, useState } from 'react';
import { fn } from 'storybook/test';

import InputText from '../../input-text/src/InputText.js';

import './InputText.css';

const meta: Meta<typeof InputText> = {
    component: InputText,
    parameters: {
        docs: {
            description: {
                component:
                    '`InputText` is a React component that renders a textual input (`type: "text"|"email"|"number"|"password"|"search"|"tel"|"url"`) that is uncontrolled, but whose value is overwritten whenever `props.initialValue` changes. Also, if `props.selectTextOnFocus` is true, it selects the entire contents of the input whenever the input is focused. And it supports multiline inputs (rendered as a `<textarea>`) that automatically resize vertically to fit their content.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/InputText',
};

export default meta;

type Story = StoryObj<typeof InputText>;

export const EmptyInput: Story = {
    args: {
        className: 'input-text',
        name: 'empty',
        // NOTE spies are a workaround for a bug related to implicit arg detection
        onBlur: fn(),
        onChange: fn(),
        onChangeValue: fn(),
        onFocus: fn(),
        onKeyDown: fn(),
        onKeyUp: fn(),
        placeholder: 'enter text here…',
    },
};

export const InputWithInitialValue: Story = {
    args: {
        className: 'input-text',
        initialValue: 'Bolivia',
        placeholder: 'enter country name',
    },
};

export const InputWithInitialValueAndSelectTextOnFocus: Story = {
    args: {
        className: 'input-text',
        initialValue: 'Bolivia',
        name: 'country',
        placeholder: 'enter country name (selectTextOnFocus)',
        selectTextOnFocus: true,
    },
};

export const MultiLineInputWithInitialValueAndSelectTextOnFocus: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'The Black Hawk War, or, How to Demolish an Entire Civilization and Still Feel Good About Yourself in the Morning, or, We Apologize for the Inconvenience but You’re Going to Have to Leave Now, or, “I have fought the Big Knives and will continue to fight them until they are off our lands!”',
        maxHeight: 600,
        multiLine: true,
        name: 'multi-line-input',
        placeholder: 'enter text of any length',
        selectTextOnFocus: true,
    },
};

const SUBMIT_ON_ENTER_PROPS = {
    className: 'multi-line-input-text',
    maxHeight: 600,
    multiLine: true,
    name: 'multi-line-submit-on-enter-input',
    placeholder: 'enter text of any length',
    submitOnEnter: true,
};

const formatDate = new Intl.DateTimeFormat(undefined, {
    timeStyle: 'medium',
}).format;

export const MultiLineInputWithSubmitOnEnter: Story = {
    args: SUBMIT_ON_ENTER_PROPS,
    render() {
        const [lastSubmitDate, setLastSubmitDate] = useState<Date | null>(null);
        const lastSubmit = lastSubmitDate ? formatDate(lastSubmitDate) : 'never';

        return (
            <form
                onSubmit={(event: FormEvent<HTMLFormElement>) => {
                    event.preventDefault();
                    setLastSubmitDate(new Date());
                }}
            >
                <InputText {...SUBMIT_ON_ENTER_PROPS} />
                <pre>Last submitted: {lastSubmit}</pre>
            </form>
        );
    },
};

export const MultiLineInputWithSubmitOnEnterNoForm: Story = {
    args: {
        ...SUBMIT_ON_ENTER_PROPS,
        name: `${SUBMIT_ON_ENTER_PROPS.name}-no-form`,
    },
};

function ChatLikeInputDemo() {
    const [message, setMessage] = useState('');
    const [messages, setMessages] = useState<Array<string>>([]);

    return (
        <form
            onSubmit={(event) => {
                event.preventDefault();
                if (!message.trim()) return;
                setMessages((previousMessages) => [...previousMessages, message.trim()]);
                setMessage('');
            }}
        >
            <pre>{messages.join('\n') || 'No messages yet'}</pre>
            <InputText
                className="input-text"
                initialValue={message}
                keepFocusOnSubmit
                onChangeValue={setMessage}
                placeholder="Type then press Enter"
                submitOnEnter
            />
        </form>
    );
}

export const ChatLikeInputWithSubmitOnEnter: Story = {
    args: {
        className: 'input-text',
        keepFocusOnSubmit: true,
        placeholder: 'Type then press Enter',
        submitOnEnter: true,
    },
    render() {
        return <ChatLikeInputDemo />;
    },
};

const DOUBLE_CLICK_TO_EDIT_PROPS = {
    className: 'input-text-double-click-to-edit',
    doubleClickToEdit: true,
    initialValue: 'Lorem ipsum dolor sit amet',
    name: 'double-click-to-edit-input',
};

export const InputWithDoubleClickToEdit: Story = {
    args: DOUBLE_CLICK_TO_EDIT_PROPS,
};

const DISCARD_ON_ESCAPE_PROPS = {
    className: 'input-text',
    discardOnEscape: true,
    initialValue: 'Lorem ipsum',
    name: 'discard-on-escape-input',
};

export const InputWithDiscardOnEscape: Story = {
    args: DISCARD_ON_ESCAPE_PROPS,
};

export const InputWithDoubleClickToEditAndDiscardOnEscape: Story = {
    args: {
        ...DISCARD_ON_ESCAPE_PROPS,
        ...DOUBLE_CLICK_TO_EDIT_PROPS,
        name: 'double-click-to-edit-and-discard-on-escape-input',
    },
};

export const InputWithAutoFocus: Story = {
    args: {
        autoFocus: true,
        name: 'autofocus-input',
    },
};

export const MultiLineInputWithMinHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'This textarea has a minHeight of 50px.\n\nTry deleting this text to see that the textarea does not shrink below the minimum height.',
        minHeight: 50,
        multiLine: true,
        name: 'multi-line-min-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithMaxHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'This textarea has a maxHeight of 150px.\n\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10',
        maxHeight: 150,
        multiLine: true,
        name: 'multi-line-max-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithMinHeightAndMaxHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue: 'This textarea has minHeight of 100px and maxHeight of 200px.',
        maxHeight: 200,
        minHeight: 100,
        multiLine: true,
        name: 'multi-line-min-max-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithCSSTransition: Story = {
    args: {
        className: 'multi-line-input-css-transition',
        multiLine: true,
        name: 'multi-line-input-css-transition',
        placeholder: 'Write a quick note here',
        rows: 4,
    },
};

const MULTI_LINE_INPUT_IN_POPOVER_PROPS = {
    className: 'multi-line-input-text',
    initialValue:
        'This multi-line input should resize to fit its contents when the popover opens even though it initializes with display: none as a result of being inside a hidden popover element so it doesn’t have any dimensions when the component initially renders.',
    multiLine: true,
    name: 'multi-line-input-in-popover',
    selectTextOnFocus: true,
};

export const MultiLineInputInPopover: Story = {
    args: MULTI_LINE_INPUT_IN_POPOVER_PROPS,
    render() {
        return (
            <>
                <button popoverTarget="multi-line-input-popover">Open Popover</button>
                <div id="multi-line-input-popover" popover="auto">
                    <InputText {...MULTI_LINE_INPUT_IN_POPOVER_PROPS} />
                </div>
            </>
        );
    },
};

const MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS = {
    autoFocus: true,
    initialValue: 'This multi-line input should be focused when the popover opens',
    multiLine: true,
    name: 'multi-line-input-with-autofocus-in-popover',
    selectTextOnFocus: true,
};

export const MultiLineInputWithAutoFocusInPopover: Story = {
    args: MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS,
    render() {
        return (
            <>
                <button popoverTarget="multi-line-input-with-autofocus-popover">
                    Open Popover
                </button>
                <div id="multi-line-input-with-autofocus-popover" popover="auto">
                    <InputText {...MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS} />
                </div>
            </>
        );
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { InputText } from "@acusti/uikit-docs";
Empty Input story ok
const EmptyInput = () => <InputText
    className="input-text"
    name="empty"
    onBlur={fn()}
    onChange={fn()}
    onChangeValue={fn()}
    onFocus={fn()}
    onKeyDown={fn()}
    onKeyUp={fn()}
    placeholder="enter text here…" />;
Input With Initial Value story ok
const InputWithInitialValue = () => <InputText
    className="input-text"
    initialValue="Bolivia"
    placeholder="enter country name" />;
Input With Initial Value And Select Text On Focus story ok
const InputWithInitialValueAndSelectTextOnFocus = () => <InputText
    className="input-text"
    initialValue="Bolivia"
    name="country"
    placeholder="enter country name (selectTextOnFocus)"
    selectTextOnFocus />;
Multi Line Input With Initial Value And Select Text On Focus story ok
const MultiLineInputWithInitialValueAndSelectTextOnFocus = () => <InputText
    className="multi-line-input-text"
    initialValue="The Black Hawk War, or, How to Demolish an Entire Civilization and Still Feel Good About Yourself in the Morning, or, We Apologize for the Inconvenience but You’re Going to Have to Leave Now, or, “I have fought the Big Knives and will continue to fight them until they are off our lands!”"
    maxHeight={600}
    multiLine
    name="multi-line-input"
    placeholder="enter text of any length"
    selectTextOnFocus />;
Multi Line Input With Submit On Enter story ok
const MultiLineInputWithSubmitOnEnter = () => <InputText />;
Multi Line Input With Submit On Enter No Form story ok
const MultiLineInputWithSubmitOnEnterNoForm = () => <InputText name={`${SUBMIT_ON_ENTER_PROPS.name}-no-form`} />;
Chat Like Input With Submit On Enter story ok
const ChatLikeInputWithSubmitOnEnter = () => <InputText
    className="input-text"
    keepFocusOnSubmit
    placeholder="Type then press Enter"
    submitOnEnter />;
Input With Double Click To Edit story ok
const InputWithDoubleClickToEdit = () => <InputText />;
Input With Discard On Escape story ok
const InputWithDiscardOnEscape = () => <InputText />;
Input With Double Click To Edit And Discard On Escape story ok
const InputWithDoubleClickToEditAndDiscardOnEscape = () => <InputText name="double-click-to-edit-and-discard-on-escape-input" />;
Input With Auto Focus story ok
const InputWithAutoFocus = () => <InputText autoFocus name="autofocus-input" />;
Multi Line Input With Min Height story ok
const MultiLineInputWithMinHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has a minHeight of 50px.\n\nTry deleting this text to see that the textarea does not shrink below the minimum height."
    minHeight={50}
    multiLine
    name="multi-line-min-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With Max Height story ok
const MultiLineInputWithMaxHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has a maxHeight of 150px.\n\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10"
    maxHeight={150}
    multiLine
    name="multi-line-max-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With Min Height And Max Height story ok
const MultiLineInputWithMinHeightAndMaxHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has minHeight of 100px and maxHeight of 200px."
    maxHeight={200}
    minHeight={100}
    multiLine
    name="multi-line-min-max-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With CSS Transition story ok
const MultiLineInputWithCSSTransition = () => <InputText
    className="multi-line-input-css-transition"
    multiLine
    name="multi-line-input-css-transition"
    placeholder="Write a quick note here"
    rows={4} />;
Multi Line Input In Popover story ok
const MultiLineInputInPopover = () => <InputText />;
Multi Line Input With Auto Focus In Popover story ok
const MultiLineInputWithAutoFocusInPopover = () => <InputText />;

MonthCalendar

uikit-controls-datepicker-monthcalendar · ./stories/MonthCalendar.stories.ts
Prop type error
File: /Users/andrew/Projects/uikit/packages/date-picker/src/index.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
export { default as DatePicker } from './DatePicker.js';
export { default as MonthCalendar } from './MonthCalendar.js';
export * from './utils.js';


File: /Users/andrew/Projects/uikit/packages/date-picker/src/utils.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
// The following utils work on a “month” as a unique numerical value
// representing the number of months since the unix epoch (jan 1970)
const START_YEAR = 1970;
const MONTH_NAMES = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
];

const getYearFromDate = (date: Date, asUTC?: boolean) =>
    (asUTC ? date.getUTCFullYear() : date.getFullYear()) - START_YEAR;

export const getMonthFromDate = (date: Date, asUTC?: boolean) => {
    const yearAsMonths = getYearFromDate(date, asUTC) * 12;
    return yearAsMonths + (asUTC ? date.getUTCMonth() : date.getMonth());
};

export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;

export const getMonthNameFromMonth = (month: number): string => {
    let index = month % 12;
    if (Number.isNaN(index)) return '';
    if (index < 0) index = 12 + index;
    return MONTH_NAMES[index];
};

export const getMonthAbbreviationFromMonth = (month: number) => {
    const monthName = getMonthNameFromMonth(month);
    if (monthName === 'September') return 'Sept';
    return monthName.substring(0, 3);
};

export const getDateFromMonthAndDay = (month: number, day: number, asUTC?: boolean) => {
    const monthIn12 = month < 0 ? (12 - Math.abs(month % 12)) % 12 : month % 12;
    const year = getYearFromMonth(month);
    return asUTC
        ? new Date(Date.UTC(year, monthIn12, day))
        : new Date(year, monthIn12, day);
};

export const getLastDateFromMonth = (month: number, asUTC?: boolean) => {
    // day 0 of the next month is the last day of the current month
    return getDateFromMonthAndDay(month + 1, 0, asUTC);
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { MonthCalendar } from "@acusti/date-picker";
This Months Calendar story ok
const ThisMonthsCalendar = () => <MonthCalendar className="month-calendar-story" month={getMonthFromDate(new Date())} />;
February 1985 Calendar story ok
const February1985Calendar = () => <MonthCalendar className="february-month-calendar-story" month={181} />;
Date Range Diwali Calendar story ok
const DateRangeDiwaliCalendar = () => <MonthCalendar
    className="date-range-month-calendar-story"
    dateEnd={new Date(2023, 10, 14)}
    dateStart={new Date(2023, 10, 9)}
    month={getMonthFromDate(new Date(2023, 10, 1))} />;

CSSValueInput

uikit-controls-cssvalueinput · ./stories/CSSValueInput.stories.tsx
Prop type error
No component file found for the "CSSValueInput" component.
   6 | import type { Meta, StoryObj } from '@storybook/react-vite';
   7 |
>  8 | const meta: Meta<typeof CSSValueInput> = {
     | ^
   9 |     component: CSSValueInput,
  10 |     parameters: {
  11 |         docs: {

./stories/CSSValueInput.stories.tsx:
import CSSValueInput from '../../css-value-input/src/CSSValueInput.js';

import './CSSValueInput.css';
import './InputText.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const meta: Meta<typeof CSSValueInput> = {
    component: CSSValueInput,
    parameters: {
        docs: {
            description: {
                component:
                    '`CSSValueInput` is a React component that renders a text input that can take and update a CSS value of a particular type with a default unit. The input’s behavior is similar to those in design applications such as Adobe Illustrator or XD.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/CSSValueInput',
};

export default meta;

type Story = StoryObj<typeof CSSValueInput>;

export const Length: Story = {
    args: {
        className: 'my-special-input',
        cssValueType: 'length',
        label: 'Font size',
        name: 'fontsize',
        placeholder: '1rem',
        tabIndex: 1,
        unit: 'rem',
        validator:
            /^(xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|inherit)$/,
        value: '24px',
    },
};

export const Time: Story = {
    args: {
        className: 'my-panel-input',
        cssValueType: 'time',
        label: 'Duration',
        max: 20,
        min: 0,
        name: 'duration',
        placeholder: '0.25s',
        step: 0.1,
        unit: 's',
    },
};

export const Angle: Story = {
    args: {
        className: 'flex-item-example',
        cssValueType: 'angle',
        icon: (
            <svg
                width="100px"
                height="100px"
                viewBox="0 0 100 100"
                version="1.1"
                xmlns="http://www.w3.org/2000/svg"
            >
                <g stroke="none" strokeWidth="1" fill="none">
                    <g transform="translate(2, 2)" stroke="#222F3E" strokeWidth="4">
                        <path
                            d="M56.5106952,10.5464071 C60.8135865,11.5200327 64.8423906,13.2161538 68.4628809,15.5005439 L76.8618891,8.97963811 L87.0203619,19.1381109 L80.4994561,27.5371191 C82.7838462,31.1576094 84.4799673,35.1864135 85.4535929,39.4893048 L96,40.816875 L96,55.183125 L85.4535929,56.5106952 C84.4799673,60.8135865 82.7838462,64.8423906 80.4994561,68.4628809 L87.0203619,76.8618891 L76.8618891,87.0203619 L68.4628809,80.4994561 C64.8423906,82.7838462 60.8135865,84.4799673 56.5106952,85.4535929 L55.183125,96 L40.816875,96 L39.4893048,85.4535929 C35.1864135,84.4799673 31.1576094,82.7838462 27.5371191,80.4994561 L19.1381109,87.0203619 L8.97963811,76.8618891 L15.5005439,68.4628809 C13.2161538,64.8423906 11.5200327,60.8135865 10.5464071,56.5106952 L0,55.183125 L0,40.816875 L10.5464071,39.4893048 C11.5200327,35.1864135 13.2161538,31.1576094 15.5005439,27.5371191 L8.97963811,19.1381109 L19.1381109,8.97963811 L27.5371191,15.5005439 C31.1576094,13.2161538 35.1864135,11.5200327 39.4893048,10.5464071 L40.816875,0 L55.183125,0 L56.5106952,10.5464071 Z"
                            id="Layer-1"
                        ></path>
                        <circle cx="48" cy="48" r="14.4"></circle>
                    </g>
                </g>
            </svg>
        ),
        label: 'Rotate Z',
        name: 'rotatez',
        placeholder: '0deg',
        step: 45,
        unit: 'deg',
        value: '90deg',
    },
};

export const Percent: Story = {
    args: {
        cssValueType: 'percent',
        label: 'Width',
        min: 0,
        name: 'width',
        placeholder: '100%',
        step: 10,
        unit: '%',
        value: '30%',
    },
};

export const LabelLess: Story = {
    args: {
        className: 'my-special-input',
        cssValueType: 'length',
        name: 'labelless',
        placeholder: '1rem',
        title: 'No label',
        unit: 'rem',
        value: '24px',
    },
};

export const CustomGetValueAsNumber: Story = {
    args: {
        className: 'letter-spacing',
        getValueAsNumber: (value: number | string) => {
            if (typeof value === 'number') return value;
            // “normal” for letter-spacing is effectively equivalent to 0
            if (typeof value === 'string' && value.toLowerCase() === 'normal') {
                return 0;
            }
            return parseFloat(value);
        },
        label: 'Letter spacing',
        name: 'letterspacing',
        placeholder: 'normal',
        tabIndex: 2,
    },
};

export const BackgroundSize: Story = {
    args: {
        className: 'background-size',
        label: 'Background Size',
        name: 'backgroundsize',
        unit: '%',
        validator: /^(auto|contain|cover)$/,
        value: 'cover',
    },
};

export const ZIndex: Story = {
    args: {
        cssValueType: 'integer',
        label: 'z-index',
        name: 'zindex',
        value: '0',
    },
};

export const NumberValue: Story = {
    args: {
        cssValueType: 'integer',
        label: 'opacity',
        name: 'opacity',
        value: '0',
    },
};

export const LineHeight: Story = {
    args: {
        cssValueType: 'length',
        label: 'line height',
        name: 'line-height',
        step: 0.1,
        unit: '',
        value: '1.4',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { CSSValueInput } from "@acusti/uikit-docs";
Length story ok
const Length = () => <CSSValueInput
    className="my-special-input"
    cssValueType="length"
    label="Font size"
    name="fontsize"
    placeholder="1rem"
    tabIndex={1}
    unit="rem"
    validator={/^(xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|inherit)$/}
    value="24px" />;
Time story ok
const Time = () => <CSSValueInput
    className="my-panel-input"
    cssValueType="time"
    label="Duration"
    max={20}
    min={0}
    name="duration"
    placeholder="0.25s"
    step={0.1}
    unit="s" />;
Angle story ok
const Angle = () => <CSSValueInput
    className="flex-item-example"
    cssValueType="angle"
    icon={(<svg
        width="100px"
        height="100px"
        viewBox="0 0 100 100"
        version="1.1"
        xmlns="http://www.w3.org/2000/svg"
    >
        <g stroke="none" strokeWidth="1" fill="none">
            <g transform="translate(2, 2)" stroke="#222F3E" strokeWidth="4">
                <path
                    d="M56.5106952,10.5464071 C60.8135865,11.5200327 64.8423906,13.2161538 68.4628809,15.5005439 L76.8618891,8.97963811 L87.0203619,19.1381109 L80.4994561,27.5371191 C82.7838462,31.1576094 84.4799673,35.1864135 85.4535929,39.4893048 L96,40.816875 L96,55.183125 L85.4535929,56.5106952 C84.4799673,60.8135865 82.7838462,64.8423906 80.4994561,68.4628809 L87.0203619,76.8618891 L76.8618891,87.0203619 L68.4628809,80.4994561 C64.8423906,82.7838462 60.8135865,84.4799673 56.5106952,85.4535929 L55.183125,96 L40.816875,96 L39.4893048,85.4535929 C35.1864135,84.4799673 31.1576094,82.7838462 27.5371191,80.4994561 L19.1381109,87.0203619 L8.97963811,76.8618891 L15.5005439,68.4628809 C13.2161538,64.8423906 11.5200327,60.8135865 10.5464071,56.5106952 L0,55.183125 L0,40.816875 L10.5464071,39.4893048 C11.5200327,35.1864135 13.2161538,31.1576094 15.5005439,27.5371191 L8.97963811,19.1381109 L19.1381109,8.97963811 L27.5371191,15.5005439 C31.1576094,13.2161538 35.1864135,11.5200327 39.4893048,10.5464071 L40.816875,0 L55.183125,0 L56.5106952,10.5464071 Z"
                    id="Layer-1"
                ></path>
                <circle cx="48" cy="48" r="14.4"></circle>
            </g>
        </g>
    </svg>)}
    label="Rotate Z"
    name="rotatez"
    placeholder="0deg"
    step={45}
    unit="deg"
    value="90deg" />;
Percent story ok
const Percent = () => <CSSValueInput
    cssValueType="percent"
    label="Width"
    min={0}
    name="width"
    placeholder="100%"
    step={10}
    unit="%"
    value="30%" />;
Label Less story ok
const LabelLess = () => <CSSValueInput
    className="my-special-input"
    cssValueType="length"
    name="labelless"
    placeholder="1rem"
    title="No label"
    unit="rem"
    value="24px" />;
Custom Get Value As Number story ok
const CustomGetValueAsNumber = () => <CSSValueInput
    className="letter-spacing"
    getValueAsNumber={(value: number | string) => {
        if (typeof value === 'number') return value;
        // “normal” for letter-spacing is effectively equivalent to 0
        if (typeof value === 'string' && value.toLowerCase() === 'normal') {
            return 0;
        }
        return parseFloat(value);
    }}
    label="Letter spacing"
    name="letterspacing"
    placeholder="normal"
    tabIndex={2} />;
Background Size story ok
const BackgroundSize = () => <CSSValueInput
    className="background-size"
    label="Background Size"
    name="backgroundsize"
    unit="%"
    validator={/^(auto|contain|cover)$/}
    value="cover" />;
Z Index story ok
const ZIndex = () => <CSSValueInput cssValueType="integer" label="z-index" name="zindex" value="0" />;
Number Value story ok
const NumberValue = () => <CSSValueInput cssValueType="integer" label="opacity" name="opacity" value="0" />;
Line Height story ok
const LineHeight = () => <CSSValueInput
    cssValueType="length"
    label="line height"
    name="line-height"
    step={0.1}
    unit=""
    value="1.4" />;

Demo

uikit-hooks-usekeyboardevents · ./stories/useKeyboardEvents.stories.tsx
Prop type error
No component file found for the "Demo" component.
  39 | }
  40 |
> 41 | const meta: Meta<typeof Demo> = {
     | ^
  42 |     argTypes: {
  43 |         ignoreUsedKeyboardEvents: {
  44 |             control: 'boolean',

./stories/useKeyboardEvents.stories.tsx:
import * as React from 'react';

import useKeyboardEvents from '../../use-keyboard-events/src/useKeyboardEvents.js';

import './useKeyboardEvents.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const { Fragment, useState } = React;

function Demo() {
    const [event, setEvent] = useState<KeyboardEvent | null>(null);

    useKeyboardEvents({ onKeyDown: setEvent, onKeyUp: setEvent });

    const modifiers = [
        event?.shiftKey ? '⇧ ' : '',
        event?.ctrlKey ? '⌃ ' : '',
        event?.altKey ? '⌥ ' : '',
        event?.metaKey ? '⌘ ' : '',
    ].join('');

    return (
        <Fragment>
            <p className="keyboard-event-row">
                <span className="label">Event:</span>
                <input className="code" disabled value={event?.type} />
            </p>
            <p className="keyboard-event-row">
                <span className="label">Key:</span>
                <input className="code" disabled value={event?.key} />
            </p>
            <p className="keyboard-event-row">
                <span className="label">Modifiers:</span>
                <input disabled value={modifiers} />
            </p>
        </Fragment>
    );
}

const meta: Meta<typeof Demo> = {
    argTypes: {
        ignoreUsedKeyboardEvents: {
            control: 'boolean',
            description:
                'If the prop is true, the keyboard event target is an input, textarea, or contenteditable element, and the keyboard event is usable by the element, your keyboard event listeners will not be triggered',
            table: {
                defaultValue: { summary: true },
                type: { summary: 'boolean' },
            },
        },
        priority: {
            control: 'number',
            description:
                'Priority defines what order handlers should be invoked and defaults to 0. It can be any number between -50 (lowest priority) and 50 (highest priority).',
            table: {
                defaultValue: { summary: 0 },
                type: { summary: 'number' },
            },
        },
        onKeyDown: {
            action: 'onKeyDown',
            description: 'A function that will be called when a key is pressed down',
            table: {
                type: { summary: 'function' },
            },
        },
        onKeyPress: {
            action: 'onKeyPress',
            description:
                'A function that will be called when a key that produces a character value is pressed down',
            table: {
                type: { summary: 'function' },
            },
        },
        onKeyUp: {
            action: 'onKeyUp',
            description: 'A function that will be called when a key is released',
            table: {
                type: { summary: 'function' },
            },
        },
    },
    component: Demo,
    parameters: {
        docs: {
            description: {
                component:
                    '`useKeyboardEvents` is a React hook that uses keyboard event listeners on the document to trigger the onKey(Down|Press|Up) functions in order to ensure that all key events are captured regardless of whether there is currently a focused element in the DOM (i.e. `document.activeElement` is set). This solves the problem where keyboard event handlers attached via React’s `onKey(Down|Press|Up)` props miss any keyboard events that occur when the target element and its descendants aren’t focused.',
            },
        },
    },
    // https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Hooks/useKeyboardEvents',
};

export default meta;

type Story = StoryObj<typeof Demo>;

export const UseKeyboardEvents: Story = {
    args: {},
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Use Keyboard Events story error
Could not generate snippet without component name.
Imports
import { Demo } from "@acusti/uikit-docs";

Dropdown

uikit-controls-dropdown · ./stories/Dropdown.stories.tsx
Prop type error
No component file found for the "Dropdown" component.
  35 | }
  36 |
> 37 | const meta: Meta<typeof Dropdown> = {
     | ^
  38 |     args: {
  39 |         onClick: fn(),
  40 |         onClose: fn(),

./stories/Dropdown.stories.tsx:
import { fn } from 'storybook/test';
import * as React from 'react';

import CSSValueInput from '../../css-value-input/src/CSSValueInput.js';
import Dropdown from '../../dropdown/src/Dropdown.js';

import './CSSValueInput.css';
import './Dropdown.css';
import './InputText.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const { Fragment } = React;

function ChevronDownIcon(props: React.SVGProps<SVGSVGElement>) {
    return (
        <svg
            aria-hidden="true"
            fill="none"
            focusable="false"
            height="12"
            viewBox="0 0 12 12"
            width="12"
            {...props}
        >
            <path
                d="M2.5 4.5 6 8l3.5-3.5"
                stroke="currentColor"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="1.5"
            />
        </svg>
    );
}

const meta: Meta<typeof Dropdown> = {
    args: {
        onClick: fn(),
        onClose: fn(),
        onMouseDown: fn(),
        onMouseUp: fn(),
        onOpen: fn(),
        onSubmitItem: fn(),
    },
    component: Dropdown,
    parameters: {
        docs: {
            description: {
                component:
                    '`Dropdown` is a React component that renders a menu-like UI with a trigger that the user clicks to disclose a dropdown positioned below the trigger. The body of the dropdown can include any DOM, and many dropdowns can be combined to form a multi-item menu, like the system menu in the top toolbar of macOS.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/Dropdown',
};

export default meta;

type Story = StoryObj<typeof Dropdown>;

export const CSSLengthsDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'css-lengths no-trigger-text',
    },
};

export const StatesDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>Alabama</li>
                <li>Alaska</li>
                <li>Arizona</li>
                <li>Arkansas</li>
                <li>California</li>
                <li>Colorado</li>
                <li>Connecticut</li>
                <li>Delaware</li>
                <li>Florida</li>
                <li>Georgia</li>
                <li>Hawaii</li>
                <li>Idaho</li>
                <li>Illinois</li>
                <li>Indiana</li>
                <li>Iowa</li>
                <li>Kansas</li>
                <li>Kentucky</li>
                <li>Louisiana</li>
                <li>Maine</li>
                <li>Maryland</li>
                <li>Massachusetts</li>
                <li>Michigan</li>
                <li>Minnesota</li>
                <li>Mississippi</li>
                <li>Missouri</li>
                <li>Montana</li>
                <li>Nebraska</li>
                <li>Nevada</li>
                <li>New Hampshire</li>
                <li>New Jersey</li>
                <li>New Mexico</li>
                <li>New York</li>
                <li>North Carolina</li>
                <li>North Dakota</li>
                <li>Ohio</li>
                <li>Oklahoma</li>
                <li>Oregon</li>
                <li>Pennsylvania</li>
                <li>Rhode Island</li>
                <li>South Carolina</li>
                <li>South Dakota</li>
                <li>Tennessee</li>
                <li>Texas</li>
                <li>Utah</li>
                <li>Vermont</li>
                <li>Virginia</li>
                <li>Washington</li>
                <li>West Virginia</li>
                <li>Wisconsin</li>
                <li>Wyoming</li>
            </ul>
        ),
        className: 'states-dropdown',
        isSearchable: true,
        placeholder: 'Choose a state…',
    },
};

export const FontWeightDropdown: Story = {
    args: {
        children: (
            <ul>
                <li data-ukt-value="100">
                    <span className="item-title">Font Weight - </span>
                    100
                </li>
                <li data-ukt-value="200">
                    <span className="item-title">Font Weight - </span>
                    200
                </li>
                <li data-ukt-value="300">
                    <span className="item-title">Font Weight - </span>
                    300
                </li>
                <li data-ukt-value="400">
                    <span className="item-title">Font Weight - </span>
                    400
                </li>
                <li data-ukt-value="500">
                    <span className="item-title">Font Weight - </span>
                    500
                </li>
                <li data-ukt-value="600">
                    <span className="item-title">Font Weight - </span>
                    600
                </li>
                <li data-ukt-value="700">
                    <span className="item-title">Font Weight - </span>
                    700
                </li>
            </ul>
        ),
        className: 'font-weight',
        isSearchable: true,
    },
};

export const ShowContextMenuOnMount: Story = {
    args: {
        children: [
            'View menu',
            <Fragment>
                <h4 className="heading">View</h4>
                <ul>
                    <li data-ukt-item>Open</li>
                    <li data-ukt-item>Preview</li>
                </ul>
                <h4 className="heading">Edit</h4>
                <ul>
                    <li data-ukt-value="save-item">Save</li>
                    <li data-ukt-value="edit-item">Edit</li>
                    <li data-ukt-value="delete-item">Delete</li>
                </ul>
            </Fragment>,
        ],
        className: 'open-on-mount-context-menu',
        isOpenOnMount: true,
    },
};

export const DropdownWithInteractiveContents: Story = {
    args: {
        children: [
            'Open',
            <div>
                <p>
                    Try interacting with the controls here. The dropdown should only close
                    when you click outside of the entire dropdown or if you hit the escape
                    key when focus isn’t in the input controls.
                </p>
                <CSSValueInput
                    cssValueType="length"
                    label="Width"
                    onSubmitValue={() => {}}
                    placeholder="100vw"
                    unit="vw"
                />
                <CSSValueInput
                    cssValueType="length"
                    label="Rotation"
                    onSubmitValue={() => {}}
                    placeholder="0deg"
                    step={5}
                    unit="deg"
                />
            </div>,
        ],
        className: 'dropdown-without-items',
        hasItems: false,
    },
};

export const SearchableWithLabel: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'searchable-with-label',
        isSearchable: true,
        label: (
            <span
                style={{
                    alignItems: 'center',
                    display: 'inline-flex',
                    gap: '0.25rem',
                }}
            >
                Font size
                <ChevronDownIcon />
            </span>
        ),
    },
};

export const SearchableAndAllowCreate: Story = {
    args: {
        allowCreate: true,
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'searchable-and-allow-create',
        isSearchable: true,
        label: 'Font size',
    },
};

export const CSSValueInputTrigger: Story = {
    args: {
        allowCreate: true,
        children: [
            <CSSValueInput
                name="cssinputbackgroundsize"
                onSubmitValue={() => {}}
                placeholder="cover"
                validator={/^(auto|contain|cover)$/}
            />,
            <ul>
                <li>cover</li>
                <li>contain</li>
                <li>auto</li>
                <li>50px</li>
                <li>100px</li>
                <li>200px</li>
                <li>50%</li>
            </ul>,
        ],
        className: 'css-value-input-trigger',
        hasItems: true,
        label: 'Background size',
    },
};

export const TextareaTrigger: Story = {
    args: {
        children: [
            <textarea></textarea>,
            <ul>
                <li>
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
                    ullamcorper fringilla quam, vel tincidunt nisl mattis vel.
                </li>
                <li>
                    Aenean posuere erat sed enim luctus, et accumsan nisl elementum. Nulla
                    vel blandit urna, vel accumsan nulla. Nulla varius luctus ex, gravida
                    ultrices orci sagittis eu.
                </li>
                <li>
                    Quisque vitae magna euismod ligula molestie maximus id et nunc. Nam et
                    lacus euismod, porttitor massa vel, sollicitudin ex. Sed ut tellus
                    suscipit, faucibus tortor nec, fermentum mi.
                </li>
                <li>
                    Nulla sagittis justo non accumsan sagittis. Cras a eros et dolor
                    dapibus bibendum lobortis quis ante. Ut eget scelerisque massa.
                </li>
                <li>
                    Vestibulum quis dignissim nunc. Mauris fringilla at nulla non lacinia.
                    Etiam tristique elit non nisl finibus, fringilla hendrerit ligula
                    hendrerit. Fusce eget leo lacinia, eleifend diam non, suscipit purus.
                </li>
            </ul>,
        ],
        className: 'textarea-trigger',
        hasItems: true,
    },
};

export const CheckboxesDropdown: Story = {
    args: {
        children: [
            'Colors',
            <ul>
                <li>
                    <label>
                        <input type="checkbox" /> Red
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Blue
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Yellow
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Cyan
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Orchid
                    </label>
                </li>
                <li>
                    <label>
                        <input type="checkbox" /> Slate
                    </label>
                </li>
            </ul>,
        ],
        className: 'checkboxes',
        keepOpenOnSubmit: true,
    },
};

const FIXED_HEADER_PROPS = {
    children: [
        <button
            aria-label="Open user menu"
            className="avatar-profile has-avatar"
            popoverTarget="avatar-menu-popover"
            style={{ backgroundImage: `url("https://picsum.photos/id/40/100/100")` }}
        >
            AP
        </button>,
        <ul className="menu-list avatar-dropdown">
            <div
                className="avatar-edit has-avatar"
                style={{
                    backgroundImage: `url("https://picsum.photos/id/40/100/100")`,
                }}
            >
                <div className="avatar-initials">AP</div>
            </div>
            <div className="profile-email-wrap">
                <p className="profile-email">andrew@example.com</p>
            </div>
            <form method="post" action="/logout" className="sign-out-wrap">
                <button className="btn-ghost" type="submit">
                    Sign Out
                </button>
            </form>
        </ul>,
    ] as const,
    className: 'avatar-menu',
};

export const FixedHeader: Story = {
    args: FIXED_HEADER_PROPS,
    render() {
        // const [dateStart, setDateStart] = useState(
        //     FIXED_HEADER_PROPS.dateStart,
        // );
        // const [dateEnd, setDateEnd] = useState(
        //     FIXED_HEADER_PROPS.dateEnd,
        // );

        return (
            <>
                <header className="mk-header">
                    <nav className="mk-nav a1">
                        <a className="logo" href="/"></a>
                        <a className="btn-text logo-text" href="/">
                            UIKit
                        </a>
                    </nav>
                    <div className="mk-nav center">
                        <h5 className="mk subtitle">
                            Welcome! Join our{' '}
                            <a
                                className="home-link"
                                rel="noreferrer"
                                href="https://discord.gg/dTpXZpQ9Rz"
                                target="_blank"
                            >
                                Discord.
                            </a>
                        </h5>
                    </div>
                    <nav className="mk-nav a2">
                        <a className="btn-text" href="/projects">
                            Projects
                        </a>
                        <Dropdown {...FIXED_HEADER_PROPS} />
                    </nav>
                </header>
                <h1>Lorem ipsum</h1>
            </>
        );
    },
};

export const DisabledDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'disabled-dropdown',
        disabled: true,
        isSearchable: true,
        label: 'Disabled',
        name: 'disabledexample',
        value: '167px',
    },
};

export const OverlappingDropdown: Story = {
    args: {
        children: (
            <ul>
                <li>the carbon in our apple pies</li>
                <li>sea of tranquility tesseract</li>
                <li>encyclopaedia galactica</li>
                <li>billions upon billions</li>
                <li>network of wormholes</li>
                <li>tingling of the spine</li>
                <li>corpus callosum</li>
                <li>finite but unbounded</li>
            </ul>
        ),
        className: 'overlapping-dropdown no-trigger-text',
    },
};

export const OutOfBoundsAtRight: Story = {
    args: {
        children: (
            <ul>
                <li>0px</li>
                <li>4px</li>
                <li>9px</li>
                <li>18px</li>
                <li>36px</li>
                <li>54px</li>
                <li>72px</li>
                <li>144px</li>
                <li>167px</li>
                <li>198px</li>
            </ul>
        ),
        className: 'out-of-bounds-example position-right',
        isSearchable: true,
        name: 'outofboundsatright',
        placeholder: 'Fill available space',
    },
};

export const OutOfBoundsWithNoDirectionChange: Story = {
    args: {
        children: (
            <ul>
                <li>Antarctica</li>
                <li>Arctic Circle</li>
                <li>North Pole</li>
            </ul>
        ),
        className: 'out-of-bounds-example no-direction-change',
        isSearchable: true,
        name: 'outofboundsatbottomnodirectionchange',
        placeholder: 'Show below even though it goes out of bounds',
    },
};

export const ConstrainHeightToAvoidClipping: Story = {
    args: {
        children: (
            <ul>
                <li>Antarctica</li>
                <li>Arctic Circle</li>
                <li>North Pole</li>
            </ul>
        ),
        className: 'out-of-bounds-example no-direction-change',
        constrainHeightToAvoidClipping: true,
        isSearchable: true,
        name: 'constrainheighttoavoidclipping',
        placeholder: 'Stay below, but scroll if clipping remains',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { CSSValueInput, Dropdown } from "@acusti/uikit-docs";
CSS Lengths Dropdown story ok
const CSSLengthsDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="css-lengths no-trigger-text">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
States Dropdown story ok
const StatesDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="states-dropdown"
    isSearchable
    placeholder="Choose a state…">(<ul>
        <li>Alabama</li>
        <li>Alaska</li>
        <li>Arizona</li>
        <li>Arkansas</li>
        <li>California</li>
        <li>Colorado</li>
        <li>Connecticut</li>
        <li>Delaware</li>
        <li>Florida</li>
        <li>Georgia</li>
        <li>Hawaii</li>
        <li>Idaho</li>
        <li>Illinois</li>
        <li>Indiana</li>
        <li>Iowa</li>
        <li>Kansas</li>
        <li>Kentucky</li>
        <li>Louisiana</li>
        <li>Maine</li>
        <li>Maryland</li>
        <li>Massachusetts</li>
        <li>Michigan</li>
        <li>Minnesota</li>
        <li>Mississippi</li>
        <li>Missouri</li>
        <li>Montana</li>
        <li>Nebraska</li>
        <li>Nevada</li>
        <li>New Hampshire</li>
        <li>New Jersey</li>
        <li>New Mexico</li>
        <li>New York</li>
        <li>North Carolina</li>
        <li>North Dakota</li>
        <li>Ohio</li>
        <li>Oklahoma</li>
        <li>Oregon</li>
        <li>Pennsylvania</li>
        <li>Rhode Island</li>
        <li>South Carolina</li>
        <li>South Dakota</li>
        <li>Tennessee</li>
        <li>Texas</li>
        <li>Utah</li>
        <li>Vermont</li>
        <li>Virginia</li>
        <li>Washington</li>
        <li>West Virginia</li>
        <li>Wisconsin</li>
        <li>Wyoming</li>
    </ul>)</Dropdown>;
Font Weight Dropdown story ok
const FontWeightDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="font-weight"
    isSearchable>(<ul>
        <li data-ukt-value="100">
            <span className="item-title">Font Weight - </span>
            100
        </li>
        <li data-ukt-value="200">
            <span className="item-title">Font Weight - </span>
            200
        </li>
        <li data-ukt-value="300">
            <span className="item-title">Font Weight - </span>
            300
        </li>
        <li data-ukt-value="400">
            <span className="item-title">Font Weight - </span>
            400
        </li>
        <li data-ukt-value="500">
            <span className="item-title">Font Weight - </span>
            500
        </li>
        <li data-ukt-value="600">
            <span className="item-title">Font Weight - </span>
            600
        </li>
        <li data-ukt-value="700">
            <span className="item-title">Font Weight - </span>
            700
        </li>
    </ul>)</Dropdown>;
Show Context Menu On Mount story ok
const ShowContextMenuOnMount = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="open-on-mount-context-menu"
    isOpenOnMount>{[
        'View menu',
        <Fragment>
            <h4 className="heading">View</h4>
            <ul>
                <li data-ukt-item>Open</li>
                <li data-ukt-item>Preview</li>
            </ul>
            <h4 className="heading">Edit</h4>
            <ul>
                <li data-ukt-value="save-item">Save</li>
                <li data-ukt-value="edit-item">Edit</li>
                <li data-ukt-value="delete-item">Delete</li>
            </ul>
        </Fragment>,
    ]}</Dropdown>;
Dropdown With Interactive Contents story ok
const DropdownWithInteractiveContents = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="dropdown-without-items"
    hasItems={false}>{[
        'Open',
        <div>
            <p>
                Try interacting with the controls here. The dropdown should only close
                when you click outside of the entire dropdown or if you hit the escape
                key when focus isn’t in the input controls.
            </p>
            <CSSValueInput
                cssValueType="length"
                label="Width"
                onSubmitValue={() => {}}
                placeholder="100vw"
                unit="vw"
            />
            <CSSValueInput
                cssValueType="length"
                label="Rotation"
                onSubmitValue={() => {}}
                placeholder="0deg"
                step={5}
                unit="deg"
            />
        </div>,
    ]}</Dropdown>;
Searchable With Label story ok
const SearchableWithLabel = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="searchable-with-label"
    isSearchable
    label={(<span
        style={{
            alignItems: 'center',
            display: 'inline-flex',
            gap: '0.25rem',
        }}
    >Font size
                        <ChevronDownIcon />
    </span>)}>(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Searchable And Allow Create story ok
const SearchableAndAllowCreate = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    allowCreate
    className="searchable-and-allow-create"
    isSearchable
    label="Font size">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
CSS Value Input Trigger story ok
const CSSValueInputTrigger = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    allowCreate
    className="css-value-input-trigger"
    hasItems
    label="Background size">{[
        <CSSValueInput
            name="cssinputbackgroundsize"
            onSubmitValue={() => {}}
            placeholder="cover"
            validator={/^(auto|contain|cover)$/}
        />,
        <ul>
            <li>cover</li>
            <li>contain</li>
            <li>auto</li>
            <li>50px</li>
            <li>100px</li>
            <li>200px</li>
            <li>50%</li>
        </ul>,
    ]}</Dropdown>;
Textarea Trigger story ok
const TextareaTrigger = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="textarea-trigger"
    hasItems>{[
        <textarea></textarea>,
        <ul>
            <li>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque
                ullamcorper fringilla quam, vel tincidunt nisl mattis vel.
            </li>
            <li>
                Aenean posuere erat sed enim luctus, et accumsan nisl elementum. Nulla
                vel blandit urna, vel accumsan nulla. Nulla varius luctus ex, gravida
                ultrices orci sagittis eu.
            </li>
            <li>
                Quisque vitae magna euismod ligula molestie maximus id et nunc. Nam et
                lacus euismod, porttitor massa vel, sollicitudin ex. Sed ut tellus
                suscipit, faucibus tortor nec, fermentum mi.
            </li>
            <li>
                Nulla sagittis justo non accumsan sagittis. Cras a eros et dolor
                dapibus bibendum lobortis quis ante. Ut eget scelerisque massa.
            </li>
            <li>
                Vestibulum quis dignissim nunc. Mauris fringilla at nulla non lacinia.
                Etiam tristique elit non nisl finibus, fringilla hendrerit ligula
                hendrerit. Fusce eget leo lacinia, eleifend diam non, suscipit purus.
            </li>
        </ul>,
    ]}</Dropdown>;
Checkboxes Dropdown story ok
const CheckboxesDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="checkboxes"
    keepOpenOnSubmit>{[
        'Colors',
        <ul>
            <li>
                <label>
                    <input type="checkbox" /> Red
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Blue
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Yellow
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Cyan
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Orchid
                </label>
            </li>
            <li>
                <label>
                    <input type="checkbox" /> Slate
                </label>
            </li>
        </ul>,
    ]}</Dropdown>;
Fixed Header story ok
const FixedHeader = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()} />;
Disabled Dropdown story ok
const DisabledDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="disabled-dropdown"
    disabled
    isSearchable
    label="Disabled"
    name="disabledexample"
    value="167px">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Overlapping Dropdown story ok
const OverlappingDropdown = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="overlapping-dropdown no-trigger-text">(<ul>
        <li>the carbon in our apple pies</li>
        <li>sea of tranquility tesseract</li>
        <li>encyclopaedia galactica</li>
        <li>billions upon billions</li>
        <li>network of wormholes</li>
        <li>tingling of the spine</li>
        <li>corpus callosum</li>
        <li>finite but unbounded</li>
    </ul>)</Dropdown>;
Out Of Bounds At Right story ok
const OutOfBoundsAtRight = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example position-right"
    isSearchable
    name="outofboundsatright"
    placeholder="Fill available space">(<ul>
        <li>0px</li>
        <li>4px</li>
        <li>9px</li>
        <li>18px</li>
        <li>36px</li>
        <li>54px</li>
        <li>72px</li>
        <li>144px</li>
        <li>167px</li>
        <li>198px</li>
    </ul>)</Dropdown>;
Out Of Bounds With No Direction Change story ok
const OutOfBoundsWithNoDirectionChange = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example no-direction-change"
    isSearchable
    name="outofboundsatbottomnodirectionchange"
    placeholder="Show below even though it goes out of bounds">(<ul>
        <li>Antarctica</li>
        <li>Arctic Circle</li>
        <li>North Pole</li>
    </ul>)</Dropdown>;
Constrain Height To Avoid Clipping story ok
const ConstrainHeightToAvoidClipping = () => <Dropdown
    onClick={fn()}
    onClose={fn()}
    onMouseDown={fn()}
    onMouseUp={fn()}
    onOpen={fn()}
    onSubmitItem={fn()}
    className="out-of-bounds-example no-direction-change"
    constrainHeightToAvoidClipping
    isSearchable
    name="constrainheighttoavoidclipping"
    placeholder="Stay below, but scroll if clipping remains">(<ul>
        <li>Antarctica</li>
        <li>Arctic Circle</li>
        <li>North Pole</li>
    </ul>)</Dropdown>;

Dropdown

uikit-hooks-useisoutofbounds · ./stories/useIsOutOfBounds.stories.tsx
Prop type error
No component file found for the "Dropdown" component.
   7 | import type { Meta, StoryObj } from '@storybook/react-vite';
   8 |
>  9 | const meta: Meta<typeof useIsOutOfBounds> = {
     | ^
  10 |     argTypes: {
  11 |         element: {
  12 |             description:

./stories/useIsOutOfBounds.stories.tsx:
import Dropdown from '../../dropdown/src/Dropdown.js';
import useIsOutOfBounds from '../../use-is-out-of-bounds/src/useIsOutOfBounds.js';

import './Dropdown.css';
import './useIsOutOfBounds.css';

import type { Meta, StoryObj } from '@storybook/react-vite';

const meta: Meta<typeof useIsOutOfBounds> = {
    argTypes: {
        element: {
            description:
                'The HTMLElement that will be checked to see if it is out of bounds and in what direction. Can be null or undefined.',
            table: {
                type: { summary: 'object' },
            },
        },
    },
    component: Dropdown,
    parameters: {
        controls: { exclude: /.*/g },
        docs: {
            description: {
                component: `\`useIsOutOfBounds\` is a React hook that returns an object indicating if the
current component is out of the bounds of its nearest ancestor that doesn’t have overflow: visible. In other words,
it provides collision detection between an element and its bounds. The return value is

\`\`\`
type OutOfBounds = {
    bottom: boolean;
    hasLayout: boolean;
    left: boolean;
    maxHeight: null | number;
    maxWidth: null | number;
    right: boolean;
    top: boolean;
};
\`\`\`

It is used in @acusti/dropdown to automatically position the dropdown in the direction
where there is room for it to render, so this story uses \`<Dropdown>\` to illustrate that behavior.`,
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Hooks/useIsOutOfBounds',
};

export default meta;

type Story = StoryObj<typeof Dropdown>;

const list = (
    <ul>
        <li>Brunei Darussalam</li>
        <li>Cambodia</li>
        <li>Indonesia</li>
        <li>Laos</li>
        <li>Malaysia</li>
        <li>Myanmar (Burma)</li>
        <li>Philippines</li>
        <li>Singapore</li>
        <li>Thailand</li>
        <li>Timor-Leste (East Timor)</li>
        <li>Vietnam</li>
    </ul>
);

export const NotOutOfBounds: Story = {
    args: {
        children: list,
        className: 'not-out-of-bounds-example',
        isSearchable: true,
        name: 'notoutofbounds',
        placeholder: 'Default behavior',
    },
};

export const OutOfBoundsAtBottom: Story = {
    args: {
        children: list,
        className: 'out-of-bounds-example',
        isSearchable: true,
        name: 'outofboundsatbottom',
        placeholder: 'Show above',
    },
};

export const OutOfBoundsAtRight: Story = {
    args: {
        children: list,
        className: 'out-of-bounds-example position-right',
        isSearchable: true,
        name: 'outofboundsatright',
        placeholder: 'Show above & to the left',
    },
};

export const OutOfBoundsTopAndBottom: Story = {
    args: {
        children: (
            <ul>
                <li>Algeria</li>
                <li>Angola</li>
                <li>Benin</li>
                <li>Botswana</li>
                <li>Burkina Faso</li>
                <li>Burundi</li>
                <li>Cabo Verde</li>
                <li>Cameroon</li>
                <li>Central African Republic</li>
                <li>Chad</li>
                <li>Comoros</li>
                <li>Congo, Democratic Republic of the</li>
                <li>Congo, Republic of the</li>
                <li>Cote d’Ivoire</li>
                <li>Djibouti</li>
                <li>Egypt</li>
                <li>Equatorial Guinea</li>
                <li>Eritrea</li>
                <li>Eswatini</li>
                <li>Ethiopia</li>
                <li>Gabon</li>
                <li>Gambia</li>
                <li>Ghana</li>
                <li>Guinea</li>
                <li>Guinea-Bissau</li>
                <li>Kenya</li>
                <li>Lesotho</li>
                <li>Liberia</li>
                <li>Libya</li>
                <li>Madagascar</li>
                <li>Malawi</li>
                <li>Mali</li>
                <li>Mauritania</li>
                <li>Mauritius</li>
                <li>Morocco</li>
                <li>Mozambique</li>
                <li>Namibia</li>
                <li>Niger</li>
                <li>Nigeria</li>
                <li>Rwanda</li>
                <li>Sao Tome and Principe</li>
                <li>Senegal</li>
                <li>Seychelles</li>
                <li>Sierra Leone</li>
                <li>Somalia</li>
                <li>South Africa</li>
                <li>South Sudan</li>
                <li>Sudan</li>
                <li>Tanzania</li>
                <li>Togo</li>
                <li>Tunisia</li>
                <li>Uganda</li>
                <li>Zambia</li>
                <li>Zimbabwe</li>
            </ul>
        ),
        className: 'out-of-bounds-top-and-bottom-example',
        isSearchable: true,
        name: 'outofboundstopandbottom',
        placeholder: 'long list',
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { Dropdown } from "@acusti/uikit-docs";
Not Out Of Bounds story ok
const NotOutOfBounds = () => <Dropdown
    className="not-out-of-bounds-example"
    isSearchable
    name="notoutofbounds"
    placeholder="Default behavior">{list}</Dropdown>;
Out Of Bounds At Bottom story ok
const OutOfBoundsAtBottom = () => <Dropdown
    className="out-of-bounds-example"
    isSearchable
    name="outofboundsatbottom"
    placeholder="Show above">{list}</Dropdown>;
Out Of Bounds At Right story ok
const OutOfBoundsAtRight = () => <Dropdown
    className="out-of-bounds-example position-right"
    isSearchable
    name="outofboundsatright"
    placeholder="Show above & to the left">{list}</Dropdown>;
Out Of Bounds Top And Bottom story ok
const OutOfBoundsTopAndBottom = () => <Dropdown
    className="out-of-bounds-top-and-bottom-example"
    isSearchable
    name="outofboundstopandbottom"
    placeholder="long list">(<ul>
        <li>Algeria</li>
        <li>Angola</li>
        <li>Benin</li>
        <li>Botswana</li>
        <li>Burkina Faso</li>
        <li>Burundi</li>
        <li>Cabo Verde</li>
        <li>Cameroon</li>
        <li>Central African Republic</li>
        <li>Chad</li>
        <li>Comoros</li>
        <li>Congo, Democratic Republic of the</li>
        <li>Congo, Republic of the</li>
        <li>Cote d’Ivoire</li>
        <li>Djibouti</li>
        <li>Egypt</li>
        <li>Equatorial Guinea</li>
        <li>Eritrea</li>
        <li>Eswatini</li>
        <li>Ethiopia</li>
        <li>Gabon</li>
        <li>Gambia</li>
        <li>Ghana</li>
        <li>Guinea</li>
        <li>Guinea-Bissau</li>
        <li>Kenya</li>
        <li>Lesotho</li>
        <li>Liberia</li>
        <li>Libya</li>
        <li>Madagascar</li>
        <li>Malawi</li>
        <li>Mali</li>
        <li>Mauritania</li>
        <li>Mauritius</li>
        <li>Morocco</li>
        <li>Mozambique</li>
        <li>Namibia</li>
        <li>Niger</li>
        <li>Nigeria</li>
        <li>Rwanda</li>
        <li>Sao Tome and Principe</li>
        <li>Senegal</li>
        <li>Seychelles</li>
        <li>Sierra Leone</li>
        <li>Somalia</li>
        <li>South Africa</li>
        <li>South Sudan</li>
        <li>Sudan</li>
        <li>Tanzania</li>
        <li>Togo</li>
        <li>Tunisia</li>
        <li>Uganda</li>
        <li>Zambia</li>
        <li>Zimbabwe</li>
    </ul>)</Dropdown>;

InputText

uikit-controls-inputtext · ./stories/InputText.stories.tsx
Prop type error
No component file found for the "InputText" component.
   7 | import './InputText.css';
   8 |
>  9 | const meta: Meta<typeof InputText> = {
     | ^
  10 |     component: InputText,
  11 |     parameters: {
  12 |         docs: {

./stories/InputText.stories.tsx:
import type { Meta, StoryObj } from '@storybook/react-vite';
import { type FormEvent, useState } from 'react';
import { fn } from 'storybook/test';

import InputText from '../../input-text/src/InputText.js';

import './InputText.css';

const meta: Meta<typeof InputText> = {
    component: InputText,
    parameters: {
        docs: {
            description: {
                component:
                    '`InputText` is a React component that renders a textual input (`type: "text"|"email"|"number"|"password"|"search"|"tel"|"url"`) that is uncontrolled, but whose value is overwritten whenever `props.initialValue` changes. Also, if `props.selectTextOnFocus` is true, it selects the entire contents of the input whenever the input is focused. And it supports multiline inputs (rendered as a `<textarea>`) that automatically resize vertically to fit their content.',
            },
        },
    },
    //https://storybook.js.org/docs/react/writing-docs/autodocs#setup-automated-documentation
    tags: ['autodocs'],
    title: 'UIKit/Controls/InputText',
};

export default meta;

type Story = StoryObj<typeof InputText>;

export const EmptyInput: Story = {
    args: {
        className: 'input-text',
        name: 'empty',
        // NOTE spies are a workaround for a bug related to implicit arg detection
        onBlur: fn(),
        onChange: fn(),
        onChangeValue: fn(),
        onFocus: fn(),
        onKeyDown: fn(),
        onKeyUp: fn(),
        placeholder: 'enter text here…',
    },
};

export const InputWithInitialValue: Story = {
    args: {
        className: 'input-text',
        initialValue: 'Bolivia',
        placeholder: 'enter country name',
    },
};

export const InputWithInitialValueAndSelectTextOnFocus: Story = {
    args: {
        className: 'input-text',
        initialValue: 'Bolivia',
        name: 'country',
        placeholder: 'enter country name (selectTextOnFocus)',
        selectTextOnFocus: true,
    },
};

export const MultiLineInputWithInitialValueAndSelectTextOnFocus: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'The Black Hawk War, or, How to Demolish an Entire Civilization and Still Feel Good About Yourself in the Morning, or, We Apologize for the Inconvenience but You’re Going to Have to Leave Now, or, “I have fought the Big Knives and will continue to fight them until they are off our lands!”',
        maxHeight: 600,
        multiLine: true,
        name: 'multi-line-input',
        placeholder: 'enter text of any length',
        selectTextOnFocus: true,
    },
};

const SUBMIT_ON_ENTER_PROPS = {
    className: 'multi-line-input-text',
    maxHeight: 600,
    multiLine: true,
    name: 'multi-line-submit-on-enter-input',
    placeholder: 'enter text of any length',
    submitOnEnter: true,
};

const formatDate = new Intl.DateTimeFormat(undefined, {
    timeStyle: 'medium',
}).format;

export const MultiLineInputWithSubmitOnEnter: Story = {
    args: SUBMIT_ON_ENTER_PROPS,
    render() {
        const [lastSubmitDate, setLastSubmitDate] = useState<Date | null>(null);
        const lastSubmit = lastSubmitDate ? formatDate(lastSubmitDate) : 'never';

        return (
            <form
                onSubmit={(event: FormEvent<HTMLFormElement>) => {
                    event.preventDefault();
                    setLastSubmitDate(new Date());
                }}
            >
                <InputText {...SUBMIT_ON_ENTER_PROPS} />
                <pre>Last submitted: {lastSubmit}</pre>
            </form>
        );
    },
};

export const MultiLineInputWithSubmitOnEnterNoForm: Story = {
    args: {
        ...SUBMIT_ON_ENTER_PROPS,
        name: `${SUBMIT_ON_ENTER_PROPS.name}-no-form`,
    },
};

function ChatLikeInputDemo() {
    const [message, setMessage] = useState('');
    const [messages, setMessages] = useState<Array<string>>([]);

    return (
        <form
            onSubmit={(event) => {
                event.preventDefault();
                if (!message.trim()) return;
                setMessages((previousMessages) => [...previousMessages, message.trim()]);
                setMessage('');
            }}
        >
            <pre>{messages.join('\n') || 'No messages yet'}</pre>
            <InputText
                className="input-text"
                initialValue={message}
                keepFocusOnSubmit
                onChangeValue={setMessage}
                placeholder="Type then press Enter"
                submitOnEnter
            />
        </form>
    );
}

export const ChatLikeInputWithSubmitOnEnter: Story = {
    args: {
        className: 'input-text',
        keepFocusOnSubmit: true,
        placeholder: 'Type then press Enter',
        submitOnEnter: true,
    },
    render() {
        return <ChatLikeInputDemo />;
    },
};

const DOUBLE_CLICK_TO_EDIT_PROPS = {
    className: 'input-text-double-click-to-edit',
    doubleClickToEdit: true,
    initialValue: 'Lorem ipsum dolor sit amet',
    name: 'double-click-to-edit-input',
};

export const InputWithDoubleClickToEdit: Story = {
    args: DOUBLE_CLICK_TO_EDIT_PROPS,
};

const DISCARD_ON_ESCAPE_PROPS = {
    className: 'input-text',
    discardOnEscape: true,
    initialValue: 'Lorem ipsum',
    name: 'discard-on-escape-input',
};

export const InputWithDiscardOnEscape: Story = {
    args: DISCARD_ON_ESCAPE_PROPS,
};

export const InputWithDoubleClickToEditAndDiscardOnEscape: Story = {
    args: {
        ...DISCARD_ON_ESCAPE_PROPS,
        ...DOUBLE_CLICK_TO_EDIT_PROPS,
        name: 'double-click-to-edit-and-discard-on-escape-input',
    },
};

export const InputWithAutoFocus: Story = {
    args: {
        autoFocus: true,
        name: 'autofocus-input',
    },
};

export const MultiLineInputWithMinHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'This textarea has a minHeight of 50px.\n\nTry deleting this text to see that the textarea does not shrink below the minimum height.',
        minHeight: 50,
        multiLine: true,
        name: 'multi-line-min-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithMaxHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue:
            'This textarea has a maxHeight of 150px.\n\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10',
        maxHeight: 150,
        multiLine: true,
        name: 'multi-line-max-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithMinHeightAndMaxHeight: Story = {
    args: {
        className: 'multi-line-input-text',
        initialValue: 'This textarea has minHeight of 100px and maxHeight of 200px.',
        maxHeight: 200,
        minHeight: 100,
        multiLine: true,
        name: 'multi-line-min-max-height-input',
        placeholder: 'enter text of any length',
    },
};

export const MultiLineInputWithCSSTransition: Story = {
    args: {
        className: 'multi-line-input-css-transition',
        multiLine: true,
        name: 'multi-line-input-css-transition',
        placeholder: 'Write a quick note here',
        rows: 4,
    },
};

const MULTI_LINE_INPUT_IN_POPOVER_PROPS = {
    className: 'multi-line-input-text',
    initialValue:
        'This multi-line input should resize to fit its contents when the popover opens even though it initializes with display: none as a result of being inside a hidden popover element so it doesn’t have any dimensions when the component initially renders.',
    multiLine: true,
    name: 'multi-line-input-in-popover',
    selectTextOnFocus: true,
};

export const MultiLineInputInPopover: Story = {
    args: MULTI_LINE_INPUT_IN_POPOVER_PROPS,
    render() {
        return (
            <>
                <button popoverTarget="multi-line-input-popover">Open Popover</button>
                <div id="multi-line-input-popover" popover="auto">
                    <InputText {...MULTI_LINE_INPUT_IN_POPOVER_PROPS} />
                </div>
            </>
        );
    },
};

const MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS = {
    autoFocus: true,
    initialValue: 'This multi-line input should be focused when the popover opens',
    multiLine: true,
    name: 'multi-line-input-with-autofocus-in-popover',
    selectTextOnFocus: true,
};

export const MultiLineInputWithAutoFocusInPopover: Story = {
    args: MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS,
    render() {
        return (
            <>
                <button popoverTarget="multi-line-input-with-autofocus-popover">
                    Open Popover
                </button>
                <div id="multi-line-input-with-autofocus-popover" popover="auto">
                    <InputText {...MULTI_LINE_INPUT_WITH_AUTO_FOCUS_PROPS} />
                </div>
            </>
        );
    },
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { InputText } from "@acusti/uikit-docs";
Empty Input story ok
const EmptyInput = () => <InputText
    className="input-text"
    name="empty"
    onBlur={fn()}
    onChange={fn()}
    onChangeValue={fn()}
    onFocus={fn()}
    onKeyDown={fn()}
    onKeyUp={fn()}
    placeholder="enter text here…" />;
Input With Initial Value story ok
const InputWithInitialValue = () => <InputText
    className="input-text"
    initialValue="Bolivia"
    placeholder="enter country name" />;
Input With Initial Value And Select Text On Focus story ok
const InputWithInitialValueAndSelectTextOnFocus = () => <InputText
    className="input-text"
    initialValue="Bolivia"
    name="country"
    placeholder="enter country name (selectTextOnFocus)"
    selectTextOnFocus />;
Multi Line Input With Initial Value And Select Text On Focus story ok
const MultiLineInputWithInitialValueAndSelectTextOnFocus = () => <InputText
    className="multi-line-input-text"
    initialValue="The Black Hawk War, or, How to Demolish an Entire Civilization and Still Feel Good About Yourself in the Morning, or, We Apologize for the Inconvenience but You’re Going to Have to Leave Now, or, “I have fought the Big Knives and will continue to fight them until they are off our lands!”"
    maxHeight={600}
    multiLine
    name="multi-line-input"
    placeholder="enter text of any length"
    selectTextOnFocus />;
Multi Line Input With Submit On Enter story ok
const MultiLineInputWithSubmitOnEnter = () => <InputText />;
Multi Line Input With Submit On Enter No Form story ok
const MultiLineInputWithSubmitOnEnterNoForm = () => <InputText name={`${SUBMIT_ON_ENTER_PROPS.name}-no-form`} />;
Chat Like Input With Submit On Enter story ok
const ChatLikeInputWithSubmitOnEnter = () => <InputText
    className="input-text"
    keepFocusOnSubmit
    placeholder="Type then press Enter"
    submitOnEnter />;
Input With Double Click To Edit story ok
const InputWithDoubleClickToEdit = () => <InputText />;
Input With Discard On Escape story ok
const InputWithDiscardOnEscape = () => <InputText />;
Input With Double Click To Edit And Discard On Escape story ok
const InputWithDoubleClickToEditAndDiscardOnEscape = () => <InputText name="double-click-to-edit-and-discard-on-escape-input" />;
Input With Auto Focus story ok
const InputWithAutoFocus = () => <InputText autoFocus name="autofocus-input" />;
Multi Line Input With Min Height story ok
const MultiLineInputWithMinHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has a minHeight of 50px.\n\nTry deleting this text to see that the textarea does not shrink below the minimum height."
    minHeight={50}
    multiLine
    name="multi-line-min-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With Max Height story ok
const MultiLineInputWithMaxHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has a maxHeight of 150px.\n\nLine 3\nLine 4\nLine 5\nLine 6\nLine 7\nLine 8\nLine 9\nLine 10"
    maxHeight={150}
    multiLine
    name="multi-line-max-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With Min Height And Max Height story ok
const MultiLineInputWithMinHeightAndMaxHeight = () => <InputText
    className="multi-line-input-text"
    initialValue="This textarea has minHeight of 100px and maxHeight of 200px."
    maxHeight={200}
    minHeight={100}
    multiLine
    name="multi-line-min-max-height-input"
    placeholder="enter text of any length" />;
Multi Line Input With CSS Transition story ok
const MultiLineInputWithCSSTransition = () => <InputText
    className="multi-line-input-css-transition"
    multiLine
    name="multi-line-input-css-transition"
    placeholder="Write a quick note here"
    rows={4} />;
Multi Line Input In Popover story ok
const MultiLineInputInPopover = () => <InputText />;
Multi Line Input With Auto Focus In Popover story ok
const MultiLineInputWithAutoFocusInPopover = () => <InputText />;

DatePicker

uikit-controls-datepicker-datepicker · ./stories/DatePicker.stories.tsx
Prop type error
File: /Users/andrew/Projects/uikit/packages/date-picker/src/index.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
export { default as DatePicker } from './DatePicker.js';
export { default as MonthCalendar } from './MonthCalendar.js';
export * from './utils.js';


File: /Users/andrew/Projects/uikit/packages/date-picker/src/utils.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
// The following utils work on a “month” as a unique numerical value
// representing the number of months since the unix epoch (jan 1970)
const START_YEAR = 1970;
const MONTH_NAMES = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
];

const getYearFromDate = (date: Date, asUTC?: boolean) =>
    (asUTC ? date.getUTCFullYear() : date.getFullYear()) - START_YEAR;

export const getMonthFromDate = (date: Date, asUTC?: boolean) => {
    const yearAsMonths = getYearFromDate(date, asUTC) * 12;
    return yearAsMonths + (asUTC ? date.getUTCMonth() : date.getMonth());
};

export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;

export const getMonthNameFromMonth = (month: number): string => {
    let index = month % 12;
    if (Number.isNaN(index)) return '';
    if (index < 0) index = 12 + index;
    return MONTH_NAMES[index];
};

export const getMonthAbbreviationFromMonth = (month: number) => {
    const monthName = getMonthNameFromMonth(month);
    if (monthName === 'September') return 'Sept';
    return monthName.substring(0, 3);
};

export const getDateFromMonthAndDay = (month: number, day: number, asUTC?: boolean) => {
    const monthIn12 = month < 0 ? (12 - Math.abs(month % 12)) % 12 : month % 12;
    const year = getYearFromMonth(month);
    return asUTC
        ? new Date(Date.UTC(year, monthIn12, day))
        : new Date(year, monthIn12, day);
};

export const getLastDateFromMonth = (month: number, asUTC?: boolean) => {
    // day 0 of the next month is the last day of the current month
    return getDateFromMonthAndDay(month + 1, 0, asUTC);
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { DatePicker } from "@acusti/date-picker";
Default Date Picker story ok
const DefaultDatePicker = () => <DatePicker className="default-date-picker-story" />;
Two Up Date Picker story ok
const TwoUpDatePicker = () => <DatePicker className="two-up-date-picker-story" isTwoUp />;
Date Range Navidad Dia De Los Reyes Date Picker story ok
const DateRangeNavidadDiaDeLosReyesDatePicker = () => <DatePicker />;
No Future Two Up Date Picker story ok
const NoFutureTwoUpDatePicker = () => <DatePicker
    className="no-future-two-up-date-picker-story"
    isTwoUp
    monthLimitLast={getMonthFromDate(new Date())} />;
Show End Initially Date Picker story ok
const ShowEndInitiallyDatePicker = () => <DatePicker
    className="no-future-two-up-date-picker-story"
    defaultDateEnd={new Date(1234, 0, 1).toISOString()}
    defaultDateStart={new Date(1233, 0, 1).toISOString()}
    isTwoUp
    showEndInitially />;
Booking System Date Range story ok
const BookingSystemDateRange = () => <DatePicker />;
Event Scheduler story ok
const EventScheduler = () => <DatePicker />;
Birthday Picker story ok
const BirthdayPicker = () => <DatePicker />;
Flexible Date Picker story ok
const FlexibleDatePicker = () => <DatePicker />;

MonthCalendar

uikit-controls-datepicker-monthcalendar · ./stories/MonthCalendar.stories.ts
Prop type error
File: /Users/andrew/Projects/uikit/packages/date-picker/src/index.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
export { default as DatePicker } from './DatePicker.js';
export { default as MonthCalendar } from './MonthCalendar.js';
export * from './utils.js';


File: /Users/andrew/Projects/uikit/packages/date-picker/src/utils.ts
Error:
No suitable component definition found.
You can debug your component file in this playground: https://react-docgen.dev/playground
Code:
// The following utils work on a “month” as a unique numerical value
// representing the number of months since the unix epoch (jan 1970)
const START_YEAR = 1970;
const MONTH_NAMES = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December',
];

const getYearFromDate = (date: Date, asUTC?: boolean) =>
    (asUTC ? date.getUTCFullYear() : date.getFullYear()) - START_YEAR;

export const getMonthFromDate = (date: Date, asUTC?: boolean) => {
    const yearAsMonths = getYearFromDate(date, asUTC) * 12;
    return yearAsMonths + (asUTC ? date.getUTCMonth() : date.getMonth());
};

export const getYearFromMonth = (month: number) => Math.floor(month / 12) + START_YEAR;

export const getMonthNameFromMonth = (month: number): string => {
    let index = month % 12;
    if (Number.isNaN(index)) return '';
    if (index < 0) index = 12 + index;
    return MONTH_NAMES[index];
};

export const getMonthAbbreviationFromMonth = (month: number) => {
    const monthName = getMonthNameFromMonth(month);
    if (monthName === 'September') return 'Sept';
    return monthName.substring(0, 3);
};

export const getDateFromMonthAndDay = (month: number, day: number, asUTC?: boolean) => {
    const monthIn12 = month < 0 ? (12 - Math.abs(month % 12)) % 12 : month % 12;
    const year = getYearFromMonth(month);
    return asUTC
        ? new Date(Date.UTC(year, monthIn12, day))
        : new Date(year, monthIn12, day);
};

export const getLastDateFromMonth = (month: number, asUTC?: boolean) => {
    // day 0 of the next month is the last day of the current month
    return getDateFromMonthAndDay(month + 1, 0, asUTC);
};
Info
No description found. Write a jsdoc comment such as /** Component description */.
Imports
import { MonthCalendar } from "@acusti/date-picker";
This Months Calendar story ok
const ThisMonthsCalendar = () => <MonthCalendar className="month-calendar-story" month={getMonthFromDate(new Date())} />;
February 1985 Calendar story ok
const February1985Calendar = () => <MonthCalendar className="february-month-calendar-story" month={181} />;
Date Range Diwali Calendar story ok
const DateRangeDiwaliCalendar = () => <MonthCalendar
    className="date-range-month-calendar-story"
    dateEnd={new Date(2023, 10, 14)}
    dateStart={new Date(2023, 10, 9)}
    month={getMonthFromDate(new Date(2023, 10, 1))} />;

Unattached Docs

UIKit/Introduction

uikit-introduction--docs · ./stories/Introduction.mdx
import { Meta } from '@storybook/addon-docs/blocks';

import Github from './assets/github.svg';
import Discord from './assets/discord.svg';
import Youtube from './assets/youtube.svg';
import Tutorials from './assets/tutorials.svg';
import Styling from './assets/styling.png';
import Context from './assets/context.png';
import Assets from './assets/assets.png';
import Docs from './assets/docs.png';
import Share from './assets/share.png';
import FigmaPlugin from './assets/figma-plugin.png';
import Testing from './assets/testing.png';
import Accessibility from './assets/accessibility.png';
import Theming from './assets/theming.png';
import AddonLibrary from './assets/addon-library.png';

<Meta title="UIKit/Introduction" />

# Welcome to UIKit’s Storybook

[UIKit](https://github.com/acusti/uikit) provides a collection of UI
components and tools for building modern web and mobile applications. To
see what the components look like and how to use them, explore everything
under the “Controls” folder in the sidebar. The four components currently
documented here are:

- [InputText](../?path=/docs/uikit-controls-inputtext--docs)
- [CSSValueInput](../?path=/docs/uikit-controls-CSSValueInput--docs)
- [Dropdown](../?path=/docs/uikit-controls-Dropdown--docs)
- [DatePicker](../?path=/docs/uikit-controls-datepicker-datepicker--docs)

There are also two custom React hooks available under the “Hooks” folder:

- [useIsOutOfBounds](../?path=/docs/uikit-hooks-useisoutofbounds--docs)
- [useKeyboardEvents](../?path=/docs/uikit-hooks-usekeyboardevents--docs)

See below for more about Storybook and how it works.

export const RightArrow = () => (
    <svg
        viewBox="0 0 14 14"
        width="8px"
        height="14px"
        style={{
            marginLeft: '4px',
            display: 'inline-block',
            shapeRendering: 'inherit',
            verticalAlign: 'middle',
            fill: 'currentColor',
            'path fill': 'currentColor',
        }}
    >
        <path d="m11.1 7.35-5.5 5.5a.5.5 0 0 1-.7-.7L10.04 7 4.9 1.85a.5.5 0 1 1 .7-.7l5.5 5.5c.2.2.2.5 0 .7Z" />
    </svg>
);

<div className="sb-container">
  <div className='sb-section-title'>
    # Configure your project

    Because Storybook works separately from your app, you'll need to configure it for your specific stack and setup. Below, explore guides for configuring Storybook with popular frameworks and tools. If you get stuck, learn how you can ask for help from our community.

  </div>
  <div className="sb-section">
    <div className="sb-section-item">
      <img
        src={Styling}
        alt="A wall of logos representing different styling technologies"
      />
      <h4 className="sb-section-item-heading">Add styling and CSS</h4>
      <p className="sb-section-item-paragraph">Like with web applications, there are many ways to include CSS within Storybook. Learn more about setting up styling within Storybook.</p>
      <a
        href="https://storybook.js.org/docs/react/configure/styling-and-css"
        target="_blank"
      >Learn more<RightArrow /></a>
    </div>
    <div className="sb-section-item">
      <img
        src={Context}
        alt="An abstraction representing the composition of data for a component"
      />
      <h4 className="sb-section-item-heading">Provide context and mocking</h4>
      <p className="sb-section-item-paragraph">Often when a story doesn't render, it's because your component is expecting a specific environment or context (like a theme provider) to be available.</p>
      <a
        href="https://storybook.js.org/docs/react/writing-stories/decorators#context-for-mocking"
        target="_blank"
      >Learn more<RightArrow /></a>
    </div>
    <div className="sb-section-item">
      <img src={Assets} alt="A representation of typography and image assets" />
      <div>
        <h4 className="sb-section-item-heading">Load assets and resources</h4>
        <p className="sb-section-item-paragraph">To link static files (like fonts) to your projects and stories, use the
        `staticDirs` configuration option to specify folders to load when
        starting Storybook.</p>
        <a
          href="https://storybook.js.org/docs/react/configure/images-and-assets"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
    </div>
  </div>
</div>
<div className="sb-container">
  <div className='sb-section-title'>
    # Do more with Storybook

    Now that you know the basics, let's explore other parts of Storybook that will improve your experience. This list is just to get you started. You can customise Storybook in many ways to fit your needs.

  </div>

  <div className="sb-section">
    <div className="sb-features-grid">
      <div className="sb-grid-item">
        <img src={Docs} alt="A screenshot showing the autodocs tag being set, pointing a docs page being generated" />
        <h4 className="sb-section-item-heading">Autodocs</h4>
        <p className="sb-section-item-paragraph">Auto-generate living,
          interactive reference documentation from your components and stories.</p>
        <a
          href="https://storybook.js.org/docs/react/writing-docs/autodocs"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
      <div className="sb-grid-item">
        <img src={Share} alt="A browser window showing a Storybook being published to a chromatic.com URL" />
        <h4 className="sb-section-item-heading">Publish to Chromatic</h4>
        <p className="sb-section-item-paragraph">Publish your Storybook to review and collaborate with your entire team.</p>
        <a
          href="https://storybook.js.org/docs/react/sharing/publish-storybook#publish-storybook-with-chromatic"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
      <div className="sb-grid-item">
        <img src={FigmaPlugin} alt="Windows showing the Storybook plugin in Figma" />
        <h4 className="sb-section-item-heading">Figma Plugin</h4>
        <p className="sb-section-item-paragraph">Embed your stories into Figma to cross-reference the design and live
          implementation in one place.</p>
        <a
          href="https://storybook.js.org/docs/react/sharing/design-integrations#embed-storybook-in-figma-with-the-plugin"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
      <div className="sb-grid-item">
        <img src={Testing} alt="Screenshot of tests passing and failing" />
        <h4 className="sb-section-item-heading">Testing</h4>
        <p className="sb-section-item-paragraph">Use stories to test a component in all its variations, no matter how
          complex.</p>
        <a
          href="https://storybook.js.org/docs/react/writing-tests/introduction"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
      <div className="sb-grid-item">
        <img src={Accessibility} alt="Screenshot of accessibility tests passing and failing" />
        <h4 className="sb-section-item-heading">Accessibility</h4>
        <p className="sb-section-item-paragraph">Automatically test your components for a11y issues as you develop.</p>
        <a
          href="https://storybook.js.org/docs/react/writing-tests/accessibility-testing"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
      <div className="sb-grid-item">
        <img src={Theming} alt="Screenshot of Storybook in light and dark mode" />
        <h4 className="sb-section-item-heading">Theming</h4>
        <p className="sb-section-item-paragraph">Theme Storybook's UI to personalize it to your project.</p>
        <a
          href="https://storybook.js.org/docs/react/configure/theming"
          target="_blank"
        >Learn more<RightArrow /></a>
      </div>
    </div>
  </div>
</div>
<div className='sb-addon'>
  <div className='sb-addon-text'>
    <h4>Addons</h4>
    <p className="sb-section-item-paragraph">Integrate your tools with Storybook to connect workflows.</p>
    <a
        href="https://storybook.js.org/integrations/"
        target="_blank"
      >Discover all addons<RightArrow /></a>
  </div>
  <div className='sb-addon-img'>
    <img src={AddonLibrary} alt="Integrate your tools with Storybook to connect workflows." />
  </div>
</div>

<div className="sb-section sb-socials">
    <div className="sb-section-item">
      <img src={Github} alt="Github logo" className="sb-explore-image"/>
      Join our contributors building the future of UI development.

      <a
        href="https://github.com/storybookjs/storybook"
        target="_blank"
      >Star on GitHub<RightArrow /></a>
    </div>
    <div className="sb-section-item">
      <img src={Discord} alt="Discord logo" className="sb-explore-image"/>
      <div>
        Get support and chat with frontend developers.

        <a
          href="https://discord.gg/storybook"
          target="_blank"
        >Join Discord server<RightArrow /></a>
      </div>
    </div>
    <div className="sb-section-item">
      <img src={Youtube} alt="Youtube logo" className="sb-explore-image"/>
      <div>
        Watch tutorials, feature previews and interviews.

        <a
          href="https://www.youtube.com/@chromaticui"
          target="_blank"
        >Watch on YouTube<RightArrow /></a>
      </div>
    </div>
    <div className="sb-section-item">
      <img src={Tutorials} alt="A book" className="sb-explore-image"/>
      <p>Follow guided walkthroughs on for key workflows.</p>

      <a
          href="https://storybook.js.org/tutorials/"
          target="_blank"
        >Discover tutorials<RightArrow /></a>
    </div>

</div>

<style>
    {`
  .sb-container {
    margin-bottom: 48px;
  }

  .sb-section {
    width: 100%;
    display: flex;
    flex-direction: row;
    gap: 20px;
  }

  img {
    object-fit: cover;
  }

  .sb-section-title {
    margin-bottom: 32px;
  }

  .sb-section a:not(h1 a, h2 a, h3 a) {
    font-size: 14px;
  }

  .sb-section-item, .sb-grid-item {
    flex: 1;
    display: flex;
    flex-direction: column;
  }

  .sb-section-item-heading {
    padding-top: 20px !important;
    padding-bottom: 5px !important;
    margin: 0 !important;
  }
  .sb-section-item-paragraph {
    margin: 0;
    padding-bottom: 10px;
  }

  .sb-chevron {
    margin-left: 5px;
  }

  .sb-features-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-gap: 32px 20px;
  }

  .sb-socials {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
  }

  .sb-socials p {
    margin-bottom: 10px;
  }

  .sb-explore-image {
    max-height: 32px;
    align-self: flex-start;
  }

  .sb-addon {
    width: 100%;
    display: flex;
    align-items: center;
    position: relative;
    background-color: #EEF3F8;
    border-radius: 5px;
    border: 1px solid rgba(0, 0, 0, 0.05);
    background: #EEF3F8;
    height: 180px;
    margin-bottom: 48px;
    overflow: hidden;
  }

  .sb-addon-text {
    padding-left: 48px;
    max-width: 240px;
  }

  .sb-addon-text h4 {
    padding-top: 0px;
  }

  .sb-addon-img {
    position: absolute;
    left: 345px;
    top: 0;
    height: 100%;
    width: 200%;
    overflow: hidden;
  }

  .sb-addon-img img {
    width: 650px;
    transform: rotate(-15deg);
    margin-left: 40px;
    margin-top: -72px;
    box-shadow: 0 0 1px rgba(255, 255, 255, 0);
    backface-visibility: hidden;
  }

  @media screen and (max-width: 800px) {
    .sb-addon-img {
      left: 300px;
    }
  }

  @media screen and (max-width: 600px) {
    .sb-section {
      flex-direction: column;
    }

    .sb-features-grid {
      grid-template-columns: repeat(1, 1fr);
    }

    .sb-socials {
      grid-template-columns: repeat(2, 1fr);
    }

    .sb-addon {
      height: 280px;
      align-items: flex-start;
      padding-top: 32px;
      overflow: hidden;
    }

    .sb-addon-text {
      padding-left: 24px;
    }

    .sb-addon-img {
      right: 0;
      left: 0;
      top: 130px;
      bottom: 0;
      overflow: hidden;
      height: auto;
      width: 124%;
    }

    .sb-addon-img img {
      width: 1200px;
      transform: rotate(-12deg);
      margin-left: 0;
      margin-top: 48px;
      margin-bottom: -40px;
      margin-left: -24px;
    }
  }
  `}
</style>