leva icon indicating copy to clipboard operation
leva copied to clipboard

feat: add label/value object support for Select options, streamlines normalization

Open Copilot opened this issue 1 month ago • 18 comments

Enables human-readable labels for Select option values, particularly useful when values are hex codes or other technical representations.

Changes

Core logic (select-plugin.ts):

  • Detect arrays of {value, label} objects by checking first element
  • Extract values and labels separately; fallback to value as label when label is missing
  • Fixed array mutation bug where options array was incorrectly modified
  • Updated comment to document support for array of {value, label} objects

Type definitions:

  • Added SelectOption<T> type to select-types.ts and public.ts
  • Extended SelectSettings to accept SelectOption<U>[]

Examples (Select.stories.tsx):

  • Added ValueLabelObjects story demonstrating hex colors with friendly names

Usage

// Before: labels and values were coupled
useControls({
  icon: { options: { none: '', IconA, IconB } }  // Keys as labels
})

// After: labels and values are independent
useControls({
  color: {
    options: [
      { value: '#f00', label: 'red' },
      { value: '#0f0', label: 'green' },
      { value: '#00f', label: 'blue' }
    ]
  }
})

Backward compatible with existing array and object formats.

Demo

Labels display in the dropdown while hex color values are returned.

  • Fixes pmndrs/leva#551
Original prompt

This section details on the original issue you should resolve

<issue_title>Feature request: Allow label for options bindings?</issue_title> <issue_description>Rather than always have to see the actual values for a multi-value selection, it'd be great if one could specify per-value labels. Maybe along the lines of this:

const colorPicker = useControls({
  options: [
    { value: '#f00', label: 'red' },
    { value: '#0f0', label: 'green' },
    { value: '#00f', label: 'blue' }
  ],
  value: '#f00'
});

In my current use case I actually want the values to be JavaScript function objects, and I want to make human-readable labels for them.</issue_description>

<agent_instructions>User wants to be able to pass options as a value/label object.</agent_instructions>

Comments on the Issue (you are @copilot in this section)

@gsimone Want to make a PR @danfuzz ?
  • Fixes pmndrs/leva#551

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Summary by CodeRabbit

  • New Features
    • Select control now supports label/value object options ({ value, label }) alongside previous formats; missing or mismatched values default to the first option.
  • Types
    • Runtime-backed typings for Select options updated for more accurate type inference with object-based options.
  • Tests
    • Added comprehensive tests covering option formats, edge cases, validation and warnings.
  • Stories
    • Updated Select stories to demonstrate new option formats, component rendering and interactive behavior.

Copilot avatar Nov 02 '25 15:11 Copilot

🦋 Changeset detected

Latest commit: 5011336473dc64f45d29c379c8c20e63908b46c7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
leva Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

changeset-bot[bot] avatar Nov 02 '25 15:11 changeset-bot[bot]

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
leva Ready Ready Preview Comment Nov 9, 2025 0:17am

vercel[bot] avatar Nov 02 '25 15:11 vercel[bot]

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 5011336473dc64f45d29c379c8c20e63908b46c7:

Sandbox Source
leva-minimal Configuration
leva-busy Configuration
leva-scroll Configuration
leva-advanced-panels Configuration
leva-ui Configuration
leva-theme Configuration
leva-transient Configuration
leva-plugin-plot Configuration
leva-plugin-bezier Configuration
leva-plugin-spring Configuration
leva-plugin-dates Configuration
leva-custom-plugin Configuration

codesandbox-ci[bot] avatar Nov 02 '25 15:11 codesandbox-ci[bot]

@copilot Fix the comments and add a story for the new api

gsimone avatar Nov 02 '25 22:11 gsimone

@copilot Fix the comments and add a story for the new api

Fixed the comment in select-plugin.ts to document array of {value, label} objects format, and the ValueLabelObjects story demonstrates the new API in commit 5579ffe.

Copilot avatar Nov 02 '25 22:11 Copilot

[!NOTE]

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a label/value object API for Select options: introduces zod-driven schemas and runtime types, updates normalize/sanitize/schema/format logic, expands tests and stories to cover { value, label } option objects alongside primitives and record formats, and adds zod as a dependency and a changeset.

Changes

