Embedded demos
Use the tabs below to switch between framework shells. Each tab renders
a different adapter boundary against the same framework-neutral
@starbeam-demos/table-core inventory model.
Framework shells
The React shell wraps the table read in useReactive()
and keeps mutations in event handlers.
import { function useReactive<T>(callback: () => T, dependencies?: React.DependencyList): T
useReactive } from "@starbeam/react";import type { type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, (alias) interface InventoryItemimport InventoryItem
InventoryItem, (alias) interface InventoryViewOptionsimport InventoryViewOptions
InventoryViewOptions,} from "@starbeam-demos/table-core";import { const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD } from "@starbeam-demos/table-core";import type { (alias) namespace JSXimport JSX
JSX } from "react";import { function useId(): string
useId, function useState<S>(initialState: S | (() => S)): [S, React.Dispatch<React.SetStateAction<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState } from "react";
import { const inventory: Inventory
inventory, function resetInventory(): void
resetInventory } from "./demo.js";
const const CATEGORIES: readonly InventoryCategory[]
CATEGORIES: readonly type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory[] = [ "produce", "bakery", "pantry", "dairy",];
const const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS = { produce: string
produce: "Produce", bakery: string
bakery: "Bakery", pantry: string
pantry: "Pantry", dairy: string
dairy: "Dairy",} satisfies type Record<K extends keyof any, T> = { [P in K]: T; }
Construct a type with a set of properties K of type T
Record<type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, string>;
type type CategoryFilter = InventoryCategory | "all"
CategoryFilter = type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory | "all";type type SortMode = "name" | "category" | "stock" | "value"
SortMode = type NonNullable<T> = T & {}
Exclude null and undefined from T
NonNullable<(alias) interface InventoryViewOptionsimport InventoryViewOptions
InventoryViewOptions["sort"]>;
const const NO_ITEMS: 0
NO_ITEMS = 0;const const ONE_ITEM: 1
ONE_ITEM = 1;let let nextCustomItemId: number
nextCustomItemId = 1;
export function function App(): JSX.Element
App(): (alias) namespace JSXimport JSX
JSX.interface React.JSX.Element
Element { const [const category: CategoryFilter
category, const setCategory: React.Dispatch<React.SetStateAction<CategoryFilter>>
setCategory] = useState<CategoryFilter>(initialState: CategoryFilter | (() => CategoryFilter)): [CategoryFilter, React.Dispatch<React.SetStateAction<CategoryFilter>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState<type CategoryFilter = InventoryCategory | "all"
CategoryFilter>("all"); const [const lowStockOnly: boolean
lowStockOnly, const setLowStockOnly: React.Dispatch<React.SetStateAction<boolean>>
setLowStockOnly] = useState<boolean>(initialState: boolean | (() => boolean)): [boolean, React.Dispatch<React.SetStateAction<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState(false); const [const search: string
search, const setSearch: React.Dispatch<React.SetStateAction<string>>
setSearch] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState(""); const [const sort: SortMode
sort, const setSort: React.Dispatch<React.SetStateAction<SortMode>>
setSort] = useState<SortMode>(initialState: SortMode | (() => SortMode)): [SortMode, React.Dispatch<React.SetStateAction<SortMode>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState<type SortMode = "name" | "category" | "stock" | "value"
SortMode>("name"); const [const draftName: string
draftName, const setDraftName: React.Dispatch<React.SetStateAction<string>>
setDraftName] = useState<string>(initialState: string | (() => string)): [string, React.Dispatch<React.SetStateAction<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState("");
const const view: TableView<InventoryItem>
view = useReactive<TableView<InventoryItem>>(callback: () => TableView<InventoryItem>, dependencies?: React.DependencyList): TableView<InventoryItem>
useReactive( () => const inventory: Inventory
inventory.Inventory.view(options?: InventoryViewOptions): TableView<InventoryItem>
view({ InventoryViewOptions.category?: InventoryCategory | "all" | undefined
category, InventoryViewOptions.lowStockOnly?: boolean | undefined
lowStockOnly, InventoryViewOptions.search?: string | undefined
search, InventoryViewOptions.sort?: "name" | "category" | "stock" | "value" | undefined
sort }), [const category: CategoryFilter
category, const lowStockOnly: boolean
lowStockOnly, const search: string
search, const sort: SortMode
sort], ); const const stats: InventoryStats
stats = useReactive<InventoryStats>(callback: () => InventoryStats, dependencies?: React.DependencyList): InventoryStats
useReactive(() => const inventory: Inventory
inventory.Inventory.stats: InventoryStats
stats);
const const categoryCounts: { category: InventoryCategory; count: number;}[]
categoryCounts = const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<{ category: InventoryCategory; count: number;}>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => { category: InventoryCategory; count: number;}, thisArg?: any): { category: InventoryCategory; count: number;}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((itemCategory: InventoryCategory
itemCategory) => ({ category: InventoryCategory
category: itemCategory: InventoryCategory
itemCategory, count: number
count: const stats: InventoryStats
stats.InventoryStats.categories: ReadonlyMap<InventoryCategory, number>
categories.ReadonlyMap<InventoryCategory, number>.get(key: InventoryCategory): number | undefined
get(itemCategory: InventoryCategory
itemCategory) ?? const NO_ITEMS: 0
NO_ITEMS, }));
function function (local function) addItem(): void
addItem(): void { const const name: string
name = const draftName: string
draftName.String.trim(): string
Removes the leading and trailing white space and line terminator characters from a string.
trim();
if (const name: string
name === "") { return; }
const const id: string
id = function createInventoryId(name: string): string
createInventoryId(const name: string
name);
const inventory: Inventory
inventory.Inventory.add(item: InventoryItem): void
add({ TableRow.id: string
id, InventoryItem.name: string
name, InventoryItem.category: InventoryCategory
category: "pantry", InventoryItem.price: number
price: 3, InventoryItem.stock: number
stock: 1, }); const setDraftName: (value: React.SetStateAction<string>) => void
setDraftName(""); }
return ( <React.JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
main React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="shell"> <React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="hero"> <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p React.HTMLAttributes<T>.className?: string | undefined
className="eyebrow">Starbeam demo</React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1>Reactive inventory table</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1> <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> The table model lives in a framework-neutral package. This React app only renders it and calls model methods from event handlers. </React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="stats" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Inventory summary"> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): JSX.Element
StatCard label: string
label="Items" value: string
value={const stats: InventoryStats
stats.InventoryStats.totalItems: number
totalItems.Number.toString(radix?: number): string
Returns a string representation of an object.
toString()} /> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): JSX.Element
StatCard label: string
label="Low stock" value: string
value={const stats: InventoryStats
stats.InventoryStats.lowStockCount: number
lowStockCount.Number.toString(radix?: number): string
Returns a string representation of an object.
toString()} /> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): JSX.Element
StatCard label: string
label="Inventory value" value: string
value={function formatCurrency(value: number): string
formatCurrency(const stats: InventoryStats
stats.InventoryStats.inventoryValue: number
inventoryValue)} /> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel controls" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Inventory controls"> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Search <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={const search: string
search} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { const setSearch: (value: React.SetStateAction<string>) => void
setSearch(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value); }} React.InputHTMLAttributes<HTMLInputElement>.placeholder?: string | undefined
placeholder="Filter by name" /> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Category <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={const category: CategoryFilter
category} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { const setCategory: (value: React.SetStateAction<CategoryFilter>) => void
setCategory(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLSelectElement, EventTarget>.currentTarget: EventTarget & HTMLSelectElement
currentTarget.HTMLSelectElement.value: string
The HTMLSelectElement.value property contains the value of the first selected element associated with this element.
value as type CategoryFilter = InventoryCategory | "all"
CategoryFilter); }} > <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="all">All</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> {const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<JSX.Element>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((itemCategory: InventoryCategory
itemCategory) => ( <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.Attributes.key?: React.Key | null | undefined
key={itemCategory: InventoryCategory
itemCategory} React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value={itemCategory: InventoryCategory
itemCategory}> {const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[itemCategory: InventoryCategory
itemCategory]} </React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> ))} </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Sort <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={const sort: SortMode
sort} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { const setSort: (value: React.SetStateAction<SortMode>) => void
setSort(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLSelectElement, EventTarget>.currentTarget: EventTarget & HTMLSelectElement
currentTarget.HTMLSelectElement.value: string
The HTMLSelectElement.value property contains the value of the first selected element associated with this element.
value as type SortMode = "name" | "category" | "stock" | "value"
SortMode); }} > <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="name">Name</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="category">Category</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="stock">Stock</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="value">Value</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="checkbox"> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="checkbox" React.InputHTMLAttributes<HTMLInputElement>.checked?: boolean | undefined
checked={const lowStockOnly: boolean
lowStockOnly} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { const setLowStockOnly: (value: React.SetStateAction<boolean>) => void
setLowStockOnly(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.checked: boolean
The checked property of the HTMLInputElement interface specifies the current checkedness of the element; that is, whether the form control is checked or not.
checked); }} /> Low stock only </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-secondary" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={function resetInventory(): void
resetInventory} > Restore data </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.HTMLAttributes<T>.className?: string | undefined
className="supporting-panels"> <React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel add-item" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Add inventory item"> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Add an item <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={const draftName: string
draftName} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { const setDraftName: (value: React.SetStateAction<string>) => void
setDraftName(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value); }} React.DOMAttributes<HTMLInputElement>.onKeyDown?: React.KeyboardEventHandler<HTMLInputElement> | undefined
onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>
event) => { if (event: React.KeyboardEvent<HTMLInputElement>
event.React.KeyboardEvent<HTMLInputElement>.key: string
See the DOM Level 3 Events spec. for possible values
key === "Enter") { function (local function) addItem(): void
addItem(); } }} React.InputHTMLAttributes<HTMLInputElement>.placeholder?: string | undefined
placeholder="Item name" /> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-primary" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={function (local function) addItem(): void
addItem}> Add </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel category-counts" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Category counts"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2>Categories</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2> <React.JSX.IntrinsicElements.dl: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDListElement>, HTMLDListElement>
dl> {const categoryCounts: { category: InventoryCategory; count: number;}[]
categoryCounts.Array<{ category: InventoryCategory; count: number; }>.map<JSX.Element>(callbackfn: (value: { category: InventoryCategory; count: number;}, index: number, array: { category: InventoryCategory; count: number;}[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map(({ category: InventoryCategory
category: itemCategory: InventoryCategory
itemCategory, count: number
count }) => ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.Attributes.key?: React.Key | null | undefined
key={itemCategory: InventoryCategory
itemCategory}> <React.JSX.IntrinsicElements.dt: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dt>{const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[itemCategory: InventoryCategory
itemCategory]}</React.JSX.IntrinsicElements.dt: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dt> <React.JSX.IntrinsicElements.dd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dd>{count: number
count}</React.JSX.IntrinsicElements.dd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dd> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> ))} </React.JSX.IntrinsicElements.dl: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDListElement>, HTMLDListElement>
dl> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel table-panel"> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.HTMLAttributes<T>.className?: string | undefined
className="table-header"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2>Inventory</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span>{function formatItemCount(count: number): string
formatItemCount(const view: TableView<InventoryItem>
view.TableView<InventoryItem>.count: number
count)}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div>
<React.JSX.IntrinsicElements.table: React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>
table> <React.JSX.IntrinsicElements.thead: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
thead> <React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Name</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Category</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Price</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Stock</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Value</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Actions</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> </React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> </React.JSX.IntrinsicElements.thead: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
thead> <React.JSX.IntrinsicElements.tbody: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
tbody> {const view: TableView<InventoryItem>
view.TableView<InventoryItem>.rows: readonly InventoryItem[]
rows.ReadonlyArray<InventoryItem>.map<JSX.Element>(callbackfn: (value: InventoryItem, index: number, array: readonly InventoryItem[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((item: InventoryItem
item) => ( <function InventoryRow({ item }: { readonly item: InventoryItem;}): JSX.Element
InventoryRow React.Attributes.key?: React.Key | null | undefined
key={item: InventoryItem
item.TableRow.id: string
id} item: InventoryItem
item={item: InventoryItem
item} /> ))} </React.JSX.IntrinsicElements.tbody: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
tbody> </React.JSX.IntrinsicElements.table: React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>
table> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section> </React.JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
main> );}
function function createInventoryId(name: string): string
createInventoryId(name: string
name: string): string { const const slug: string
slug = name: string
name.String.toLowerCase(): string
Converts all the alphabetic characters in a string to lowercase.
toLowerCase().String.replaceAll(searchValue: string | RegExp, replaceValue: string): string (+1 overload)
Replace all instances of a substring in a string, using a regular expression or search string.
replaceAll(/[^a-z0-9]+/gu, "-");
return `${const slug: string
slug}-${let nextCustomItemId: number
nextCustomItemId++}`;}
function function InventoryRow({ item }: { readonly item: InventoryItem;}): JSX.Element
InventoryRow({ item: InventoryItem
item }: { readonly item: InventoryItem
item: (alias) interface InventoryItemimport InventoryItem
InventoryItem }): (alias) namespace JSXimport JSX
JSX.interface React.JSX.Element
Element { const const categoryId: string
categoryId = function useId(): string
useId(); const const priceId: string
priceId = function useId(): string
useId(); const const stockId: string
stockId = function useId(): string
useId(); const const isLowStock: boolean
isLowStock = item: InventoryItem
item.InventoryItem.stock: number
stock <= const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD;
function function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem(updater: (item: InventoryItem) => InventoryItem
updater: (item: InventoryItem
item: (alias) interface InventoryItemimport InventoryItem
InventoryItem) => (alias) interface InventoryItemimport InventoryItem
InventoryItem): void { const inventory: Inventory
inventory.Inventory.update(id: RowId, updater: (item: InventoryItem) => InventoryItem): InventoryItem
update(item: InventoryItem
item.TableRow.id: string
id, updater: (item: InventoryItem) => InventoryItem
updater); }
return ( <React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr React.HTMLAttributes<T>.className?: string | undefined
className={const isLowStock: boolean
isLowStock ? "is-low-stock" : var undefined
undefined}> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label={`${item: InventoryItem
item.InventoryItem.name: string
name} name`} React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.name: string
name} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.name: string
name: event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value, })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const categoryId: string
categoryId}> {item: InventoryItem
item.InventoryItem.name: string
name} category </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.HTMLAttributes<HTMLSelectElement>.id?: string | undefined
id={const categoryId: string
categoryId} React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.category: InventoryCategory
category} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.category: InventoryCategory
category: event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLSelectElement, EventTarget>.currentTarget: EventTarget & HTMLSelectElement
currentTarget.HTMLSelectElement.value: string
The HTMLSelectElement.value property contains the value of the first selected element associated with this element.
value as type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, })); }} > {const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<JSX.Element>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((category: InventoryCategory
category) => ( <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.Attributes.key?: React.Key | null | undefined
key={category: InventoryCategory
category} React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value={category: InventoryCategory
category}> {const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[category: InventoryCategory
category]} </React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> ))} </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const priceId: string
priceId}> {item: InventoryItem
item.InventoryItem.name: string
name} price </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.HTMLAttributes<HTMLInputElement>.id?: string | undefined
id={const priceId: string
priceId} React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="number" React.InputHTMLAttributes<HTMLInputElement>.min?: string | number | undefined
min="0" React.InputHTMLAttributes<HTMLInputElement>.step?: string | number | undefined
step="0.25" React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.price: number
price} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.price: number
price: var Number: NumberConstructor(value?: any) => number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value), })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const stockId: string
stockId}> {item: InventoryItem
item.InventoryItem.name: string
name} stock </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.HTMLAttributes<HTMLInputElement>.id?: string | undefined
id={const stockId: string
stockId} React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="number" React.InputHTMLAttributes<HTMLInputElement>.min?: string | number | undefined
min="0" React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.stock: number
stock} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.stock: number
stock: var Number: NumberConstructor(value?: any) => number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event.React.BaseSyntheticEvent<Event, EventTarget & HTMLInputElement, EventTarget>.currentTarget: EventTarget & HTMLInputElement
currentTarget.HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value), })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span React.HTMLAttributes<T>.className?: string | undefined
className="row-value"> {function formatCurrency(value: number): string
formatCurrency(item: InventoryItem
item.InventoryItem.price: number
price * item: InventoryItem
item.InventoryItem.stock: number
stock)} </React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-danger" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={() => { const inventory: Inventory
inventory.Inventory.delete(id: RowId): boolean
delete(item: InventoryItem
item.TableRow.id: string
id); }} > Delete </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> </React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> );}
function function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): JSX.Element
StatCard({ label: string
label, value: string
value,}: { readonly label: string
label: string; readonly value: string
value: string;}): (alias) namespace JSXimport JSX
JSX.interface React.JSX.Element
Element { return ( <React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
article React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="stat-card"> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span>{label: string
label}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> <React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong>{value: string
value}</React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong> </React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
article> );}
function function formatCurrency(value: number): string
formatCurrency(value: number
value: number): string { return new namespace Intl
Intl.var Intl.NumberFormat: Intl.NumberFormatConstructornew (locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => Intl.NumberFormat (+1 overload)
NumberFormat("en", { Intl.NumberFormatOptions.currency?: string | undefined
currency: "USD", Intl.NumberFormatOptions.style?: keyof Intl.NumberFormatOptionsStyleRegistry | undefined
style: "currency", }).Intl.NumberFormat.format(value: number | bigint): string (+1 overload)
format(value: number
value);}
function function formatItemCount(count: number): string
formatItemCount(count: number
count: number): string { return count: number
count === const ONE_ITEM: 1
ONE_ITEM ? "1 item shown" : `${count: number
count} items shown`;}
The Preact shell installs @starbeam/preact once, then
reads the table directly while rendering.
import type { type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, (alias) interface InventoryItemimport InventoryItem
InventoryItem, (alias) interface InventoryViewOptionsimport InventoryViewOptions
InventoryViewOptions,} from "@starbeam-demos/table-core";import { const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD } from "@starbeam-demos/table-core";import type { interface VNode<P = {}>
VNode } from "preact";import { function useState<S>(initialState: S | (() => S)): [S, Dispatch<StateUpdater<S>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState } from "preact/hooks";
import { const inventory: Inventory
inventory, function resetInventory(): void
resetInventory } from "./demo.js";
const const CATEGORIES: readonly InventoryCategory[]
CATEGORIES: readonly type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory[] = [ "produce", "bakery", "pantry", "dairy",];
const const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS = { produce: string
produce: "Produce", bakery: string
bakery: "Bakery", pantry: string
pantry: "Pantry", dairy: string
dairy: "Dairy",} satisfies type Record<K extends keyof any, T> = { [P in K]: T; }
Construct a type with a set of properties K of type T
Record<type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, string>;
type type CategoryFilter = InventoryCategory | "all"
CategoryFilter = type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory | "all";type type SortMode = "name" | "category" | "stock" | "value"
SortMode = type NonNullable<T> = T & {}
Exclude null and undefined from T
NonNullable<(alias) interface InventoryViewOptionsimport InventoryViewOptions
InventoryViewOptions["sort"]>;
const const NO_ITEMS: 0
NO_ITEMS = 0;const const ONE_ITEM: 1
ONE_ITEM = 1;let let nextCustomItemId: number
nextCustomItemId = 1;
export function function App(): VNode
App(): interface VNode<P = {}>
VNode { const [const category: CategoryFilter
category, const setCategory: Dispatch<StateUpdater<CategoryFilter>>
setCategory] = useState<CategoryFilter>(initialState: CategoryFilter | (() => CategoryFilter)): [CategoryFilter, Dispatch<StateUpdater<CategoryFilter>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState<type CategoryFilter = InventoryCategory | "all"
CategoryFilter>("all"); const [const lowStockOnly: boolean
lowStockOnly, const setLowStockOnly: Dispatch<StateUpdater<boolean>>
setLowStockOnly] = useState<boolean>(initialState: boolean | (() => boolean)): [boolean, Dispatch<StateUpdater<boolean>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState(false); const [const search: string
search, const setSearch: Dispatch<StateUpdater<string>>
setSearch] = useState<string>(initialState: string | (() => string)): [string, Dispatch<StateUpdater<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState(""); const [const sort: SortMode
sort, const setSort: Dispatch<StateUpdater<SortMode>>
setSort] = useState<SortMode>(initialState: SortMode | (() => SortMode)): [SortMode, Dispatch<StateUpdater<SortMode>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState<type SortMode = "name" | "category" | "stock" | "value"
SortMode>("name"); const [const draftName: string
draftName, const setDraftName: Dispatch<StateUpdater<string>>
setDraftName] = useState<string>(initialState: string | (() => string)): [string, Dispatch<StateUpdater<string>>] (+1 overload)
Returns a stateful value, and a function to update it.
useState("");
const const view: TableView<InventoryItem>
view = const inventory: Inventory
inventory.Inventory.view(options?: InventoryViewOptions): TableView<InventoryItem>
view({ InventoryViewOptions.category?: InventoryCategory | "all" | undefined
category, InventoryViewOptions.lowStockOnly?: boolean | undefined
lowStockOnly, InventoryViewOptions.search?: string | undefined
search, InventoryViewOptions.sort?: "name" | "category" | "stock" | "value" | undefined
sort }); const const stats: InventoryStats
stats = const inventory: Inventory
inventory.Inventory.stats: InventoryStats
stats;
const const categoryCounts: { category: InventoryCategory; count: number;}[]
categoryCounts = const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<{ category: InventoryCategory; count: number;}>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => { category: InventoryCategory; count: number;}, thisArg?: any): { category: InventoryCategory; count: number;}[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((itemCategory: InventoryCategory
itemCategory) => ({ category: InventoryCategory
category: itemCategory: InventoryCategory
itemCategory, count: number
count: const stats: InventoryStats
stats.InventoryStats.categories: ReadonlyMap<InventoryCategory, number>
categories.ReadonlyMap<InventoryCategory, number>.get(key: InventoryCategory): number | undefined
get(itemCategory: InventoryCategory
itemCategory) ?? const NO_ITEMS: 0
NO_ITEMS, }));
function function (local function) addItem(): void
addItem(): void { const const name: string
name = const draftName: string
draftName.String.trim(): string
Removes the leading and trailing white space and line terminator characters from a string.
trim();
if (const name: string
name === "") { return; }
const const id: string
id = function createInventoryId(name: string): string
createInventoryId(const name: string
name);
const inventory: Inventory
inventory.Inventory.add(item: InventoryItem): void
add({ TableRow.id: string
id, InventoryItem.name: string
name, InventoryItem.category: InventoryCategory
category: "pantry", InventoryItem.price: number
price: 3, InventoryItem.stock: number
stock: 1, }); const setDraftName: (value: StateUpdater<string>) => void
setDraftName(""); }
return ( <React.JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
main React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="shell"> <React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="hero"> <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p React.HTMLAttributes<T>.className?: string | undefined
className="eyebrow">Starbeam demo</React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> <React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1>Reactive inventory table</React.JSX.IntrinsicElements.h1: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h1> <React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> The table model lives in a framework-neutral package. This Preact app reads it directly during render and calls model methods from event handlers. </React.JSX.IntrinsicElements.p: React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>
p> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="stats" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Inventory summary"> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): VNode
StatCard label: string
label="Items" value: string
value={const stats: InventoryStats
stats.InventoryStats.totalItems: number
totalItems.Number.toString(radix?: number): string
Returns a string representation of an object.
toString()} /> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): VNode
StatCard label: string
label="Low stock" value: string
value={const stats: InventoryStats
stats.InventoryStats.lowStockCount: number
lowStockCount.Number.toString(radix?: number): string
Returns a string representation of an object.
toString()} /> <function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): VNode
StatCard label: string
label="Inventory value" value: string
value={function formatCurrency(value: number): string
formatCurrency(const stats: InventoryStats
stats.InventoryStats.inventoryValue: number
inventoryValue)} /> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel controls" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Inventory controls"> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Search <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={const search: string
search} React.DOMAttributes<HTMLInputElement>.onInput?: React.InputEventHandler<HTMLInputElement> | undefined
onInput={(event: React.InputEvent<HTMLInputElement>
event) => { const setSearch: (value: StateUpdater<string>) => void
setSearch(function inputValue(event: Event): string
inputValue(event: React.InputEvent<HTMLInputElement>
event)); }} React.InputHTMLAttributes<HTMLInputElement>.placeholder?: string | undefined
placeholder="Filter by name" /> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Category <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={const category: CategoryFilter
category} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { const setCategory: (value: StateUpdater<CategoryFilter>) => void
setCategory(function selectValue(event: Event): string
selectValue(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) as type CategoryFilter = InventoryCategory | "all"
CategoryFilter); }} > <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="all">All</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> {const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<JSX.Element>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((itemCategory: InventoryCategory
itemCategory) => ( <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.Attributes.key?: React.Key | null | undefined
key={itemCategory: InventoryCategory
itemCategory} React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value={itemCategory: InventoryCategory
itemCategory}> {const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[itemCategory: InventoryCategory
itemCategory]} </React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> ))} </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Sort <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={const sort: SortMode
sort} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { const setSort: (value: StateUpdater<SortMode>) => void
setSort(function selectValue(event: Event): string
selectValue(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) as type SortMode = "name" | "category" | "stock" | "value"
SortMode); }} > <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="name">Name</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="category">Category</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="stock">Stock</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value="value">Value</React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="checkbox"> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="checkbox" React.InputHTMLAttributes<HTMLInputElement>.checked?: boolean | undefined
checked={const lowStockOnly: boolean
lowStockOnly} React.InputHTMLAttributes<HTMLInputElement>.onChange?: React.ChangeEventHandler<HTMLInputElement, HTMLInputElement> | undefined
onChange={(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event) => { const setLowStockOnly: (value: StateUpdater<boolean>) => void
setLowStockOnly(function checkedValue(event: Event): boolean
checkedValue(event: React.ChangeEvent<HTMLInputElement, HTMLInputElement>
event)); }} /> Low stock only </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label>
<React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-secondary" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={function resetInventory(): void
resetInventory} > Restore data </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.HTMLAttributes<T>.className?: string | undefined
className="supporting-panels"> <React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel add-item" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Add inventory item"> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> Add an item <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={const draftName: string
draftName} React.DOMAttributes<HTMLInputElement>.onInput?: React.InputEventHandler<HTMLInputElement> | undefined
onInput={(event: React.InputEvent<HTMLInputElement>
event) => { const setDraftName: (value: StateUpdater<string>) => void
setDraftName(function inputValue(event: Event): string
inputValue(event: React.InputEvent<HTMLInputElement>
event)); }} React.DOMAttributes<HTMLInputElement>.onKeyDown?: React.KeyboardEventHandler<HTMLInputElement> | undefined
onKeyDown={(event: React.KeyboardEvent<HTMLInputElement>
event) => { if (event: React.KeyboardEvent<HTMLInputElement>
event.React.KeyboardEvent<HTMLInputElement>.key: string
See the DOM Level 3 Events spec. for possible values
key === "Enter") { function (local function) addItem(): void
addItem(); } }} React.InputHTMLAttributes<HTMLInputElement>.placeholder?: string | undefined
placeholder="Item name" /> </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-primary" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={function (local function) addItem(): void
addItem}> Add </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel category-counts" React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label="Category counts"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2>Categories</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2> <React.JSX.IntrinsicElements.dl: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDListElement>, HTMLDListElement>
dl> {const categoryCounts: { category: InventoryCategory; count: number;}[]
categoryCounts.Array<{ category: InventoryCategory; count: number; }>.map<JSX.Element>(callbackfn: (value: { category: InventoryCategory; count: number;}, index: number, array: { category: InventoryCategory; count: number;}[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map(({ category: InventoryCategory
category: itemCategory: InventoryCategory
itemCategory, count: number
count }) => ( <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.Attributes.key?: React.Key | null | undefined
key={itemCategory: InventoryCategory
itemCategory}> <React.JSX.IntrinsicElements.dt: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dt>{const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[itemCategory: InventoryCategory
itemCategory]}</React.JSX.IntrinsicElements.dt: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dt> <React.JSX.IntrinsicElements.dd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dd>{count: number
count}</React.JSX.IntrinsicElements.dd: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
dd> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> ))} </React.JSX.IntrinsicElements.dl: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDListElement>, HTMLDListElement>
dl> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div>
<React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="panel table-panel"> <React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div React.HTMLAttributes<T>.className?: string | undefined
className="table-header"> <React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2>Inventory</React.JSX.IntrinsicElements.h2: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>
h2> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span>{function formatItemCount(count: number): string
formatItemCount(const view: TableView<InventoryItem>
view.TableView<InventoryItem>.count: number
count)}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> </React.JSX.IntrinsicElements.div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div>
<React.JSX.IntrinsicElements.table: React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>
table> <React.JSX.IntrinsicElements.thead: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
thead> <React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Name</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Category</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Price</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Stock</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Value</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> <React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th>Actions</React.JSX.IntrinsicElements.th: React.DetailedHTMLProps<React.ThHTMLAttributes<HTMLTableHeaderCellElement>, HTMLTableHeaderCellElement>
th> </React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> </React.JSX.IntrinsicElements.thead: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
thead> <React.JSX.IntrinsicElements.tbody: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
tbody> {const view: TableView<InventoryItem>
view.TableView<InventoryItem>.rows: readonly InventoryItem[]
rows.ReadonlyArray<InventoryItem>.map<JSX.Element>(callbackfn: (value: InventoryItem, index: number, array: readonly InventoryItem[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((item: InventoryItem
item) => ( <function InventoryRow({ item }: { readonly item: InventoryItem;}): VNode
InventoryRow React.Attributes.key?: React.Key | null | undefined
key={item: InventoryItem
item.TableRow.id: string
id} item: InventoryItem
item={item: InventoryItem
item} /> ))} </React.JSX.IntrinsicElements.tbody: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>
tbody> </React.JSX.IntrinsicElements.table: React.DetailedHTMLProps<React.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>
table> </React.JSX.IntrinsicElements.section: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
section> </React.JSX.IntrinsicElements.main: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
main> );}
function function createInventoryId(name: string): string
createInventoryId(name: string
name: string): string { const const slug: string
slug = name: string
name.String.toLowerCase(): string
Converts all the alphabetic characters in a string to lowercase.
toLowerCase().String.replaceAll(searchValue: string | RegExp, replaceValue: string): string (+1 overload)
Replace all instances of a substring in a string, using a regular expression or search string.
replaceAll(/[^a-z0-9]+/gu, "-");
return `${const slug: string
slug}-${let nextCustomItemId: number
nextCustomItemId++}`;}
function function InventoryRow({ item }: { readonly item: InventoryItem;}): VNode
InventoryRow({ item: InventoryItem
item }: { readonly item: InventoryItem
item: (alias) interface InventoryItemimport InventoryItem
InventoryItem }): interface VNode<P = {}>
VNode { const const categoryId: string
categoryId = `${item: InventoryItem
item.TableRow.id: string
id}-category`; const const priceId: string
priceId = `${item: InventoryItem
item.TableRow.id: string
id}-price`; const const stockId: string
stockId = `${item: InventoryItem
item.TableRow.id: string
id}-stock`; const const isLowStock: boolean
isLowStock = item: InventoryItem
item.InventoryItem.stock: number
stock <= const LOW_STOCK_THRESHOLD: 5
LOW_STOCK_THRESHOLD;
function function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem(updater: (item: InventoryItem) => InventoryItem
updater: (item: InventoryItem
item: (alias) interface InventoryItemimport InventoryItem
InventoryItem) => (alias) interface InventoryItemimport InventoryItem
InventoryItem): void { const inventory: Inventory
inventory.Inventory.update(id: RowId, updater: (item: InventoryItem) => InventoryItem): InventoryItem
update(item: InventoryItem
item.TableRow.id: string
id, updater: (item: InventoryItem) => InventoryItem
updater); }
return ( <React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr React.HTMLAttributes<T>.className?: string | undefined
className={const isLowStock: boolean
isLowStock ? "is-low-stock" : var undefined
undefined}> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.AriaAttributes["aria-label"]?: string | undefined
Defines a string value that labels the current element.
aria-label={`${item: InventoryItem
item.InventoryItem.name: string
name} name`} React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.name: string
name} React.DOMAttributes<HTMLInputElement>.onInput?: React.InputEventHandler<HTMLInputElement> | undefined
onInput={(event: React.InputEvent<HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.name: string
name: function inputValue(event: Event): string
inputValue(event: React.InputEvent<HTMLInputElement>
event), })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const categoryId: string
categoryId}> {item: InventoryItem
item.InventoryItem.name: string
name} category </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select React.HTMLAttributes<HTMLSelectElement>.id?: string | undefined
id={const categoryId: string
categoryId} React.SelectHTMLAttributes<HTMLSelectElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.category: InventoryCategory
category} React.SelectHTMLAttributes<HTMLSelectElement>.onChange?: React.ChangeEventHandler<HTMLSelectElement, HTMLSelectElement> | undefined
onChange={(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.category: InventoryCategory
category: function selectValue(event: Event): string
selectValue(event: React.ChangeEvent<HTMLSelectElement, HTMLSelectElement>
event) as type InventoryCategory = "produce" | "bakery" | "pantry" | "dairy"
InventoryCategory, })); }} > {const CATEGORIES: readonly InventoryCategory[]
CATEGORIES.ReadonlyArray<InventoryCategory>.map<JSX.Element>(callbackfn: (value: InventoryCategory, index: number, array: readonly InventoryCategory[]) => JSX.Element, thisArg?: any): JSX.Element[]
Calls a defined callback function on each element of an array, and returns an array that contains the results.
map((category: InventoryCategory
category) => ( <React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option React.Attributes.key?: React.Key | null | undefined
key={category: InventoryCategory
category} React.OptionHTMLAttributes<HTMLOptionElement>.value?: string | number | readonly string[] | undefined
value={category: InventoryCategory
category}> {const CATEGORY_LABELS: { produce: string; bakery: string; pantry: string; dairy: string;}
CATEGORY_LABELS[category: InventoryCategory
category]} </React.JSX.IntrinsicElements.option: React.DetailedHTMLProps<React.OptionHTMLAttributes<HTMLOptionElement>, HTMLOptionElement>
option> ))} </React.JSX.IntrinsicElements.select: React.DetailedHTMLProps<React.SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>
select> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const priceId: string
priceId}> {item: InventoryItem
item.InventoryItem.name: string
name} price </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.HTMLAttributes<HTMLInputElement>.id?: string | undefined
id={const priceId: string
priceId} React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="number" React.InputHTMLAttributes<HTMLInputElement>.min?: string | number | undefined
min="0" React.InputHTMLAttributes<HTMLInputElement>.step?: string | number | undefined
step="0.25" React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.price: number
price} React.DOMAttributes<HTMLInputElement>.onInput?: React.InputEventHandler<HTMLInputElement> | undefined
onInput={(event: React.InputEvent<HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.price: number
price: var Number: NumberConstructor(value?: any) => number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(function inputValue(event: Event): string
inputValue(event: React.InputEvent<HTMLInputElement>
event)), })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label React.HTMLAttributes<T>.className?: string | undefined
className="sr-only" React.LabelHTMLAttributes<HTMLLabelElement>.htmlFor?: string | undefined
htmlFor={const stockId: string
stockId}> {item: InventoryItem
item.InventoryItem.name: string
name} stock </React.JSX.IntrinsicElements.label: React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>
label> <React.JSX.IntrinsicElements.input: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
input React.HTMLAttributes<HTMLInputElement>.id?: string | undefined
id={const stockId: string
stockId} React.InputHTMLAttributes<HTMLInputElement>.type?: React.HTMLInputTypeAttribute | undefined
type="number" React.InputHTMLAttributes<HTMLInputElement>.min?: string | number | undefined
min="0" React.InputHTMLAttributes<HTMLInputElement>.value?: string | number | readonly string[] | undefined
value={item: InventoryItem
item.InventoryItem.stock: number
stock} React.DOMAttributes<HTMLInputElement>.onInput?: React.InputEventHandler<HTMLInputElement> | undefined
onInput={(event: React.InputEvent<HTMLInputElement>
event) => { function (local function) updateItem(updater: (item: InventoryItem) => InventoryItem): void
updateItem((current: InventoryItem
current) => ({ ...current: InventoryItem
current, InventoryItem.stock: number
stock: var Number: NumberConstructor(value?: any) => number
An object that represents a number of any kind. All JavaScript numbers are 64-bit floating-point numbers.
Number(function inputValue(event: Event): string
inputValue(event: React.InputEvent<HTMLInputElement>
event)), })); }} /> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span React.HTMLAttributes<T>.className?: string | undefined
className="row-value"> {function formatCurrency(value: number): string
formatCurrency(item: InventoryItem
item.InventoryItem.price: number
price * item: InventoryItem
item.InventoryItem.stock: number
stock)} </React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> <React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button React.HTMLAttributes<T>.className?: string | undefined
className="button-danger" React.ButtonHTMLAttributes<HTMLButtonElement>.type?: "button" | "reset" | "submit" | undefined
type="button" React.DOMAttributes<HTMLButtonElement>.onClick?: React.MouseEventHandler<HTMLButtonElement> | undefined
onClick={() => { const inventory: Inventory
inventory.Inventory.delete(id: RowId): boolean
delete(item: InventoryItem
item.TableRow.id: string
id); }} > Delete </React.JSX.IntrinsicElements.button: React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>
button> </React.JSX.IntrinsicElements.td: React.DetailedHTMLProps<React.TdHTMLAttributes<HTMLTableDataCellElement>, HTMLTableDataCellElement>
td> </React.JSX.IntrinsicElements.tr: React.DetailedHTMLProps<React.HTMLAttributes<HTMLTableRowElement>, HTMLTableRowElement>
tr> );}
function function StatCard({ label, value, }: { readonly label: string; readonly value: string;}): VNode
StatCard({ label: string
label, value: string
value,}: { readonly label: string
label: string; readonly value: string
value: string;}): interface VNode<P = {}>
VNode { return ( <React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
article React.HTMLAttributes<HTMLElement>.className?: string | undefined
className="stat-card"> <React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span>{label: string
label}</React.JSX.IntrinsicElements.span: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
span> <React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong>{value: string
value}</React.JSX.IntrinsicElements.strong: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
strong> </React.JSX.IntrinsicElements.article: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
article> );}
function function inputValue(event: Event): string
inputValue(event: Event
event: interface Event
The Event interface represents an event which takes place on an EventTarget.
Event): string { return (event: Event
event.Event.currentTarget: EventTarget | null
The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.
currentTarget as interface HTMLInputElement
The HTMLInputElement interface provides special properties and methods for manipulating the options, layout, and presentation of elements.
HTMLInputElement).HTMLInputElement.value: string
The value property of the HTMLInputElement interface represents the current value of the element as a string.
value;}
function function selectValue(event: Event): string
selectValue(event: Event
event: interface Event
The Event interface represents an event which takes place on an EventTarget.
Event): string { return (event: Event
event.Event.currentTarget: EventTarget | null
The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.
currentTarget as interface HTMLSelectElement
The HTMLSelectElement interface represents a HTML Element. These elements also share all of the properties and methods of other HTML elements via the HTMLElement interface.
HTMLSelectElement).HTMLSelectElement.value: string
The HTMLSelectElement.value property contains the value of the first selected element associated with this element.
value;}
function function checkedValue(event: Event): boolean
checkedValue(event: Event
event: interface Event
The Event interface represents an event which takes place on an EventTarget.
Event): boolean { return (event: Event
event.Event.currentTarget: EventTarget | null
The currentTarget read-only property of the Event interface identifies the element to which the event handler has been attached.
currentTarget as interface HTMLInputElement
The HTMLInputElement interface provides special properties and methods for manipulating the options, layout, and presentation of elements.
HTMLInputElement).HTMLInputElement.checked: boolean
The checked property of the HTMLInputElement interface specifies the current checkedness of the element; that is, whether the form control is checked or not.
checked;}
function function formatCurrency(value: number): string
formatCurrency(value: number
value: number): string { return new namespace Intl
Intl.var Intl.NumberFormat: Intl.NumberFormatConstructornew (locales?: Intl.LocalesArgument, options?: Intl.NumberFormatOptions) => Intl.NumberFormat (+1 overload)
NumberFormat("en", { Intl.NumberFormatOptions.currency?: string | undefined
currency: "USD", Intl.NumberFormatOptions.style?: keyof Intl.NumberFormatOptionsStyleRegistry | undefined
style: "currency", }).Intl.NumberFormat.format(value: number | bigint): string (+1 overload)
format(value: number
value);}
function function formatItemCount(count: number): string
formatItemCount(count: number
count: number): string { return count: number
count === const ONE_ITEM: 1
ONE_ITEM ? "1 item shown" : `${count: number
count} items shown`;}
The Vue shell calls useReactive() during setup, then
reads the table directly from the template.
<script setup lang="ts">import { useReactive } from "@starbeam/vue";import type { InventoryCategory, InventoryItem, InventoryViewOptions,} from "@starbeam-demos/table-core";import { LOW_STOCK_THRESHOLD } from "@starbeam-demos/table-core";import { ref } from "vue";
import { inventory, resetInventory } from "./demo.js";
const CATEGORIES: readonly InventoryCategory[] = [ "produce", "bakery", "pantry", "dairy",];
const CATEGORY_LABELS = { produce: "Produce", bakery: "Bakery", pantry: "Pantry", dairy: "Dairy",} satisfies Record<InventoryCategory, string>;
type CategoryFilter = InventoryCategory | "all";type SortMode = NonNullable<InventoryViewOptions["sort"]>;
const NO_ITEMS = 0;const ONE_ITEM = 1;let nextCustomItemId = 1;
useReactive();
const category = ref<CategoryFilter>("all");const lowStockOnly = ref(false);const search = ref("");const sort = ref<SortMode>("name");const draftName = ref("");
function currentView() { return inventory.view({ category: category.value, lowStockOnly: lowStockOnly.value, search: search.value, sort: sort.value, });}
function categoryCount(itemCategory: InventoryCategory): number { return inventory.stats.categories.get(itemCategory) ?? NO_ITEMS;}
function addItem(): void { const name = draftName.value.trim();
if (name === "") { return; }
const id = createInventoryId(name);
inventory.add({ id, name, category: "pantry", price: 3, stock: 1, }); draftName.value = "";}
function createInventoryId(name: string): string { const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-");
return `${slug}-${nextCustomItemId++}`;}
function updateItem( item: InventoryItem, updater: (item: InventoryItem) => InventoryItem,): void { inventory.update(item.id, updater);}
function updateItemName(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, name: value }));}
function updateItemCategory(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, category: value as InventoryCategory, }));}
function updateItemPrice(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, price: Number(value) }));}
function updateItemStock(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, stock: Number(value) }));}
function formatCurrency(value: number): string { return new Intl.NumberFormat("en", { currency: "USD", style: "currency", }).format(value);}
function formatItemCount(count: number): string { return count === ONE_ITEM ? "1 item shown" : `${count} items shown`;}</script>
<template> <main class="shell"> <section class="hero"> <p class="eyebrow">Starbeam demo</p> <h1>Reactive inventory table</h1> <p> The table model lives in a framework-neutral package. This Vue app reads it directly from the template and calls model methods from event handlers. </p> </section>
<section class="stats" aria-label="Inventory summary"> <article class="stat-card"> <span>Items</span> <strong>{{ inventory.stats.totalItems }}</strong> </article> <article class="stat-card"> <span>Low stock</span> <strong>{{ inventory.stats.lowStockCount }}</strong> </article> <article class="stat-card"> <span>Inventory value</span> <strong>{{ formatCurrency(inventory.stats.inventoryValue) }}</strong> </article> </section>
<section class="panel controls" aria-label="Inventory controls"> <label> Search <input v-model="search" placeholder="Filter by name" /> </label>
<label> Category <select v-model="category"> <option value="all">All</option> <option v-for="itemCategory of CATEGORIES" :key="itemCategory" :value="itemCategory" > {{ CATEGORY_LABELS[itemCategory] }} </option> </select> </label>
<label> Sort <select v-model="sort"> <option value="name">Name</option> <option value="category">Category</option> <option value="stock">Stock</option> <option value="value">Value</option> </select> </label>
<label class="checkbox"> <input v-model="lowStockOnly" type="checkbox" /> Low stock only </label>
<button class="button-secondary" type="button" @click="resetInventory"> Restore data </button> </section>
<div class="supporting-panels"> <section class="panel add-item" aria-label="Add inventory item"> <label> Add an item <input v-model="draftName" placeholder="Item name" @keydown.enter="addItem" /> </label> <button class="button-primary" type="button" @click="addItem"> Add </button> </section>
<section class="panel category-counts" aria-label="Category counts"> <h2>Categories</h2> <dl> <div v-for="itemCategory of CATEGORIES" :key="itemCategory"> <dt>{{ CATEGORY_LABELS[itemCategory] }}</dt> <dd>{{ categoryCount(itemCategory) }}</dd> </div> </dl> </section> </div>
<section class="panel table-panel"> <div class="table-header"> <h2>Inventory</h2> <span>{{ formatItemCount(currentView().count) }}</span> </div>
<table> <thead> <tr> <th>Name</th> <th>Category</th> <th>Price</th> <th>Stock</th> <th>Value</th> <th>Actions</th> </tr> </thead> <tbody> <tr v-for="item of currentView().rows" :key="item.id" :class="{ 'is-low-stock': item.stock <= LOW_STOCK_THRESHOLD }" > <td> <input :aria-label="`${item.name} name`" :value="item.name" @input=" updateItemName( item, ($event.currentTarget as HTMLInputElement).value, ) " /> </td> <td> <label class="sr-only" :for="`${item.id}-category`"> {{ item.name }} category </label> <select :id="`${item.id}-category`" :value="item.category" @change=" updateItemCategory( item, ($event.currentTarget as HTMLSelectElement).value, ) " > <option v-for="itemCategory of CATEGORIES" :key="itemCategory" :value="itemCategory" > {{ CATEGORY_LABELS[itemCategory] }} </option> </select> </td> <td> <label class="sr-only" :for="`${item.id}-price`"> {{ item.name }} price </label> <input :id="`${item.id}-price`" type="number" min="0" step="0.25" :value="item.price" @input=" updateItemPrice( item, ($event.currentTarget as HTMLInputElement).value, ) " /> </td> <td> <label class="sr-only" :for="`${item.id}-stock`"> {{ item.name }} stock </label> <input :id="`${item.id}-stock`" type="number" min="0" :value="item.stock" @input=" updateItemStock( item, ($event.currentTarget as HTMLInputElement).value, ) " /> </td> <td> <span class="row-value"> {{ formatCurrency(item.price * item.stock) }} </span> </td> <td> <button class="button-danger" type="button" @click="inventory.delete(item.id)" > Delete </button> </td> </tr> </tbody> </table> </section> </main></template>
The Svelte shell wraps Starbeam reads in
fromStarbeam() and reads bridged values from the
template.
<script lang="ts"> import { fromStarbeam } from "@starbeam/svelte"; import type { InventoryCategory, InventoryItem, InventoryViewOptions, } from "@starbeam-demos/table-core"; import { LOW_STOCK_THRESHOLD } from "@starbeam-demos/table-core";
import { inventory, resetInventory } from "./demo.js";
const CATEGORIES: readonly InventoryCategory[] = [ "produce", "bakery", "pantry", "dairy", ];
const CATEGORY_LABELS = { produce: "Produce", bakery: "Bakery", pantry: "Pantry", dairy: "Dairy", } satisfies Record<InventoryCategory, string>;
type CategoryFilter = InventoryCategory | "all"; type SortMode = NonNullable<InventoryViewOptions["sort"]>;
const NO_ITEMS = 0; const ONE_ITEM = 1; let nextCustomItemId = 1;
let category = $state<CategoryFilter>("all"); let lowStockOnly = $state(false); let search = $state(""); let sort = $state<SortMode>("name"); let draftName = $state("");
const inventoryView = fromStarbeam(() => inventory.view({ category, lowStockOnly, search, sort }), ); const inventoryStats = fromStarbeam(() => inventory.stats);
const view = $derived(inventoryView.current); const stats = $derived(inventoryStats.current);
function categoryCount(itemCategory: InventoryCategory): number { return stats.categories.get(itemCategory) ?? NO_ITEMS; }
function addItem(): void { const name = draftName.trim();
if (name === "") { return; }
const id = createInventoryId(name);
inventory.add({ id, name, category: "pantry", price: 3, stock: 1, }); draftName = ""; }
function createInventoryId(name: string): string { const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-");
return `${slug}-${nextCustomItemId++}`; }
function updateItem( item: InventoryItem, updater: (item: InventoryItem) => InventoryItem, ): void { inventory.update(item.id, updater); }
function updateItemName(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, name: value })); }
function updateItemCategory(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, category: value as InventoryCategory, })); }
function updateItemPrice(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, price: Number(value) })); }
function updateItemStock(item: InventoryItem, value: string): void { updateItem(item, (current) => ({ ...current, stock: Number(value) })); }
function inputValue(event: Event): string { return (event.currentTarget as HTMLInputElement).value; }
function selectValue(event: Event): string { return (event.currentTarget as HTMLSelectElement).value; }
function addItemOnEnter(event: KeyboardEvent): void { if (event.key === "Enter") { addItem(); } }
function formatCurrency(value: number): string { return new Intl.NumberFormat("en", { currency: "USD", style: "currency", }).format(value); }
function formatItemCount(count: number): string { return count === ONE_ITEM ? "1 item shown" : `${count} items shown`; }</script>
<main class="shell"> <section class="hero"> <p class="eyebrow">Starbeam demo</p> <h1>Reactive inventory table</h1> <p> The table model lives in a framework-neutral package. This Svelte app reads it through <code>fromStarbeam()</code> and calls model methods from event handlers. </p> </section>
<section class="stats" aria-label="Inventory summary"> <article class="stat-card"> <span>Items</span> <strong>{stats.totalItems}</strong> </article> <article class="stat-card"> <span>Low stock</span> <strong>{stats.lowStockCount}</strong> </article> <article class="stat-card"> <span>Inventory value</span> <strong>{formatCurrency(stats.inventoryValue)}</strong> </article> </section>
<section class="panel controls" aria-label="Inventory controls"> <label> Search <input bind:value={search} placeholder="Filter by name" /> </label>
<label> Category <select bind:value={category}> <option value="all">All</option> {#each CATEGORIES as itemCategory} <option value={itemCategory}>{CATEGORY_LABELS[itemCategory]}</option> {/each} </select> </label>
<label> Sort <select bind:value={sort}> <option value="name">Name</option> <option value="category">Category</option> <option value="stock">Stock</option> <option value="value">Value</option> </select> </label>
<label class="checkbox"> <input bind:checked={lowStockOnly} type="checkbox" /> Low stock only </label>
<button class="button-secondary" type="button" onclick={resetInventory}> Restore data </button> </section>
<div class="supporting-panels"> <section class="panel add-item" aria-label="Add inventory item"> <label> Add an item <input bind:value={draftName} placeholder="Item name" onkeydown={addItemOnEnter} /> </label> <button class="button-primary" type="button" onclick={addItem}> Add </button> </section>
<section class="panel category-counts" aria-label="Category counts"> <h2>Categories</h2> <dl> {#each CATEGORIES as itemCategory} <div> <dt>{CATEGORY_LABELS[itemCategory]}</dt> <dd>{categoryCount(itemCategory)}</dd> </div> {/each} </dl> </section> </div>
<section class="panel table-panel"> <div class="table-header"> <h2>Inventory</h2> <span>{formatItemCount(view.count)}</span> </div>
<table> <thead> <tr> <th>Name</th> <th>Category</th> <th>Price</th> <th>Stock</th> <th>Value</th> <th>Actions</th> </tr> </thead> <tbody> {#each view.rows as item (item.id)} <tr class={item.stock <= LOW_STOCK_THRESHOLD ? "is-low-stock" : ""}> <td> <input aria-label={`${item.name} name`} value={item.name} oninput={(event) => updateItemName(item, inputValue(event))} /> </td> <td> <label class="sr-only" for={`${item.id}-category`}> {item.name} category </label> <select id={`${item.id}-category`} value={item.category} onchange={(event) => updateItemCategory(item, selectValue(event))} > {#each CATEGORIES as itemCategory} <option value={itemCategory}>{CATEGORY_LABELS[itemCategory]}</option> {/each} </select> </td> <td> <label class="sr-only" for={`${item.id}-price`}> {item.name} price </label> <input id={`${item.id}-price`} type="number" min="0" step="0.25" value={item.price} oninput={(event) => updateItemPrice(item, inputValue(event))} /> </td> <td> <label class="sr-only" for={`${item.id}-stock`}> {item.name} stock </label> <input id={`${item.id}-stock`} type="number" min="0" value={item.stock} oninput={(event) => updateItemStock(item, inputValue(event))} /> </td> <td> <span class="row-value"> {formatCurrency(item.price * item.stock)} </span> </td> <td> <button class="button-danger" type="button" onclick={() => inventory.delete(item.id)} > Delete </button> </td> </tr> {/each} </tbody> </table> </section></main>
The Ember shell authors an idiomatic
@glimmer/component and reads the table from plain
getters. No fromStarbeam() โ Starbeam writes
invalidate the getters directly.
import { on } from "@ember/modifier";import { tracked } from "@glimmer/tracking";import Component from "@glimmer/component";import type { InventoryCategory, InventoryItem, InventoryStats, InventoryViewOptions, TableView,} from "@starbeam-demos/table-core";import { LOW_STOCK_THRESHOLD } from "@starbeam-demos/table-core";
import { inventory, resetInventory } from "./demo.js";
const CATEGORIES: readonly InventoryCategory[] = [ "produce", "bakery", "pantry", "dairy",];
const CATEGORY_LABELS = { produce: "Produce", bakery: "Bakery", pantry: "Pantry", dairy: "Dairy",} satisfies Record<InventoryCategory, string>;
type CategoryFilter = InventoryCategory | "all";type SortMode = NonNullable<InventoryViewOptions["sort"]>;
const NO_ITEMS = 0;const ONE_ITEM = 1;
function categoryLabel(category: InventoryCategory): string { return CATEGORY_LABELS[category];}
function categoryCount(stats: InventoryStats, category: InventoryCategory): number { return stats.categories.get(category) ?? NO_ITEMS;}
function isLowStock(item: InventoryItem): boolean { return item.stock <= LOW_STOCK_THRESHOLD;}
function rowClass(item: InventoryItem): string { return isLowStock(item) ? "is-low-stock" : "";}
function categoryId(item: InventoryItem): string { return `${item.id}-category`;}
function priceId(item: InventoryItem): string { return `${item.id}-price`;}
function stockId(item: InventoryItem): string { return `${item.id}-stock`;}
function nameLabel(item: InventoryItem): string { return `${item.name} name`;}
function rowValue(item: InventoryItem): string { return formatCurrency(item.price * item.stock);}
function inputValue(event: Event): string { return (event.currentTarget as HTMLInputElement).value;}
function selectValue(event: Event): string { return (event.currentTarget as HTMLSelectElement).value;}
function formatCurrency(value: number): string { return new Intl.NumberFormat("en", { currency: "USD", style: "currency", }).format(value);}
function formatItemCount(count: number): string { return count === ONE_ITEM ? "1 item shown" : `${count} items shown`;}
let nextCustomItemId = 1;
export default class App extends Component { @tracked category: CategoryFilter = "all"; @tracked lowStockOnly = false; @tracked search = ""; @tracked sort: SortMode = "name"; @tracked draftName = "";
get view(): TableView<InventoryItem> { return inventory.view({ category: this.category, lowStockOnly: this.lowStockOnly, search: this.search, sort: this.sort, }); }
get stats(): InventoryStats { return inventory.stats; }
get itemCountLabel(): string { return formatItemCount(this.view.count); }
resetInventory = (): void => { resetInventory(); };
updateSearch = (event: Event): void => { this.search = inputValue(event); };
updateCategory = (event: Event): void => { this.category = selectValue(event) as CategoryFilter; };
updateSort = (event: Event): void => { this.sort = selectValue(event) as SortMode; };
updateLowStockOnly = (event: Event): void => { this.lowStockOnly = (event.currentTarget as HTMLInputElement).checked; };
updateDraftName = (event: Event): void => { this.draftName = inputValue(event); };
addItem = (): void => { const name = this.draftName.trim();
if (name === "") { return; }
const id = this.createInventoryId(name);
inventory.add({ id, name, category: "pantry", price: 3, stock: 1, }); this.draftName = ""; };
addItemOnEnter = (event: KeyboardEvent): void => { if (event.key === "Enter") { this.addItem(); } };
createInventoryId(name: string): string { const slug = name.toLowerCase().replaceAll(/[^a-z0-9]+/gu, "-");
return `${slug}-${nextCustomItemId++}`; }
updateItem = ( item: InventoryItem, updater: (item: InventoryItem) => InventoryItem, ): void => { inventory.update(item.id, updater); };
updateItemName = (item: InventoryItem, event: Event): void => { const value = inputValue(event); this.updateItem(item, (current) => ({ ...current, name: value })); };
updateItemCategory = (item: InventoryItem, event: Event): void => { const value = selectValue(event) as InventoryCategory; this.updateItem(item, (current) => ({ ...current, category: value })); };
updateItemPrice = (item: InventoryItem, event: Event): void => { const value = Number(inputValue(event)); this.updateItem(item, (current) => ({ ...current, price: value })); };
updateItemStock = (item: InventoryItem, event: Event): void => { const value = Number(inputValue(event)); this.updateItem(item, (current) => ({ ...current, stock: value })); };
deleteItem = (item: InventoryItem): void => { inventory.delete(item.id); };
<template> <main class="shell"> <section class="hero"> <p class="eyebrow">Starbeam demo</p> <h1>Reactive inventory table</h1> <p> The table model lives in a framework-neutral package. This Ember app reads it directly from plain Glimmer getters and calls model methods from event handlers. </p> </section>
<section class="stats" aria-label="Inventory summary"> <article class="stat-card"> <span>Items</span> <strong>{{this.stats.totalItems}}</strong> </article> <article class="stat-card"> <span>Low stock</span> <strong>{{this.stats.lowStockCount}}</strong> </article> <article class="stat-card"> <span>Inventory value</span> <strong>{{formatCurrency this.stats.inventoryValue}}</strong> </article> </section>
<section class="panel controls" aria-label="Inventory controls"> <label> Search <input value={{this.search}} placeholder="Filter by name" {{on "input" this.updateSearch}} /> </label>
<label> Category <select {{on "change" this.updateCategory}}> <option value="all" selected={{this.isAll}}>All</option> {{#each CATEGORIES as |itemCategory|}} <option value={{itemCategory}} selected={{this.isSelectedCategory itemCategory}} > {{categoryLabel itemCategory}} </option> {{/each}} </select> </label>
<label> Sort <select {{on "change" this.updateSort}}> <option value="name" selected={{this.isSortName}}>Name</option> <option value="category" selected={{this.isSortCategory}}>Category</option> <option value="stock" selected={{this.isSortStock}}>Stock</option> <option value="value" selected={{this.isSortValue}}>Value</option> </select> </label>
<label class="checkbox"> <input type="checkbox" checked={{this.lowStockOnly}} {{on "change" this.updateLowStockOnly}} /> Low stock only </label>
<button class="button-secondary" type="button" {{on "click" this.resetInventory}} > Restore data </button> </section>
<div class="supporting-panels"> <section class="panel add-item" aria-label="Add inventory item"> <label> Add an item <input value={{this.draftName}} placeholder="Item name" {{on "input" this.updateDraftName}} {{on "keydown" this.addItemOnEnter}} /> </label> <button class="button-primary" type="button" {{on "click" this.addItem}}> Add </button> </section>
<section class="panel category-counts" aria-label="Category counts"> <h2>Categories</h2> <dl> {{#each CATEGORIES as |itemCategory|}} <div> <dt>{{categoryLabel itemCategory}}</dt> <dd>{{categoryCount this.stats itemCategory}}</dd> </div> {{/each}} </dl> </section> </div>
<section class="panel table-panel"> <div class="table-header"> <h2>Inventory</h2> <span>{{this.itemCountLabel}}</span> </div>
<table> <thead> <tr> <th>Name</th> <th>Category</th> <th>Price</th> <th>Stock</th> <th>Value</th> <th>Actions</th> </tr> </thead> <tbody> {{#each this.view.rows key="id" as |item|}} <tr class={{rowClass item}}> <td> <input aria-label={{nameLabel item}} value={{item.name}} {{on "input" (this.bindUpdate this.updateItemName item)}} /> </td> <td> <label class="sr-only" for={{categoryId item}}> {{item.name}} category </label> <select id={{categoryId item}} {{on "change" (this.bindUpdate this.updateItemCategory item)}} > {{#each CATEGORIES as |itemCategory|}} <option value={{itemCategory}} selected={{this.isItemCategory item itemCategory}} > {{categoryLabel itemCategory}} </option> {{/each}} </select> </td> <td> <label class="sr-only" for={{priceId item}}> {{item.name}} price </label> <input id={{priceId item}} type="number" min="0" step="0.25" value={{item.price}} {{on "input" (this.bindUpdate this.updateItemPrice item)}} /> </td> <td> <label class="sr-only" for={{stockId item}}> {{item.name}} stock </label> <input id={{stockId item}} type="number" min="0" value={{item.stock}} {{on "input" (this.bindUpdate this.updateItemStock item)}} /> </td> <td> <span class="row-value"> {{rowValue item}} </span> </td> <td> <button class="button-danger" type="button" {{on "click" (this.bindDelete item)}} > Delete </button> </td> </tr> {{/each}} </tbody> </table> </section> </main> </template>
get isAll(): boolean { return this.category === "all"; }
isSelectedCategory = (category: InventoryCategory): boolean => { return this.category === category; };
isItemCategory = (item: InventoryItem, category: InventoryCategory): boolean => { return item.category === category; };
get isSortName(): boolean { return this.sort === "name"; }
get isSortCategory(): boolean { return this.sort === "category"; }
get isSortStock(): boolean { return this.sort === "stock"; }
get isSortValue(): boolean { return this.sort === "value"; }
bindUpdate = ( handler: (item: InventoryItem, event: Event) => void, item: InventoryItem, ): ((event: Event) => void) => { return (event: Event) => handler(item, event); };
bindDelete = (item: InventoryItem): (() => void) => { return () => this.deleteItem(item); };}