forked from CoreBunch/Instatic
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathControlRow.tsx
More file actions
90 lines (86 loc) · 3 KB
/
Copy pathControlRow.tsx
File metadata and controls
90 lines (86 loc) · 3 KB
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
* ControlRow — shared layout shell used by every property control row.
*
* Owns the wrapper div + label row so individual controls don't have to
* duplicate the same boilerplate. Honors the `layout` variant:
*
* - `inline` (default): 100px label column + control column.
* - `stacked`: label on its own line above a full-width control.
*
* The `labelSuffix` slot is used by controls that surface inline metadata
* next to the label (e.g. NumberControl's unit, MediaLibraryControl /
* UrlControl's validation error).
*
* Shared admin primitive — used by the site editor's PropertiesPanel
* property controls and the data admin's TableSettings inspector.
*/
import type { ReactNode } from 'react'
import { cn } from '@ui/cn'
import styles from './ControlRow.module.css'
/** Row layout variant. Mirrors `PropertyControlLayout` from the module engine. */
type ControlRowLayout = 'inline' | 'stacked'
interface ControlRowProps {
/** Property key — used for the `htmlFor`/`id` linkage when `inputId` is omitted. */
propKey: string
/** Visible label text. Falls back to `propKey` when omitted. */
label?: string
/** Override the input id used for the `htmlFor` attribute. */
inputId?: string
/** Render the row in inline (default) or stacked layout. */
layout?: ControlRowLayout
/** Highlight the label as a breakpoint override. */
isOverride?: boolean
/** Dim the row to indicate the control is disabled. */
disabled?: boolean
/** Optional inline content rendered after the label (unit, validation error). */
labelSuffix?: ReactNode
/** Optional caption shown below the row in subdued text. */
description?: ReactNode
/** The actual control input(s). */
children: ReactNode
}
export function ControlRow({
propKey,
label,
inputId,
layout = 'inline',
isOverride,
disabled,
labelSuffix,
description,
children,
}: ControlRowProps) {
// Allow callers to fully suppress the label row by passing `label=""`
// (empty string). Useful when a control is embedded inside another
// labelled control (e.g. BackgroundImageControl mounting MediaLibraryControl
// inside its `image` mode) and a second label would just add a dead row
// beneath the outer label. Passing `undefined` keeps the legacy fallback
// of using `propKey` as the visible label.
const showLabelRow = label !== ''
return (
<div
className={cn(
styles.controlWrapper,
layout === 'stacked' && styles.controlWrapperStacked,
!showLabelRow && styles.controlWrapperNoLabel,
disabled && styles.controlWrapperDisabled,
)}
>
{showLabelRow && (
<div className={styles.labelRow}>
<label
htmlFor={inputId ?? `ctrl-${propKey}`}
className={isOverride ? styles.labelOverride : undefined}
>
{label ?? propKey}
</label>
{labelSuffix}
</div>
)}
{children}
{description && (
<span className={styles.description}>{description}</span>
)}
</div>
)
}