get() Upstream
get() Upstream demo built with Expressive MVC - the complete source below runs as an editable sandbox when JavaScript is enabled.
App.tsx
import './App.css';
import { Component, get } from '@expressive/react';
import type { ReactNode } from 'react';
export default () => (
<div className="container">
<h1>Upstream</h1>
<p>
<code>get(Form)</code> locates the nearest form by class, not by prop. A{' '}
<code>Component</code> is in context for everything it renders, so the form
provides itself just by being one - and every field below finds it, however
deep it sits.
</p>
<Form />
<p>
With <code>false</code> the lookup is optional. This is the same Field class,
rendered outside any form: it finds nothing, says so, and still works.
</p>
<Field label="Nickname" />
<small>
One class covers both placements because the answer is typed{' '}
<code>Form | undefined</code> - the compiler makes you handle the standalone
case, rather than a missing provider making you find out at runtime.
</small>
</div>
);
class Form extends Component {
locked = false;
render() {
const { locked } = this;
return (
<form className="signup" onSubmit={(e) => e.preventDefault()}>
<Field label="Name" />
<Group title="Contact">
<Field label="Email" />
</Group>
<footer>
<button type="button" onClick={() => (this.locked = !locked)}>
{locked ? 'Unlock' : 'Lock'} form
</button>
</footer>
</form>
);
}
}
class Field extends Component {
form = get(Form, false);
label = '';
value = '';
render() {
const { form, label, value } = this;
return (
<label className="field">
<span>
{label}
<small>{form ? 'in a form' : 'no form above'}</small>
</span>
<input
value={value}
disabled={form?.locked}
placeholder={form?.locked ? 'locked' : `Your ${label.toLowerCase()}`}
onChange={(e) => (this.value = e.target.value)}
/>
</label>
);
}
}
const Group = (props: { title: string; children?: ReactNode }) => (
<fieldset className="group">
<legend>{props.title}</legend>
{props.children}
</fieldset>
);
App.css
.signup {
display: flex;
flex-direction: column;
gap: var(--s4);
width: 100%;
padding: var(--s4);
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--r-lg);
}
.field {
display: flex;
flex-direction: column;
gap: var(--s2);
width: 100%;
text-align: left;
}
.field span {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--s2);
font-size: var(--t-sm);
font-weight: 500;
}
.field small {
font-family: var(--font-mono);
font-size: var(--t-xs);
}
.field input:disabled {
color: var(--muted);
background: var(--surface-2);
cursor: not-allowed;
}
.signup footer {
display: flex;
padding-top: var(--s3);
border-top: 1px solid var(--border);
}
.signup footer button {
flex: 1;
font-size: var(--t-sm);
}
.group {
display: flex;
flex-direction: column;
gap: var(--s2);
margin: 0;
padding: var(--s3);
border: 1px dashed var(--border-2);
border-radius: var(--r);
}
.group legend {
padding: 0 var(--s2);
font-size: var(--t-xs);
color: var(--muted);
text-transform: uppercase;
letter-spacing: 0.08em;
}