Mixins / foldkit-mixins-ui

Picker

namespace · packages/mixins-ui/src/picker.ts:28

export * as Picker from './picker.js'

A picker that is a dropdown on a desktop and a bottom sheet on a phone: one control, one Model and one set of Messages whatever the width. The application owns the value, as with @foldkit/ui's Listbox, and hears a choice made either way as the same Chose.

at or above the breakpoint: Listbox trigger -> Listbox panel -> Selected -> Chose
below it:                   opener -> Sheet -> an option pressed  -> Chose

Both are drawn, and Recipes.Picker shows one: the dropdown (a Listbox, its panel kept in place with portal: false) at or above its sheetBelow breakpoint, the opener below it, so nothing reads the width and a server render is right at every width. The one hidden is display: none, out of the accessibility tree and the tab order. Opening the Sheet closes the Listbox, so one left open behind a window narrowed past the breakpoint does not stay open beside it; a Sheet open when the window widens stays until chosen from or dismissed.

The Sheet's list is a listbox of option buttons: the chosen one (or the first) takes the Dialog's first focus and is the one in the tab order, the arrows, Home and End move focus between them, and Enter, Space or a tap chooses, which closes the Sheet and gives focus back to the opener. An option's content and the trigger's are Listbox.parts', in the Listbox's slots.

In the guides

Members

Picker.init

function · packages/mixins-ui/src/picker.ts:97

function init(config: InitConfig): Model

A closed picker.

Picker.InitConfig

interface · packages/mixins-ui/src/picker.ts:89

interface InitConfig {
  readonly id: string
  readonly sheet?: Omit<Sheet.InitConfig, 'id' | 'side'>
}

Picker.Message

const · packages/mixins-ui/src/picker.ts:72