Cohort / File(s) Change Summary
Changeset & Dependency
​.changeset/fair-donkeys-cheer.md, packages/leva/package.json
Adds a changeset declaring a patch release and adds zod (^4.1.12) to package dependencies.
Select plugin implementation
packages/leva/src/plugins/Select/select-plugin.ts
Replaces v8n validation with zod schemas (primitives, key->label records, value/label objects, unions); rewrites normalize() to detect formats and build gathered keys/values; updates sanitize() and schema() to use zod; adds warnings and explicit handling for missing/invalid values; exports selectOptionsSchema, valueLabelObjectSchema, and related types.
Select plugin tests
packages/leva/src/plugins/Select/select-plugin.test.ts
Adds comprehensive tests for normalize, schema, sanitize, and format, covering primitives, value/label objects, records, mixed/invalid inputs, edge cases, and warnings.
Select type shapes
packages/leva/src/plugins/Select/select-types.ts
Replaces generic SelectSettings<U> with concrete SelectSettings referencing SelectOptionsType; removes the extra generic on SelectInput; aligns internal types to the new SelectOptionsType.
Public types & exports
packages/leva/src/types/public.ts, packages/leva/src/types/public.test.ts
Adds runtime-backed types (SelectOption, SelectOptionsType, ValueLabelObjectType) and updates SelectInput, SelectWithValueInput, and SelectWithoutValueInput to support value/label objects; adjusts type tests to reflect narrowed inference for object-labeled options.
Stories — Select examples
packages/leva/stories/inputs/Select.stories.tsx
Converts to typed Storybook pattern (Meta/StoryObj), replaces templates with Story objects (render/play), adds ValueLabelObjects story and component-as-option examples, and updates story exports and typings.
Stories — Advanced example
packages/leva/stories/advanced/Busy.stories.tsx
Adjusts an example's select options from a nested structure to a flat set of strings.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer / Consumer
    participant Plugin as Select Plugin
    participant Zod as Zod Schemas

    Dev->>Plugin: normalize(options, value)
    Plugin->>Zod: try parse as array of {value,label}
    alt matched value/label array
        Zod-->>Plugin: matched
        Plugin->>Plugin: extract gatheredKeys & gatheredValues
    else not matched
        Plugin->>Zod: try parse as array of primitives
        alt matched primitives
            Zod-->>Plugin: matched
            Plugin->>Plugin: use primitives as keys/values
        else not matched
            Plugin->>Zod: try parse as record key->value
            alt matched record
                Zod-->>Plugin: matched
                Plugin->>Plugin: extract keys & values from record
            else no match
                Plugin-->>Dev: warn("invalid options format") and return empty settings
            end
        end
    end

    Plugin->>Plugin: check provided value in gatheredValues
    alt value found
        Plugin-->>Dev: return { value, settings }
    else not found
        Plugin-->>Dev: warn("value not in options") and return { value: undefined, settings }
    end

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Focus areas:
    • packages/leva/src/plugins/Select/select-plugin.ts: zod schema correctness, normalization control flow, warning semantics, and exported types.
    • Type impacts in select-types.ts and types/public.ts: ensure backward compatibility and type inference for all option formats.
    • Tests: ensure new tests accurately reflect intended behavior and edge cases.
    • Stories: verify Storybook render/play logic and component-as-option examples render as expected.

"A rabbit hopped through lines of code,
nibbling schema crumbs along the road.
With zod I plant each label, value, seed,
options now speak cleanly—planted deed by deed.
Carrot cheers for tests and stories sown!"

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding label/value object support for Select options and streamlining normalization logic.
Linked Issues check ✅ Passed The PR fully implements the requested feature from #551 with support for { value, label } object format, handles all required formats (primitives, objects, value/label arrays), maintains backward compatibility, and adds comprehensive tests and documentation.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the label/value object API. Updates include schema validation, type definitions, tests, stories, and dependencies—all necessary for the feature scope.
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch copilot/add-labels-for-options-bindings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Nov 08 '25 18:11 coderabbitai[bot]

@coderabbitai review

gsimone avatar Nov 08 '25 18:11 gsimone

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot] avatar Nov 08 '25 18:11 coderabbitai[bot]

@coderabbitai review

gsimone avatar Nov 08 '25 23:11 gsimone

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot] avatar Nov 08 '25 23:11 coderabbitai[bot]

@coderabbitai review

gsimone avatar Nov 09 '25 00:11 gsimone

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot] avatar Nov 09 '25 00:11 coderabbitai[bot]

@coderabbitai generate docstrings

gsimone avatar Nov 09 '25 00:11 gsimone

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

coderabbitai[bot] avatar Nov 09 '25 00:11 coderabbitai[bot]

[!WARNING] Docstrings generation - IN PROGRESS

Generating docstrings for this pull request

coderabbitai[bot] avatar Nov 09 '25 00:11 coderabbitai[bot]

@coderabbitai review

gsimone avatar Nov 09 '25 00:11 gsimone

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot] avatar Nov 09 '25 00:11 coderabbitai[bot]

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

coderabbitai[bot] avatar Nov 09 '25 00:11 coderabbitai[bot]