import type { Meta, StoryObj } from "@storybook/react-native-web-vite";
import React from "react";
import { View } from "react-native";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { PortalHost } from "@rn-primitives/portal";
import { Select } from "@jobber/components-native";
import {
SelectComposableBasic,
SelectComposableControlledWithRef,
SelectComposableCustomMarker,
SelectComposableDependentOptions,
SelectComposableDescription,
SelectComposableDisabled,
SelectComposableDisabledOptions,
SelectComposableGroupedOptions,
SelectComposableItemPrefixSuffix,
SelectComposableLabelAbove,
SelectComposableLabelInside,
SelectComposableReadOnly,
SelectComposableValidationFlow,
} from "./docs";
const meta = {
title: "Components/Selections/Select/SelectComposable",
component: Select.Root,
parameters: {
viewport: { defaultViewport: "mobile1" },
},
decorators: [
// PortalHost outside SafeAreaProvider so the portal-based dropdown renders
// and resolves its position against the page origin (see the SelectPrimitive
// stories for the rationale). Apps mount one PortalHost at their root.
(Story: React.ComponentType) => (
<>
>
),
],
} satisfies Meta;
export default meta;
type Story = StoryObj;
// ── Field & label placement ────────────────────────────────────────────────
/** Default placement: the composed `Select.Label` renders inside the trigger. */
export const Basic: Story = { render: SelectComposableBasic };
/** `labelPlacement="above"` renders the same `Select.Label` above the trigger. */
export const LabelAbove: Story = { render: SelectComposableLabelAbove };
/** `labelPlacement="inside"` renders the label as a small label inside the trigger. */
export const LabelInside: Story = { render: SelectComposableLabelInside };
/** Supporting `description` rendered below the field. */
export const Description: Story = { render: SelectComposableDescription };
/** Validation: the `error` message and critical styling clear once selected. */
export const ValidationFlow: Story = { render: SelectComposableValidationFlow };
// ── Options & content ──────────────────────────────────────────────────────
/** Grouped options with group labels and a separator between groups. */
export const GroupedOptions: Story = { render: SelectComposableGroupedOptions };
/** `Select.ItemPrefix` / `Select.ItemSuffix` slots passed into `Select.Item`. */
export const ItemPrefixSuffix: Story = {
render: SelectComposableItemPrefixSuffix,
};
/** Override the default checkmark via the `indicator` slot prop. */
export const CustomMarker: Story = { render: SelectComposableCustomMarker };
/** Individual options can be disabled. */
export const DisabledOptions: Story = {
render: SelectComposableDisabledOptions,
};
// ── Behaviour & field states ───────────────────────────────────────────────
/** The trigger ref exposes imperative `open()` / `close()`. */
export const ControlledWithRef: Story = {
render: SelectComposableControlledWithRef,
};
/** Changing a parent selection clears a now-invalid controlled child value. */
export const ControlledValueReset: Story = {
render: SelectComposableDependentOptions,
};
/** Read-only: non-interactive, value rendered as text with no chevron. */
export const ReadOnly: Story = { render: SelectComposableReadOnly };
/** Disabled field. */
export const Disabled: Story = { render: SelectComposableDisabled };