const Message: MessageUnion<{ readonly GotListbox: { readonly message: MessageUnion<{ readonly Opened: { maybeActiveItemIndex: Schema.Option<Schema.Number>; }; readonly Closed: {}; readonly BlurredItems: {}; readonly ActivatedItem: { index: Schema.Number; activationTrigger: Schema.Literals<readonly ["Pointer", "Keyboard"]>; }; readonly DeactivatedItem: {}; readonly SelectedItem: { item: Schema.String; }; readonly MovedPointerOverItem: { index: Schema.Number; screenX: Schema.Number; screenY: Schema.Number; }; readonly RequestedItemClick: { index: Schema.Number; }; readonly Searched: { key: Schema.String; maybeTargetIndex: Schema.Option<Schema.Number>; }; readonly CompletedDelayClearSearch: { version: Schema.Number; }; readonly CompletedLockScroll: {}; readonly CompletedUnlockScroll: {}; readonly CompletedInertOthers: {}; readonly CompletedRestoreInert: {}; readonly CompletedFocusButton: {}; readonly CompletedFocusItems: {}; readonly CompletedScrollIntoView: {}; readonly CompletedClickItem: {}; readonly ClickedButton: {}; readonly IgnoredMouseClick: {}; readonly SuppressedSpaceScroll: {}; readonly SuppressedItemCommit: {}; readonly CompletedAnchorListbox: {}; readonly CompletedPortalListboxBackdrop: {}; readonly GotAnimationMessage: { message: import("foldkit/message").MessageUnion<{ readonly Showed: {}; readonly Hid: {}; readonly CompletedWaitForPaint: { generation: Schema.Number; }; readonly EndedAnimation: { generation: Schema.Number; }; }>; }; readonly PressedPointerOnButton: { pointerTyp …;

Picker.Model

const · packages/mixins-ui/src/picker.ts:63

const Model: Schema.Struct<{ readonly id: Schema.String; readonly listbox: Schema.Struct<{ readonly id: Schema.String; readonly isOpen: Schema.Boolean; readonly isAnimated: Schema.Boolean; readonly isModal: Schema.Boolean; readonly orientation: Schema.Literals<readonly ["Vertical", "Horizontal"]>; readonly animation: Schema.Struct<{ readonly id: Schema.String; readonly isShowing: Schema.Boolean; readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>; readonly transitionGeneration: Schema.Number; }>; readonly maybeActiveItemIndex: Schema.Option<Schema.Number>; readonly activationTrigger: Schema.Literals<readonly ["Pointer", "Keyboard"]>; readonly searchQuery: Schema.String; readonly searchVersion: Schema.Number; readonly maybeLastPointerPosition: Schema.Option<Schema.Struct<{ readonly screenX: Schema.Number; readonly screenY: Schema.Number; }>>; readonly maybeLastButtonPointerType: Schema.Option<Schema.String>; }>; readonly sheet: Schema.Struct<{ readonly dialog: Schema.Struct<{ readonly id: Schema.String; readonly isOpen: Schema.Boolean; readonly isAnimated: Schema.Boolean; readonly animation: Schema.Struct<{ readonly id: Schema.String; readonly isShowing: Schema.Boolean; readonly transitionState: Schema.Literals<readonly ["Idle", "EnterStart", "EnterAnimating", "LeaveStart", "LeaveAnimating"]>; readonly transitionGeneration: Schema.Number; }>; readonly maybeFocusSelector: Schema.Option<Schema.String>; }>; readonly side …;

Picker.optionId

function · packages/mixins-ui/src/picker.ts:104

function optionId(id: string, index: number): string

The id of the Sheet's option at index.

Picker.OutMessage

const · packages/mixins-ui/src/picker.ts:83

const OutMessage: MessageUnion<{
  readonly Chose: { readonly value: Schema.String }
}>

Picker.PickerOption

interface · packages/mixins-ui/src/picker.ts:158

interface PickerOption<Value extends string> extends Listbox.OptionContent {
  readonly value: Value
}

An option: its value, and what it shows in the list and on the trigger.

Picker.PickerSlots

const · packages/mixins-ui/src/picker.ts:44

const PickerSlots: Slots.Contract<{
  readonly root: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly dropdown: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly Slot.AttributeName[],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly opener: Slot.UnnamedSlot<
    Capability.Capability<
      'Interactive',
      readonly [Capability.Capability<'Base', readonly []>]
    >,
    readonly [Event.EventToken<'click'>],
    readonly [Attr.AttrToken<'aria-expanded'>, Attr.AttrToken<'aria-label'>],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly list: Slot.UnnamedSlot<
    Capability.Capability<
      'Container',
      readonly [
        Capability.Capability<
          'Interactive',
          readonly [Capability.Capability<'Base', readonly []>]
        >,
      ]
    >,
    readonly Slot.EventName[],
    readonly [Attr.AttrToken<'role'>],
    readonly Slot.RequirementName[],
    boolean
  >
  readonly option: Slot.UnnamedSlot<
    Capability.Capability<
      'Interactive',
      readonly [Capability.Capability<'Base', readonly []>]
    >,
    readonly [Event.EventToken<'click'>, Event.EventToken<'keydown'>],
    readonly [Attr.AttrToken<'role'>, Attr.AttrToken<'aria-selected'>],
    readonly Slot.RequirementName[],
    boolean
  >
}>

Picker.PickerView

interface · packages/mixins-ui/src/picker.ts:162

interface PickerView<Value extends string, Outer> {
  readonly model: Model
  readonly onMessage: (message: Message) => NoInfer<Outer>
  readonly label: string
  readonly options: ReadonlyArray<PickerOption<Value>>
  readonly value: Option.Option<NoInfer<Value>>
  readonly placeholder: string
  readonly anchor?: UiListbox.AnchorConfig
  readonly style?: NamedStyle<typeof PickerSlots> | undefined
  readonly mixins?: MixinList<Outer> | undefined
  readonly listbox?: MixinList<Outer> | undefined
  readonly sheet?: MixinList<Outer> | undefined
}

Picker.Return

type · packages/mixins-ui/src/picker.ts:116

type Return = ReturnWithOutMessage<Model, Message, OutMessage>

Picker.update

function · packages/mixins-ui/src/picker.ts:135

function update(model: Model, message: Message): Return

The picker after message; the same Model when nothing changes.

Picker.view

function · packages/mixins-ui/src/picker.ts:194

function view<Value extends string, Outer>(
  options: PickerView<Value, Outer>,
  h: HtmlBuilder<Outer>,
): Html

The picker: the dropdown and the opener, one shown by the style, and the Sheet.