All files / web/src/components/studio StudioSelect.tsx

100% Statements 68/68
100% Branches 8/8
100% Functions 2/2
100% Lines 68/68

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 691x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 39x 126x 126x 126x 126x 126x 126x 126x 126x 126x 126x 39x 39x 39x 39x 39x  
'use client'
 
// StudioSelect — a tiny labeled <select> for the dark studio rails (the app's
// debug panel has no select primitive). Extracted verbatim from the viewer's
// local Select so the design rail (scheme/palette/rails) and the fabrication rail
// (printer profile) share one control instead of forking it. Options are plain
// strings (value === label) or {value,label} pairs for id→label menus.
//
// Styled from theme.ts: label ABOVE the control in muted label-type, the select
// itself the shared `CONTROL` box at full width, so selects, text fields, colour
// wells and sliders all line up on the same left edge down a rail.
//
// An option may be `disabled` — kept visible on purpose. When a choice is real
// hardware the user might own but the current geometry can't seat (a 1/2"
// bumper on a stock-width brim), hiding it would read as "we don't support
// that"; greying it with the reason in its own label says "not at these
// settings", which is the true statement and names the fix. The option colours
// are the light-popup pair from the theme — every platform paints the native
// menu on white, whatever the rail behind it looks like.
 
import { CONTROL, STUDIO } from './theme'
 
export interface StudioSelectProps {
  label: string
  value: string
  options: Array<string | { value: string; label: string; disabled?: boolean }>
  onChange: (v: string) => void
  dataElement?: string
  dataAction?: string
}
 
export function StudioSelect({
  label,
  value,
  options,
  onChange,
  dataElement = 'studio-select',
  dataAction,
}: StudioSelectProps) {
  const opts = options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o))
  return (
    <label
      data-element={dataElement}
      style={{ display: 'flex', flexDirection: 'column', gap: STUDIO.space.field }}
    >
      <span style={STUDIO.type.label}>{label}</span>
      <select
        value={value}
        data-action={dataAction}
        onChange={(e) => onChange(e.target.value)}
        style={{ ...CONTROL, width: '100%', boxSizing: 'border-box', cursor: 'pointer' }}
      >
        {opts.map((o) => (
          <option
            key={o.value}
            value={o.value}
            disabled={o.disabled}
            style={{
              color: o.disabled ? STUDIO.color.optionTextDisabled : STUDIO.color.optionText,
            }}
          >
            {o.label}
          </option>
        ))}
      </select>
    </label>
  )
}